mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge #6480 from ZyX-I/colored-cmdline'/input-dict
This commit is contained in:
commit
17531ed082
@ -4665,10 +4665,23 @@ index({list}, {expr} [, {start} [, {ic}]]) *index()*
|
|||||||
|
|
||||||
|
|
||||||
input({prompt} [, {text} [, {completion}]]) *input()*
|
input({prompt} [, {text} [, {completion}]]) *input()*
|
||||||
|
input({opts})
|
||||||
The result is a String, which is whatever the user typed on
|
The result is a String, which is whatever the user typed on
|
||||||
the command-line. The {prompt} argument is either a prompt
|
the command-line. The {prompt} argument is either a prompt
|
||||||
string, or a blank string (for no prompt). A '\n' can be used
|
string, or a blank string (for no prompt). A '\n' can be used
|
||||||
in the prompt to start a new line.
|
in the prompt to start a new line.
|
||||||
|
|
||||||
|
In the second form it accepts a single dictionary with the
|
||||||
|
following keys, any of which may be omitted:
|
||||||
|
|
||||||
|
Key Default Description ~
|
||||||
|
prompt "" Same as {prompt} in the first form.
|
||||||
|
default "" Same as {text} in the first form.
|
||||||
|
completion nothing Same as {completion} in the first form.
|
||||||
|
cancelreturn "" Same as {cancelreturn} from
|
||||||
|
|inputdialog()|. Also works with
|
||||||
|
input().
|
||||||
|
|
||||||
The highlighting set with |:echohl| is used for the prompt.
|
The highlighting set with |:echohl| is used for the prompt.
|
||||||
The input is entered just like a command-line, with the same
|
The input is entered just like a command-line, with the same
|
||||||
editing commands and mappings. There is a separate history
|
editing commands and mappings. There is a separate history
|
||||||
@ -4710,6 +4723,7 @@ input({prompt} [, {text} [, {completion}]]) *input()*
|
|||||||
:endfunction
|
:endfunction
|
||||||
|
|
||||||
inputdialog({prompt} [, {text} [, {cancelreturn}]]) *inputdialog()*
|
inputdialog({prompt} [, {text} [, {cancelreturn}]]) *inputdialog()*
|
||||||
|
inputdialog({opts})
|
||||||
Like |input()|, but when the GUI is running and text dialogs
|
Like |input()|, but when the GUI is running and text dialogs
|
||||||
are supported, a dialog window pops up to input the text.
|
are supported, a dialog window pops up to input the text.
|
||||||
Example: >
|
Example: >
|
||||||
@ -4721,7 +4735,6 @@ inputdialog({prompt} [, {text} [, {cancelreturn}]]) *inputdialog()*
|
|||||||
omitted an empty string is returned.
|
omitted an empty string is returned.
|
||||||
Hitting <Enter> works like pressing the OK button. Hitting
|
Hitting <Enter> works like pressing the OK button. Hitting
|
||||||
<Esc> works like pressing the Cancel button.
|
<Esc> works like pressing the Cancel button.
|
||||||
NOTE: Command-line completion is not supported.
|
|
||||||
|
|
||||||
inputlist({textlist}) *inputlist()*
|
inputlist({textlist}) *inputlist()*
|
||||||
{textlist} must be a |List| of strings. This |List| is
|
{textlist} must be a |List| of strings. This |List| is
|
||||||
|
@ -244,6 +244,10 @@ Lua interface (|if_lua.txt|):
|
|||||||
- Lua has direct access to Nvim |API| via `vim.api`.
|
- Lua has direct access to Nvim |API| via `vim.api`.
|
||||||
- Currently, most legacy Vim features are missing.
|
- Currently, most legacy Vim features are missing.
|
||||||
|
|
||||||
|
|input()| and |inputdialog()| gained support for each other’s features (return
|
||||||
|
on cancel and completion respectively) via dictionary argument (replaces all
|
||||||
|
other arguments if used).
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
5. Missing legacy features *nvim-features-missing*
|
5. Missing legacy features *nvim-features-missing*
|
||||||
|
|
||||||
|
169
src/nvim/eval.c
169
src/nvim/eval.c
@ -10980,81 +10980,122 @@ void get_user_input(const typval_T *const argvars,
|
|||||||
typval_T *const rettv, const bool inputdialog)
|
typval_T *const rettv, const bool inputdialog)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
const char *prompt = tv_get_string_chk(&argvars[0]);
|
|
||||||
int cmd_silent_save = cmd_silent;
|
|
||||||
int xp_type = EXPAND_NOTHING;
|
|
||||||
char_u *xp_arg = NULL;
|
|
||||||
|
|
||||||
rettv->v_type = VAR_STRING;
|
rettv->v_type = VAR_STRING;
|
||||||
rettv->vval.v_string = NULL;
|
rettv->vval.v_string = NULL;
|
||||||
|
|
||||||
cmd_silent = FALSE; /* Want to see the prompt. */
|
const char *prompt = "";
|
||||||
if (prompt != NULL) {
|
const char *defstr = "";
|
||||||
// Only the part of the message after the last NL is considered as
|
const char *cancelreturn = NULL;
|
||||||
// prompt for the command line.
|
const char *xp_name = NULL;
|
||||||
const char *p = strrchr(prompt, '\n');
|
char prompt_buf[NUMBUFLEN];
|
||||||
if (p == NULL) {
|
char defstr_buf[NUMBUFLEN];
|
||||||
p = prompt;
|
char cancelreturn_buf[NUMBUFLEN];
|
||||||
} else {
|
char xp_name_buf[NUMBUFLEN];
|
||||||
p++;
|
if (argvars[0].v_type == VAR_DICT) {
|
||||||
msg_start();
|
|
||||||
msg_clr_eos();
|
|
||||||
msg_puts_attr_len(prompt, p - prompt, echo_attr);
|
|
||||||
msg_didout = false;
|
|
||||||
msg_starthere();
|
|
||||||
}
|
|
||||||
cmdline_row = msg_row;
|
|
||||||
|
|
||||||
const char *defstr = "";
|
|
||||||
char buf[NUMBUFLEN];
|
|
||||||
if (argvars[1].v_type != VAR_UNKNOWN) {
|
if (argvars[1].v_type != VAR_UNKNOWN) {
|
||||||
defstr = tv_get_string_buf_chk(&argvars[1], buf);
|
emsgf(_("E5050: {opts} must be the only argument"));
|
||||||
if (defstr != NULL) {
|
return;
|
||||||
stuffReadbuffSpec(defstr);
|
}
|
||||||
|
const dict_T *const dict = argvars[0].vval.v_dict;
|
||||||
|
prompt = tv_dict_get_string_buf_chk(dict, S_LEN("prompt"), prompt_buf, "");
|
||||||
|
if (prompt == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
defstr = tv_dict_get_string_buf_chk(dict, S_LEN("default"), defstr_buf, "");
|
||||||
|
if (defstr == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char def[1] = { 0 };
|
||||||
|
cancelreturn = tv_dict_get_string_buf_chk(dict, S_LEN("cancelreturn"),
|
||||||
|
cancelreturn_buf, def);
|
||||||
|
if (cancelreturn == NULL) { // error
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (*cancelreturn == NUL) {
|
||||||
|
cancelreturn = NULL;
|
||||||
|
}
|
||||||
|
xp_name = tv_dict_get_string_buf_chk(dict, S_LEN("completion"),
|
||||||
|
xp_name_buf, def);
|
||||||
|
if (xp_name == NULL) { // error
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (xp_name == def) { // default to NULL
|
||||||
|
xp_name = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
prompt = tv_get_string_buf_chk(&argvars[0], prompt_buf);
|
||||||
|
if (prompt == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (argvars[1].v_type != VAR_UNKNOWN) {
|
||||||
|
defstr = tv_get_string_buf_chk(&argvars[1], defstr_buf);
|
||||||
|
if (defstr == NULL) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||||
if (!inputdialog && argvars[2].v_type != VAR_UNKNOWN) {
|
const char *const arg2 = tv_get_string_buf_chk(&argvars[2],
|
||||||
char buf2[NUMBUFLEN];
|
cancelreturn_buf);
|
||||||
// input() with a third argument: completion
|
if (arg2 == NULL) {
|
||||||
rettv->vval.v_string = NULL;
|
|
||||||
|
|
||||||
const char *const xp_name = tv_get_string_buf_chk(&argvars[2], buf2);
|
|
||||||
if (xp_name == NULL) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (inputdialog) {
|
||||||
const int xp_namelen = (int)strlen(xp_name);
|
cancelreturn = arg2;
|
||||||
|
} else {
|
||||||
uint32_t argt;
|
xp_name = arg2;
|
||||||
if (parse_compl_arg((char_u *)xp_name, xp_namelen, &xp_type, &argt,
|
|
||||||
&xp_arg) == FAIL) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defstr != NULL) {
|
|
||||||
int save_ex_normal_busy = ex_normal_busy;
|
|
||||||
ex_normal_busy = 0;
|
|
||||||
rettv->vval.v_string =
|
|
||||||
getcmdline_prompt(inputsecret_flag ? NUL : '@', (char_u *)p, echo_attr,
|
|
||||||
xp_type, xp_arg);
|
|
||||||
ex_normal_busy = save_ex_normal_busy;
|
|
||||||
}
|
|
||||||
if (inputdialog && rettv->vval.v_string == NULL
|
|
||||||
&& argvars[1].v_type != VAR_UNKNOWN
|
|
||||||
&& argvars[2].v_type != VAR_UNKNOWN) {
|
|
||||||
char buf[NUMBUFLEN];
|
|
||||||
rettv->vval.v_string = (char_u *)xstrdup(tv_get_string_buf(
|
|
||||||
&argvars[2], buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
xfree(xp_arg);
|
|
||||||
|
|
||||||
/* since the user typed this, no need to wait for return */
|
|
||||||
need_wait_return = FALSE;
|
|
||||||
msg_didout = FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int xp_type = EXPAND_NOTHING;
|
||||||
|
char *xp_arg = NULL;
|
||||||
|
if (xp_name != NULL) {
|
||||||
|
// input() with a third argument: completion
|
||||||
|
const int xp_namelen = (int)strlen(xp_name);
|
||||||
|
|
||||||
|
uint32_t argt;
|
||||||
|
if (parse_compl_arg((char_u *)xp_name, xp_namelen, &xp_type,
|
||||||
|
&argt, (char_u **)&xp_arg) == FAIL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmd_silent_save = cmd_silent;
|
||||||
|
|
||||||
|
cmd_silent = false; // Want to see the prompt.
|
||||||
|
// Only the part of the message after the last NL is considered as
|
||||||
|
// prompt for the command line.
|
||||||
|
const char *p = strrchr(prompt, '\n');
|
||||||
|
if (p == NULL) {
|
||||||
|
p = prompt;
|
||||||
|
} else {
|
||||||
|
p++;
|
||||||
|
msg_start();
|
||||||
|
msg_clr_eos();
|
||||||
|
msg_puts_attr_len(prompt, p - prompt, echo_attr);
|
||||||
|
msg_didout = false;
|
||||||
|
msg_starthere();
|
||||||
|
}
|
||||||
|
cmdline_row = msg_row;
|
||||||
|
|
||||||
|
stuffReadbuffSpec(defstr);
|
||||||
|
|
||||||
|
int save_ex_normal_busy = ex_normal_busy;
|
||||||
|
ex_normal_busy = 0;
|
||||||
|
rettv->vval.v_string =
|
||||||
|
getcmdline_prompt(inputsecret_flag ? NUL : '@', (char_u *)p, echo_attr,
|
||||||
|
xp_type, (char_u *)xp_arg);
|
||||||
|
ex_normal_busy = save_ex_normal_busy;
|
||||||
|
|
||||||
|
if (rettv->vval.v_string == NULL && cancelreturn != NULL) {
|
||||||
|
rettv->vval.v_string = (char_u *)xstrdup(cancelreturn);
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree(xp_arg);
|
||||||
|
|
||||||
|
// Since the user typed this, no need to wait for return.
|
||||||
|
need_wait_return = false;
|
||||||
|
msg_didout = false;
|
||||||
cmd_silent = cmd_silent_save;
|
cmd_silent = cmd_silent_save;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1210,7 +1210,8 @@ char *tv_dict_get_string(const dict_T *const d, const char *const key,
|
|||||||
///
|
///
|
||||||
/// @param[in] d Dictionary to get item from.
|
/// @param[in] d Dictionary to get item from.
|
||||||
/// @param[in] key Dictionary key.
|
/// @param[in] key Dictionary key.
|
||||||
/// @param[in] numbuf Numbuf for.
|
/// @param[in] numbuf Buffer for non-string items converted to strings, at
|
||||||
|
/// least of #NUMBUFLEN length.
|
||||||
///
|
///
|
||||||
/// @return NULL if key does not exist, empty string in case of type error,
|
/// @return NULL if key does not exist, empty string in case of type error,
|
||||||
/// string item value otherwise.
|
/// string item value otherwise.
|
||||||
@ -1225,6 +1226,32 @@ const char *tv_dict_get_string_buf(const dict_T *const d, const char *const key,
|
|||||||
return tv_get_string_buf(&di->di_tv, numbuf);
|
return tv_get_string_buf(&di->di_tv, numbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a string item from a dictionary
|
||||||
|
///
|
||||||
|
/// @param[in] d Dictionary to get item from.
|
||||||
|
/// @param[in] key Dictionary key.
|
||||||
|
/// @param[in] key_len Key length.
|
||||||
|
/// @param[in] numbuf Buffer for non-string items converted to strings, at
|
||||||
|
/// least of #NUMBUFLEN length.
|
||||||
|
/// @param[in] def Default return when key does not exist.
|
||||||
|
///
|
||||||
|
/// @return `def` when key does not exist,
|
||||||
|
/// NULL in case of type error,
|
||||||
|
/// string item value in case of success.
|
||||||
|
const char *tv_dict_get_string_buf_chk(const dict_T *const d,
|
||||||
|
const char *const key,
|
||||||
|
const ptrdiff_t key_len,
|
||||||
|
char *const numbuf,
|
||||||
|
const char *const def)
|
||||||
|
FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
|
{
|
||||||
|
const dictitem_T *const di = tv_dict_find(d, key, key_len);
|
||||||
|
if (di == NULL) {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
return tv_get_string_buf_chk(&di->di_tv, numbuf);
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a function from a dictionary
|
/// Get a function from a dictionary
|
||||||
///
|
///
|
||||||
/// @param[in] d Dictionary to get callback from.
|
/// @param[in] d Dictionary to get callback from.
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
local helpers = require('test.functional.helpers')(after_each)
|
local helpers = require('test.functional.helpers')(after_each)
|
||||||
local Screen = require('test.functional.ui.screen')
|
local Screen = require('test.functional.ui.screen')
|
||||||
|
|
||||||
|
local eq = helpers.eq
|
||||||
local feed = helpers.feed
|
local feed = helpers.feed
|
||||||
|
local meths = helpers.meths
|
||||||
local clear = helpers.clear
|
local clear = helpers.clear
|
||||||
|
local source = helpers.source
|
||||||
local command = helpers.command
|
local command = helpers.command
|
||||||
|
local exc_exec = helpers.exc_exec
|
||||||
|
|
||||||
local screen
|
local screen
|
||||||
|
|
||||||
@ -11,28 +15,352 @@ before_each(function()
|
|||||||
clear()
|
clear()
|
||||||
screen = Screen.new(25, 5)
|
screen = Screen.new(25, 5)
|
||||||
screen:attach()
|
screen:attach()
|
||||||
|
source([[
|
||||||
|
hi Test ctermfg=Red guifg=Red term=bold
|
||||||
|
function CustomCompl(...)
|
||||||
|
return 'TEST'
|
||||||
|
endfunction
|
||||||
|
function CustomListCompl(...)
|
||||||
|
return ['FOO']
|
||||||
|
endfunction
|
||||||
|
]])
|
||||||
|
screen:set_default_attr_ids({
|
||||||
|
EOB={bold = true, foreground = Screen.colors.Blue1},
|
||||||
|
T={foreground=Screen.colors.Red},
|
||||||
|
})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('input()', function()
|
describe('input()', function()
|
||||||
it('works correctly with multiline prompts', function()
|
it('works with multiline prompts', function()
|
||||||
feed([[:call input("Test\nFoo")<CR>]])
|
feed([[:call input("Test\nFoo")<CR>]])
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
{1:~ }|
|
{EOB:~ }|
|
||||||
{1:~ }|
|
{EOB:~ }|
|
||||||
{1:~ }|
|
{EOB:~ }|
|
||||||
Test |
|
Test |
|
||||||
Foo^ |
|
Foo^ |
|
||||||
]], {{bold=true, foreground=Screen.colors.Blue}})
|
]])
|
||||||
end)
|
end)
|
||||||
it('works correctly with multiline prompts and :echohl', function()
|
it('works with multiline prompts and :echohl', function()
|
||||||
command('hi Test ctermfg=Red guifg=Red term=bold')
|
|
||||||
feed([[:echohl Test | call input("Test\nFoo")<CR>]])
|
feed([[:echohl Test | call input("Test\nFoo")<CR>]])
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
{1:~ }|
|
{EOB:~ }|
|
||||||
{1:~ }|
|
{EOB:~ }|
|
||||||
{1:~ }|
|
{EOB:~ }|
|
||||||
{2:Test} |
|
{T:Test} |
|
||||||
{2:Foo}^ |
|
{T:Foo}^ |
|
||||||
]], {{bold=true, foreground=Screen.colors.Blue}, {foreground=Screen.colors.Red}})
|
]])
|
||||||
|
command('redraw!')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:Foo}^ |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
it('allows unequal numeric arguments when using multiple args', function()
|
||||||
|
command('echohl Test')
|
||||||
|
feed([[:call input(1, 2)<CR>]])
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:1}2^ |
|
||||||
|
]])
|
||||||
|
feed('<BS>')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:1}^ |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
it('allows unequal numeric values when using {opts} dictionary', function()
|
||||||
|
command('echohl Test')
|
||||||
|
meths.set_var('opts', {prompt=1, default=2, cancelreturn=3})
|
||||||
|
feed([[:echo input(opts)<CR>]])
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:1}2^ |
|
||||||
|
]])
|
||||||
|
feed('<BS>')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:1}^ |
|
||||||
|
]])
|
||||||
|
feed('<Esc>')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:3} |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
it('works with redraw', function()
|
||||||
|
command('echohl Test')
|
||||||
|
meths.set_var('opts', {prompt='Foo>', default='Bar'})
|
||||||
|
feed([[:echo inputdialog(opts)<CR>]])
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:Foo>}Bar^ |
|
||||||
|
]])
|
||||||
|
command('redraw!')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:Foo>}Bar^ |
|
||||||
|
]])
|
||||||
|
feed('<BS>')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:Foo>}Ba^ |
|
||||||
|
]])
|
||||||
|
command('redraw!')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:Foo>}Ba^ |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
it('allows omitting everything with dictionary argument', function()
|
||||||
|
command('echohl Test')
|
||||||
|
feed([[:call input({})<CR>]])
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
^ |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
it('supports completion', function()
|
||||||
|
feed(':let var = input("", "", "custom,CustomCompl")<CR>')
|
||||||
|
feed('<Tab><CR>')
|
||||||
|
eq('TEST', meths.get_var('var'))
|
||||||
|
|
||||||
|
feed(':let var = input({"completion": "customlist,CustomListCompl"})<CR>')
|
||||||
|
feed('<Tab><CR>')
|
||||||
|
eq('FOO', meths.get_var('var'))
|
||||||
|
end)
|
||||||
|
it('supports cancelreturn', function()
|
||||||
|
feed(':let var = input({"cancelreturn": "BAR"})<CR>')
|
||||||
|
feed('<Esc>')
|
||||||
|
eq('BAR', meths.get_var('var'))
|
||||||
|
end)
|
||||||
|
it('supports default string', function()
|
||||||
|
feed(':let var = input("", "DEF1")<CR>')
|
||||||
|
feed('<CR>')
|
||||||
|
eq('DEF1', meths.get_var('var'))
|
||||||
|
|
||||||
|
feed(':let var = input({"default": "DEF2"})<CR>')
|
||||||
|
feed('<CR>')
|
||||||
|
eq('DEF2', meths.get_var('var'))
|
||||||
|
end)
|
||||||
|
it('errors out on invalid inputs', function()
|
||||||
|
eq('Vim(call):E730: using List as a String',
|
||||||
|
exc_exec('call input([])'))
|
||||||
|
eq('Vim(call):E730: using List as a String',
|
||||||
|
exc_exec('call input("", [])'))
|
||||||
|
eq('Vim(call):E730: using List as a String',
|
||||||
|
exc_exec('call input("", "", [])'))
|
||||||
|
eq('Vim(call):E730: using List as a String',
|
||||||
|
exc_exec('call input({"prompt": []})'))
|
||||||
|
eq('Vim(call):E730: using List as a String',
|
||||||
|
exc_exec('call input({"cancelreturn": []})'))
|
||||||
|
eq('Vim(call):E730: using List as a String',
|
||||||
|
exc_exec('call input({"default": []})'))
|
||||||
|
eq('Vim(call):E730: using List as a String',
|
||||||
|
exc_exec('call input({"completion": []})'))
|
||||||
|
eq('Vim(call):E5050: {opts} must be the only argument',
|
||||||
|
exc_exec('call input({}, "default")'))
|
||||||
|
eq('Vim(call):E118: Too many arguments for function: input',
|
||||||
|
exc_exec('call input("prompt> ", "default", "file", "extra")'))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
describe('inputdialog()', function()
|
||||||
|
it('works with multiline prompts', function()
|
||||||
|
feed([[:call inputdialog("Test\nFoo")<CR>]])
|
||||||
|
screen:expect([[
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
Test |
|
||||||
|
Foo^ |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
it('works with multiline prompts and :echohl', function()
|
||||||
|
feed([[:echohl Test | call inputdialog("Test\nFoo")<CR>]])
|
||||||
|
screen:expect([[
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:Test} |
|
||||||
|
{T:Foo}^ |
|
||||||
|
]])
|
||||||
|
command('redraw!')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:Foo}^ |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
it('allows unequal numeric arguments when using multiple args', function()
|
||||||
|
command('echohl Test')
|
||||||
|
feed([[:call inputdialog(1, 2)<CR>]])
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:1}2^ |
|
||||||
|
]])
|
||||||
|
feed('<BS>')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:1}^ |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
it('allows unequal numeric values when using {opts} dictionary', function()
|
||||||
|
command('echohl Test')
|
||||||
|
meths.set_var('opts', {prompt=1, default=2, cancelreturn=3})
|
||||||
|
feed([[:echo input(opts)<CR>]])
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:1}2^ |
|
||||||
|
]])
|
||||||
|
feed('<BS>')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:1}^ |
|
||||||
|
]])
|
||||||
|
feed('<Esc>')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:3} |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
it('works with redraw', function()
|
||||||
|
command('echohl Test')
|
||||||
|
meths.set_var('opts', {prompt='Foo>', default='Bar'})
|
||||||
|
feed([[:echo input(opts)<CR>]])
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:Foo>}Bar^ |
|
||||||
|
]])
|
||||||
|
command('redraw!')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:Foo>}Bar^ |
|
||||||
|
]])
|
||||||
|
feed('<BS>')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:Foo>}Ba^ |
|
||||||
|
]])
|
||||||
|
command('redraw!')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{T:Foo>}Ba^ |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
it('allows omitting everything with dictionary argument', function()
|
||||||
|
command('echohl Test')
|
||||||
|
feed(':echo inputdialog({})<CR>')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
^ |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
it('supports completion', function()
|
||||||
|
feed(':let var = inputdialog({"completion": "customlist,CustomListCompl"})<CR>')
|
||||||
|
feed('<Tab><CR>')
|
||||||
|
eq('FOO', meths.get_var('var'))
|
||||||
|
end)
|
||||||
|
it('supports cancelreturn', function()
|
||||||
|
feed(':let var = inputdialog("", "", "CR1")<CR>')
|
||||||
|
feed('<Esc>')
|
||||||
|
eq('CR1', meths.get_var('var'))
|
||||||
|
|
||||||
|
feed(':let var = inputdialog({"cancelreturn": "BAR"})<CR>')
|
||||||
|
feed('<Esc>')
|
||||||
|
eq('BAR', meths.get_var('var'))
|
||||||
|
end)
|
||||||
|
it('supports default string', function()
|
||||||
|
feed(':let var = inputdialog("", "DEF1")<CR>')
|
||||||
|
feed('<CR>')
|
||||||
|
eq('DEF1', meths.get_var('var'))
|
||||||
|
|
||||||
|
feed(':let var = inputdialog({"default": "DEF2"})<CR>')
|
||||||
|
feed('<CR>')
|
||||||
|
eq('DEF2', meths.get_var('var'))
|
||||||
|
end)
|
||||||
|
it('errors out on invalid inputs', function()
|
||||||
|
eq('Vim(call):E730: using List as a String',
|
||||||
|
exc_exec('call inputdialog([])'))
|
||||||
|
eq('Vim(call):E730: using List as a String',
|
||||||
|
exc_exec('call inputdialog("", [])'))
|
||||||
|
eq('Vim(call):E730: using List as a String',
|
||||||
|
exc_exec('call inputdialog("", "", [])'))
|
||||||
|
eq('Vim(call):E730: using List as a String',
|
||||||
|
exc_exec('call inputdialog({"prompt": []})'))
|
||||||
|
eq('Vim(call):E730: using List as a String',
|
||||||
|
exc_exec('call inputdialog({"cancelreturn": []})'))
|
||||||
|
eq('Vim(call):E730: using List as a String',
|
||||||
|
exc_exec('call inputdialog({"default": []})'))
|
||||||
|
eq('Vim(call):E730: using List as a String',
|
||||||
|
exc_exec('call inputdialog({"completion": []})'))
|
||||||
|
eq('Vim(call):E5050: {opts} must be the only argument',
|
||||||
|
exc_exec('call inputdialog({}, "default")'))
|
||||||
|
eq('Vim(call):E118: Too many arguments for function: inputdialog',
|
||||||
|
exc_exec('call inputdialog("prompt> ", "default", "file", "extra")'))
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -1751,6 +1751,55 @@ describe('typval.c', function()
|
|||||||
eq('2', s)
|
eq('2', s)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
describe('get_string_buf_chk()', function()
|
||||||
|
local function tv_dict_get_string_buf_chk(d, key, len, buf, def, emsg)
|
||||||
|
buf = buf or ffi.gc(lib.xmalloc(lib.NUMBUFLEN), lib.xfree)
|
||||||
|
def = def or ffi.gc(lib.xstrdup('DEFAULT'), lib.xfree)
|
||||||
|
len = len or #key
|
||||||
|
alloc_log:clear()
|
||||||
|
local ret = check_emsg(function() return lib.tv_dict_get_string_buf_chk(d, key, len, buf, def) end,
|
||||||
|
emsg)
|
||||||
|
local s_ret = (ret ~= nil) and ffi.string(ret) or nil
|
||||||
|
if not emsg then
|
||||||
|
alloc_log:check({})
|
||||||
|
end
|
||||||
|
return s_ret, ret, buf, def
|
||||||
|
end
|
||||||
|
itp('works with NULL dict', function()
|
||||||
|
eq('DEFAULT', tv_dict_get_string_buf_chk(nil, 'test'))
|
||||||
|
end)
|
||||||
|
itp('works', function()
|
||||||
|
local lua_d = {
|
||||||
|
['']={},
|
||||||
|
t=1,
|
||||||
|
te=int(2),
|
||||||
|
tes=empty_list,
|
||||||
|
test='tset',
|
||||||
|
testt=5,
|
||||||
|
}
|
||||||
|
local d = dict(lua_d)
|
||||||
|
alloc_log:clear()
|
||||||
|
eq(lua_d, dct2tbl(d))
|
||||||
|
alloc_log:check({})
|
||||||
|
local s, r, b, def
|
||||||
|
s, r, b, def = tv_dict_get_string_buf_chk(d, 'test')
|
||||||
|
neq(r, b)
|
||||||
|
neq(r, def)
|
||||||
|
eq('tset', s)
|
||||||
|
s, r, b, def = tv_dict_get_string_buf_chk(d, 'test', 1, nil, nil, 'E806: using Float as a String')
|
||||||
|
neq(r, b)
|
||||||
|
neq(r, def)
|
||||||
|
eq(nil, s)
|
||||||
|
s, r, b, def = tv_dict_get_string_buf_chk(d, 'te')
|
||||||
|
eq(r, b)
|
||||||
|
neq(r, def)
|
||||||
|
eq('2', s)
|
||||||
|
s, r, b, def = tv_dict_get_string_buf_chk(d, 'TEST')
|
||||||
|
eq(r, def)
|
||||||
|
neq(r, b)
|
||||||
|
eq('DEFAULT', s)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
describe('get_callback()', function()
|
describe('get_callback()', function()
|
||||||
local function tv_dict_get_callback(d, key, key_len, emsg)
|
local function tv_dict_get_callback(d, key, key_len, emsg)
|
||||||
key_len = key_len or #key
|
key_len = key_len or #key
|
||||||
|
Loading…
Reference in New Issue
Block a user