To: vim_dev@googlegroups.com Subject: Patch 8.1.2080 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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\") + call term_sendkeys(buf, ":source 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') + 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 -- Bram@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 ///