Skip to content

Commit

Permalink
vimode: Take into account folded lines when moving cursor
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
techee committed May 21, 2024
1 parent 644550b commit 522b79d
Showing 1 changed file with 56 additions and 18 deletions.
74 changes: 56 additions & 18 deletions vimode/src/cmds/motion.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -136,39 +164,40 @@ 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);
}


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


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


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


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


Expand All @@ -177,30 +206,39 @@ 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);
}


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

Expand Down

0 comments on commit 522b79d

Please sign in to comment.