void () { if (myEditor.isPurePaintingMode()) return; EditorImpl.CaretRectangle[] locations = myEditor.getCaretLocations(true); if (locations == null) return; Graphics2D g = IdeBackgroundUtil.getOriginalGraphics(myGraphics); int caretHeight = myView.getCaretHeight(); EditorSettings settings = myEditor.getSettings(); int topOverhang = settings.isFullLineHeightCursor() ? 0 : myView.getTopOverhang(); Color caretColor = myEditor.getColorsScheme().getColor(EditorColors.CARET_COLOR); if (caretColor == null) caretColor = new JBColor(CARET_DARK, CARET_LIGHT); int minX = myInsets.left; for (EditorImpl.CaretRectangle location : locations) { float x = (float)location.myPoint.getX(); int y = (int)location.myPoint.getY() - topOverhang + myYShift; Caret caret = location.myCaret; CaretVisualAttributes attr = caret == null ? CaretVisualAttributes.DEFAULT : caret.getVisualAttributes(); g.setColor(attr.getColor() != null ? attr.getColor() : caretColor); boolean isRtl = location.myIsRtl; float width = location.myWidth; float startX = Math.max(minX, isRtl ? x - width : x); CaretVisualAttributes.Shape shape = attr.getShape(); switch (shape) { case DEFAULT -> { if (myEditor.isInsertMode() != settings.isBlockCursor()) { int lineWidth = JBUIScale.scale(attr.getWidth(settings.getLineCursorWidth())); // fully cover extra character's pixel which can appear due to antialiasing // see IDEA-148843 for more details if (x > minX && lineWidth > 1) x -= 1 / JBUIScale.sysScale(g); paintCaretBar(g, caret, x, y, lineWidth, caretHeight, isRtl); } else { paintCaretBlock(g, startX, y, width, caretHeight); paintCaretText(g, caret, caretColor, startX, y, topOverhang, isRtl); } } case BLOCK -> { paintCaretBlock(g, startX, y, width, caretHeight); paintCaretText(g, caret, caretColor, startX, y, topOverhang, isRtl); } case BAR -> { // Don't draw if thickness is zero. This allows a plugin to "hide" carets, e.g. to visually emulate a block selection as a // selection rather than as multiple carets with discrete selections if (attr.getThickness() > 0) { int barWidth = Math.max((int)(width * attr.getThickness()), JBUIScale.scale(settings.getLineCursorWidth())); if (!isRtl && x > minX && barWidth > 1 && barWidth < (width / 2)) x -= 1 / JBUIScale.sysScale(g); paintCaretBar(g, caret, isRtl ? x - barWidth : x, y, barWidth, caretHeight, isRtl); Shape savedClip = g.getClip(); g.setClip(new Rectangle2D.Float(isRtl ? x - barWidth : x, y, barWidth, caretHeight)); paintCaretText(g, caret, caretColor, startX, y, topOverhang, isRtl); g.setClip(savedClip); } } case UNDERSCORE -> { if (attr.getThickness() > 0) { int underscoreHeight = Math.max((int)(caretHeight * attr.getThickness()), 1); paintCaretUnderscore(g, startX, y + caretHeight - underscoreHeight, width, underscoreHeight); Shape oldClip = g.getClip(); g.setClip(new Rectangle2D.Float(startX, y + caretHeight - underscoreHeight, width, underscoreHeight)); paintCaretText(g, caret, caretColor, startX, y, topOverhang, isRtl); g.setClip(oldClip); } } case BOX -> paintCaretBox(g, startX, y, width, caretHeight); } } }