private String getDisplayInfoInternal(boolean showPackageInfo, int totalTextLength) { final RangeHighlighter highlighter = getHighlighter(); if (highlighter.isValid() && isValid()) { final int lineNumber = (highlighter.getDocument().getLineNumber(highlighter.getStartOffset()) + 1); String className = getClassName(); final boolean hasClassInfo = className != null && className.length() > 0; final boolean hasMethodInfo = myMethodName != null && myMethodName.length() > 0; if (hasClassInfo || hasMethodInfo) { final StringBuilder info = StringBuilderSpinAllocator.alloc(); try { boolean isFile = getSourcePosition().getFile().getName().equals(className); String packageName = null; if (hasClassInfo) { final int dotIndex = className.lastIndexOf("."); if (dotIndex >= 0 && !isFile) { packageName = className.substring(0, dotIndex); className = className.substring(dotIndex + 1); } if (totalTextLength != -1) { if (className.length() + (hasMethodInfo ? myMethodName.length() : 0) > totalTextLength + 3) { int offset = totalTextLength - (hasMethodInfo ? myMethodName.length() : 0); if (offset > 0 && offset < className.length()) { className = className.substring(className.length() - offset); info.append("..."); } } } info.append(className); } if (hasMethodInfo) { if (isFile) { info.append(":"); } else if (hasClassInfo) { info.append("."); } info.append(myMethodName); } if (showPackageInfo && packageName != null) { info.append(" (").append(packageName).append(")"); } return DebuggerBundle.message( "line.breakpoint.display.name.with.class.or.method", lineNumber, info.toString()); } finally { StringBuilderSpinAllocator.dispose(info); } } return DebuggerBundle.message("line.breakpoint.display.name", lineNumber); } return DebuggerBundle.message("status.breakpoint.invalid"); }
@Nullable public Document getDocument() { final RangeHighlighter highlighter = getHighlighter(); if (highlighter != null) { return highlighter.getDocument(); } final SourcePosition position = getSourcePosition(); if (position != null) { final PsiFile file = position.getFile(); return PsiDocumentManager.getInstance(getProject()).getDocument(file); } return null; }
@CalledInAwt void setResolved(@NotNull Side side, boolean value) { myResolved[side.getIndex()] = value; markInnerFragmentsDamaged(); if (isResolved()) { destroyInnerHighlighter(); } else { // Destroy only resolved side to reduce blinking Document document = myViewer.getEditor(side.select(ThreeSide.LEFT, ThreeSide.RIGHT)).getDocument(); for (RangeHighlighter highlighter : myInnerHighlighters) { if (document.equals(highlighter.getDocument())) { highlighter.dispose(); // it's OK to call dispose() few times } } } }
@Override @SuppressWarnings({"AssignmentToForLoopParameter"}) public void paint( @NotNull Editor editor, @NotNull RangeHighlighter highlighter, @NotNull Graphics g) { int startOffset = highlighter.getStartOffset(); final Document doc = highlighter.getDocument(); if (startOffset >= doc.getTextLength()) return; final int endOffset = highlighter.getEndOffset(); final int endLine = doc.getLineNumber(endOffset); int off; int startLine = doc.getLineNumber(startOffset); IndentGuideDescriptor descriptor = editor.getIndentsModel().getDescriptor(startLine, endLine); final CharSequence chars = doc.getCharsSequence(); do { int start = doc.getLineStartOffset(startLine); int end = doc.getLineEndOffset(startLine); off = CharArrayUtil.shiftForward(chars, start, end, " \t"); startLine--; } while (startLine > 1 && off < doc.getTextLength() && chars.charAt(off) == '\n'); final VisualPosition startPosition = editor.offsetToVisualPosition(off); int indentColumn = startPosition.column; // It's considered that indent guide can cross not only white space but comments, javadocs // etc. Hence, there is a possible // case that the first indent guide line is, say, single-line comment where comment // symbols ('//') are located at the first // visual column. We need to calculate correct indent guide column then. int lineShift = 1; if (indentColumn <= 0 && descriptor != null) { indentColumn = descriptor.indentLevel; lineShift = 0; } if (indentColumn <= 0) return; final FoldingModel foldingModel = editor.getFoldingModel(); if (foldingModel.isOffsetCollapsed(off)) return; final FoldRegion headerRegion = foldingModel.getCollapsedRegionAtOffset(doc.getLineEndOffset(doc.getLineNumber(off))); final FoldRegion tailRegion = foldingModel.getCollapsedRegionAtOffset( doc.getLineStartOffset(doc.getLineNumber(endOffset))); if (tailRegion != null && tailRegion == headerRegion) return; final boolean selected; final IndentGuideDescriptor guide = editor.getIndentsModel().getCaretIndentGuide(); if (guide != null) { final CaretModel caretModel = editor.getCaretModel(); final int caretOffset = caretModel.getOffset(); selected = caretOffset >= off && caretOffset < endOffset && caretModel.getLogicalPosition().column == indentColumn; } else { selected = false; } Point start = editor.visualPositionToXY( new VisualPosition(startPosition.line + lineShift, indentColumn)); final VisualPosition endPosition = editor.offsetToVisualPosition(endOffset); Point end = editor.visualPositionToXY(new VisualPosition(endPosition.line, endPosition.column)); int maxY = end.y; if (endPosition.line == editor.offsetToVisualPosition(doc.getTextLength()).line) { maxY += editor.getLineHeight(); } Rectangle clip = g.getClipBounds(); if (clip != null) { if (clip.y >= maxY || clip.y + clip.height <= start.y) { return; } maxY = Math.min(maxY, clip.y + clip.height); } final EditorColorsScheme scheme = editor.getColorsScheme(); g.setColor( selected ? scheme.getColor(EditorColors.SELECTED_INDENT_GUIDE_COLOR) : scheme.getColor(EditorColors.INDENT_GUIDE_COLOR)); // There is a possible case that indent line intersects soft wrap-introduced text. // Example: // this is a long line <soft-wrap> // that| is soft-wrapped // | // | <- vertical indent // // Also it's possible that no additional intersections are added because of soft wrap: // this is a long line <soft-wrap> // | that is soft-wrapped // | // | <- vertical indent // We want to use the following approach then: // 1. Show only active indent if it crosses soft wrap-introduced text; // 2. Show indent as is if it doesn't intersect with soft wrap-introduced text; if (selected) { g.drawLine(start.x + 2, start.y, start.x + 2, maxY); } else { int y = start.y; int newY = start.y; SoftWrapModel softWrapModel = editor.getSoftWrapModel(); int lineHeight = editor.getLineHeight(); for (int i = Math.max(0, startLine + lineShift); i < endLine && newY < maxY; i++) { List<? extends SoftWrap> softWraps = softWrapModel.getSoftWrapsForLine(i); int logicalLineHeight = softWraps.size() * lineHeight; if (i > startLine + lineShift) { logicalLineHeight += lineHeight; // We assume that initial 'y' value points just below the target // line. } if (!softWraps.isEmpty() && softWraps.get(0).getIndentInColumns() < indentColumn) { if (y < newY || i > startLine + lineShift) { // There is a possible case that soft wrap is located on // indent start line. g.drawLine(start.x + 2, y, start.x + 2, newY + lineHeight); } newY += logicalLineHeight; y = newY; } else { newY += logicalLineHeight; } FoldRegion foldRegion = foldingModel.getCollapsedRegionAtOffset(doc.getLineEndOffset(i)); if (foldRegion != null && foldRegion.getEndOffset() < doc.getTextLength()) { i = doc.getLineNumber(foldRegion.getEndOffset()); } } if (y < maxY) { g.drawLine(start.x + 2, y, start.x + 2, maxY); } } }