1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-03-05 15:32:51 +01:00

Fix keeping caret on screen with preceding inlay

This commit is contained in:
Matt Ellis 2020-09-16 18:58:21 +01:00
parent eabe43061c
commit fa17af8d33
No known key found for this signature in database
GPG Key ID: FA6025D54131324B
5 changed files with 69 additions and 37 deletions
src/com/maddyhome/idea/vim
test/org/jetbrains/plugins/ideavim/action/scroll

View File

@ -81,7 +81,7 @@ public class DigraphGroup {
}
private void showDigraphs(@NotNull Editor editor) {
int width = EditorHelper.getScreenWidth(editor);
int width = EditorHelper.getApproximateScreenWidth(editor);
if (width < 10) {
width = 80;
}

View File

@ -171,36 +171,40 @@ public class MotionGroup {
private static void moveCaretToView(@NotNull Editor editor) {
final int scrollOffset = getNormalizedScrollOffset(editor);
int topVisualLine = EditorHelper.getVisualLineAtTopOfScreen(editor);
int bottomVisualLine = EditorHelper.getVisualLineAtBottomOfScreen(editor);
int caretVisualLine = editor.getCaretModel().getVisualPosition().line;
int newVisualLine = caretVisualLine;
final int topVisualLine = EditorHelper.getVisualLineAtTopOfScreen(editor);
final int bottomVisualLine = EditorHelper.getVisualLineAtBottomOfScreen(editor);
final int caretVisualLine = editor.getCaretModel().getVisualPosition().line;
final int newVisualLine;
if (caretVisualLine < topVisualLine + scrollOffset) {
newVisualLine = EditorHelper.normalizeVisualLine(editor, topVisualLine + scrollOffset);
}
else if (caretVisualLine >= bottomVisualLine - scrollOffset) {
newVisualLine = EditorHelper.normalizeVisualLine(editor, bottomVisualLine - scrollOffset);
}
int sideScrollOffset = OptionsManager.INSTANCE.getSidescrolloff().value();
int width = EditorHelper.getScreenWidth(editor);
if (sideScrollOffset > width / 2) {
sideScrollOffset = width / 2;
else {
newVisualLine = caretVisualLine;
}
int col = editor.getCaretModel().getVisualPosition().column;
int oldColumn = col;
final int sideScrollOffset = getNormalizedSideScrollOffset(editor);
final int oldColumn = editor.getCaretModel().getVisualPosition().column;
int col = oldColumn;
if (col >= EditorHelper.getLineLength(editor) - 1) {
col = UserDataManager.getVimLastColumn(editor.getCaretModel().getPrimaryCaret());
}
int visualColumn = EditorHelper.getVisualColumnAtLeftOfScreen(editor, newVisualLine);
final int leftVisualColumn = EditorHelper.getVisualColumnAtLeftOfScreen(editor, newVisualLine);
final int rightVisualColumn = EditorHelper.getVisualColumnAtRightOfScreen(editor, newVisualLine);
int caretColumn = col;
int newColumn = caretColumn;
if (caretColumn < visualColumn + sideScrollOffset) {
newColumn = visualColumn + sideScrollOffset;
// TODO: Visual column arithmetic will be inaccurate as it include columns for inlays and folds
if (caretColumn < leftVisualColumn + sideScrollOffset) {
newColumn = leftVisualColumn + sideScrollOffset;
}
else if (caretColumn >= visualColumn + width - sideScrollOffset) {
newColumn = visualColumn + width - sideScrollOffset - 1;
else if (caretColumn > rightVisualColumn - sideScrollOffset) {
newColumn = rightVisualColumn - sideScrollOffset;
}
if (newVisualLine == caretVisualLine && newColumn != caretColumn) {
@ -270,10 +274,15 @@ public class MotionGroup {
}
private static int getNormalizedScrollOffset(final @NotNull Editor editor) {
int scrollOffset = OptionsManager.INSTANCE.getScrolloff().value();
final int scrollOffset = OptionsManager.INSTANCE.getScrolloff().value();
return EditorHelper.normalizeScrollOffset(editor, scrollOffset);
}
private static int getNormalizedSideScrollOffset(final @NotNull Editor editor) {
final int sideScrollOffset = OptionsManager.INSTANCE.getSidescrolloff().value();
return EditorHelper.normalizeSideScrollOffset(editor, sideScrollOffset);
}
public static void moveCaret(@NotNull Editor editor, @NotNull Caret caret, int offset) {
if (offset < 0 || offset > editor.getDocument().getTextLength() || !caret.isValid()) return;
@ -590,7 +599,7 @@ public class MotionGroup {
public boolean scrollCaretColumnToFirstScreenColumn(@NotNull Editor editor) {
final VisualPosition caretVisualPosition = editor.getCaretModel().getVisualPosition();
final int scrollOffset = Math.min(OptionsManager.INSTANCE.getSidescrolloff().value(), EditorHelper.getScreenWidth(editor) / 2);
final int scrollOffset = getNormalizedSideScrollOffset(editor);
// TODO: Should the offset be applied to visual columns? This includes inline inlays and folds
final int column = Math.max(0, caretVisualPosition.column - scrollOffset);
EditorHelper.scrollColumnToLeftOfScreen(editor, caretVisualPosition.line, column);
@ -599,7 +608,7 @@ public class MotionGroup {
public boolean scrollCaretColumnToLastScreenColumn(@NotNull Editor editor) {
final VisualPosition caretVisualPosition = editor.getCaretModel().getVisualPosition();
final int scrollOffset = Math.min(OptionsManager.INSTANCE.getSidescrolloff().value(), EditorHelper.getScreenWidth(editor) / 2);
final int scrollOffset = getNormalizedSideScrollOffset(editor);
// TODO: Should the offset be applied to visual columns? This includes inline inlays and folds
final int column = EditorHelper.normalizeVisualColumn(editor, caretVisualPosition.line, caretVisualPosition.column + scrollOffset, false);
EditorHelper.scrollColumnToRightOfScreen(editor, caretVisualPosition.line, column);
@ -751,8 +760,8 @@ public class MotionGroup {
final int currentVisualRightColumn = EditorHelper.getVisualColumnAtRightOfScreen(editor, position.line);
final int caretColumn = position.column;
final int halfWidth = EditorHelper.getScreenWidth(editor) / 2;
final int scrollOffset = Math.min(OptionsManager.INSTANCE.getSidescrolloff().value(), halfWidth);
final int halfWidth = EditorHelper.getApproximateScreenWidth(editor) / 2;
final int scrollOffset = getNormalizedSideScrollOffset(editor);
final EnumSet<CommandFlags> flags = CommandState.getInstance(editor).getExecutingCommandFlags();
final boolean allowSidescroll = !flags.contains(CommandFlags.FLAG_IGNORE_SIDE_SCROLL_JUMP);
@ -907,7 +916,7 @@ public class MotionGroup {
}
public int moveCaretToMiddleColumn(@NotNull Editor editor, @NotNull Caret caret) {
final int width = EditorHelper.getScreenWidth(editor) / 2;
final int width = EditorHelper.getApproximateScreenWidth(editor) / 2;
final int len = EditorHelper.getLineLength(editor);
return moveCaretToColumn(editor, caret, Math.max(0, Math.min(len - 1, width)), false);

View File

@ -183,8 +183,18 @@ public class EditorHelper {
}
/**
* Gets the number of lines than can be displayed on the screen at one time. This is rounded down to the
* nearest whole line if there is a partial line visible at the bottom of the screen.
* Best efforts to ensure the side scroll offset doesn't overlap itself and remains a sensible value. Inline inlays
* can cause this to work incorrectly.
* @param editor The editor to use to normalize the side scroll offset
* @param sideScrollOffset The value of the 'sidescroll' option
* @return The side scroll offset value to use
*/
public static int normalizeSideScrollOffset(final @NotNull Editor editor, int sideScrollOffset) {
return Math.min(sideScrollOffset, getApproximateScreenWidth(editor) / 2);
}
/**
* Gets the number of lines than can be displayed on the screen at one time.
*
* Note that this value is only approximate and should be avoided whenever possible!
*
@ -192,24 +202,20 @@ public class EditorHelper {
* @return The number of screen lines
*/
private static int getApproximateScreenHeight(final @NotNull Editor editor) {
int lh = editor.getLineHeight();
Rectangle area = getVisibleArea(editor);
int height = area.y + area.height - getVisualLineAtTopOfScreen(editor) * lh;
return height / lh;
return getVisibleArea(editor).height / editor.getLineHeight();
}
/**
* Gets the number of characters that are visible on a screen line
* Gets the number of characters that are visible on a screen line, based on screen width and assuming a fixed width
* font. It does not include inlays or folds.
*
* Note that this value is only approximate and should be avoided whenever possible!
*
* @param editor The editor
* @return The number of screen columns
*/
public static int getScreenWidth(final @NotNull Editor editor) {
Rectangle rect = getVisibleArea(editor);
Point pt = new Point(rect.width, 0);
VisualPosition vp = editor.xyToVisualPosition(pt);
return vp.column;
public static int getApproximateScreenWidth(final @NotNull Editor editor) {
return getVisibleArea(editor).width / EditorUtil.getPlainSpaceWidth(editor);
}
/**

View File

@ -314,7 +314,7 @@ object OptionsManager {
cols.sortBy { it.name }
extra.sortBy { it.name }
var width = EditorHelper.getScreenWidth(editor)
var width = EditorHelper.getApproximateScreenWidth(editor)
if (width < 20) {
width = 80
}

View File

@ -146,4 +146,21 @@ class ScrollColumnRightActionTest : VimTestCase() {
typeText(parseKeys("zh")) // 9
assertVisibleLineBounds(0, 49, 128) // 80 characters
}
fun `test scroll column to right with preceding inline inlay moves cursor at end of screen`() {
configureByColumns(200)
val inlay = myFixture.editor.inlayModel.addInlineElement(90, false, HintRenderer("test:"))!!
typeText(parseKeys("100|", "ze", "zh"))
assertPosition(0, 98)
assertVisibleLineBounds(0, 24, 98)
typeText(parseKeys("zh"))
assertPosition(0, 97)
assertVisibleLineBounds(0, 23, 97)
typeText(parseKeys("zh"))
assertPosition(0, 96)
assertVisibleLineBounds(0, 22, 96)
typeText(parseKeys("zh"))
assertPosition(0, 95)
assertVisibleLineBounds(0, 21, 95)
}
}