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:
parent
eabe43061c
commit
fa17af8d33
src/com/maddyhome/idea/vim
test/org/jetbrains/plugins/ideavim/action/scroll
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user