Merge #9906 from janlazo/vim-8.0.0647

vim-patch:8.0.{647,768,797,1085,1092,1107,1133,1408}
This commit is contained in:
Justin M. Keyes
2019-04-24 11:23:32 +02:00
committed by GitHub
10 changed files with 346 additions and 88 deletions

View File

@@ -4528,10 +4528,14 @@ A jump table for the options with a short description can be found at |Q_op|.
'redrawtime' 'rdt' number (default 2000) 'redrawtime' 'rdt' number (default 2000)
global global
Time in milliseconds for redrawing the display. Applies to Time in milliseconds for redrawing the display. Applies to
'hlsearch', 'inccommand' and |:match| highlighting. 'hlsearch', 'inccommand', |:match| highlighting and syntax
highlighting.
When redrawing takes more than this many milliseconds no further When redrawing takes more than this many milliseconds no further
matches will be highlighted. This is used to avoid that Vim hangs matches will be highlighted.
when using a very complicated pattern. For syntax highlighting the time applies per window. When over the
limit syntax highlighting is disabled until |CTRL-L| is used.
This is used to avoid that Vim hangs when using a very complicated
pattern.
*'regexpengine'* *'re'* *'regexpengine'* *'re'*
'regexpengine' 're' number (default 0) 'regexpengine' 're' number (default 0)

View File

@@ -25,32 +25,44 @@ endif
command -nargs=* -complete=file Termdebug call s:StartDebug(<q-args>) command -nargs=* -complete=file Termdebug call s:StartDebug(<q-args>)
" Name of the gdb command, defaults to "gdb". " Name of the gdb command, defaults to "gdb".
if !exists('debugger') if !exists('termdebugger')
let debugger = 'gdb' let termdebugger = 'gdb'
endif endif
" Sign used to highlight the line where the program has stopped.
sign define debugPC linehl=debugPC
if &background == 'light'
hi debugPC term=reverse ctermbg=lightblue guibg=lightblue
else
hi debugPC term=reverse ctermbg=darkblue guibg=darkblue
endif
let s:pc_id = 12 let s:pc_id = 12
let s:break_id = 13
if &background == 'light'
hi default debugPC term=reverse ctermbg=lightblue guibg=lightblue
else
hi default debugPC term=reverse ctermbg=darkblue guibg=darkblue
endif
hi default debugBreakpoint term=reverse ctermbg=red guibg=red
func s:StartDebug(cmd) func s:StartDebug(cmd)
let s:startwin = win_getid(winnr()) let s:startwin = win_getid(winnr())
let s:startsigncolumn = &signcolumn let s:startsigncolumn = &signcolumn
if exists('g:termdebug_wide') && &columns < g:termdebug_wide
let s:save_columns = &columns
let &columns = g:termdebug_wide
let vertical = 1
else
let s:save_columns = 0
let vertical = 0
endif
" Open a terminal window without a job, to run the debugged program " Open a terminal window without a job, to run the debugged program
let s:ptybuf = term_start('NONE', { let s:ptybuf = term_start('NONE', {
\ 'term_name': 'gdb program', \ 'term_name': 'gdb program',
\ 'vertical': vertical,
\ }) \ })
if s:ptybuf == 0 if s:ptybuf == 0
echoerr 'Failed to open the program terminal window' echoerr 'Failed to open the program terminal window'
return return
endif endif
let pty = job_info(term_getjob(s:ptybuf))['tty_out'] let pty = job_info(term_getjob(s:ptybuf))['tty_out']
let s:ptywin = win_getid(winnr())
" Create a hidden terminal window to communicate with gdb " Create a hidden terminal window to communicate with gdb
let s:commbuf = term_start('NONE', { let s:commbuf = term_start('NONE', {
@@ -66,7 +78,7 @@ func s:StartDebug(cmd)
let commpty = job_info(term_getjob(s:commbuf))['tty_out'] let commpty = job_info(term_getjob(s:commbuf))['tty_out']
" Open a terminal window to run the debugger. " Open a terminal window to run the debugger.
let cmd = [g:debugger, '-tty', pty, a:cmd] let cmd = [g:termdebugger, '-tty', pty, a:cmd]
echomsg 'executing "' . join(cmd) . '"' echomsg 'executing "' . join(cmd) . '"'
let gdbbuf = term_start(cmd, { let gdbbuf = term_start(cmd, {
\ 'exit_cb': function('s:EndDebug'), \ 'exit_cb': function('s:EndDebug'),
@@ -78,15 +90,41 @@ func s:StartDebug(cmd)
exe 'bwipe! ' . s:commbuf exe 'bwipe! ' . s:commbuf
return return
endif endif
let s:gdbwin = win_getid(winnr())
" Connect gdb to the communication pty, using the GDB/MI interface " Connect gdb to the communication pty, using the GDB/MI interface
call term_sendkeys(gdbbuf, 'new-ui mi ' . commpty . "\r") call term_sendkeys(gdbbuf, 'new-ui mi ' . commpty . "\r")
" Sign used to highlight the line where the program has stopped.
" There can be only one.
sign define debugPC linehl=debugPC
" Sign used to indicate a breakpoint.
" Can be used multiple times.
sign define debugBreakpoint text=>> texthl=debugBreakpoint
" Install debugger commands in the text window.
call win_gotoid(s:startwin)
call s:InstallCommands()
call win_gotoid(s:gdbwin)
let s:breakpoints = {}
endfunc endfunc
func s:EndDebug(job, status) func s:EndDebug(job, status)
exe 'bwipe! ' . s:ptybuf exe 'bwipe! ' . s:ptybuf
exe 'bwipe! ' . s:commbuf exe 'bwipe! ' . s:commbuf
call setwinvar(s:startwin, '&signcolumn', s:startsigncolumn)
let curwinid = win_getid(winnr())
call win_gotoid(s:startwin)
let &signcolumn = s:startsigncolumn
call s:DeleteCommands()
call win_gotoid(curwinid)
if s:save_columns > 0
let &columns = s:save_columns
endif
endfunc endfunc
" Handle a message received from gdb on the GDB/MI interface. " Handle a message received from gdb on the GDB/MI interface.
@@ -100,34 +138,175 @@ func s:CommOutput(chan, msg)
endif endif
if msg != '' if msg != ''
if msg =~ '^\*\(stopped\|running\)' if msg =~ '^\*\(stopped\|running\)'
let wid = win_getid(winnr()) call s:HandleCursor(msg)
elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,'
if win_gotoid(s:startwin) call s:HandleNewBreakpoint(msg)
if msg =~ '^\*stopped' elseif msg =~ '^=breakpoint-deleted,'
" TODO: proper parsing call s:HandleBreakpointDelete(msg)
let fname = substitute(msg, '.*fullname="\([^"]*\)".*', '\1', '') elseif msg =~ '^\^done,value='
let lnum = substitute(msg, '.*line="\([^"]*\)".*', '\1', '') call s:HandleEvaluate(msg)
if lnum =~ '^[0-9]*$' elseif msg =~ '^\^error,msg='
if expand('%:h') != fname call s:HandleError(msg)
if &modified
" TODO: find existing window
exe 'split ' . fnameescape(fname)
let s:startwin = win_getid(winnr())
else
exe 'edit ' . fnameescape(fname)
endif
endif
exe lnum
exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fnameescape(fname)
setlocal signcolumn=yes
endif
else
exe 'sign unplace ' . s:pc_id
endif
call win_gotoid(wid)
endif
endif endif
endif endif
endfor endfor
endfunc endfunc
" Install commands in the current window to control the debugger.
func s:InstallCommands()
command Break call s:SetBreakpoint()
command Delete call s:DeleteBreakpoint()
command Step call s:SendCommand('-exec-step')
command Over call s:SendCommand('-exec-next')
command Finish call s:SendCommand('-exec-finish')
command Continue call s:SendCommand('-exec-continue')
command -range -nargs=* Evaluate call s:Evaluate(<range>, <q-args>)
command Gdb call win_gotoid(s:gdbwin)
command Program call win_gotoid(s:ptywin)
" TODO: can the K mapping be restored?
nnoremap K :Evaluate<CR>
endfunc
" Delete installed debugger commands in the current window.
func s:DeleteCommands()
delcommand Break
delcommand Delete
delcommand Step
delcommand Over
delcommand Finish
delcommand Continue
delcommand Evaluate
delcommand Gdb
delcommand Program
nunmap K
exe 'sign unplace ' . s:pc_id
for key in keys(s:breakpoints)
exe 'sign unplace ' . (s:break_id + key)
endfor
sign undefine debugPC
sign undefine debugBreakpoint
unlet s:breakpoints
endfunc
" :Break - Set a breakpoint at the cursor position.
func s:SetBreakpoint()
call term_sendkeys(s:commbuf, '-break-insert --source '
\ . fnameescape(expand('%:p')) . ' --line ' . line('.') . "\r")
endfunc
" :Delete - Delete a breakpoint at the cursor position.
func s:DeleteBreakpoint()
let fname = fnameescape(expand('%:p'))
let lnum = line('.')
for [key, val] in items(s:breakpoints)
if val['fname'] == fname && val['lnum'] == lnum
call term_sendkeys(s:commbuf, '-break-delete ' . key . "\r")
" Assume this always wors, the reply is simply "^done".
exe 'sign unplace ' . (s:break_id + key)
unlet s:breakpoints[key]
break
endif
endfor
endfunc
" :Next, :Continue, etc - send a command to gdb
func s:SendCommand(cmd)
call term_sendkeys(s:commbuf, a:cmd . "\r")
endfunc
" :Evaluate - evaluate what is under the cursor
func s:Evaluate(range, arg)
if a:arg != ''
let expr = a:arg
elseif a:range == 2
let pos = getcurpos()
let reg = getreg('v', 1, 1)
let regt = getregtype('v')
normal! gv"vy
let expr = @v
call setpos('.', pos)
call setreg('v', reg, regt)
else
let expr = expand('<cexpr>')
endif
call term_sendkeys(s:commbuf, '-data-evaluate-expression "' . expr . "\"\r")
let s:evalexpr = expr
endfunc
" Handle the result of data-evaluate-expression
func s:HandleEvaluate(msg)
echomsg '"' . s:evalexpr . '": ' . substitute(a:msg, '.*value="\(.*\)"', '\1', '')
endfunc
" Handle an error.
func s:HandleError(msg)
echoerr substitute(a:msg, '.*msg="\(.*\)"', '\1', '')
endfunc
" Handle stopping and running message from gdb.
" Will update the sign that shows the current position.
func s:HandleCursor(msg)
let wid = win_getid(winnr())
if win_gotoid(s:startwin)
let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '')
if a:msg =~ '^\*stopped' && filereadable(fname)
let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
if lnum =~ '^[0-9]*$'
if expand('%:h') != fname
if &modified
" TODO: find existing window
exe 'split ' . fnameescape(fname)
let s:startwin = win_getid(winnr())
else
exe 'edit ' . fnameescape(fname)
endif
endif
exe lnum
exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fnameescape(fname)
setlocal signcolumn=yes
endif
else
exe 'sign unplace ' . s:pc_id
endif
call win_gotoid(wid)
endif
endfunc
" Handle setting a breakpoint
" Will update the sign that shows the breakpoint
func s:HandleNewBreakpoint(msg)
let nr = substitute(a:msg, '.*number="\([0-9]\)*\".*', '\1', '') + 0
if nr == 0
return
endif
if has_key(s:breakpoints, nr)
let entry = s:breakpoints[nr]
else
let entry = {}
let s:breakpoints[nr] = entry
endif
let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '')
let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
exe 'sign place ' . (s:break_id + nr) . ' line=' . lnum . ' name=debugBreakpoint file=' . fnameescape(fname)
let entry['fname'] = fname
let entry['lnum'] = lnum
endfunc
" Handle deleting a breakpoint
" Will remove the sign that shows the breakpoint
func s:HandleBreakpointDelete(msg)
let nr = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0
if nr == 0
return
endif
exe 'sign unplace ' . (s:break_id + nr)
unlet s:breakpoints[nr]
endfunc

View File

@@ -5211,8 +5211,8 @@ char_u *buf_spname(buf_T *buf)
return (char_u *)_(msg_qflist); return (char_u *)_(msg_qflist);
} }
} }
/* There is no _file_ when 'buftype' is "nofile", b_sfname // There is no _file_ when 'buftype' is "nofile", b_sfname
* contains the name as specified by the user */ // contains the name as specified by the user.
if (bt_nofile(buf)) { if (bt_nofile(buf)) {
if (buf->b_sfname != NULL) { if (buf->b_sfname != NULL) {
return buf->b_sfname; return buf->b_sfname;

View File

@@ -388,24 +388,25 @@ typedef struct {
* a window may have its own instance. * a window may have its own instance.
*/ */
typedef struct { typedef struct {
hashtab_T b_keywtab; /* syntax keywords hash table */ hashtab_T b_keywtab; // syntax keywords hash table
hashtab_T b_keywtab_ic; /* idem, ignore case */ hashtab_T b_keywtab_ic; // idem, ignore case
int b_syn_error; /* TRUE when error occurred in HL */ int b_syn_error; // TRUE when error occurred in HL
int b_syn_ic; /* ignore case for :syn cmds */ bool b_syn_slow; // true when 'redrawtime' reached
int b_syn_spell; /* SYNSPL_ values */ int b_syn_ic; // ignore case for :syn cmds
garray_T b_syn_patterns; /* table for syntax patterns */ int b_syn_spell; // SYNSPL_ values
garray_T b_syn_clusters; /* table for syntax clusters */ garray_T b_syn_patterns; // table for syntax patterns
int b_spell_cluster_id; /* @Spell cluster ID or 0 */ garray_T b_syn_clusters; // table for syntax clusters
int b_nospell_cluster_id; /* @NoSpell cluster ID or 0 */ int b_spell_cluster_id; // @Spell cluster ID or 0
int b_syn_containedin; /* TRUE when there is an item with a int b_nospell_cluster_id; // @NoSpell cluster ID or 0
"containedin" argument */ int b_syn_containedin; // TRUE when there is an item with a
int b_syn_sync_flags; /* flags about how to sync */ // "containedin" argument
short b_syn_sync_id; /* group to sync on */ int b_syn_sync_flags; // flags about how to sync
long b_syn_sync_minlines; /* minimal sync lines offset */ int16_t b_syn_sync_id; // group to sync on
long b_syn_sync_maxlines; /* maximal sync lines offset */ long b_syn_sync_minlines; // minimal sync lines offset
long b_syn_sync_linebreaks; /* offset for multi-line pattern */ long b_syn_sync_maxlines; // maximal sync lines offset
char_u *b_syn_linecont_pat; /* line continuation pattern */ long b_syn_sync_linebreaks; // offset for multi-line pattern
regprog_T *b_syn_linecont_prog; /* line continuation program */ char_u *b_syn_linecont_pat; // line continuation pattern
regprog_T *b_syn_linecont_prog; // line continuation program
syn_time_T b_syn_linecont_time; syn_time_T b_syn_linecont_time;
int b_syn_linecont_ic; /* ignore-case flag for above */ int b_syn_linecont_ic; /* ignore-case flag for above */
int b_syn_topgrp; /* for ":syntax include" */ int b_syn_topgrp; /* for ":syntax include" */

View File

@@ -4642,6 +4642,9 @@ static void nv_clear(cmdarg_T *cap)
if (!checkclearop(cap->oap)) { if (!checkclearop(cap->oap)) {
/* Clear all syntax states to force resyncing. */ /* Clear all syntax states to force resyncing. */
syn_stack_free_all(curwin->w_s); syn_stack_free_all(curwin->w_s);
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
wp->w_s->b_syn_slow = false;
}
redraw_later(CLEAR); redraw_later(CLEAR);
} }
} }

View File

@@ -5098,8 +5098,6 @@ static int regmatch(
printf("Premature EOL\n"); printf("Premature EOL\n");
#endif #endif
} }
if (status == RA_FAIL)
got_int = TRUE;
return status == RA_MATCH; return status == RA_MATCH;
} }
@@ -7226,7 +7224,8 @@ static void report_re_switch(char_u *pat)
/// @param nl /// @param nl
/// ///
/// @return TRUE if there is a match, FALSE if not. /// @return TRUE if there is a match, FALSE if not.
static int vim_regexec_both(regmatch_T *rmp, char_u *line, colnr_T col, bool nl) static int vim_regexec_string(regmatch_T *rmp, char_u *line, colnr_T col,
bool nl)
{ {
regexec_T rex_save; regexec_T rex_save;
bool rex_in_use_save = rex_in_use; bool rex_in_use_save = rex_in_use;
@@ -7275,8 +7274,8 @@ static int vim_regexec_both(regmatch_T *rmp, char_u *line, colnr_T col, bool nl)
int vim_regexec_prog(regprog_T **prog, bool ignore_case, char_u *line, int vim_regexec_prog(regprog_T **prog, bool ignore_case, char_u *line,
colnr_T col) colnr_T col)
{ {
regmatch_T regmatch = {.regprog = *prog, .rm_ic = ignore_case}; regmatch_T regmatch = { .regprog = *prog, .rm_ic = ignore_case };
int r = vim_regexec_both(&regmatch, line, col, false); int r = vim_regexec_string(&regmatch, line, col, false);
*prog = regmatch.regprog; *prog = regmatch.regprog;
return r; return r;
} }
@@ -7285,7 +7284,7 @@ int vim_regexec_prog(regprog_T **prog, bool ignore_case, char_u *line,
// Return TRUE if there is a match, FALSE if not. // Return TRUE if there is a match, FALSE if not.
int vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col) int vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col)
{ {
return vim_regexec_both(rmp, line, col, false); return vim_regexec_string(rmp, line, col, false);
} }
// Like vim_regexec(), but consider a "\n" in "line" to be a line break. // Like vim_regexec(), but consider a "\n" in "line" to be a line break.
@@ -7293,7 +7292,7 @@ int vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col)
// Return TRUE if there is a match, FALSE if not. // Return TRUE if there is a match, FALSE if not.
int vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col) int vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col)
{ {
return vim_regexec_both(rmp, line, col, true); return vim_regexec_string(rmp, line, col, true);
} }
/// Match a regexp against multiple lines. /// Match a regexp against multiple lines.

View File

@@ -1135,6 +1135,9 @@ static void win_update(win_T *wp)
/* reset got_int, otherwise regexp won't work */ /* reset got_int, otherwise regexp won't work */
save_got_int = got_int; save_got_int = got_int;
got_int = 0; got_int = 0;
// Set the time limit to 'redrawtime'.
proftime_T syntax_tm = profile_setlimit(p_rdt);
syn_set_timeout(&syntax_tm);
win_foldinfo.fi_level = 0; win_foldinfo.fi_level = 0;
/* /*
@@ -1493,6 +1496,7 @@ static void win_update(win_T *wp)
if (wp->w_redr_type >= REDRAW_TOP) { if (wp->w_redr_type >= REDRAW_TOP) {
draw_vsep_win(wp, 0); draw_vsep_win(wp, 0);
} }
syn_set_timeout(NULL);
/* Reset the type of redrawing required, the window has been updated. */ /* Reset the type of redrawing required, the window has been updated. */
wp->w_redr_type = 0; wp->w_redr_type = 0;
@@ -2189,7 +2193,7 @@ win_line (
// To speed up the loop below, set extra_check when there is linebreak, // To speed up the loop below, set extra_check when there is linebreak,
// trailing white space and/or syntax processing to be done. // trailing white space and/or syntax processing to be done.
extra_check = wp->w_p_lbr; extra_check = wp->w_p_lbr;
if (syntax_present(wp) && !wp->w_s->b_syn_error) { if (syntax_present(wp) && !wp->w_s->b_syn_error && !wp->w_s->b_syn_slow) {
// Prepare for syntax highlighting in this line. When there is an // Prepare for syntax highlighting in this line. When there is an
// error, stop syntax highlighting. // error, stop syntax highlighting.
save_did_emsg = did_emsg; save_did_emsg = did_emsg;
@@ -2199,8 +2203,10 @@ win_line (
wp->w_s->b_syn_error = true; wp->w_s->b_syn_error = true;
} else { } else {
did_emsg = save_did_emsg; did_emsg = save_did_emsg;
has_syntax = true; if (!wp->w_s->b_syn_slow) {
extra_check = true; has_syntax = true;
extra_check = true;
}
} }
} }
@@ -2539,9 +2545,10 @@ win_line (
} }
wp->w_cursor = pos; wp->w_cursor = pos;
/* Need to restart syntax highlighting for this line. */ // Need to restart syntax highlighting for this line.
if (has_syntax) if (has_syntax) {
syntax_start(wp, lnum); syntax_start(wp, lnum);
}
} }
} }
@@ -2587,6 +2594,9 @@ win_line (
} }
next_search_hl(wp, shl, lnum, (colnr_T)v, next_search_hl(wp, shl, lnum, (colnr_T)v,
shl == &search_hl ? NULL : cur); shl == &search_hl ? NULL : cur);
if (wp->w_s->b_syn_slow) {
has_syntax = false;
}
// Need to get the line again, a multi-line regexp may have made it // Need to get the line again, a multi-line regexp may have made it
// invalid. // invalid.
@@ -4821,13 +4831,13 @@ static void win_redr_status(win_T *wp)
p = NameBuff; p = NameBuff;
len = (int)STRLEN(p); len = (int)STRLEN(p);
if (wp->w_buffer->b_help if (bt_help(wp->w_buffer)
|| wp->w_p_pvw || wp->w_p_pvw
|| bufIsChanged(wp->w_buffer) || bufIsChanged(wp->w_buffer)
|| wp->w_buffer->b_p_ro) { || wp->w_buffer->b_p_ro) {
*(p + len++) = ' '; *(p + len++) = ' ';
} }
if (wp->w_buffer->b_help) { if (bt_help(wp->w_buffer)) {
STRCPY(p + len, _("[Help]")); STRCPY(p + len, _("[Help]"));
len += (int)STRLEN(p + len); len += (int)STRLEN(p + len);
} }

View File

@@ -356,15 +356,16 @@ static reg_extmatch_T *next_match_extmatch = NULL;
* The current state (within the line) of the recognition engine. * The current state (within the line) of the recognition engine.
* When current_state.ga_itemsize is 0 the current state is invalid. * When current_state.ga_itemsize is 0 the current state is invalid.
*/ */
static win_T *syn_win; /* current window for highlighting */ static win_T *syn_win; // current window for highlighting
static buf_T *syn_buf; /* current buffer for highlighting */ static buf_T *syn_buf; // current buffer for highlighting
static synblock_T *syn_block; /* current buffer for highlighting */ static synblock_T *syn_block; // current buffer for highlighting
static linenr_T current_lnum = 0; /* lnum of current state */ static proftime_T *syn_tm; // timeout limit
static colnr_T current_col = 0; /* column of current state */ static linenr_T current_lnum = 0; // lnum of current state
static int current_state_stored = 0; /* TRUE if stored current state static colnr_T current_col = 0; // column of current state
* after setting current_finished */ static int current_state_stored = 0; // TRUE if stored current state
static int current_finished = 0; /* current line has been finished */ // after setting current_finished
static garray_T current_state /* current stack of state_items */ static int current_finished = 0; // current line has been finished
static garray_T current_state // current stack of state_items
= GA_EMPTY_INIT_VALUE; = GA_EMPTY_INIT_VALUE;
static int16_t *current_next_list = NULL; // when non-zero, nextgroup list static int16_t *current_next_list = NULL; // when non-zero, nextgroup list
static int current_next_flags = 0; // flags for current_next_list static int current_next_flags = 0; // flags for current_next_list
@@ -375,7 +376,12 @@ static int current_line_id = 0; // unique number for current line
static int syn_time_on = FALSE; static int syn_time_on = FALSE;
# define IF_SYN_TIME(p) (p) # define IF_SYN_TIME(p) (p)
// Set the timeout used for syntax highlighting.
// Use NULL to reset, no timeout.
void syn_set_timeout(proftime_T *tm)
{
syn_tm = tm;
}
/* /*
* Start the syntax recognition for a line. This function is normally called * Start the syntax recognition for a line. This function is normally called
@@ -2887,6 +2893,7 @@ static char_u *syn_getcurline(void)
static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T *st) static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T *st)
{ {
int r; int r;
int timed_out = 0;
proftime_T pt; proftime_T pt;
const int l_syn_time_on = syn_time_on; const int l_syn_time_on = syn_time_on;
@@ -2902,7 +2909,8 @@ static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T
} }
rmp->rmm_maxcol = syn_buf->b_p_smc; rmp->rmm_maxcol = syn_buf->b_p_smc;
r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col, NULL, NULL); r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col,
syn_tm, &timed_out);
if (l_syn_time_on) { if (l_syn_time_on) {
pt = profile_end(pt); pt = profile_end(pt);
@@ -2914,6 +2922,9 @@ static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T
if (r > 0) if (r > 0)
++st->match; ++st->match;
} }
if (timed_out) {
syn_win->w_s->b_syn_slow = true;
}
if (r > 0) { if (r > 0) {
rmp->startpos[0].lnum += lnum; rmp->startpos[0].lnum += lnum;
@@ -3144,6 +3155,7 @@ static void syn_cmd_iskeyword(exarg_T *eap, int syncing)
void syntax_clear(synblock_T *block) void syntax_clear(synblock_T *block)
{ {
block->b_syn_error = false; // clear previous error block->b_syn_error = false; // clear previous error
block->b_syn_slow = false; // clear previous timeout
block->b_syn_ic = false; // Use case, by default block->b_syn_ic = false; // Use case, by default
block->b_syn_spell = SYNSPL_DEFAULT; // default spell checking block->b_syn_spell = SYNSPL_DEFAULT; // default spell checking
block->b_syn_containedin = false; block->b_syn_containedin = false;
@@ -5756,8 +5768,10 @@ int syn_get_foldlevel(win_T *wp, long lnum)
{ {
int level = 0; int level = 0;
/* Return quickly when there are no fold items at all. */ // Return quickly when there are no fold items at all.
if (wp->w_s->b_syn_folditems != 0) { if (wp->w_s->b_syn_folditems != 0
&& !wp->w_s->b_syn_error
&& !wp->w_s->b_syn_slow) {
syntax_start(wp, lnum); syntax_start(wp, lnum);
for (int i = 0; i < current_state.ga_len; ++i) { for (int i = 0; i < current_state.ga_len; ++i) {

View File

@@ -1379,6 +1379,11 @@ func XquickfixSetListWithAct(cchar)
call assert_fails("call g:Xsetlist(list1, 0)", 'E928:') call assert_fails("call g:Xsetlist(list1, 0)", 'E928:')
endfunc endfunc
func Test_setqflist_invalid_nr()
" The following command used to crash Vim
call setqflist([], ' ', {'nr' : $XXX_DOES_NOT_EXIST})
endfunc
func Test_quickfix_set_list_with_act() func Test_quickfix_set_list_with_act()
call XquickfixSetListWithAct('c') call XquickfixSetListWithAct('c')
call XquickfixSetListWithAct('l') call XquickfixSetListWithAct('l')
@@ -2649,6 +2654,15 @@ func Test_qf_id()
call Xqfid_tests('l') call Xqfid_tests('l')
endfunc endfunc
func Test_getqflist_invalid_nr()
" The following commands used to crash Vim
cexpr ""
call getqflist({'nr' : $XXX_DOES_NOT_EXIST_XXX})
" Cleanup
call setqflist([], 'r')
endfunc
" Test for shortening/simplifying the file name when opening the " Test for shortening/simplifying the file name when opening the
" quickfix window or when displaying the quickfix list " quickfix window or when displaying the quickfix list
func Test_shorten_fname() func Test_shorten_fname()

View File

@@ -503,3 +503,37 @@ func Test_syn_wrong_z_one()
" call test_override("ALL", 0) " call test_override("ALL", 0)
bwipe! bwipe!
endfunc endfunc
func Test_syntax_hangs()
if !has('reltime') || !has('float') || !has('syntax')
return
endif
" This pattern takes a long time to match, it should timeout.
new
call setline(1, ['aaa', repeat('abc ', 1000), 'ccc'])
let start = reltime()
set nolazyredraw redrawtime=101
syn match Error /\%#=1a*.*X\@<=b*/
redraw
let elapsed = reltimefloat(reltime(start))
call assert_true(elapsed > 0.1)
call assert_true(elapsed < 1.0)
" second time syntax HL is disabled
let start = reltime()
redraw
let elapsed = reltimefloat(reltime(start))
call assert_true(elapsed < 0.1)
" after CTRL-L the timeout flag is reset
let start = reltime()
exe "normal \<C-L>"
redraw
let elapsed = reltimefloat(reltime(start))
call assert_true(elapsed > 0.1)
call assert_true(elapsed < 1.0)
set redrawtime&
bwipe!
endfunc