From 4813ad48cd12a03ca50c01ac1b20518bf4df57f2 Mon Sep 17 00:00:00 2001 From: erw7 Date: Mon, 20 May 2019 11:57:45 +0900 Subject: [PATCH] vim-patch:8.1.0027: difficult to make a plugin that feeds a line to a job Problem: Difficult to make a plugin that feeds a line to a job. Solution: Add the nitial code for the "prompt" buftype. https://github.com/vim/vim/commit/f273245f6433d5d43a5671306b520a3230c35787 --- runtime/doc/eval.txt | 42 +++++++++- runtime/doc/options.txt | 2 + src/nvim/buffer.c | 19 ++++- src/nvim/buffer_defs.h | 3 + src/nvim/diff.c | 4 + src/nvim/edit.c | 58 +++++++++++++ src/nvim/eval.c | 31 +++++++ src/nvim/eval.lua | 2 + src/nvim/eval/funcs.c | 45 ++++++++++ src/nvim/normal.c | 59 +++++++++++-- src/nvim/ops.c | 72 +++++++++------- src/nvim/option.c | 3 +- test/functional/legacy/prompt_buffer_spec.lua | 84 +++++++++++++++++++ 13 files changed, 378 insertions(+), 46 deletions(-) create mode 100644 test/functional/legacy/prompt_buffer_spec.lua diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index e0ce83f8d2..a9d9c83867 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2280,6 +2280,9 @@ pathshorten({expr}) String shorten directory names in a path pow({x}, {y}) Float {x} to the power of {y} prevnonblank({lnum}) Number line nr of non-blank line <= {lnum} printf({fmt}, {expr1}...) String format text +prompt_addtext({buf}, {expr}) none add text to a prompt buffer +prompt_setprompt({buf}, {text}) none set prompt text +prompt_setcallback({buf}, {expr}) none set prompt callback function pum_getpos() Dict position and size of pum if visible pumvisible() Number whether popup menu is visible pyeval({expr}) any evaluate |Python| expression @@ -2290,7 +2293,7 @@ range({expr} [, {max} [, {stride}]]) readdir({dir} [, {expr}]) List file names in {dir} selected by {expr} readfile({fname} [, {binary} [, {max}]]) List get list of lines from file {fname} -reg_executing() Number get the executing register name +reg_executing() String get the executing register name reg_recording() String get the recording register name reltime([{start} [, {end}]]) List get time value reltimefloat({time}) Float turn the time value into a Float @@ -4541,7 +4544,7 @@ getline({lnum} [, {end}]) from the current buffer. Example: > getline(1) < When {lnum} is a String that doesn't start with a - digit, line() is called to translate the String into a Number. + digit, |line()| is called to translate the String into a Number. To get the line under the cursor: > getline(".") < When {lnum} is smaller than 1 or bigger than the number of @@ -6541,6 +6544,40 @@ printf({fmt}, {expr1} ...) *printf()* of "%" items. If there are not sufficient or too many arguments an error is given. Up to 18 arguments can be used. +prompt_setprompt({buf}, {text}) *prompt_setprompt()* + Set prompt for buffer {buf} to {text}. You most likely want + {text} to end in a space. + The result is only visible if {buf} has 'buftype' set to + "prompt". Example: > + call prompt_setprompt(bufnr(''), 'command: ') + + +prompt_setcallback({buf}, {expr}) *prompt_setcallback()* + Set prompt callback for buffer {buf} to {expr}. This has only + effect if {buf} has 'buftype' set to "prompt". + The callback is invoked when pressing Enter. The current + buffer will always be the prompt buffer. A new line for a + prompt is added before invoking the callback, thus the prompt + for which the callback was invoked will be in the last but one + line. + If the callback wants to add text to the buffer, it must + insert it above the last line, since that is where the current + prompt is. This can also be done asynchronously. + The callback is invoked with one argument, which is the text + that was entered at the prompt. This can be an empty string + if the user only typed Enter. + Example: > + call prompt_setcallback(bufnr(''), function('s:TextEntered')) + func s:TextEntered(text) + if a:text == 'exit' || a:text == 'quit' + stopinsert + close + else + call append(line('$') - 1, 'Entered: "' . a:text . '"') + " Reset 'modified' to allow the buffer to be closed. + set nomodified + endif + endfunc pum_getpos() *pum_getpos()* If the popup menu (see |ins-completion-menu|) is not visible, @@ -6554,7 +6591,6 @@ pum_getpos() *pum_getpos()* scrollbar |TRUE| if visible The values are the same as in |v:event| during |CompleteChanged|. - pumvisible() *pumvisible()* Returns non-zero when the popup menu is visible, zero otherwise. See |ins-completion-menu|. diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 70af23ee29..7107a0135d 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1093,6 +1093,8 @@ A jump table for the options with a short description can be found at |Q_op|. nowrite buffer will not be written quickfix list of errors |:cwindow| or locations |:lwindow| terminal |terminal-emulator| buffer + prompt buffer where only the last line can be edited, meant + to be used by a plugin, see |prompt-buffer| This option is used together with 'bufhidden' and 'swapfile' to specify special kinds of buffers. See |special-buffers|. diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 19d0cac2d3..91a96d1195 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -763,6 +763,8 @@ static void free_buffer(buf_T *buf) unref_var_dict(buf->b_vars); aubuflocal_remove(buf); tv_dict_unref(buf->additional_data); + xfree(buf->b_prompt_text); + callback_free(&buf->b_prompt_callback); clear_fmark(&buf->b_last_cursor); clear_fmark(&buf->b_last_insert); clear_fmark(&buf->b_last_change); @@ -1876,6 +1878,9 @@ buf_T * buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum, int flags) } } + buf->b_prompt_callback.type = kCallbackNone; + buf->b_prompt_text = NULL; + return buf; } @@ -4824,6 +4829,12 @@ do_arg_all( xfree(opened); } +// Return TRUE if "buf" is a prompt buffer. +int bt_prompt(buf_T *buf) +{ + return buf != NULL && buf->b_p_bt[0] == 'p'; +} + /* * Open a window for a number of buffers. */ @@ -5218,14 +5229,18 @@ bool bt_nofile(const buf_T *const buf) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f') - || buf->b_p_bt[0] == 'a' || buf->terminal); + || buf->b_p_bt[0] == 'a' + || buf->terminal + || buf->b_p_bt[0] == 'p'); } // Return true if "buf" is a "nowrite", "nofile" or "terminal" buffer. bool bt_dontwrite(const buf_T *const buf) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - return buf != NULL && (buf->b_p_bt[0] == 'n' || buf->terminal); + return buf != NULL && (buf->b_p_bt[0] == 'n' + || buf->terminal + || buf->b_p_bt[0] == 'p'); } bool bt_dontwrite_msg(const buf_T *const buf) diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index a0379740b6..e3e036f91c 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -791,6 +791,9 @@ struct file_buffer { // are not used! Use the B_SPELL macro to // access b_spell without #ifdef. + char_u *b_prompt_text; // set by prompt_setprompt() + Callback b_prompt_callback; // set by prompt_setcallback() + synblock_T b_s; // Info related to syntax highlighting. w_s // normally points to this, but some windows // may use a different synblock_T. diff --git a/src/nvim/diff.c b/src/nvim/diff.c index c31adc01fd..04309444d9 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -2432,6 +2432,10 @@ void nv_diffgetput(bool put, size_t count) exarg_T ea; char buf[30]; + if (bt_prompt(curbuf)) { + vim_beep(BO_OPER); + return; + } if (count == 0) { ea.arg = (char_u *)""; } else { diff --git a/src/nvim/edit.c b/src/nvim/edit.c index e253905057..64510589fd 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -574,6 +574,12 @@ static int insert_check(VimState *state) foldCheckClose(); } + int cmdchar_todo = s->cmdchar; + if (bt_prompt(curbuf)) { + init_prompt(cmdchar_todo); + cmdchar_todo = NUL; + } + // If we inserted a character at the last position of the last line in the // window, scroll the window one line up. This avoids an extra redraw. This // is detected when the cursor column is smaller after inserting something. @@ -1143,6 +1149,14 @@ check_pum: cmdwin_result = CAR; return 0; } + if (bt_prompt(curbuf)) { + invoke_prompt_callback(); + if (curbuf != buf) { + // buffer changed, get out of Insert mode + return 0; + } + break; + } if (!ins_eol(s->c) && !p_im) { return 0; // out of memory } @@ -1569,6 +1583,50 @@ void edit_putchar(int c, int highlight) } } +// Return the effective prompt for the current buffer. +char_u *prompt_text(void) +{ + if (curbuf->b_prompt_text == NULL) { + return (char_u *)"% "; + } + return curbuf->b_prompt_text; +} + +// Prepare for prompt mode: Make sure the last line has the prompt text. +// Move the cursor to this line. +static void init_prompt(int cmdchar_todo) +{ + char_u *prompt = prompt_text(); + char_u *text; + + curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; + text = get_cursor_line_ptr(); + if (STRNCMP(text, prompt, STRLEN(prompt)) != 0) { + // prompt is missing, insert it or append a line with it + if (*text == NUL) { + ml_replace(curbuf->b_ml.ml_line_count, prompt, true); + } else { + ml_append(curbuf->b_ml.ml_line_count, prompt, 0, false); + } + curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; + coladvance((colnr_T)MAXCOL); + changed_bytes(curbuf->b_ml.ml_line_count, 0); + } + if (cmdchar_todo == 'A') { + coladvance((colnr_T)MAXCOL); + } + if (cmdchar_todo == 'I' || curwin->w_cursor.col <= (int)STRLEN(prompt)) { + curwin->w_cursor.col = STRLEN(prompt); + } +} + +// Return TRUE if the cursor is in the editable position of the prompt line. +int prompt_curpos_editable(void) +{ + return curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count + && curwin->w_cursor.col >= (int)STRLEN(prompt_text()); +} + /* * Undo the previous edit_putchar(). */ diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 0dceca671b..b330e7161d 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -13687,3 +13687,34 @@ void ex_checkhealth(exarg_T *eap) xfree(buf); } + +void invoke_prompt_callback(void) +{ + typval_T rettv; + typval_T argv[2]; + char_u *text; + char_u *prompt; + linenr_T lnum = 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, (char_u *)"", 0, false); + curwin->w_cursor.lnum = lnum + 1; + curwin->w_cursor.col = 0; + + if (curbuf->b_prompt_callback.type == kCallbackNone) { + return; + } + text = ml_get(lnum); + prompt = prompt_text(); + if (STRLEN(text) >= STRLEN(prompt)) { + text += STRLEN(prompt); + } + argv[0].v_type = VAR_STRING; + argv[0].vval.v_string = vim_strsave(text); + argv[1].v_type = VAR_UNKNOWN; + + callback_call(&curbuf->b_prompt_callback, 1, argv, &rettv); + tv_clear(&argv[0]); + tv_clear(&rettv); +} diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index efeac70816..fb72402f0d 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -243,6 +243,8 @@ return { pow={args=2}, prevnonblank={args=1}, printf={args=varargs(1)}, + prompt_setcallback={args={2, 2}}, + prompt_setprompt={args={2, 2}}, pum_getpos={}, pumvisible={}, py3eval={args=1}, diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 8232136783..a89d62fdfd 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -6076,6 +6076,51 @@ static void f_printf(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } +// "prompt_setcallback({buffer}, {callback})" function +static void f_prompt_setcallback(typval_T *argvars, + typval_T *rettv, FunPtr fptr) +{ + buf_T *buf; + Callback prompt_callback = { .type = kCallbackNone }; + + if (check_secure()) { + return; + } + buf = tv_get_buf(&argvars[0], false); + if (buf == NULL) { + return; + } + + if (argvars[1].v_type != VAR_STRING || *argvars[1].vval.v_string != NUL) { + if (!callback_from_typval(&prompt_callback, &argvars[1])) { + return; + } + } + + callback_free(&buf->b_prompt_callback); + buf->b_prompt_callback = prompt_callback; +} + +// "prompt_setprompt({buffer}, {text})" function +static void f_prompt_setprompt(typval_T *argvars, + typval_T *rettv, FunPtr fptr) +{ + buf_T *buf; + const char_u *text; + + if (check_secure()) { + return; + } + buf = tv_get_buf(&argvars[0], false); + if (buf == NULL) { + return; + } + + text = (const char_u *)tv_get_string(&argvars[1]); + xfree(buf->b_prompt_text); + buf->b_prompt_text = vim_strsave(text); +} + // "pum_getpos()" function static void f_pum_getpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) { diff --git a/src/nvim/normal.c b/src/nvim/normal.c index dac4c8f527..c69b10f99a 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -3642,7 +3642,9 @@ static void nv_help(cmdarg_T *cap) */ static void nv_addsub(cmdarg_T *cap) { - if (!VIsual_active && cap->oap->op_type == OP_NOP) { + if (bt_prompt(curbuf) && !prompt_curpos_editable()) { + clearopbeep(cap->oap); + } else if (!VIsual_active && cap->oap->op_type == OP_NOP) { prep_redo_cmd(cap); cap->oap->op_type = cap->cmdchar == Ctrl_A ? OP_NR_ADD : OP_NR_SUB; op_addsub(cap->oap, cap->count1, cap->arg); @@ -5239,6 +5241,13 @@ static void nv_down(cmdarg_T *cap) // In the cmdline window a executes the command. if (cmdwin_type != 0 && cap->cmdchar == CAR) { cmdwin_result = CAR; + } else if (bt_prompt(curbuf) && cap->cmdchar == CAR + && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) { + // In a prompt buffer a in the last line invokes the callback. + invoke_prompt_callback(); + if (restart_edit == 0) { + restart_edit = 'a'; + } } else { cap->oap->motion_type = kMTLineWise; if (cursor_down(cap->count1, cap->oap->op_type == OP_NOP) == false) { @@ -5831,6 +5840,10 @@ static void nv_undo(cmdarg_T *cap) static void nv_kundo(cmdarg_T *cap) { if (!checkclearopq(cap->oap)) { + if (bt_prompt(curbuf)) { + clearopbeep(cap->oap); + return; + } u_undo((int)cap->count1); curwin->w_set_curswant = true; } @@ -5844,8 +5857,13 @@ static void nv_replace(cmdarg_T *cap) char_u *ptr; int had_ctrl_v; - if (checkclearop(cap->oap)) + if (checkclearop(cap->oap)) { return; + } + if (bt_prompt(curbuf) && !prompt_curpos_editable()) { + clearopbeep(cap->oap); + return; + } /* get another character */ if (cap->nchar == Ctrl_V) { @@ -6182,7 +6200,11 @@ static void v_visop(cmdarg_T *cap) */ static void nv_subst(cmdarg_T *cap) { - if (VIsual_active) { /* "vs" and "vS" are the same as "vc" */ + if (bt_prompt(curbuf) && !prompt_curpos_editable()) { + clearopbeep(cap->oap); + return; + } + if (VIsual_active) { // "vs" and "vS" are the same as "vc" if (cap->cmdchar == 'S') { VIsual_mode_orig = VIsual_mode; VIsual_mode = 'V'; @@ -7120,10 +7142,15 @@ static void nv_tilde(cmdarg_T *cap) { if (!p_to && !VIsual_active - && cap->oap->op_type != OP_TILDE) + && cap->oap->op_type != OP_TILDE) { + if (bt_prompt(curbuf) && !prompt_curpos_editable()) { + clearopbeep(cap->oap); + return; + } n_swapchar(cap); - else + } else { nv_operator(cap); + } } /* @@ -7136,6 +7163,12 @@ static void nv_operator(cmdarg_T *cap) op_type = get_op_type(cap->cmdchar, cap->nchar); + if (bt_prompt(curbuf) && op_is_change(op_type) + && !prompt_curpos_editable()) { + clearopbeep(cap->oap); + return; + } + if (op_type == cap->oap->op_type) /* double operator works on lines */ nv_lineop(cap); else if (!checkclearop(cap->oap)) { @@ -7796,8 +7829,11 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent) clearop(cap->oap); assert(cap->opcount >= 0); nv_diffgetput(true, (size_t)cap->opcount); - } else + } else { clearopbeep(cap->oap); + } + } else if (bt_prompt(curbuf) && !prompt_curpos_editable()) { + clearopbeep(cap->oap); } else { if (fix_indent) { dir = (cap->cmdchar == ']' && cap->nchar == 'p') @@ -7809,8 +7845,9 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent) ? BACKWARD : FORWARD; } prep_redo_cmd(cap); - if (cap->cmdchar == 'g') + if (cap->cmdchar == 'g') { flags |= PUT_CURSEND; + } if (VIsual_active) { /* Putting in Visual mode: The put text replaces the selected @@ -7916,10 +7953,14 @@ static void nv_open(cmdarg_T *cap) clearop(cap->oap); assert(cap->opcount >= 0); nv_diffgetput(false, (size_t)cap->opcount); - } else if (VIsual_active) /* switch start and end of visual */ + } else if (VIsual_active) { + // switch start and end of visual/ v_swap_corners(cap->cmdchar); - else + } else if (bt_prompt(curbuf)) { + clearopbeep(cap->oap); + } else { n_opencmd(cap); + } } // Calculate start/end virtual columns for operating in block mode. diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 6d327c0814..735a33ca97 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -89,6 +89,10 @@ struct block_def { # include "ops.c.generated.h" #endif +// Flags for third item in "opchars". +#define OPF_LINES 1 // operator always works on lines +#define OPF_CHANGE 2 // operator changes text + /* * The names of operators. * IMPORTANT: Index must correspond with defines in vim.h!!! @@ -96,36 +100,36 @@ struct block_def { */ static char opchars[][3] = { - { NUL, NUL, false }, // OP_NOP - { 'd', NUL, false }, // OP_DELETE - { 'y', NUL, false }, // OP_YANK - { 'c', NUL, false }, // OP_CHANGE - { '<', NUL, true }, // OP_LSHIFT - { '>', NUL, true }, // OP_RSHIFT - { '!', NUL, true }, // OP_FILTER - { 'g', '~', false }, // OP_TILDE - { '=', NUL, true }, // OP_INDENT - { 'g', 'q', true }, // OP_FORMAT - { ':', NUL, true }, // OP_COLON - { 'g', 'U', false }, // OP_UPPER - { 'g', 'u', false }, // OP_LOWER - { 'J', NUL, true }, // DO_JOIN - { 'g', 'J', true }, // DO_JOIN_NS - { 'g', '?', false }, // OP_ROT13 - { 'r', NUL, false }, // OP_REPLACE - { 'I', NUL, false }, // OP_INSERT - { 'A', NUL, false }, // OP_APPEND - { 'z', 'f', true }, // OP_FOLD - { 'z', 'o', true }, // OP_FOLDOPEN - { 'z', 'O', true }, // OP_FOLDOPENREC - { 'z', 'c', true }, // OP_FOLDCLOSE - { 'z', 'C', true }, // OP_FOLDCLOSEREC - { 'z', 'd', true }, // OP_FOLDDEL - { 'z', 'D', true }, // OP_FOLDDELREC - { 'g', 'w', true }, // OP_FORMAT2 - { 'g', '@', false }, // OP_FUNCTION - { Ctrl_A, NUL, false }, // OP_NR_ADD - { Ctrl_X, NUL, false }, // OP_NR_SUB + { NUL, NUL, 0 }, // OP_NOP + { 'd', NUL, OPF_CHANGE }, // OP_DELETE + { 'y', NUL, 0 }, // OP_YANK + { 'c', NUL, OPF_CHANGE }, // OP_CHANGE + { '<', NUL, OPF_LINES | OPF_CHANGE }, // OP_LSHIFT + { '>', NUL, OPF_LINES | OPF_CHANGE }, // OP_RSHIFT + { '!', NUL, OPF_LINES | OPF_CHANGE }, // OP_FILTER + { 'g', '~', OPF_CHANGE }, // OP_TILDE + { '=', NUL, OPF_LINES | OPF_CHANGE }, // OP_INDENT + { 'g', 'q', OPF_LINES | OPF_CHANGE }, // OP_FORMAT + { ':', NUL, OPF_LINES }, // OP_COLON + { 'g', 'U', OPF_CHANGE }, // OP_UPPER + { 'g', 'u', OPF_CHANGE }, // OP_LOWER + { 'J', NUL, OPF_LINES | OPF_CHANGE }, // DO_JOIN + { 'g', 'J', OPF_LINES | OPF_CHANGE }, // DO_JOIN_NS + { 'g', '?', OPF_CHANGE }, // OP_ROT13 + { 'r', NUL, OPF_CHANGE }, // OP_REPLACE + { 'I', NUL, OPF_CHANGE }, // OP_INSERT + { 'A', NUL, OPF_CHANGE }, // OP_APPEND + { 'z', 'f', OPF_LINES }, // OP_FOLD + { 'z', 'o', OPF_LINES }, // OP_FOLDOPEN + { 'z', 'O', OPF_LINES }, // OP_FOLDOPENREC + { 'z', 'c', OPF_LINES }, // OP_FOLDCLOSE + { 'z', 'C', OPF_LINES }, // OP_FOLDCLOSEREC + { 'z', 'd', OPF_LINES }, // OP_FOLDDEL + { 'z', 'D', OPF_LINES }, // OP_FOLDDELREC + { 'g', 'w', OPF_LINES | OPF_CHANGE }, // OP_FORMAT2 + { 'g', '@', OPF_CHANGE }, // OP_FUNCTION + { Ctrl_A, NUL, OPF_CHANGE }, // OP_NR_ADD + { Ctrl_X, NUL, OPF_CHANGE }, // OP_NR_SUB }; /* @@ -169,7 +173,13 @@ int get_op_type(int char1, int char2) */ int op_on_lines(int op) { - return opchars[op][2]; + return opchars[op][2] & OPF_LINES; +} + +// Return TRUE if operator "op" changes text. +int op_is_change(int op) +{ + return opchars[op][2] & OPF_CHANGE; } /* diff --git a/src/nvim/option.c b/src/nvim/option.c index 15ff8414ce..fa994e24c3 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -299,7 +299,8 @@ static char *(p_scbopt_values[]) = { "ver", "hor", "jump", NULL }; static char *(p_debug_values[]) = { "msg", "throw", "beep", NULL }; static char *(p_ead_values[]) = { "both", "ver", "hor", NULL }; static char *(p_buftype_values[]) = { "nofile", "nowrite", "quickfix", - "help", "acwrite", "terminal", NULL }; + "help", "acwrite", "terminal", + "prompt", NULL }; static char *(p_bufhidden_values[]) = { "hide", "unload", "delete", "wipe", NULL }; diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua new file mode 100644 index 0000000000..749e65a985 --- /dev/null +++ b/test/functional/legacy/prompt_buffer_spec.lua @@ -0,0 +1,84 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') +local feed= helpers.feed +local source = helpers.source +local clear = helpers.clear +local feed_command = helpers.feed_command + +describe('prompt buffer', function() + local screen + + before_each(function() + clear() + screen = Screen.new(25, 10) + screen:attach() + source([[ + func TextEntered(text) + if a:text == "exit" + stopinsert + close + else + call append(line("$") - 1, 'Command: "' . a:text . '"') + set nomodfied + call timer_start(20, {id -> TimerFunc(a:text)}) + endif + endfunc + + func TimerFunc(text) + call append(line("$") - 1, 'Result: "' . a:text .'"') + endfunc + ]]) + end) + + after_each(function() + screen:detach() + end) + + it('works', function() + feed_command("set noshowmode | set laststatus=0") + feed_command("call setline(1, 'other buffer')") + feed_command("new") + feed_command("set buftype=prompt") + feed_command("call prompt_setcallback(bufnr(''), function('TextEntered'))") + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + [Scratch] | + other buffer | + ~ | + ~ | + ~ | + | + ]]) + feed_command("startinsert") + feed("hello\n") + screen:expect([[ + % hello | + Command: "hello" | + Result: "hello" | + % ^ | + [Scratch] | + other buffer | + ~ | + ~ | + ~ | + | + ]]) + feed("exit\n") + screen:expect([[ + ^other buffer | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + end) + +end)