patch 9.2.0127: line('w0') and line('w$') return wrong values in a terminalCommit: https://github.com/vim/vim/commit/ffeb2339cb2f3eba2fa34a955747853b672cfa76 Author: Christian Brabandt <[email protected]> Date: Mon Mar 9 18:26:41 2026 +0000 patch 9.2.0127: line('w0') and line('w$') return wrong values in a terminal Problem: In a terminal window, line('w0') and line('w$') return wrong values instead of the first and last visible line number, because a terminal buffer does not go through the normal redraw path that updates w_topline and w_botline (ubaldot). Solution: Before computing w0 and w$, sync the terminal contents to the buffer by calling may_move_terminal_to_buffer() so that w_topline and w_botline are correctly updated. fixes: #19585 closes: #19615 supported by AI claude. Signed-off-by: Christian Brabandt <[email protected]> diff --git a/src/eval.c b/src/eval.c index a23089498..5f156fafa 100644 --- a/src/eval.c +++ b/src/eval.c @@ -6945,6 +6945,10 @@ var2fpos( pos.col = 0; if (name[1] == '0') // "w0": first visible line { +#ifdef FEAT_TERMINAL + if (bt_terminal(curwin->w_buffer)) + may_move_terminal_to_buffer(curwin->w_buffer->b_term, TRUE); +#endif update_topline(); // In silent Ex mode topline is zero, but that's not a valid line // number; use one instead. @@ -6953,6 +6957,10 @@ var2fpos( } else if (name[1] == '$') // "w$": last visible line { +#ifdef FEAT_TERMINAL + if (bt_terminal(curwin->w_buffer)) + may_move_terminal_to_buffer(curwin->w_buffer->b_term, TRUE); +#endif validate_botline(); // In silent Ex mode botline is zero, return zero then. pos.lnum = curwin->w_botline > 0 ? curwin->w_botline - 1 : 0; diff --git a/src/proto/terminal.pro b/src/proto/terminal.pro index 5ae6b4ca6..c042df545 100644 --- a/src/proto/terminal.pro +++ b/src/proto/terminal.pro @@ -13,6 +13,7 @@ int term_job_running_not_none(term_T *term); int term_none_open(term_T *term); int term_confirm_stop(buf_T *buf); int term_try_stop_job(buf_T *buf); +void may_move_terminal_to_buffer(term_T *term, int redraw); int term_check_timers(int next_due_arg, proftime_T *now); int term_in_normal_mode(void); void term_enter_job_mode(void); diff --git a/src/terminal.c b/src/terminal.c index 86e975568..3d0c7ea99 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -2172,7 +2172,7 @@ for_all_windows_and_curwin(win_T **wp, int *did_curwin) * Terminal-Normal mode. * When "redraw" is TRUE redraw the windows that show the terminal. */ - static void + void may_move_terminal_to_buffer(term_T *term, int redraw) { if (term->tl_vterm == NULL) diff --git a/src/testdir/test_terminal3.vim b/src/testdir/test_terminal3.vim index 7deb0eaaf..8046f14a5 100644 --- a/src/testdir/test_terminal3.vim +++ b/src/testdir/test_terminal3.vim @@ -1162,4 +1162,47 @@ func Test_terminal_max_combining_chars() exe buf . "bwipe!" endfunc +func Test_term_getpos() + CheckRunVimInTerminal + CheckUnix + CheckExecutable seq + defer delete('XTest_getpos_result') + + let lines =<< trim EOL + term ++curwin sh + EOL + call writefile(lines, 'XTest_getpos', 'D') + let buf = RunVimInTerminal('-S XTest_getpos', {'rows': 15}) + call term_sendkeys(buf, "for i in `seq 1 30`; do echo line$i; done\<cr>") + + call WaitForAssert({-> assert_match("line18", term_getline(buf, 1))}) + call WaitForAssert({-> assert_match("line30", term_getline(buf, 13))}) + + call term_sendkeys(buf, "\<c-w>:let g:job_w0 = line('w0')\<cr>") + call term_sendkeys(buf, "\<c-w>:let g:job_wdollar = line('w$')\<cr>") + call term_sendkeys(buf, "\<c-w>:call writefile([string(g:job_w0), string(g:job_wdollar)], 'XTest_getpos_result')\<cr>") + call WaitForAssert({-> assert_true(filereadable('XTest_getpos_result'))}) + call WaitForAssert({-> assert_equal(2, len(readfile('XTest_getpos_result')))}) + let job_result = readfile('XTest_getpos_result') + " 15 - 1: statusline - 1: prompt line + call assert_equal(13, str2nr(job_result[1]) - str2nr(job_result[0])) + call assert_true(str2nr(job_result[0]) > 1) + call delete('XTest_getpos_result') + + " switch to Terminal-Normal mode and record w0/w$ + call term_sendkeys(buf, "\<c-w>N") + call term_sendkeys(buf, ":let g:w0 = line('w0')\<cr>") + call term_sendkeys(buf, ":let g:wdollar = line('w$')\<cr>") + call term_sendkeys(buf, ":call writefile([string(g:w0), string(g:wdollar)], 'XTest_getpos_result')\<cr>") + + call WaitForAssert({-> assert_true(filereadable('XTest_getpos_result'))}) + call WaitForAssert({-> assert_equal(2, len(readfile('XTest_getpos_result')))}) + let result = readfile('XTest_getpos_result') + " 15 - 1: statusline - 1: for prompt line + call assert_equal(13, str2nr(result[1]) - str2nr(result[0])) + call assert_true(str2nr(result[0]) > 1) + + call StopVimInTerminal(buf) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index ff021ff19..47c695c44 100644 --- a/src/version.c +++ b/src/version.c @@ -734,6 +734,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 127, /**/ 126, /**/ -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1vzfMo-00Enfa-29%40256bit.org.
