aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/normal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/normal.c')
-rw-r--r--src/nvim/normal.c476
1 files changed, 268 insertions, 208 deletions
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index e7e6d2b365..968cfde388 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -24,7 +24,7 @@
#include "nvim/diff.h"
#include "nvim/digraph.h"
#include "nvim/edit.h"
-#include "nvim/eval.h"
+#include "nvim/eval/userfunc.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
@@ -615,14 +615,19 @@ static void normal_redraw_mode_message(NormalState *s)
kmsg = keep_msg;
keep_msg = NULL;
- // showmode() will clear keep_msg, but we want to use it anyway
+ // Showmode() will clear keep_msg, but we want to use it anyway.
+ // First update w_topline.
+ setcursor();
update_screen(0);
// now reset it, otherwise it's put in the history again
keep_msg = kmsg;
+
+ kmsg = vim_strsave(keep_msg);
msg_attr((const char *)kmsg, keep_msg_attr);
xfree(kmsg);
}
setcursor();
+ ui_cursor_shape(); // show different cursor shape
ui_flush();
if (msg_scroll || emsg_on_display) {
os_delay(1000L, true); // wait at least one second
@@ -760,7 +765,7 @@ static void normal_get_additional_char(NormalState *s)
// because if it's put back with vungetc() it's too late to apply
// mapping.
no_mapping--;
- while (enc_utf8 && lang && (s->c = vpeekc()) > 0
+ while (lang && (s->c = vpeekc()) > 0
&& (s->c >= 0x100 || MB_BYTE2LEN(vpeekc()) > 1)) {
s->c = plain_vgetc();
if (!utf_iscomposing(s->c)) {
@@ -874,8 +879,10 @@ static void normal_finish_command(NormalState *s)
s->old_mapped_len = typebuf_maplen();
}
- // If an operation is pending, handle it...
- do_pending_operator(&s->ca, s->old_col, false);
+ // If an operation is pending, handle it. But not for K_IGNORE.
+ if (s->ca.cmdchar != K_IGNORE) {
+ do_pending_operator(&s->ca, s->old_col, false);
+ }
// Wait for a moment when a message is displayed that will be overwritten
// by the mode message.
@@ -1255,13 +1262,20 @@ static void normal_redraw(NormalState *s)
maketitle();
}
+ curbuf->b_last_used = time(NULL);
+
// Display message after redraw. If an external message is still visible,
// it contains the kept message already.
if (keep_msg != NULL && !msg_ext_is_visible()) {
- // msg_attr_keep() will set keep_msg to NULL, must free the string here.
- // Don't reset keep_msg, msg_attr_keep() uses it to check for duplicates.
- char *p = (char *)keep_msg;
- msg_attr(p, keep_msg_attr);
+ char_u *const p = vim_strsave(keep_msg);
+
+ // msg_start() will set keep_msg to NULL, make a copy
+ // first. Don't reset keep_msg, msg_attr_keep() uses it to
+ // check for duplicates. Never put this message in
+ // history.
+ msg_hist_off = true;
+ msg_attr((const char *)p, keep_msg_attr);
+ msg_hist_off = false;
xfree(p);
}
@@ -1422,12 +1436,12 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
if (oap->motion_type == kMTLineWise) {
oap->inclusive = false;
} else if (oap->motion_type == kMTCharWise) {
- // If the motion already was characterwise, toggle "inclusive"
+ // If the motion already was charwise, toggle "inclusive"
oap->inclusive = !oap->inclusive;
}
oap->motion_type = kMTCharWise;
} else if (oap->motion_force == Ctrl_V) {
- // Change line- or characterwise motion into Visual block mode.
+ // Change line- or charwise motion into Visual block mode.
if (!VIsual_active) {
VIsual_active = true;
VIsual = oap->start;
@@ -1516,7 +1530,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
}
// In Select mode, a linewise selection is operated upon like a
- // characterwise selection.
+ // charwise selection.
// Special case: gH<Del> deletes the last line.
if (VIsual_select && VIsual_mode == 'V'
&& cap->oap->op_type != OP_DELETE) {
@@ -1553,9 +1567,13 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
if (!VIsual_active) {
if (hasFolding(oap->start.lnum, &oap->start.lnum, NULL))
oap->start.col = 0;
- if (hasFolding(curwin->w_cursor.lnum, NULL,
- &curwin->w_cursor.lnum))
+ if ((curwin->w_cursor.col > 0
+ || oap->inclusive
+ || oap->motion_type == kMTLineWise)
+ && hasFolding(curwin->w_cursor.lnum, NULL,
+ &curwin->w_cursor.lnum)) {
curwin->w_cursor.col = (colnr_T)STRLEN(get_cursor_line_ptr());
+ }
}
oap->end = curwin->w_cursor;
curwin->w_cursor = oap->start;
@@ -1705,13 +1723,12 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
}
}
- /* Include the trailing byte of a multi-byte char. */
- if (has_mbyte && oap->inclusive) {
- int l;
-
- l = (*mb_ptr2len)(ml_get_pos(&oap->end));
- if (l > 1)
+ // Include the trailing byte of a multi-byte char.
+ if (oap->inclusive) {
+ const int l = utfc_ptr2len(ml_get_pos(&oap->end));
+ if (l > 1) {
oap->end.col += l - 1;
+ }
}
curwin->w_set_curswant = true;
@@ -1840,10 +1857,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
restart_edit = 0;
// Restore linebreak, so that when the user edits it looks as before.
- if (curwin->w_p_lbr != lbr_saved) {
- curwin->w_p_lbr = lbr_saved;
- get_op_vcol(oap, redo_VIsual_mode, false);
- }
+ curwin->w_p_lbr = lbr_saved;
// Reset finish_op now, don't want it set inside edit().
finish_op = false;
@@ -1929,10 +1943,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
restart_edit = 0;
// Restore linebreak, so that when the user edits it looks as before.
- if (curwin->w_p_lbr != lbr_saved) {
- curwin->w_p_lbr = lbr_saved;
- get_op_vcol(oap, redo_VIsual_mode, false);
- }
+ curwin->w_p_lbr = lbr_saved;
op_insert(oap, cap->count1);
@@ -1958,18 +1969,15 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
CancelRedo();
} else {
// Restore linebreak, so that when the user edits it looks as before.
- if (curwin->w_p_lbr != lbr_saved) {
- curwin->w_p_lbr = lbr_saved;
- get_op_vcol(oap, redo_VIsual_mode, false);
- }
+ curwin->w_p_lbr = lbr_saved;
op_replace(oap, cap->nchar);
}
break;
case OP_FOLD:
- VIsual_reselect = false; /* don't reselect now */
- foldCreate(oap->start.lnum, oap->end.lnum);
+ VIsual_reselect = false; // don't reselect now
+ foldCreate(curwin, oap->start.lnum, oap->end.lnum);
break;
case OP_FOLDOPEN:
@@ -1987,9 +1995,9 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
case OP_FOLDDEL:
case OP_FOLDDELREC:
- VIsual_reselect = false; /* don't reselect now */
- deleteFold(oap->start.lnum, oap->end.lnum,
- oap->op_type == OP_FOLDDELREC, oap->is_VIsual);
+ VIsual_reselect = false; // don't reselect now
+ deleteFold(curwin, oap->start.lnum, oap->end.lnum,
+ oap->op_type == OP_FOLDDELREC, oap->is_VIsual);
break;
case OP_NR_ADD:
@@ -2560,7 +2568,14 @@ do_mouse (
* JUMP!
*/
jump_flags = jump_to_mouse(jump_flags,
- oap == NULL ? NULL : &(oap->inclusive), which_button);
+ oap == NULL ? NULL : &(oap->inclusive),
+ which_button);
+
+ // A click in the window toolbar has no side effects.
+ if (jump_flags & MOUSE_WINBAR) {
+ return false;
+ }
+
moved = (jump_flags & CURSOR_MOVED);
in_status_line = (jump_flags & IN_STATUS_LINE);
in_sep_line = (jump_flags & IN_SEP_LINE);
@@ -2588,12 +2603,13 @@ do_mouse (
/* Set global flag that we are extending the Visual area with mouse
* dragging; temporarily minimize 'scrolloff'. */
- if (VIsual_active && is_drag && p_so) {
- /* In the very first line, allow scrolling one line */
- if (mouse_row == 0)
+ if (VIsual_active && is_drag && get_scrolloff_value()) {
+ // In the very first line, allow scrolling one line
+ if (mouse_row == 0) {
mouse_dragging = 2;
- else
+ } else {
mouse_dragging = 1;
+ }
}
/* When dragging the mouse above the window, scroll down. */
@@ -2900,17 +2916,17 @@ static void find_end_of_word(pos_T *pos)
*/
static int get_mouse_class(char_u *p)
{
- int c;
-
- if (has_mbyte && MB_BYTE2LEN(p[0]) > 1)
+ if (MB_BYTE2LEN(p[0]) > 1) {
return mb_get_class(p);
+ }
- c = *p;
- if (c == ' ' || c == '\t')
+ const int c = *p;
+ if (c == ' ' || c == '\t') {
return 0;
-
- if (vim_iswordc(c))
+ }
+ if (vim_iswordc(c)) {
return 2;
+ }
/*
* There are a few special cases where we want certain combinations of
@@ -3646,7 +3662,9 @@ static void nv_help(cmdarg_T *cap)
*/
static void nv_addsub(cmdarg_T *cap)
{
- if (!VIsual_active && cap->oap->op_type == OP_NOP) {
+ if (bt_prompt(curbuf) && !prompt_curpos_editable()) {
+ clearopbeep(cap->oap);
+ } else if (!VIsual_active && cap->oap->op_type == OP_NOP) {
prep_redo_cmd(cap);
cap->oap->op_type = cap->cmdchar == Ctrl_A ? OP_NR_ADD : OP_NR_SUB;
op_addsub(cap->oap, cap->count1, cap->arg);
@@ -3754,7 +3772,6 @@ find_decl (
bool retval = true;
bool incll;
int searchflags = flags_arg;
- bool valid;
pat = xmalloc(len + 7);
@@ -3789,10 +3806,8 @@ find_decl (
/* Search forward for the identifier, ignore comment lines. */
clearpos(&found_pos);
for (;; ) {
- valid = false;
- (void)valid; // Avoid "dead assignment" warning.
t = searchit(curwin, curbuf, &curwin->w_cursor, NULL, FORWARD,
- pat, 1L, searchflags, RE_LAST, (linenr_T)0, NULL, NULL);
+ pat, 1L, searchflags, RE_LAST, NULL);
if (curwin->w_cursor.lnum >= old_pos.lnum) {
t = false; // match after start is failure too
}
@@ -3825,7 +3840,7 @@ find_decl (
curwin->w_cursor.col = 0;
continue;
}
- valid = is_ident(get_cursor_line_ptr(), curwin->w_cursor.col);
+ bool valid = is_ident(get_cursor_line_ptr(), curwin->w_cursor.col);
// If the current position is not a valid identifier and a previous match is
// present, favor that one instead.
@@ -3923,18 +3938,20 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist)
n = ((linelen - width1 - 1) / width2 + 1) * width2 + width1;
else
n = width1;
- if (curwin->w_curswant > (colnr_T)n + 1)
- curwin->w_curswant -= ((curwin->w_curswant - n) / width2 + 1)
- * width2;
+ if (curwin->w_curswant >= n) {
+ curwin->w_curswant = n - 1;
+ }
}
while (dist--) {
if (dir == BACKWARD) {
- if ((long)curwin->w_curswant >= width2)
- /* move back within line */
+ if (curwin->w_curswant >= width1) {
+ // Move back within the line. This can give a negative value
+ // for w_curswant if width1 < width2 (with cpoptions+=n),
+ // which will get clipped to column 0.
curwin->w_curswant -= width2;
- else {
- /* to previous line */
+ } else {
+ // to previous line
if (curwin->w_cursor.lnum == 1) {
retval = false;
break;
@@ -3971,6 +3988,13 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist)
}
curwin->w_cursor.lnum++;
curwin->w_curswant %= width2;
+ // Check if the cursor has moved below the number display
+ // when width1 < width2 (with cpoptions+=n). Subtract width2
+ // to get a negative value for w_curswant, which will get
+ // clipped to column 0.
+ if (curwin->w_curswant >= width1) {
+ curwin->w_curswant -= width2;
+ }
linelen = linetabsize(get_cursor_line_ptr());
}
}
@@ -4085,9 +4109,9 @@ void scroll_redraw(int up, long count)
scrollup(count, true);
else
scrolldown(count, true);
- if (p_so) {
- /* Adjust the cursor position for 'scrolloff'. Mark w_topline as
- * valid, otherwise the screen jumps back at the end of the file. */
+ if (get_scrolloff_value()) {
+ // Adjust the cursor position for 'scrolloff'. Mark w_topline as
+ // valid, otherwise the screen jumps back at the end of the file.
cursor_correct();
check_cursor_moved(curwin);
curwin->w_valid |= VALID_TOPLINE;
@@ -4116,6 +4140,7 @@ void scroll_redraw(int up, long count)
}
if (curwin->w_cursor.lnum != prev_lnum)
coladvance(curwin->w_curswant);
+ curwin->w_viewport_invalid = true;
redraw_later(VALID);
}
@@ -4131,8 +4156,8 @@ static void nv_zet(cmdarg_T *cap)
int old_fen = curwin->w_p_fen;
bool undo = false;
- assert(p_siso <= INT_MAX);
- int l_p_siso = (int)p_siso;
+ int l_p_siso = (int)get_sidescrolloff_value();
+ assert(l_p_siso <= INT_MAX);
if (ascii_isdigit(nchar)) {
/*
@@ -4336,11 +4361,12 @@ dozet:
/* "zD": delete fold at cursor recursively */
case 'd':
case 'D': if (foldManualAllowed(false)) {
- if (VIsual_active)
+ if (VIsual_active) {
nv_operator(cap);
- else
- deleteFold(curwin->w_cursor.lnum,
- curwin->w_cursor.lnum, nchar == 'D', false);
+ } else {
+ deleteFold(curwin, curwin->w_cursor.lnum,
+ curwin->w_cursor.lnum, nchar == 'D', false);
+ }
}
break;
@@ -4348,11 +4374,11 @@ dozet:
case 'E': if (foldmethodIsManual(curwin)) {
clearFolding(curwin);
changed_window_setting();
- } else if (foldmethodIsMarker(curwin))
- deleteFold((linenr_T)1, curbuf->b_ml.ml_line_count,
- true, false);
- else
+ } else if (foldmethodIsMarker(curwin)) {
+ deleteFold(curwin, (linenr_T)1, curbuf->b_ml.ml_line_count, true, false);
+ } else {
EMSG(_("E352: Cannot erase folds with current 'foldmethod'"));
+ }
break;
/* "zn": fold none: reset 'foldenable' */
@@ -4454,16 +4480,16 @@ dozet:
case 'r':
curwin->w_p_fdl += cap->count1;
{
- int d = getDeepestNesting();
+ int d = getDeepestNesting(curwin);
if (curwin->w_p_fdl >= d) {
curwin->w_p_fdl = d;
}
}
break;
- /* "zR": open all folds */
- case 'R': curwin->w_p_fdl = getDeepestNesting();
- old_fdl = -1; /* force an update */
+ case 'R': // "zR": open all folds
+ curwin->w_p_fdl = getDeepestNesting(curwin);
+ old_fdl = -1; // force an update
break;
case 'j': /* "zj" move to next fold downwards */
@@ -4577,7 +4603,7 @@ static void nv_colon(cmdarg_T *cap)
nv_operator(cap);
} else {
if (cap->oap->op_type != OP_NOP) {
- // Using ":" as a movement is characterwise exclusive.
+ // Using ":" as a movement is charwise exclusive.
cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
} else if (cap->count0 && !is_cmdkey) {
@@ -4678,9 +4704,8 @@ static void nv_ctrlo(cmdarg_T *cap)
}
}
-/*
- * CTRL-^ command, short for ":e #"
- */
+// CTRL-^ command, short for ":e #". Works even when the alternate buffer is
+// not named.
static void nv_hat(cmdarg_T *cap)
{
if (!checkclearopq(cap->oap))
@@ -4905,10 +4930,9 @@ static void nv_ident(cmdarg_T *cap)
*p++ = '\\';
/* When current byte is a part of multibyte character, copy all
* bytes of that character. */
- if (has_mbyte) {
- size_t len = (size_t)((*mb_ptr2len)(ptr) - 1);
- for (size_t i = 0; i < len && n > 0; ++i, --n)
- *p++ = *ptr++;
+ const size_t len = (size_t)(utfc_ptr2len(ptr) - 1);
+ for (size_t i = 0; i < len && n > 0; i++, n--) {
+ *p++ = *ptr++;
}
*p++ = *ptr++;
}
@@ -4919,16 +4943,19 @@ static void nv_ident(cmdarg_T *cap)
* Execute the command.
*/
if (cmdchar == '*' || cmdchar == '#') {
- if (!g_cmd && (
- has_mbyte ? vim_iswordp(mb_prevptr(get_cursor_line_ptr(), ptr)) :
- vim_iswordc(ptr[-1])))
+ if (!g_cmd
+ && vim_iswordp(mb_prevptr(get_cursor_line_ptr(), ptr))) {
STRCAT(buf, "\\>");
- /* put pattern in search history */
+ }
+ // put pattern in search history
init_history();
add_to_history(HIST_SEARCH, (char_u *)buf, true, NUL);
- (void)normal_search(cap, cmdchar == '*' ? '/' : '?', (char_u *)buf, 0);
+ (void)normal_search(cap, cmdchar == '*' ? '/' : '?', (char_u *)buf, 0,
+ NULL);
} else {
+ g_tag_at_cursor = true;
do_cmdline_cmd(buf);
+ g_tag_at_cursor = false;
}
xfree(buf);
@@ -4963,9 +4990,8 @@ get_visual_text (
*pp = ml_get_pos(&VIsual);
*lenp = (size_t)curwin->w_cursor.col - (size_t)VIsual.col + 1;
}
- if (has_mbyte)
- /* Correct the length to include the whole last character. */
- *lenp += (size_t)((*mb_ptr2len)(*pp + (*lenp - 1)) - 1);
+ // Correct the length to include the whole last character.
+ *lenp += (size_t)(utfc_ptr2len(*pp + (*lenp - 1)) - 1);
}
reset_VIsual_and_resel();
return true;
@@ -5125,14 +5151,10 @@ static void nv_right(cmdarg_T *cap)
break;
} else if (PAST_LINE) {
curwin->w_set_curswant = true;
- if (virtual_active())
+ if (virtual_active()) {
oneright();
- else {
- if (has_mbyte)
- curwin->w_cursor.col +=
- (*mb_ptr2len)(get_cursor_pos_ptr());
- else
- ++curwin->w_cursor.col;
+ } else {
+ curwin->w_cursor.col += (*mb_ptr2len)(get_cursor_pos_ptr());
}
}
}
@@ -5187,11 +5209,7 @@ static void nv_left(cmdarg_T *cap)
char_u *cp = get_cursor_pos_ptr();
if (*cp != NUL) {
- if (has_mbyte) {
- curwin->w_cursor.col += (*mb_ptr2len)(cp);
- } else {
- curwin->w_cursor.col++;
- }
+ curwin->w_cursor.col += utfc_ptr2len(cp);
}
cap->retval |= CA_NO_ADJ_OP_END;
}
@@ -5245,6 +5263,13 @@ static void nv_down(cmdarg_T *cap)
// In the cmdline window a <CR> executes the command.
if (cmdwin_type != 0 && cap->cmdchar == CAR) {
cmdwin_result = CAR;
+ } else if (bt_prompt(curbuf) && cap->cmdchar == CAR
+ && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) {
+ // In a prompt buffer a <CR> in the last line invokes the callback.
+ invoke_prompt_callback();
+ if (restart_edit == 0) {
+ restart_edit = 'a';
+ }
} else {
cap->oap->motion_type = kMTLineWise;
if (cursor_down(cap->count1, cap->oap->op_type == OP_NOP) == false) {
@@ -5346,7 +5371,7 @@ static void nv_search(cmdarg_T *cap)
// When using 'incsearch' the cursor may be moved to set a different search
// start position.
- cap->searchbuf = getcmdline(cap->cmdchar, cap->count1, 0);
+ cap->searchbuf = getcmdline(cap->cmdchar, cap->count1, 0, true);
if (cap->searchbuf == NULL) {
clearop(oap);
@@ -5355,7 +5380,7 @@ static void nv_search(cmdarg_T *cap)
(void)normal_search(cap, cap->cmdchar, cap->searchbuf,
(cap->arg || !equalpos(save_cursor, curwin->w_cursor))
- ? 0 : SEARCH_MARK);
+ ? 0 : SEARCH_MARK, NULL);
}
/*
@@ -5365,14 +5390,15 @@ static void nv_search(cmdarg_T *cap)
static void nv_next(cmdarg_T *cap)
{
pos_T old = curwin->w_cursor;
- int i = normal_search(cap, 0, NULL, SEARCH_MARK | cap->arg);
+ int wrapped = false;
+ int i = normal_search(cap, 0, NULL, SEARCH_MARK | cap->arg, &wrapped);
- if (i == 1 && equalpos(old, curwin->w_cursor)) {
+ if (i == 1 && !wrapped && equalpos(old, curwin->w_cursor)) {
// Avoid getting stuck on the current cursor position, which can happen when
// an offset is given and the cursor is on the last char in the buffer:
// Repeat with count + 1.
cap->count1 += 1;
- (void)normal_search(cap, 0, NULL, SEARCH_MARK | cap->arg);
+ (void)normal_search(cap, 0, NULL, SEARCH_MARK | cap->arg, NULL);
cap->count1 -= 1;
}
}
@@ -5386,18 +5412,24 @@ static int normal_search(
cmdarg_T *cap,
int dir,
char_u *pat,
- int opt /* extra flags for do_search() */
+ int opt, // extra flags for do_search()
+ int *wrapped
)
{
int i;
+ searchit_arg_T sia;
cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
cap->oap->use_reg_one = true;
curwin->w_set_curswant = true;
+ memset(&sia, 0, sizeof(sia));
i = do_search(cap->oap, dir, pat, cap->count1,
- opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, NULL, NULL);
+ opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, &sia);
+ if (wrapped != NULL) {
+ *wrapped = sia.sa_wrapped;
+ }
if (i == 0) {
clearop(cap->oap);
} else {
@@ -5830,6 +5862,10 @@ static void nv_undo(cmdarg_T *cap)
static void nv_kundo(cmdarg_T *cap)
{
if (!checkclearopq(cap->oap)) {
+ if (bt_prompt(curbuf)) {
+ clearopbeep(cap->oap);
+ return;
+ }
u_undo((int)cap->count1);
curwin->w_set_curswant = true;
}
@@ -5842,10 +5878,14 @@ static void nv_replace(cmdarg_T *cap)
{
char_u *ptr;
int had_ctrl_v;
- long n;
- if (checkclearop(cap->oap))
+ if (checkclearop(cap->oap)) {
return;
+ }
+ if (bt_prompt(curbuf) && !prompt_curpos_editable()) {
+ clearopbeep(cap->oap);
+ return;
+ }
/* get another character */
if (cap->nchar == Ctrl_V) {
@@ -5896,7 +5936,7 @@ static void nv_replace(cmdarg_T *cap)
/* Abort if not enough characters to replace. */
ptr = get_cursor_pos_ptr();
if (STRLEN(ptr) < (unsigned)cap->count1
- || (has_mbyte && mb_charlen(ptr) < cap->count1)
+ || (mb_charlen(ptr) < cap->count1)
) {
clearopbeep(cap->oap);
return;
@@ -5938,71 +5978,44 @@ static void nv_replace(cmdarg_T *cap)
NUL, 'r', NUL, had_ctrl_v, cap->nchar);
curbuf->b_op_start = curwin->w_cursor;
- if (has_mbyte) {
- int old_State = State;
-
- if (cap->ncharC1 != 0)
- AppendCharToRedobuff(cap->ncharC1);
- if (cap->ncharC2 != 0)
- AppendCharToRedobuff(cap->ncharC2);
-
- /* This is slow, but it handles replacing a single-byte with a
- * multi-byte and the other way around. Also handles adding
- * composing characters for utf-8. */
- for (n = cap->count1; n > 0; --n) {
- State = REPLACE;
- if (cap->nchar == Ctrl_E || cap->nchar == Ctrl_Y) {
- int c = ins_copychar(curwin->w_cursor.lnum
- + (cap->nchar == Ctrl_Y ? -1 : 1));
- if (c != NUL)
- ins_char(c);
- else
- /* will be decremented further down */
- ++curwin->w_cursor.col;
- } else
- ins_char(cap->nchar);
- State = old_State;
- if (cap->ncharC1 != 0)
- ins_char(cap->ncharC1);
- if (cap->ncharC2 != 0)
- ins_char(cap->ncharC2);
- }
- } else {
- /*
- * Replace the characters within one line.
- */
- for (n = cap->count1; n > 0; --n) {
- /*
- * Get ptr again, because u_save and/or showmatch() will have
- * released the line. At the same time we let know that the
- * line will be changed.
- */
- ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, true);
- if (cap->nchar == Ctrl_E || cap->nchar == Ctrl_Y) {
- int c = ins_copychar(curwin->w_cursor.lnum
- + (cap->nchar == Ctrl_Y ? -1 : 1));
- if (c != NUL) {
- assert(c >= 0 && c <= UCHAR_MAX);
- ptr[curwin->w_cursor.col] = (char_u)c;
- }
+ const int old_State = State;
+
+ if (cap->ncharC1 != 0) {
+ AppendCharToRedobuff(cap->ncharC1);
+ }
+ if (cap->ncharC2 != 0) {
+ AppendCharToRedobuff(cap->ncharC2);
+ }
+
+ // This is slow, but it handles replacing a single-byte with a
+ // multi-byte and the other way around. Also handles adding
+ // composing characters for utf-8.
+ for (long n = cap->count1; n > 0; n--) {
+ State = REPLACE;
+ if (cap->nchar == Ctrl_E || cap->nchar == Ctrl_Y) {
+ int c = ins_copychar(curwin->w_cursor.lnum
+ + (cap->nchar == Ctrl_Y ? -1 : 1));
+ if (c != NUL) {
+ ins_char(c);
} else {
- assert(cap->nchar >= 0 && cap->nchar <= UCHAR_MAX);
- ptr[curwin->w_cursor.col] = (char_u)cap->nchar;
+ // will be decremented further down
+ curwin->w_cursor.col++;
}
- if (p_sm && msg_silent == 0)
- showmatch(cap->nchar);
- ++curwin->w_cursor.col;
+ } else {
+ ins_char(cap->nchar);
+ }
+ State = old_State;
+ if (cap->ncharC1 != 0) {
+ ins_char(cap->ncharC1);
+ }
+ if (cap->ncharC2 != 0) {
+ ins_char(cap->ncharC2);
}
-
- /* mark the buffer as changed and prepare for displaying */
- changed_bytes(curwin->w_cursor.lnum,
- (colnr_T)(curwin->w_cursor.col - cap->count1));
}
--curwin->w_cursor.col; /* cursor on the last replaced char */
/* if the character on the left of the current cursor is a multi-byte
* character, move two characters left */
- if (has_mbyte)
- mb_adjust_cursor();
+ mb_adjust_cursor();
curbuf->b_op_end = curwin->w_cursor;
curwin->w_set_curswant = true;
set_last_insert(cap->nchar);
@@ -6209,7 +6222,11 @@ static void v_visop(cmdarg_T *cap)
*/
static void nv_subst(cmdarg_T *cap)
{
- if (VIsual_active) { /* "vs" and "vS" are the same as "vc" */
+ if (bt_prompt(curbuf) && !prompt_curpos_editable()) {
+ clearopbeep(cap->oap);
+ return;
+ }
+ if (VIsual_active) { // "vs" and "vS" are the same as "vc"
if (cap->cmdchar == 'S') {
VIsual_mode_orig = VIsual_mode;
VIsual_mode = 'V';
@@ -6292,9 +6309,7 @@ static void nv_gomark(cmdarg_T *cap)
}
}
-/*
- * Handle CTRL-O, CTRL-I, "g;" and "g," commands.
- */
+// Handle CTRL-O, CTRL-I, "g;", "g,", and "CTRL-Tab" commands.
static void nv_pcmark(cmdarg_T *cap)
{
pos_T *pos;
@@ -6302,11 +6317,16 @@ static void nv_pcmark(cmdarg_T *cap)
const bool old_KeyTyped = KeyTyped; // getting file may reset it
if (!checkclearopq(cap->oap)) {
- if (cap->cmdchar == 'g')
+ if (cap->cmdchar == TAB && mod_mask == MOD_MASK_CTRL) {
+ goto_tabpage_lastused();
+ return;
+ }
+ if (cap->cmdchar == 'g') {
pos = movechangelist((int)cap->count1);
- else
+ } else {
pos = movemark((int)cap->count1);
- if (pos == (pos_T *)-1) { /* jump to other file */
+ }
+ if (pos == (pos_T *)-1) { // jump to other file
curwin->w_set_curswant = true;
check_cursor();
} else if (pos != NULL) /* can jump */
@@ -6356,8 +6376,8 @@ static void nv_visual(cmdarg_T *cap)
if (cap->cmdchar == Ctrl_Q)
cap->cmdchar = Ctrl_V;
- /* 'v', 'V' and CTRL-V can be used while an operator is pending to make it
- * characterwise, linewise, or blockwise. */
+ // 'v', 'V' and CTRL-V can be used while an operator is pending to make it
+ // charwise, linewise, or blockwise.
if (cap->oap->op_type != OP_NOP) {
motion_force = cap->oap->motion_force = cap->cmdchar;
finish_op = false; // operator doesn't finish now but later
@@ -6733,6 +6753,22 @@ static void nv_g_cmd(cmdarg_T *cap)
curwin->w_set_curswant = true;
break;
+ case 'M':
+ {
+ const char_u *const ptr = get_cursor_line_ptr();
+
+ oap->motion_type = kMTCharWise;
+ oap->inclusive = false;
+ i = (int)mb_string2cells_len(ptr, STRLEN(ptr));
+ if (cap->count0 > 0 && cap->count0 <= 100) {
+ coladvance((colnr_T)(i * cap->count0 / 100));
+ } else {
+ coladvance((colnr_T)(i / 2));
+ }
+ curwin->w_set_curswant = true;
+ }
+ break;
+
case '_':
/* "g_": to the last non-blank character in the line or <count> lines
* downward. */
@@ -6797,10 +6833,14 @@ static void nv_g_cmd(cmdarg_T *cap)
} else if (nv_screengo(oap, FORWARD, cap->count1 - 1) == false)
clearopbeep(oap);
} else {
+ if (cap->count1 > 1) {
+ // if it fails, let the cursor still move to the last char
+ cursor_down(cap->count1 - 1, false);
+ }
i = curwin->w_leftcol + curwin->w_width_inner - col_off - 1;
coladvance((colnr_T)i);
- /* Make sure we stick in this column. */
+ // Make sure we stick in this column.
validate_virtcol();
curwin->w_curswant = curwin->w_virtcol;
curwin->w_set_curswant = false;
@@ -7019,6 +7059,11 @@ static void nv_g_cmd(cmdarg_T *cap)
if (!checkclearop(oap))
goto_tabpage(-(int)cap->count1);
break;
+ case TAB:
+ if (!checkclearop(oap)) {
+ goto_tabpage_lastused();
+ }
+ break;
case '+':
case '-': /* "g+" and "g-": undo or redo along the timeline */
@@ -7119,10 +7164,15 @@ static void nv_tilde(cmdarg_T *cap)
{
if (!p_to
&& !VIsual_active
- && cap->oap->op_type != OP_TILDE)
+ && cap->oap->op_type != OP_TILDE) {
+ if (bt_prompt(curbuf) && !prompt_curpos_editable()) {
+ clearopbeep(cap->oap);
+ return;
+ }
n_swapchar(cap);
- else
+ } else {
nv_operator(cap);
+ }
}
/*
@@ -7135,6 +7185,12 @@ static void nv_operator(cmdarg_T *cap)
op_type = get_op_type(cap->cmdchar, cap->nchar);
+ if (bt_prompt(curbuf) && op_is_change(op_type)
+ && !prompt_curpos_editable()) {
+ clearopbeep(cap->oap);
+ return;
+ }
+
if (op_type == cap->oap->op_type) /* double operator works on lines */
nv_lineop(cap);
else if (!checkclearop(cap->oap)) {
@@ -7320,10 +7376,9 @@ static void adjust_cursor(oparg_T *oap)
&& (!VIsual_active || *p_sel == 'o')
&& !virtual_active() && (ve_flags & VE_ONEMORE) == 0
) {
- --curwin->w_cursor.col;
- /* prevent cursor from moving on the trail byte */
- if (has_mbyte)
- mb_adjust_cursor();
+ curwin->w_cursor.col--;
+ // prevent cursor from moving on the trail byte
+ mb_adjust_cursor();
oap->inclusive = true;
}
}
@@ -7350,10 +7405,7 @@ static void adjust_for_sel(cmdarg_T *cap)
{
if (VIsual_active && cap->oap->inclusive && *p_sel == 'e'
&& gchar_cursor() != NUL && lt(VIsual, curwin->w_cursor)) {
- if (has_mbyte)
- inc_cursor();
- else
- ++curwin->w_cursor.col;
+ inc_cursor();
cap->oap->inclusive = false;
}
}
@@ -7799,8 +7851,11 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent)
clearop(cap->oap);
assert(cap->opcount >= 0);
nv_diffgetput(true, (size_t)cap->opcount);
- } else
+ } else {
clearopbeep(cap->oap);
+ }
+ } else if (bt_prompt(curbuf) && !prompt_curpos_editable()) {
+ clearopbeep(cap->oap);
} else {
if (fix_indent) {
dir = (cap->cmdchar == ']' && cap->nchar == 'p')
@@ -7812,8 +7867,9 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent)
? BACKWARD : FORWARD;
}
prep_redo_cmd(cap);
- if (cap->cmdchar == 'g')
+ if (cap->cmdchar == 'g') {
flags |= PUT_CURSEND;
+ }
if (VIsual_active) {
/* Putting in Visual mode: The put text replaces the selected
@@ -7851,15 +7907,17 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent)
cap->oap->regname = regname;
}
- /* When deleted a linewise Visual area, put the register as
- * lines to avoid it joined with the next line. When deletion was
- * characterwise, split a line when putting lines. */
- if (VIsual_mode == 'V')
+ // When deleted a linewise Visual area, put the register as
+ // lines to avoid it joined with the next line. When deletion was
+ // charwise, split a line when putting lines.
+ if (VIsual_mode == 'V') {
flags |= PUT_LINE;
- else if (VIsual_mode == 'v')
+ } else if (VIsual_mode == 'v') {
flags |= PUT_LINE_SPLIT;
- if (VIsual_mode == Ctrl_V && dir == FORWARD)
+ }
+ if (VIsual_mode == Ctrl_V && dir == FORWARD) {
flags |= PUT_LINE_FORWARD;
+ }
dir = BACKWARD;
if ((VIsual_mode != 'V'
&& curwin->w_cursor.col < curbuf->b_op_start.col)
@@ -7917,10 +7975,14 @@ static void nv_open(cmdarg_T *cap)
clearop(cap->oap);
assert(cap->opcount >= 0);
nv_diffgetput(false, (size_t)cap->opcount);
- } else if (VIsual_active) /* switch start and end of visual */
+ } else if (VIsual_active) {
+ // switch start and end of visual/
v_swap_corners(cap->cmdchar);
- else
+ } else if (bt_prompt(curbuf)) {
+ clearopbeep(cap->oap);
+ } else {
n_opencmd(cap);
+ }
}
// Calculate start/end virtual columns for operating in block mode.
@@ -7941,9 +8003,7 @@ static void get_op_vcol(
oap->motion_type = kMTBlockWise;
// prevent from moving onto a trail byte
- if (has_mbyte) {
- mark_mb_adjustpos(curwin->w_buffer, &oap->end);
- }
+ mark_mb_adjustpos(curwin->w_buffer, &oap->end);
getvvcol(curwin, &(oap->start), &oap->start_vcol, NULL, &oap->end_vcol);
if (!redo_VIsual_busy) {