patch 9.1.1070: Cannot control cursor positioning of getchar()

Commit: 
https://github.com/vim/vim/commit/edf0f7db28f87611368e158210e58ed30f673098
Author: zeertzjq <zeert...@outlook.com>
Date:   Sun Feb 2 19:01:01 2025 +0100

    patch 9.1.1070: Cannot control cursor positioning of getchar()
    
    Problem:  Cannot control cursor positioning of getchar().
    Solution: Add "cursor" flag to {opts}, with possible values "hide",
              "keep" and "msg".
    
    related: #10603
    closes: #16569
    
    Signed-off-by: zeertzjq <zeert...@outlook.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 46c3ba855..39ff14e5f 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -3953,6 +3953,13 @@ getchar([{expr} [, {opts}]])                             
*getchar()*
                The optional argument {opts} is a Dict and supports the
                following items:
 
+                       cursor          A String specifying cursor behavior
+                                       when waiting for a character.
+                                       "hide": hide the cursor.
+                                       "keep": keep current cursor unchanged.
+                                       "msg": move cursor to message area.
+                                       (default: "msg")
+
                        number          If |TRUE|, return a Number when getting
                                        a single character.
                                        If |FALSE|, the return value is always
diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt
index 2d48cc974..5338b8b0a 100644
--- a/runtime/doc/todo.txt
+++ b/runtime/doc/todo.txt
@@ -1,4 +1,4 @@
-*todo.txt*      For Vim version 9.1.  Last change: 2025 Jan 16
+*todo.txt*      For Vim version 9.1.  Last change: 2025 Feb 02
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -467,9 +467,6 @@ IDEA: when drawing the text, store the text byte index in 
ScreenLinesIdx[].
 When converting screen column to text position use this.
 The line number can be obtained from win->w_lines[].
 
-Version of getchar() that does not move the cursor - #10603 Use a separate
-argument for the new flag.
-
 test_arglist func Test_all_not_allowed_from_cmdwin() hangs on MS-Windows.
 
 Can we add highlighting to ":echowindow"?
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index 010a0cbad..68287d3e2 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -41636,6 +41636,8 @@ Changed~
 - add |dist#vim9#Launch()| and |dist#vim9#Open()| to the |vim-script-library|
   and decouple it from |netrw|
 - new digraph "APPROACHES THE LIMIT" using ".="
+- Add the optional {opts} |Dict| argument to |getchar()| to control: cursor
+  behaviour, return type and whether or not to simplify the returned key
 
                                                        *added-9.2*
 Added ~
diff --git a/src/getchar.c b/src/getchar.c
index 06f4ad435..83a9861ec 100644
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -2386,9 +2386,11 @@ char_avail(void)
     static void
 getchar_common(typval_T *argvars, typval_T *rettv, int allow_number)
 {
-    varnumber_T                n;
+    varnumber_T                n = 0;
+    int                        called_emsg_start = called_emsg;
     int                        error = FALSE;
     int                        simplify = TRUE;
+    char_u             cursor_flag = 'm';
 
     if ((in_vim9script()
                && check_for_opt_bool_or_number_arg(argvars, 0) == FAIL)
@@ -2399,18 +2401,31 @@ getchar_common(typval_T *argvars, typval_T *rettv, int 
allow_number)
     if (argvars[0].v_type != VAR_UNKNOWN && argvars[1].v_type == VAR_DICT)
     {
        dict_T          *d = argvars[1].vval.v_dict;
+       char_u          *cursor_str;
 
        if (allow_number)
            allow_number = dict_get_bool(d, "number", TRUE);
        else if (dict_has_key(d, "number"))
-       {
            semsg(_(e_invalid_argument_str), "number");
-           error = TRUE;
-       }
 
        simplify = dict_get_bool(d, "simplify", TRUE);
+
+       cursor_str = dict_get_string(d, "cursor", FALSE);
+       if (cursor_str != NULL)
+       {
+           if (STRCMP(cursor_str, "hide") != 0
+                   && STRCMP(cursor_str, "keep") != 0
+                   && STRCMP(cursor_str, "msg") != 0)
+               semsg(_(e_invalid_value_for_argument_str_str), "cursor",
+                                                                  cursor_str);
+           else
+               cursor_flag = cursor_str[0];
+       }
     }
 
+    if (called_emsg != called_emsg_start)
+       return;
+
 #ifdef MESSAGE_QUEUE
     // vpeekc() used to check for messages, but that caused problems, invoking
     // a callback where it was not expected.  Some plugins use getchar(1) in a
@@ -2418,14 +2433,16 @@ getchar_common(typval_T *argvars, typval_T *rettv, int 
allow_number)
     parse_queued_messages();
 #endif
 
-    // Position the cursor.  Needed after a message that ends in a space.
-    windgoto(msg_row, msg_col);
+    if (cursor_flag == 'h')
+       cursor_sleep();
+    else if (cursor_flag == 'm')
+       windgoto(msg_row, msg_col);
 
     ++no_mapping;
     ++allow_keys;
     if (!simplify)
        ++no_reduce_keys;
-    while (!error)
+    for (;;)
     {
        if (argvars[0].v_type == VAR_UNKNOWN
                || (argvars[0].v_type == VAR_NUMBER
@@ -2453,6 +2470,9 @@ getchar_common(typval_T *argvars, typval_T *rettv, int 
allow_number)
     if (!simplify)
        --no_reduce_keys;
 
+    if (cursor_flag == 'h')
+       cursor_unsleep();
+
     set_vim_var_nr(VV_MOUSE_WIN, 0);
     set_vim_var_nr(VV_MOUSE_WINID, 0);
     set_vim_var_nr(VV_MOUSE_LNUM, 0);
diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim
index 4672fc0c4..5783c7a8e 100644
--- a/src/testdir/test_functions.vim
+++ b/src/testdir/test_functions.vim
@@ -2628,6 +2628,14 @@ func Test_getchar()
 
   call assert_fails('call getchar(1, 1)', 'E1206:')
   call assert_fails('call getcharstr(1, 1)', 'E1206:')
+  call assert_fails('call getchar(1, #{cursor: "foo"})', 'E475:')
+  call assert_fails('call getcharstr(1, #{cursor: "foo"})', 'E475:')
+  call assert_fails('call getchar(1, #{cursor: 0z})', 'E976:')
+  call assert_fails('call getcharstr(1, #{cursor: 0z})', 'E976:')
+  call assert_fails('call getchar(1, #{simplify: 0z})', 'E974:')
+  call assert_fails('call getcharstr(1, #{simplify: 0z})', 'E974:')
+  call assert_fails('call getchar(1, #{number: []})', 'E745:')
+  call assert_fails('call getchar(1, #{number: {}})', 'E728:')
   call assert_fails('call getcharstr(1, #{number: v:true})', 'E475:')
   call assert_fails('call getcharstr(1, #{number: v:false})', 'E475:')
 
@@ -2646,6 +2654,57 @@ func Test_getchar()
   enew!
 endfunc
 
+func Test_getchar_cursor_position()
+  CheckRunVimInTerminal
+
+  let lines =<< trim END
+    call setline(1, ['foobar', 'foobar', 'foobar'])
+    call cursor(3, 6)
+    nnoremap <F1> <Cmd>echo 1234<Bar>call getchar()<CR>
+    nnoremap <F2> <Cmd>call getchar()<CR>
+    nnoremap <F3> <Cmd>call getchar(-1, {})<CR>
+    nnoremap <F4> <Cmd>call getchar(-1, #{cursor: 'msg'})<CR>
+    nnoremap <F5> <Cmd>call getchar(-1, #{cursor: 'keep'})<CR>
+    nnoremap <F6> <Cmd>call getchar(-1, #{cursor: 'hide'})<CR>
+  END
+  call writefile(lines, 'XgetcharCursorPos', 'D')
+  let buf = RunVimInTerminal('-S XgetcharCursorPos', {'rows': 6})
+  call WaitForAssert({-> assert_equal([3, 6], term_getcursor(buf)[0:1])})
+
+  call term_sendkeys(buf, "\<F1>")
+  call WaitForAssert({-> assert_equal([6, 5], term_getcursor(buf)[0:1])})
+  call assert_true(term_getcursor(buf)[2].visible)
+  call term_sendkeys(buf, 'a')
+  call WaitForAssert({-> assert_equal([3, 6], term_getcursor(buf)[0:1])})
+  call assert_true(term_getcursor(buf)[2].visible)
+
+  for key in ["\<F2>", "\<F3>", "\<F4>"]
+    call term_sendkeys(buf, key)
+    call WaitForAssert({-> assert_equal([6, 1], term_getcursor(buf)[0:1])})
+    call assert_true(term_getcursor(buf)[2].visible)
+    call term_sendkeys(buf, 'a')
+    call WaitForAssert({-> assert_equal([3, 6], term_getcursor(buf)[0:1])})
+    call assert_true(term_getcursor(buf)[2].visible)
+  endfor
+
+  call term_sendkeys(buf, "\<F5>")
+  call TermWait(buf, 50)
+  call assert_equal([3, 6], term_getcursor(buf)[0:1])
+  call assert_true(term_getcursor(buf)[2].visible)
+  call term_sendkeys(buf, 'a')
+  call TermWait(buf, 50)
+  call assert_equal([3, 6], term_getcursor(buf)[0:1])
+  call assert_true(term_getcursor(buf)[2].visible)
+
+  call term_sendkeys(buf, "\<F6>")
+  call WaitForAssert({-> assert_false(term_getcursor(buf)[2].visible)})
+  call term_sendkeys(buf, 'a')
+  call WaitForAssert({-> assert_true(term_getcursor(buf)[2].visible)})
+  call assert_equal([3, 6], term_getcursor(buf)[0:1])
+
+  call StopVimInTerminal(buf)
+endfunc
+
 func Test_libcall_libcallnr()
   CheckFeature libcall
 
diff --git a/src/version.c b/src/version.c
index f9d99a5dc..5ed5bcf31 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1070,
 /**/
     1069,
 /**/

-- 
-- 
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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1teeUp-001KuT-Ut%40256bit.org.

Raspunde prin e-mail lui