Patch 8.1.2080

10 views
Skip to first unread message

Bram Moolenaar

unread,
Sep 26, 2019, 5:09:36 PM9/26/19
to vim...@googlegroups.com

Patch 8.1.2080
Problem: The terminal API is limited and can't be disabled.
Solution: Add term_setapi() to set the function prefix. (Ozaki Kiichi,
closes #2907)
Files: runtime/doc/eval.txt, runtime/doc/terminal.txt, src/channel.c,
src/evalfunc.c, src/proto/terminal.pro, src/structs.h,
src/terminal.c, src/testdir/term_util.vim,
src/testdir/test_terminal.vim


*** ../vim-8.1.2079/runtime/doc/eval.txt 2019-09-18 21:15:25.413966524 +0200
--- runtime/doc/eval.txt 2019-09-26 22:20:41.803905716 +0200
***************
*** 1,4 ****
! *eval.txt* For Vim version 8.1. Last change: 2019 May 05


VIM REFERENCE MANUAL by Bram Moolenaar
--- 1,4 ----
! *eval.txt* For Vim version 8.1. Last change: 2019 Sep 26


VIM REFERENCE MANUAL by Bram Moolenaar
***************
*** 2052,2065 ****
Read-only.

*v:progpath* *progpath-variable*
! v:progpath Contains the command with which Vim was invoked, including the
! path. Useful if you want to message a Vim server using a
|--remote-expr|.
To get the full path use: >
echo exepath(v:progpath)
! < If the path is relative it will be expanded to the full path,
! so that it still works after `:cd`. Thus starting "./vim"
! results in "/home/user/path/to/vim/src/vim".
On MS-Windows the executable may be called "vim.exe", but the
".exe" is not added to v:progpath.
Read-only.
--- 2052,2070 ----
Read-only.

*v:progpath* *progpath-variable*
! v:progpath Contains the command with which Vim was invoked, in a form
! that when passed to the shell will run the same Vim executable
! as the current one (if $PATH remains unchanged).
! Useful if you want to message a Vim server using a
|--remote-expr|.
To get the full path use: >
echo exepath(v:progpath)
! < If the command has a relative path it will be expanded to the
! full path, so that it still works after `:cd`. Thus starting
! "./vim" results in "/home/user/path/to/vim/src/vim".
! On Linux and other systems it will always be the full path.
! On Mac it may just be "vim" and using exepath() as mentioned
! above should be used to get the full path.
On MS-Windows the executable may be called "vim.exe", but the
".exe" is not added to v:progpath.
Read-only.
***************
*** 2590,2596 ****
pathshorten({expr}) String shorten directory names in a path
perleval({expr}) any evaluate |Perl| expression
popup_atcursor({what}, {options}) Number create popup window near the cursor
! popup_beval({what}, {options}) Number create popup window for 'ballooneval'
popup_clear() none close all popup windows
popup_close({id} [, {result}]) none close popup window {id}
popup_create({what}, {options}) Number create a popup window
--- 2595,2601 ----
pathshorten({expr}) String shorten directory names in a path
perleval({expr}) any evaluate |Perl| expression
popup_atcursor({what}, {options}) Number create popup window near the cursor
! popup_beval({what}, {options}) Number create popup window for 'ballooneval'
popup_clear() none close all popup windows
popup_close({id} [, {result}]) none close popup window {id}
popup_create({what}, {options}) Number create a popup window
***************
*** 2814,2819 ****
--- 2819,2825 ----
term_list() List get the list of terminal buffers
term_scrape({buf}, {row}) List get row of a terminal screen
term_sendkeys({buf}, {keys}) none send keystrokes to a terminal
+ term_setapi({buf}, {expr}) none set |terminal-api| function name prefix
term_setansicolors({buf}, {colors})
none set ANSI palette in GUI color mode
term_setkill({buf}, {how}) none set signal to stop job in terminal
***************
*** 3133,3140 ****
{title} title for the requester
{initdir} directory to start browsing in
{default} default file name
! When the "Cancel" button is hit, something went wrong, or
! browsing is not possible, an empty string is returned.

*browsedir()*
browsedir({title}, {initdir})
--- 3139,3146 ----
{title} title for the requester
{initdir} directory to start browsing in
{default} default file name
! An empty string is returned when the "Cancel" button is hit,
! something went wrong, or browsing is not possible.

*browsedir()*
browsedir({title}, {initdir})
***************
*** 3155,3161 ****
number. Otherwise return the buffer number of the newly
created buffer. When {name} is an empty string then a new
buffer is always created.
! The buffer will not have' 'buflisted' set and not be loaded
yet. To add some text to the buffer use this: >
let bufnr = bufadd('someName')
call bufload(bufnr)
--- 3161,3167 ----
number. Otherwise return the buffer number of the newly
created buffer. When {name} is an empty string then a new
buffer is always created.
! The buffer will not have 'buflisted' set and not be loaded
yet. To add some text to the buffer use this: >
let bufnr = bufadd('someName')
call bufload(bufnr)
***************
*** 3257,3265 ****
The result is the number of a buffer, as it is displayed by
the ":ls" command. For the use of {expr}, see |bufname()|
above.
If the buffer doesn't exist, -1 is returned. Or, if the
{create} argument is present and not zero, a new, unlisted,
! buffer is created and its number is returned.
bufnr("$") is the last buffer: >
:let last_buffer = bufnr("$")
< The result is a Number, which is the highest buffer number
--- 3263,3276 ----
The result is the number of a buffer, as it is displayed by
the ":ls" command. For the use of {expr}, see |bufname()|
above.
+
If the buffer doesn't exist, -1 is returned. Or, if the
{create} argument is present and not zero, a new, unlisted,
! buffer is created and its number is returned. Example: >
! let newbuf = bufnr('Scratch001', 1)
! < Using an empty name uses the current buffer. To create a new
! buffer with an empty name use |bufadd()|.
!
bufnr("$") is the last buffer: >
:let last_buffer = bufnr("$")
< The result is a Number, which is the highest buffer number
***************
*** 4723,4729 ****
get({dict}, {key} [, {default}])
Get item with key {key} from |Dictionary| {dict}. When this
item is not available return {default}. Return zero when
! {default} is omitted.
get({func}, {what})
Get an item with from Funcref {func}. Possible values for
{what} are:
--- 4734,4743 ----
get({dict}, {key} [, {default}])
Get item with key {key} from |Dictionary| {dict}. When this
item is not available return {default}. Return zero when
! {default} is omitted. Useful example: >
! let val = get(g:, 'var_name', 'default')
! < This gets the value of g:var_name if it exists, and uses
! 'default' when it does not exist.
get({func}, {what})
Get an item with from Funcref {func}. Possible values for
{what} are:
***************
*** 5691,5698 ****
GetExpr()->glob2regpat()
< *globpath()*
globpath({path}, {expr} [, {nosuf} [, {list} [, {alllinks}]]])
! Perform glob() on all directories in {path} and concatenate
! the results. Example: >
:echo globpath(&rtp, "syntax/c.vim")
<
{path} is a comma-separated list of directory names. Each
--- 5705,5712 ----
GetExpr()->glob2regpat()
< *globpath()*
globpath({path}, {expr} [, {nosuf} [, {list} [, {alllinks}]]])
! Perform glob() for {expr} on all directories in {path} and
! concatenate the results. Example: >
:echo globpath(&rtp, "syntax/c.vim")
<
{path} is a comma-separated list of directory names. Each
***************
*** 5793,5799 ****
If no matching mapping is found 0 is returned.
The following characters are recognized in {mode}:
n Normal mode
! v Visual mode
o Operator-pending mode
i Insert mode
l Language-Argument ("r", "f", "t", etc.)
--- 5807,5815 ----
If no matching mapping is found 0 is returned.
The following characters are recognized in {mode}:
n Normal mode
! v Visual and Select mode
! x Visual mode
! s Select mode
o Operator-pending mode
i Insert mode
l Language-Argument ("r", "f", "t", etc.)
***************
*** 6466,6472 ****
buffer is used.
Returns a unique ID that can be passed to |listener_remove()|.

! The {callback} is invoked with four arguments:
a:bufnr the buffer that was changed
a:start first changed line number
a:end first line number below the change
--- 6482,6488 ----
buffer is used.
Returns a unique ID that can be passed to |listener_remove()|.

! The {callback} is invoked with five arguments:
a:bufnr the buffer that was changed
a:start first changed line number
a:end first line number below the change
***************
*** 9038,9068 ****
current state. Mostly useful in callbacks that want to do
work that may not always be safe. Roughly this works like:
- callback uses state() to check if work is safe to do.
! If yes, then do it right away.
! Otherwise add to work queue and add SafeState and/or
! SafeStateAgain autocommand.
! - When SafeState or SafeStateAgain is triggered, check with
! state() if the work can be done now, and if yes remove it
! from the queue and execute.
Also see |mode()|.

When {what} is given only characters in this string will be
added. E.g, this checks if the screen has scrolled: >
! if state('s') != ''
<
These characters indicate the state, generally indicating that
something is busy:
! m halfway a mapping, :normal command, feedkeys() or
! stuffed command
! o operator pending or waiting for a command argument
! a Insert mode autocomplete active
! x executing an autocommand
! w blocked on waiting, e.g. ch_evalexpr() and
! ch_read(), ch_readraw() when reading json.
! S not triggering SafeState or SafeStateAgain
! c callback invoked, including timer (repeats for
! recursiveness up to "ccc")
! s screen has scrolled for messages

str2float({expr}) *str2float()*
Convert String {expr} to a Float. This mostly works the same
--- 9054,9089 ----
current state. Mostly useful in callbacks that want to do
work that may not always be safe. Roughly this works like:
- callback uses state() to check if work is safe to do.
! Yes: then do it right away.
! No: add to work queue and add a |SafeState| and/or
! |SafeStateAgain| autocommand (|SafeState| triggers at
! toplevel, |SafeStateAgain| triggers after handling
! messages and callbacks).
! - When SafeState or SafeStateAgain is triggered and executes
! your autocommand, check with `state()` if the work can be
! done now, and if yes remove it from the queue and execute.
! Remove the autocommand if the queue is now empty.
Also see |mode()|.

When {what} is given only characters in this string will be
added. E.g, this checks if the screen has scrolled: >
! if state('s') == ''
! " screen has not scrolled
<
These characters indicate the state, generally indicating that
something is busy:
! m halfway a mapping, :normal command, feedkeys() or
! stuffed command
! o operator pending or waiting for a command argument,
! e.g. after |f|
! a Insert mode autocomplete active
! x executing an autocommand
! w blocked on waiting, e.g. ch_evalexpr() and
! ch_read(), ch_readraw() when reading json.
! S not triggering SafeState or SafeStateAgain
! c callback invoked, including timer (repeats for
! recursiveness up to "ccc")
! s screen has scrolled for messages

str2float({expr}) *str2float()*
Convert String {expr} to a Float. This mostly works the same
***************
*** 9758,9764 ****

term_ functions are documented here: |terminal-function-details|

! test_ functions are documented here: |test-functions|


*timer_info()*
--- 9779,9785 ----

term_ functions are documented here: |terminal-function-details|

! test_ functions are documented here: |test-functions-details|


*timer_info()*
***************
*** 10556,10561 ****
--- 10577,10583 ----
menu Compiled with support for |:menu|.
mksession Compiled with support for |:mksession|.
modify_fname Compiled with file name modifiers. |filename-modifiers|
+ (always true)
mouse Compiled with support mouse.
mouse_dec Compiled with support for Dec terminal mouse.
mouse_gpm Compiled with support for gpm (Linux console mouse)
***************
*** 11203,11208 ****
--- 11225,11236 ----
:let ${env-name} = {expr1} *:let-environment* *:let-$*
Set environment variable {env-name} to the result of
the expression {expr1}. The type is always String.
+
+ On some systems making an environment variable empty
+ causes it to be deleted. Many systems do not make a
+ difference between an environment variable that is not
+ set and an environment variable that is empty.
+
:let ${env-name} .= {expr1}
Append {expr1} to the environment variable {env-name}.
If the environment variable didn't exist yet this
*** ../vim-8.1.2079/runtime/doc/terminal.txt 2019-09-08 20:55:03.146072987 +0200
--- runtime/doc/terminal.txt 2019-09-26 22:32:54.242424613 +0200
***************
*** 1,4 ****
! *terminal.txt* For Vim version 8.1. Last change: 2019 May 05


VIM REFERENCE MANUAL by Bram Moolenaar
--- 1,4 ----
! *terminal.txt* For Vim version 8.1. Last change: 2019 Sep 26


VIM REFERENCE MANUAL by Bram Moolenaar
***************
*** 222,228 ****
Vim width (no window left or right of
the terminal window) this value is
ignored.
! ++eof={text} when using [range]: text to send after
the last line was written. Cannot
contain white space. A CR is
appended. For MS-Windows the default
--- 222,228 ----
Vim width (no window left or right of
the terminal window) this value is
ignored.
! ++eof={text} When using [range]: text to send after
the last line was written. Cannot
contain white space. A CR is
appended. For MS-Windows the default
***************
*** 234,239 ****
--- 234,243 ----
++type={pty} (MS-Windows only): Use {pty} as the
virtual console. See 'termwintype'
for the values.
+ ++api={expr} Permit the function name starting with
+ {expr} to be called as |terminal-api|
+ function. If {expr} is empty then no
+ function can be called.

If you want to use more options use the |term_start()|
function.
***************
*** 701,706 ****
--- 705,719 ----
GetBufnr()->term_sendkeys(keys)


+ term_setapi({buf}, {expr}) *term_setapi()*
+ Set the function name prefix to be used for the |terminal-api|
+ function in terminal {buf}. For example: >
+ :call term_setapi(buf, "Myapi_")
+ :call term_setapi(buf, "")
+ <
+ The default is "Tapi_". When {expr} is an empty string then
+ no |terminal-api| function can be used for {buf}.
+
term_setansicolors({buf}, {colors}) *term_setansicolors()*
Set the ANSI color palette used by terminal {buf}.
{colors} must be a List of 16 valid color names or hexadecimal
***************
*** 843,848 ****
--- 856,864 ----
color modes. See |g:terminal_ansi_colors|.
"tty_type" (MS-Windows only): Specify which pty to
use. See 'termwintype' for the values.
+ "term_api" function name prefix for the
+ |terminal-api| function. See
+ |term_setapi()|.

Can also be used as a |method|: >
GetCommand()->term_start()
***************
*** 902,910 ****
Call a user defined function with {argument}.
The function is called with two arguments: the buffer number
of the terminal and {argument}, the decoded JSON argument.
! The function name must start with "Tapi_" to avoid
accidentally calling a function not meant to be used for the
! terminal API.
The user function should sanity check the argument.
The function can use |term_sendkeys()| to send back a reply.
Example in JSON: >
--- 918,926 ----
Call a user defined function with {argument}.
The function is called with two arguments: the buffer number
of the terminal and {argument}, the decoded JSON argument.
! By default, the function name must start with "Tapi_" to avoid
accidentally calling a function not meant to be used for the
! terminal API. This can be changed with |term_setapi()|.
The user function should sanity check the argument.
The function can use |term_sendkeys()| to send back a reply.
Example in JSON: >
*** ../vim-8.1.2079/src/channel.c 2019-09-25 21:43:07.275251603 +0200
--- src/channel.c 2019-09-26 22:25:12.202839993 +0200
***************
*** 5144,5149 ****
--- 5144,5157 ----
memcpy(opt->jo_ansi_colors, rgb, sizeof(rgb));
}
# endif
+ else if (STRCMP(hi->hi_key, "term_api") == 0)
+ {
+ if (!(supported2 & JO2_TERM_API))
+ break;
+ opt->jo_set2 |= JO2_TERM_API;
+ opt->jo_term_api = tv_get_string_buf_chk(item,
+ opt->jo_term_api_buf);
+ }
#endif
else if (STRCMP(hi->hi_key, "env") == 0)
{
*** ../vim-8.1.2079/src/evalfunc.c 2019-09-16 22:55:57.728006887 +0200
--- src/evalfunc.c 2019-09-26 22:13:13.745597982 +0200
***************
*** 787,792 ****
--- 787,793 ----
# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
{"term_setansicolors", 2, 2, FEARG_1, f_term_setansicolors},
# endif
+ {"term_setapi", 2, 2, FEARG_1, f_term_setapi},
{"term_setkill", 2, 2, FEARG_1, f_term_setkill},
{"term_setrestore", 2, 2, FEARG_1, f_term_setrestore},
{"term_setsize", 3, 3, FEARG_1, f_term_setsize},
*** ../vim-8.1.2079/src/proto/terminal.pro 2019-09-10 21:27:15.175646978 +0200
--- src/proto/terminal.pro 2019-09-26 22:07:13.654822573 +0200
***************
*** 50,55 ****
--- 50,56 ----
void f_term_sendkeys(typval_T *argvars, typval_T *rettv);
void f_term_getansicolors(typval_T *argvars, typval_T *rettv);
void f_term_setansicolors(typval_T *argvars, typval_T *rettv);
+ void f_term_setapi(typval_T *argvars, typval_T *rettv);
void f_term_setrestore(typval_T *argvars, typval_T *rettv);
void f_term_setkill(typval_T *argvars, typval_T *rettv);
void f_term_start(typval_T *argvars, typval_T *rettv);
*** ../vim-8.1.2079/src/structs.h 2019-09-25 22:36:57.300103046 +0200
--- src/structs.h 2019-09-26 22:25:01.002884547 +0200
***************
*** 1938,1943 ****
--- 1938,1944 ----
#define JO2_ANSI_COLORS 0x8000 // "ansi_colors"
#define JO2_TTY_TYPE 0x10000 // "tty_type"
#define JO2_BUFNR 0x20000 // "bufnr"
+ #define JO2_TERM_API 0x40000 // "term_api"

#define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
#define JO_CB_ALL \
***************
*** 2007,2012 ****
--- 2008,2015 ----
long_u jo_ansi_colors[16];
# endif
int jo_tty_type; // first character of "tty_type"
+ char_u *jo_term_api;
+ char_u jo_term_api_buf[NUMBUFLEN];
#endif
} jobopt_T;

*** ../vim-8.1.2079/src/terminal.c 2019-09-25 22:14:26.698530906 +0200
--- src/terminal.c 2019-09-26 22:44:23.488918273 +0200
***************
*** 109,114 ****
--- 109,115 ----
#define TL_FINISH_OPEN 'o' /* ++open */
char_u *tl_opencmd;
char_u *tl_eof_chars;
+ char_u *tl_api; // prefix for terminal API function

char_u *tl_arg0_cmd; // To format the status bar

***************
*** 641,646 ****
--- 642,652 ----
term->tl_kill = vim_strnsave(opt->jo_term_kill, p - opt->jo_term_kill);
}

+ if (opt->jo_term_api != NULL)
+ term->tl_api = vim_strsave(opt->jo_term_api);
+ else
+ term->tl_api = vim_strsave((char_u *)"Tapi_");
+
/* System dependent: setup the vterm and maybe start the job in it. */
if (argv == NULL
&& argvar->v_type == VAR_STRING
***************
*** 708,751 ****
cmd += 2;
p = skiptowhite(cmd);
ep = vim_strchr(cmd, '=');
! if (ep != NULL && ep < p)
! p = ep;

! if ((int)(p - cmd) == 5 && STRNICMP(cmd, "close", 5) == 0)
opt.jo_term_finish = 'c';
! else if ((int)(p - cmd) == 7 && STRNICMP(cmd, "noclose", 7) == 0)
opt.jo_term_finish = 'n';
! else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "open", 4) == 0)
opt.jo_term_finish = 'o';
! else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "curwin", 6) == 0)
opt.jo_curwin = 1;
! else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "hidden", 6) == 0)
opt.jo_hidden = 1;
! else if ((int)(p - cmd) == 9 && STRNICMP(cmd, "norestore", 9) == 0)
opt.jo_term_norestore = 1;
! else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "kill", 4) == 0
! && ep != NULL)
{
opt.jo_set2 |= JO2_TERM_KILL;
opt.jo_term_kill = ep + 1;
p = skiptowhite(cmd);
}
! else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "rows", 4) == 0
! && ep != NULL && isdigit(ep[1]))
{
opt.jo_set2 |= JO2_TERM_ROWS;
opt.jo_term_rows = atoi((char *)ep + 1);
p = skiptowhite(cmd);
}
! else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "cols", 4) == 0
! && ep != NULL && isdigit(ep[1]))
{
opt.jo_set2 |= JO2_TERM_COLS;
opt.jo_term_cols = atoi((char *)ep + 1);
p = skiptowhite(cmd);
}
! else if ((int)(p - cmd) == 3 && STRNICMP(cmd, "eof", 3) == 0
! && ep != NULL)
{
char_u *buf = NULL;
char_u *keys;
--- 714,771 ----
cmd += 2;
p = skiptowhite(cmd);
ep = vim_strchr(cmd, '=');
! if (ep != NULL)
! {
! if (ep < p)
! p = ep;
! else
! ep = NULL;
! }

! # define OPTARG_HAS(name) ((int)(p - cmd) == sizeof(name) - 1 \
! && STRNICMP(cmd, name, sizeof(name) - 1) == 0)
! if (OPTARG_HAS("close"))
opt.jo_term_finish = 'c';
! else if (OPTARG_HAS("noclose"))
opt.jo_term_finish = 'n';
! else if (OPTARG_HAS("open"))
opt.jo_term_finish = 'o';
! else if (OPTARG_HAS("curwin"))
opt.jo_curwin = 1;
! else if (OPTARG_HAS("hidden"))
opt.jo_hidden = 1;
! else if (OPTARG_HAS("norestore"))
opt.jo_term_norestore = 1;
! else if (OPTARG_HAS("kill") && ep != NULL)
{
opt.jo_set2 |= JO2_TERM_KILL;
opt.jo_term_kill = ep + 1;
p = skiptowhite(cmd);
}
! else if (OPTARG_HAS("api"))
! {
! opt.jo_set2 |= JO2_TERM_API;
! if (ep != NULL)
! {
! opt.jo_term_api = ep + 1;
! p = skiptowhite(cmd);
! }
! else
! opt.jo_term_api = NULL;
! }
! else if (OPTARG_HAS("rows") && ep != NULL && isdigit(ep[1]))
{
opt.jo_set2 |= JO2_TERM_ROWS;
opt.jo_term_rows = atoi((char *)ep + 1);
p = skiptowhite(cmd);
}
! else if (OPTARG_HAS("cols") && ep != NULL && isdigit(ep[1]))
{
opt.jo_set2 |= JO2_TERM_COLS;
opt.jo_term_cols = atoi((char *)ep + 1);
p = skiptowhite(cmd);
}
! else if (OPTARG_HAS("eof") && ep != NULL)
{
char_u *buf = NULL;
char_u *keys;
***************
*** 785,790 ****
--- 805,811 ----
semsg(_("E181: Invalid attribute: %s"), cmd);
goto theend;
}
+ # undef OPTARG_HAS
cmd = skipwhite(p);
}
if (*cmd == NUL)
***************
*** 933,938 ****
--- 954,960 ----
free_scrollback(term);

term_free_vterm(term);
+ vim_free(term->tl_api);
vim_free(term->tl_title);
#ifdef FEAT_SESSION
vim_free(term->tl_command);
***************
*** 3770,3775 ****
--- 3792,3806 ----
}

/*
+ * Return TRUE if "func" starts with "pat" and "pat" isn't empty.
+ */
+ static int
+ is_permitted_term_api(char_u *func, char_u *pat)
+ {
+ return pat != NULL && *pat != NUL && STRNICMP(func, pat, STRLEN(pat)) == 0;
+ }
+
+ /*
* Handles a function call from the job running in a terminal.
* "item" is the function name, "item->li_next" has the arguments.
*/
***************
*** 3788,3796 ****
}
func = tv_get_string(&item->li_tv);

! if (STRNCMP(func, "Tapi_", 5) != 0)
{
! ch_log(channel, "Invalid function name: %s", func);
return;
}

--- 3819,3827 ----
}
func = tv_get_string(&item->li_tv);

! if (!is_permitted_term_api(func, term->tl_api))
{
! ch_log(channel, "Unpermitted function: %s", func);
return;
}

***************
*** 5546,5551 ****
--- 5577,5603 ----
#endif

/*
+ * "term_setapi(buf, api)" function
+ */
+ void
+ f_term_setapi(typval_T *argvars, typval_T *rettv UNUSED)
+ {
+ buf_T *buf = term_get_buf(argvars, "term_setapi()");
+ term_T *term;
+ char_u *api;
+
+ if (buf == NULL)
+ return;
+ term = buf->b_term;
+ vim_free(term->tl_api);
+ api = tv_get_string_chk(&argvars[1]);
+ if (api != NULL)
+ term->tl_api = vim_strsave(api);
+ else
+ term->tl_api = NULL;
+ }
+
+ /*
* "term_setrestore(buf, command)" function
*/
void
***************
*** 5608,5614 ****
+ JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
+ JO2_CWD + JO2_ENV + JO2_EOF_CHARS
+ JO2_NORESTORE + JO2_TERM_KILL
! + JO2_ANSI_COLORS + JO2_TTY_TYPE) == FAIL)
return;

buf = term_start(&argvars[0], NULL, &opt, 0);
--- 5660,5666 ----
+ JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
+ JO2_CWD + JO2_ENV + JO2_EOF_CHARS
+ JO2_NORESTORE + JO2_TERM_KILL
! + JO2_ANSI_COLORS + JO2_TTY_TYPE + JO2_TERM_API) == FAIL)
return;

buf = term_start(&argvars[0], NULL, &opt, 0);
*** ../vim-8.1.2079/src/testdir/term_util.vim 2019-07-04 14:20:38.180325318 +0200
--- src/testdir/term_util.vim 2019-09-26 23:02:16.746622527 +0200
***************
*** 61,71 ****

let cmd = GetVimCommandCleanTerm() .. a:arguments

! let buf = term_start(cmd, {
\ 'curwin': 1,
\ 'term_rows': rows,
\ 'term_cols': cols,
! \ })
if &termwinsize == ''
" in the GUI we may end up with a different size, try to set it.
if term_getsize(buf) != [rows, cols]
--- 61,76 ----

let cmd = GetVimCommandCleanTerm() .. a:arguments

! let options = {
\ 'curwin': 1,
\ 'term_rows': rows,
\ 'term_cols': cols,
! \ }
! " Accept other options whose name starts with 'term_'.
! call extend(options, filter(copy(a:options), 'v:key =~# "^term_"'))
!
! let buf = term_start(cmd, options)
!
if &termwinsize == ''
" in the GUI we may end up with a different size, try to set it.
if term_getsize(buf) != [rows, cols]
*** ../vim-8.1.2079/src/testdir/test_terminal.vim 2019-09-22 21:29:49.659426007 +0200
--- src/testdir/test_terminal.vim 2019-09-26 22:49:33.190913684 +0200
***************
*** 1353,1382 ****
func Test_terminal_api_call()
CheckRunVimInTerminal

call WriteApiCall('Tapi_TryThis')
let buf = RunVimInTerminal('-S Xscript', {})
call WaitFor({-> exists('g:called_bufnum')})
call assert_equal(buf, g:called_bufnum)
call assert_equal(['hello', 123], g:called_arg)

call StopVimInTerminal(buf)
call delete('Xscript')
! unlet g:called_bufnum
! unlet g:called_arg
endfunc

func Test_terminal_api_call_fails()
CheckRunVimInTerminal

call WriteApiCall('TryThis')
call ch_logfile('Xlog', 'w')
! let buf = RunVimInTerminal('-S Xscript', {})
! call WaitForAssert({-> assert_match('Invalid function name: TryThis', string(readfile('Xlog')))})

call StopVimInTerminal(buf)
call delete('Xscript')
! call ch_logfile('', '')
call delete('Xlog')
endfunc

let s:caught_e937 = 0
--- 1353,1442 ----
func Test_terminal_api_call()
CheckRunVimInTerminal

+ call ch_logfile('logfile', 'w')
+ unlet! g:called_bufnum
+ unlet! g:called_arg
+
call WriteApiCall('Tapi_TryThis')
+
+ " Default
let buf = RunVimInTerminal('-S Xscript', {})
call WaitFor({-> exists('g:called_bufnum')})
call assert_equal(buf, g:called_bufnum)
call assert_equal(['hello', 123], g:called_arg)
+ call StopVimInTerminal(buf)
+
+ unlet! g:called_bufnum
+ unlet! g:called_arg
+
+ " Enable explicitly
+ let buf = RunVimInTerminal('-S Xscript', {'term_api': 'Tapi_Try'})
+ call WaitFor({-> exists('g:called_bufnum')})
+ call assert_equal(buf, g:called_bufnum)
+ call assert_equal(['hello', 123], g:called_arg)
+ call StopVimInTerminal(buf)

+ unlet! g:called_bufnum
+ unlet! g:called_arg
+
+ func! ApiCall_TryThis(bufnum, arg)
+ let g:called_bufnum2 = a:bufnum
+ let g:called_arg2 = a:arg
+ endfunc
+
+ call WriteApiCall('ApiCall_TryThis')
+
+ " Use prefix match
+ let buf = RunVimInTerminal('-S Xscript', {'term_api': 'ApiCall_'})
+ call WaitFor({-> exists('g:called_bufnum2')})
+ call assert_equal(buf, g:called_bufnum2)
+ call assert_equal(['hello', 123], g:called_arg2)
call StopVimInTerminal(buf)
+
+ unlet! g:called_bufnum2
+ unlet! g:called_arg2
+
call delete('Xscript')
! delfunction! ApiCall_TryThis
! unlet! g:called_bufnum2
! unlet! g:called_arg2
endfunc

func Test_terminal_api_call_fails()
CheckRunVimInTerminal

+ func! TryThis(bufnum, arg)
+ let g:called_bufnum3 = a:bufnum
+ let g:called_arg3 = a:arg
+ endfunc
+
call WriteApiCall('TryThis')
+
+ unlet! g:called_bufnum3
+ unlet! g:called_arg3
+
+ " Not permitted
call ch_logfile('Xlog', 'w')
! let buf = RunVimInTerminal('-S Xscript', {'term_api': ''})
! call WaitForAssert({-> assert_match('Unpermitted function: TryThis', string(readfile('Xlog')))})
! call assert_false(exists('g:called_bufnum3'))
! call assert_false(exists('g:called_arg3'))
! call StopVimInTerminal(buf)

+ " No match
+ call ch_logfile('Xlog', 'w')
+ let buf = RunVimInTerminal('-S Xscript', {'term_api': 'TryThat'})
+ call WaitFor({-> string(readfile('Xlog')) =~ 'Unpermitted function: TryThis'})
+ call assert_false(exists('g:called_bufnum3'))
+ call assert_false(exists('g:called_arg3'))
call StopVimInTerminal(buf)
+
call delete('Xscript')
! call ch_logfile('')
call delete('Xlog')
+ delfunction! TryThis
+ unlet! g:called_bufnum3
+ unlet! g:called_arg3
endfunc

let s:caught_e937 = 0
***************
*** 2061,2063 ****
--- 2121,2154 ----
exe buf . "bwipe!"
call delete('Xtext')
endfunc
+
+ func Test_terminal_setapi_and_call()
+ if !CanRunVimInTerminal()
+ return
+ endif
+
+ call WriteApiCall('Tapi_TryThis')
+ call ch_logfile('Xlog', 'w')
+
+ unlet! g:called_bufnum
+ unlet! g:called_arg
+
+ let buf = RunVimInTerminal('-S Xscript', {'term_api': 0})
+ call WaitForAssert({-> assert_match('Unpermitted function: Tapi_TryThis', string(readfile('Xlog')))})
+ call assert_false(exists('g:called_bufnum'))
+ call assert_false(exists('g:called_arg'))
+
+ call term_setapi(buf, 'Tapi_TryThis')
+ call term_sendkeys(buf, ":set notitle\<CR>")
+ call term_sendkeys(buf, ":source Xscript\<CR>")
+ call WaitFor({-> exists('g:called_bufnum')})
+ call assert_equal(buf, g:called_bufnum)
+ call assert_equal(['hello', 123], g:called_arg)
+ call StopVimInTerminal(buf)
+
+ call delete('Xscript')
+ call ch_logfile('')
+ call delete('Xlog')
+ unlet! g:called_bufnum
+ unlet! g:called_arg
+ endfunc
*** ../vim-8.1.2079/src/version.c 2019-09-25 23:06:35.859483812 +0200
--- src/version.c 2019-09-26 23:05:39.786313095 +0200
***************
*** 759,760 ****
--- 759,762 ----
{ /* Add new patch number below this line */
+ /**/
+ 2080,
/**/

--
MORTICIAN: What?
CUSTOMER: Nothing -- here's your nine pence.
DEAD PERSON: I'm not dead!
MORTICIAN: Here -- he says he's not dead!
CUSTOMER: Yes, he is.
DEAD PERSON: I'm not!
The Quest for the Holy Grail (Monty Python)

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
Reply all
Reply to author
Forward
0 new messages