Merge pull request #14411 from seandewar/vim-8.2.1588

vim-patch:8.2.1588 - port `prompt_getprompt()`
This commit is contained in:
Jan Edmund Lazo
2021-04-21 21:23:04 -04:00
committed by GitHub
7 changed files with 261 additions and 37 deletions

View File

@@ -2309,6 +2309,7 @@ perleval({expr}) any evaluate |perl| expression
pow({x}, {y}) Float {x} to the power of {y} pow({x}, {y}) Float {x} to the power of {y}
prevnonblank({lnum}) Number line nr of non-blank line <= {lnum} prevnonblank({lnum}) Number line nr of non-blank line <= {lnum}
printf({fmt}, {expr1}...) String format text printf({fmt}, {expr1}...) String format text
prompt_getprompt({buf}) String get prompt text
prompt_setcallback({buf}, {expr}) none set prompt callback function prompt_setcallback({buf}, {expr}) none set prompt callback function
prompt_setinterrupt({buf}, {text}) none set prompt interrupt function prompt_setinterrupt({buf}, {text}) none set prompt interrupt function
prompt_setprompt({buf}, {text}) none set prompt text prompt_setprompt({buf}, {text}) none set prompt text
@@ -6746,6 +6747,13 @@ printf({fmt}, {expr1} ...) *printf()*
of "%" items. If there are not sufficient or too many of "%" items. If there are not sufficient or too many
arguments an error is given. Up to 18 arguments can be used. arguments an error is given. Up to 18 arguments can be used.
prompt_getprompt({buf}) *prompt_getprompt()*
Returns the effective prompt text for buffer {buf}. {buf} can
be a buffer name or number. See |prompt-buffer|.
If the buffer doesn't exist or isn't a prompt buffer, an empty
string is returned.
prompt_setcallback({buf}, {expr}) *prompt_setcallback()* prompt_setcallback({buf}, {expr}) *prompt_setcallback()*
Set prompt callback for buffer {buf} to {expr}. When {expr} Set prompt callback for buffer {buf} to {expr}. When {expr}
is an empty string the callback is removed. This has only is an empty string the callback is removed. This has only

View File

@@ -978,6 +978,7 @@ Tags: *tag-functions*
settagstack() modify the tag stack of a window settagstack() modify the tag stack of a window
Prompt Buffer: *promptbuffer-functions* Prompt Buffer: *promptbuffer-functions*
prompt_getprompt() get the effective prompt text for a buffer
prompt_setcallback() set prompt callback for a buffer prompt_setcallback() set prompt callback for a buffer
prompt_setinterrupt() set interrupt callback for a buffer prompt_setinterrupt() set interrupt callback for a buffer
prompt_setprompt() set the prompt text for a buffer prompt_setprompt() set the prompt text for a buffer

View File

@@ -1604,13 +1604,20 @@ void edit_putchar(int c, bool highlight)
} }
} }
// Return the effective prompt for the current buffer. /// Return the effective prompt for the specified buffer.
char_u *prompt_text(void) char_u *buf_prompt_text(const buf_T *const buf)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{ {
if (curbuf->b_prompt_text == NULL) { if (buf->b_prompt_text == NULL) {
return (char_u *)"% "; return (char_u *)"% ";
} }
return curbuf->b_prompt_text; return buf->b_prompt_text;
}
// Return the effective prompt for the current buffer.
char_u *prompt_text(void) FUNC_ATTR_WARN_UNUSED_RESULT
{
return buf_prompt_text(curbuf);
} }
// Prepare for prompt mode: Make sure the last line has the prompt text. // Prepare for prompt mode: Make sure the last line has the prompt text.

View File

@@ -251,6 +251,7 @@ return {
pow={args=2}, pow={args=2},
prevnonblank={args=1}, prevnonblank={args=1},
printf={args=varargs(1)}, printf={args=varargs(1)},
prompt_getprompt={args=1},
prompt_setcallback={args={2, 2}}, prompt_setcallback={args={2, 2}},
prompt_setinterrupt={args={2, 2}}, prompt_setinterrupt={args={2, 2}},
prompt_setprompt={args={2, 2}}, prompt_setprompt={args={2, 2}},

View File

@@ -602,12 +602,7 @@ static void f_bufname(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[0].v_type == VAR_UNKNOWN) { if (argvars[0].v_type == VAR_UNKNOWN) {
buf = curbuf; buf = curbuf;
} else { } else {
if (!tv_check_str_or_nr(&argvars[0])) { buf = tv_get_buf_from_arg(&argvars[0]);
return;
}
emsg_off++;
buf = tv_get_buf(&argvars[0], false);
emsg_off--;
} }
if (buf != NULL && buf->b_fname != NULL) { if (buf != NULL && buf->b_fname != NULL) {
rettv->vval.v_string = (char_u *)xstrdup((char *)buf->b_fname); rettv->vval.v_string = (char_u *)xstrdup((char *)buf->b_fname);
@@ -627,6 +622,9 @@ static void f_bufnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[0].v_type == VAR_UNKNOWN) { if (argvars[0].v_type == VAR_UNKNOWN) {
buf = curbuf; buf = curbuf;
} else { } else {
// Don't use tv_get_buf_from_arg(); we continue if the buffer wasn't found
// and the second argument isn't zero, but we want to return early if the
// first argument isn't a string or number so only one error is shown.
if (!tv_check_str_or_nr(&argvars[0])) { if (!tv_check_str_or_nr(&argvars[0])) {
return; return;
} }
@@ -653,18 +651,12 @@ static void f_bufnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void buf_win_common(typval_T *argvars, typval_T *rettv, bool get_nr) static void buf_win_common(typval_T *argvars, typval_T *rettv, bool get_nr)
{ {
if (!tv_check_str_or_nr(&argvars[0])) { const buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
if (buf == NULL) { // no need to search if invalid arg or buffer not found
rettv->vval.v_number = -1; rettv->vval.v_number = -1;
return; return;
} }
emsg_off++;
buf_T *buf = tv_get_buf(&argvars[0], true);
if (buf == NULL) { // no need to search if buffer was not found
rettv->vval.v_number = -1;
goto end;
}
int winnr = 0; int winnr = 0;
int winid; int winid;
bool found_buf = false; bool found_buf = false;
@@ -677,8 +669,6 @@ static void buf_win_common(typval_T *argvars, typval_T *rettv, bool get_nr)
} }
} }
rettv->vval.v_number = (found_buf ? (get_nr ? winnr : winid) : -1); rettv->vval.v_number = (found_buf ? (get_nr ? winnr : winid) : -1);
end:
emsg_off--;
} }
/// "bufwinid(nr)" function /// "bufwinid(nr)" function
@@ -731,6 +721,18 @@ buf_T *tv_get_buf(typval_T *tv, int curtab_only)
return buf; return buf;
} }
/// Like tv_get_buf() but give an error message if the type is wrong.
buf_T *tv_get_buf_from_arg(typval_T *const tv) FUNC_ATTR_NONNULL_ALL
{
if (!tv_check_str_or_nr(tv)) {
return NULL;
}
emsg_off++;
buf_T *const buf = tv_get_buf(tv, false);
emsg_off--;
return buf;
}
/// Get the buffer from "arg" and give an error and return NULL if it is not /// Get the buffer from "arg" and give an error and return NULL if it is not
/// valid. /// valid.
buf_T * get_buf_arg(typval_T *arg) buf_T * get_buf_arg(typval_T *arg)
@@ -2799,15 +2801,11 @@ static void f_getbufinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
} else if (argvars[0].v_type != VAR_UNKNOWN) { } else if (argvars[0].v_type != VAR_UNKNOWN) {
// Information about one buffer. Argument specifies the buffer // Information about one buffer. Argument specifies the buffer
if (tv_check_num(&argvars[0])) { // issue errmsg if type error argbuf = tv_get_buf_from_arg(&argvars[0]);
emsg_off++;
argbuf = tv_get_buf(&argvars[0], false);
emsg_off--;
if (argbuf == NULL) { if (argbuf == NULL) {
return; return;
} }
} }
}
// Return information about all the buffers or a specified buffer // Return information about all the buffers or a specified buffer
FOR_ALL_BUFFERS(buf) { FOR_ALL_BUFFERS(buf) {
@@ -2875,13 +2873,7 @@ static void get_buffer_lines(buf_T *buf,
*/ */
static void f_getbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr) static void f_getbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{ {
buf_T *buf = NULL; buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
if (tv_check_str_or_nr(&argvars[0])) {
emsg_off++;
buf = tv_get_buf(&argvars[0], false);
emsg_off--;
}
const linenr_T lnum = tv_get_lnum_buf(&argvars[1], buf); const linenr_T lnum = tv_get_lnum_buf(&argvars[1], buf);
const linenr_T end = (argvars[2].v_type == VAR_UNKNOWN const linenr_T end = (argvars[2].v_type == VAR_UNKNOWN
@@ -6499,6 +6491,26 @@ static void f_prompt_setinterrupt(typval_T *argvars,
buf->b_prompt_interrupt= interrupt_callback; buf->b_prompt_interrupt= interrupt_callback;
} }
/// "prompt_getprompt({buffer})" function
void f_prompt_getprompt(typval_T *argvars, typval_T *rettv, FunPtr 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 = vim_strsave(buf_prompt_text(buf));
}
// "prompt_setprompt({buffer}, {text})" function // "prompt_setprompt({buffer}, {text})" function
static void f_prompt_setprompt(typval_T *argvars, static void f_prompt_setprompt(typval_T *argvars,
typval_T *rettv, FunPtr fptr) typval_T *rettv, FunPtr fptr)

View File

@@ -47,7 +47,7 @@ func Test_buffers_lastused()
endfor endfor
call assert_equal(['bufb', 'bufa', 'bufc'], names) call assert_equal(['bufb', 'bufa', 'bufc'], names)
call assert_match('[0-2] seconds ago', bufs[1][1]) call assert_match('[0-2] seconds\= ago', bufs[1][1])
bwipeout bufa bwipeout bufa
bwipeout bufb bwipeout bufb

View File

@@ -0,0 +1,195 @@
" Tests for setting 'buftype' to "prompt"
source check.vim
" Nvim's channel implementation differs from Vim's
" CheckFeature channel
source shared.vim
source screendump.vim
func CanTestPromptBuffer()
" We need to use a terminal window to be able to feed keys without leaving
" Insert mode.
" Nvim's terminal implementation differs from Vim's
" CheckFeature terminal
" TODO: make the tests work on MS-Windows
CheckNotMSWindows
endfunc
func WriteScript(name)
call writefile([
\ 'func TextEntered(text)',
\ ' if a:text == "exit"',
\ ' " Reset &modified to allow the buffer to be closed.',
\ ' set nomodified',
\ ' stopinsert',
\ ' close',
\ ' else',
\ ' " Add the output above the current prompt.',
\ ' call append(line("$") - 1, "Command: \"" . a:text . "\"")',
\ ' " Reset &modified to allow the buffer to be closed.',
\ ' set nomodified',
\ ' call timer_start(20, {id -> TimerFunc(a:text)})',
\ ' endif',
\ 'endfunc',
\ '',
\ 'func TimerFunc(text)',
\ ' " Add the output above the current prompt.',
\ ' call append(line("$") - 1, "Result: \"" . a:text . "\"")',
\ ' " Reset &modified to allow the buffer to be closed.',
\ ' set nomodified',
\ 'endfunc',
\ '',
\ 'call setline(1, "other buffer")',
\ 'set nomodified',
\ 'new',
\ 'set buftype=prompt',
\ 'call prompt_setcallback(bufnr(""), function("TextEntered"))',
\ 'eval bufnr("")->prompt_setprompt("cmd: ")',
\ 'startinsert',
\ ], a:name)
endfunc
func Test_prompt_basic()
throw 'skipped: TODO'
call CanTestPromptBuffer()
let scriptName = 'XpromptscriptBasic'
call WriteScript(scriptName)
let buf = RunVimInTerminal('-S ' . scriptName, {})
call WaitForAssert({-> assert_equal('cmd:', term_getline(buf, 1))})
call term_sendkeys(buf, "hello\<CR>")
call WaitForAssert({-> assert_equal('cmd: hello', term_getline(buf, 1))})
call WaitForAssert({-> assert_equal('Command: "hello"', term_getline(buf, 2))})
call WaitForAssert({-> assert_equal('Result: "hello"', term_getline(buf, 3))})
call term_sendkeys(buf, "exit\<CR>")
call WaitForAssert({-> assert_equal('other buffer', term_getline(buf, 1))})
call StopVimInTerminal(buf)
call delete(scriptName)
endfunc
func Test_prompt_editing()
throw 'skipped: TODO'
call CanTestPromptBuffer()
let scriptName = 'XpromptscriptEditing'
call WriteScript(scriptName)
let buf = RunVimInTerminal('-S ' . scriptName, {})
call WaitForAssert({-> assert_equal('cmd:', term_getline(buf, 1))})
let bs = "\<BS>"
call term_sendkeys(buf, "hello" . bs . bs)
call WaitForAssert({-> assert_equal('cmd: hel', term_getline(buf, 1))})
let left = "\<Left>"
call term_sendkeys(buf, left . left . left . bs . '-')
call WaitForAssert({-> assert_equal('cmd: -hel', term_getline(buf, 1))})
let end = "\<End>"
call term_sendkeys(buf, end . "x")
call WaitForAssert({-> assert_equal('cmd: -helx', term_getline(buf, 1))})
call term_sendkeys(buf, "\<C-U>exit\<CR>")
call WaitForAssert({-> assert_equal('other buffer', term_getline(buf, 1))})
call StopVimInTerminal(buf)
call delete(scriptName)
endfunc
func Test_prompt_garbage_collect()
func MyPromptCallback(x, text)
" NOP
endfunc
func MyPromptInterrupt(x)
" NOP
endfunc
new
set buftype=prompt
" Nvim doesn't support method call syntax yet.
" eval bufnr('')->prompt_setcallback(function('MyPromptCallback', [{}]))
" eval bufnr('')->prompt_setinterrupt(function('MyPromptInterrupt', [{}]))
eval prompt_setcallback(bufnr(''), function('MyPromptCallback', [{}]))
eval prompt_setinterrupt(bufnr(''), function('MyPromptInterrupt', [{}]))
call test_garbagecollect_now()
" Must not crash
call feedkeys("\<CR>\<C-C>", 'xt')
call assert_true(v:true)
call assert_fails("call prompt_setcallback(bufnr(), [])", 'E921:')
call assert_equal(0, prompt_setcallback({}, ''))
call assert_fails("call prompt_setinterrupt(bufnr(), [])", 'E921:')
call assert_equal(0, prompt_setinterrupt({}, ''))
delfunc MyPromptCallback
bwipe!
endfunc
" Test for editing the prompt buffer
func Test_prompt_buffer_edit()
new
set buftype=prompt
normal! i
call assert_beeps('normal! dd')
call assert_beeps('normal! ~')
call assert_beeps('normal! o')
call assert_beeps('normal! O')
call assert_beeps('normal! p')
call assert_beeps('normal! P')
call assert_beeps('normal! u')
call assert_beeps('normal! ra')
call assert_beeps('normal! s')
call assert_beeps('normal! S')
call assert_beeps("normal! \<C-A>")
call assert_beeps("normal! \<C-X>")
" pressing CTRL-W in the prompt buffer should trigger the window commands
call assert_equal(1, winnr())
" In Nvim, CTRL-W commands aren't usable from insert mode in a prompt buffer
" exe "normal A\<C-W>\<C-W>"
" call assert_equal(2, winnr())
" wincmd w
close!
call assert_equal(0, prompt_setprompt([], ''))
endfunc
func Test_prompt_buffer_getbufinfo()
new
call assert_equal('', prompt_getprompt('%'))
call assert_equal('', prompt_getprompt(bufnr('%')))
let another_buffer = bufnr('%')
set buftype=prompt
call assert_equal('% ', prompt_getprompt('%'))
call prompt_setprompt( bufnr( '%' ), 'This is a test: ' )
call assert_equal('This is a test: ', prompt_getprompt('%'))
call prompt_setprompt( bufnr( '%' ), '' )
" Nvim doesn't support method call syntax yet.
" call assert_equal('', '%'->prompt_getprompt())
call assert_equal('', prompt_getprompt('%'))
call prompt_setprompt( bufnr( '%' ), 'Another: ' )
call assert_equal('Another: ', prompt_getprompt('%'))
let another = bufnr('%')
new
call assert_equal('', prompt_getprompt('%'))
call assert_equal('Another: ', prompt_getprompt(another))
" Doesn't exist
let buffers_before = len( getbufinfo() )
call assert_equal('', prompt_getprompt( bufnr('$') + 1))
call assert_equal(buffers_before, len( getbufinfo()))
" invalid type
call assert_fails('call prompt_getprompt({})', 'E728:')
%bwipe!
endfunc
" vim: shiftwidth=2 sts=2 expandtab