Problem: Difficult to make a plugin that feeds a line to a job.
Solution: Add the nitial code for the "prompt" buftype.
9. Starting a job without a channel |job-start-nochannel|
10. Job options |job-options|
11. Controlling a job |job-control|
+12. Using a prompt buffer |prompt-buffer|
{Vi does not have any of these features}
{only when compiled with the |+channel| feature for channel stuff}
For more options see |job_stop()|.
+==============================================================================
+12. Using a prompt buffer *prompt-buffer*
+
+If you want to type input for the job in a Vim window you have a few options:
+- Use a normal buffer and handle all possible commands yourself.
+ This will be complicated, since there are so many possible commands.
+- Use a terminal window. This works well if what you type goes directly to
+ the job and the job output is directly displayed in the window.
+ See |terminal-window|.
+- Use a prompt window. This works well when entering a line for the job in Vim
+ while displaying (possibly filtered) output from the job.
+
+A prompt buffer is created by setting 'buftype' to "prompt". You would
+normally only do that in a newly created buffer.
+
+The user can edit and enter one line of text at the very last line of the
+buffer. When pressing Enter in the prompt line the callback set with
+|prompt_setcallback()| is invoked. It would normally send the line to a job.
+Another callback would receive the output from the job and display it in the
+buffer, below the prompt (and above the next prompt).
+
+Only the text in the last line, after the prompt, is editable. The rest of the
+buffer is not modifiable with Normal mode commands. It can be modified by
+calling functions, such as |append()|. Using other commands may mess up the
+buffer.
+
+After setting 'buftype' to "prompt" Vim does not automatically start Insert
+mode, use `:startinsert` if you want to enter Insert mode, so that the user
+can start typing a line.
+
+The text of the prompt can be set with the |prompt_setprompt()| function.
+
+The user can go to Normal mode and navigate through the buffer. This can be
+useful see older output or copy text.
+
+Any command that starts Insert mode, such as "a", "i", "A" and "I", will move
+the cursor to the last line, after the prompt.
+
vim:tw=78:ts=8:ft=help:norl:
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
pumvisible() Number whether popup menu is visible
pyeval({expr}) any evaluate |Python| expression
py3eval({expr}) any evaluate |python3| expression
List items from {expr} to {max}
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
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
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
+
+
pumvisible() *pumvisible()*
Returns non-zero when the popup menu is visible, zero
otherwise. See |ins-completion-menu|.
manually)
terminal buffer for a |terminal| (you are not supposed to set
this manually)
+ prompt buffer where only the last line can be edited, meant
+ to be used by a plugin, see |prompt-buffer|
+ {only when compiled with the |+channel| feature}
This option is used together with 'bufhidden' and 'swapfile' to
specify special kinds of buffers. See |special-buffers|.
'imactivatefunc' 'imaf' string (default "")
global
{not in Vi}
- {only available when compiled with |+mbyte|}
+ {only available when compiled with the |+multi_byte|
+ feature}
This option specifies a function that will be called to
activate or deactivate the Input Method.
It is not used in the GUI.
'imcmdline' 'imc' boolean (default off)
global
{not in Vi}
- {only available when compiled with |+mbyte|}
+ {only available when compiled with the |+multi_byte|
+ feature}
When set the Input Method is always on when starting to edit a command
line, unless entering a search pattern (see 'imsearch' for that).
Setting this option is useful when your input method allows entering
'imdisable' 'imd' boolean (default off, on for some systems (SGI))
global
{not in Vi}
- {only available when compiled with |+mbyte|}
+ {only available when compiled with the |+multi_byte|
+ feature}
When set the Input Method is never used. This is useful to disable
the IM when it doesn't work properly.
Currently this option is on by default for SGI/IRIX machines. This
'imstatusfunc' 'imsf' string (default "")
global
{not in Vi}
- {only available when compiled with |+mbyte|}
+ {only available when compiled with the |+multi_byte|
+ feature}
This option specifies a function that is called to obtain the status
of Input Method. It must return a positive number when IME is active.
It is not used in the GUI.
*known-bugs*
-------------------- Known bugs and current work -----------------------
+Prompt buffer:
+- Add a command line history.
+- delay next prompt until plugin gives OK?
+
Terminal emulator window:
- Win32: Termdebug doesn't work, because gdb does not support mi2 on a tty.
This plugin: https://github.com/cpiger/NeoDebug runs gdb as a job,
On Win32 when not in the console and t_Co >= 256, allow using 'tgc'.
(Nobuhiro Takasaki, #2833) Also check t_Co.
-balloon_show() does not work properly in the terminal. (Ben Jackson, 2017 Dec
-20, #2481)
-Also see #2352, want better control over balloon, perhaps set the position.
+Patch to fix arguments of :edit. (Dominique Pelle, 2018 May 28 #2966)
+
+Ptch to update html syntax. (Jorge Maldonado Ventura, #2974)
+
+Patch to fix that restoring window doesn't work when 'winheight' is large.
+(Darrell Nash, 2018 May 30, #2971) Doesn't work? Issue #2970
+
+Patch to add completion to :unlet for environment vars. (Jason Franklin, 2018
+May 30) Last update.
Errors found with random data:
heap-buffer-overflow in alist_add (#2472)
More warnings from static analysis:
https://lgtm.com/projects/g/vim/vim/alerts/?mode=list
+Patch to make "is" and "as" work bettter. (Jason Franklin, 2018 May 19)
+
+Patch to add tests for user and language completion. (Dominique Pelle, 2018
+Jun 2, #2978)
+
+Using ":file" in quickfix window during an autocommand doesn't work.
+(Jason Franklin, 2018 May 23) Allow for using it when there is no argument.
+
+Pull request #2967: Allow white space in sign text. (Ben Jackson)
+
+Patch for xterm and vt320 builtin termcap. (Kouichi Iwamoto, 2018 May 31,
+#2973)
+
+Patch to add more testing for :cd command. (Dominique Pelle, 2018 May 30,
+#2972)
+
Script generated by :mksession does not work well if there are windows with
modified buffers
change "silent only" into "silent only!"
skip "badd fname" if "fname" is already in the buffer list
remove remark about unloading buffers from documentation
+Patch to make :help work for tags with a ?. (Hirohito Higashi, 2018 May 28)
+
Compiler warnings (geeknik, 2017 Oct 26):
- signed integer overflow in do_sub() (#2249)
- signed integer overflow in get_address() (#2248)
- signed integer overflow in getdecchrs() (#2254)
- undefined left shift in get_string_tv() (#2250)
+Patch for more quickfix refactoring. (Yegappan Lakshmanan, #2950)
+
Tests failing for "make testgui" with GTK:
- Test_setbufvar_options()
- Test_exit_callback_interval()
+Make balloon_show() work outside of 'balloonexpr'? Users expect it to work:
+#2948. (related to #1512?)
+On Win32 it stops showing, because showState is already ShS_SHOWING.
+balloon_show() does not work properly in the terminal. (Ben Jackson, 2017 Dec
+20, #2481)
+Also see #2352, want better control over balloon, perhaps set the position.
+
Try out background make plugin:
https://github.com/AndrewVos/vim-make-background
or asyncmake:
Cursor in wrong position when line wraps. (#2540)
+Patch for Lua support. (Kazunobu Kuriyama, 2018 May 26)
+
Add an option similar to 'lazyredraw' to skip redrawing while executing a
script or function.
Alternative manpager.vim. (Enno, 2018 Jan 5, #2529)
+Patch to use NGETTEXT() in many more places. (Sergey Alyoshin, 2018 May 25)
+Updated ptach May 27.
+
Does setting 'cursorline' cause syntax highlighting to slow down? Perhaps is
mess up the cache? (Mike Lee Williams, 2018 Jan 27, #2539)
Also: 'foldtext' is evaluated too often. (Daniel Hahler, #2773)
test_popup \
test_preview \
test_profile \
+ test_prompt_buffer \
test_put \
test_python2 \
test_python3 \
#ifdef FEAT_TERMINAL
free_terminal(buf);
#endif
+#ifdef FEAT_JOB_CHANNEL
+ vim_free(buf->b_prompt_text);
+ free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
+#endif
buf_hashtab_remove(buf);
return buf != NULL && buf->b_help;
}
+/*
+ * Return TRUE if "buf" is a prompt buffer.
+ */
+ int
+bt_prompt(buf_T *buf)
+{
+ return buf != NULL && buf->b_p_bt[0] == 'p';
+}
+
/*
* Return TRUE if "buf" is a "nofile", "acwrite" or "terminal" buffer.
* This means the buffer name is not a file name.
{
return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f')
|| buf->b_p_bt[0] == 'a'
- || buf->b_p_bt[0] == 't');
+ || buf->b_p_bt[0] == 't'
+ || buf->b_p_bt[0] == 'p');
}
/*
int
bt_dontwrite(buf_T *buf)
{
- return buf != NULL && (buf->b_p_bt[0] == 'n' || buf->b_p_bt[0] == 't');
+ return buf != NULL && (buf->b_p_bt[0] == 'n'
+ || buf->b_p_bt[0] == 't'
+ || buf->b_p_bt[0] == 'p');
}
int
return 1;
}
+ void
+invoke_prompt_callback(void)
+{
+ typval_T rettv;
+ int dummy;
+ 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 == NULL)
+ 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;
+
+ call_func(curbuf->b_prompt_callback,
+ (int)STRLEN(curbuf->b_prompt_callback),
+ &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
+ curbuf->b_prompt_partial, NULL);
+ clear_tv(&argv[0]);
+ clear_tv(&rettv);
+}
+
#endif /* FEAT_JOB_CHANNEL */
exarg_T ea;
char_u buf[30];
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf))
+ {
+ vim_beep(BO_OPER);
+ return;
+ }
+#endif
if (count == 0)
ea.arg = (char_u *)"";
else
static void ins_redraw(int ready);
static void ins_ctrl_v(void);
+#ifdef FEAT_JOB_CHANNEL
+static void init_prompt(int cmdchar_todo);
+#endif
static void undisplay_dollar(void);
static void insert_special(int, int, int);
static void internal_format(int textwidth, int second_indent, int flags, int format_only, int c);
int inserted_space = FALSE; /* just inserted a space */
int replaceState = REPLACE;
int nomove = FALSE; /* don't move cursor on return */
+#ifdef FEAT_JOB_CHANNEL
+ int cmdchar_todo = cmdchar;
+#endif
/* Remember whether editing was restarted after CTRL-O. */
did_restart_edit = restart_edit;
foldCheckClose();
#endif
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf))
+ {
+ init_prompt(cmdchar_todo);
+ cmdchar_todo = NUL;
+ }
+#endif
+
/*
* 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
cmdwin_result = CAR;
goto doESCkey;
}
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf))
+ {
+ buf_T *buf = curbuf;
+
+ invoke_prompt_callback();
+ if (curbuf != buf)
+ // buffer changed, get out of Insert mode
+ goto doESCkey;
+ break;
+ }
#endif
if (ins_eol(c) == FAIL && !p_im)
goto doESCkey; /* out of memory */
}
}
+#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
+/*
+ * 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 = ml_get_curline();
+ 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()
+{
+ return curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count
+ && curwin->w_cursor.col >= (int)STRLEN(prompt_text());
+}
+#endif
+
/*
* Undo the previous edit_putchar().
*/
#endif
static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
static void f_printf(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_JOB_CHANNEL
+static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
+static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
+#endif
static void f_pumvisible(typval_T *argvars, typval_T *rettv);
#ifdef FEAT_PYTHON3
static void f_py3eval(typval_T *argvars, typval_T *rettv);
#endif
{"prevnonblank", 1, 1, f_prevnonblank},
{"printf", 1, 19, f_printf},
+#ifdef FEAT_JOB_CHANNEL
+ {"prompt_setcallback", 2, 2, f_prompt_setcallback},
+ {"prompt_setprompt", 2, 2, f_prompt_setprompt},
+#endif
{"pumvisible", 0, 0, f_pumvisible},
#ifdef FEAT_PYTHON3
{"py3eval", 1, 1, f_py3eval},
appended_lines_mark(lnum, added);
if (curwin->w_cursor.lnum > lnum)
curwin->w_cursor.lnum += added;
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf) && (State & INSERT))
+ // show the line with the prompt
+ update_topline();
+#endif
}
else
rettv->vval.v_number = 1; /* Failed */
did_emsg |= saved_did_emsg;
}
+#ifdef FEAT_JOB_CHANNEL
+/*
+ * "prompt_setcallback({buffer}, {callback})" function
+ */
+ static void
+f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ buf_T *buf;
+ char_u *callback;
+ partial_T *partial;
+
+ if (check_secure())
+ return;
+ buf = get_buf_tv(&argvars[0], FALSE);
+ if (buf == NULL)
+ return;
+
+ callback = get_callback(&argvars[1], &partial);
+ if (callback == NULL)
+ return;
+
+ free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
+ if (partial == NULL)
+ buf->b_prompt_callback = vim_strsave(callback);
+ else
+ /* pointer into the partial */
+ buf->b_prompt_callback = callback;
+ buf->b_prompt_partial = partial;
+}
+
+/*
+ * "prompt_setprompt({buffer}, {text})" function
+ */
+ static void
+f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ buf_T *buf;
+ char_u *text;
+
+ if (check_secure())
+ return;
+ buf = get_buf_tv(&argvars[0], FALSE);
+ if (buf == NULL)
+ return;
+
+ text = get_tv_string(&argvars[1]);
+ vim_free(buf->b_prompt_text);
+ buf->b_prompt_text = vim_strsave(text);
+}
+#endif
+
/*
* "pumvisible()" function
*/
static void
nv_addsub(cmdarg_T *cap)
{
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf) && !prompt_curpos_editable())
+ clearopbeep(cap->oap);
+ else
+#endif
if (!VIsual_active && cap->oap->op_type == OP_NOP)
{
prep_redo_cmd(cap);
if (cmdwin_type != 0 && cap->cmdchar == CAR)
cmdwin_result = CAR;
else
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ /* In a prompt buffer a <CR> in the last line invokes the callback. */
+ if (bt_prompt(curbuf) && cap->cmdchar == CAR
+ && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
+ {
+ invoke_prompt_callback();
+ if (restart_edit == 0)
+ restart_edit = 'a';
+ }
+ else
#endif
{
cap->oap->motion_type = MLINE;
{
if (!checkclearopq(cap->oap))
{
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf))
+ {
+ clearopbeep(cap->oap);
+ return;
+ }
+#endif
u_undo((int)cap->count1);
curwin->w_set_curswant = TRUE;
}
if (checkclearop(cap->oap))
return;
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf) && !prompt_curpos_editable())
+ {
+ clearopbeep(cap->oap);
+ return;
+ }
+#endif
/* get another character */
if (cap->nchar == Ctrl_V)
/* When showing output of term_dumpdiff() swap the top and botom. */
if (term_swap_diff() == OK)
return;
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf) && !prompt_curpos_editable())
+ {
+ clearopbeep(cap->oap);
+ return;
+ }
#endif
if (VIsual_active) /* "vs" and "vS" are the same as "vc" */
{
nv_tilde(cmdarg_T *cap)
{
if (!p_to && !VIsual_active && cap->oap->op_type != OP_TILDE)
+ {
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf) && !prompt_curpos_editable())
+ {
+ clearopbeep(cap->oap);
+ return;
+ }
+#endif
n_swapchar(cap);
+ }
else
nv_operator(cap);
}
int op_type;
op_type = get_op_type(cap->cmdchar, cap->nchar);
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf) && op_is_change(op_type) && !prompt_curpos_editable())
+ {
+ clearopbeep(cap->oap);
+ return;
+ }
+#endif
if (op_type == cap->oap->op_type) /* double operator works on lines */
nv_lineop(cap);
#endif
clearopbeep(cap->oap);
}
+#ifdef FEAT_JOB_CHANNEL
+ else if (bt_prompt(curbuf) && !prompt_curpos_editable())
+ {
+ clearopbeep(cap->oap);
+ }
+#endif
else
{
dir = (cap->cmdchar == 'P'
#endif
if (VIsual_active) /* switch start and end of visual */
v_swap_corners(cap->cmdchar);
+#ifdef FEAT_JOB_CHANNEL
+ else if (bt_prompt(curbuf))
+ {
+ clearopbeep(cap->oap);
+ }
+#endif
else
n_opencmd(cap);
}
static int fmt_check_par(linenr_T);
#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!!!
- * The third field indicates whether the operator always works on lines.
+ * The third field holds OPF_ flags.
*/
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
};
/*
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;
}
/*
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", "terminal", "acwrite", NULL};
+static char *(p_buftype_values[]) = {"nofile", "nowrite", "quickfix", "help", "terminal", "acwrite", "prompt", NULL};
static char *(p_bufhidden_values[]) = {"hide", "unload", "delete", "wipe", NULL};
static char *(p_bs_values[]) = {"indent", "eol", "start", NULL};
#ifdef FEAT_FOLDING
int bt_quickfix(buf_T *buf);
int bt_terminal(buf_T *buf);
int bt_help(buf_T *buf);
+int bt_prompt(buf_T *buf);
int bt_nofile(buf_T *buf);
int bt_dontwrite(buf_T *buf);
int bt_dontwrite_msg(buf_T *buf);
void job_info(job_T *job, dict_T *dict);
void job_info_all(list_T *l);
int job_stop(job_T *job, typval_T *argvars, char *type);
+void invoke_prompt_callback(void);
/* vim: set ft=c : */
/* edit.c */
int edit(int cmdchar, int startln, long count);
void edit_putchar(int c, int highlight);
+char_u *prompt_text(void);
+int prompt_curpos_editable(void);
void edit_unputchar(void);
void display_dollar(colnr_T col);
void change_indent(int type, int amount, int round, int replaced, int call_changed_bytes);
/* ops.c */
int get_op_type(int char1, int char2);
int op_on_lines(int op);
+int op_is_change(int op);
int get_op_char(int optype);
int get_extra_op_char(int optype);
void op_shift(oparg_T *oap, int curs_top, int amount);
int b_shortname; /* this file has an 8.3 file name */
+#ifdef FEAT_JOB_CHANNEL
+ char_u *b_prompt_text; // set by prompt_setprompt()
+ char_u *b_prompt_callback; // set by prompt_setcallback()
+ partial_T *b_prompt_partial; // set by prompt_setcallback()
+#endif
#ifdef FEAT_MZSCHEME
void *b_mzscheme_ref; /* The MzScheme reference to this buffer */
#endif
test_perl.res \
test_plus_arg_edit.res \
test_preview.res \
+ test_prompt_buffer.res \
test_profile.res \
test_python2.res \
test_python3.res \
finish
endif
-" Need to be able to run terminal Vim with 256 colors. On MS-Windows the
-" console only has 16 colors and the GUI can't run in a terminal.
-if !has('terminal') || has('win32')
- func CanRunVimInTerminal()
- return 0
- endfunc
- finish
-endif
-
+" For most tests we need to be able to run terminal Vim with 256 colors. On
+" MS-Windows the console only has 16 colors and the GUI can't run in a
+" terminal.
func CanRunVimInTerminal()
- return 1
+ return has('terminal') && !has('win32')
endfunc
+" Skip the rest if there is no terminal feature at all.
+if !has('terminal')
+ finish
+endif
+
source shared.vim
" Run Vim with "arguments" in a new terminal window.
let cols = get(a:options, 'cols', 75)
let cmd = GetVimCommandClean()
+
" Add -v to have gvim run in the terminal (if possible)
let cmd .= ' -v ' . a:arguments
let buf = term_start(cmd, {'curwin': 1, 'term_rows': rows, 'term_cols': cols})
let cols = term_getsize(buf)[1]
endif
- " Wait for "All" or "Top" of the ruler in the status line to be shown. This
- " can be quite slow (e.g. when using valgrind).
+ " Wait for "All" or "Top" of the ruler to be shown in the last line or in
+ " the status line of the last window. This can be quite slow (e.g. when
+ " using valgrind).
" If it fails then show the terminal contents for debugging.
try
- call WaitFor({-> len(term_getline(buf, rows)) >= cols - 1})
+ call WaitFor({-> len(term_getline(buf, rows)) >= cols - 1 || len(term_getline(buf, rows - 1)) >= cols - 1})
catch /timed out after/
let lines = map(range(1, rows), {key, val -> term_getline(buf, val)})
call assert_report('RunVimInTerminal() failed, screen contents: ' . join(lines, "<NL>"))
" Stop a Vim running in terminal buffer "buf".
func StopVimInTerminal(buf)
call assert_equal("running", term_getstatus(a:buf))
- call term_sendkeys(a:buf, "\<Esc>\<Esc>:qa!\<cr>")
+ call term_sendkeys(a:buf, "\<Esc>:qa!\<cr>")
call WaitForAssert({-> assert_equal("finished", term_getstatus(a:buf))})
only!
endfunc
--- /dev/null
+" Tests for setting 'buftype' to "prompt"
+
+if !has('channel')
+ finish
+endif
+
+source shared.vim
+source screendump.vim
+
+func Test_prompt_basic()
+ " We need to use a terminal window to be able to feed keys without leaving
+ " Insert mode.
+ if !has('terminal')
+ call assert_report('no terminal')
+ return
+ endif
+ call writefile([
+ \ 'func TextEntered(text)',
+ \ ' if a:text == "exit"',
+ \ ' 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 . "\"")',
+ \ 'endfunc',
+ \ '',
+ \ 'call setline(1, "other buffer")',
+ \ 'new',
+ \ 'set buftype=prompt',
+ \ 'call prompt_setcallback(bufnr(""), function("TextEntered"))',
+ \ 'startinsert',
+ \ ], 'Xpromptscript')
+ let buf = RunVimInTerminal('-S Xpromptscript', {})
+ call WaitForAssert({-> assert_equal('%', term_getline(buf, 1))})
+
+ call term_sendkeys(buf, "hello\<CR>")
+ call WaitForAssert({-> assert_equal('% 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('Xpromptscript')
+endfunc
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 27,
/**/
26,
/**/