private int visualLineStartOffset(int offset, boolean leanForward) { EditorImpl editor = myView.getEditor(); int result = EditorUtil.getNotFoldedLineStartOffset(editor, offset); SoftWrapModelImpl softWrapModel = editor.getSoftWrapModel(); List<? extends SoftWrap> softWraps = softWrapModel.getRegisteredSoftWraps(); int currentOrPrevWrapIndex = softWrapModel.getSoftWrapIndex(offset); SoftWrap currentOrPrevWrap; if (currentOrPrevWrapIndex < 0) { currentOrPrevWrapIndex = - currentOrPrevWrapIndex - 2; currentOrPrevWrap = currentOrPrevWrapIndex < 0 || currentOrPrevWrapIndex >= softWraps.size() ? null : softWraps.get(currentOrPrevWrapIndex); } else { currentOrPrevWrap = leanForward ? softWraps.get(currentOrPrevWrapIndex) : null; } if (currentOrPrevWrap != null && currentOrPrevWrap.getStart() > result) { result = currentOrPrevWrap.getStart(); } return result; }
@Override public Integer processFoldRegion(@NotNull EditorPosition position, @NotNull FoldRegion foldRegion) { int startLine = position.logicalLine; int startColumn = position.logicalColumn; int startX = position.x; advancePositionOnFolding(position, foldRegion); if (position.logicalLine < targetPosition.line || position.logicalLine == targetPosition.line && position.logicalColumn <= targetPosition.column) { return null; } Document document = myEditor.getDocument(); int lineEndOffset = document.getLineEndOffset(targetPosition.line); int result = SoftWrapModelImpl.getEditorTextRepresentationHelper(myEditor) .calcSoftWrapUnawareOffset(targetPosition.line == startLine ? foldRegion.getStartOffset() : document.getLineStartOffset(targetPosition.line), lineEndOffset, targetPosition.line == startLine ? startColumn : 0, targetPosition.column, targetPosition.line == startLine ? startX : 0); return result < 0 ? lineEndOffset : result; }
public void testNoUnnecessaryHorizontalScrollBar() throws IOException { // Inspired by IDEA-87184 final String text = "12345678 abcdefgh"; init(15, 7, text); myEditor.getCaretModel().moveToOffset(text.length()); final Ref<Boolean> fail = new Ref<Boolean>(true); SoftWrapApplianceManager applianceManager = ((SoftWrapModelImpl)myEditor.getSoftWrapModel()).getApplianceManager(); SoftWrapAwareDocumentParsingListener listener = new SoftWrapAwareDocumentParsingListenerAdapter() { @Override public void beforeSoftWrapLineFeed(@NotNull EditorPosition position) { if (position.x == text.indexOf("a") * 7) { fail.set(false); } } }; applianceManager.addListener(listener); try { backspace(); } finally { applianceManager.removeListener(listener); } assertFalse(fail.get()); }
public void testOnlyMinimalRangeIsRecalculatedOnDocumentChange() throws IOException { init("aa bb cc dd ee<caret> ff gg hh ii jj", TestFileType.TEXT); EditorTestUtil.configureSoftWraps(myEditor, 8); verifySoftWrapPositions(6, 12, 18, 24); final IncrementalCacheUpdateEvent[] event = new IncrementalCacheUpdateEvent[1]; ((SoftWrapModelImpl)myEditor.getSoftWrapModel()).getApplianceManager().addListener(new SoftWrapAwareDocumentParsingListenerAdapter() { @Override public void onRecalculationEnd(@NotNull IncrementalCacheUpdateEvent e) { assertNull(event[0]); event[0] = e; } }); type(' '); verifySoftWrapPositions(6, 12, 19, 25); assertNotNull(event[0]); assertEquals(6, event[0].getStartOffset()); assertEquals(19, event[0].getActualEndOffset()); }
private void init(final int visibleWidth, @NotNull String fileText, @NotNull TestFileType fileType, final int symbolWidth) throws IOException { init(fileText, fileType); myEditor.getSettings().setUseSoftWraps(true); SoftWrapModelImpl model = (SoftWrapModelImpl)myEditor.getSoftWrapModel(); model.reinitSettings(); SoftWrapApplianceManager applianceManager = model.getApplianceManager(); applianceManager.setWidthProvider(new SoftWrapApplianceManager.VisibleAreaWidthProvider() { @Override public int getVisibleAreaWidth() { return visibleWidth; } }); if (symbolWidth > 0) { applianceManager.setRepresentationHelper(new DefaultEditorTextRepresentationHelper(myEditor) { @Override public int charWidth(char c, int fontType) { return symbolWidth; } }); } applianceManager.registerSoftWrapIfNecessary(); }
public void testOnlyMinimalRangeIsRecalculatedOnDocumentChange() throws IOException { init("aa bb cc dd ee<caret> ff gg hh ii jj", TestFileType.TEXT); EditorTestUtil.configureSoftWraps(myEditor, 8); verifySoftWrapPositions(6, 12, 18, 24); final IncrementalCacheUpdateEvent[] event = new IncrementalCacheUpdateEvent[1]; ((SoftWrapModelImpl)myEditor.getSoftWrapModel()).getApplianceManager().addListener(new SoftWrapAwareDocumentParsingListenerAdapter() { @Override public void onRecalculationEnd(@Nonnull IncrementalCacheUpdateEvent e) { assertNull(event[0]); event[0] = e; } }); type(' '); verifySoftWrapPositions(6, 12, 19, 25); assertNotNull(event[0]); assertEquals(6, event[0].getStartOffset()); assertEquals(19, event[0].getActualEndOffset()); }
private int visualLineStartOffset(int offset, boolean leanForward) { EditorImpl editor = myView.getEditor(); offset = DocumentUtil.alignToCodePointBoundary(myDocument, offset); int result = EditorUtil.getNotFoldedLineStartOffset(editor, offset); SoftWrapModelImpl softWrapModel = editor.getSoftWrapModel(); List<? extends SoftWrap> softWraps = softWrapModel.getRegisteredSoftWraps(); int currentOrPrevWrapIndex = softWrapModel.getSoftWrapIndex(offset); SoftWrap currentOrPrevWrap; if (currentOrPrevWrapIndex < 0) { currentOrPrevWrapIndex = - currentOrPrevWrapIndex - 2; currentOrPrevWrap = currentOrPrevWrapIndex < 0 || currentOrPrevWrapIndex >= softWraps.size() ? null : softWraps.get(currentOrPrevWrapIndex); } else { currentOrPrevWrap = leanForward ? softWraps.get(currentOrPrevWrapIndex) : null; } if (currentOrPrevWrap != null && currentOrPrevWrap.getStart() > result) { result = currentOrPrevWrap.getStart(); } return result; }
private static VisualLineInfo getVisualLineInfo(@Nonnull EditorImpl editor, int offset, boolean beforeSoftWrap) { Document document = editor.getDocument(); int textLength = document.getTextLength(); if (offset <= 0 || textLength == 0) return new VisualLineInfo(0, false); offset = Math.min(offset, textLength); int startOffset = EditorUtil.getNotFoldedLineStartOffset(editor, offset); SoftWrapModelImpl softWrapModel = editor.getSoftWrapModel(); int wrapIndex = softWrapModel.getSoftWrapIndex(offset); int prevSoftWrapIndex = wrapIndex < 0 ? (- wrapIndex - 2) : wrapIndex - (beforeSoftWrap ? 1 : 0); SoftWrap prevSoftWrap = prevSoftWrapIndex < 0 ? null : softWrapModel.getRegisteredSoftWraps().get(prevSoftWrapIndex); int visualLineStartOffset = prevSoftWrap == null ? startOffset : Math.max(startOffset, prevSoftWrap.getStart()); return new VisualLineInfo(visualLineStartOffset, prevSoftWrap != null && prevSoftWrap.getStart() == visualLineStartOffset); }
/** * Updates state of the current processing position in order to point it to the end offset of the given fold region. * * @param foldRegion fold region which end offset should be pointed by the current position * @param collapsedSymbolsWidthInColumns identifies collapsed text width in columns, i.e. width of the last collapsed logical line * in columns, negative value, if it's unknown and needs to be calculated */ public void advance(@NotNull FoldRegion foldRegion, int collapsedSymbolsWidthInColumns) { // We assume that fold region placeholder contains only 'simple' symbols, i.e. symbols that occupy single visual column. String placeholder = foldRegion.getPlaceholderText(); visualColumn += placeholder.length(); offset = foldRegion.getEndOffset(); Document document = myEditor.getDocument(); int endOffsetLogicalLine = document.getLineNumber(foldRegion.getEndOffset()); if (logicalLine == endOffsetLogicalLine) { // Single-line fold region. if (collapsedSymbolsWidthInColumns < 0) { collapsedSymbolsWidthInColumns = SoftWrapModelImpl.getEditorTextRepresentationHelper(myEditor) .toVisualColumnSymbolsNumber(foldRegion.getStartOffset(), foldRegion.getEndOffset(), x); } logicalColumn += collapsedSymbolsWidthInColumns; foldingColumnDiff += placeholder.length() - collapsedSymbolsWidthInColumns; } else { // Multi-line fold region. if (collapsedSymbolsWidthInColumns < 0) { collapsedSymbolsWidthInColumns = SoftWrapModelImpl.getEditorTextRepresentationHelper(myEditor) .toVisualColumnSymbolsNumber(foldRegion.getStartOffset(), foldRegion.getEndOffset(), 0); } int linesDiff = endOffsetLogicalLine - logicalLine; logicalLine += linesDiff; foldedLines += linesDiff; logicalColumn = collapsedSymbolsWidthInColumns; foldingColumnDiff = visualColumn - logicalColumn - softWrapColumnDiff; softWrapLinesBefore += softWrapLinesCurrent; softWrapLinesCurrent = 0; } }
@Override protected VisualPosition buildIfExceeds(@NotNull EditorPosition context, @NotNull FoldRegion foldRegion) { int foldEndLine = myEditor.getDocument().getLineNumber(foldRegion.getEndOffset()); if (myTargetLogical.line > foldEndLine) { return null; } if (myTargetLogical.line < foldEndLine) { // Map all logical position that point inside collapsed fold region to visual position of its start. return context.buildVisualPosition(); } FoldingData data = getFoldRegionData(foldRegion); int foldEndColumn; if (data == null) { int xStart = myEditor.getDocument().getLineNumber(foldRegion.getStartOffset()) == foldEndLine ? context.x : 0; foldEndColumn = SoftWrapModelImpl.getEditorTextRepresentationHelper(myEditor).toVisualColumnSymbolsNumber( foldRegion.getStartOffset(), foldRegion.getEndOffset(), xStart ); } else { foldEndColumn = data.getCollapsedSymbolsWidthInColumns(); } if (foldEndLine == context.logicalLine) { // Single-line fold region. foldEndColumn += context.logicalColumn; } if (foldEndColumn <= myTargetLogical.column) { return null; } // Map all logical position that point inside collapsed fold region to visual position of its start. return context.buildVisualPosition(); }
@Override protected LogicalPosition buildIfExceeds(@NotNull EditorPosition position, @NotNull FoldRegion foldRegion) { if (myTargetOffset >= foldRegion.getEndOffset()) { return null; } Document document = myEditor.getDocument(); int targetLogicalLine = document.getLineNumber(myTargetOffset); if (targetLogicalLine == position.logicalLine) { // Target offset is located on the same logical line as folding start. position.logicalColumn += SoftWrapModelImpl.getEditorTextRepresentationHelper(myEditor).toVisualColumnSymbolsNumber( foldRegion.getStartOffset(), myTargetOffset, position.x ); } else { // Target offset is located on a different line with folding start. position.logicalColumn = SoftWrapModelImpl.getEditorTextRepresentationHelper(myEditor).toVisualColumnSymbolsNumber( foldRegion.getStartOffset(), myTargetOffset, 0 ); position.softWrapColumnDiff = 0; int linesDiff = document.getLineNumber(myTargetOffset) - document.getLineNumber(foldRegion.getStartOffset()); position.logicalLine += linesDiff; position.foldedLines += linesDiff; position.softWrapLinesBefore += position.softWrapLinesCurrent; position.softWrapLinesCurrent = 0; } position.foldingColumnDiff = position.visualColumn - position.softWrapColumnDiff - position.logicalColumn; position.offset = myTargetOffset; return position.buildLogicalPosition(); }
private static void checkConsistency() { Set<Integer> softWrapOffsets = checkSoftWraps(); List<CacheEntry> cache = ((SoftWrapModelImpl)myEditor.getSoftWrapModel()).getDataMapper().getCache(); CacheEntry prevEntry = null; for (CacheEntry entry : cache) { boolean currentLineStartsWithSoftWrap = checkRelationBetweenNeighbourEntries(entry, prevEntry, softWrapOffsets); checkConsistencyWithinEntry(entry, currentLineStartsWithSoftWrap); checkConsistencyWithFoldingsAndTabs(entry); prevEntry = entry; } assertTrue(softWrapOffsets.isEmpty()); }
public void testNoWrapAtFirstNonWsSymbolWithCustomIndent() throws IOException { String text = " 1111111111111111111111111111111"; init(10, text); getEditor().getSettings().setCustomSoftWrapIndent(0); getEditor().getSettings().setUseCustomSoftWrapIndent(true); //Trigger soft wraps recalculation. ((SoftWrapModelImpl)myEditor.getSoftWrapModel()).prepareToMapping(); // Don't expect soft wraps to be registered as there is no point in wrapping at the first non-white space symbol position // in all cases when soft wrap is located at the left screen edge. assertEmpty(getSoftWrapModel().getRegisteredSoftWraps()); }
public VisualLinesIterator(@Nonnull EditorImpl editor, int startVisualLine) { myEditor = editor; SoftWrapModelImpl softWrapModel = myEditor.getSoftWrapModel(); myDocument = myEditor.getDocument(); FoldRegion[] regions = myEditor.getFoldingModel().fetchTopLevel(); myFoldRegions = regions == null ? FoldRegion.EMPTY_ARRAY : regions; mySoftWraps = softWrapModel.getRegisteredSoftWraps(); myLocation = new Location(startVisualLine); }
private VisualLineFragmentsIterator(EditorView view, int offset, boolean beforeSoftWrap, @Nullable Runnable quickEvaluationListener) { EditorImpl editor = view.getEditor(); int visualLineStartOffset = EditorUtil.getNotFoldedLineStartOffset(editor, offset); SoftWrapModelImpl softWrapModel = editor.getSoftWrapModel(); List<? extends SoftWrap> softWraps = softWrapModel.getRegisteredSoftWraps(); int currentOrPrevWrapIndex = softWrapModel.getSoftWrapIndex(offset); if (currentOrPrevWrapIndex < 0) { currentOrPrevWrapIndex = - currentOrPrevWrapIndex - 2; } else if (beforeSoftWrap) { currentOrPrevWrapIndex--; } SoftWrap currentOrPrevWrap = currentOrPrevWrapIndex < 0 || currentOrPrevWrapIndex >= softWraps.size() ? null : softWraps.get(currentOrPrevWrapIndex); if (currentOrPrevWrap != null && currentOrPrevWrap.getStart() > visualLineStartOffset) { visualLineStartOffset = currentOrPrevWrap.getStart(); } int nextFoldingIndex = editor.getFoldingModel().getLastCollapsedRegionBefore(visualLineStartOffset) + 1; init(view, visualLineStartOffset, editor.getDocument().getLineNumber(visualLineStartOffset), currentOrPrevWrapIndex, nextFoldingIndex, quickEvaluationListener); }
private void init(EditorView view, int startOffset, int startLogicalLine, int currentOrPrevWrapIndex, int nextFoldingIndex, @Nullable Runnable quickEvaluationListener) { myQuickEvaluationListener = quickEvaluationListener; myView = view; EditorImpl editor = view.getEditor(); myDocument = editor.getDocument(); FoldingModelEx foldingModel = editor.getFoldingModel(); FoldRegion[] regions = foldingModel.fetchTopLevel(); myRegions = regions == null ? FoldRegion.EMPTY_ARRAY : regions; SoftWrapModelImpl softWrapModel = editor.getSoftWrapModel(); List<? extends SoftWrap> softWraps = softWrapModel.getRegisteredSoftWraps(); SoftWrap currentOrPrevWrap = currentOrPrevWrapIndex < 0 || currentOrPrevWrapIndex >= softWraps.size() ? null : softWraps.get(currentOrPrevWrapIndex); SoftWrap followingWrap = (currentOrPrevWrapIndex + 1) < 0 || (currentOrPrevWrapIndex + 1) >= softWraps.size() ? null : softWraps.get(currentOrPrevWrapIndex + 1); myVisualLineStartOffset = mySegmentStartOffset = startOffset; myCurrentFoldRegionIndex = nextFoldingIndex; myCurrentEndLogicalLine = startLogicalLine; myCurrentX = myView.getInsets().left; if (mySegmentStartOffset == 0) { myCurrentX += myView.getPrefixTextWidthInPixels(); } else if (currentOrPrevWrap != null && mySegmentStartOffset == currentOrPrevWrap.getStart()) { myCurrentX += currentOrPrevWrap.getIndentInPixels(); myCurrentVisualColumn = currentOrPrevWrap.getIndentInColumns(); } myNextWrapOffset = followingWrap == null ? Integer.MAX_VALUE : followingWrap.getStart(); setInlaysAndFragmentIterator(); }
private VisualLineFragmentsIterator(EditorView view, int offset, boolean beforeSoftWrap, @Nullable Runnable quickEvaluationListener) { myQuickEvaluationListener = quickEvaluationListener; myView = view; EditorImpl editor = view.getEditor(); myDocument = editor.getDocument(); FoldingModelEx foldingModel = editor.getFoldingModel(); FoldRegion[] regions = foldingModel.fetchTopLevel(); myRegions = regions == null ? FoldRegion.EMPTY_ARRAY : regions; int visualLineStartOffset = EditorUtil.getNotFoldedLineStartOffset(editor, offset); SoftWrapModelImpl softWrapModel = editor.getSoftWrapModel(); List<? extends SoftWrap> softWraps = softWrapModel.getRegisteredSoftWraps(); int currentOrPrevWrapIndex = softWrapModel.getSoftWrapIndex(offset); if (currentOrPrevWrapIndex < 0) { currentOrPrevWrapIndex = - currentOrPrevWrapIndex - 2; } else if (beforeSoftWrap) { currentOrPrevWrapIndex--; } SoftWrap currentOrPrevWrap = currentOrPrevWrapIndex < 0 || currentOrPrevWrapIndex >= softWraps.size() ? null : softWraps.get(currentOrPrevWrapIndex); SoftWrap followingWrap = (currentOrPrevWrapIndex + 1) >= softWraps.size() ? null : softWraps.get(currentOrPrevWrapIndex + 1); if (currentOrPrevWrap != null && currentOrPrevWrap.getStart() > visualLineStartOffset) { visualLineStartOffset = currentOrPrevWrap.getStart(); } myVisualLineStartOffset = mySegmentStartOffset = visualLineStartOffset; myCurrentFoldRegionIndex = foldingModel.getLastCollapsedRegionBefore(mySegmentStartOffset) + 1; myCurrentEndLogicalLine = myDocument.getLineNumber(mySegmentStartOffset); if (mySegmentStartOffset == 0) { myCurrentX = myView.getPrefixTextWidthInPixels(); } else if (currentOrPrevWrap != null && mySegmentStartOffset == currentOrPrevWrap.getStart()) { myCurrentX = currentOrPrevWrap.getIndentInPixels(); myCurrentVisualColumn = currentOrPrevWrap.getIndentInColumns(); } myNextWrapOffset = followingWrap == null ? Integer.MAX_VALUE : followingWrap.getStart(); setFragmentIterator(); }
private static SoftWrapModelImpl getSoftWrapModel() { return (SoftWrapModelImpl)myEditor.getSoftWrapModel(); }