summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-01-20 18:25:54 +0100
committerBram Moolenaar <Bram@vim.org>2019-01-20 18:25:54 +0100
commit10772307c4e5299ed45470f92779f089a00d841e (patch)
tree9833e1deac8d97753cf44e919ebf48ec38e936d7
parent113e10721f42fc2500b63fe95193f8665658a90c (diff)
patch 8.1.0786: ml_get error when updating the status linev8.1.0786
Problem: ml_get error when updating the status line and a terminal had its scrollback cleared. (Chris Patuzzo) Solution: Check the cursor position when drawing the status line. (closes #3830)
-rw-r--r--src/buffer.c32
-rw-r--r--src/testdir/test_terminal.vim25
-rw-r--r--src/version.c2
3 files changed, 53 insertions, 6 deletions
diff --git a/src/buffer.c b/src/buffer.c
index 33df710674..fa2e6524b7 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -3869,6 +3869,8 @@ build_stl_str_hl(
struct stl_hlrec *hltab, /* return: HL attributes (can be NULL) */
struct stl_hlrec *tabtab) /* return: tab page nrs (can be NULL) */
{
+ linenr_T lnum;
+ size_t len;
char_u *p;
char_u *s;
char_u *t;
@@ -3943,15 +3945,33 @@ build_stl_str_hl(
fillchar = '-';
#endif
- /* Get line & check if empty (cursorpos will show "0-1"). Note that
- * p will become invalid when getting another buffer line. */
- p = ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE);
+ // The cursor in windows other than the current one isn't always
+ // up-to-date, esp. because of autocommands and timers.
+ lnum = wp->w_cursor.lnum;
+ if (lnum > wp->w_buffer->b_ml.ml_line_count)
+ {
+ lnum = wp->w_buffer->b_ml.ml_line_count;
+ wp->w_cursor.lnum = lnum;
+ }
+
+ // Get line & check if empty (cursorpos will show "0-1"). Note that
+ // p will become invalid when getting another buffer line.
+ p = ml_get_buf(wp->w_buffer, lnum, FALSE);
empty_line = (*p == NUL);
- /* Get the byte value now, in case we need it below. This is more
- * efficient than making a copy of the line. */
- if (wp->w_cursor.col > (colnr_T)STRLEN(p))
+ // Get the byte value now, in case we need it below. This is more efficient
+ // than making a copy of the line.
+ len = STRLEN(p);
+ if (wp->w_cursor.col > (colnr_T)len)
+ {
+ // Line may have changed since checking the cursor column, or the lnum
+ // was adjusted above.
+ wp->w_cursor.col = (colnr_T)len;
+#ifdef FEAT_VIRTUALEDIT
+ wp->w_cursor.coladd = 0;
+#endif
byteval = 0;
+ }
else
#ifdef FEAT_MBYTE
byteval = (*mb_ptr2char)(p + wp->w_cursor.col);
diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim
index f78d66ca2c..960a85e978 100644
--- a/src/testdir/test_terminal.vim
+++ b/src/testdir/test_terminal.vim
@@ -1719,3 +1719,28 @@ func Test_term_gettitle()
exe term . 'bwipe!'
endfunc
+
+" When drawing the statusline the cursor position may not have been updated
+" yet.
+" 1. create a terminal, make it show 2 lines
+" 2. 0.5 sec later: leave terminal window, execute "i"
+" 3. 0.5 sec later: clear terminal window, now it's 1 line
+" 4. 0.5 sec later: redraw, including statusline (used to trigger bug)
+" 4. 0.5 sec later: should be done, clean up
+func Test_terminal_statusline()
+ if !has('unix')
+ return
+ endif
+ set statusline=x
+ terminal
+ let tbuf = bufnr('')
+ call term_sendkeys(tbuf, "clear; echo a; echo b; sleep 1; clear\n")
+ call timer_start(500, { tid -> feedkeys("\<C-w>j", 'tx') })
+ call timer_start(1500, { tid -> feedkeys("\<C-l>", 'tx') })
+ au BufLeave * if &buftype == 'terminal' | silent! normal i | endif
+
+ sleep 2
+ exe tbuf . 'bwipe!'
+ au! BufLeave
+ set statusline=
+endfunc
diff --git a/src/version.c b/src/version.c
index 0ef836e9bf..8f1c8bc752 100644
--- a/src/version.c
+++ b/src/version.c
@@ -792,6 +792,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 786,
+/**/
785,
/**/
784,