diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt index ed4e9e38ba..2e00ccfa94 100644 --- a/runtime/doc/develop.txt +++ b/runtime/doc/develop.txt @@ -1,4 +1,4 @@ -*develop.txt* For Vim version 8.0. Last change: 2017 Jul 31 +*develop.txt* For Vim version 8.0. Last change: 2018 Apr 17 VIM REFERENCE MANUAL by Bram Moolenaar @@ -185,9 +185,40 @@ The basic steps to make changes to the code: C COMPILER *style-compiler* The minimal C compiler version supported is C89, also known as ANSI C. -Later standards don't add much and C89 is the widest supported. +Later standards, such as C99, are not widely supported, or at least not 100% +supported. Therefore we use only some of the C99 features and disallow some +(at least for now). -One restriction that this implies: no // comments, only /* comments */. +Please don't make changes everywhere to use the C99 features, it causes merge +problems for existing patches. Only use them for new and changed code. + +Comments ~ + +Traditionally Vim uses /* comments */. We intend to keep it that way, +especially for file and function headers. For new code or lines of code that +change, it is allowed to use // comments. Especially when it comes after +code: + int some_var; // single line comment useful here + +Enums ~ + +The last item in an enum may have a trailing comma. C89 didn't allow this. + +Types ~ + +"long long" is allowed and can be expected to be 64 bits. Use %lld in printf +formats. Also "long long unsigned" with %llu. + +Not to be used ~ + +These C99 features are not to be used, because not enough compilers support +them: +- Declaration after Statements (MSVC 2012 does not support it). All + declarations need to be at the start of the block. +- Variable length arrays (even in C11 this is an optional feature). +- _Bool and _Complex types. +- "inline" (it's hardly ever needed, let the optimizer do its work) +- flexible array members: Not supported by HP-UX C compiler (John Marriott) USE OF COMMON FUNCTIONS *style-functions* diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 92595690f6..9985d2579f 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -8124,15 +8124,23 @@ A jump table for the options with a short description can be found at |Q_op|. 'termsize' 'tms' string (default "") local to window {not in Vi} - Size of the |terminal| window. Format: {rows}x{columns}. + Size of the |terminal| window. Format: {rows}x{columns} or + {rows}*{columns}. - When empty the terminal gets the size from the window. - - When set (e.g., "24x80") the terminal size is not adjusted to the - window size. If the window is smaller only the top-left part is - displayed. - When rows is zero then use the height of the window. - When columns is zero then use the width of the window. - For example: "30x0" uses 30 rows with the current window width. - Using "0x0" is the same as empty. + - When set with a "x" (e.g., "24x80") the terminal size is not + adjusted to the window size. If the window is smaller only the + top-left part is displayed. + - When set with a "*" (e.g., "10*50") the terminal size follows the + window size, but will not be smaller than the specified rows and/or + columns. + - When rows is zero then use the height of the window. + - When columns is zero then use the width of the window. + - Using "0x0" or "0*0" is the same as empty. + + Examples: + "30x0" uses 30 rows and the current window width. + "20*0" uses at least 20 rows and the current window width. + "0*40" uses the current window height and at least 40 columns. Note that the command running in the terminal window may still change the size of the terminal. In that case the Vim window will be adjusted to that size, if possible. diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt index 8deba3922d..cce087f7a4 100644 --- a/runtime/doc/terminal.txt +++ b/runtime/doc/terminal.txt @@ -623,7 +623,8 @@ Starting ~ Load the plugin with this command: > packadd termdebug < *:Termdebug* -To start debugging use `:Termdebug` followed by the command name, for example: > +To start debugging use `:Termdebug` or `:TermdebugCommand`` followed by the +command name, for example: > :Termdebug vim This opens two windows: @@ -641,7 +642,8 @@ source file location will be displayed, if possible. A sign is used to highlight the current position, using highlight group debugPC. If the buffer in the current window is modified, another window will be opened -to display the current gdb position. +to display the current gdb position. You can use `:Winbar` to add a window +toolbar there. Focus the terminal of the executed program to interact with it. This works the same as any command running in a terminal window. @@ -650,12 +652,25 @@ When the debugger ends, typically by typing "quit" in the gdb window, the two opened windows are closed. Only one debugger can be active at a time. + *:TermdebugCommand* +If you want to give specific commands to the command being debugged, you can +use the `:TermdebugCommand` command followed by the command name and +additional parameters. > + :TermdebugCommand vim --clean -c ':set nu' -To attach gdb to an already running executable, or use a core file, pass extra +Both the `:Termdebug` and `:TermdebugCommand` support an optional "!" bang +argument to start the command right away, without pausing at the gdb window +(and cursor will be in the debugged window). For example: > + :TermdebugCommand! vim --clean + +To attach gdb to an already running executable or use a core file, pass extra arguments. E.g.: > :Termdebug vim core :Termdebug vim 98343 +If no argument is given, you'll end up in a gdb window, in which you need to +specify which command to run using e.g. the gdb `file` command. + Example session ~ *termdebug-example* @@ -728,18 +743,20 @@ Put focus on the gdb window to type commands there. Some common ones are: - frame N go to the Nth stack frame - continue continue execution -In the window showing the source code these commands can be used to control gdb: + *:Run* *:Arguments* +In the window showing the source code these commands can be used to control +gdb: `:Run` [args] run the program with [args] or the previous arguments `:Arguments` {args} set arguments for the next `:Run` - `:Break` set a breakpoint at the current line; a sign will be displayed - `:Clear` delete the breakpoint at the current line + *:Break* set a breakpoint at the current line; a sign will be displayed + *:Clear* delete the breakpoint at the current line - `:Step` execute the gdb "step" command - `:Over` execute the gdb "next" command (`:Next` is a Vim command) - `:Finish` execute the gdb "finish" command - `:Continue` execute the gdb "continue" command - `:Stop` interrupt the program + *:Step* execute the gdb "step" command + *:Over* execute the gdb "next" command (`:Next` is a Vim command) + *:Finish* execute the gdb "finish" command + *:Continue* execute the gdb "continue" command + *:Stop* interrupt the program If 'mouse' is set the plugin adds a window toolbar with these entries: Step `:Step` @@ -750,7 +767,7 @@ If 'mouse' is set the plugin adds a window toolbar with these entries: Eval `:Evaluate` This way you can use the mouse to perform the most common commands. You need to have the 'mouse' option set to enable mouse clicks. - + *:Winbar* You can add the window toolbar in other windows you open with: > :Winbar @@ -761,7 +778,7 @@ abandoned. Inspecting variables ~ - *termdebug-variables* + *termdebug-variables* *:Evaluate* `:Evaluate` evaluate the expression under the cursor `K` same `:Evaluate` {expr} evaluate {expr} @@ -773,9 +790,9 @@ You can usually shorten `:Evaluate` to `:Ev`. Other commands ~ *termdebug-commands* - :Gdb jump to the gdb window - :Program jump to the window with the running program - :Source jump to the window with the source code, create it if there + *:Gdb* jump to the gdb window + *:Program* jump to the window with the running program + *:Source* jump to the window with the source code, create it if there isn't one diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim index ded114a2d7..f2f0f0944d 100644 --- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim +++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim @@ -25,7 +25,8 @@ endif " The command that starts debugging, e.g. ":Termdebug vim". " To end type "quit" in the gdb window. -command -nargs=* -complete=file Termdebug call s:StartDebug() +command -nargs=* -complete=file -bang Termdebug call s:StartDebug(0, ) +command -nargs=+ -complete=file -bang TermdebugCommand call s:StartDebugCommand(0, ) " Name of the gdb command, defaults to "gdb". if !exists('termdebugger') @@ -43,7 +44,17 @@ else endif hi default debugBreakpoint term=reverse ctermbg=red guibg=red -func s:StartDebug(...) +func s:StartDebug(bang, ...) + " First argument is the command to debug, second core file or process ID. + call s:StartDebug_internal({'gdb_args': a:000, 'bang': a:bang}) +endfunc + +func s:StartDebugCommand(bang, ...) + " First argument is the command to debug, rest are run arguments. + call s:StartDebug_internal({'gdb_args': [a:1], 'proc_args': a:000[1:], 'bang': a:bang}) +endfunc + +func s:StartDebug_internal(dict) if exists('s:gdbwin') echoerr 'Terminal debugger already running' return @@ -95,7 +106,10 @@ func s:StartDebug(...) " Open a terminal window to run the debugger. " Add -quiet to avoid the intro message causing a hit-enter prompt. - let cmd = [g:termdebugger, '-quiet', '-tty', pty] + a:000 + let gdb_args = get(a:dict, 'gdb_args', []) + let proc_args = get(a:dict, 'proc_args', []) + + let cmd = [g:termdebugger, '-quiet', '-tty', pty] + gdb_args echomsg 'executing "' . join(cmd) . '"' let s:gdbbuf = term_start(cmd, { \ 'exit_cb': function('s:EndDebug'), @@ -109,6 +123,11 @@ func s:StartDebug(...) endif let s:gdbwin = win_getid(winnr()) + " Set arguments to be run + if len(proc_args) + call term_sendkeys(s:gdbbuf, 'set args ' . join(proc_args) . "\r") + endif + " Connect gdb to the communication pty, using the GDB/MI interface call term_sendkeys(s:gdbbuf, 'new-ui mi ' . commpty . "\r") @@ -182,6 +201,14 @@ func s:StartDebug(...) au BufRead * call s:BufRead() au BufUnload * call s:BufUnloaded() augroup END + + " Run the command if the bang attribute was given + " and got to the window + if get(a:dict, 'bang', 0) + call s:SendCommand('-exec-run') + call win_gotoid(s:ptywin) + endif + endfunc func s:EndDebug(job, status) diff --git a/src/auto/configure b/src/auto/configure index 6a73151d19..0c8827db80 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -4177,6 +4177,36 @@ $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the compiler can handle Vim code" >&5 +$as_echo_n "checking if the compiler can handle Vim code... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + + enum { + one, // one comment + two, // two comments + three, // three comments + }; + long long int a = 1; + long long unsigned b = 2; + printf("a %lld and a %llu", a, b); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + as_fn_error $? "compiler does not work properly - see auto/config.log" "$LINENO" 5 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-fail-if-missing argument" >&5 $as_echo_n "checking --enable-fail-if-missing argument... " >&6; } diff --git a/src/buffer.c b/src/buffer.c index dad8fdb94a..5770d55115 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -417,6 +417,8 @@ buf_hashtab_remove(buf_T *buf) hash_remove(&buf_hashtab, hi); } +static char *e_buflocked = N_("E937: Attempt to delete a buffer that is in use"); + /* * Close the link to a buffer. * "action" is used when there is no longer a window for the buffer. @@ -476,8 +478,15 @@ close_buffer( if (term_job_running(buf->b_term)) { if (wipe_buf || unload_buf) + { + if (buf->b_locked) + { + EMSG(_(e_buflocked)); + return; + } /* Wiping out or unloading a terminal buffer kills the job. */ free_terminal(buf); + } else { /* The job keeps running, hide the buffer. */ @@ -499,7 +508,7 @@ close_buffer( * halfway a command that relies on it). Unloading is allowed. */ if (buf->b_locked > 0 && (del_buf || wipe_buf)) { - EMSG(_("E937: Attempt to delete a buffer that is in use")); + EMSG(_(e_buflocked)); return; } @@ -1360,6 +1369,12 @@ do_buffer( int forward; bufref_T bufref; + if (buf->b_locked) + { + EMSG(_(e_buflocked)); + return FAIL; + } + set_bufref(&bufref, buf); /* When unloading or deleting a buffer that's already unloaded and diff --git a/src/configure.ac b/src/configure.ac index 652369b40e..6a28e55f63 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -29,6 +29,25 @@ dnl in autoconf needs it, where it uses STDC_HEADERS. AC_HEADER_STDC AC_HEADER_SYS_WAIT +dnl Check that the C99 features that Vim uses are supported: +dnl - // commands +dnl - comma after last enum item +dnl - "long long int" and "long long unsigned" +dnl - flexible array member +AC_MSG_CHECKING(if the compiler can handle Vim code) +AC_TRY_COMPILE([#include ], [ + enum { + one, // one comment + two, // two comments + three, // three comments + }; + long long int a = 1; + long long unsigned b = 2; + printf("a %lld and a %llu", a, b); + ], +AC_MSG_RESULT(yes), +AC_MSG_ERROR([compiler does not work properly - see auto/config.log])) + dnl Check for the flag that fails if stuff are missing. AC_MSG_CHECKING(--enable-fail-if-missing argument) diff --git a/src/edit.c b/src/edit.c index 34a5079c3a..82ea672314 100644 --- a/src/edit.c +++ b/src/edit.c @@ -3665,7 +3665,9 @@ ins_compl_set_original_text(char_u *str) { char_u *p; - /* Replace the original text entry. */ + /* Replace the original text entry. + * The ORIGINAL_TEXT flag is either at the first item or might possibly be + * at the last item for backward completion */ if (compl_first_match->cp_flags & ORIGINAL_TEXT) /* safety check */ { p = vim_strsave(str); @@ -3675,6 +3677,16 @@ ins_compl_set_original_text(char_u *str) compl_first_match->cp_str = p; } } + else if (compl_first_match->cp_prev != NULL + && (compl_first_match->cp_prev->cp_flags & ORIGINAL_TEXT)) + { + p = vim_strsave(str); + if (p != NULL) + { + vim_free(compl_first_match->cp_prev->cp_str); + compl_first_match->cp_prev->cp_str = p; + } + } } /* diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c index b337fa8024..4204b13451 100644 --- a/src/ex_cmds2.c +++ b/src/ex_cmds2.c @@ -3894,10 +3894,30 @@ static int APP_BOTH; static void add_pack_plugin(char_u *fname, void *cookie) { - if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)fname) == NULL) - /* directory is not yet in 'runtimepath', add it */ - if (add_pack_dir_to_rtp(fname) == FAIL) + if (cookie != &APP_LOAD) + { + char_u *buf = alloc(MAXPATHL); + char_u *p; + int found = FALSE; + + if (buf == NULL) return; + p = p_rtp; + while (*p != NUL) + { + copy_option_part(&p, buf, MAXPATHL, ","); + if (pathcmp((char *)buf, (char *)fname, -1) == 0) + { + found = TRUE; + break; + } + } + vim_free(buf); + if (!found) + /* directory is not yet in 'runtimepath', add it */ + if (add_pack_dir_to_rtp(fname) == FAIL) + return; + } if (cookie != &APP_ADD_DIR) load_pack_plugin(fname); diff --git a/src/main.c b/src/main.c index aca98971d7..9f8fc93e1b 100644 --- a/src/main.c +++ b/src/main.c @@ -1119,7 +1119,7 @@ main_loop( int cmdwin, /* TRUE when working in the command-line window */ int noexmode) /* TRUE when return on entering Ex mode */ { - oparg_T oa; /* operator arguments */ + oparg_T oa; /* operator arguments */ volatile int previous_got_int = FALSE; /* "got_int" was TRUE */ #ifdef FEAT_CONCEAL /* these are static to avoid a compiler warning */ @@ -1458,11 +1458,6 @@ getout_preserve_modified(int exitval) void getout(int exitval) { - tabpage_T *tp; - tabpage_T *next_tp; - buf_T *buf; - win_T *wp; - exiting = TRUE; #if defined(FEAT_JOB_CHANNEL) ch_log(NULL, "Exiting..."); @@ -1491,6 +1486,11 @@ getout(int exitval) if (v_dying <= 1) { + tabpage_T *tp; + tabpage_T *next_tp; + buf_T *buf; + win_T *wp; + /* Trigger BufWinLeave for all windows, but only once per buffer. */ for (tp = first_tabpage; tp != NULL; tp = next_tp) { diff --git a/src/message.c b/src/message.c index a4f09f2c80..7b45af8d1d 100644 --- a/src/message.c +++ b/src/message.c @@ -1707,8 +1707,6 @@ str2special( { c = TO_SPECIAL(str[1], str[2]); str += 2; - if (c == KS_ZERO) /* display as ^@ or */ - c = NUL; } if (IS_SPECIAL(c) || modifiers) /* special key */ special = TRUE; diff --git a/src/option.c b/src/option.c index 1bf1dbc018..5c52e631e2 100644 --- a/src/option.c +++ b/src/option.c @@ -7587,7 +7587,9 @@ did_set_string_option( if (*curwin->w_p_tms != NUL) { p = skipdigits(curwin->w_p_tms); - if (p == curwin->w_p_tms || *p != 'x' || *skipdigits(p + 1) != NUL) + if (p == curwin->w_p_tms + || (*p != 'x' && *p != '*') + || *skipdigits(p + 1) != NUL) errmsg = e_invarg; } } diff --git a/src/quickfix.c b/src/quickfix.c index c370761bf2..39e3913c09 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -1183,7 +1183,8 @@ qf_init_ext( fields.errmsglen = CMDBUFFSIZE + 1; fields.errmsg = alloc_id(fields.errmsglen, aid_qf_errmsg); fields.pattern = alloc_id(CMDBUFFSIZE + 1, aid_qf_pattern); - if (fields.namebuf == NULL || fields.errmsg == NULL || fields.pattern == NULL) + if (fields.namebuf == NULL || fields.errmsg == NULL + || fields.pattern == NULL) goto qf_init_end; if (efile != NULL && (state.fd = mch_fopen((char *)efile, "r")) == NULL) @@ -1817,7 +1818,6 @@ qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, int is_file_stack) } } - /* * pop dirbuf from the directory stack and return previous directory or NULL if * stack is empty @@ -4948,7 +4948,8 @@ enum { }; /* - * Parse text from 'di' and return the quickfix list items + * Parse text from 'di' and return the quickfix list items. + * Existing quickfix lists are not modified. */ static int qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict) @@ -5017,25 +5018,13 @@ qf_winid(qf_info_T *qi) } /* - * Return quickfix/location list details (title) as a - * dictionary. 'what' contains the details to return. If 'list_idx' is -1, - * then current list is used. Otherwise the specified list is used. + * Convert the keys in 'what' to quickfix list property flags. */ - int -qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict) + static int +qf_getprop_keys2flags(dict_T *what) { - qf_info_T *qi = &ql_info; - int status = OK; - int qf_idx; - dictitem_T *di; int flags = QF_GETLIST_NONE; - if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL) - return qf_get_list_from_lines(what, di, retdict); - - if (wp != NULL) - qi = GET_LOC_LIST(wp); - if (dict_find(what, (char_u *)"all", -1) != NULL) flags |= QF_GETLIST_ALL; @@ -5066,140 +5055,223 @@ qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict) if (dict_find(what, (char_u *)"changedtick", -1) != NULL) flags |= QF_GETLIST_TICK; - if (qi != NULL && qi->qf_listcount != 0) - { - qf_idx = qi->qf_curlist; /* default is the current list */ - if ((di = dict_find(what, (char_u *)"nr", -1)) != NULL) - { - /* Use the specified quickfix/location list */ - if (di->di_tv.v_type == VAR_NUMBER) - { - /* for zero use the current list */ - if (di->di_tv.vval.v_number != 0) - { - qf_idx = di->di_tv.vval.v_number - 1; - if (qf_idx < 0 || qf_idx >= qi->qf_listcount) - qf_idx = -1; - } - } - else if (di->di_tv.v_type == VAR_STRING - && di->di_tv.vval.v_string != NULL - && STRCMP(di->di_tv.vval.v_string, "$") == 0) - /* Get the last quickfix list number */ - qf_idx = qi->qf_listcount - 1; - else - qf_idx = -1; - flags |= QF_GETLIST_NR; - } + return flags; +} - if ((di = dict_find(what, (char_u *)"id", -1)) != NULL) +/* + * Return the quickfix list index based on 'nr' or 'id' in 'what'. + * If 'nr' and 'id' are not present in 'what' then return the current + * quickfix list index. + * If 'nr' is zero then return the current quickfix list index. + * If 'nr' is '$' then return the last quickfix list index. + * If 'id' is present then return the index of the quickfix list with that id. + * If 'id' is zero then return the quickfix list index specified by 'nr'. + * Return -1, if quickfix list is not present or if the stack is empty. + */ + static int +qf_getprop_qfidx(qf_info_T *qi, dict_T *what) +{ + int qf_idx; + dictitem_T *di; + + qf_idx = qi->qf_curlist; /* default is the current list */ + if ((di = dict_find(what, (char_u *)"nr", -1)) != NULL) + { + /* Use the specified quickfix/location list */ + if (di->di_tv.v_type == VAR_NUMBER) { - /* Look for a list with the specified id */ - if (di->di_tv.v_type == VAR_NUMBER) + /* for zero use the current list */ + if (di->di_tv.vval.v_number != 0) { - /* - * For zero, use the current list or the list specifed by 'nr' - */ - if (di->di_tv.vval.v_number != 0) - qf_idx = qf_id2nr(qi, di->di_tv.vval.v_number); - flags |= QF_GETLIST_ID; + qf_idx = di->di_tv.vval.v_number - 1; + if (qf_idx < 0 || qf_idx >= qi->qf_listcount) + qf_idx = -1; } - else - qf_idx = -1; } + else if (di->di_tv.v_type == VAR_STRING + && di->di_tv.vval.v_string != NULL + && STRCMP(di->di_tv.vval.v_string, "$") == 0) + /* Get the last quickfix list number */ + qf_idx = qi->qf_listcount - 1; + else + qf_idx = -1; } + if ((di = dict_find(what, (char_u *)"id", -1)) != NULL) + { + /* Look for a list with the specified id */ + if (di->di_tv.v_type == VAR_NUMBER) + { + /* + * For zero, use the current list or the list specified by 'nr' + */ + if (di->di_tv.vval.v_number != 0) + qf_idx = qf_id2nr(qi, di->di_tv.vval.v_number); + } + else + qf_idx = -1; + } + + return qf_idx; +} + +/* + * Return default values for quickfix list properties in retdict. + */ + static int +qf_getprop_defaults(qf_info_T *qi, int flags, dict_T *retdict) +{ + int status = OK; + + if (flags & QF_GETLIST_TITLE) + status = dict_add_nr_str(retdict, "title", 0L, (char_u *)""); + if ((status == OK) && (flags & QF_GETLIST_ITEMS)) + { + list_T *l = list_alloc(); + if (l != NULL) + status = dict_add_list(retdict, "items", l); + else + status = FAIL; + } + if ((status == OK) && (flags & QF_GETLIST_NR)) + status = dict_add_nr_str(retdict, "nr", 0L, NULL); + if ((status == OK) && (flags & QF_GETLIST_WINID)) + status = dict_add_nr_str(retdict, "winid", qf_winid(qi), NULL); + if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) + status = dict_add_nr_str(retdict, "context", 0L, (char_u *)""); + if ((status == OK) && (flags & QF_GETLIST_ID)) + status = dict_add_nr_str(retdict, "id", 0L, NULL); + if ((status == OK) && (flags & QF_GETLIST_IDX)) + status = dict_add_nr_str(retdict, "idx", 0L, NULL); + if ((status == OK) && (flags & QF_GETLIST_SIZE)) + status = dict_add_nr_str(retdict, "size", 0L, NULL); + if ((status == OK) && (flags & QF_GETLIST_TICK)) + status = dict_add_nr_str(retdict, "changedtick", 0L, NULL); + + return status; +} + +/* + * Return the quickfix list title as 'title' in retdict + */ + static int +qf_getprop_title(qf_info_T *qi, int qf_idx, dict_T *retdict) +{ + char_u *t; + + t = qi->qf_lists[qf_idx].qf_title; + if (t == NULL) + t = (char_u *)""; + return dict_add_nr_str(retdict, "title", 0L, t); +} + +/* + * Return the quickfix list items/entries as 'items' in retdict + */ + static int +qf_getprop_items(qf_info_T *qi, int qf_idx, dict_T *retdict) +{ + int status = OK; + list_T *l = list_alloc(); + if (l != NULL) + { + (void)get_errorlist(qi, NULL, qf_idx, l); + dict_add_list(retdict, "items", l); + } + else + status = FAIL; + + return status; +} + +/* + * Return the quickfix list context (if any) as 'context' in retdict. + */ + static int +qf_getprop_ctx(qf_info_T *qi, int qf_idx, dict_T *retdict) +{ + int status; + dictitem_T *di; + + if (qi->qf_lists[qf_idx].qf_ctx != NULL) + { + di = dictitem_alloc((char_u *)"context"); + if (di != NULL) + { + copy_tv(qi->qf_lists[qf_idx].qf_ctx, &di->di_tv); + status = dict_add(retdict, di); + if (status == FAIL) + dictitem_free(di); + } + else + status = FAIL; + } + else + status = dict_add_nr_str(retdict, "context", 0L, (char_u *)""); + + return status; +} + +/* + * Return the quickfix list index as 'idx' in retdict + */ + static int +qf_getprop_idx(qf_info_T *qi, int qf_idx, dict_T *retdict) +{ + int idx = qi->qf_lists[qf_idx].qf_index; + if (qi->qf_lists[qf_idx].qf_count == 0) + /* For empty lists, qf_index is set to 1 */ + idx = 0; + return dict_add_nr_str(retdict, "idx", idx, NULL); +} + +/* + * Return quickfix/location list details (title) as a + * dictionary. 'what' contains the details to return. If 'list_idx' is -1, + * then current list is used. Otherwise the specified list is used. + */ + int +qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict) +{ + qf_info_T *qi = &ql_info; + int status = OK; + int qf_idx; + dictitem_T *di; + int flags = QF_GETLIST_NONE; + + if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL) + return qf_get_list_from_lines(what, di, retdict); + + if (wp != NULL) + qi = GET_LOC_LIST(wp); + + flags = qf_getprop_keys2flags(what); + + if (qi != NULL && qi->qf_listcount != 0) + qf_idx = qf_getprop_qfidx(qi, what); + /* List is not present or is empty */ if (qi == NULL || qi->qf_listcount == 0 || qf_idx == -1) - { - if (flags & QF_GETLIST_TITLE) - status = dict_add_nr_str(retdict, "title", 0L, (char_u *)""); - if ((status == OK) && (flags & QF_GETLIST_ITEMS)) - { - list_T *l = list_alloc(); - if (l != NULL) - status = dict_add_list(retdict, "items", l); - else - status = FAIL; - } - if ((status == OK) && (flags & QF_GETLIST_NR)) - status = dict_add_nr_str(retdict, "nr", 0L, NULL); - if ((status == OK) && (flags & QF_GETLIST_WINID)) - status = dict_add_nr_str(retdict, "winid", qf_winid(qi), NULL); - if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) - status = dict_add_nr_str(retdict, "context", 0L, (char_u *)""); - if ((status == OK) && (flags & QF_GETLIST_ID)) - status = dict_add_nr_str(retdict, "id", 0L, NULL); - if ((status == OK) && (flags & QF_GETLIST_IDX)) - status = dict_add_nr_str(retdict, "idx", 0L, NULL); - if ((status == OK) && (flags & QF_GETLIST_SIZE)) - status = dict_add_nr_str(retdict, "size", 0L, NULL); - if ((status == OK) && (flags & QF_GETLIST_TICK)) - status = dict_add_nr_str(retdict, "changedtick", 0L, NULL); - - return status; - } + return qf_getprop_defaults(qi, flags, retdict); if (flags & QF_GETLIST_TITLE) - { - char_u *t; - t = qi->qf_lists[qf_idx].qf_title; - if (t == NULL) - t = (char_u *)""; - status = dict_add_nr_str(retdict, "title", 0L, t); - } + status = qf_getprop_title(qi, qf_idx, retdict); if ((status == OK) && (flags & QF_GETLIST_NR)) status = dict_add_nr_str(retdict, "nr", qf_idx + 1, NULL); if ((status == OK) && (flags & QF_GETLIST_WINID)) status = dict_add_nr_str(retdict, "winid", qf_winid(qi), NULL); if ((status == OK) && (flags & QF_GETLIST_ITEMS)) - { - list_T *l = list_alloc(); - if (l != NULL) - { - (void)get_errorlist(qi, NULL, qf_idx, l); - dict_add_list(retdict, "items", l); - } - else - status = FAIL; - } - + status = qf_getprop_items(qi, qf_idx, retdict); if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) - { - if (qi->qf_lists[qf_idx].qf_ctx != NULL) - { - di = dictitem_alloc((char_u *)"context"); - if (di != NULL) - { - copy_tv(qi->qf_lists[qf_idx].qf_ctx, &di->di_tv); - status = dict_add(retdict, di); - if (status == FAIL) - dictitem_free(di); - } - else - status = FAIL; - } - else - status = dict_add_nr_str(retdict, "context", 0L, (char_u *)""); - } - + status = qf_getprop_ctx(qi, qf_idx, retdict); if ((status == OK) && (flags & QF_GETLIST_ID)) status = dict_add_nr_str(retdict, "id", qi->qf_lists[qf_idx].qf_id, NULL); - if ((status == OK) && (flags & QF_GETLIST_IDX)) - { - int idx = qi->qf_lists[qf_idx].qf_index; - if (qi->qf_lists[qf_idx].qf_count == 0) - /* For empty lists, qf_index is set to 1 */ - idx = 0; - status = dict_add_nr_str(retdict, "idx", idx, NULL); - } - + status = qf_getprop_idx(qi, qf_idx, retdict); if ((status == OK) && (flags & QF_GETLIST_SIZE)) status = dict_add_nr_str(retdict, "size", qi->qf_lists[qf_idx].qf_count, NULL); - if ((status == OK) && (flags & QF_GETLIST_TICK)) status = dict_add_nr_str(retdict, "changedtick", qi->qf_lists[qf_idx].qf_changedtick, NULL); @@ -5609,7 +5681,7 @@ mark_quickfix_ctx(qf_info_T *qi, int copyID) /* * Mark the context of the quickfix list and the location lists (if present) as - * "in use". So that garabage collection doesn't free the context. + * "in use". So that garbage collection doesn't free the context. */ int set_ref_in_quickfix(int copyID) diff --git a/src/structs.h b/src/structs.h index ee423e0178..469be3fac1 100644 --- a/src/structs.h +++ b/src/structs.h @@ -827,9 +827,9 @@ struct msglist */ typedef enum { - ET_USER, /* exception caused by ":throw" command */ - ET_ERROR, /* error exception */ - ET_INTERRUPT /* interrupt exception triggered by Ctrl-C */ + ET_USER, // exception caused by ":throw" command + ET_ERROR, // error exception + ET_INTERRUPT, // interrupt exception triggered by Ctrl-C } except_type_T; /* @@ -1190,16 +1190,16 @@ typedef struct channel_S channel_T; typedef enum { VAR_UNKNOWN = 0, - VAR_NUMBER, /* "v_number" is used */ - VAR_STRING, /* "v_string" is used */ - VAR_FUNC, /* "v_string" is function name */ - VAR_PARTIAL, /* "v_partial" is used */ - VAR_LIST, /* "v_list" is used */ - VAR_DICT, /* "v_dict" is used */ - VAR_FLOAT, /* "v_float" is used */ - VAR_SPECIAL, /* "v_number" is used */ - VAR_JOB, /* "v_job" is used */ - VAR_CHANNEL /* "v_channel" is used */ + VAR_NUMBER, // "v_number" is used + VAR_STRING, // "v_string" is used + VAR_FUNC, // "v_string" is function name + VAR_PARTIAL, // "v_partial" is used + VAR_LIST, // "v_list" is used + VAR_DICT, // "v_dict" is used + VAR_FLOAT, // "v_float" is used + VAR_SPECIAL, // "v_number" is used + VAR_JOB, // "v_job" is used + VAR_CHANNEL, // "v_channel" is used } vartype_T; /* @@ -1456,8 +1456,8 @@ typedef enum { JOB_FAILED, JOB_STARTED, - JOB_ENDED, /* detected job done */ - JOB_FINISHED /* job done and cleanup done */ + JOB_ENDED, // detected job done + JOB_FINISHED, // job done and cleanup done } jobstatus_T; /* @@ -1531,11 +1531,11 @@ typedef enum MODE_NL = 0, MODE_RAW, MODE_JSON, - MODE_JS + MODE_JS, } ch_mode_T; typedef enum { - JIO_PIPE, /* default */ + JIO_PIPE, // default JIO_NULL, JIO_FILE, JIO_BUFFER, @@ -1557,7 +1557,7 @@ typedef enum { PART_IN, # define CH_IN_FD CH_PART_FD(PART_IN) #endif - PART_COUNT + PART_COUNT, } ch_part_T; #define INVALID_FD (-1) @@ -3271,15 +3271,15 @@ typedef struct { */ typedef enum { - TYPE_UNKNOWN = 0 - , TYPE_EQUAL /* == */ - , TYPE_NEQUAL /* != */ - , TYPE_GREATER /* > */ - , TYPE_GEQUAL /* >= */ - , TYPE_SMALLER /* < */ - , TYPE_SEQUAL /* <= */ - , TYPE_MATCH /* =~ */ - , TYPE_NOMATCH /* !~ */ + TYPE_UNKNOWN = 0, + TYPE_EQUAL, // == + TYPE_NEQUAL, // != + TYPE_GREATER, // > + TYPE_GEQUAL, // >= + TYPE_SMALLER, // < + TYPE_SEQUAL, // <= + TYPE_MATCH, // =~ + TYPE_NOMATCH, // !~ } exptype_T; /* diff --git a/src/terminal.c b/src/terminal.c index 8faa0cc85e..b70670ce47 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -42,26 +42,23 @@ * redirection. Probably in call to channel_set_pipes(). * - Win32: Redirecting output does not work, Test_terminal_redir_file() * is disabled. - * - Copy text in the vterm to the Vim buffer once in a while, so that - * completion works. * - When starting terminal window with shell in terminal, then using :gui to * switch to GUI, shell stops working. Scrollback seems wrong, command * running in shell is still running. - * - in GUI vertical split causes problems. Cursor is flickering. (Hirohito - * Higashi, 2017 Sep 19) - * - after resizing windows overlap. (Boris Staletic, #2164) - * - cursor blinks in terminal on widows with a timer. (xtal8, #2142) - * - Termdebug does not work when Vim build with mzscheme. gdb hangs. - * - After executing a shell command the status line isn't redraw. - * - add test for giving error for invalid 'termsize' value. - * - support minimal size when 'termsize' is "rows*cols". - * - support minimal size when 'termsize' is empty? * - GUI: when using tabs, focus in terminal, click on tab does not work. + * - handle_moverect() scrolls one line at a time. Postpone scrolling, count + * the number of lines, until a redraw happens. Then if scrolling many lines + * a redraw is faster. + * - Copy text in the vterm to the Vim buffer once in a while, so that + * completion works. * - Redrawing is slow with Athena and Motif. Also other GUI? (Ramel Eshed) * - For the GUI fill termios with default values, perhaps like pangoterm: * http://bazaar.launchpad.net/~leonerd/pangoterm/trunk/view/head:/main.c#L134 * - When 'encoding' is not utf-8, or the job is using another encoding, setup * conversions. + * - Termdebug does not work when Vim build with mzscheme: gdb hangs just after + * "run". Everything else works, including communication channel. Not + * initializing mzscheme avoid the problem, thus it's not some #ifdef. */ #include "vim.h" @@ -133,9 +130,6 @@ struct terminal_S { /* last known vterm size */ int tl_rows; int tl_cols; - /* vterm size does not follow window size */ - int tl_rows_fixed; - int tl_cols_fixed; char_u *tl_title; /* NULL or allocated */ char_u *tl_status_text; /* NULL or allocated */ @@ -207,9 +201,38 @@ static int desired_cursor_blink = -1; * 1. Generic code for all systems. */ +/* + * Parse 'termsize' and set "rows" and "cols" for the terminal size in the + * current window. + * Sets "rows" and/or "cols" to zero when it should follow the window size. + * Return TRUE if the size is the minimum size: "24*80". + */ + static int +parse_termsize(win_T *wp, int *rows, int *cols) +{ + int minsize = FALSE; + + *rows = 0; + *cols = 0; + + if (*wp->w_p_tms != NUL) + { + char_u *p = vim_strchr(wp->w_p_tms, 'x'); + + /* Syntax of value was already checked when it's set. */ + if (p == NULL) + { + minsize = TRUE; + p = vim_strchr(wp->w_p_tms, '*'); + } + *rows = atoi((char *)wp->w_p_tms); + *cols = atoi((char *)p + 1); + } + return minsize; +} + /* * Determine the terminal size from 'termsize' and the current window. - * Assumes term->tl_rows and term->tl_cols are zero. */ static void set_term_and_win_size(term_T *term) @@ -224,27 +247,21 @@ set_term_and_win_size(term_T *term) return; } #endif - if (*curwin->w_p_tms != NUL) + if (parse_termsize(curwin, &term->tl_rows, &term->tl_cols)) { - char_u *p = vim_strchr(curwin->w_p_tms, 'x') + 1; - - term->tl_rows = atoi((char *)curwin->w_p_tms); - term->tl_cols = atoi((char *)p); + if (term->tl_rows != 0) + term->tl_rows = MAX(term->tl_rows, curwin->w_height); + if (term->tl_cols != 0) + term->tl_cols = MAX(term->tl_cols, curwin->w_width); } if (term->tl_rows == 0) term->tl_rows = curwin->w_height; else - { win_setheight_win(term->tl_rows, curwin); - term->tl_rows_fixed = TRUE; - } if (term->tl_cols == 0) term->tl_cols = curwin->w_width; else - { win_setwidth_win(term->tl_cols, curwin); - term->tl_cols_fixed = TRUE; - } } /* @@ -2858,6 +2875,10 @@ term_update_window(win_T *wp) VTermScreen *screen; VTermState *state; VTermPos pos; + int rows, cols; + int newrows, newcols; + int minsize; + win_T *twp; if (term == NULL || term->tl_vterm == NULL || term->tl_normal_mode) return FAIL; @@ -2876,31 +2897,32 @@ term_update_window(win_T *wp) * If the window was resized a redraw will be triggered and we get here. * Adjust the size of the vterm unless 'termsize' specifies a fixed size. */ - if ((!term->tl_rows_fixed && term->tl_rows != wp->w_height) - || (!term->tl_cols_fixed && term->tl_cols != wp->w_width)) - { - int rows = term->tl_rows_fixed ? term->tl_rows : wp->w_height; - int cols = term->tl_cols_fixed ? term->tl_cols : wp->w_width; - win_T *twp; + minsize = parse_termsize(wp, &rows, &cols); - FOR_ALL_WINDOWS(twp) + newrows = 99999; + newcols = 99999; + FOR_ALL_WINDOWS(twp) + { + /* When more than one window shows the same terminal, use the + * smallest size. */ + if (twp->w_buffer == term->tl_buffer) { - /* When more than one window shows the same terminal, use the - * smallest size. */ - if (twp->w_buffer == term->tl_buffer) - { - if (!term->tl_rows_fixed && rows > twp->w_height) - rows = twp->w_height; - if (!term->tl_cols_fixed && cols > twp->w_width) - cols = twp->w_width; - } + newrows = MIN(newrows, twp->w_height); + newcols = MIN(newcols, twp->w_width); } + } + newrows = rows == 0 ? newrows : minsize ? MAX(rows, newrows) : rows; + newcols = cols == 0 ? newcols : minsize ? MAX(cols, newcols) : cols; + + if (term->tl_rows != newrows || term->tl_cols != newcols) + { + term->tl_vterm_size_changed = TRUE; - vterm_set_size(vterm, rows, cols); + vterm_set_size(vterm, newrows, newcols); ch_log(term->tl_job->jv_channel, "Resizing terminal to %d lines", - rows); - term_report_winsize(term, rows, cols); + newrows); + term_report_winsize(term, newrows, newcols); } /* The cursor may have been moved when resizing. */ @@ -3419,6 +3441,10 @@ parse_osc(const char *command, size_t cmdlen, void *user) { char_u *cmd = get_tv_string(&item->li_tv); + /* Make sure an invoked command doesn't delete the buffer (and the + * terminal) under our fingers. */ + ++term->tl_buffer->b_locked; + item = item->li_next; if (item == NULL) ch_log(channel, "Missing argument for %s", cmd); @@ -3428,6 +3454,7 @@ parse_osc(const char *command, size_t cmdlen, void *user) handle_call_command(term, channel, item); else ch_log(channel, "Invalid command received: %s", cmd); + --term->tl_buffer->b_locked; } } else diff --git a/src/testdir/screendump.vim b/src/testdir/screendump.vim index 9812e7e6de..af9e371488 100644 --- a/src/testdir/screendump.vim +++ b/src/testdir/screendump.vim @@ -57,7 +57,12 @@ func RunVimInTerminal(arguments, options) " Add -v to have gvim run in the terminal (if possible) let cmd .= ' -v ' . a:arguments let buf = term_start(cmd, {'curwin': 1, 'term_rows': rows, 'term_cols': cols}) - call assert_equal([rows, cols], term_getsize(buf)) + if &termsize == '' + call assert_equal([rows, cols], term_getsize(buf)) + else + let rows = term_getsize(buf)[0] + let cols = term_getsize(buf)[1] + endif " Wait for "All" of the ruler in the status line to be shown. " This can be quite slow (e.g. when using valgrind). diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index e5f14bad56..daaea86b2a 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -119,7 +119,9 @@ func Test_autocmd_bufunload_avoiding_SEGV_01() exe 'autocmd BufUnload ' . (lastbuf + 1) . 'bwipeout!' augroup END - call assert_fails('edit bb.txt', 'E937:') + " Todo: check for E937 generated first + " call assert_fails('edit bb.txt', 'E937:') + call assert_fails('edit bb.txt', 'E517:') autocmd! test_autocmd_bufunload augroup! test_autocmd_bufunload @@ -316,7 +318,7 @@ func Test_three_windows() e Xtestje2 sp Xtestje1 call assert_fails('e', 'E937:') - call assert_equal('Xtestje2', expand('%')) + call assert_equal('Xtestje1', expand('%')) " Test changing buffers in a BufWipeout autocommand. If this goes wrong " there are ml_line errors and/or a Crash. @@ -338,7 +340,6 @@ func Test_three_windows() au! enew - bwipe! Xtestje1 call delete('Xtestje1') call delete('Xtestje2') call delete('Xtestje3') @@ -1181,7 +1182,9 @@ endfunc func Test_nocatch_wipe_all_buffers() " Real nasty autocommand: wipe all buffers on any event. au * * bwipe * - call assert_fails('next x', 'E93') + " Get E93 first? + " call assert_fails('next x', 'E93:') + call assert_fails('next x', 'E517:') bwipe au! endfunc diff --git a/src/testdir/test_packadd.vim b/src/testdir/test_packadd.vim index 889d77f414..64bd8d2b23 100644 --- a/src/testdir/test_packadd.vim +++ b/src/testdir/test_packadd.vim @@ -40,6 +40,15 @@ func Test_packadd() call assert_match('/testdir/Xdir/pack/mine/opt/mytest\($\|,\)', &rtp) call assert_match('/testdir/Xdir/pack/mine/opt/mytest/after$', &rtp) + " NOTE: '/.../opt/myte' forwardly matches with '/.../opt/mytest' + call mkdir(fnamemodify(s:plugdir, ':h') . '/myte', 'p') + let rtp = &rtp + packadd myte + + " Check the path of 'myte' is added + call assert_true(len(&rtp) > len(rtp)) + call assert_match('/testdir/Xdir/pack/mine/opt/myte\($\|,\)', &rtp) + " Check exception call assert_fails("packadd directorynotfound", 'E919:') call assert_fails("packadd", 'E471:') diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim index 8294febe6a..ed31985856 100644 --- a/src/testdir/test_popup.vim +++ b/src/testdir/test_popup.vim @@ -814,5 +814,24 @@ func Test_popup_command() call delete('Xtest') endfunc +func Test_popup_complete_backwards() + new + call setline(1, ['Post', 'Port', 'Po']) + let expected=['Post', 'Port', 'Port'] + call cursor(3,2) + call feedkeys("A\". repeat("\", 3). "rt\", 'tx') + call assert_equal(expected, getline(1,'$')) + bwipe! +endfunc + +func Test_popup_complete_backwards_ctrl_p() + new + call setline(1, ['Post', 'Port', 'Po']) + let expected=['Post', 'Port', 'Port'] + call cursor(3,2) + call feedkeys("A\\rt\", 'tx') + call assert_equal(expected, getline(1,'$')) + bwipe! +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 8fd1b239cf..a8841f2389 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -1297,6 +1297,30 @@ func Test_terminal_api_call_fails() call delete('Xlog') endfunc +let s:caught_e937 = 0 + +func Tapi_Delete(bufnum, arg) + try + execute 'bdelete!' a:bufnum + catch /E937:/ + let s:caught_e937 = 1 + endtry +endfunc + +func Test_terminal_api_call_fail_delete() + if !CanRunVimInTerminal() + return + endif + + call WriteApiCall('Tapi_Delete') + let buf = RunVimInTerminal('-S Xscript', {}) + call WaitFor({-> s:caught_e937 == 1}) + + call StopVimInTerminal(buf) + call delete('Xscript') + call ch_logfile('', '') +endfunc + func Test_terminal_ansicolors_default() let colors = [ \ '#000000', '#e00000', @@ -1366,3 +1390,102 @@ func Test_terminal_ansicolors_func() call term_wait(buf) exe buf . 'bwipe' endfunc + +func Test_terminal_termsize_option_fixed() + if !CanRunVimInTerminal() + return + endif + set termsize=6x40 + let text = [] + for n in range(10) + call add(text, repeat(n, 50)) + endfor + call writefile(text, 'Xwinsize') + let buf = RunVimInTerminal('Xwinsize', {}) + let win = bufwinid(buf) + call assert_equal([6, 40], term_getsize(buf)) + call assert_equal(6, winheight(win)) + call assert_equal(40, winwidth(win)) + + " resizing the window doesn't resize the terminal. + resize 10 + vertical resize 60 + call assert_equal([6, 40], term_getsize(buf)) + call assert_equal(10, winheight(win)) + call assert_equal(60, winwidth(win)) + + call StopVimInTerminal(buf) + call delete('Xwinsize') + + call assert_fails('set termsize=40', 'E474') + call assert_fails('set termsize=10+40', 'E474') + call assert_fails('set termsize=abc', 'E474') + + set termsize= +endfunc + +func Test_terminal_termsize_option_zero() + set termsize=0x0 + let buf = Run_shell_in_terminal({}) + let win = bufwinid(buf) + call assert_equal([winheight(win), winwidth(win)], term_getsize(buf)) + call Stop_shell_in_terminal(buf) + call term_wait(buf) + exe buf . 'bwipe' + + set termsize=7x0 + let buf = Run_shell_in_terminal({}) + let win = bufwinid(buf) + call assert_equal([7, winwidth(win)], term_getsize(buf)) + call Stop_shell_in_terminal(buf) + call term_wait(buf) + exe buf . 'bwipe' + + set termsize=0x33 + let buf = Run_shell_in_terminal({}) + let win = bufwinid(buf) + call assert_equal([winheight(win), 33], term_getsize(buf)) + call Stop_shell_in_terminal(buf) + call term_wait(buf) + exe buf . 'bwipe' + + set termsize= +endfunc + +func Test_terminal_termsize_mininmum() + set termsize=10*50 + vsplit + let buf = Run_shell_in_terminal({}) + let win = bufwinid(buf) + call assert_inrange(10, 1000, winheight(win)) + call assert_inrange(50, 1000, winwidth(win)) + call assert_equal([winheight(win), winwidth(win)], term_getsize(buf)) + + resize 15 + vertical resize 60 + redraw + call assert_equal([15, 60], term_getsize(buf)) + call assert_equal(15, winheight(win)) + call assert_equal(60, winwidth(win)) + + resize 7 + vertical resize 30 + redraw + call assert_equal([10, 50], term_getsize(buf)) + call assert_equal(7, winheight(win)) + call assert_equal(30, winwidth(win)) + + call Stop_shell_in_terminal(buf) + call term_wait(buf) + exe buf . 'bwipe' + + set termsize=0*0 + let buf = Run_shell_in_terminal({}) + let win = bufwinid(buf) + call assert_equal([winheight(win), winwidth(win)], term_getsize(buf)) + call Stop_shell_in_terminal(buf) + call term_wait(buf) + exe buf . 'bwipe' + + set termsize= +endfunc diff --git a/src/version.c b/src/version.c index 692098fb45..d76787129a 100644 --- a/src/version.c +++ b/src/version.c @@ -777,6 +777,36 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1735, +/**/ + 1734, +/**/ + 1733, +/**/ + 1732, +/**/ + 1731, +/**/ + 1730, +/**/ + 1729, +/**/ + 1728, +/**/ + 1727, +/**/ + 1726, +/**/ + 1725, +/**/ + 1724, +/**/ + 1723, +/**/ + 1722, +/**/ + 1721, /**/ 1720, /**/