Skip to content

Commit d2842ea

Browse files
committed
patch 8.1.2080: the terminal API is limited and can't be disabled
Problem: The terminal API is limited and can't be disabled. Solution: Add term_setapi() to set the function prefix. (Ozaki Kiichi, closes #2907)
1 parent d2c1fb4 commit d2842ea

10 files changed

Lines changed: 217 additions & 32 deletions

File tree

runtime/doc/eval.txt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*eval.txt* For Vim version 8.1. Last change: 2019 Sep 19
1+
*eval.txt* For Vim version 8.1. Last change: 2019 Sep 26
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -2819,6 +2819,7 @@ term_gettty({buf}, [{input}]) String get the tty name of a terminal
28192819
term_list() List get the list of terminal buffers
28202820
term_scrape({buf}, {row}) List get row of a terminal screen
28212821
term_sendkeys({buf}, {keys}) none send keystrokes to a terminal
2822+
term_setapi({buf}, {expr}) none set |terminal-api| function name prefix
28222823
term_setansicolors({buf}, {colors})
28232824
none set ANSI palette in GUI color mode
28242825
term_setkill({buf}, {how}) none set signal to stop job in terminal
@@ -3262,9 +3263,14 @@ bufnr([{expr} [, {create}]])
32623263
The result is the number of a buffer, as it is displayed by
32633264
the ":ls" command. For the use of {expr}, see |bufname()|
32643265
above.
3266+
32653267
If the buffer doesn't exist, -1 is returned. Or, if the
32663268
{create} argument is present and not zero, a new, unlisted,
3267-
buffer is created and its number is returned.
3269+
buffer is created and its number is returned. Example: >
3270+
let newbuf = bufnr('Scratch001', 1)
3271+
< Using an empty name uses the current buffer. To create a new
3272+
buffer with an empty name use |bufadd()|.
3273+
32683274
bufnr("$") is the last buffer: >
32693275
:let last_buffer = bufnr("$")
32703276
< The result is a Number, which is the highest buffer number

runtime/doc/terminal.txt

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*terminal.txt* For Vim version 8.1. Last change: 2019 Sep 20
1+
*terminal.txt* For Vim version 8.1. Last change: 2019 Sep 26
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -222,7 +222,7 @@ Command syntax ~
222222
Vim width (no window left or right of
223223
the terminal window) this value is
224224
ignored.
225-
++eof={text} when using [range]: text to send after
225+
++eof={text} When using [range]: text to send after
226226
the last line was written. Cannot
227227
contain white space. A CR is
228228
appended. For MS-Windows the default
@@ -234,6 +234,10 @@ Command syntax ~
234234
++type={pty} (MS-Windows only): Use {pty} as the
235235
virtual console. See 'termwintype'
236236
for the values.
237+
++api={expr} Permit the function name starting with
238+
{expr} to be called as |terminal-api|
239+
function. If {expr} is empty then no
240+
function can be called.
237241

238242
If you want to use more options use the |term_start()|
239243
function.
@@ -701,6 +705,15 @@ term_sendkeys({buf}, {keys}) *term_sendkeys()*
701705
GetBufnr()->term_sendkeys(keys)
702706
703707
708+
term_setapi({buf}, {expr}) *term_setapi()*
709+
Set the function name prefix to be used for the |terminal-api|
710+
function in terminal {buf}. For example: >
711+
:call term_setapi(buf, "Myapi_")
712+
:call term_setapi(buf, "")
713+
<
714+
The default is "Tapi_". When {expr} is an empty string then
715+
no |terminal-api| function can be used for {buf}.
716+
704717
term_setansicolors({buf}, {colors}) *term_setansicolors()*
705718
Set the ANSI color palette used by terminal {buf}.
706719
{colors} must be a List of 16 valid color names or hexadecimal
@@ -843,6 +856,9 @@ term_start({cmd} [, {options}]) *term_start()*
843856
color modes. See |g:terminal_ansi_colors|.
844857
"tty_type" (MS-Windows only): Specify which pty to
845858
use. See 'termwintype' for the values.
859+
"term_api" function name prefix for the
860+
|terminal-api| function. See
861+
|term_setapi()|.
846862

847863
Can also be used as a |method|: >
848864
GetCommand()->term_start()
@@ -902,9 +918,9 @@ Currently supported commands:
902918
Call a user defined function with {argument}.
903919
The function is called with two arguments: the buffer number
904920
of the terminal and {argument}, the decoded JSON argument.
905-
The function name must start with "Tapi_" to avoid
921+
By default, the function name must start with "Tapi_" to avoid
906922
accidentally calling a function not meant to be used for the
907-
terminal API.
923+
terminal API. This can be changed with |term_setapi()|.
908924
The user function should sanity check the argument.
909925
The function can use |term_sendkeys()| to send back a reply.
910926
Example in JSON: >

src/channel.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5144,6 +5144,14 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
51445144
memcpy(opt->jo_ansi_colors, rgb, sizeof(rgb));
51455145
}
51465146
# endif
5147+
else if (STRCMP(hi->hi_key, "term_api") == 0)
5148+
{
5149+
if (!(supported2 & JO2_TERM_API))
5150+
break;
5151+
opt->jo_set2 |= JO2_TERM_API;
5152+
opt->jo_term_api = tv_get_string_buf_chk(item,
5153+
opt->jo_term_api_buf);
5154+
}
51475155
#endif
51485156
else if (STRCMP(hi->hi_key, "env") == 0)
51495157
{

src/evalfunc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,7 @@ static funcentry_T global_functions[] =
787787
# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
788788
{"term_setansicolors", 2, 2, FEARG_1, f_term_setansicolors},
789789
# endif
790+
{"term_setapi", 2, 2, FEARG_1, f_term_setapi},
790791
{"term_setkill", 2, 2, FEARG_1, f_term_setkill},
791792
{"term_setrestore", 2, 2, FEARG_1, f_term_setrestore},
792793
{"term_setsize", 3, 3, FEARG_1, f_term_setsize},

src/proto/terminal.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ void f_term_scrape(typval_T *argvars, typval_T *rettv);
5050
void f_term_sendkeys(typval_T *argvars, typval_T *rettv);
5151
void f_term_getansicolors(typval_T *argvars, typval_T *rettv);
5252
void f_term_setansicolors(typval_T *argvars, typval_T *rettv);
53+
void f_term_setapi(typval_T *argvars, typval_T *rettv);
5354
void f_term_setrestore(typval_T *argvars, typval_T *rettv);
5455
void f_term_setkill(typval_T *argvars, typval_T *rettv);
5556
void f_term_start(typval_T *argvars, typval_T *rettv);

src/structs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1938,6 +1938,7 @@ struct channel_S {
19381938
#define JO2_ANSI_COLORS 0x8000 // "ansi_colors"
19391939
#define JO2_TTY_TYPE 0x10000 // "tty_type"
19401940
#define JO2_BUFNR 0x20000 // "bufnr"
1941+
#define JO2_TERM_API 0x40000 // "term_api"
19411942

19421943
#define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
19431944
#define JO_CB_ALL \
@@ -2007,6 +2008,8 @@ typedef struct
20072008
long_u jo_ansi_colors[16];
20082009
# endif
20092010
int jo_tty_type; // first character of "tty_type"
2011+
char_u *jo_term_api;
2012+
char_u jo_term_api_buf[NUMBUFLEN];
20102013
#endif
20112014
} jobopt_T;
20122015

src/terminal.c

Lines changed: 71 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ struct terminal_S {
109109
#define TL_FINISH_OPEN 'o' /* ++open */
110110
char_u *tl_opencmd;
111111
char_u *tl_eof_chars;
112+
char_u *tl_api; // prefix for terminal API function
112113

113114
char_u *tl_arg0_cmd; // To format the status bar
114115

@@ -641,6 +642,11 @@ term_start(
641642
term->tl_kill = vim_strnsave(opt->jo_term_kill, p - opt->jo_term_kill);
642643
}
643644

645+
if (opt->jo_term_api != NULL)
646+
term->tl_api = vim_strsave(opt->jo_term_api);
647+
else
648+
term->tl_api = vim_strsave((char_u *)"Tapi_");
649+
644650
/* System dependent: setup the vterm and maybe start the job in it. */
645651
if (argv == NULL
646652
&& argvar->v_type == VAR_STRING
@@ -708,44 +714,58 @@ ex_terminal(exarg_T *eap)
708714
cmd += 2;
709715
p = skiptowhite(cmd);
710716
ep = vim_strchr(cmd, '=');
711-
if (ep != NULL && ep < p)
712-
p = ep;
717+
if (ep != NULL)
718+
{
719+
if (ep < p)
720+
p = ep;
721+
else
722+
ep = NULL;
723+
}
713724

714-
if ((int)(p - cmd) == 5 && STRNICMP(cmd, "close", 5) == 0)
725+
# define OPTARG_HAS(name) ((int)(p - cmd) == sizeof(name) - 1 \
726+
&& STRNICMP(cmd, name, sizeof(name) - 1) == 0)
727+
if (OPTARG_HAS("close"))
715728
opt.jo_term_finish = 'c';
716-
else if ((int)(p - cmd) == 7 && STRNICMP(cmd, "noclose", 7) == 0)
729+
else if (OPTARG_HAS("noclose"))
717730
opt.jo_term_finish = 'n';
718-
else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "open", 4) == 0)
731+
else if (OPTARG_HAS("open"))
719732
opt.jo_term_finish = 'o';
720-
else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "curwin", 6) == 0)
733+
else if (OPTARG_HAS("curwin"))
721734
opt.jo_curwin = 1;
722-
else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "hidden", 6) == 0)
735+
else if (OPTARG_HAS("hidden"))
723736
opt.jo_hidden = 1;
724-
else if ((int)(p - cmd) == 9 && STRNICMP(cmd, "norestore", 9) == 0)
737+
else if (OPTARG_HAS("norestore"))
725738
opt.jo_term_norestore = 1;
726-
else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "kill", 4) == 0
727-
&& ep != NULL)
739+
else if (OPTARG_HAS("kill") && ep != NULL)
728740
{
729741
opt.jo_set2 |= JO2_TERM_KILL;
730742
opt.jo_term_kill = ep + 1;
731743
p = skiptowhite(cmd);
732744
}
733-
else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "rows", 4) == 0
734-
&& ep != NULL && isdigit(ep[1]))
745+
else if (OPTARG_HAS("api"))
746+
{
747+
opt.jo_set2 |= JO2_TERM_API;
748+
if (ep != NULL)
749+
{
750+
opt.jo_term_api = ep + 1;
751+
p = skiptowhite(cmd);
752+
}
753+
else
754+
opt.jo_term_api = NULL;
755+
}
756+
else if (OPTARG_HAS("rows") && ep != NULL && isdigit(ep[1]))
735757
{
736758
opt.jo_set2 |= JO2_TERM_ROWS;
737759
opt.jo_term_rows = atoi((char *)ep + 1);
738760
p = skiptowhite(cmd);
739761
}
740-
else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "cols", 4) == 0
741-
&& ep != NULL && isdigit(ep[1]))
762+
else if (OPTARG_HAS("cols") && ep != NULL && isdigit(ep[1]))
742763
{
743764
opt.jo_set2 |= JO2_TERM_COLS;
744765
opt.jo_term_cols = atoi((char *)ep + 1);
745766
p = skiptowhite(cmd);
746767
}
747-
else if ((int)(p - cmd) == 3 && STRNICMP(cmd, "eof", 3) == 0
748-
&& ep != NULL)
768+
else if (OPTARG_HAS("eof") && ep != NULL)
749769
{
750770
char_u *buf = NULL;
751771
char_u *keys;
@@ -785,6 +805,7 @@ ex_terminal(exarg_T *eap)
785805
semsg(_("E181: Invalid attribute: %s"), cmd);
786806
goto theend;
787807
}
808+
# undef OPTARG_HAS
788809
cmd = skipwhite(p);
789810
}
790811
if (*cmd == NUL)
@@ -933,6 +954,7 @@ free_unused_terminals()
933954
free_scrollback(term);
934955

935956
term_free_vterm(term);
957+
vim_free(term->tl_api);
936958
vim_free(term->tl_title);
937959
#ifdef FEAT_SESSION
938960
vim_free(term->tl_command);
@@ -3769,6 +3791,15 @@ handle_drop_command(listitem_T *item)
37693791
vim_free(tofree);
37703792
}
37713793

3794+
/*
3795+
* Return TRUE if "func" starts with "pat" and "pat" isn't empty.
3796+
*/
3797+
static int
3798+
is_permitted_term_api(char_u *func, char_u *pat)
3799+
{
3800+
return pat != NULL && *pat != NUL && STRNICMP(func, pat, STRLEN(pat)) == 0;
3801+
}
3802+
37723803
/*
37733804
* Handles a function call from the job running in a terminal.
37743805
* "item" is the function name, "item->li_next" has the arguments.
@@ -3788,9 +3819,9 @@ handle_call_command(term_T *term, channel_T *channel, listitem_T *item)
37883819
}
37893820
func = tv_get_string(&item->li_tv);
37903821

3791-
if (STRNCMP(func, "Tapi_", 5) != 0)
3822+
if (!is_permitted_term_api(func, term->tl_api))
37923823
{
3793-
ch_log(channel, "Invalid function name: %s", func);
3824+
ch_log(channel, "Unpermitted function: %s", func);
37943825
return;
37953826
}
37963827

@@ -5545,6 +5576,27 @@ f_term_setansicolors(typval_T *argvars, typval_T *rettv UNUSED)
55455576
}
55465577
#endif
55475578

5579+
/*
5580+
* "term_setapi(buf, api)" function
5581+
*/
5582+
void
5583+
f_term_setapi(typval_T *argvars, typval_T *rettv UNUSED)
5584+
{
5585+
buf_T *buf = term_get_buf(argvars, "term_setapi()");
5586+
term_T *term;
5587+
char_u *api;
5588+
5589+
if (buf == NULL)
5590+
return;
5591+
term = buf->b_term;
5592+
vim_free(term->tl_api);
5593+
api = tv_get_string_chk(&argvars[1]);
5594+
if (api != NULL)
5595+
term->tl_api = vim_strsave(api);
5596+
else
5597+
term->tl_api = NULL;
5598+
}
5599+
55485600
/*
55495601
* "term_setrestore(buf, command)" function
55505602
*/
@@ -5608,7 +5660,7 @@ f_term_start(typval_T *argvars, typval_T *rettv)
56085660
+ JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
56095661
+ JO2_CWD + JO2_ENV + JO2_EOF_CHARS
56105662
+ JO2_NORESTORE + JO2_TERM_KILL
5611-
+ JO2_ANSI_COLORS + JO2_TTY_TYPE) == FAIL)
5663+
+ JO2_ANSI_COLORS + JO2_TTY_TYPE + JO2_TERM_API) == FAIL)
56125664
return;
56135665

56145666
buf = term_start(&argvars[0], NULL, &opt, 0);

src/testdir/term_util.vim

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,16 @@ func RunVimInTerminal(arguments, options)
6161

6262
let cmd = GetVimCommandCleanTerm() .. a:arguments
6363

64-
let buf = term_start(cmd, {
64+
let options = {
6565
\ 'curwin': 1,
6666
\ 'term_rows': rows,
6767
\ 'term_cols': cols,
68-
\ })
68+
\ }
69+
" Accept other options whose name starts with 'term_'.
70+
call extend(options, filter(copy(a:options), 'v:key =~# "^term_"'))
71+
72+
let buf = term_start(cmd, options)
73+
6974
if &termwinsize == ''
7075
" in the GUI we may end up with a different size, try to set it.
7176
if term_getsize(buf) != [rows, cols]

0 commit comments

Comments
 (0)