mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
'inccommand': Introduce CMDPREVIEW state.
Command "live preview" is fundamentally a non-recursive concept ("preview of a preview" is not useful). Maintaining this as a global is less awkward and closer to what we actually want to express, vs adorning exarg_T, CommandLineState, etc.
This commit is contained in:
parent
708617ebb6
commit
3f7a2d785d
@ -2952,10 +2952,11 @@ void sub_set_replacement(SubReplacementString sub)
|
|||||||
/// @param[in] pat Search pattern
|
/// @param[in] pat Search pattern
|
||||||
/// @param[in] sub Replacement string
|
/// @param[in] sub Replacement string
|
||||||
/// @param[in] cmd Command from :s_flags
|
/// @param[in] cmd Command from :s_flags
|
||||||
|
/// @param[in] save Save pattern to options, history
|
||||||
///
|
///
|
||||||
/// @returns true if :substitute can be replaced with a join command
|
/// @returns true if :substitute can be replaced with a join command
|
||||||
static bool sub_joining_lines(exarg_T *eap, char_u *pat,
|
static bool sub_joining_lines(exarg_T *eap, char_u *pat, char_u *sub,
|
||||||
char_u *sub, char_u *cmd)
|
char_u *cmd, bool save)
|
||||||
FUNC_ATTR_NONNULL_ARG(1, 3, 4)
|
FUNC_ATTR_NONNULL_ARG(1, 3, 4)
|
||||||
{
|
{
|
||||||
// TODO(vim): find a generic solution to make line-joining operations more
|
// TODO(vim): find a generic solution to make line-joining operations more
|
||||||
@ -2989,7 +2990,7 @@ static bool sub_joining_lines(exarg_T *eap, char_u *pat,
|
|||||||
ex_may_print(eap);
|
ex_may_print(eap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!eap->is_live) {
|
if (save) {
|
||||||
if (!cmdmod.keeppatterns) {
|
if (!cmdmod.keeppatterns) {
|
||||||
save_re_pat(RE_SUBST, pat, p_magic);
|
save_re_pat(RE_SUBST, pat, p_magic);
|
||||||
}
|
}
|
||||||
@ -3108,7 +3109,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
|
||||||
static buf_T *do_sub(exarg_T *eap)
|
static buf_T *do_sub(exarg_T *eap, proftime_T timeout)
|
||||||
{
|
{
|
||||||
long i = 0;
|
long i = 0;
|
||||||
regmmatch_T regmatch;
|
regmmatch_T regmatch;
|
||||||
@ -3137,10 +3138,10 @@ static 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;
|
||||||
|
bool preview = (State & CMDPREVIEW);
|
||||||
|
|
||||||
if (!global_busy) {
|
if (!global_busy) {
|
||||||
sub_nsubs = 0;
|
sub_nsubs = 0;
|
||||||
@ -3208,7 +3209,7 @@ static buf_T *do_sub(exarg_T *eap)
|
|||||||
mb_ptr_adv(cmd);
|
mb_ptr_adv(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!eap->skip && !eap->is_live) {
|
if (!eap->skip && !preview) {
|
||||||
sub_set_replacement((SubReplacementString) {
|
sub_set_replacement((SubReplacementString) {
|
||||||
.sub = xstrdup((char *) sub),
|
.sub = xstrdup((char *) sub),
|
||||||
.timestamp = os_time(),
|
.timestamp = os_time(),
|
||||||
@ -3228,7 +3229,7 @@ static buf_T *do_sub(exarg_T *eap)
|
|||||||
endcolumn = (curwin->w_curswant == MAXCOL);
|
endcolumn = (curwin->w_curswant == MAXCOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sub_joining_lines(eap, pat, sub, cmd)) {
|
if (sub_joining_lines(eap, pat, sub, cmd, !preview)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3273,7 +3274,7 @@ static buf_T *do_sub(exarg_T *eap)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (search_regcomp(pat, RE_SUBST, which_pat, (eap->is_live ? 0 : SEARCH_HIS),
|
if (search_regcomp(pat, RE_SUBST, which_pat, (preview ? 0 : SEARCH_HIS),
|
||||||
®match) == FAIL) {
|
®match) == FAIL) {
|
||||||
if (subflags.do_error) {
|
if (subflags.do_error) {
|
||||||
EMSG(_(e_invcmd));
|
EMSG(_(e_invcmd));
|
||||||
@ -3403,7 +3404,7 @@ static buf_T *do_sub(exarg_T *eap)
|
|||||||
curwin->w_cursor.lnum = lnum;
|
curwin->w_cursor.lnum = lnum;
|
||||||
do_again = FALSE;
|
do_again = FALSE;
|
||||||
|
|
||||||
if (eap->is_live) {
|
if (preview) {
|
||||||
// Increment the in-line match count and store the column.
|
// Increment the in-line match count and store the column.
|
||||||
matched_line.nmatch++;
|
matched_line.nmatch++;
|
||||||
kv_push(matched_line.cols, regmatch.startpos[0].col);
|
kv_push(matched_line.cols, regmatch.startpos[0].col);
|
||||||
@ -3456,7 +3457,7 @@ static buf_T *do_sub(exarg_T *eap)
|
|||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subflags.do_ask && !eap->is_live) {
|
if (subflags.do_ask && !preview) {
|
||||||
int typed = 0;
|
int typed = 0;
|
||||||
|
|
||||||
/* change State to CONFIRM, so that the mouse works
|
/* change State to CONFIRM, so that the mouse works
|
||||||
@ -3627,9 +3628,9 @@ static buf_T *do_sub(exarg_T *eap)
|
|||||||
* use "\=col("."). */
|
* use "\=col("."). */
|
||||||
curwin->w_cursor.col = regmatch.startpos[0].col;
|
curwin->w_cursor.col = regmatch.startpos[0].col;
|
||||||
|
|
||||||
// 3. Substitute the string. During 'inccommand' only do this if there
|
// 3. Substitute the string. During 'inccommand' preview only do this if
|
||||||
// is a replace pattern.
|
// there is a replace pattern.
|
||||||
if (!eap->is_live || has_second_delim) {
|
if (!preview || has_second_delim) {
|
||||||
if (subflags.do_count) {
|
if (subflags.do_count) {
|
||||||
// prevent accidentally changing the buffer by a function
|
// prevent accidentally changing the buffer by a function
|
||||||
save_ma = curbuf->b_p_ma;
|
save_ma = curbuf->b_p_ma;
|
||||||
@ -3873,7 +3874,7 @@ skip:
|
|||||||
xfree(sub_firstline); /* free the copy of the original line */
|
xfree(sub_firstline); /* free the copy of the original line */
|
||||||
sub_firstline = NULL;
|
sub_firstline = NULL;
|
||||||
|
|
||||||
if (eap->is_live) {
|
if (preview) {
|
||||||
matched_line.lnum = lnum;
|
matched_line.lnum = lnum;
|
||||||
matched_line.line = vim_strsave(ml_get(lnum));
|
matched_line.line = vim_strsave(ml_get(lnum));
|
||||||
kv_push(matched_lines, matched_line);
|
kv_push(matched_lines, matched_line);
|
||||||
@ -3917,7 +3918,7 @@ skip:
|
|||||||
beginline(BL_WHITE | BL_FIX);
|
beginline(BL_WHITE | BL_FIX);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!eap->is_live && !do_sub_msg(subflags.do_count) && subflags.do_ask) {
|
if (!preview && !do_sub_msg(subflags.do_count) && subflags.do_ask) {
|
||||||
MSG("");
|
MSG("");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -3952,7 +3953,7 @@ 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 && !aborting()) {
|
if (preview && !aborting()) {
|
||||||
if (got_quit) { // Substitution is too slow, disable 'inccommand'.
|
if (got_quit) { // Substitution is too slow, disable 'inccommand'.
|
||||||
set_string_option_direct((char_u *)"icm", -1, (char_u *)"", OPT_FREE,
|
set_string_option_direct((char_u *)"icm", -1, (char_u *)"", OPT_FREE,
|
||||||
SID_NONE);
|
SID_NONE);
|
||||||
@ -6122,8 +6123,9 @@ static buf_T *show_sub(exarg_T *eap, pos_T old_cusr, char_u *pat, char_u *sub,
|
|||||||
/// from undo history.
|
/// from undo history.
|
||||||
void ex_substitute(exarg_T *eap)
|
void ex_substitute(exarg_T *eap)
|
||||||
{
|
{
|
||||||
if (*p_icm == NUL || !eap->is_live) { // 'inccommand' is disabled
|
bool preview = (State & CMDPREVIEW);
|
||||||
(void)do_sub(eap);
|
if (*p_icm == NUL || !preview) { // 'inccommand' is disabled
|
||||||
|
(void)do_sub(eap, profile_zero());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6145,7 +6147,7 @@ void ex_substitute(exarg_T *eap)
|
|||||||
curwin->w_p_cul = false; // Disable 'cursorline'
|
curwin->w_p_cul = false; // Disable 'cursorline'
|
||||||
curwin->w_p_cuc = false; // Disable 'cursorcolumn'
|
curwin->w_p_cuc = false; // Disable 'cursorcolumn'
|
||||||
|
|
||||||
buf_T *preview_buf = do_sub(eap);
|
buf_T *preview_buf = do_sub(eap, profile_setlimit(p_rdt));
|
||||||
|
|
||||||
if (save_changedtick != curbuf->b_changedtick) {
|
if (save_changedtick != curbuf->b_changedtick) {
|
||||||
// Undo invisibly. This also moves the cursor!
|
// Undo invisibly. This also moves the cursor!
|
||||||
|
@ -124,7 +124,6 @@ struct exarg {
|
|||||||
LineGetter getline; ///< Function used to get the next line
|
LineGetter getline; ///< Function used to get the next line
|
||||||
void *cookie; ///< argument for getline()
|
void *cookie; ///< argument for getline()
|
||||||
struct condstack *cstack; ///< condition stack for ":if" etc.
|
struct condstack *cstack; ///< condition stack for ":if" etc.
|
||||||
bool is_live; ///< 'inccommand' live preview
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FORCE_BIN 1 // ":edit ++bin file"
|
#define FORCE_BIN 1 // ":edit ++bin file"
|
||||||
|
@ -1248,7 +1248,6 @@ static char_u * do_one_cmd(char_u **cmdlinep,
|
|||||||
memset(&ea, 0, sizeof(ea));
|
memset(&ea, 0, sizeof(ea));
|
||||||
ea.line1 = 1;
|
ea.line1 = 1;
|
||||||
ea.line2 = 1;
|
ea.line2 = 1;
|
||||||
ea.is_live = flags & DOCMD_LIVE;
|
|
||||||
ex_nesting_level++;
|
ex_nesting_level++;
|
||||||
|
|
||||||
/* When the last file has not been edited :q has to be typed twice. */
|
/* When the last file has not been edited :q has to be typed twice. */
|
||||||
@ -9648,12 +9647,12 @@ static void ex_terminal(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether commandline starts with a live command
|
/// Checks if `cmd` is "previewable" (i.e. supported by 'inccommand').
|
||||||
///
|
///
|
||||||
/// @param[in] cmd Commandline to check. May start with a range.
|
/// @param[in] cmd Commandline to check. May start with a range.
|
||||||
///
|
///
|
||||||
/// @return True if first command is a live command
|
/// @return true if `cmd` is previewable
|
||||||
bool cmd_is_live(char_u *cmd)
|
bool cmd_can_preview(char_u *cmd)
|
||||||
{
|
{
|
||||||
if (cmd == NULL) {
|
if (cmd == NULL) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
#define DOCMD_KEYTYPED 0x08 // don't reset KeyTyped
|
#define DOCMD_KEYTYPED 0x08 // don't reset KeyTyped
|
||||||
#define DOCMD_EXCRESET 0x10 // reset exception environment (for debugging
|
#define DOCMD_EXCRESET 0x10 // reset exception environment (for debugging
|
||||||
#define DOCMD_KEEPLINE 0x20 // keep typed line for repeating with "."
|
#define DOCMD_KEEPLINE 0x20 // keep typed line for repeating with "."
|
||||||
#define DOCMD_LIVE 0x40 // show updates as-you-type ("live" command)
|
|
||||||
|
|
||||||
/* defines for eval_vars() */
|
/* defines for eval_vars() */
|
||||||
#define VALID_PATH 1
|
#define VALID_PATH 1
|
||||||
|
@ -103,7 +103,6 @@ typedef struct command_line_state {
|
|||||||
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;
|
||||||
@ -400,8 +399,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1601,13 +1599,17 @@ static int command_line_changed(CommandLineState *s)
|
|||||||
&& *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_can_preview(ccline.cmdbuff)
|
||||||
&& !vpeekc_any()) {
|
&& !vpeekc_any()) {
|
||||||
s->live = true;
|
// Show 'inccommand' preview. It works like this:
|
||||||
// process a "live" command ('inccommand')
|
// 1. Do the command.
|
||||||
do_cmdline(ccline.cmdbuff, NULL, NULL, DOCMD_KEEPLINE|DOCMD_LIVE);
|
// 2. Command implementation detects CMDPREVIEW state, then:
|
||||||
|
// - Update the screen while the effects are in place.
|
||||||
|
// - Immediately undo the effects.
|
||||||
|
State |= CMDPREVIEW;
|
||||||
|
do_cmdline(ccline.cmdbuff, NULL, NULL, DOCMD_KEEPLINE|DOCMD_NOWAIT);
|
||||||
|
|
||||||
// restore the window "view"
|
// Restore the window "view".
|
||||||
curwin->w_cursor = s->old_cursor;
|
curwin->w_cursor = s->old_cursor;
|
||||||
curwin->w_curswant = s->old_curswant;
|
curwin->w_curswant = s->old_curswant;
|
||||||
curwin->w_leftcol = s->old_leftcol;
|
curwin->w_leftcol = s->old_leftcol;
|
||||||
@ -1617,8 +1619,8 @@ static int command_line_changed(CommandLineState *s)
|
|||||||
update_topline();
|
update_topline();
|
||||||
|
|
||||||
redrawcmdline();
|
redrawcmdline();
|
||||||
} else if (s->live) {
|
} else if (State & CMDPREVIEW) {
|
||||||
s->live = false;
|
State = (State & ~CMDPREVIEW);
|
||||||
update_screen(SOME_VALID); // Clear 'inccommand' preview.
|
update_screen(SOME_VALID); // Clear 'inccommand' preview.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -955,7 +955,6 @@ static void invalidate_terminal(Terminal *term, int start_row, int end_row)
|
|||||||
|
|
||||||
static void refresh_terminal(Terminal *term)
|
static void refresh_terminal(Terminal *term)
|
||||||
{
|
{
|
||||||
// TODO(SplinterOfChaos): Find the condition that makes term->buf invalid.
|
|
||||||
buf_T *buf = handle_get_buffer(term->buf_handle);
|
buf_T *buf = handle_get_buffer(term->buf_handle);
|
||||||
bool valid = true;
|
bool valid = true;
|
||||||
if (!buf || !(valid = buf_valid(buf))) {
|
if (!buf || !(valid = buf_valid(buf))) {
|
||||||
|
@ -104,6 +104,7 @@ Error: configure did not run properly.Check auto/config.log.
|
|||||||
#define CONFIRM 0x800 /* ":confirm" prompt */
|
#define CONFIRM 0x800 /* ":confirm" prompt */
|
||||||
#define SELECTMODE 0x1000 /* Select mode, only for mappings */
|
#define SELECTMODE 0x1000 /* Select mode, only for mappings */
|
||||||
#define TERM_FOCUS 0x2000 // Terminal focus mode
|
#define TERM_FOCUS 0x2000 // Terminal focus mode
|
||||||
|
#define CMDPREVIEW 0x4000 // Showing 'inccommand' command "live" preview.
|
||||||
|
|
||||||
// all mode bits used for mapping
|
// all mode bits used for mapping
|
||||||
#define MAP_ALL_MODES (0x3f | SELECTMODE | TERM_FOCUS)
|
#define MAP_ALL_MODES (0x3f | SELECTMODE | TERM_FOCUS)
|
||||||
|
Loading…
Reference in New Issue
Block a user