diff options
-rw-r--r-- | runtime/doc/options.txt | 7 | ||||
-rw-r--r-- | src/nvim/ex_cmds.c | 27 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 46 | ||||
-rw-r--r-- | src/nvim/getchar.c | 44 | ||||
-rw-r--r-- | src/nvim/option.h | 12 |
5 files changed, 78 insertions, 58 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index d13a245d87..1789f73aa9 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -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| + If the preview is too slow (exceeds 'redrawtime') then 'inccommand' is + automatically disabled until |Command-line-mode| is done. + *'include'* *'inc'* 'include' 'inc' string (default "^\s*#\s*include") 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 {only available when compiled with the |+reltime| feature} - The time in milliseconds for redrawing the display. This applies to - searching for patterns for 'hlsearch' and |:match| highlighting. + Time in milliseconds for redrawing the display. Applies to + 'hlsearch', 'inccommand' and |:match| highlighting. When redrawing takes more than this many milliseconds no further matches will be highlighted. This is used to avoid that Vim hangs when using a very complicated pattern. diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 66b6aa2f46..a747ead6b9 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -3100,8 +3100,6 @@ static char_u *sub_parse_flags(char_u *cmd, subflags_T *subflags, return cmd; } -/// do_sub() -/// /// 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: /// @@ -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. /// /// @return buffer used for 'inccommand' preview -buf_T *do_sub(exarg_T *eap) +static buf_T *do_sub(exarg_T *eap) { long i = 0; regmmatch_T regmatch; @@ -3139,6 +3137,7 @@ buf_T *do_sub(exarg_T *eap) bool endcolumn = false; // cursor in last column when done MatchedLineVec matched_lines = KV_INITIAL_VALUE; pos_T old_cursor = curwin->w_cursor; + proftime_T timeout = eap->is_live ? profile_setlimit(p_rdt) : profile_zero(); int start_nsubs; int save_ma = 0; int save_b_changed = curbuf->b_changed; @@ -3581,7 +3580,7 @@ buf_T *do_sub(exarg_T *eap) || typed == intr_char #endif ) { - got_quit = TRUE; + got_quit = true; break; } if (typed == 'n') @@ -3882,6 +3881,10 @@ skip: } line_breakcheck(); + + if (profile_passed_limit(timeout)) { + got_quit = true; + } } if (first_line != 0) { @@ -3949,9 +3952,14 @@ skip: // Show 'inccommand' preview if there are matched lines. buf_T *preview_buf = NULL; - if (eap->is_live && *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); + if (eap->is_live && !aborting()) { + if (got_quit) { // Substitution is too slow, disable 'inccommand'. + 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);) { @@ -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.noswapfile = true; // disable swap for preview buffer // 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 || 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); 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); // Update screen now. Must do this _before_ close_windows(). diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index c4169f03f0..3093caebaf 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -95,19 +95,21 @@ typedef struct command_line_state { char_u *lookfor; // string to match int hiscnt; // current history line in use int histype; // history type to be used - pos_T old_cursor; - colnr_T old_curswant; - colnr_T old_leftcol; - linenr_T old_topline; - int old_topfill; - linenr_T old_botline; + pos_T old_cursor; + colnr_T old_curswant; + colnr_T old_leftcol; + linenr_T old_topline; + int old_topfill; + linenr_T old_botline; int did_incsearch; int incsearch_postponed; + bool live; // performing 'inccommand' preview int did_wild_list; // did wild_list() recently int wim_index; // index in wim_flags[] int res; - int save_msg_scroll; - int save_State; // remember State when called + int save_msg_scroll; + int save_State; // remember State when called + char_u *save_p_icm; int some_key_typed; // one of the keys was typed // mouse drag and release events are ignored, unless they are // 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->save_msg_scroll = msg_scroll; s->save_State = State; + s->save_p_icm = vim_strsave(p_icm); s->ignore_drag_release = true; if (s->firstc == -1) { @@ -323,9 +326,12 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) need_wait_return = false; } + set_string_option_direct((char_u *)"icm", -1, s->save_p_icm, OPT_FREE, + SID_NONE); State = s->save_State; setmouse(); ui_cursor_shape(); // may show different cursor shape + xfree(s->save_p_icm); { char_u *p = ccline.cmdbuff; @@ -394,7 +400,8 @@ static int command_line_execute(VimState *state, int key) if ((s->c == Ctrl_C) && s->firstc != '@' && !s->break_ctrl_c - && !global_busy) { + && !global_busy + && !cmd_is_live(ccline.cmdbuff)) { got_int = false; } @@ -981,7 +988,6 @@ static int command_line_handle_key(CommandLineState *s) status_redraw_curbuf(); return command_line_not_changed(s); - // case '@': only in very old vi case Ctrl_U: // delete all characters left of the cursor s->j = ccline.cmdpos; @@ -996,7 +1002,6 @@ static int command_line_handle_key(CommandLineState *s) redrawcmd(); return command_line_changed(s); - case ESC: // get here if p_wc != ESC or when ESC typed twice case Ctrl_C: // 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) { - // This part implements incremental searches for "/" and "?" Jump to - // cmdline_not_changed when a character has been read but the command line - // did not change. Then we only search and redraw if something changed in - // the past. Jump to cmdline_changed when the command line did change. - // (Sorry for the goto's, I know it is ugly). + // Incremental searches for "/" and "?": + // Enter command_line_not_changed() when a character has been read but the + // command line did not change. Then we only search and redraw if something + // changed in the past. + // Enter command_line_changed() when the command line did change. if (!s->incsearch_postponed) { return 1; } @@ -1592,11 +1597,13 @@ static int command_line_changed(CommandLineState *s) redrawcmdline(); s->did_incsearch = true; } else if (s->firstc == ':' - && KeyTyped // only if interactive + && current_SID == 0 // only if interactive && *p_icm != NUL // 'inccommand' is set && curbuf->b_p_ma // buffer is modifiable && 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') do_cmdline(ccline.cmdbuff, NULL, NULL, DOCMD_KEEPLINE|DOCMD_LIVE); @@ -1610,6 +1617,9 @@ static int command_line_changed(CommandLineState *s) update_topline(); redrawcmdline(); + } else if (s->live) { + s->live = false; + update_screen(SOME_VALID); // Clear 'inccommand' preview. } if (cmdmsg_rl || (p_arshape && !p_tbidi && enc_utf8)) { diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index dad0ac33cd..ab52ee0372 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1583,29 +1583,27 @@ vungetc ( /* unget one character (can only be done once!) */ old_mouse_col = mouse_col; } -/* - * get a character: - * 1. from the stuffbuffer - * This is used for abbreviated commands like "D" -> "d$". - * Also used to redo a command for ".". - * 2. from the typeahead buffer - * Stores text obtained previously but not used yet. - * Also stores the result of mappings. - * Also used for the ":normal" command. - * 3. from the user - * This may do a blocking wait if "advance" is TRUE. - * - * if "advance" is TRUE (vgetc()): - * really get the character. - * KeyTyped is set to TRUE in the case the user typed the key. - * KeyStuffed is TRUE if the character comes from the stuff buffer. - * if "advance" is FALSE (vpeekc()): - * just look whether there is a character available. - * - * When "no_mapping" is zero, checks for mappings in the current mode. - * Only returns one byte (of a multi-byte character). - * K_SPECIAL and CSI may be escaped, need to get two more bytes then. - */ +/// get a character: +/// 1. from the stuffbuffer +/// This is used for abbreviated commands like "D" -> "d$". +/// Also used to redo a command for ".". +/// 2. from the typeahead buffer +/// Stores text obtained previously but not used yet. +/// Also stores the result of mappings. +/// Also used for the ":normal" command. +/// 3. from the user +/// This may do a blocking wait if "advance" is TRUE. +/// +/// if "advance" is TRUE (vgetc()): +/// really get the character. +/// KeyTyped is set to TRUE in the case the user typed the key. +/// KeyStuffed is TRUE if the character comes from the stuff buffer. +/// if "advance" is FALSE (vpeekc()): +/// just look whether there is a character available. +/// +/// When "no_mapping" is zero, checks for mappings in the current mode. +/// Only returns one byte (of a multi-byte character). +/// K_SPECIAL and CSI may be escaped, need to get two more bytes then. static int vgetorpeek(int advance) { int c, c1; diff --git a/src/nvim/option.h b/src/nvim/option.h index cf167cdd2c..60f14dea44 100644 --- a/src/nvim/option.h +++ b/src/nvim/option.h @@ -13,12 +13,12 @@ /// When OPT_GLOBAL and OPT_LOCAL are both missing, set both local and global /// values, get local value. typedef enum { - OPT_FREE = 1, ///< Free old value if it was allocated. - OPT_GLOBAL = 2, ///< Use global value. - OPT_LOCAL = 4, ///< Use local value. - OPT_MODELINE = 8, ///< Option in modeline. - OPT_WINONLY = 16, ///< Only set window-local options. - OPT_NOWIN = 32, ///< Don’t set window-local options. + OPT_FREE = 1, ///< Free old value if it was allocated. + OPT_GLOBAL = 2, ///< Use global value. + OPT_LOCAL = 4, ///< Use local value. + OPT_MODELINE = 8, ///< Option in modeline. + OPT_WINONLY = 16, ///< Only set window-local options. + OPT_NOWIN = 32, ///< Don’t set window-local options. } OptionFlags; #ifdef INCLUDE_GENERATED_DECLARATIONS |