summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2018-06-03 14:47:35 +0200
committerBram Moolenaar <Bram@vim.org>2018-06-03 14:47:35 +0200
commitf273245f6433d5d43a5671306b520a3230c35787 (patch)
tree958293fed4c59ee0cb91a491c8c0e32aa0e618c2
parent33c5e9fa7af935c61a8aac461b9664c501003440 (diff)
patch 8.1.0027: difficult to make a plugin that feeds a line to a jobv8.1.0027
Problem: Difficult to make a plugin that feeds a line to a job. Solution: Add the nitial code for the "prompt" buftype.
-rw-r--r--runtime/doc/channel.txt39
-rw-r--r--runtime/doc/eval.txt43
-rw-r--r--runtime/doc/options.txt15
-rw-r--r--runtime/doc/todo.txt48
-rw-r--r--src/Makefile1
-rw-r--r--src/buffer.c20
-rw-r--r--src/channel.c34
-rw-r--r--src/diff.c7
-rw-r--r--src/edit.c78
-rw-r--r--src/evalfunc.c64
-rw-r--r--src/normal.c65
-rw-r--r--src/ops.c77
-rw-r--r--src/option.c2
-rw-r--r--src/proto/buffer.pro1
-rw-r--r--src/proto/channel.pro1
-rw-r--r--src/proto/edit.pro2
-rw-r--r--src/proto/ops.pro1
-rw-r--r--src/structs.h5
-rw-r--r--src/testdir/Make_all.mak1
-rw-r--r--src/testdir/screendump.vim29
-rw-r--r--src/testdir/test_prompt_buffer.vim55
-rw-r--r--src/version.c2
22 files changed, 532 insertions, 58 deletions
diff --git a/runtime/doc/channel.txt b/runtime/doc/channel.txt
index 9cc2be37ad..bffb3e2833 100644
--- a/runtime/doc/channel.txt
+++ b/runtime/doc/channel.txt
@@ -22,6 +22,7 @@ The Netbeans interface also uses a channel. |netbeans|
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}
@@ -770,5 +771,43 @@ signals. E.g. to force a job to stop, "kill it": >
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:
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index e243ba3788..7d214c11aa 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2294,6 +2294,9 @@ perleval({expr}) any evaluate |Perl| expression
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
@@ -2302,7 +2305,7 @@ range({expr} [, {max} [, {stride}]])
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
@@ -4650,7 +4653,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
@@ -6475,6 +6478,42 @@ printf({fmt}, {expr1} ...) *printf()*
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|.
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 422f100285..d37fa641a4 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1394,6 +1394,9 @@ A jump table for the options with a short description can be found at |Q_op|.
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|.
@@ -4264,7 +4267,8 @@ A jump table for the options with a short description can be found at |Q_op|.
'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.
@@ -4316,7 +4320,8 @@ A jump table for the options with a short description can be found at |Q_op|.
'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
@@ -4327,7 +4332,8 @@ A jump table for the options with a short description can be found at |Q_op|.
'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
@@ -4380,7 +4386,8 @@ A jump table for the options with a short description can be found at |Q_op|.
'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.
diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt
index 2029c35ee1..dbd293526b 100644
--- a/runtime/doc/todo.txt
+++ b/runtime/doc/todo.txt
@@ -38,6 +38,10 @@ browser use: https://github.com/vim/vim/issues/1234
*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,
@@ -71,9 +75,15 @@ Crash when mixing matchadd and substitute()? (Max Christian Pohle, 2018 May
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)
@@ -81,6 +91,22 @@ Errors found with random data:
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!"
@@ -88,16 +114,27 @@ modified buffers
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:
@@ -112,6 +149,8 @@ used for git temp files.
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.
@@ -141,6 +180,9 @@ How to test that it works well for all Vim users?
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)
diff --git a/src/Makefile b/src/Makefile
index 0e4c555627..ca972547f6 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -2252,6 +2252,7 @@ test_arglist \
test_popup \
test_preview \
test_profile \
+ test_prompt_buffer \
test_put \
test_python2 \
test_python3 \
diff --git a/src/buffer.c b/src/buffer.c
index e3cbdac1e8..1c55acbaf2 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -851,6 +851,10 @@ free_buffer(buf_T *buf)
#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);
@@ -5634,6 +5638,15 @@ bt_help(buf_T *buf)
}
/*
+ * 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.
*/
@@ -5642,7 +5655,8 @@ bt_nofile(buf_T *buf)
{
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');
}
/*
@@ -5651,7 +5665,9 @@ bt_nofile(buf_T *buf)
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
diff --git a/src/channel.c b/src/channel.c
index 504d6b6095..40a3e955d8 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -5836,4 +5836,38 @@ job_stop(job_T *job, typval_T *argvars, char *type)
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 */
diff --git a/src/diff.c b/src/diff.c
index cc9e6de8fd..c67654f621 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -2141,6 +2141,13 @@ nv_diffgetput(int put, long count)
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
diff --git a/src/edit.c b/src/edit.c
index 1ae8e2db44..1b79eccac9 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -203,6 +203,9 @@ static unsigned quote_meta(char_u *dest, char_u *str, int len);
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);
@@ -351,6 +354,9 @@ edit(
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;
@@ -707,6 +713,14 @@ 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
@@ -1374,6 +1388,18 @@ doESCkey:
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 */
auto_format(FALSE, FALSE);
@@ -1808,6 +1834,58 @@ edit_putchar(int c, int highlight)
}
}
+#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().
*/
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 90aa2efd50..9441bd89f4 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -294,6 +294,10 @@ static void f_pow(typval_T *argvars, typval_T *rettv);
#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);
@@ -744,6 +748,10 @@ static struct fst
#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},
@@ -1240,6 +1248,11 @@ f_append(typval_T *argvars, typval_T *rettv)
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 */
@@ -8379,6 +8392,57 @@ f_printf(typval_T *argvars, typval_T *rettv)
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
*/
diff --git a/src/normal.c b/src/normal.c
index 58f7a7a965..a01a434867 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -4180,6 +4180,11 @@ nv_help(cmdarg_T *cap)
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);
@@ -6214,6 +6219,17 @@ nv_down(cmdarg_T *cap)
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 (cursor_down(cap->count1, cap->oap->op_type == OP_NOP) == FAIL)
@@ -6972,6 +6988,13 @@ nv_kundo(cmdarg_T *cap)
{
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;
}
@@ -6989,6 +7012,13 @@ nv_replace(cmdarg_T *cap)
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)
@@ -7465,6 +7495,13 @@ nv_subst(cmdarg_T *cap)
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" */
{
if (cap->cmdchar == 'S')
@@ -8570,7 +8607,16 @@ nv_Undo(cmdarg_T *cap)
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);
}
@@ -8585,6 +8631,13 @@ nv_operator(cmdarg_T *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);
@@ -9426,6 +9479,12 @@ nv_put(cmdarg_T *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'
@@ -9551,6 +9610,12 @@ nv_open(cmdarg_T *cap)
#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);
}
diff --git a/src/ops.c b/src/ops.c
index 1bc51d8480..65fc75e20b 100644
--- a/src/ops.c
+++ b/src/ops.c
@@ -126,43 +126,47 @@ static int fmt_check_par(linenr_T, int *, char_u **, int do_comments);
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
};
/*
@@ -201,7 +205,16 @@ 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/option.c b/src/option.c
index 7fd1dda99c..16d05d8b50 100644
--- a/src/option.c
+++ b/src/option.c
@@ -3229,7 +3229,7 @@ static char *(p_bsdir_values[]) = {"current", "last", "buffer", NULL};
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
diff --git a/src/proto/buffer.pro b/src/proto/buffer.pro
index 59bb2c2012..9e63fb6055 100644
--- a/src/proto/buffer.pro
+++ b/