aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/buffer_defs.h33
-rw-r--r--src/nvim/fileio.c2
-rw-r--r--src/nvim/testdir/test_autocmd.vim44
-rw-r--r--src/nvim/window.c24
4 files changed, 92 insertions, 11 deletions
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 6d99a06eb9..5e28a7b513 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -999,6 +999,16 @@ typedef struct {
.relative = 0, .external = false, \
.focusable = true })
+// Structure to store last cursor position and topline. Used by check_lnums()
+// and reset_lnums().
+typedef struct
+{
+ int w_topline_save; // original topline value
+ int w_topline_corr; // corrected topline value
+ pos_T w_cursor_save; // original cursor position
+ pos_T w_cursor_corr; // corrected cursor position
+} pos_save_T;
+
/// Structure which contains all information that belongs to a window.
///
/// All row numbers are relative to the start of the window, except w_winrow.
@@ -1091,17 +1101,18 @@ struct window_S {
colnr_T w_skipcol; /* starting column when a single line
doesn't fit in the window */
- /*
- * Layout of the window in the screen.
- * May need to add "msg_scrolled" to "w_winrow" in rare situations.
- */
- int w_winrow; /* first row of window in screen */
- int w_height; /* number of rows in window, excluding
- status/command line(s) */
- int w_status_height; /* number of status lines (0 or 1) */
- int w_wincol; /* Leftmost column of window in screen. */
- int w_width; /* Width of window, excluding separation. */
- int w_vsep_width; /* Number of separator columns (0 or 1). */
+ //
+ // Layout of the window in the screen.
+ // May need to add "msg_scrolled" to "w_winrow" in rare situations.
+ //
+ int w_winrow; // first row of window in screen
+ int w_height; // number of rows in window, excluding
+ // status/command line(s)
+ int w_status_height; // number of status lines (0 or 1)
+ int w_wincol; // Leftmost column of window in screen.
+ int w_width; // Width of window, excluding separation.
+ int w_vsep_width; // Number of separator columns (0 or 1).
+ pos_save_T w_save_cursor; // backup of cursor pos and topline
// inner size of window, which can be overridden by external UI
int w_height_inner;
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 416d7f5cce..717ae6e602 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -7072,6 +7072,8 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
do_cmdline(NULL, getnextac, (void *)&patcmd,
DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
+ reset_lnums(); // restore cursor and topline, unless they were changed
+
if (eap != NULL) {
(void)set_cmdarg(NULL, save_cmdarg);
set_vim_var_nr(VV_CMDBANG, save_cmdbang);
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index d13761e2ba..1c1da0572b 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -1425,6 +1425,50 @@ func Test_autocmd_once()
call assert_fails('au WinNew * ++once ++once echo bad', 'E983:')
endfunc
+func Test_autocmd_bufreadpre()
+ new
+ let b:bufreadpre = 1
+ call append(0, range(100))
+ w! XAutocmdBufReadPre.txt
+ autocmd BufReadPre <buffer> :let b:bufreadpre += 1
+ norm! 50gg
+ sp
+ norm! 100gg
+ wincmd p
+ let g:wsv1 = winsaveview()
+ wincmd p
+ let g:wsv2 = winsaveview()
+ " triggers BufReadPre, should not move the cursor in either window
+ " The topline may change one line in a large window.
+ edit
+ call assert_inrange(g:wsv2.topline - 1, g:wsv2.topline + 1, winsaveview().topline)
+ call assert_equal(g:wsv2.lnum, winsaveview().lnum)
+ call assert_equal(2, b:bufreadpre)
+ wincmd p
+ call assert_equal(g:wsv1.topline, winsaveview().topline)
+ call assert_equal(g:wsv1.lnum, winsaveview().lnum)
+ call assert_equal(2, b:bufreadpre)
+ " Now set the cursor position in an BufReadPre autocommand
+ " (even though the position will be invalid, this should make Vim reset the
+ " cursor position in the other window.
+ wincmd p
+ 1
+ " won't do anything, but try to set the cursor on an invalid lnum
+ autocmd BufReadPre <buffer> :norm! 70gg
+ " triggers BufReadPre, should not move the cursor in either window
+ e
+ call assert_equal(1, winsaveview().topline)
+ call assert_equal(1, winsaveview().lnum)
+ call assert_equal(3, b:bufreadpre)
+ wincmd p
+ call assert_equal(g:wsv1.topline, winsaveview().topline)
+ call assert_equal(g:wsv1.lnum, winsaveview().lnum)
+ call assert_equal(3, b:bufreadpre)
+ close
+ close
+ call delete('XAutocmdBufReadPre.txt')
+endfunc
+
" Tests for the following autocommands:
" - FileWritePre writing a compressed file
" - FileReadPost reading a compressed file
diff --git a/src/nvim/window.c b/src/nvim/window.c
index e737bfbd05..200c651d1e 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -5963,16 +5963,40 @@ void check_lnums(int do_curwin)
{
FOR_ALL_TAB_WINDOWS(tp, wp) {
if ((do_curwin || wp != curwin) && wp->w_buffer == curbuf) {
+ // save the original cursor position and topline
+ wp->w_save_cursor.w_cursor_save = wp->w_cursor;
+ wp->w_save_cursor.w_topline_save = wp->w_topline;
+
if (wp->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
wp->w_cursor.lnum = curbuf->b_ml.ml_line_count;
}
if (wp->w_topline > curbuf->b_ml.ml_line_count) {
wp->w_topline = curbuf->b_ml.ml_line_count;
}
+
+ // save the corrected cursor position and topline
+ wp->w_save_cursor.w_cursor_corr = wp->w_cursor;
+ wp->w_save_cursor.w_topline_corr = wp->w_topline;
}
}
}
+/// Reset cursor and topline to its stored values from check_lnums().
+/// check_lnums() must have been called first!
+void reset_lnums(void)
+{
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer == curbuf) {
+ // Restore the value if the autocommand didn't change it.
+ if (equalpos(wp->w_save_cursor.w_cursor_corr, wp->w_cursor)) {
+ wp->w_cursor = wp->w_save_cursor.w_cursor_save;
+ }
+ if (wp->w_save_cursor.w_topline_corr == wp->w_topline) {
+ wp->w_topline = wp->w_save_cursor.w_topline_save;
+ }
+ }
+ }
+}
/*
* A snapshot of the window sizes, to restore them after closing the help