/** * We know that there are problems with incremental soft wraps cache update at the moment. Hence, * we may implement full cache reconstruction when the problem is encountered in order to avoid * customer annoyance. * * <p>However, the problems still should be fixed, hence, we report them only if dedicated flag is * set. * * <p>Current method encapsulates the logic mentioned above. * * @param task command object that which execution may trigger incremental update of update soft * wraps cache */ @SuppressWarnings({"UseOfArchaicSystemPropertyAccessors"}) private void executeSafely(SoftWrapAwareTask task) { try { task.run(true); } catch (Throwable e) { if (Boolean.getBoolean(DEBUG_PROPERTY_NAME) || ApplicationManager.getApplication().isUnitTestMode()) { String info = myEditor.dumpState(); LOG.error( String.format("Unexpected exception occurred during performing '%s'", task), e, info); } myEditor.getFoldingModel().rebuild(); myDataMapper.release(); myApplianceManager.reset(); myStorage.removeAll(); myApplianceManager.recalculateIfNecessary(); try { task.run(true); } catch (Throwable e1) { String info = myEditor.dumpState(); LOG.error( String.format("Can't perform %s even with complete soft wraps cache re-parsing", task), e1, info); myEditor.getSettings().setUseSoftWraps(false); task.run(false); } } }
private void paintCaret(Graphics2D g_) { EditorImpl.CaretRectangle[] locations = myEditor.getCaretLocations(true); if (locations == null) return; Graphics2D g = IdeBackgroundUtil.getOriginalGraphics(g_); int lineHeight = myView.getLineHeight(); EditorSettings settings = myEditor.getSettings(); Color caretColor = myEditor.getColorsScheme().getColor(EditorColors.CARET_COLOR); if (caretColor == null) caretColor = new JBColor(CARET_DARK, CARET_LIGHT); g.setColor(caretColor); for (EditorImpl.CaretRectangle location : locations) { int x = location.myPoint.x; int y = location.myPoint.y; Caret caret = location.myCaret; boolean isRtl = location.myIsRtl; if (myEditor.isInsertMode() != settings.isBlockCursor()) { int lineWidth = JBUI.scale(settings.getLineCursorWidth()); g.fillRect(x, y, lineWidth, lineHeight); if (myDocument.getTextLength() > 0 && caret != null && !myView.getLineLayout(caret.getLogicalPosition().line).isLtr()) { g.fillPolygon( new int[] { isRtl ? x + lineWidth : x, isRtl ? x + lineWidth - CARET_DIRECTION_MARK_SIZE : x + CARET_DIRECTION_MARK_SIZE, isRtl ? x + lineWidth : x }, new int[] {y, y, y + CARET_DIRECTION_MARK_SIZE}, 3); } } else { int width = location.myWidth; int startX = Math.max(0, isRtl ? x - width : x); g.fillRect(startX, y, width, lineHeight - 1); if (myDocument.getTextLength() > 0 && caret != null) { int targetVisualColumn = caret.getVisualPosition().column; for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, caret.getVisualLineStart(), false)) { int startVisualColumn = fragment.getStartVisualColumn(); int endVisualColumn = fragment.getEndVisualColumn(); if (startVisualColumn < targetVisualColumn && endVisualColumn > targetVisualColumn || startVisualColumn == targetVisualColumn && !isRtl || endVisualColumn == targetVisualColumn && isRtl) { g.setColor(ColorUtil.isDark(caretColor) ? CARET_LIGHT : CARET_DARK); fragment.draw( g, startX, y + myView.getAscent(), targetVisualColumn - startVisualColumn - (isRtl ? 1 : 0), targetVisualColumn - startVisualColumn + (isRtl ? 0 : 1)); break; } } } } } }
private void paintRightMargin(Graphics g, Rectangle clip) { EditorSettings settings = myEditor.getSettings(); Color rightMargin = myEditor.getColorsScheme().getColor(EditorColors.RIGHT_MARGIN_COLOR); if (!settings.isRightMarginShown() || rightMargin == null) return; int x = settings.getRightMargin(myEditor.getProject()) * myView.getPlainSpaceWidth(); g.setColor(rightMargin); UIUtil.drawLine(g, x, clip.y, x, clip.y + clip.height); }
@Override public int paint( @NotNull Graphics g, @NotNull SoftWrapDrawingType drawingType, int x, int y, int lineHeight) { if (!isSoftWrappingEnabled()) { return 0; } if (!myEditor.getSettings().isAllSoftWrapsShown()) { int visualLine = y / lineHeight; LogicalPosition position = myEditor.visualToLogicalPosition(new VisualPosition(visualLine, 0)); if (position.line != myEditor.getCaretModel().getLogicalPosition().line) { return myPainter.getDrawingHorizontalOffset(g, drawingType, x, y, lineHeight); } } return doPaint(g, drawingType, x, y, lineHeight); }
private void paintLineMarkerSeparator(RangeHighlighter marker, Rectangle clip, Graphics g) { Color separatorColor = marker.getLineSeparatorColor(); LineSeparatorRenderer lineSeparatorRenderer = marker.getLineSeparatorRenderer(); if (separatorColor == null && lineSeparatorRenderer == null) { return; } int line = myDocument.getLineNumber( marker.getLineSeparatorPlacement() == SeparatorPlacement.TOP ? marker.getStartOffset() : marker.getEndOffset()); int visualLine = myView.logicalToVisualPosition( new LogicalPosition( line + (marker.getLineSeparatorPlacement() == SeparatorPlacement.TOP ? 0 : 1), 0), false) .line; int y = myView.visualLineToY(visualLine) - 1; int endShift = clip.x + clip.width; EditorSettings settings = myEditor.getSettings(); if (settings.isRightMarginShown() && myEditor.getColorsScheme().getColor(EditorColors.RIGHT_MARGIN_COLOR) != null) { endShift = Math.min( endShift, settings.getRightMargin(myEditor.getProject()) * myView.getPlainSpaceWidth()); } g.setColor(separatorColor); if (lineSeparatorRenderer != null) { lineSeparatorRenderer.drawLine(g, 0, endShift, y); } else { UIUtil.drawLine(g, 0, y, endShift, y); } }
private boolean areSoftWrapsEnabledInEditor() { return myEditor.getSettings().isUseSoftWraps() && !myEditor.myUseNewRendering && (!(myEditor.getDocument() instanceof DocumentImpl) || !((DocumentImpl) myEditor.getDocument()).acceptsSlashR()); }
private void moveToLogicalPosition(LogicalPosition pos, boolean locateBeforeSoftWrap) { assertIsDispatchThread(); myDesiredX = -1; validateCallContext(); int column = pos.column; int line = pos.line; int softWrapLinesBefore = pos.softWrapLinesBeforeCurrentLogicalLine; int softWrapLinesCurrent = pos.softWrapLinesOnCurrentLogicalLine; int softWrapColumns = pos.softWrapColumnDiff; Document doc = myEditor.getDocument(); if (column < 0) { column = 0; softWrapColumns = 0; } if (line < 0) { line = 0; softWrapLinesBefore = 0; softWrapLinesCurrent = 0; } int lineCount = doc.getLineCount(); if (lineCount == 0) { line = 0; } else if (line > lineCount - 1) { line = lineCount - 1; softWrapLinesBefore = 0; softWrapLinesCurrent = 0; } EditorSettings editorSettings = myEditor.getSettings(); if (!editorSettings.isVirtualSpace() && line < lineCount && !myEditor.getSelectionModel().hasBlockSelection()) { int lineEndOffset = doc.getLineEndOffset(line); int lineEndColumnNumber = myEditor.offsetToLogicalPosition(lineEndOffset).column; if (column > lineEndColumnNumber) { column = lineEndColumnNumber; if (softWrapColumns != 0) { softWrapColumns -= column - lineEndColumnNumber; } } } ((FoldingModelImpl) myEditor.getFoldingModel()).flushCaretPosition(); VerticalInfo oldInfo = myCaretInfo; LogicalPosition oldCaretPosition = myLogicalCaret; LogicalPosition logicalPositionToUse; if (pos.visualPositionAware) { logicalPositionToUse = new LogicalPosition( line, column, softWrapLinesBefore, softWrapLinesCurrent, softWrapColumns, pos.foldedLines, pos.foldingColumnDiff); } else { logicalPositionToUse = new LogicalPosition(line, column); } setCurrentLogicalCaret(logicalPositionToUse); final int offset = myEditor.logicalPositionToOffset(myLogicalCaret); FoldRegion collapsedAt = myEditor.getFoldingModel().getCollapsedRegionAtOffset(offset); if (collapsedAt != null && offset > collapsedAt.getStartOffset()) { Runnable runnable = new Runnable() { public void run() { FoldRegion[] allCollapsedAt = ((FoldingModelImpl) myEditor.getFoldingModel()).fetchCollapsedAt(offset); for (FoldRegion foldRange : allCollapsedAt) { foldRange.setExpanded(true); } } }; myEditor.getFoldingModel().runBatchFoldingOperation(runnable); } myEditor.setLastColumnNumber(myLogicalCaret.column); myVisibleCaret = myEditor.logicalToVisualPosition(myLogicalCaret); myOffset = myEditor.logicalPositionToOffset(myLogicalCaret); LOG.assertTrue(myOffset >= 0 && myOffset <= myEditor.getDocument().getTextLength()); myVisualLineStart = myEditor.logicalPositionToOffset( myEditor.visualToLogicalPosition(new VisualPosition(myVisibleCaret.line, 0))); myVisualLineEnd = myEditor.logicalPositionToOffset( myEditor.visualToLogicalPosition(new VisualPosition(myVisibleCaret.line + 1, 0))); myEditor.updateCaretCursor(); requestRepaint(oldInfo); if (locateBeforeSoftWrap && SoftWrapHelper.isCaretAfterSoftWrap(myEditor)) { int lineToUse = myVisibleCaret.line - 1; if (lineToUse >= 0) { moveToVisualPosition( new VisualPosition( lineToUse, EditorUtil.getLastVisualLineColumnNumber(myEditor, lineToUse))); return; } } if (!oldCaretPosition.toVisualPosition().equals(myLogicalCaret.toVisualPosition())) { CaretEvent event = new CaretEvent(myEditor, oldCaretPosition, myLogicalCaret); for (CaretListener listener : myCaretListeners) { listener.caretPositionChanged(event); } } }
public void moveCaretRelatively( int columnShift, int lineShift, boolean withSelection, boolean blockSelection, boolean scrollToCaret) { assertIsDispatchThread(); SelectionModel selectionModel = myEditor.getSelectionModel(); int selectionStart = selectionModel.getLeadSelectionOffset(); LogicalPosition blockSelectionStart = selectionModel.hasBlockSelection() ? selectionModel.getBlockStart() : getLogicalPosition(); EditorSettings editorSettings = myEditor.getSettings(); VisualPosition visualCaret = getVisualPosition(); int desiredX = myDesiredX; if (columnShift == 0) { if (myDesiredX < 0) { desiredX = myEditor.visualPositionToXY(visualCaret).x; } } else { myDesiredX = desiredX = -1; } int newLineNumber = visualCaret.line + lineShift; int newColumnNumber = visualCaret.column + columnShift; if (desiredX >= 0 && !ApplicationManager.getApplication().isUnitTestMode()) { newColumnNumber = myEditor.xyToVisualPosition( new Point(desiredX, Math.max(0, newLineNumber) * myEditor.getLineHeight())) .column; } Document document = myEditor.getDocument(); if (!editorSettings.isVirtualSpace() && columnShift == 0 && getLogicalPosition().softWrapLinesOnCurrentLogicalLine <= 0) { newColumnNumber = myEditor.getLastColumnNumber(); } else if (!editorSettings.isVirtualSpace() && lineShift == 0 && columnShift == 1) { int lastLine = document.getLineCount() - 1; if (lastLine < 0) lastLine = 0; if (EditorModificationUtil.calcAfterLineEnd(myEditor) >= 0 && newLineNumber < myEditor.logicalToVisualPosition(new LogicalPosition(lastLine, 0)).line) { newColumnNumber = 0; newLineNumber++; } } else if (!editorSettings.isVirtualSpace() && lineShift == 0 && columnShift == -1) { if (newColumnNumber < 0 && newLineNumber > 0) { newLineNumber--; newColumnNumber = EditorUtil.getLastVisualLineColumnNumber(myEditor, newLineNumber); } } if (newColumnNumber < 0) newColumnNumber = 0; // There is a possible case that caret is located at the first line and user presses 'Shift+Up'. // We want to select all text // from the document start to the current caret position then. So, we have a dedicated flag for // tracking that. boolean selectToDocumentStart = false; if (newLineNumber < 0) { selectToDocumentStart = true; newLineNumber = 0; // We want to move caret to the first column if it's already located at the first line and // 'Up' is pressed. newColumnNumber = 0; desiredX = -1; } VisualPosition pos = new VisualPosition(newLineNumber, newColumnNumber); int lastColumnNumber = newColumnNumber; if (!editorSettings.isCaretInsideTabs() && !myEditor.getSoftWrapModel().isInsideSoftWrap(pos)) { LogicalPosition log = myEditor.visualToLogicalPosition(new VisualPosition(newLineNumber, newColumnNumber)); int offset = myEditor.logicalPositionToOffset(log); if (offset >= document.getTextLength()) { int lastOffsetColumn = myEditor.offsetToVisualPosition(document.getTextLength()).column; // We want to move caret to the last column if if it's located at the last line and 'Down' // is pressed. newColumnNumber = lastColumnNumber = Math.max(lastOffsetColumn, newColumnNumber); desiredX = -1; } CharSequence text = document.getCharsSequence(); if (offset >= 0 && offset < document.getTextLength()) { if (text.charAt(offset) == '\t' && (columnShift <= 0 || offset == myOffset)) { if (columnShift <= 0) { newColumnNumber = myEditor.offsetToVisualPosition(offset).column; } else { SoftWrap softWrap = myEditor.getSoftWrapModel().getSoftWrap(offset + 1); // There is a possible case that tabulation symbol is the last document symbol // represented on a visual line before // soft wrap. We can't just use column from 'offset + 1' because it would point on a // next visual line. if (softWrap == null) { newColumnNumber = myEditor.offsetToVisualPosition(offset + 1).column; } else { newColumnNumber = EditorUtil.getLastVisualLineColumnNumber(myEditor, newLineNumber); } } } } } pos = new VisualPosition(newLineNumber, newColumnNumber); if (columnShift != 0 && lineShift == 0 && myEditor.getSoftWrapModel().isInsideSoftWrap(pos)) { LogicalPosition logical = myEditor.visualToLogicalPosition(pos); int softWrapOffset = myEditor.logicalPositionToOffset(logical); if (columnShift >= 0) { moveToOffset(softWrapOffset); } else { int line = myEditor.offsetToVisualLine(softWrapOffset - 1); moveToVisualPosition( new VisualPosition(line, EditorUtil.getLastVisualLineColumnNumber(myEditor, line))); } } else { moveToVisualPosition(pos); if (!editorSettings.isVirtualSpace() && columnShift == 0) { myEditor.setLastColumnNumber(lastColumnNumber); } } if (withSelection) { if (blockSelection) { selectionModel.setBlockSelection(blockSelectionStart, getLogicalPosition()); } else { if (selectToDocumentStart) { selectionModel.setSelection(selectionStart, 0); } else if (pos.line >= myEditor.getVisibleLineCount()) { if (selectionStart < document.getTextLength()) { selectionModel.setSelection(selectionStart, document.getTextLength()); } } else { selectionModel.setSelection(selectionStart, getVisualPosition(), getOffset()); } } } else { selectionModel.removeSelection(); } if (scrollToCaret) { myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); } if (desiredX >= 0) { myDesiredX = desiredX; } EditorActionUtil.selectNonexpandableFold(myEditor); }
public void moveToVisualPosition(@NotNull VisualPosition pos) { assertIsDispatchThread(); validateCallContext(); myDesiredX = -1; int column = pos.column; int line = pos.line; if (column < 0) column = 0; if (line < 0) line = 0; int lastLine = myEditor.getVisibleLineCount() - 1; if (lastLine <= 0) { lastLine = 0; } if (line > lastLine) { line = lastLine; } EditorSettings editorSettings = myEditor.getSettings(); if (!editorSettings.isVirtualSpace() && line <= lastLine) { int lineEndColumn = EditorUtil.getLastVisualLineColumnNumber(myEditor, line); if (column > lineEndColumn) { column = lineEndColumn; } if (column < 0 && line > 0) { line--; column = EditorUtil.getLastVisualLineColumnNumber(myEditor, line); } } myVisibleCaret = new VisualPosition(line, column); VerticalInfo oldInfo = myCaretInfo; LogicalPosition oldPosition = myLogicalCaret; setCurrentLogicalCaret(myEditor.visualToLogicalPosition(myVisibleCaret)); myOffset = myEditor.logicalPositionToOffset(myLogicalCaret); LOG.assertTrue(myOffset >= 0 && myOffset <= myEditor.getDocument().getTextLength()); myVisualLineStart = myEditor.logicalPositionToOffset( myEditor.visualToLogicalPosition(new VisualPosition(myVisibleCaret.line, 0))); myVisualLineEnd = myEditor.logicalPositionToOffset( myEditor.visualToLogicalPosition(new VisualPosition(myVisibleCaret.line + 1, 0))); ((FoldingModelImpl) myEditor.getFoldingModel()).flushCaretPosition(); myEditor.setLastColumnNumber(myVisibleCaret.column); myEditor.updateCaretCursor(); requestRepaint(oldInfo); if (oldPosition.column != myLogicalCaret.column || oldPosition.line != myLogicalCaret.line) { CaretEvent event = new CaretEvent(myEditor, oldPosition, myLogicalCaret); for (CaretListener listener : myCaretListeners) { listener.caretPositionChanged(event); } } }