From 522b79dc7b1f25576e4bf44277f5e49bfa46cd9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Techet?= Date: Thu, 25 Apr 2024 14:25:31 +0200 Subject: [PATCH 1/2] vimode: Take into account folded lines when moving cursor We need to perform the moves based on visible lines and not plain document lines as the latter may be folded and then the moves are made incorrectly. --- vimode/src/cmds/motion.c | 74 ++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/vimode/src/cmds/motion.c b/vimode/src/cmds/motion.c index 4492d98c9..d528d5d5d 100644 --- a/vimode/src/cmds/motion.c +++ b/vimode/src/cmds/motion.c @@ -41,9 +41,39 @@ void cmd_goto_right(CmdContext *c, CmdParams *p) } +static gint doc_line_from_visible_delta(CmdParams *p, gint line, gint delta, gboolean *overflow) +{ + gboolean oflow = FALSE; + gint new_line = line; + gint i = 0; + + while (i < ABS(delta)) + { + gint inc = delta > 0 ? 1 : -1; + gint tmp = new_line + inc; + + if (tmp < 0 || tmp >= p->line_num) + { + oflow = TRUE; + break; + } + new_line = tmp; + + if (SSM(p->sci, SCI_GETLINEVISIBLE, new_line, 0)) + i++; + } + + if (overflow) + *overflow = oflow; + + return new_line; +} + + void cmd_goto_up(CmdContext *c, CmdParams *p) { gint one_above, pos; + gboolean line_underflow; if (p->line == 0) return; @@ -53,8 +83,8 @@ void cmd_goto_up(CmdContext *c, CmdParams *p) * SCI_CHOOSECARETX which we cannot read directly from Scintilla and which * we want to keep - perform jump to previous/following line and add * one final SCI_LINEUP/SCI_LINEDOWN which recovers SCI_CHOOSECARETX for us. */ - one_above = p->line - p->num - 1; - if (one_above >= 0) + one_above = doc_line_from_visible_delta(p, p->line, -p->num - 1, &line_underflow); + if (!line_underflow) { /* Every case except for the first line - go one line above and perform * SCI_LINEDOWN. This ensures that even with wrapping on, we get the @@ -70,7 +100,7 @@ void cmd_goto_up(CmdContext *c, CmdParams *p) * on, we need to repeat SCI_LINEUP to get to the first line of wrapping. * This may lead to visible slow scrolling which is why there's the * fast case above for anything else but the first line. */ - gint one_below = p->line - p->num + 1; + gint one_below = doc_line_from_visible_delta(p, p->line, -p->num + 1, NULL); gint wrap_count; one_below = one_below > 0 ? one_below : 1; @@ -98,15 +128,13 @@ void cmd_goto_up_nonempty(CmdContext *c, CmdParams *p) static void goto_down(CmdParams *p, gint num) { gint one_above, pos; - gint last_line = p->line_num - 1; - if (p->line == last_line) + if (p->line >= p->line_num - 1) return; - /* see cmd_goto_up() for explanation */ - one_above = p->line + num - 1; - one_above = one_above < last_line ? one_above : last_line - 1; + one_above = doc_line_from_visible_delta(p, p->line, p->num - 1, NULL); pos = SSM(p->sci, SCI_GETLINEENDPOSITION, one_above, 0); + SET_POS_NOX(p->sci, pos, FALSE); SSM(p->sci, SCI_LINEDOWN, 0, 0); } @@ -136,7 +164,7 @@ void cmd_goto_down_one_less_nonempty(CmdContext *c, CmdParams *p) void cmd_goto_page_up(CmdContext *c, CmdParams *p) { gint shift = p->line_visible_num * p->num; - gint new_line = get_line_number_rel(p->sci, -shift); + gint new_line = doc_line_from_visible_delta(p, p->line, -shift, NULL); goto_nonempty(p->sci, new_line, TRUE); } @@ -144,7 +172,7 @@ void cmd_goto_page_up(CmdContext *c, CmdParams *p) void cmd_goto_page_down(CmdContext *c, CmdParams *p) { gint shift = p->line_visible_num * p->num; - gint new_line = get_line_number_rel(p->sci, shift); + gint new_line = doc_line_from_visible_delta(p, p->line, shift, NULL); goto_nonempty(p->sci, new_line, TRUE); } @@ -152,7 +180,7 @@ void cmd_goto_page_down(CmdContext *c, CmdParams *p) void cmd_goto_halfpage_up(CmdContext *c, CmdParams *p) { gint shift = p->num_present ? p->num : p->line_visible_num / 2; - gint new_line = get_line_number_rel(p->sci, -shift); + gint new_line = doc_line_from_visible_delta(p, p->line, -shift, NULL); goto_nonempty(p->sci, new_line, TRUE); } @@ -160,7 +188,7 @@ void cmd_goto_halfpage_up(CmdContext *c, CmdParams *p) void cmd_goto_halfpage_down(CmdContext *c, CmdParams *p) { gint shift = p->num_present ? p->num : p->line_visible_num / 2; - gint new_line = get_line_number_rel(p->sci, shift); + gint new_line = doc_line_from_visible_delta(p, p->line, shift, NULL); goto_nonempty(p->sci, new_line, TRUE); } @@ -168,7 +196,8 @@ void cmd_goto_halfpage_down(CmdContext *c, CmdParams *p) void cmd_goto_line(CmdContext *c, CmdParams *p) { gint num = p->num > p->line_num ? p->line_num : p->num; - goto_nonempty(p->sci, num - 1, TRUE); + num = doc_line_from_visible_delta(p, num, -1, NULL); + goto_nonempty(p->sci, num, TRUE); } @@ -177,22 +206,31 @@ void cmd_goto_line_last(CmdContext *c, CmdParams *p) gint num = p->num > p->line_num ? p->line_num : p->num; if (!p->num_present) num = p->line_num; - goto_nonempty(p->sci, num - 1, TRUE); + num = doc_line_from_visible_delta(p, num, -1, NULL); + goto_nonempty(p->sci, num, TRUE); } void cmd_goto_screen_top(CmdContext *c, CmdParams *p) { + gint line; gint top = p->line_visible_first; gint count = p->line_visible_num; - gint line = top + p->num; - goto_nonempty(p->sci, line > top + count ? top + count : line, FALSE); + gint max = doc_line_from_visible_delta(p, top, count, NULL); + gint num = p->num; + + if (!p->num_present) + num = 0; + + line = doc_line_from_visible_delta(p, top, num, NULL); + goto_nonempty(p->sci, line > max ? max : line, FALSE); } void cmd_goto_screen_middle(CmdContext *c, CmdParams *p) { - goto_nonempty(p->sci, p->line_visible_first + p->line_visible_num/2, FALSE); + gint num = doc_line_from_visible_delta(p, p->line_visible_first, p->line_visible_num / 2, NULL); + goto_nonempty(p->sci, num, FALSE); } @@ -200,7 +238,7 @@ void cmd_goto_screen_bottom(CmdContext *c, CmdParams *p) { gint top = p->line_visible_first; gint count = p->line_visible_num; - gint line = top + count - p->num; + gint line = doc_line_from_visible_delta(p, top, count - p->num, NULL); goto_nonempty(p->sci, line < top ? top : line, FALSE); } From 33984abc9bd24bbf03db3ac517eb45ca2c7e6b7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Techet?= Date: Thu, 25 Apr 2024 16:06:22 +0200 Subject: [PATCH 2/2] vimode: Ensure that the line with the cursor is expanded after performing a command Without this, using e.g. 'w' to go to the next word makes the cursor go "inside" the fold and disappear. Vim seems to auto-expand the fold in such situations so do the same. --- vimode/src/cmd-runner.c | 1 + vimode/src/excmd-runner.c | 2 ++ vimode/src/utils.c | 8 ++++++++ vimode/src/utils.h | 1 + 4 files changed, 12 insertions(+) diff --git a/vimode/src/cmd-runner.c b/vimode/src/cmd-runner.c index 49706a539..43878c6c1 100644 --- a/vimode/src/cmd-runner.c +++ b/vimode/src/cmd-runner.c @@ -704,6 +704,7 @@ static gboolean process_cmd(CmdDef *cmds, CmdContext *ctx, gboolean ins_mode) { if (orig_mode == VI_MODE_COMMAND_SINGLE) vi_set_mode(VI_MODE_INSERT); + ensure_current_line_expanded(ctx->sci); } else if (!consumed && ctx->kpl) { diff --git a/vimode/src/excmd-runner.c b/vimode/src/excmd-runner.c index 663291813..4cca689df 100644 --- a/vimode/src/excmd-runner.c +++ b/vimode/src/excmd-runner.c @@ -465,6 +465,7 @@ void excmd_perform(CmdContext *ctx, const gchar *cmd) { case ':': perform_simple_ex_cmd(ctx, cmd + 1); + ensure_current_line_expanded(ctx->sci); break; case '/': case '?': @@ -483,6 +484,7 @@ void excmd_perform(CmdContext *ctx, const gchar *cmd) pos = perform_search(ctx->sci, ctx->search_text, ctx->num, FALSE); if (pos >= 0) SET_POS(ctx->sci, pos, TRUE); + ensure_current_line_expanded(ctx->sci); break; } } diff --git a/vimode/src/utils.c b/vimode/src/utils.c index b491a2dc1..2a367a80c 100644 --- a/vimode/src/utils.c +++ b/vimode/src/utils.c @@ -219,3 +219,11 @@ void goto_nonempty(ScintillaObject *sci, gint line, gboolean scroll) pos = NEXT(sci, pos); SET_POS(sci, pos, scroll); } + + +void ensure_current_line_expanded(ScintillaObject *sci) +{ + gint line = GET_CUR_LINE(sci); + if (!SSM(sci, SCI_GETLINEVISIBLE, line, 0)) + SSM(sci, SCI_ENSUREVISIBLE, line, 0); +} diff --git a/vimode/src/utils.h b/vimode/src/utils.h index e2e83d97c..b535cae81 100644 --- a/vimode/src/utils.h +++ b/vimode/src/utils.h @@ -32,5 +32,6 @@ void perform_substitute(ScintillaObject *sci, const gchar *cmd, gint from, gint const gchar *flag_override); gint get_line_number_rel(ScintillaObject *sci, gint shift); +void ensure_current_line_expanded(ScintillaObject *sci); #endif