summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuuk van Baal <luukvbaal@gmail.com>2022-09-27 12:31:15 +0100
committerBram Moolenaar <Bram@vim.org>2022-09-27 12:31:15 +0100
commit7c1cbb6cd437c6e0c3ccc05840cc931108b4a60a (patch)
tree6beeee2a32dd5f38a4aa2429c2573ad3a96658dc
parent7fc6c0e4dab4e80b9806a973936af54276468513 (diff)
downloadvim-git-7c1cbb6cd437c6e0c3ccc05840cc931108b4a60a.tar.gz
patch 9.0.0603: with 'nosplitscroll' folds are not handled correctlyv9.0.0603
Problem: With 'nosplitscroll' folds are not handled correctly. Solution: Take care of closed folds when moving the cursor. (Luuk van Baal, closes #11234)
-rw-r--r--src/edit.c180
-rw-r--r--src/proto/edit.pro2
-rw-r--r--src/testdir/dumps/Test_nosplitscroll_fold_1.dump10
-rw-r--r--src/testdir/dumps/Test_nosplitscroll_fold_2.dump10
-rw-r--r--src/testdir/dumps/Test_nosplitscroll_fold_3.dump10
-rw-r--r--src/testdir/test_window_cmd.vim30
-rw-r--r--src/version.c2
-rw-r--r--src/window.c69
8 files changed, 204 insertions, 109 deletions
diff --git a/src/edit.c b/src/edit.c
index ec3e8ff6c..2ac544a6b 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -2749,52 +2749,62 @@ oneleft(void)
return OK;
}
- int
-cursor_up(
- long n,
- int upd_topline) // When TRUE: update topline
+/*
+ * Move the cursor up "n" lines in window "wp".
+ * Takes care of closed folds.
+ * Returns the new cursor line or zero for failure.
+ */
+ linenr_T
+cursor_up_inner(win_T *wp, long n)
{
- linenr_T lnum;
+ linenr_T lnum = wp->w_cursor.lnum;
- if (n > 0)
- {
- lnum = curwin->w_cursor.lnum;
- // This fails if the cursor is already in the first line or the count
- // is larger than the line number and '-' is in 'cpoptions'
- if (lnum <= 1 || (n >= lnum && vim_strchr(p_cpo, CPO_MINUS) != NULL))
- return FAIL;
- if (n >= lnum)
- lnum = 1;
- else
+ // This fails if the cursor is already in the first line or the count is
+ // larger than the line number and '-' is in 'cpoptions'
+ if (lnum <= 1 || (n >= lnum && vim_strchr(p_cpo, CPO_MINUS) != NULL))
+ return 0;
+ if (n >= lnum)
+ lnum = 1;
+ else
#ifdef FEAT_FOLDING
- if (hasAnyFolding(curwin))
- {
- /*
- * Count each sequence of folded lines as one logical line.
- */
- // go to the start of the current fold
- (void)hasFolding(lnum, &lnum, NULL);
+ if (hasAnyFolding(wp))
+ {
+ /*
+ * Count each sequence of folded lines as one logical line.
+ */
+ // go to the start of the current fold
+ (void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
- while (n--)
- {
- // move up one line
- --lnum;
- if (lnum <= 1)
- break;
- // If we entered a fold, move to the beginning, unless in
- // Insert mode or when 'foldopen' contains "all": it will open
- // in a moment.
- if (n > 0 || !((State & MODE_INSERT) || (fdo_flags & FDO_ALL)))
- (void)hasFolding(lnum, &lnum, NULL);
- }
- if (lnum < 1)
- lnum = 1;
+ while (n--)
+ {
+ // move up one line
+ --lnum;
+ if (lnum <= 1)
+ break;
+ // If we entered a fold, move to the beginning, unless in
+ // Insert mode or when 'foldopen' contains "all": it will open
+ // in a moment.
+ if (n > 0 || !((State & MODE_INSERT) || (fdo_flags & FDO_ALL)))
+ (void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
}
- else
-#endif
- lnum -= n;
- curwin->w_cursor.lnum = lnum;
+ if (lnum < 1)
+ lnum = 1;
}
+ else
+#endif
+ lnum -= n;
+
+ wp->w_cursor.lnum = lnum;
+ return lnum;
+}
+
+ int
+cursor_up(
+ long n,
+ int upd_topline) // When TRUE: update topline
+{
+ if (n > 0 && cursor_up_inner(curwin, n) == 0)
+ return FAIL;
// try to advance to the column we want to be at
coladvance(curwin->w_curswant);
@@ -2806,54 +2816,64 @@ cursor_up(
}
/*
- * Cursor down a number of logical lines.
+ * Move the cursor down "n" lines in window "wp".
+ * Takes care of closed folds.
+ * Returns the new cursor line or zero for failure.
*/
- int
-cursor_down(
- long n,
- int upd_topline) // When TRUE: update topline
+ linenr_T
+cursor_down_inner(win_T *wp, long n)
{
- linenr_T lnum;
+ linenr_T lnum = wp->w_cursor.lnum;
+ linenr_T line_count = wp->w_buffer->b_ml.ml_line_count;
- if (n > 0)
- {
- lnum = curwin->w_cursor.lnum;
#ifdef FEAT_FOLDING
- // Move to last line of fold, will fail if it's the end-of-file.
- (void)hasFolding(lnum, NULL, &lnum);
-#endif
- // This fails if the cursor is already in the last line or would move
- // beyond the last line and '-' is in 'cpoptions'
- if (lnum >= curbuf->b_ml.ml_line_count
- || (lnum + n > curbuf->b_ml.ml_line_count
- && vim_strchr(p_cpo, CPO_MINUS) != NULL))
- return FAIL;
- if (lnum + n >= curbuf->b_ml.ml_line_count)
- lnum = curbuf->b_ml.ml_line_count;
- else
+ // Move to last line of fold, will fail if it's the end-of-file.
+ (void)hasFoldingWin(wp, lnum, NULL, &lnum, TRUE, NULL);
+#endif
+ // This fails if the cursor is already in the last line or would move
+ // beyond the last line and '-' is in 'cpoptions'
+ if (lnum >= line_count
+ || (lnum + n > line_count && vim_strchr(p_cpo, CPO_MINUS) != NULL))
+ return FAIL;
+ if (lnum + n >= line_count)
+ lnum = line_count;
+ else
#ifdef FEAT_FOLDING
- if (hasAnyFolding(curwin))
- {
- linenr_T last;
+ if (hasAnyFolding(wp))
+ {
+ linenr_T last;
- // count each sequence of folded lines as one logical line
- while (n--)
- {
- if (hasFolding(lnum, NULL, &last))
- lnum = last + 1;
- else
- ++lnum;
- if (lnum >= curbuf->b_ml.ml_line_count)
- break;
- }
- if (lnum > curbuf->b_ml.ml_line_count)
- lnum = curbuf->b_ml.ml_line_count;
+ // count each sequence of folded lines as one logical line
+ while (n--)
+ {
+ if (hasFoldingWin(wp, lnum, NULL, &last, TRUE, NULL))
+ lnum = last + 1;
+ else
+ ++lnum;
+ if (lnum >= line_count)
+ break;
}
- else
-#endif
- lnum += n;
- curwin->w_cursor.lnum = lnum;
+ if (lnum > line_count)
+ lnum = line_count;
}
+ else
+#endif
+ lnum += n;
+
+ wp->w_cursor.lnum = lnum;
+ return lnum;
+}
+
+/*
+ * Cursor down a number of logical lines.
+ */
+ int
+cursor_down(
+ long n,
+ int upd_topline) // When TRUE: update topline
+{
+ if (n > 0 && cursor_down_inner(curwin, n) == 0)
+ return FAIL;
// try to advance to the column we want to be at
coladvance(curwin->w_curswant);
diff --git a/src/proto/edit.pro b/src/proto/edit.pro
index f35ec1ed5..4513f4fe0 100644
--- a/src/proto/edit.pro
+++ b/src/proto/edit.pro
@@ -19,7 +19,9 @@ char_u *add_char2buf(int c, char_u *s);
void beginline(int flags);
int oneright(void);
int oneleft(void);
+linenr_T cursor_up_inner(win_T *wp, long n);
int cursor_up(long n, int upd_topline);
+linenr_T cursor_down_inner(win_T *wp, long n);
int cursor_down(long n, int upd_topline);
int stuff_inserted(int c, long count, int no_esc);
char_u *get_last_insert(void);
diff --git a/src/testdir/dumps/Test_nosplitscroll_fold_1.dump b/src/testdir/dumps/Test_nosplitscroll_fold_1.dump
new file mode 100644
index 000000000..748a3c86e
--- /dev/null
+++ b/src/testdir/dumps/Test_nosplitscroll_fold_1.dump
@@ -0,0 +1,10 @@
+| +0#0000e05#a8a8a8255@1|1| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| |F|u|n|c|N|a|m|e|(|)| |{|-@40
+| +0#af5f00255#ffffff0@1|8| >a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+| +0#0000e05#a8a8a8255@1|9| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| |F|u|n|c|N|a|m|e|(|)| |{|-@40
+| +0#af5f00255#ffffff0|1|6| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+|[+3&&|N|o| |N|a|m|e|]| |[|+|]| @43|8|,|1| @11|T|o|p
+| +0#af5f00255&|2|4| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+| +0#0000e05#a8a8a8255|2|5| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| |F|u|n|c|N|a|m|e|(|)| |{|-@40
+| +0#af5f00255#ffffff0|3|2| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+|[+1&&|N|o| |N|a|m|e|]| |[|+|]| @43|2|3|,|1| @10|3|2|%
+|:+0&&|w|i|n|c|m|d| |s| @65
diff --git a/src/testdir/dumps/Test_nosplitscroll_fold_2.dump b/src/testdir/dumps/Test_nosplitscroll_fold_2.dump
new file mode 100644
index 000000000..959cb64ba
--- /dev/null
+++ b/src/testdir/dumps/Test_nosplitscroll_fold_2.dump
@@ -0,0 +1,10 @@
+| +0#0000e05#a8a8a8255@1|1| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| |F|u|n|c|N|a|m|e|(|)| |{|-@40
+| +0#af5f00255#ffffff0@1|8| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+| +0#0000e05#a8a8a8255@1|9| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| |F|u|n|c|N|a|m|e|(|)| |{|-@40
+| +0#af5f00255#ffffff0|1|6| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+| +0#0000e05#a8a8a8255|1|7| >+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| |F|u|n|c|N|a|m|e|(|)| |{|-@40
+| +0#af5f00255#ffffff0|2|4| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+| +0#0000e05#a8a8a8255|2|5| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| |F|u|n|c|N|a|m|e|(|)| |{|-@40
+| +0#af5f00255#ffffff0|3|2| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+| +0#0000e05#a8a8a8255|3@1| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| |F|u|n|c|N|a|m|e|(|)| |{|-@40
+|:+0#0000000#ffffff0|q|u|i|t| @51|1|7|,|1| @9|T|o|p|
diff --git a/src/testdir/dumps/Test_nosplitscroll_fold_3.dump b/src/testdir/dumps/Test_nosplitscroll_fold_3.dump
new file mode 100644
index 000000000..6880104a7
--- /dev/null
+++ b/src/testdir/dumps/Test_nosplitscroll_fold_3.dump
@@ -0,0 +1,10 @@
+| +0#0000e05#a8a8a8255@1|1| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| |F|u|n|c|N|a|m|e|(|)| |{|-@40
+| +0#af5f00255#ffffff0@1|8| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+| +0#0000e05#a8a8a8255@1|9| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| |F|u|n|c|N|a|m|e|(|)| |{|-@40
+|[+1#0000000#ffffff0|N|o| |N|a|m|e|]| |[|+|]| @43|1|,|1| @11|T|o|p
+| +0#0000e05#a8a8a8255|1|7| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| |F|u|n|c|N|a|m|e|(|)| |{|-@40
+| +0#af5f00255#ffffff0|2|4| >a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+| +0#0000e05#a8a8a8255|2|5| |+|-@1| @1|7| |l|i|n|e|s|:| |i|n|t| |F|u|n|c|N|a|m|e|(|)| |{|-@40
+| +0#af5f00255#ffffff0|3|2| |a+0#0000000&|f|t|e|r| |f|o|l|d| @60
+|[+3&&|N|o| |N|a|m|e|]| |[|+|]| @43|2|4|,|1| @10|2|5|%
+|:+0&&|b|e|l|o|w| |s|p|l|i|t| @62
diff --git a/src/testdir/test_window_cmd.vim b/src/testdir/test_window_cmd.vim
index 2ee441787..aa69522d7 100644
--- a/src/testdir/test_window_cmd.vim
+++ b/src/testdir/test_window_cmd.vim
@@ -1848,4 +1848,34 @@ function Test_nosplitscroll_callback()
call VerifyScreenDump(buf, 'Test_nosplitscroll_callback_4', {})
endfunc
+function Test_nosplitscroll_fold()
+CheckScreendump
+
+let lines =<< trim END
+ set nosplitscroll
+ set foldmethod=marker
+ set number
+ let line = 1
+ for n in range(1, &lines)
+ call setline(line, ['int FuncName() {/*{{{*/', 1, 2, 3, 4, 5, '}/*}}}*/',
+ \ 'after fold'])
+ let line += 8
+ endfor
+END
+ call writefile(lines, 'XTestNosplitscrollFold', 'D')
+ let buf = RunVimInTerminal('-S XTestNosplitscrollFold', #{rows: 10})
+
+ call term_sendkeys(buf, "L:wincmd s\<CR>")
+ call VerifyScreenDump(buf, 'Test_nosplitscroll_fold_1', {})
+
+ call term_sendkeys(buf, ":quit\<CR>")
+ call VerifyScreenDump(buf, 'Test_nosplitscroll_fold_2', {})
+
+ call term_sendkeys(buf, "H:below split\<CR>")
+ call VerifyScreenDump(buf, 'Test_nosplitscroll_fold_3', {})
+
+ call term_sendkeys(buf, ":wincmd k\<CR>:quit\<CR>")
+ call VerifyScreenDump(buf, 'Test_nosplitscroll_fold_4', {})
+endfunction
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 430475110..f6b88274a 100644
--- a/src/version.c
+++ b/src/version.c
@@ -700,6 +700,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 603,
+/**/
602,
/**/
601,
diff --git a/src/window.c b/src/window.c
index db08e4132..d4580e474 100644
--- a/src/window.c
+++ b/src/window.c
@@ -6351,7 +6351,7 @@ set_fraction(win_T *wp)
/*
* Handle scroll position for 'nosplitscroll'. Replaces scroll_to_fraction()
* call from win_new_height(). Instead we iterate over all windows in a
- * tabpage and calculate the new scroll/cursor position.
+ * tabpage and calculate the new scroll position.
* TODO: Ensure this also works with wrapped lines.
* Requires topline to be able to be set to a bufferline with some
* offset(row-wise scrolling/smoothscroll).
@@ -6359,8 +6359,9 @@ set_fraction(win_T *wp)
static void
win_fix_scroll(int resize)
{
- win_T *wp;
- linenr_T lnum;
+ int diff;
+ win_T *wp;
+ linenr_T lnum;
skip_update_topline = TRUE; // avoid scrolling in curs_columns()
FOR_ALL_WINDOWS(wp)
@@ -6368,13 +6369,18 @@ win_fix_scroll(int resize)
// Skip when window height has not changed.
if (wp->w_height != wp->w_prev_height)
{
- // Determine botline needed to avoid scrolling and set cursor.
+ // If window has moved update botline to keep the same screenlines.
if (wp->w_winrow != wp->w_prev_winrow)
{
lnum = wp->w_cursor.lnum;
- wp->w_cursor.lnum = MIN(wp->w_buffer->b_ml.ml_line_count,
- wp->w_botline - 1 + (wp->w_winrow - wp->w_prev_winrow)
- + (wp->w_height - wp->w_prev_height));
+ diff = (wp->w_winrow - wp->w_prev_winrow)
+ + (wp->w_height - wp->w_prev_height);
+ wp->w_cursor.lnum = wp->w_botline - 1;
+ // Add difference in height and row to botline.
+ if (diff > 0)
+ cursor_down_inner(wp, diff);
+ else
+ cursor_up_inner(wp, -diff);
// Bring the new cursor position to the bottom of the screen.
wp->w_fraction = FRACTION_MULT;
scroll_to_fraction(wp, wp->w_prev_height);
@@ -6405,9 +6411,12 @@ win_fix_scroll(int resize)
static void
win_fix_cursor(int normal)
{
- win_T *wp = curwin;
- long so = get_scrolloff_value();
- linenr_T nlnum = 0;
+ long so = get_scrolloff_value();
+ win_T *wp = curwin;
+ linenr_T nlnum = 0;
+ linenr_T lnum = wp->w_cursor.lnum;
+ linenr_T bot;
+ linenr_T top;
if (wp->w_buffer->b_ml.ml_line_count < wp->w_height)
return;
@@ -6415,28 +6424,30 @@ win_fix_cursor(int normal)
if (skip_win_fix_cursor)
return;
#endif
-
+ // Determine valid cursor range.
so = MIN(wp->w_height / 2, so);
- // Check if cursor position is above topline or below botline.
- if (wp->w_cursor.lnum < (wp->w_topline + so) && wp->w_topline != 1)
- nlnum = MIN(wp->w_topline + so, wp->w_buffer->b_ml.ml_line_count);
- else if (wp->w_cursor.lnum > (wp->w_botline - so - 1)
- && (wp->w_botline - wp->w_buffer->b_ml.ml_line_count) != 1)
- nlnum = MAX(wp->w_botline - so - 1, 1);
- // If cursor was invalid scroll or change cursor.
- if (nlnum)
- {
- if (normal)
- { // Make sure cursor is closer to topline than botline.
- if (so == wp->w_height / 2
- && nlnum - wp->w_topline > wp->w_botline - 1 - nlnum)
- nlnum--;
- setmark('\''); // save cursor position
- wp->w_cursor.lnum = nlnum; // change to avoid scrolling
+ wp->w_cursor.lnum = wp->w_topline;
+ top = cursor_down_inner(wp, so);
+ wp->w_cursor.lnum = wp->w_botline - 1;
+ bot = cursor_up_inner(wp, so);
+ // Check if cursor position is above or below valid cursor range.
+ if (lnum > bot && (wp->w_botline - wp->w_buffer->b_ml.ml_line_count) != 1)
+ nlnum = bot;
+ else if (lnum < top && wp->w_topline != 1)
+ nlnum = (so == wp->w_height / 2) ? bot : top;
+
+ wp->w_cursor.lnum = lnum;
+
+ if (nlnum) // Cursor is invalid for current scroll position.
+ {
+ if (normal) // Save to jumplist and set cursor to avoid scrolling.
+ {
+ setmark('\'');
+ wp->w_cursor.lnum = nlnum;
curs_columns(TRUE); // validate w_wrow
}
- else
- { // Ensure cursor stays visible if we are not in normal mode.
+ else // Scroll instead when not in normal mode.
+ {
wp->w_fraction = 0.5 * FRACTION_MULT;
scroll_to_fraction(wp, wp->w_prev_height);
validate_botline_win(curwin);