aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/buffer.c12
-rw-r--r--src/nvim/ex_cmds.c71
-rw-r--r--src/nvim/ex_cmds.h1
-rw-r--r--src/nvim/ex_docmd.c10
-rw-r--r--src/nvim/ex_getln.c14
-rw-r--r--src/nvim/undo.c3
6 files changed, 59 insertions, 52 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 75caf2223b..8e6066453c 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -5273,14 +5273,20 @@ wipe_buffer (
}
}
-/// Creates or switches to a special-purpose buffer.
+/// Creates or switches to a scratch buffer. :h special-buffers
+/// Scratch buffer is:
+/// - buftype=nofile bufhidden=hide noswapfile
+/// - Always considered 'nomodified'
///
/// @param bufnr Buffer to switch to, or 0 to create a new buffer.
-void buf_open_special(handle_T bufnr, char *bufname, char *buftype)
+///
+/// @see curbufIsChanged()
+void buf_open_scratch(handle_T bufnr, char *bufname)
{
(void)do_ecmd((int)bufnr, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL);
(void)setfname(curbuf, (char_u *)bufname, NULL, true);
- set_option_value((char_u *)"bt", 0L, (char_u *)buftype, OPT_LOCAL);
+ set_option_value((char_u *)"bh", 0L, (char_u *)"hide", OPT_LOCAL);
+ set_option_value((char_u *)"bt", 0L, (char_u *)"nofile", OPT_LOCAL);
set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
RESET_BINDING(curwin);
}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 13a0282b76..66b6aa2f46 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -2188,7 +2188,6 @@ int do_ecmd(
if (fnum) {
buf = buflist_findnr(fnum);
} else {
- ILOG("here");
if (flags & ECMD_ADDBUF) {
linenr_T tlnum = 1L;
@@ -3275,8 +3274,7 @@ buf_T *do_sub(exarg_T *eap)
return NULL;
}
- int search_options = eap->is_live ? 0 : SEARCH_HIS;
- if (search_regcomp(pat, RE_SUBST, which_pat, search_options,
+ if (search_regcomp(pat, RE_SUBST, which_pat, (eap->is_live ? 0 : SEARCH_HIS),
&regmatch) == FAIL) {
if (subflags.do_error) {
EMSG(_(e_invcmd));
@@ -3951,13 +3949,9 @@ skip:
// Show 'inccommand' preview if there are matched lines.
buf_T *preview_buf = NULL;
- if (eap->is_live && matched_lines.size != 0 && pat != NULL && *p_icm != NUL) {
+ 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(old_cursor, pat, sub, eap->line1, eap->line2,
- &matched_lines);
-
- } else if (*p_icm != NUL && eap->is_live) {
- curwin->w_cursor = old_cursor; // don't move the cursor
+ preview_buf = show_sub(eap, old_cursor, pat, sub, &matched_lines);
}
for (MatchedLine m; kv_size(matched_lines);) {
@@ -6004,8 +5998,8 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg)
/// Shows the effects of the :substitute command being typed ('inccommand').
/// If inccommand=split, shows a preview window and later restores the layout.
-static buf_T *show_sub(pos_T old_cusr, char_u *pat, char_u *sub, linenr_T line1,
- linenr_T line2, MatchedLineVec *matched_lines)
+static buf_T *show_sub(exarg_T *eap, pos_T old_cusr, char_u *pat, char_u *sub,
+ MatchedLineVec *matched_lines)
FUNC_ATTR_NONNULL_ALL
{
static handle_T bufnr = 0; // special buffer, re-used on each visit
@@ -6025,49 +6019,35 @@ static buf_T *show_sub(pos_T old_cusr, char_u *pat, char_u *sub, linenr_T line1,
// disable file info message
set_option_value((char_u *)"shm", 0L, (char_u *)"F", 0);
- bool outside_curline = (line1 != curwin->w_cursor.lnum
- || line2 != curwin->w_cursor.lnum);
+ bool outside_curline = (eap->line1 != old_cusr.lnum
+ || eap->line2 != old_cusr.lnum);
bool split = outside_curline && (*p_icm != 'n') && (sub_size || pat_size);
if (preview_buf == curbuf) { // Preview buffer cannot preview itself!
split = false;
preview_buf = NULL;
}
- // Place cursor on the first match after the cursor. (If all matches are
- // above, then do_sub already placed cursor on the last match.)
- colnr_T cur_col = -1;
- MatchedLine curmatch;
- for (size_t j = 0; j < matched_lines->size && cur_col == -1; j++) {
- curmatch = matched_lines->items[j];
- if (curmatch.lnum == old_cusr.lnum) {
- // On cursor line; iterate in-line matches to find one after cursor.
- for (size_t i = 0; i < curmatch.cols.size; i++) {
- if (curmatch.cols.items[i] >= old_cusr.col) {
- cur_col = curmatch.cols.items[i];
- curwin->w_cursor.lnum = curmatch.lnum;
- curwin->w_cursor.col = cur_col;
- break;
- }
- }
- } else if (curmatch.lnum > old_cusr.lnum) {
- // After cursor; put cursor on first match there.
- cur_col = curmatch.cols.items[0];
+ // Place cursor on nearest matching line, to undo do_sub() cursor placement.
+ for (size_t i = 0; i < matched_lines->size; i++) {
+ MatchedLine curmatch = matched_lines->items[i];
+ if (curmatch.lnum >= old_cusr.lnum) {
curwin->w_cursor.lnum = curmatch.lnum;
- curwin->w_cursor.col = cur_col;
- }
+ curwin->w_cursor.col = curmatch.cols.items[0];
+ break;
+ } // Else: All matches are above, do_sub() already placed cursor.
}
if (split && win_split((int)p_cwh, WSP_BOT) != FAIL) {
- buf_open_special(preview_buf ? bufnr : 0, "[Preview]", "incsub");
+ buf_open_scratch(preview_buf ? bufnr : 0, "[Preview]");
buf_clear();
preview_buf = curbuf;
- set_option_value((char_u *)"bufhidden", 0L, (char_u *)"hide", OPT_LOCAL);
bufnr = preview_buf->handle;
curbuf->b_p_bl = false;
curbuf->b_p_ma = true;
curbuf->b_p_ul = -1;
curbuf->b_p_tw = 0; // Reset 'textwidth' (was set by ftplugin)
curwin->w_p_cul = false;
+ curwin->w_p_cuc = false;
curwin->w_p_spell = false;
curwin->w_p_fen = false;
@@ -6092,7 +6072,7 @@ static buf_T *show_sub(pos_T old_cusr, char_u *pat, char_u *sub, linenr_T line1,
old_line_size = line_size;
}
- // put " | lnum|line" into str and append it to the preview buffer
+ // Put "|lnum| line" into `str` and append it to the preview buffer.
snprintf(str, line_size, "|%*ld| %s", col_width - 3, mat.lnum, mat.line);
ml_append(line, (char_u *)str, (colnr_T)line_size, false);
@@ -6132,8 +6112,8 @@ static buf_T *show_sub(pos_T old_cusr, char_u *pat, char_u *sub, linenr_T line1,
/// :substitute command
///
-/// If 'inccommand' is empty this just calls do_sub().
-/// If 'inccommand' is set, shows a "live" preview then removes the changes
+/// If 'inccommand' is empty: calls do_sub().
+/// If 'inccommand' is set: shows a "live" preview then removes the changes.
/// from undo history.
void ex_substitute(exarg_T *eap)
{
@@ -6142,19 +6122,26 @@ void ex_substitute(exarg_T *eap)
return;
}
+ block_autocmds(); // Disable events during command preview.
+
char_u *save_eap = eap->arg;
save_search_patterns();
int save_changedtick = curbuf->b_changedtick;
time_t save_b_u_time_cur = curbuf->b_u_time_cur;
u_header_T *save_b_u_newhead = curbuf->b_u_newhead;
long save_b_p_ul = curbuf->b_p_ul;
+ int save_w_p_cul = curwin->w_p_cul;
+ int save_w_p_cuc = curwin->w_p_cuc;
+
+ emsg_off++; // No error messages during command preview.
curbuf->b_p_ul = LONG_MAX; // make sure we can undo all changes
- block_autocmds(); // disable events before show_sub() opens window/buffer
- emsg_off++; // No error messages for live commands
+ curwin->w_p_cul = false; // Disable 'cursorline'
+ curwin->w_p_cuc = false; // Disable 'cursorcolumn'
buf_T *preview_buf = do_sub(eap);
if (save_changedtick != curbuf->b_changedtick) {
+ // Undo invisibly. This also moves the cursor!
if (!u_undo_and_forget(1)) { abort(); }
// Restore newhead. It is meaningless when curhead is valid, but we must
// restore it so that undotree() is identical before/after the preview.
@@ -6167,6 +6154,8 @@ void ex_substitute(exarg_T *eap)
close_windows(preview_buf, false);
}
curbuf->b_p_ul = save_b_p_ul;
+ curwin->w_p_cul = save_w_p_cul; // Restore 'cursorline'
+ curwin->w_p_cuc = save_w_p_cuc; // Restore 'cursorcolumn'
eap->arg = save_eap;
restore_search_patterns();
emsg_off--;
diff --git a/src/nvim/ex_cmds.h b/src/nvim/ex_cmds.h
index ccb2202edb..243b11255e 100644
--- a/src/nvim/ex_cmds.h
+++ b/src/nvim/ex_cmds.h
@@ -14,7 +14,6 @@
#define ECMD_OLDBUF 0x04 // use existing buffer if it exists
#define ECMD_FORCEIT 0x08 // ! used in Ex command
#define ECMD_ADDBUF 0x10 // don't edit, just add to buffer list
-#define ECMD_RESERVED_BUFNR 0x20 // bufnr argument is reserved bufnr
/* for lnum argument in do_ecmd() */
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 30347cbe85..07e0fa8844 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -7295,15 +7295,13 @@ void ex_may_print(exarg_T *eap)
}
}
-/*
- * ":smagic" and ":snomagic".
- */
+/// ":smagic" and ":snomagic".
static void ex_submagic(exarg_T *eap)
{
int magic_save = p_magic;
p_magic = (eap->cmdidx == CMD_smagic);
- do_sub(eap);
+ ex_substitute(eap);
p_magic = magic_save;
}
@@ -9669,5 +9667,7 @@ bool cmd_is_live(char_u *cmd)
}
find_command(&ea, NULL);
- return (ea.cmdidx == CMD_substitute);
+ return ea.cmdidx == CMD_substitute
+ || ea.cmdidx == CMD_smagic
+ || ea.cmdidx == CMD_snomagic;
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 17693ecfc8..c4169f03f0 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -1599,6 +1599,16 @@ static int command_line_changed(CommandLineState *s)
&& cmd_is_live(ccline.cmdbuff)) {
// process a "live" command ('inccommand')
do_cmdline(ccline.cmdbuff, NULL, NULL, DOCMD_KEEPLINE|DOCMD_LIVE);
+
+ // restore the window "view"
+ curwin->w_cursor = s->old_cursor;
+ curwin->w_curswant = s->old_curswant;
+ curwin->w_leftcol = s->old_leftcol;
+ curwin->w_topline = s->old_topline;
+ curwin->w_topfill = s->old_topfill;
+ curwin->w_botline = s->old_botline;
+ update_topline();
+
redrawcmdline();
}
@@ -5147,7 +5157,9 @@ static int ex_window(void)
cmdwin_type = get_cmdline_type();
// Create empty command-line buffer.
- buf_open_special(0, "[Command Line]", "nofile");
+ buf_open_scratch(0, "[Command Line]");
+ // Command-line buffer has bufhidden=wipe, unlike a true "scratch" buffer.
+ set_option_value((char_u *)"bh", 0L, (char_u *)"wipe", OPT_LOCAL);
curwin->w_p_rl = cmdmsg_rl;
cmdmsg_rl = false;
curbuf->b_p_ma = true;
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 2f4317980a..d6428d63f7 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -1685,7 +1685,8 @@ void u_redo(int count)
u_doit(count, false);
}
-/// undo, and remove the undo branch from the undo tree.
+/// Undo and remove the branch from the undo tree.
+/// Also moves the cursor (as a "normal" undo would).
bool u_undo_and_forget(int count)
{
if (curbuf->b_u_synced == false) {