mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
'inccommand': Detect "non-interactive", "too slow".
command_line_changed: - Check (current_SID == 0) instead of KeyTyped - We want to update during mappings (KeyTyped is false then). - Check vpeekc_any() - Avoids unnecessary work. - Avoids triggering live preview during macros. - Caveat: This makes the redraw "stutter" if user spams (holds a key) in the replace pattern. But that scenario is not important. - Update screen if the command is changed to a non-live command. (`s->live` goes from true => false) => clears the preview command_line_execute: - Let CTRL-C cancel live preview do_sub: - Enforce a time limit ('redrawtime'). - Unset 'inccommand' if time limit is reached. Closes #5602 Closes #5585
This commit is contained in:
parent
4539d867d4
commit
91507c271e
@ -3418,6 +3418,9 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
|
|
||||||
Works for |:substitute|, |:smagic|, |:snomagic|. |hl-Substitute|
|
Works for |:substitute|, |:smagic|, |:snomagic|. |hl-Substitute|
|
||||||
|
|
||||||
|
If the preview is too slow (exceeds 'redrawtime') then 'inccommand' is
|
||||||
|
automatically disabled until |Command-line-mode| is done.
|
||||||
|
|
||||||
*'include'* *'inc'*
|
*'include'* *'inc'*
|
||||||
'include' 'inc' string (default "^\s*#\s*include")
|
'include' 'inc' string (default "^\s*#\s*include")
|
||||||
global or local to buffer |global-local|
|
global or local to buffer |global-local|
|
||||||
@ -4733,8 +4736,8 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
global
|
global
|
||||||
{only available when compiled with the |+reltime|
|
{only available when compiled with the |+reltime|
|
||||||
feature}
|
feature}
|
||||||
The time in milliseconds for redrawing the display. This applies to
|
Time in milliseconds for redrawing the display. Applies to
|
||||||
searching for patterns for 'hlsearch' and |:match| highlighting.
|
'hlsearch', 'inccommand' and |:match| 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. This is used to avoid that Vim hangs
|
||||||
when using a very complicated pattern.
|
when using a very complicated pattern.
|
||||||
|
@ -3100,8 +3100,6 @@ static char_u *sub_parse_flags(char_u *cmd, subflags_T *subflags,
|
|||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// do_sub()
|
|
||||||
///
|
|
||||||
/// Perform a substitution from line eap->line1 to line eap->line2 using the
|
/// Perform a substitution from line eap->line1 to line eap->line2 using the
|
||||||
/// command pointed to by eap->arg which should be of the form:
|
/// command pointed to by eap->arg which should be of the form:
|
||||||
///
|
///
|
||||||
@ -3110,7 +3108,7 @@ static char_u *sub_parse_flags(char_u *cmd, subflags_T *subflags,
|
|||||||
/// The usual escapes are supported as described in the regexp docs.
|
/// The usual escapes are supported as described in the regexp docs.
|
||||||
///
|
///
|
||||||
/// @return buffer used for 'inccommand' preview
|
/// @return buffer used for 'inccommand' preview
|
||||||
buf_T *do_sub(exarg_T *eap)
|
static buf_T *do_sub(exarg_T *eap)
|
||||||
{
|
{
|
||||||
long i = 0;
|
long i = 0;
|
||||||
regmmatch_T regmatch;
|
regmmatch_T regmatch;
|
||||||
@ -3139,6 +3137,7 @@ buf_T *do_sub(exarg_T *eap)
|
|||||||
bool endcolumn = false; // cursor in last column when done
|
bool endcolumn = false; // cursor in last column when done
|
||||||
MatchedLineVec matched_lines = KV_INITIAL_VALUE;
|
MatchedLineVec matched_lines = KV_INITIAL_VALUE;
|
||||||
pos_T old_cursor = curwin->w_cursor;
|
pos_T old_cursor = curwin->w_cursor;
|
||||||
|
proftime_T timeout = eap->is_live ? profile_setlimit(p_rdt) : profile_zero();
|
||||||
int start_nsubs;
|
int start_nsubs;
|
||||||
int save_ma = 0;
|
int save_ma = 0;
|
||||||
int save_b_changed = curbuf->b_changed;
|
int save_b_changed = curbuf->b_changed;
|
||||||
@ -3581,7 +3580,7 @@ buf_T *do_sub(exarg_T *eap)
|
|||||||
|| typed == intr_char
|
|| typed == intr_char
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
got_quit = TRUE;
|
got_quit = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (typed == 'n')
|
if (typed == 'n')
|
||||||
@ -3882,6 +3881,10 @@ skip:
|
|||||||
}
|
}
|
||||||
|
|
||||||
line_breakcheck();
|
line_breakcheck();
|
||||||
|
|
||||||
|
if (profile_passed_limit(timeout)) {
|
||||||
|
got_quit = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (first_line != 0) {
|
if (first_line != 0) {
|
||||||
@ -3949,9 +3952,14 @@ skip:
|
|||||||
|
|
||||||
// Show 'inccommand' preview if there are matched lines.
|
// Show 'inccommand' preview if there are matched lines.
|
||||||
buf_T *preview_buf = NULL;
|
buf_T *preview_buf = NULL;
|
||||||
if (eap->is_live && *p_icm != NUL && matched_lines.size != 0 && pat != NULL) {
|
if (eap->is_live && !aborting()) {
|
||||||
curbuf->b_changed = save_b_changed; // preserve 'modified' during preview
|
if (got_quit) { // Substitution is too slow, disable 'inccommand'.
|
||||||
preview_buf = show_sub(eap, old_cursor, pat, sub, &matched_lines);
|
set_string_option_direct((char_u *)"icm", -1, (char_u *)"", OPT_FREE,
|
||||||
|
SID_NONE);
|
||||||
|
} else if (*p_icm != NUL && matched_lines.size != 0 && pat != NULL) {
|
||||||
|
curbuf->b_changed = save_b_changed; // preserve 'modified' during preview
|
||||||
|
preview_buf = show_sub(eap, old_cursor, pat, sub, &matched_lines);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (MatchedLine m; kv_size(matched_lines);) {
|
for (MatchedLine m; kv_size(matched_lines);) {
|
||||||
@ -6017,7 +6025,8 @@ static buf_T *show_sub(exarg_T *eap, pos_T old_cusr, char_u *pat, char_u *sub,
|
|||||||
cmdmod.tab = 0; // disable :tab modifier
|
cmdmod.tab = 0; // disable :tab modifier
|
||||||
cmdmod.noswapfile = true; // disable swap for preview buffer
|
cmdmod.noswapfile = true; // disable swap for preview buffer
|
||||||
// disable file info message
|
// disable file info message
|
||||||
set_option_value((char_u *)"shm", 0L, (char_u *)"F", 0);
|
set_string_option_direct((char_u *)"shm", -1, (char_u *)"F", OPT_FREE,
|
||||||
|
SID_NONE);
|
||||||
|
|
||||||
bool outside_curline = (eap->line1 != old_cusr.lnum
|
bool outside_curline = (eap->line1 != old_cusr.lnum
|
||||||
|| eap->line2 != old_cusr.lnum);
|
|| eap->line2 != old_cusr.lnum);
|
||||||
@ -6096,7 +6105,7 @@ static buf_T *show_sub(exarg_T *eap, pos_T old_cusr, char_u *pat, char_u *sub,
|
|||||||
win_size_restore(&save_winsizes);
|
win_size_restore(&save_winsizes);
|
||||||
ga_clear(&save_winsizes);
|
ga_clear(&save_winsizes);
|
||||||
|
|
||||||
set_option_value((char_u *)"shm", 0L, save_shm_p, 0);
|
set_string_option_direct((char_u *)"shm", -1, save_shm_p, OPT_FREE, SID_NONE);
|
||||||
xfree(save_shm_p);
|
xfree(save_shm_p);
|
||||||
|
|
||||||
// Update screen now. Must do this _before_ close_windows().
|
// Update screen now. Must do this _before_ close_windows().
|
||||||
|
@ -95,19 +95,21 @@ typedef struct command_line_state {
|
|||||||
char_u *lookfor; // string to match
|
char_u *lookfor; // string to match
|
||||||
int hiscnt; // current history line in use
|
int hiscnt; // current history line in use
|
||||||
int histype; // history type to be used
|
int histype; // history type to be used
|
||||||
pos_T old_cursor;
|
pos_T old_cursor;
|
||||||
colnr_T old_curswant;
|
colnr_T old_curswant;
|
||||||
colnr_T old_leftcol;
|
colnr_T old_leftcol;
|
||||||
linenr_T old_topline;
|
linenr_T old_topline;
|
||||||
int old_topfill;
|
int old_topfill;
|
||||||
linenr_T old_botline;
|
linenr_T old_botline;
|
||||||
int did_incsearch;
|
int did_incsearch;
|
||||||
int incsearch_postponed;
|
int incsearch_postponed;
|
||||||
|
bool live; // performing 'inccommand' preview
|
||||||
int did_wild_list; // did wild_list() recently
|
int did_wild_list; // did wild_list() recently
|
||||||
int wim_index; // index in wim_flags[]
|
int wim_index; // index in wim_flags[]
|
||||||
int res;
|
int res;
|
||||||
int save_msg_scroll;
|
int save_msg_scroll;
|
||||||
int save_State; // remember State when called
|
int save_State; // remember State when called
|
||||||
|
char_u *save_p_icm;
|
||||||
int some_key_typed; // one of the keys was typed
|
int some_key_typed; // one of the keys was typed
|
||||||
// mouse drag and release events are ignored, unless they are
|
// mouse drag and release events are ignored, unless they are
|
||||||
// preceded with a mouse down event
|
// preceded with a mouse down event
|
||||||
@ -159,6 +161,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
|
|||||||
s->indent = indent;
|
s->indent = indent;
|
||||||
s->save_msg_scroll = msg_scroll;
|
s->save_msg_scroll = msg_scroll;
|
||||||
s->save_State = State;
|
s->save_State = State;
|
||||||
|
s->save_p_icm = vim_strsave(p_icm);
|
||||||
s->ignore_drag_release = true;
|
s->ignore_drag_release = true;
|
||||||
|
|
||||||
if (s->firstc == -1) {
|
if (s->firstc == -1) {
|
||||||
@ -323,9 +326,12 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
|
|||||||
need_wait_return = false;
|
need_wait_return = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_string_option_direct((char_u *)"icm", -1, s->save_p_icm, OPT_FREE,
|
||||||
|
SID_NONE);
|
||||||
State = s->save_State;
|
State = s->save_State;
|
||||||
setmouse();
|
setmouse();
|
||||||
ui_cursor_shape(); // may show different cursor shape
|
ui_cursor_shape(); // may show different cursor shape
|
||||||
|
xfree(s->save_p_icm);
|
||||||
|
|
||||||
{
|
{
|
||||||
char_u *p = ccline.cmdbuff;
|
char_u *p = ccline.cmdbuff;
|
||||||
@ -394,7 +400,8 @@ static int command_line_execute(VimState *state, int key)
|
|||||||
if ((s->c == Ctrl_C)
|
if ((s->c == Ctrl_C)
|
||||||
&& s->firstc != '@'
|
&& s->firstc != '@'
|
||||||
&& !s->break_ctrl_c
|
&& !s->break_ctrl_c
|
||||||
&& !global_busy) {
|
&& !global_busy
|
||||||
|
&& !cmd_is_live(ccline.cmdbuff)) {
|
||||||
got_int = false;
|
got_int = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -981,7 +988,6 @@ static int command_line_handle_key(CommandLineState *s)
|
|||||||
status_redraw_curbuf();
|
status_redraw_curbuf();
|
||||||
return command_line_not_changed(s);
|
return command_line_not_changed(s);
|
||||||
|
|
||||||
// case '@': only in very old vi
|
|
||||||
case Ctrl_U:
|
case Ctrl_U:
|
||||||
// delete all characters left of the cursor
|
// delete all characters left of the cursor
|
||||||
s->j = ccline.cmdpos;
|
s->j = ccline.cmdpos;
|
||||||
@ -996,7 +1002,6 @@ static int command_line_handle_key(CommandLineState *s)
|
|||||||
redrawcmd();
|
redrawcmd();
|
||||||
return command_line_changed(s);
|
return command_line_changed(s);
|
||||||
|
|
||||||
|
|
||||||
case ESC: // get here if p_wc != ESC or when ESC typed twice
|
case ESC: // get here if p_wc != ESC or when ESC typed twice
|
||||||
case Ctrl_C:
|
case Ctrl_C:
|
||||||
// In exmode it doesn't make sense to return. Except when
|
// In exmode it doesn't make sense to return. Except when
|
||||||
@ -1489,11 +1494,11 @@ static int command_line_handle_key(CommandLineState *s)
|
|||||||
|
|
||||||
static int command_line_not_changed(CommandLineState *s)
|
static int command_line_not_changed(CommandLineState *s)
|
||||||
{
|
{
|
||||||
// This part implements incremental searches for "/" and "?" Jump to
|
// Incremental searches for "/" and "?":
|
||||||
// cmdline_not_changed when a character has been read but the command line
|
// Enter command_line_not_changed() when a character has been read but the
|
||||||
// did not change. Then we only search and redraw if something changed in
|
// command line did not change. Then we only search and redraw if something
|
||||||
// the past. Jump to cmdline_changed when the command line did change.
|
// changed in the past.
|
||||||
// (Sorry for the goto's, I know it is ugly).
|
// Enter command_line_changed() when the command line did change.
|
||||||
if (!s->incsearch_postponed) {
|
if (!s->incsearch_postponed) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -1592,11 +1597,13 @@ static int command_line_changed(CommandLineState *s)
|
|||||||
redrawcmdline();
|
redrawcmdline();
|
||||||
s->did_incsearch = true;
|
s->did_incsearch = true;
|
||||||
} else if (s->firstc == ':'
|
} else if (s->firstc == ':'
|
||||||
&& KeyTyped // only if interactive
|
&& current_SID == 0 // only if interactive
|
||||||
&& *p_icm != NUL // 'inccommand' is set
|
&& *p_icm != NUL // 'inccommand' is set
|
||||||
&& curbuf->b_p_ma // buffer is modifiable
|
&& curbuf->b_p_ma // buffer is modifiable
|
||||||
&& cmdline_star == 0 // not typing a password
|
&& cmdline_star == 0 // not typing a password
|
||||||
&& cmd_is_live(ccline.cmdbuff)) {
|
&& cmd_is_live(ccline.cmdbuff)
|
||||||
|
&& !vpeekc_any()) {
|
||||||
|
s->live = true;
|
||||||
// process a "live" command ('inccommand')
|
// process a "live" command ('inccommand')
|
||||||
do_cmdline(ccline.cmdbuff, NULL, NULL, DOCMD_KEEPLINE|DOCMD_LIVE);
|
do_cmdline(ccline.cmdbuff, NULL, NULL, DOCMD_KEEPLINE|DOCMD_LIVE);
|
||||||
|
|
||||||
@ -1610,6 +1617,9 @@ static int command_line_changed(CommandLineState *s)
|
|||||||
update_topline();
|
update_topline();
|
||||||
|
|
||||||
redrawcmdline();
|
redrawcmdline();
|
||||||
|
} else if (s->live) {
|
||||||
|
s->live = false;
|
||||||
|
update_screen(SOME_VALID); // Clear 'inccommand' preview.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdmsg_rl || (p_arshape && !p_tbidi && enc_utf8)) {
|
if (cmdmsg_rl || (p_arshape && !p_tbidi && enc_utf8)) {
|
||||||
|
@ -1583,29 +1583,27 @@ vungetc ( /* unget one character (can only be done once!) */
|
|||||||
old_mouse_col = mouse_col;
|
old_mouse_col = mouse_col;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/// get a character:
|
||||||
* get a character:
|
/// 1. from the stuffbuffer
|
||||||
* 1. from the stuffbuffer
|
/// This is used for abbreviated commands like "D" -> "d$".
|
||||||
* This is used for abbreviated commands like "D" -> "d$".
|
/// Also used to redo a command for ".".
|
||||||
* Also used to redo a command for ".".
|
/// 2. from the typeahead buffer
|
||||||
* 2. from the typeahead buffer
|
/// Stores text obtained previously but not used yet.
|
||||||
* Stores text obtained previously but not used yet.
|
/// Also stores the result of mappings.
|
||||||
* Also stores the result of mappings.
|
/// Also used for the ":normal" command.
|
||||||
* Also used for the ":normal" command.
|
/// 3. from the user
|
||||||
* 3. from the user
|
/// This may do a blocking wait if "advance" is TRUE.
|
||||||
* This may do a blocking wait if "advance" is TRUE.
|
///
|
||||||
*
|
/// if "advance" is TRUE (vgetc()):
|
||||||
* if "advance" is TRUE (vgetc()):
|
/// really get the character.
|
||||||
* really get the character.
|
/// KeyTyped is set to TRUE in the case the user typed the key.
|
||||||
* KeyTyped is set to TRUE in the case the user typed the key.
|
/// KeyStuffed is TRUE if the character comes from the stuff buffer.
|
||||||
* KeyStuffed is TRUE if the character comes from the stuff buffer.
|
/// if "advance" is FALSE (vpeekc()):
|
||||||
* if "advance" is FALSE (vpeekc()):
|
/// just look whether there is a character available.
|
||||||
* just look whether there is a character available.
|
///
|
||||||
*
|
/// When "no_mapping" is zero, checks for mappings in the current mode.
|
||||||
* When "no_mapping" is zero, checks for mappings in the current mode.
|
/// Only returns one byte (of a multi-byte character).
|
||||||
* Only returns one byte (of a multi-byte character).
|
/// K_SPECIAL and CSI may be escaped, need to get two more bytes then.
|
||||||
* K_SPECIAL and CSI may be escaped, need to get two more bytes then.
|
|
||||||
*/
|
|
||||||
static int vgetorpeek(int advance)
|
static int vgetorpeek(int advance)
|
||||||
{
|
{
|
||||||
int c, c1;
|
int c, c1;
|
||||||
|
@ -13,12 +13,12 @@
|
|||||||
/// When OPT_GLOBAL and OPT_LOCAL are both missing, set both local and global
|
/// When OPT_GLOBAL and OPT_LOCAL are both missing, set both local and global
|
||||||
/// values, get local value.
|
/// values, get local value.
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OPT_FREE = 1, ///< Free old value if it was allocated.
|
OPT_FREE = 1, ///< Free old value if it was allocated.
|
||||||
OPT_GLOBAL = 2, ///< Use global value.
|
OPT_GLOBAL = 2, ///< Use global value.
|
||||||
OPT_LOCAL = 4, ///< Use local value.
|
OPT_LOCAL = 4, ///< Use local value.
|
||||||
OPT_MODELINE = 8, ///< Option in modeline.
|
OPT_MODELINE = 8, ///< Option in modeline.
|
||||||
OPT_WINONLY = 16, ///< Only set window-local options.
|
OPT_WINONLY = 16, ///< Only set window-local options.
|
||||||
OPT_NOWIN = 32, ///< Don’t set window-local options.
|
OPT_NOWIN = 32, ///< Don’t set window-local options.
|
||||||
} OptionFlags;
|
} OptionFlags;
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
|
Loading…
Reference in New Issue
Block a user