Merge remote-tracking branch 'vim/master'

This commit is contained in:
Kazuki Sakamoto
2018-04-18 20:58:21 -07:00
21 changed files with 717 additions and 250 deletions
+34 -3
View File
@@ -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*
+16 -8
View File
@@ -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.
+33 -16
View File
@@ -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
+30 -3
View File
@@ -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(<f-args>)
command -nargs=* -complete=file -bang Termdebug call s:StartDebug(<bang>0, <f-args>)
command -nargs=+ -complete=file -bang TermdebugCommand call s:StartDebugCommand(<bang>0, <f-args>)
" 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)
+30
View File
@@ -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 <stdio.h>
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; }
+16 -1
View File
@@ -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
+19
View File
@@ -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 <stdio.h>], [
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)
+13 -1
View File
@@ -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;
}
}
}
/*
+23 -3
View File
@@ -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);
+6 -6
View File
@@ -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)
{
-2
View File
@@ -1707,8 +1707,6 @@ str2special(
{
c = TO_SPECIAL(str[1], str[2]);
str += 2;
if (c == KS_ZERO) /* display <Nul> as ^@ or <Nul> */
c = NUL;
}
if (IS_SPECIAL(c) || modifiers) /* special key */
special = TRUE;
+3 -1
View File
@@ -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;
}
}
+201 -129
View File
@@ -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)
+27 -27
View File
@@ -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;
/*
+72 -45
View File
@@ -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
+6 -1
View File
@@ -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).
+7 -4
View File
@@ -119,7 +119,9 @@ func Test_autocmd_bufunload_avoiding_SEGV_01()
exe 'autocmd BufUnload <buffer> ' . (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
+9
View File
@@ -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:')
+19
View File
@@ -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\<C-X>". repeat("\<C-P>", 3). "rt\<cr>", '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\<C-P>\<C-N>rt\<cr>", 'tx')
call assert_equal(expected, getline(1,'$'))
bwipe!
endfunc
" vim: shiftwidth=2 sts=2 expandtab
+123
View File
@@ -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
+30
View File
@@ -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,
/**/