patch 9.2.0127: line('w0') and line('w$') return wrong values in a terminal

Commit: 
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.

Raspunde prin e-mail lui