mirror of
https://github.com/neovim/neovim
synced 2025-07-15 16:51:49 +00:00
feat(prompt): prompt_getinput() gets current input #34491
Problem: Not easy to get user-input in prompt-buffer before the user submits the input. Under the current system user/plugin needs to read the buffer contents, figure out where the prompt is, then extract the text. Solution: - Add prompt_getinput(). - Extract prompt text extraction logic to a separate function
This commit is contained in:
@ -151,6 +151,8 @@ EDITOR
|
||||
• |omnicompletion| in `help` buffer. |ft-help-omni|
|
||||
• Setting "'0" in 'shada' prevents storing the jumplist in the shada file.
|
||||
• 'shada' now correctly respects "/0" and "f0".
|
||||
• |prompt-buffer| supports multiline input/paste, undo/redo, and o/O normal
|
||||
commands.
|
||||
|
||||
EVENTS
|
||||
|
||||
@ -253,6 +255,7 @@ UI
|
||||
VIMSCRIPT
|
||||
|
||||
• |cmdcomplete_info()| gets current cmdline completion info.
|
||||
• |prompt_getinput()| gets current user-input in prompt-buffer.
|
||||
|
||||
==============================================================================
|
||||
CHANGED FEATURES *news-changed*
|
||||
|
@ -333,6 +333,7 @@ Functions:
|
||||
- |tempname()| tries to recover if the Nvim |tempdir| disappears.
|
||||
- |writefile()| with "p" flag creates parent directories.
|
||||
- |searchcount()|'s maximal value is raised from 99 to 999.
|
||||
- |prompt_getinput()|
|
||||
|
||||
Highlight groups:
|
||||
- |highlight-blend| controls blend level for a highlight group
|
||||
|
@ -7548,6 +7548,19 @@ printf({fmt}, {expr1} ...) *printf()*
|
||||
Return: ~
|
||||
(`string`)
|
||||
|
||||
prompt_getinput({buf}) *prompt_getinput()*
|
||||
Gets the current user-input in |prompt-buffer| {buf} without invoking
|
||||
prompt_callback. {buf} can be a buffer name or number.
|
||||
|
||||
If the buffer doesn't exist or isn't a prompt buffer, an empty
|
||||
string is returned.
|
||||
|
||||
Parameters: ~
|
||||
• {buf} (`integer|string`)
|
||||
|
||||
Return: ~
|
||||
(`any`)
|
||||
|
||||
prompt_getprompt({buf}) *prompt_getprompt()*
|
||||
Returns the effective prompt text for buffer {buf}. {buf} can
|
||||
be a buffer name or number. See |prompt-buffer|.
|
||||
|
10
runtime/lua/vim/_meta/vimfn.lua
generated
10
runtime/lua/vim/_meta/vimfn.lua
generated
@ -6867,6 +6867,16 @@ function vim.fn.prevnonblank(lnum) end
|
||||
--- @return string
|
||||
function vim.fn.printf(fmt, expr1) end
|
||||
|
||||
--- Gets the current user-input in |prompt-buffer| {buf} without invoking
|
||||
--- prompt_callback. {buf} can be a buffer name or number.
|
||||
---
|
||||
--- If the buffer doesn't exist or isn't a prompt buffer, an empty
|
||||
--- string is returned.
|
||||
---
|
||||
--- @param buf integer|string
|
||||
--- @return any
|
||||
function vim.fn.prompt_getinput(buf) end
|
||||
|
||||
--- Returns the effective prompt text for buffer {buf}. {buf} can
|
||||
--- be a buffer name or number. See |prompt-buffer|.
|
||||
---
|
||||
|
@ -1078,7 +1078,7 @@ check_pum:
|
||||
return 0;
|
||||
}
|
||||
if ((mod_mask & MOD_MASK_SHIFT) == 0 && bt_prompt(curbuf)) {
|
||||
invoke_prompt_callback();
|
||||
prompt_invoke_callback();
|
||||
if (!bt_prompt(curbuf)) {
|
||||
// buffer changed to a non-prompt buffer, get out of
|
||||
// Insert mode
|
||||
|
@ -8660,24 +8660,16 @@ void eval_fmt_source_name_line(char *buf, size_t bufsize)
|
||||
}
|
||||
}
|
||||
|
||||
void invoke_prompt_callback(void)
|
||||
/// Gets the current user-input in prompt buffer `buf`, or NULL if buffer is not a prompt buffer.
|
||||
char *prompt_get_input(buf_T *buf)
|
||||
{
|
||||
typval_T rettv;
|
||||
typval_T argv[2];
|
||||
linenr_T lnum_start = curbuf->b_prompt_start.mark.lnum;
|
||||
linenr_T lnum_last = curbuf->b_ml.ml_line_count;
|
||||
|
||||
// Add a new line for the prompt before invoking the callback, so that
|
||||
// text can always be inserted above the last line.
|
||||
ml_append(lnum_last, "", 0, false);
|
||||
appended_lines_mark(lnum_last, 1);
|
||||
curwin->w_cursor.lnum = lnum_last + 1;
|
||||
curwin->w_cursor.col = 0;
|
||||
|
||||
if (curbuf->b_prompt_callback.type == kCallbackNone) {
|
||||
goto theend;
|
||||
if (!bt_prompt(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
char *text = ml_get(lnum_start);
|
||||
linenr_T lnum_start = buf->b_prompt_start.mark.lnum;
|
||||
linenr_T lnum_last = buf->b_ml.ml_line_count;
|
||||
|
||||
char *text = ml_get_buf(buf, lnum_start);
|
||||
char *prompt = prompt_text();
|
||||
if (strlen(text) >= strlen(prompt)) {
|
||||
text += strlen(prompt);
|
||||
@ -8687,11 +8679,39 @@ void invoke_prompt_callback(void)
|
||||
for (linenr_T i = lnum_start + 1; i <= lnum_last; i++) {
|
||||
char *half_text = concat_str(full_text, "\n");
|
||||
xfree(full_text);
|
||||
full_text = concat_str(half_text, ml_get(i));
|
||||
full_text = concat_str(half_text, ml_get_buf(buf, i));
|
||||
xfree(half_text);
|
||||
}
|
||||
return full_text;
|
||||
}
|
||||
|
||||
/// Invokes the user-defined callback defined for the current prompt-buffer.
|
||||
void prompt_invoke_callback(void)
|
||||
{
|
||||
typval_T rettv;
|
||||
typval_T argv[2];
|
||||
linenr_T lnum = curbuf->b_ml.ml_line_count;
|
||||
|
||||
char *user_input = prompt_get_input(curbuf);
|
||||
|
||||
if (!user_input) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add a new line for the prompt before invoking the callback, so that
|
||||
// text can always be inserted above the last line.
|
||||
ml_append(lnum, "", 0, false);
|
||||
appended_lines_mark(lnum, 1);
|
||||
curwin->w_cursor.lnum = lnum + 1;
|
||||
curwin->w_cursor.col = 0;
|
||||
|
||||
if (curbuf->b_prompt_callback.type == kCallbackNone) {
|
||||
xfree(user_input);
|
||||
goto theend;
|
||||
}
|
||||
|
||||
argv[0].v_type = VAR_STRING;
|
||||
argv[0].vval.v_string = full_text;
|
||||
argv[0].vval.v_string = user_input;
|
||||
argv[1].v_type = VAR_UNKNOWN;
|
||||
|
||||
callback_call(&curbuf->b_prompt_callback, 1, argv, &rettv);
|
||||
|
@ -8332,6 +8332,21 @@ M.funcs = {
|
||||
signature = 'printf({fmt}, {expr1} ...)',
|
||||
returns = 'string',
|
||||
},
|
||||
prompt_getinput = {
|
||||
args = 1,
|
||||
base = 1,
|
||||
desc = [=[
|
||||
Gets the current user-input in |prompt-buffer| {buf} without invoking
|
||||
prompt_callback. {buf} can be a buffer name or number.
|
||||
|
||||
If the buffer doesn't exist or isn't a prompt buffer, an empty
|
||||
string is returned.
|
||||
|
||||
]=],
|
||||
name = 'prompt_getinput',
|
||||
params = { { 'buf', 'integer|string' } },
|
||||
signature = 'prompt_getinput({buf})',
|
||||
},
|
||||
prompt_getprompt = {
|
||||
args = 1,
|
||||
base = 1,
|
||||
|
@ -5364,6 +5364,26 @@ static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv, EvalFuncData
|
||||
buf->b_prompt_text = xstrdup(text);
|
||||
}
|
||||
|
||||
/// "prompt_getinput({buffer})" function
|
||||
static void f_prompt_getinput(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
// return an empty string by default, e.g. it's not a prompt buffer
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = NULL;
|
||||
|
||||
buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
|
||||
if (buf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bt_prompt(buf)) {
|
||||
return;
|
||||
}
|
||||
|
||||
rettv->vval.v_string = prompt_get_input(buf);
|
||||
}
|
||||
|
||||
/// "pum_getpos()" function
|
||||
static void f_pum_getpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
|
@ -3853,7 +3853,7 @@ static void nv_down(cmdarg_T *cap)
|
||||
} else if (bt_prompt(curbuf) && cap->cmdchar == CAR
|
||||
&& curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) {
|
||||
// In a prompt buffer a <CR> in the last line invokes the callback.
|
||||
invoke_prompt_callback();
|
||||
prompt_invoke_callback();
|
||||
if (restart_edit == 0) {
|
||||
restart_edit = 'a';
|
||||
}
|
||||
|
@ -249,6 +249,8 @@ describe('prompt buffer', function()
|
||||
|
||||
it('can insert multiline text', function()
|
||||
source_script()
|
||||
local buf = api.nvim_get_current_buf()
|
||||
|
||||
feed('line 1<s-cr>line 2<s-cr>line 3')
|
||||
screen:expect([[
|
||||
cmd: line 1 |
|
||||
@ -261,6 +263,9 @@ describe('prompt buffer', function()
|
||||
{5:-- INSERT --} |
|
||||
]])
|
||||
|
||||
-- prompt_getinput works with multiline input
|
||||
eq('line 1\nline 2\nline 3', fn('prompt_getinput', buf))
|
||||
|
||||
feed('<cr>')
|
||||
-- submiting multiline text works
|
||||
screen:expect([[
|
||||
@ -274,6 +279,8 @@ describe('prompt buffer', function()
|
||||
{5:-- INSERT --} |
|
||||
]])
|
||||
|
||||
eq('', fn('prompt_getinput', buf))
|
||||
|
||||
-- % prompt is not repeated with formatoptions+=r
|
||||
source([[
|
||||
bwipeout!
|
||||
@ -293,6 +300,8 @@ describe('prompt buffer', function()
|
||||
|
||||
it('can put (p) multiline text', function()
|
||||
source_script()
|
||||
local buf = api.nvim_get_current_buf()
|
||||
|
||||
fn('setreg', 'a', 'line 1\nline 2\nline 3')
|
||||
feed('<esc>"ap')
|
||||
screen:expect([[
|
||||
@ -305,6 +314,10 @@ describe('prompt buffer', function()
|
||||
{1:~ }|*3
|
||||
|
|
||||
]])
|
||||
|
||||
-- prompt_getinput works with pasted input
|
||||
eq('line 1\nline 2\nline 3', fn('prompt_getinput', buf))
|
||||
|
||||
feed('i<cr>')
|
||||
screen:expect([[
|
||||
Result: "line 1 |
|
||||
@ -335,6 +348,8 @@ describe('prompt buffer', function()
|
||||
|
||||
it('can undo current prompt', function()
|
||||
source_script()
|
||||
local buf = api.nvim_get_current_buf()
|
||||
|
||||
-- text editiing alowed in current prompt
|
||||
feed('tests-initial<esc>')
|
||||
feed('bimiddle-<esc>')
|
||||
@ -368,6 +383,9 @@ describe('prompt buffer', function()
|
||||
1 change; {MATCH:.*} |
|
||||
]])
|
||||
|
||||
-- undo is reflected in prompt_getinput
|
||||
eq('tests-middle-initial', fn('prompt_getinput', buf))
|
||||
|
||||
feed('u')
|
||||
screen:expect([[
|
||||
cmd: tests-^initial |
|
||||
@ -406,6 +424,8 @@ describe('prompt buffer', function()
|
||||
|
||||
it('o/O can create new lines', function()
|
||||
source_script()
|
||||
local buf = api.nvim_get_current_buf()
|
||||
|
||||
feed('line 1<s-cr>line 2<s-cr>line 3')
|
||||
screen:expect([[
|
||||
cmd: line 1 |
|
||||
@ -419,7 +439,6 @@ describe('prompt buffer', function()
|
||||
]])
|
||||
|
||||
feed('<esc>koafter')
|
||||
|
||||
screen:expect([[
|
||||
cmd: line 1 |
|
||||
line 2 |
|
||||
@ -431,6 +450,9 @@ describe('prompt buffer', function()
|
||||
{5:-- INSERT --} |
|
||||
]])
|
||||
|
||||
-- newline created with o is reflected in prompt_getinput
|
||||
eq('line 1\nline 2\nafter\nline 3', fn('prompt_getinput', buf))
|
||||
|
||||
feed('<esc>kObefore')
|
||||
|
||||
screen:expect([[
|
||||
@ -444,6 +466,9 @@ describe('prompt buffer', function()
|
||||
{5:-- INSERT --} |
|
||||
]])
|
||||
|
||||
-- newline created with O is reflected in prompt_getinput
|
||||
eq('line 1\nbefore\nline 2\nafter\nline 3', fn('prompt_getinput', buf))
|
||||
|
||||
feed('<cr>')
|
||||
screen:expect([[
|
||||
line 2 |
|
||||
@ -552,4 +577,23 @@ describe('prompt buffer', function()
|
||||
source('set buftype=')
|
||||
eq("Invalid mark name: ':'", t.pcall_err(api.nvim_buf_get_mark, 0, ':'))
|
||||
end)
|
||||
|
||||
describe('prompt_getinput', function()
|
||||
it('returns current prompts text', function()
|
||||
command('new')
|
||||
local bufnr = fn('bufnr')
|
||||
api.nvim_set_option_value('buftype', 'prompt', { buf = 0 })
|
||||
eq('', fn('prompt_getinput', bufnr))
|
||||
feed('iasdf')
|
||||
eq('asdf', fn('prompt_getinput', bufnr))
|
||||
feed('<esc>dd')
|
||||
eq('', fn('prompt_getinput', bufnr))
|
||||
feed('iasdf2')
|
||||
eq('asdf2', fn('prompt_getinput', bufnr))
|
||||
|
||||
-- returns empty string when called from non prompt buffer
|
||||
api.nvim_set_option_value('buftype', '', { buf = 0 })
|
||||
eq('', fn('prompt_getinput', bufnr))
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
Reference in New Issue
Block a user