diff --git a/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java b/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java index 1be9135b3939..1371104f5af3 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java @@ -244,6 +244,19 @@ public class EditorModificationUtil { int anchorLineEndOffset = document.getLineEndOffset(lineNumber); List extends TextChange> softWraps = editor.getSoftWrapModel().getSoftWrapsForLine(logicalPosition.line); for (TextChange softWrap : softWraps) { + if (!editor.getSoftWrapModel().isVisible(softWrap)) { + continue; + } + if (softWrap.getStart() == caretOffset) { + // There are two possible situations: + // *) caret is located on a visual line before soft wrap-introduced line feed; + // *) caret is located on a visual line after soft wrap-introduced line feed; + VisualPosition position = editor.offsetToVisualPosition(caretOffset - 1); + VisualPosition visualCaret = caretModel.getVisualPosition(); + if (position.line == visualCaret.line) { + return visualCaret.column - position.column - 1; + } + } if (softWrap.getStart() > caretOffset) { anchorLineEndOffset = softWrap.getStart(); break; diff --git a/platform/platform-api/src/com/intellij/openapi/editor/SoftWrapModel.java b/platform/platform-api/src/com/intellij/openapi/editor/SoftWrapModel.java index e1755408067c..dabb8b37735b 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/SoftWrapModel.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/SoftWrapModel.java @@ -106,6 +106,16 @@ public interface SoftWrapModel { @NotNull List extends TextChange> getSoftWrapsForLine(int documentLine); + /** + * Allows to answer if given soft wrap is shown. + *
+ * The soft wrap may be not shown if it's located, for example, inside collapsed folding region. + * + * @param softWrap soft wrap to check + * @returntrue if given soft wrap is visible; false otherwise
+ */
+ boolean isVisible(TextChange softWrap);
+
/**
* Notifies current model that target document is about to be changed at current caret location.
*
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java
index 8980a1decc0f..10012c0ec016 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java
@@ -215,7 +215,7 @@ public class EditorActionUtil {
if (currentVisCaret.line > caretLogLineStartVis.line) {
// Caret is located not at the first visual line of soft-wrapped logical line.
- moveCaretToStartOfSoftWrappedLine(editor, currentVisCaret);
+ moveCaretToStartOfSoftWrappedLine(editor, currentVisCaret, currentVisCaret.line - caretLogLineStartVis.line);
setupSelection(editor, isWithSelection, selectionStart, blockSelectionStart);
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
return;
@@ -249,7 +249,7 @@ public class EditorActionUtil {
LogicalPosition logLineEndLog = editor.offsetToLogicalPosition(document.getLineEndOffset(logLineToUse));
VisualPosition logLineEndVis = editor.logicalToVisualPosition(logLineEndLog);
if (logLineEndLog.softWrapLinesOnCurrentLogicalLine > 0) {
- moveCaretToStartOfSoftWrappedLine(editor, logLineEndVis);
+ moveCaretToStartOfSoftWrappedLine(editor, logLineEndVis, logLineEndLog.softWrapLinesOnCurrentLogicalLine);
}
else {
int line = logLineEndVis.line;
@@ -265,7 +265,7 @@ public class EditorActionUtil {
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
}
- private static void moveCaretToStartOfSoftWrappedLine(Editor editor, VisualPosition currentVisual) {
+ private static void moveCaretToStartOfSoftWrappedLine(Editor editor, VisualPosition currentVisual, int softWrappedLines) {
CaretModel caretModel = editor.getCaretModel();
int line = currentVisual.line;
@@ -275,8 +275,17 @@ public class EditorActionUtil {
if (currentVisual.column <= 1) {
line--;
+ softWrappedLines--;
+ // There is a possible case that caret is located at the start of the second visual line of soft-wrapped line.
+ // Hence, it should be moved to the start of the previous visual line which anchor column is not '1'
+ // (after soft wrap drawing) but '0'.
int nonSpaceColumn = findFirstNonSpaceColumnOnTheLine(editor, line);
- column = nonSpaceColumn >= 1 ? nonSpaceColumn : 1;
+ if (softWrappedLines <= 0) {
+ column = nonSpaceColumn >= 0 ? nonSpaceColumn : 0;
+ }
+ else {
+ column = nonSpaceColumn >= 1 ? nonSpaceColumn : 1;
+ }
}
else {
int nonSpaceColumn = findFirstNonSpaceColumnOnTheLine(editor, currentVisual.line);
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java
index 7e7378af51f4..e7097de43bdb 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java
@@ -317,7 +317,7 @@ public class EditorUtil {
if (column == columnNumber) {
return offset;
}
- if (column > columnNumber && text.charAt(offset) == '\t') {
+ if (column > columnNumber && offset > 0 && text.charAt(offset - 1) == '\t') {
return offset - 1;
}
currentColumn.set(column);
@@ -419,15 +419,18 @@ public class EditorUtil {
public static int textWidthInColumns(@NotNull Editor editor, CharSequence text, int start, int end, int x) {
int result = 0;
int prevX;
+ int spaceSize = getSpaceWidth(Font.PLAIN, editor);
for (int i = start; i < end; i++) {
char c = text.charAt(i);
prevX = x;
switch (c) {
- case '\t': x = nextTabStop(x, editor); break;
+ case '\t':
+ x = nextTabStop(x, editor);
+ result += columnsNumber(x - prevX, spaceSize);
+ break;
case '\n': x = result = 0; break;
- default: x += charWidth(c, Font.PLAIN, editor);
+ default: x += charWidth(c, Font.PLAIN, editor); result++;
}
- result += columnsNumber(c, x, prevX, getSpaceWidth(Font.PLAIN, editor));
}
return result;
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/DefaultEditorTextRepresentationHelper.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/DefaultEditorTextRepresentationHelper.java
index a866ba0daa4f..790256ccfcd5 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/DefaultEditorTextRepresentationHelper.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/DefaultEditorTextRepresentationHelper.java
@@ -38,11 +38,6 @@ public class DefaultEditorTextRepresentationHelper implements EditorTextRepresen
return EditorUtil.textWidthInColumns(myEditor, text, start, end, x);
}
- @Override
- public int toVisualColumnSymbolsNumber(int width) {
- return EditorUtil.columnsNumber(width, EditorUtil.getSpaceWidth(Font.PLAIN, myEditor));
- }
-
@Override
public int textWidth(@NotNull CharSequence text, int start, int end, int x) {
return EditorUtil.textWidth(myEditor, text, start, end, Font.PLAIN, x);
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java
index c6e6602858aa..cf7a03f268df 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java
@@ -1033,7 +1033,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
int linesToSkip = logical.softWrapLinesOnCurrentLogicalLine;
List extends TextChange> softWraps = getSoftWrapModel().getSoftWrapsForLine(logLine);
for (TextChange softWrap : softWraps) {
- if (myFoldingModel.isOffsetCollapsed(softWrap.getStart())) {
+ if (myFoldingModel.isOffsetCollapsed(softWrap.getStart()) && myFoldingModel.isOffsetCollapsed(softWrap.getStart() - 1)) {
continue;
}
int lineFeeds = StringUtil.countNewLines(softWrap.getText());
@@ -1061,7 +1061,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
}
- if (logLine <= 0) {
+ if (logLine < 0) {
lineStartOffset = 0;
}
else if (lineStartOffset < 0) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorTextRepresentationHelper.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorTextRepresentationHelper.java
index 6e391667b15e..fcf97a1f59be 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorTextRepresentationHelper.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorTextRepresentationHelper.java
@@ -41,14 +41,6 @@ public interface EditorTextRepresentationHelper {
*/
int toVisualColumnSymbolsNumber(@NotNull CharSequence text, int start, int end, int x);
- /**
- * Allows to answer how many visual columns is necessary for representing text of the given width.
- *
- * @param width target width
- * @return number of visual columns necessary for representation of the text with the given width
- */
- int toVisualColumnSymbolsNumber(int width);
-
/**
* Allows to retrieve width (in pixels) necessary to represent given region ([start; end)) starting
* at the given 'x' offset from visual line start using given font type.
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java
index 3dd07cde9a4b..f508694a29f7 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java
@@ -17,6 +17,7 @@ package com.intellij.openapi.editor.impl;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.editor.ex.FoldingModelEx;
import com.intellij.openapi.editor.ex.SoftWrapChangeListener;
import com.intellij.openapi.editor.ex.SoftWrapModelEx;
import com.intellij.openapi.editor.ex.util.EditorUtil;
@@ -168,6 +169,7 @@ public class SoftWrapModelImpl implements SoftWrapModelEx {
}
}
+ @Override
public List extends TextChange> getRegisteredSoftWraps() {
if (!isSoftWrappingEnabled()) {
return Collections.emptyList();
@@ -175,6 +177,20 @@ public class SoftWrapModelImpl implements SoftWrapModelEx {
return myStorage.getSoftWraps();
}
+ @Override
+ public boolean isVisible(TextChange softWrap) {
+ FoldingModel foldingModel = myEditor.getFoldingModel();
+ int start = softWrap.getStart();
+ if (!foldingModel.isOffsetCollapsed(start)) {
+ return false;
+ }
+
+ // There is a possible case that soft wrap and collapsed folding region share the same offset, i.e. soft wrap is represented
+ // before the folding. We need to return 'true' in such situation. Hence, we check if offset just before the soft wrap
+ // is collapsed as well.
+ return start <= 0 || !foldingModel.isOffsetCollapsed(start - 1);
+ }
+
@Override
public int paint(@NotNull Graphics g, @NotNull SoftWrapDrawingType drawingType, int x, int y, int lineHeight) {
if (!isSoftWrappingEnabled()) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapDataMapper.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapDataMapper.java
index 9250d2cc4be1..87889a12274a 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapDataMapper.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapDataMapper.java
@@ -264,9 +264,8 @@ public class SoftWrapDataMapper {
int i = CharArrayUtil.shiftBackwardUntil(text, region.getEndOffset() - 1, "\n");
// Process multi-line folding.
if (i >= region.getStartOffset()) {
- int width = myTextRepresentationHelper.textWidth(text, i + 1, region.getEndOffset(), 0);
- afterFolding.logicalColumn = myTextRepresentationHelper.toVisualColumnSymbolsNumber(width);
- afterFolding.x = width;
+ afterFolding.x = myTextRepresentationHelper.textWidth(text, i + 1, region.getEndOffset(), 0);
+ afterFolding.logicalColumn = myTextRepresentationHelper.toVisualColumnSymbolsNumber(text, i + 1, region.getEndOffset(), 0);
afterFolding.softWrapLinesBefore += afterFolding.softWrapLinesCurrent;
afterFolding.softWrapLinesCurrent = 0;
afterFolding.softWrapColumnDiff = 0;
@@ -276,7 +275,9 @@ public class SoftWrapDataMapper {
// Process single-line folding
else {
int width = myTextRepresentationHelper.textWidth(text, region.getStartOffset(), region.getEndOffset(), context.x);
- int logicalColumnInc = myTextRepresentationHelper.toVisualColumnSymbolsNumber(width);
+ int logicalColumnInc = myTextRepresentationHelper.toVisualColumnSymbolsNumber(
+ text, region.getStartOffset(), region.getEndOffset(), context.x
+ );
afterFolding.logicalColumn += logicalColumnInc;
afterFolding.x += width;
afterFolding.foldingColumnDiff += visualColumnInc - logicalColumnInc;
@@ -342,19 +343,20 @@ public class SoftWrapDataMapper {
// Update state to the offset that corresponds to the same logical line that was used last time.
if (currentLogicalLine == lastUsedLogicalLine) {
int width = myTextRepresentationHelper.textWidth(text, result.offset, newOffset, result.x);
- int columnDiff = myTextRepresentationHelper.toVisualColumnSymbolsNumber(width);
+ int columnDiff = myTextRepresentationHelper.toVisualColumnSymbolsNumber(text, result.offset, newOffset, result.x);
result.x += width;
result.logicalColumn += columnDiff;
result.visualColumn += columnDiff;
}
- // Update state to the start of the folding that doesn't belong to the same logical line that was used last time.
+ // Update state to offset that doesn't correspond to the same logical line that was used last time.
else {
int lineDiff = currentLogicalLine - lastUsedLogicalLine;
result.logicalLine += lineDiff;
result.visualLine += lineDiff;
int startLineOffset = document.getLineStartOffset(currentLogicalLine);
- result.x = myTextRepresentationHelper.textWidth(text, startLineOffset, newOffset, result.x);
- result.visualColumn = myTextRepresentationHelper.toVisualColumnSymbolsNumber(result.x);
+ int newX = myTextRepresentationHelper.textWidth(text, startLineOffset, newOffset, result.x);
+ result.visualColumn = myTextRepresentationHelper.toVisualColumnSymbolsNumber(text, startLineOffset, newOffset, 0);
+ result.x = newX;
result.logicalColumn = result.visualColumn;
result.onNewLine();
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentSoftWrapModel.java b/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentSoftWrapModel.java
index 82d3d3c530d8..bd60686b00ef 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentSoftWrapModel.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentSoftWrapModel.java
@@ -53,6 +53,11 @@ public class TextComponentSoftWrapModel implements SoftWrapModel {
return Collections.emptyList();
}
+ @Override
+ public boolean isVisible(TextChange softWrap) {
+ return false;
+ }
+
@Override
public void beforeDocumentChangeAtCaret() {
}
diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapDataMapperTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapDataMapperTest.java
index 39b69460cdaa..a1dd059acccb 100644
--- a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapDataMapperTest.java
+++ b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapDataMapperTest.java
@@ -858,15 +858,6 @@ public class SoftWrapDataMapperTest {
return result;
}
- @Override
- public int toVisualColumnSymbolsNumber(int width) {
- int result = width / SPACE_SIZE;
- if (width % SPACE_SIZE > 0) {
- result++;
- }
- return result;
- }
-
@Override
public int textWidth(@NotNull CharSequence text, int start, int end, int x) {
int result = 0;