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));