Skip to content

Commit 3a7503c

Browse files
committed
patch 8.2.2957: using getchar() in Vim9 script is problematic
Problem: Using getchar() in Vim9 script is problematic. Solution: Add getcharstr(). (closes #8343)
1 parent f05d2fc commit 3a7503c

6 files changed

Lines changed: 70 additions & 5 deletions

File tree

runtime/doc/eval.txt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2594,10 +2594,12 @@ getbufline({expr}, {lnum} [, {end}])
25942594
getbufvar({expr}, {varname} [, {def}])
25952595
any variable {varname} in buffer {expr}
25962596
getchangelist([{expr}]) List list of change list items
2597-
getchar([expr]) Number get one character from the user
2597+
getchar([expr]) Number or String
2598+
get one character from the user
25982599
getcharmod() Number modifiers for the last typed character
25992600
getcharpos({expr}) List position of cursor, mark, etc.
26002601
getcharsearch() Dict last character search
2602+
getcharstr([expr]) String get one character from the user
26012603
getcmdline() String return the current command-line
26022604
getcmdpos() Number return cursor position in command-line
26032605
getcmdtype() String return current command-line type
@@ -5232,6 +5234,7 @@ getchar([expr]) *getchar()*
52325234
Return zero otherwise.
52335235
If [expr] is 1, only check if a character is available, it is
52345236
not consumed. Return zero if no character available.
5237+
If you prefer always getting a string use |getcharstr()|.
52355238

52365239
Without [expr] and when [expr] is 0 a whole character or
52375240
special key is returned. If it is a single character, the
@@ -5357,6 +5360,20 @@ getcharsearch() *getcharsearch()*
53575360
:nnoremap <expr> , getcharsearch().forward ? ',' : ';'
53585361
< Also see |setcharsearch()|.
53595362

5363+
5364+
getcharstr([expr]) *getcharstr()*
5365+
Get a single character from the user or input stream as a
5366+
string.
5367+
If [expr] is omitted, wait until a character is available.
5368+
If [expr] is 0 or false, only get a character when one is
5369+
available. Return an empty string otherwise.
5370+
If [expr] is 1 or true, only check if a character is
5371+
available, it is not consumed. Return an empty string
5372+
if no character is available.
5373+
Otherwise this works like |getchar()|, except that a number
5374+
result is converted to a string.
5375+
5376+
53605377
getcmdline() *getcmdline()*
53615378
Return the current command-line. Only works when the command
53625379
line is being edited, thus requires use of |c_CTRL-\_e| or

src/evalfunc.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -945,13 +945,15 @@ static funcentry_T global_functions[] =
945945
{"getchangelist", 0, 1, FEARG_1, NULL,
946946
ret_list_any, f_getchangelist},
947947
{"getchar", 0, 1, 0, NULL,
948-
ret_number, f_getchar},
948+
ret_any, f_getchar},
949949
{"getcharmod", 0, 0, 0, NULL,
950950
ret_number, f_getcharmod},
951951
{"getcharpos", 1, 1, FEARG_1, NULL,
952952
ret_list_number, f_getcharpos},
953953
{"getcharsearch", 0, 0, 0, NULL,
954954
ret_dict_any, f_getcharsearch},
955+
{"getcharstr", 0, 1, 0, NULL,
956+
ret_string, f_getcharstr},
955957
{"getcmdline", 0, 0, 0, NULL,
956958
ret_string, f_getcmdline},
957959
{"getcmdpos", 0, 0, 0, NULL,

src/getchar.c

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2016,10 +2016,10 @@ char_avail(void)
20162016

20172017
#if defined(FEAT_EVAL) || defined(PROTO)
20182018
/*
2019-
* "getchar()" function
2019+
* "getchar()" and "getcharstr()" functions
20202020
*/
2021-
void
2022-
f_getchar(typval_T *argvars, typval_T *rettv)
2021+
static void
2022+
getchar_common(typval_T *argvars, typval_T *rettv)
20232023
{
20242024
varnumber_T n;
20252025
int error = FALSE;
@@ -2126,6 +2126,42 @@ f_getchar(typval_T *argvars, typval_T *rettv)
21262126
}
21272127
}
21282128

2129+
/*
2130+
* "getchar()" function
2131+
*/
2132+
void
2133+
f_getchar(typval_T *argvars, typval_T *rettv)
2134+
{
2135+
getchar_common(argvars, rettv);
2136+
}
2137+
2138+
/*
2139+
* "getcharstr()" function
2140+
*/
2141+
void
2142+
f_getcharstr(typval_T *argvars, typval_T *rettv)
2143+
{
2144+
getchar_common(argvars, rettv);
2145+
2146+
if (rettv->v_type == VAR_NUMBER)
2147+
{
2148+
char_u temp[7]; // mbyte-char: 6, NUL: 1
2149+
varnumber_T n = rettv->vval.v_number;
2150+
int i = 0;
2151+
2152+
if (n != 0)
2153+
{
2154+
if (has_mbyte)
2155+
i += (*mb_char2bytes)(n, temp + i);
2156+
else
2157+
temp[i++] = n;
2158+
}
2159+
temp[i++] = NUL;
2160+
rettv->v_type = VAR_STRING;
2161+
rettv->vval.v_string = vim_strsave(temp);
2162+
}
2163+
}
2164+
21292165
/*
21302166
* "getcharmod()" function
21312167
*/

src/proto/getchar.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ int vpeekc_nomap(void);
4646
int vpeekc_any(void);
4747
int char_avail(void);
4848
void f_getchar(typval_T *argvars, typval_T *rettv);
49+
void f_getcharstr(typval_T *argvars, typval_T *rettv);
4950
void f_getcharmod(typval_T *argvars, typval_T *rettv);
5051
void parse_queued_messages(void);
5152
void vungetc(int c);

src/testdir/test_functions.vim

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1729,6 +1729,13 @@ endfunc
17291729
func Test_getchar()
17301730
call feedkeys('a', '')
17311731
call assert_equal(char2nr('a'), getchar())
1732+
call assert_equal(0, getchar(0))
1733+
call assert_equal(0, getchar(1))
1734+
1735+
call feedkeys('a', '')
1736+
call assert_equal('a', getcharstr())
1737+
call assert_equal('', getcharstr(0))
1738+
call assert_equal('', getcharstr(1))
17321739

17331740
call setline(1, 'xxxx')
17341741
call test_setmouse(1, 3)

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2957,
753755
/**/
754756
2956,
755757
/**/

0 commit comments

Comments
 (0)