diff --git a/platform/editor-ui-api/src/com/intellij/openapi/editor/Editor.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/Editor.java
index 2b17a6bfb314..b952c217521c 100644
--- a/platform/editor-ui-api/src/com/intellij/openapi/editor/Editor.java
+++ b/platform/editor-ui-api/src/com/intellij/openapi/editor/Editor.java
@@ -236,6 +236,21 @@ public interface Editor extends UserDataHolder {
@NotNull
VisualPosition offsetToVisualPosition(int offset);
+ /**
+ * Maps an offset in the document to a visual position.
+ *
+ * It's assumed that original position is associated with character immediately preceding given offset,
+ * {@link VisualPosition#leansRight leansRight} value for visual position will be determined correspondingly.
+ *
+ * @param offset the offset in the document.
+ * @param leanForward if true, original position is associated with character after given offset, if false -
+ * with character before given offset. This can make a difference in bidirectional text (see {@link LogicalPosition},
+ * {@link VisualPosition})
+ * @return the corresponding visual position.
+ */
+ @NotNull
+ VisualPosition offsetToVisualPosition(int offset, boolean leanForward);
+
/**
* Maps the pixel coordinates in the editor to a logical position.
*
diff --git a/platform/editor-ui-api/src/com/intellij/openapi/editor/LogicalPosition.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/LogicalPosition.java
index 0def5003f1f2..dd69cc3edf78 100644
--- a/platform/editor-ui-api/src/com/intellij/openapi/editor/LogicalPosition.java
+++ b/platform/editor-ui-api/src/com/intellij/openapi/editor/LogicalPosition.java
@@ -207,7 +207,8 @@ public class LogicalPosition implements Comparable {
+ " (before=" + softWrapLinesBeforeCurrentLogicalLine + "; current=" + softWrapLinesOnCurrentLogicalLine + ")")
+ (softWrapColumnDiff == 0 ? "" : "; columns diff=" + softWrapColumnDiff + ";" )
+ (foldedLines == 0? "" : "; folding: lines = " + foldedLines + ";")
- + (foldingColumnDiff == 0 ? "" : "; columns diff=" + foldingColumnDiff);
+ + (foldingColumnDiff == 0 ? "" : "; columns diff=" + foldingColumnDiff)
+ + (leansForward ? "; leans forward" : "");
}
public int compareTo(LogicalPosition position) {
diff --git a/platform/editor-ui-api/src/com/intellij/openapi/editor/VisualPosition.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/VisualPosition.java
index 9622341f64e8..633d85678b18 100644
--- a/platform/editor-ui-api/src/com/intellij/openapi/editor/VisualPosition.java
+++ b/platform/editor-ui-api/src/com/intellij/openapi/editor/VisualPosition.java
@@ -79,7 +79,7 @@ public class VisualPosition {
@NonNls
public String toString() {
- return "VisualPosition: (" + line + ", " + column+")";
+ return "VisualPosition: (" + line + ", " + column+")" + (leansRight ? " leans right" : "");
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/config/LazyEditor.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/config/LazyEditor.java
index 6df7df7d1e25..8b249eb78eae 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/config/LazyEditor.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/config/LazyEditor.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2015 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.intellij.codeInsight.intention.impl.config;
import com.intellij.openapi.editor.*;
@@ -167,6 +182,12 @@ class LazyEditor extends UserDataHolderBase implements Editor {
return getEditor().offsetToVisualPosition(offset);
}
+ @Override
+ @NotNull
+ public VisualPosition offsetToVisualPosition(int offset, boolean leanForward) {
+ return getEditor().offsetToVisualPosition(offset, leanForward);
+ }
+
@Override
@NotNull
public LogicalPosition xyToLogicalPosition(@NotNull final Point p) {
diff --git a/platform/lang-impl/src/com/intellij/injected/editor/EditorWindowImpl.java b/platform/lang-impl/src/com/intellij/injected/editor/EditorWindowImpl.java
index d1bac9b4b116..69eb3446343e 100644
--- a/platform/lang-impl/src/com/intellij/injected/editor/EditorWindowImpl.java
+++ b/platform/lang-impl/src/com/intellij/injected/editor/EditorWindowImpl.java
@@ -382,6 +382,12 @@ public class EditorWindowImpl extends UserDataHolderBase implements EditorWindow
return logicalToVisualPosition(offsetToLogicalPosition(offset));
}
+ @Override
+ @NotNull
+ public VisualPosition offsetToVisualPosition(int offset, boolean leanForward) {
+ return logicalToVisualPosition(offsetToLogicalPosition(offset).leanForward(leanForward));
+ }
+
@Override
@NotNull
public LogicalPosition offsetToLogicalPosition(final int offset) {
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 b6cea0d25428..ed980b0530f7 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
@@ -79,7 +79,7 @@ public final class EditorUtil {
int resultLogLine = Math.min(lastLogLine, lastLine);
VisualPosition resVisStart = editor.offsetToVisualPosition(document.getLineStartOffset(resultLogLine));
- VisualPosition resVisEnd = editor.offsetToVisualPosition(document.getLineEndOffset(resultLogLine));
+ VisualPosition resVisEnd = editor.offsetToVisualPosition(document.getLineEndOffset(resultLogLine), true);
// Target logical line is not soft wrap affected.
if (resVisStart.line == resVisEnd.line) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java
index 9ad9e986fa88..a46a79654db8 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java
@@ -428,6 +428,8 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
int softWrapLinesBefore = pos.softWrapLinesBeforeCurrentLogicalLine;
int softWrapLinesCurrent = pos.softWrapLinesOnCurrentLogicalLine;
int softWrapColumns = pos.softWrapColumnDiff;
+ boolean leansForward = pos.leansForward;
+ boolean leansRight = pos.visualPositionLeansRight;
Document doc = myEditor.getDocument();
@@ -457,6 +459,8 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
if (column > lineEndColumnNumber) {
int oldColumn = column;
column = lineEndColumnNumber;
+ leansForward = true;
+ leansRight = true;
if (softWrapColumns != 0) {
softWrapColumns -= column - lineEndColumnNumber;
}
@@ -478,11 +482,11 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
if (pos.visualPositionAware) {
logicalPositionToUse = new LogicalPosition(
line, column, softWrapLinesBefore, softWrapLinesCurrent, softWrapColumns, pos.foldedLines, pos.foldingColumnDiff,
- pos.leansForward, pos.visualPositionLeansRight
+ leansForward, leansRight
);
}
else {
- logicalPositionToUse = new LogicalPosition(line, column);
+ logicalPositionToUse = new LogicalPosition(line, column, leansForward);
}
final int offset = myEditor.logicalPositionToOffset(logicalPositionToUse);
if (debugBuffer != null) {
@@ -628,6 +632,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
myDesiredX = -1;
int column = pos.column;
int line = pos.line;
+ boolean leanRight = pos.leansRight;
int lastLine = myEditor.getVisibleLineCount() - 1;
if (lastLine <= 0) {
@@ -644,6 +649,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
int lineEndColumn = EditorUtil.getLastVisualLineColumnNumber(myEditor, line);
if (column > lineEndColumn) {
column = lineEndColumn;
+ leanRight = true;
}
if (column < 0 && line > 0) {
@@ -652,7 +658,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
}
}
- myVisibleCaret = new VisualPosition(line, column);
+ myVisibleCaret = new VisualPosition(line, column, leanRight);
VerticalInfo oldInfo = myCaretInfo;
LogicalPosition oldPosition = myLogicalCaret;
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 bc8db2ba70a0..04306f4c4754 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
@@ -1420,9 +1420,10 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
return offsetToVisualPosition(offset, false);
}
+ @Override
@NotNull
- public VisualPosition offsetToVisualPosition(int offset, boolean leanTowardsLargerOffsets) {
- if (myUseNewRendering) return myView.offsetToVisualPosition(offset, leanTowardsLargerOffsets);
+ public VisualPosition offsetToVisualPosition(int offset, boolean leanForward) {
+ if (myUseNewRendering) return myView.offsetToVisualPosition(offset, leanForward);
return logicalToVisualPosition(offsetToLogicalPosition(offset));
}
@@ -4096,6 +4097,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
int softWrapLinesBeforeTargetLogicalLine = pos.softWrapLinesBeforeCurrentLogicalLine;
int softWrapLinesOnTargetLogicalLine = pos.softWrapLinesOnCurrentLogicalLine;
int softWrapColumns = pos.softWrapColumnDiff;
+ boolean leansForward = pos.leansForward;
+ boolean leansRight = pos.visualPositionLeansRight;
final int totalLines = myDocument.getLineCount();
if (totalLines <= 0) {
@@ -4120,6 +4123,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
int lineEndColumn = calcColumnNumber(lineEndOffset, line);
if (column > lineEndColumn) {
column = lineEndColumn;
+ leansForward = true;
+ leansRight = true;
if (softWrapColumns != 0) {
softWrapColumns -= column - lineEndColumn;
}
@@ -4135,10 +4140,12 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
}
}
- return new LogicalPosition(
- line, column, softWrapLinesBeforeTargetLogicalLine, softWrapLinesOnTargetLogicalLine, softWrapColumns,
- pos.foldedLines, pos.foldingColumnDiff, pos.leansForward, pos.visualPositionLeansRight
- );
+ return pos.visualPositionAware ?
+ new LogicalPosition(
+ line, column, softWrapLinesBeforeTargetLogicalLine, softWrapLinesOnTargetLogicalLine, softWrapColumns,
+ pos.foldedLines, pos.foldingColumnDiff, leansForward, leansRight
+ ) :
+ new LogicalPosition(line, column, leansForward);
}
private boolean checkIgnore(@NotNull MouseEvent e, boolean isFinalCheck) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorCoordinateMapper.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorCoordinateMapper.java
index 3ee82b71b8e5..210de70daca5 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorCoordinateMapper.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorCoordinateMapper.java
@@ -264,7 +264,7 @@ class EditorCoordinateMapper {
int remainingShift = (int)(p.x - x);
int additionalColumns = remainingShift <= 0 ? 0 : (remainingShift + plainSpaceWidth / 2) / plainSpaceWidth;
return new VisualPosition(visualLine, lastColumn + additionalColumns,
- remainingShift >= 0 && additionalColumns == remainingShift / plainSpaceWidth);
+ remainingShift > 0 && additionalColumns == (remainingShift - 1) / plainSpaceWidth);
}
@NotNull
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/TabFragment.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/TabFragment.java
index dc903dba9335..42ae2fca8ac9 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/TabFragment.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/TabFragment.java
@@ -81,14 +81,14 @@ class TabFragment implements LineFragment {
@Override
public int[] xToVisualColumn(float startX, float x) {
- if (x < startX) return new int[] {0, 0};
+ if (x <= startX) return new int[] {0, 0};
float nextTabStop = getNextTabStop(startX);
- if (x >= nextTabStop) return new int[] {getVisualColumnCount(startX), 1};
+ if (x > nextTabStop) return new int[] {getVisualColumnCount(startX), 1};
int column, columnWithoutRounding;
if (myEditor.getSettings().isCaretInsideTabs()) {
int plainSpaceWidth = myView.getPlainSpaceWidth();
column = ((int)(x - startX) + plainSpaceWidth / 2) / plainSpaceWidth;
- columnWithoutRounding = ((int)(x - startX)) / plainSpaceWidth;
+ columnWithoutRounding = ((int)(x - startX - 1)) / plainSpaceWidth;
}
else {
column = x > (startX + nextTabStop) / 2 ? getVisualColumnCount(startX) : 0;
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/TextFragment.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/TextFragment.java
index 01d4b0c447c4..fc01eb01b59a 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/TextFragment.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/TextFragment.java
@@ -155,11 +155,11 @@ class TextFragment implements LineFragment {
for (int i = 0; i < myCharPositions.length; i++) {
float newPos = myCharPositions[i];
if (relX < (newPos + prevPos) / 2) {
- return new int[] {i, relX < prevPos ? 0 : 1};
+ return new int[] {i, relX <= prevPos ? 0 : 1};
}
prevPos = newPos;
}
- return new int[] {myCharPositions.length, relX < myCharPositions[myCharPositions.length - 1] ? 0 : 1};
+ return new int[] {myCharPositions.length, relX <= myCharPositions[myCharPositions.length - 1] ? 0 : 1};
}
@Override
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentEditor.java b/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentEditor.java
index 486a7c511016..6fd2e848cb48 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentEditor.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentEditor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -200,6 +200,12 @@ public class TextComponentEditor extends UserDataHolderBase implements Editor {
return new VisualPosition(line, offset - lineStartOffset);
}
+ @NotNull
+ @Override
+ public VisualPosition offsetToVisualPosition(int offset, boolean leanForward) {
+ return offsetToVisualPosition(offset);
+ }
+
@Override
@NotNull
public LogicalPosition xyToLogicalPosition(@NotNull final Point p) {
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorRtlTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorRtlTest.java
index a1682e9c77d3..0d773e4a94c0 100644
--- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorRtlTest.java
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorRtlTest.java
@@ -44,11 +44,11 @@ public class EditorRtlTest extends AbstractEditorTest {
public void testPositionCalculations() throws IOException {
init("llrr");
- checkOffsetConversions(0, lP(0), vL(0), vR(0), xy(0));
- checkOffsetConversions(1, lP(1), vL(1), vR(1), xy(10));
- checkOffsetConversions(2, lP(2), vL(2), vL(4), xy(20), xy(40));
- checkOffsetConversions(3, lP(3), vR(3), vL(3), xy(30));
- checkOffsetConversions(4, lP(4), vR(2), vR(4), xy(20), xy(40));
+ checkOffsetConversions(0, lB(0), vL(0), vR(0), xy(0));
+ checkOffsetConversions(1, lB(1), vL(1), vR(1), xy(10));
+ checkOffsetConversions(2, lB(2), vL(2), vL(4), xy(20), xy(40));
+ checkOffsetConversions(3, lB(3), vR(3), vL(3), xy(30));
+ checkOffsetConversions(4, lB(4), vR(2), vR(4), xy(20), xy(40));
checkLPConversions(0, 0, vL(0), vR(0));
checkLPConversions(1, 1, vL(1), vR(1));
@@ -59,22 +59,22 @@ public class EditorRtlTest extends AbstractEditorTest {
checkLPConversions(l(1, 0, false), 4, v(1, 0, false));
checkLPConversions(l(1, 0, true), 4, v(1, 0, true));
- checkVPConversions(vL(0), lP(0), xy(0));
- checkVPConversions(vR(0), lS(0), xy(0));
- checkVPConversions(vL(1), lP(1), xy(10));
- checkVPConversions(vR(1), lS(1), xy(10));
- checkVPConversions(vL(2), lP(2), xy(20));
- checkVPConversions(vR(2), lP(4), xy(20));
- checkVPConversions(vL(3), lS(3), xy(30));
- checkVPConversions(vR(3), lP(3), xy(30));
- checkVPConversions(vL(4), lS(2), xy(40));
- checkVPConversions(vR(4), lS(4), xy(40));
- checkVPConversions(vL(5), lP(5), xy(50));
- checkVPConversions(vR(5), lS(5), xy(50));
+ checkVPConversions(vL(0), lB(0), xy(0));
+ checkVPConversions(vR(0), lF(0), xy(0));
+ checkVPConversions(vL(1), lB(1), xy(10));
+ checkVPConversions(vR(1), lF(1), xy(10));
+ checkVPConversions(vL(2), lB(2), xy(20));
+ checkVPConversions(vR(2), lB(4), xy(20));
+ checkVPConversions(vL(3), lF(3), xy(30));
+ checkVPConversions(vR(3), lB(3), xy(30));
+ checkVPConversions(vL(4), lF(2), xy(40));
+ checkVPConversions(vR(4), lF(4), xy(40));
+ checkVPConversions(vL(5), lB(5), xy(50));
+ checkVPConversions(vR(5), lF(5), xy(50));
checkVPConversions(v(1, 0, false), l(1, 0, false), xy(0, 10));
checkVPConversions(v(1, 0, true), l(1, 0, true), xy(0, 10));
- checkXYConversion(xy(0), vR(0));
+ checkXYConversion(xy(0), vL(0));
checkXYConversion(xy(12), vR(1));
checkXYConversion(xy(19), vL(2));
checkXYConversion(xy(21), vR(2));
@@ -87,13 +87,13 @@ public class EditorRtlTest extends AbstractEditorTest {
public void testNumberInsideRtlText() throws IOException {
init("rr12rr");
- checkOffsetConversions(0, lP(0), vL(0), vL(6), xy(0), xy(60));
- checkOffsetConversions(1, lP(1), vR(5), vL(5), xy(50));
- checkOffsetConversions(2, lP(2), vR(4), vR(2), xy(40), xy(20));
- checkOffsetConversions(3, lP(3), vL(3), vR(3), xy(30));
- checkOffsetConversions(4, lP(4), vL(4), vL(2), xy(40), xy(20));
- checkOffsetConversions(5, lP(5), vR(1), vL(1), xy(10));
- checkOffsetConversions(6, lP(6), vR(0), vR(6), xy(0), xy(60));
+ checkOffsetConversions(0, lB(0), vL(0), vL(6), xy(0), xy(60));
+ checkOffsetConversions(1, lB(1), vR(5), vL(5), xy(50));
+ checkOffsetConversions(2, lB(2), vR(4), vR(2), xy(40), xy(20));
+ checkOffsetConversions(3, lB(3), vL(3), vR(3), xy(30));
+ checkOffsetConversions(4, lB(4), vL(4), vL(2), xy(40), xy(20));
+ checkOffsetConversions(5, lB(5), vR(1), vL(1), xy(10));
+ checkOffsetConversions(6, lB(6), vR(0), vR(6), xy(0), xy(60));
checkLPConversions(0, 0, vL(0), vL(6));
checkLPConversions(1, 1, vR(5), vL(5));
@@ -103,29 +103,29 @@ public class EditorRtlTest extends AbstractEditorTest {
checkLPConversions(5, 5, vR(1), vL(1));
checkLPConversions(6, 6, vR(0), vR(6));
- checkVPConversions(vL(0), lP(0), xy(0));
- checkVPConversions(vR(0), lP(6), xy(0));
- checkVPConversions(vL(1), lS(5), xy(10));
- checkVPConversions(vR(1), lP(5), xy(10));
- checkVPConversions(vL(2), lS(4), xy(20));
- checkVPConversions(vR(2), lS(2), xy(20));
- checkVPConversions(vL(3), lP(3), xy(30));
- checkVPConversions(vR(3), lS(3), xy(30));
- checkVPConversions(vL(4), lP(4), xy(40));
- checkVPConversions(vR(4), lP(2), xy(40));
- checkVPConversions(vL(5), lS(1), xy(50));
- checkVPConversions(vR(5), lP(1), xy(50));
- checkVPConversions(vL(6), lS(0), xy(60));
- checkVPConversions(vR(6), lS(6), xy(60));
+ checkVPConversions(vL(0), lB(0), xy(0));
+ checkVPConversions(vR(0), lB(6), xy(0));
+ checkVPConversions(vL(1), lF(5), xy(10));
+ checkVPConversions(vR(1), lB(5), xy(10));
+ checkVPConversions(vL(2), lF(4), xy(20));
+ checkVPConversions(vR(2), lF(2), xy(20));
+ checkVPConversions(vL(3), lB(3), xy(30));
+ checkVPConversions(vR(3), lF(3), xy(30));
+ checkVPConversions(vL(4), lB(4), xy(40));
+ checkVPConversions(vR(4), lB(2), xy(40));
+ checkVPConversions(vL(5), lF(1), xy(50));
+ checkVPConversions(vR(5), lB(1), xy(50));
+ checkVPConversions(vL(6), lF(0), xy(60));
+ checkVPConversions(vR(6), lF(6), xy(60));
checkXYConversion(xy(1), vR(0));
checkXYConversion(xy(9), vL(1));
checkXYConversion(xy(19), vL(2));
checkXYConversion(xy(21), vR(2));
- checkXYConversion(xy(30), vR(3));
+ checkXYConversion(xy(30), vL(3));
checkXYConversion(xy(39), vL(4));
checkXYConversion(xy(41), vR(4));
- checkXYConversion(xy(50), vR(5));
+ checkXYConversion(xy(50), vL(5));
checkXYConversion(xy(59), vL(6));
checkXYConversion(xy(61), vR(6));
}
@@ -134,13 +134,13 @@ public class EditorRtlTest extends AbstractEditorTest {
init("rrrrrr");
addCollapsedFoldRegion(2, 4, "...");
- checkOffsetConversions(0, lP(0), vL(0), vL(2), xy(0), xy(20));
- checkOffsetConversions(1, lP(1), vR(1), vL(1), xy(10));
- checkOffsetConversions(2, lP(2), vR(0), vR(2), xy(0), xy(20));
- checkOffsetConversions(3, lP(3), vR(2), vR(2), xy(20));
- checkOffsetConversions(4, lP(4), vL(5), vL(7), xy(50), xy(70));
- checkOffsetConversions(5, lP(5), vR(6), vL(6), xy(60));
- checkOffsetConversions(6, lP(6), vR(5), vR(7), xy(50), xy(70));
+ checkOffsetConversions(0, lB(0), vL(0), vL(2), xy(0), xy(20));
+ checkOffsetConversions(1, lB(1), vR(1), vL(1), xy(10));
+ checkOffsetConversions(2, lB(2), vR(0), vR(2), xy(0), xy(20));
+ checkOffsetConversions(3, lB(3), vR(2), vR(2), xy(20));
+ checkOffsetConversions(4, lB(4), vL(5), vL(7), xy(50), xy(70));
+ checkOffsetConversions(5, lB(5), vR(6), vL(6), xy(60));
+ checkOffsetConversions(6, lB(6), vR(5), vR(7), xy(50), xy(70));
checkLPConversions(0, 0, vL(0), vL(2));
checkLPConversions(1, 1, vR(1), vL(1));
@@ -151,33 +151,33 @@ public class EditorRtlTest extends AbstractEditorTest {
checkLPConversions(6, 6, vR(5), vR(7));
checkLPConversions(7, 6, vL(8), vR(8));
- checkVPConversions(vL(0), lP(0), xy(0));
- checkVPConversions(vR(0), lP(2), xy(0));
- checkVPConversions(vL(1), lS(1), xy(10));
- checkVPConversions(vR(1), lP(1), xy(10));
- checkVPConversions(vL(2), lS(0), xy(20));
- checkVPConversions(vR(2), lS(2), xy(20));
- checkVPConversions(vL(3), lS(2), xy(30));
- checkVPConversions(vR(3), lS(2), xy(30));
- checkVPConversions(vL(4), lS(2), xy(40));
- checkVPConversions(vR(4), lS(2), xy(40));
- checkVPConversions(vL(5), lP(4), xy(50));
- checkVPConversions(vR(5), lP(6), xy(50));
- checkVPConversions(vL(6), lS(5), xy(60));
- checkVPConversions(vR(6), lP(5), xy(60));
- checkVPConversions(vL(7), lS(4), xy(70));
- checkVPConversions(vR(7), lS(6), xy(70));
- checkVPConversions(vL(8), lP(7), xy(80));
- checkVPConversions(vR(8), lS(7), xy(80));
+ checkVPConversions(vL(0), lB(0), xy(0));
+ checkVPConversions(vR(0), lB(2), xy(0));
+ checkVPConversions(vL(1), lF(1), xy(10));
+ checkVPConversions(vR(1), lB(1), xy(10));
+ checkVPConversions(vL(2), lF(0), xy(20));
+ checkVPConversions(vR(2), lF(2), xy(20));
+ checkVPConversions(vL(3), lF(2), xy(30));
+ checkVPConversions(vR(3), lF(2), xy(30));
+ checkVPConversions(vL(4), lF(2), xy(40));
+ checkVPConversions(vR(4), lF(2), xy(40));
+ checkVPConversions(vL(5), lB(4), xy(50));
+ checkVPConversions(vR(5), lB(6), xy(50));
+ checkVPConversions(vL(6), lF(5), xy(60));
+ checkVPConversions(vR(6), lB(5), xy(60));
+ checkVPConversions(vL(7), lF(4), xy(70));
+ checkVPConversions(vR(7), lF(6), xy(70));
+ checkVPConversions(vL(8), lB(7), xy(80));
+ checkVPConversions(vR(8), lF(7), xy(80));
checkXYConversion(xy(1), vR(0));
checkXYConversion(xy(9), vL(1));
checkXYConversion(xy(19), vL(2));
checkXYConversion(xy(21), vR(2));
- checkXYConversion(xy(30), vR(3));
+ checkXYConversion(xy(30), vL(3));
checkXYConversion(xy(39), vL(4));
checkXYConversion(xy(41), vR(4));
- checkXYConversion(xy(50), vR(5));
+ checkXYConversion(xy(50), vL(5));
checkXYConversion(xy(59), vL(6));
checkXYConversion(xy(69), vL(7));
checkXYConversion(xy(71), vR(7));
@@ -188,10 +188,10 @@ public class EditorRtlTest extends AbstractEditorTest {
init("r r");
addCollapsedFoldRegion(1, 2, "...");
- checkOffsetConversions(0, lP(0), vL(0), vL(1), xy(0), xy(10));
- checkOffsetConversions(1, lP(1), vR(0), vR(1), xy(0), xy(10));
- checkOffsetConversions(2, lP(2), vL(4), vL(5), xy(40), xy(50));
- checkOffsetConversions(3, lP(3), vR(4), vR(5), xy(40), xy(50));
+ checkOffsetConversions(0, lB(0), vL(0), vL(1), xy(0), xy(10));
+ checkOffsetConversions(1, lB(1), vR(0), vR(1), xy(0), xy(10));
+ checkOffsetConversions(2, lB(2), vL(4), vL(5), xy(40), xy(50));
+ checkOffsetConversions(3, lB(3), vR(4), vR(5), xy(40), xy(50));
}
public void testFoldingInInnerBidiRun() throws IOException {
@@ -204,6 +204,36 @@ public class EditorRtlTest extends AbstractEditorTest {
checkLPConversions(3, 3, vR(4), vR(5));
checkLPConversions(4, 4, vL(6), vR(6));
}
+
+ public void testSelectingRtlLineByDraggingMouseFromLeftToRight() throws IOException {
+ init("r");
+ setEditorVisibleSize(1000, 1000);
+ mouse().pressAtXY(0, 5).dragToXY(15, 5).release();
+
+ assertEquals(0, myEditor.getSelectionModel().getSelectionStart());
+ assertEquals(1, myEditor.getSelectionModel().getSelectionEnd());
+ }
+
+ public void testSelectingRtlLineByDraggingMouseFromRightToLeft() throws IOException {
+ init("r");
+ setEditorVisibleSize(1000, 1000);
+ mouse().pressAtXY(15, 5).dragToXY(0, 5).release();
+
+ assertEquals(0, myEditor.getSelectionModel().getSelectionStart());
+ assertEquals(1, myEditor.getSelectionModel().getSelectionEnd());
+ }
+
+ public void testMovingCaretToLogicalLineEnd() throws IOException {
+ init("r");
+ myEditor.getCaretModel().moveToLogicalPosition(lF(1));
+ assertVisualPositionsEqual("Wrong visual position", vR(1), myEditor.getCaretModel().getVisualPosition());
+ }
+
+ public void testMovingCaretToVisualLineEnd() throws IOException {
+ init("r");
+ myEditor.getCaretModel().moveToVisualPosition(vR(1));
+ assertLogicalPositionsEqual("Wrong logical position", lF(1), myEditor.getCaretModel().getLogicalPosition());
+ }
private void init(String text) throws IOException {
initText(text.replace(RTL_CHAR_REPRESENTATION, RTL_CHAR));
@@ -238,8 +268,8 @@ public class EditorRtlTest extends AbstractEditorTest {
private static void checkLPConversions(int logicalColumn, int offset,
VisualPosition visualPositionForPrecedingLp, VisualPosition visualPositionForSucceedingLp) {
- checkLPConversions(lP(logicalColumn), offset, visualPositionForPrecedingLp);
- checkLPConversions(lS(logicalColumn), offset, visualPositionForSucceedingLp);
+ checkLPConversions(lB(logicalColumn), offset, visualPositionForPrecedingLp);
+ checkLPConversions(lF(logicalColumn), offset, visualPositionForSucceedingLp);
}
@@ -270,13 +300,13 @@ public class EditorRtlTest extends AbstractEditorTest {
assertEquals(message + " (direction flag)", expectedPosition.leansRight, actualPosition.leansRight);
}
- // logical position leaning to the preceding character
- private static LogicalPosition lP(int column) {
+ // logical position leaning backward
+ private static LogicalPosition lB(int column) {
return new LogicalPosition(0, column);
}
- // logical position leaning to the succeeding character
- private static LogicalPosition lS(int column) {
+ // logical position leaning forward
+ private static LogicalPosition lF(int column) {
return new LogicalPosition(0, column, true);
}
diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/EditorMouseFixture.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/EditorMouseFixture.java
index b531a0648f07..3324e80b8f17 100644
--- a/platform/testFramework/src/com/intellij/testFramework/fixtures/EditorMouseFixture.java
+++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/EditorMouseFixture.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,13 +37,16 @@ public class EditorMouseFixture {
myEditor = editor;
}
- public EditorMouseFixture pressAt(int visualLine, int visualColumn) {
- return pressAt(1, visualLine, visualColumn);
+ public EditorMouseFixture pressAtXY(int x, int y) {
+ return pressAt(1, new Point(x, y));
}
- private EditorMouseFixture pressAt(int clickCount, int visualLine, int visualColumn) {
+ public EditorMouseFixture pressAt(int visualLine, int visualColumn) {
+ return pressAt(1, getPoint(visualLine, visualColumn));
+ }
+
+ private EditorMouseFixture pressAt(int clickCount, Point p) {
JComponent component = myEditor.getContentComponent();
- Point p = getPoint(visualLine, visualColumn);
component.dispatchEvent(new MouseEvent(component,
myLastId = MouseEvent.MOUSE_PRESSED,
System.currentTimeMillis(),
@@ -91,22 +94,26 @@ public class EditorMouseFixture {
}
public EditorMouseFixture doubleClickAt(int visualLine, int visualColumn) {
- return clickAt(visualLine, visualColumn).pressAt(2, visualLine, visualColumn).release(2);
+ return clickAt(visualLine, visualColumn).pressAt(2, getPoint(visualLine, visualColumn)).release(2);
}
public EditorMouseFixture tripleClickAt(int visualLine, int visualColumn) {
- return doubleClickAt(visualLine, visualColumn).pressAt(3, visualLine, visualColumn).release(3);
+ return doubleClickAt(visualLine, visualColumn).pressAt(3, getPoint(visualLine, visualColumn)).release(3);
}
public EditorMouseFixture dragTo(int visualLine, int visualColumn) {
- JComponent component = myEditor.getContentComponent();
Point p = getPoint(visualLine, visualColumn);
+ return dragToXY(p.x, p.y);
+ }
+
+ public EditorMouseFixture dragToXY(int x, int y) {
+ JComponent component = myEditor.getContentComponent();
component.dispatchEvent(new MouseEvent(component,
myLastId = MouseEvent.MOUSE_DRAGGED,
System.currentTimeMillis(),
getModifiers(),
- myX = p.x,
- myY = p.y,
+ myX = x,
+ myY = y,
1,
false,
myButton));