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 <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
001c26cd61
commit
edf0f7db28
@ -3953,6 +3953,13 @@ getchar([{expr} [, {opts}]]) *getchar()*
|
|||||||
The optional argument {opts} is a Dict and supports the
|
The optional argument {opts} is a Dict and supports the
|
||||||
following items:
|
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
|
number If |TRUE|, return a Number when getting
|
||||||
a single character.
|
a single character.
|
||||||
If |FALSE|, the return value is always
|
If |FALSE|, the return value is always
|
||||||
|
|||||||
@ -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
|
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.
|
When converting screen column to text position use this.
|
||||||
The line number can be obtained from win->w_lines[].
|
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.
|
test_arglist func Test_all_not_allowed_from_cmdwin() hangs on MS-Windows.
|
||||||
|
|
||||||
Can we add highlighting to ":echowindow"?
|
Can we add highlighting to ":echowindow"?
|
||||||
|
|||||||
@ -41636,6 +41636,8 @@ Changed~
|
|||||||
- add |dist#vim9#Launch()| and |dist#vim9#Open()| to the |vim-script-library|
|
- add |dist#vim9#Launch()| and |dist#vim9#Open()| to the |vim-script-library|
|
||||||
and decouple it from |netrw|
|
and decouple it from |netrw|
|
||||||
- new digraph "APPROACHES THE LIMIT" using ".="
|
- 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-9.2*
|
||||||
Added ~
|
Added ~
|
||||||
|
|||||||
@ -2386,9 +2386,11 @@ char_avail(void)
|
|||||||
static void
|
static void
|
||||||
getchar_common(typval_T *argvars, typval_T *rettv, int allow_number)
|
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 error = FALSE;
|
||||||
int simplify = TRUE;
|
int simplify = TRUE;
|
||||||
|
char_u cursor_flag = 'm';
|
||||||
|
|
||||||
if ((in_vim9script()
|
if ((in_vim9script()
|
||||||
&& check_for_opt_bool_or_number_arg(argvars, 0) == FAIL)
|
&& 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)
|
if (argvars[0].v_type != VAR_UNKNOWN && argvars[1].v_type == VAR_DICT)
|
||||||
{
|
{
|
||||||
dict_T *d = argvars[1].vval.v_dict;
|
dict_T *d = argvars[1].vval.v_dict;
|
||||||
|
char_u *cursor_str;
|
||||||
|
|
||||||
if (allow_number)
|
if (allow_number)
|
||||||
allow_number = dict_get_bool(d, "number", TRUE);
|
allow_number = dict_get_bool(d, "number", TRUE);
|
||||||
else if (dict_has_key(d, "number"))
|
else if (dict_has_key(d, "number"))
|
||||||
{
|
|
||||||
semsg(_(e_invalid_argument_str), "number");
|
semsg(_(e_invalid_argument_str), "number");
|
||||||
error = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
simplify = dict_get_bool(d, "simplify", 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
|
#ifdef MESSAGE_QUEUE
|
||||||
// vpeekc() used to check for messages, but that caused problems, invoking
|
// 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
|
// 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();
|
parse_queued_messages();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Position the cursor. Needed after a message that ends in a space.
|
if (cursor_flag == 'h')
|
||||||
windgoto(msg_row, msg_col);
|
cursor_sleep();
|
||||||
|
else if (cursor_flag == 'm')
|
||||||
|
windgoto(msg_row, msg_col);
|
||||||
|
|
||||||
++no_mapping;
|
++no_mapping;
|
||||||
++allow_keys;
|
++allow_keys;
|
||||||
if (!simplify)
|
if (!simplify)
|
||||||
++no_reduce_keys;
|
++no_reduce_keys;
|
||||||
while (!error)
|
for (;;)
|
||||||
{
|
{
|
||||||
if (argvars[0].v_type == VAR_UNKNOWN
|
if (argvars[0].v_type == VAR_UNKNOWN
|
||||||
|| (argvars[0].v_type == VAR_NUMBER
|
|| (argvars[0].v_type == VAR_NUMBER
|
||||||
@ -2453,6 +2470,9 @@ getchar_common(typval_T *argvars, typval_T *rettv, int allow_number)
|
|||||||
if (!simplify)
|
if (!simplify)
|
||||||
--no_reduce_keys;
|
--no_reduce_keys;
|
||||||
|
|
||||||
|
if (cursor_flag == 'h')
|
||||||
|
cursor_unsleep();
|
||||||
|
|
||||||
set_vim_var_nr(VV_MOUSE_WIN, 0);
|
set_vim_var_nr(VV_MOUSE_WIN, 0);
|
||||||
set_vim_var_nr(VV_MOUSE_WINID, 0);
|
set_vim_var_nr(VV_MOUSE_WINID, 0);
|
||||||
set_vim_var_nr(VV_MOUSE_LNUM, 0);
|
set_vim_var_nr(VV_MOUSE_LNUM, 0);
|
||||||
|
|||||||
@ -2628,6 +2628,14 @@ func Test_getchar()
|
|||||||
|
|
||||||
call assert_fails('call getchar(1, 1)', 'E1206:')
|
call assert_fails('call getchar(1, 1)', 'E1206:')
|
||||||
call assert_fails('call getcharstr(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:true})', 'E475:')
|
||||||
call assert_fails('call getcharstr(1, #{number: v:false})', 'E475:')
|
call assert_fails('call getcharstr(1, #{number: v:false})', 'E475:')
|
||||||
|
|
||||||
@ -2646,6 +2654,57 @@ func Test_getchar()
|
|||||||
enew!
|
enew!
|
||||||
endfunc
|
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()
|
func Test_libcall_libcallnr()
|
||||||
CheckFeature libcall
|
CheckFeature libcall
|
||||||
|
|
||||||
|
|||||||
@ -704,6 +704,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1070,
|
||||||
/**/
|
/**/
|
||||||
1069,
|
1069,
|
||||||
/**/
|
/**/
|
||||||
|
|||||||
Reference in New Issue
Block a user