diff options
Diffstat (limited to 'src/nvim/normal.c')
-rw-r--r-- | src/nvim/normal.c | 1834 |
1 files changed, 533 insertions, 1301 deletions
diff --git a/src/nvim/normal.c b/src/nvim/normal.c index e058be9135..58a18ca5a8 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -8,14 +8,21 @@ // #include <assert.h> +#include <ctype.h> #include <inttypes.h> +#include <limits.h> #include <stdbool.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> +#include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/ascii.h" +#include "nvim/autocmd.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/change.h" #include "nvim/charset.h" #include "nvim/cmdhist.h" @@ -25,8 +32,6 @@ #include "nvim/drawscreen.h" #include "nvim/edit.h" #include "nvim/eval.h" -#include "nvim/eval/userfunc.h" -#include "nvim/event/loop.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" #include "nvim/ex_docmd.h" @@ -34,18 +39,18 @@ #include "nvim/fileio.h" #include "nvim/fold.h" #include "nvim/getchar.h" +#include "nvim/gettext.h" #include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/help.h" -#include "nvim/indent.h" +#include "nvim/highlight_defs.h" #include "nvim/keycodes.h" -#include "nvim/log.h" -#include "nvim/main.h" +#include "nvim/macros.h" #include "nvim/mapping.h" #include "nvim/mark.h" +#include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/memory.h" -#include "nvim/menu.h" #include "nvim/message.h" #include "nvim/mouse.h" #include "nvim/move.h" @@ -57,16 +62,19 @@ #include "nvim/plines.h" #include "nvim/profile.h" #include "nvim/quickfix.h" +#include "nvim/screen.h" #include "nvim/search.h" #include "nvim/spell.h" #include "nvim/spellfile.h" #include "nvim/spellsuggest.h" #include "nvim/state.h" +#include "nvim/statusline.h" #include "nvim/strings.h" #include "nvim/syntax.h" #include "nvim/tag.h" #include "nvim/textformat.h" #include "nvim/textobject.h" +#include "nvim/types.h" #include "nvim/ui.h" #include "nvim/undo.h" #include "nvim/vim.h" @@ -145,8 +153,7 @@ static const struct nv_cmd { nv_func_T cmd_func; ///< function for this command uint16_t cmd_flags; ///< NV_ flags int16_t cmd_arg; ///< value for ca.arg -} nv_cmds[] = -{ +} nv_cmds[] = { { NUL, nv_error, 0, 0 }, { Ctrl_A, nv_addsub, 0, 0 }, { Ctrl_B, nv_page, NV_STS, BACKWARD }, @@ -444,12 +451,34 @@ static int find_command(int cmdchar) /// message, return true. static bool check_text_locked(oparg_T *oap) { - if (text_locked()) { + if (!text_locked()) { + return false; + } + + if (oap != NULL) { clearopbeep(oap); - text_locked_msg(); + } + text_locked_msg(); + return true; +} + +/// If text is locked, "curbuf->b_ro_locked" or "allbuf_lock" is set: +/// Give an error message, possibly beep and return true. +/// "oap" may be NULL. +static bool check_text_or_curbuf_locked(oparg_T *oap) +{ + if (check_text_locked(oap)) { return true; } - return false; + + if (!curbuf_locked()) { + return false; + } + + if (oap != NULL) { + clearop(oap); + } + return true; } /// Normal state entry point. This is called on: @@ -613,6 +642,7 @@ static bool normal_need_redraw_mode_message(NormalState *s) && stuff_empty() && typebuf_typed() && emsg_silent == 0 + && !in_assert_fails && !did_wait_return && s->oa.op_type == OP_NOP); } @@ -1099,8 +1129,7 @@ static int normal_execute(VimState *state, int key) goto finish; } - if ((nv_cmds[s->idx].cmd_flags & NV_NCW) - && (check_text_locked(&s->oa) || curbuf_locked())) { + if ((nv_cmds[s->idx].cmd_flags & NV_NCW) && check_text_or_curbuf_locked(&s->oa)) { // this command is not allowed now s->command_finished = true; goto finish; @@ -1132,6 +1161,7 @@ static int normal_execute(VimState *state, int key) if (s->need_flushbuf) { ui_flush(); } + if (s->ca.cmdchar != K_IGNORE && s->ca.cmdchar != K_EVENT) { did_cursorhold = false; } @@ -1222,8 +1252,7 @@ static void normal_check_interrupt(NormalState *s) static void normal_check_window_scrolled(NormalState *s) { if (!finish_op) { - // Trigger Scroll if the viewport changed. - may_trigger_winscrolled(); + may_trigger_win_scrolled_resized(); } } @@ -1389,6 +1418,9 @@ static int normal_check(VimState *state) fclose(time_fd); time_fd = NULL; } + // After the first screen update may start triggering WinScrolled + // autocmd events. Store all the scroll positions and sizes now. + may_make_initial_scroll_size_snapshot(); } // May perform garbage collection when waiting for a character, but @@ -1433,854 +1465,6 @@ static void set_vcount_ca(cmdarg_T *cap, bool *set_prevcount) *set_prevcount = false; // only set v:prevcount once } -/// Move the current tab to tab in same column as mouse or to end of the -/// tabline if there is no tab there. -static void move_tab_to_mouse(void) -{ - int tabnr = tab_page_click_defs[mouse_col].tabnr; - if (tabnr <= 0) { - tabpage_move(9999); - } else if (tabnr < tabpage_index(curtab)) { - tabpage_move(tabnr - 1); - } else { - tabpage_move(tabnr); - } -} - -/// Call click definition function for column "col" in the "click_defs" array for button -/// "which_button". -static void call_click_def_func(StlClickDefinition *click_defs, int col, int which_button) -{ - typval_T argv[] = { - { - .v_lock = VAR_FIXED, - .v_type = VAR_NUMBER, - .vval = { - .v_number = (varnumber_T)click_defs[col].tabnr - }, - }, - { - .v_lock = VAR_FIXED, - .v_type = VAR_NUMBER, - .vval = { - .v_number = ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_4CLICK - ? 4 - : ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_3CLICK - ? 3 - : ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK - ? 2 - : 1))) - }, - }, - { - .v_lock = VAR_FIXED, - .v_type = VAR_STRING, - .vval = { - .v_string = (which_button == MOUSE_LEFT - ? "l" - : (which_button == MOUSE_RIGHT - ? "r" - : (which_button == MOUSE_MIDDLE - ? "m" - : "?"))) - }, - }, - { - .v_lock = VAR_FIXED, - .v_type = VAR_STRING, - .vval = { - .v_string = (char[]) { - (char)(mod_mask & MOD_MASK_SHIFT ? 's' : ' '), - (char)(mod_mask & MOD_MASK_CTRL ? 'c' : ' '), - (char)(mod_mask & MOD_MASK_ALT ? 'a' : ' '), - (char)(mod_mask & MOD_MASK_META ? 'm' : ' '), - NUL - } - }, - } - }; - typval_T rettv; - (void)call_vim_function(click_defs[col].func, ARRAY_SIZE(argv), argv, &rettv); - tv_clear(&rettv); -} - -/// Do the appropriate action for the current mouse click in the current mode. -/// Not used for Command-line mode. -/// -/// Normal and Visual Mode: -/// event modi- position visual change action -/// fier cursor window -/// left press - yes end yes -/// left press C yes end yes "^]" (2) -/// left press S yes end (popup: extend) yes "*" (2) -/// left drag - yes start if moved no -/// left relse - yes start if moved no -/// middle press - yes if not active no put register -/// middle press - yes if active no yank and put -/// right press - yes start or extend yes -/// right press S yes no change yes "#" (2) -/// right drag - yes extend no -/// right relse - yes extend no -/// -/// Insert or Replace Mode: -/// event modi- position visual change action -/// fier cursor window -/// left press - yes (cannot be active) yes -/// left press C yes (cannot be active) yes "CTRL-O^]" (2) -/// left press S yes (cannot be active) yes "CTRL-O*" (2) -/// left drag - yes start or extend (1) no CTRL-O (1) -/// left relse - yes start or extend (1) no CTRL-O (1) -/// middle press - no (cannot be active) no put register -/// right press - yes start or extend yes CTRL-O -/// right press S yes (cannot be active) yes "CTRL-O#" (2) -/// -/// (1) only if mouse pointer moved since press -/// (2) only if click is in same buffer -/// -/// @param oap operator argument, can be NULL -/// @param c K_LEFTMOUSE, etc -/// @param dir Direction to 'put' if necessary -/// @param fixindent PUT_FIXINDENT if fixing indent necessary -/// -/// @return true if start_arrow() should be called for edit mode. -bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent) -{ - static bool got_click = false; // got a click some time back - - int which_button; // MOUSE_LEFT, _MIDDLE or _RIGHT - bool is_click; // If false it's a drag or release event - bool is_drag; // If true it's a drag event - int jump_flags = 0; // flags for jump_to_mouse() - pos_T start_visual; - bool moved; // Has cursor moved? - bool in_winbar; // mouse in window bar - bool in_status_line; // mouse in status line - static bool in_tab_line = false; // mouse clicked in tab line - bool in_sep_line; // mouse in vertical separator line - int c1, c2; - pos_T save_cursor; - win_T *old_curwin = curwin; - static pos_T orig_cursor; - colnr_T leftcol, rightcol; - pos_T end_visual; - long diff; - int old_active = VIsual_active; - int old_mode = VIsual_mode; - int regname; - - save_cursor = curwin->w_cursor; - - for (;;) { - which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag); - if (is_drag) { - // If the next character is the same mouse event then use that - // one. Speeds up dragging the status line. - // Note: Since characters added to the stuff buffer in the code - // below need to come before the next character, do not do this - // when the current character was stuffed. - if (!KeyStuffed && vpeekc() != NUL) { - int nc; - int save_mouse_grid = mouse_grid; - int save_mouse_row = mouse_row; - int save_mouse_col = mouse_col; - - // Need to get the character, peeking doesn't get the actual one. - nc = safe_vgetc(); - if (c == nc) { - continue; - } - vungetc(nc); - mouse_grid = save_mouse_grid; - mouse_row = save_mouse_row; - mouse_col = save_mouse_col; - } - } - break; - } - - if (c == K_MOUSEMOVE) { - // Mouse moved without a button pressed. - return false; - } - - // Ignore drag and release events if we didn't get a click. - if (is_click) { - got_click = true; - } else { - if (!got_click) { // didn't get click, ignore - return false; - } - if (!is_drag) { // release, reset got_click - got_click = false; - if (in_tab_line) { - in_tab_line = false; - return false; - } - } - } - - // CTRL right mouse button does CTRL-T - if (is_click && (mod_mask & MOD_MASK_CTRL) && which_button == MOUSE_RIGHT) { - if (State & MODE_INSERT) { - stuffcharReadbuff(Ctrl_O); - } - if (count > 1) { - stuffnumReadbuff(count); - } - stuffcharReadbuff(Ctrl_T); - got_click = false; // ignore drag&release now - return false; - } - - // CTRL only works with left mouse button - if ((mod_mask & MOD_MASK_CTRL) && which_button != MOUSE_LEFT) { - return false; - } - - // When a modifier is down, ignore drag and release events, as well as - // multiple clicks and the middle mouse button. - // Accept shift-leftmouse drags when 'mousemodel' is "popup.*". - if ((mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT - | MOD_MASK_META)) - && (!is_click - || (mod_mask & MOD_MASK_MULTI_CLICK) - || which_button == MOUSE_MIDDLE) - && !((mod_mask & (MOD_MASK_SHIFT|MOD_MASK_ALT)) - && mouse_model_popup() - && which_button == MOUSE_LEFT) - && !((mod_mask & MOD_MASK_ALT) - && !mouse_model_popup() - && which_button == MOUSE_RIGHT)) { - return false; - } - - // If the button press was used as the movement command for an operator (eg - // "d<MOUSE>"), or it is the middle button that is held down, ignore - // drag/release events. - if (!is_click && which_button == MOUSE_MIDDLE) { - return false; - } - - if (oap != NULL) { - regname = oap->regname; - } else { - regname = 0; - } - - // Middle mouse button does a 'put' of the selected text - if (which_button == MOUSE_MIDDLE) { - if (State == MODE_NORMAL) { - // If an operator was pending, we don't know what the user wanted to do. - // Go back to normal mode: Clear the operator and beep(). - if (oap != NULL && oap->op_type != OP_NOP) { - clearopbeep(oap); - return false; - } - - // If visual was active, yank the highlighted text and put it - // before the mouse pointer position. - // In Select mode replace the highlighted text with the clipboard. - if (VIsual_active) { - if (VIsual_select) { - stuffcharReadbuff(Ctrl_G); - stuffReadbuff("\"+p"); - } else { - stuffcharReadbuff('y'); - stuffcharReadbuff(K_MIDDLEMOUSE); - } - return false; - } - // The rest is below jump_to_mouse() - } else if ((State & MODE_INSERT) == 0) { - return false; - } - - // Middle click in insert mode doesn't move the mouse, just insert the - // contents of a register. '.' register is special, can't insert that - // with do_put(). - // Also paste at the cursor if the current mode isn't in 'mouse' (only - // happens for the GUI). - if ((State & MODE_INSERT)) { - if (regname == '.') { - insert_reg(regname, true); - } else { - if (regname == 0 && eval_has_provider("clipboard")) { - regname = '*'; - } - if ((State & REPLACE_FLAG) && !yank_register_mline(regname)) { - insert_reg(regname, true); - } else { - do_put(regname, NULL, BACKWARD, 1L, - (fixindent ? PUT_FIXINDENT : 0) | PUT_CURSEND); - - // Repeat it with CTRL-R CTRL-O r or CTRL-R CTRL-P r - AppendCharToRedobuff(Ctrl_R); - AppendCharToRedobuff(fixindent ? Ctrl_P : Ctrl_O); - AppendCharToRedobuff(regname == 0 ? '"' : regname); - } - } - return false; - } - } - - // When dragging or button-up stay in the same window. - if (!is_click) { - jump_flags |= MOUSE_FOCUS | MOUSE_DID_MOVE; - } - - start_visual.lnum = 0; - - // Check for clicking in the tab page line. - if (mouse_grid <= 1 && mouse_row == 0 && firstwin->w_winrow > 0) { - if (is_drag) { - if (in_tab_line) { - move_tab_to_mouse(); - } - return false; - } - - // click in a tab selects that tab page - if (is_click && cmdwin_type == 0 && mouse_col < Columns) { - in_tab_line = true; - c1 = tab_page_click_defs[mouse_col].tabnr; - switch (tab_page_click_defs[mouse_col].type) { - case kStlClickDisabled: - break; - case kStlClickTabClose: { - tabpage_T *tp; - - // Close the current or specified tab page. - if (c1 == 999) { - tp = curtab; - } else { - tp = find_tabpage(c1); - } - if (tp == curtab) { - if (first_tabpage->tp_next != NULL) { - tabpage_close(false); - } - } else if (tp != NULL) { - tabpage_close_other(tp, false); - } - break; - } - case kStlClickTabSwitch: - if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK) { - // double click opens new page - end_visual_mode(); - tabpage_new(); - tabpage_move(c1 == 0 ? 9999 : c1 - 1); - } else { - // Go to specified tab page, or next one if not clicking - // on a label. - goto_tabpage(c1); - - // It's like clicking on the status line of a window. - if (curwin != old_curwin) { - end_visual_mode(); - } - } - break; - case kStlClickFuncRun: - call_click_def_func(tab_page_click_defs, mouse_col, which_button); - break; - } - } - return true; - } else if (is_drag && in_tab_line) { - move_tab_to_mouse(); - return false; - } - - // When 'mousemodel' is "popup" or "popup_setpos", translate mouse events: - // right button up -> pop-up menu - // shift-left button -> right button - // alt-left button -> alt-right button - if (mouse_model_popup()) { - if (which_button == MOUSE_RIGHT - && !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))) { - if (!is_click) { - // Ignore right button release events, only shows the popup - // menu on the button down event. - return false; - } - jump_flags = 0; - if (strcmp(p_mousem, "popup_setpos") == 0) { - // First set the cursor position before showing the popup - // menu. - if (VIsual_active) { - pos_T m_pos; - // set MOUSE_MAY_STOP_VIS if we are outside the - // selection or the current window (might have false - // negative here) - if (mouse_row < curwin->w_winrow - || mouse_row > (curwin->w_winrow + curwin->w_height)) { - jump_flags = MOUSE_MAY_STOP_VIS; - } else if (get_fpos_of_mouse(&m_pos) != IN_BUFFER) { - jump_flags = MOUSE_MAY_STOP_VIS; - } else { - if ((lt(curwin->w_cursor, VIsual) - && (lt(m_pos, curwin->w_cursor) || lt(VIsual, m_pos))) - || (lt(VIsual, curwin->w_cursor) - && (lt(m_pos, VIsual) || lt(curwin->w_cursor, m_pos)))) { - jump_flags = MOUSE_MAY_STOP_VIS; - } else if (VIsual_mode == Ctrl_V) { - getvcols(curwin, &curwin->w_cursor, &VIsual, &leftcol, &rightcol); - getvcol(curwin, &m_pos, NULL, &m_pos.col, NULL); - if (m_pos.col < leftcol || m_pos.col > rightcol) { - jump_flags = MOUSE_MAY_STOP_VIS; - } - } - } - } else { - jump_flags = MOUSE_MAY_STOP_VIS; - } - } - if (jump_flags) { - jump_flags = jump_to_mouse(jump_flags, NULL, which_button); - redraw_curbuf_later(VIsual_active ? UPD_INVERTED : UPD_VALID); - update_screen(); - setcursor(); - ui_flush(); // Update before showing popup menu - } - show_popupmenu(); - got_click = false; // ignore release events - return (jump_flags & CURSOR_MOVED) != 0; - } - if (which_button == MOUSE_LEFT - && (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_ALT))) { - which_button = MOUSE_RIGHT; - mod_mask &= ~MOD_MASK_SHIFT; - } - } - - if ((State & (MODE_NORMAL | MODE_INSERT)) - && !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))) { - if (which_button == MOUSE_LEFT) { - if (is_click) { - // stop Visual mode for a left click in a window, but not when on a status line - if (VIsual_active) { - jump_flags |= MOUSE_MAY_STOP_VIS; - } - } else { - jump_flags |= MOUSE_MAY_VIS; - } - } else if (which_button == MOUSE_RIGHT) { - if (is_click && VIsual_active) { - // Remember the start and end of visual before moving the cursor. - if (lt(curwin->w_cursor, VIsual)) { - start_visual = curwin->w_cursor; - end_visual = VIsual; - } else { - start_visual = VIsual; - end_visual = curwin->w_cursor; - } - } - jump_flags |= MOUSE_FOCUS; - jump_flags |= MOUSE_MAY_VIS; - } - } - - // If an operator is pending, ignore all drags and releases until the next mouse click. - if (!is_drag && oap != NULL && oap->op_type != OP_NOP) { - got_click = false; - oap->motion_type = kMTCharWise; - } - - // When releasing the button let jump_to_mouse() know. - if (!is_click && !is_drag) { - jump_flags |= MOUSE_RELEASED; - } - - // JUMP! - jump_flags = jump_to_mouse(jump_flags, - oap == NULL ? NULL : &(oap->inclusive), - which_button); - - moved = (jump_flags & CURSOR_MOVED); - in_winbar = (jump_flags & MOUSE_WINBAR); - in_status_line = (jump_flags & IN_STATUS_LINE); - in_sep_line = (jump_flags & IN_SEP_LINE); - - if ((in_winbar || in_status_line) && is_click) { - // Handle click event on window bar or status lin - int click_grid = mouse_grid; - int click_row = mouse_row; - int click_col = mouse_col; - win_T *wp = mouse_find_win(&click_grid, &click_row, &click_col); - if (wp == NULL) { - return false; - } - - StlClickDefinition *click_defs = in_status_line ? wp->w_status_click_defs - : wp->w_winbar_click_defs; - - if (in_status_line && global_stl_height() > 0) { - // global statusline is displayed for the current window, - // and spans the whole screen. - click_defs = curwin->w_status_click_defs; - click_col = mouse_col; - } - - if (click_defs != NULL) { - switch (click_defs[click_col].type) { - case kStlClickDisabled: - break; - case kStlClickFuncRun: - call_click_def_func(click_defs, click_col, which_button); - break; - default: - assert(false && "winbar and statusline only support %@ for clicks"); - break; - } - } - - return false; - } else if (in_winbar) { - // A drag or release event in the window bar has no side effects. - return false; - } - - // When jumping to another window, clear a pending operator. That's a bit - // friendlier than beeping and not jumping to that window. - if (curwin != old_curwin && oap != NULL && oap->op_type != OP_NOP) { - clearop(oap); - } - - if (mod_mask == 0 - && !is_drag - && (jump_flags & (MOUSE_FOLD_CLOSE | MOUSE_FOLD_OPEN)) - && which_button == MOUSE_LEFT) { - // open or close a fold at this line - if (jump_flags & MOUSE_FOLD_OPEN) { - openFold(curwin->w_cursor, 1L); - } else { - closeFold(curwin->w_cursor, 1L); - } - // don't move the cursor if still in the same window - if (curwin == old_curwin) { - curwin->w_cursor = save_cursor; - } - } - - // Set global flag that we are extending the Visual area with mouse dragging; - // temporarily minimize 'scrolloff'. - if (VIsual_active && is_drag && get_scrolloff_value(curwin)) { - // In the very first line, allow scrolling one line - if (mouse_row == 0) { - mouse_dragging = 2; - } else { - mouse_dragging = 1; - } - } - - // When dragging the mouse above the window, scroll down. - if (is_drag && mouse_row < 0 && !in_status_line) { - scroll_redraw(false, 1L); - mouse_row = 0; - } - - if (start_visual.lnum) { // right click in visual mode - // When ALT is pressed make Visual mode blockwise. - if (mod_mask & MOD_MASK_ALT) { - VIsual_mode = Ctrl_V; - } - - // In Visual-block mode, divide the area in four, pick up the corner - // that is in the quarter that the cursor is in. - if (VIsual_mode == Ctrl_V) { - getvcols(curwin, &start_visual, &end_visual, &leftcol, &rightcol); - if (curwin->w_curswant > (leftcol + rightcol) / 2) { - end_visual.col = leftcol; - } else { - end_visual.col = rightcol; - } - if (curwin->w_cursor.lnum >= - (start_visual.lnum + end_visual.lnum) / 2) { - end_visual.lnum = start_visual.lnum; - } - - // move VIsual to the right column - start_visual = curwin->w_cursor; // save the cursor pos - curwin->w_cursor = end_visual; - coladvance(end_visual.col); - VIsual = curwin->w_cursor; - curwin->w_cursor = start_visual; // restore the cursor - } else { - // If the click is before the start of visual, change the start. - // If the click is after the end of visual, change the end. If - // the click is inside the visual, change the closest side. - if (lt(curwin->w_cursor, start_visual)) { - VIsual = end_visual; - } else if (lt(end_visual, curwin->w_cursor)) { - VIsual = start_visual; - } else { - // In the same line, compare column number - if (end_visual.lnum == start_visual.lnum) { - if (curwin->w_cursor.col - start_visual.col > - end_visual.col - curwin->w_cursor.col) { - VIsual = start_visual; - } else { - VIsual = end_visual; - } - } else { - // In different lines, compare line number - diff = (curwin->w_cursor.lnum - start_visual.lnum) - - (end_visual.lnum - curwin->w_cursor.lnum); - - if (diff > 0) { // closest to end - VIsual = start_visual; - } else if (diff < 0) { // closest to start - VIsual = end_visual; - } else { // in the middle line - if (curwin->w_cursor.col < - (start_visual.col + end_visual.col) / 2) { - VIsual = end_visual; - } else { - VIsual = start_visual; - } - } - } - } - } - } else if ((State & MODE_INSERT) && VIsual_active) { - // If Visual mode started in insert mode, execute "CTRL-O" - stuffcharReadbuff(Ctrl_O); - } - - // Middle mouse click: Put text before cursor. - if (which_button == MOUSE_MIDDLE) { - if (regname == 0 && eval_has_provider("clipboard")) { - regname = '*'; - } - if (yank_register_mline(regname)) { - if (mouse_past_bottom) { - dir = FORWARD; - } - } else if (mouse_past_eol) { - dir = FORWARD; - } - - if (fixindent) { - c1 = (dir == BACKWARD) ? '[' : ']'; - c2 = 'p'; - } else { - c1 = (dir == FORWARD) ? 'p' : 'P'; - c2 = NUL; - } - prep_redo(regname, count, NUL, c1, NUL, c2, NUL); - - // Remember where the paste started, so in edit() Insstart can be set to this position - if (restart_edit != 0) { - where_paste_started = curwin->w_cursor; - } - do_put(regname, NULL, dir, count, - (fixindent ? PUT_FIXINDENT : 0)| PUT_CURSEND); - } else if (((mod_mask & MOD_MASK_CTRL) || (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK) - && bt_quickfix(curbuf)) { - // Ctrl-Mouse click or double click in a quickfix window jumps to the - // error under the mouse pointer. - if (curwin->w_llist_ref == NULL) { // quickfix window - do_cmdline_cmd(".cc"); - } else { // location list window - do_cmdline_cmd(".ll"); - } - got_click = false; // ignore drag&release now - } else if ((mod_mask & MOD_MASK_CTRL) - || (curbuf->b_help && (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)) { - // Ctrl-Mouse click (or double click in a help window) jumps to the tag - // under the mouse pointer. - if (State & MODE_INSERT) { - stuffcharReadbuff(Ctrl_O); - } - stuffcharReadbuff(Ctrl_RSB); - got_click = false; // ignore drag&release now - } else if ((mod_mask & MOD_MASK_SHIFT)) { - // Shift-Mouse click searches for the next occurrence of the word under - // the mouse pointer - if (State & MODE_INSERT || (VIsual_active && VIsual_select)) { - stuffcharReadbuff(Ctrl_O); - } - if (which_button == MOUSE_LEFT) { - stuffcharReadbuff('*'); - } else { // MOUSE_RIGHT - stuffcharReadbuff('#'); - } - } else if (in_status_line || in_sep_line) { - // Do nothing if on status line or vertical separator - // Handle double clicks otherwise - } else if ((mod_mask & MOD_MASK_MULTI_CLICK) && (State & (MODE_NORMAL | MODE_INSERT))) { - if (is_click || !VIsual_active) { - if (VIsual_active) { - orig_cursor = VIsual; - } else { - VIsual = curwin->w_cursor; - orig_cursor = VIsual; - VIsual_active = true; - VIsual_reselect = true; - // start Select mode if 'selectmode' contains "mouse" - may_start_select('o'); - setmouse(); - } - if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK) { - // Double click with ALT pressed makes it blockwise. - if (mod_mask & MOD_MASK_ALT) { - VIsual_mode = Ctrl_V; - } else { - VIsual_mode = 'v'; - } - } else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_3CLICK) { - VIsual_mode = 'V'; - } else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_4CLICK) { - VIsual_mode = Ctrl_V; - } - } - // A double click selects a word or a block. - if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK) { - pos_T *pos = NULL; - int gc; - - if (is_click) { - // If the character under the cursor (skipping white space) is - // not a word character, try finding a match and select a (), - // {}, [], #if/#endif, etc. block. - end_visual = curwin->w_cursor; - while (gc = gchar_pos(&end_visual), ascii_iswhite(gc)) { - inc(&end_visual); - } - if (oap != NULL) { - oap->motion_type = kMTCharWise; - } - if (oap != NULL - && VIsual_mode == 'v' - && !vim_iswordc(gchar_pos(&end_visual)) - && equalpos(curwin->w_cursor, VIsual) - && (pos = findmatch(oap, NUL)) != NULL) { - curwin->w_cursor = *pos; - if (oap->motion_type == kMTLineWise) { - VIsual_mode = 'V'; - } else if (*p_sel == 'e') { - if (lt(curwin->w_cursor, VIsual)) { - VIsual.col++; - } else { - curwin->w_cursor.col++; - } - } - } - } - - if (pos == NULL && (is_click || is_drag)) { - // When not found a match or when dragging: extend to include a word. - if (lt(curwin->w_cursor, orig_cursor)) { - find_start_of_word(&curwin->w_cursor); - find_end_of_word(&VIsual); - } else { - find_start_of_word(&VIsual); - if (*p_sel == 'e' && *get_cursor_pos_ptr() != NUL) { - curwin->w_cursor.col += - utfc_ptr2len(get_cursor_pos_ptr()); - } - find_end_of_word(&curwin->w_cursor); - } - } - curwin->w_set_curswant = true; - } - if (is_click) { - redraw_curbuf_later(UPD_INVERTED); // update the inversion - } - } else if (VIsual_active && !old_active) { - if (mod_mask & MOD_MASK_ALT) { - VIsual_mode = Ctrl_V; - } else { - VIsual_mode = 'v'; - } - } - - // If Visual mode changed show it later. - if ((!VIsual_active && old_active && mode_displayed) - || (VIsual_active && p_smd && msg_silent == 0 - && (!old_active || VIsual_mode != old_mode))) { - redraw_cmdline = true; - } - - return moved; -} - -/// Move "pos" back to the start of the word it's in. -static void find_start_of_word(pos_T *pos) -{ - char_u *line; - int cclass; - int col; - - line = (char_u *)ml_get(pos->lnum); - cclass = get_mouse_class(line + pos->col); - - while (pos->col > 0) { - col = pos->col - 1; - col -= utf_head_off((char *)line, (char *)line + col); - if (get_mouse_class(line + col) != cclass) { - break; - } - pos->col = col; - } -} - -/// Move "pos" forward to the end of the word it's in. -/// When 'selection' is "exclusive", the position is just after the word. -static void find_end_of_word(pos_T *pos) -{ - char_u *line; - int cclass; - int col; - - line = (char_u *)ml_get(pos->lnum); - if (*p_sel == 'e' && pos->col > 0) { - pos->col--; - pos->col -= utf_head_off((char *)line, (char *)line + pos->col); - } - cclass = get_mouse_class(line + pos->col); - while (line[pos->col] != NUL) { - col = pos->col + utfc_ptr2len((char *)line + pos->col); - if (get_mouse_class(line + col) != cclass) { - if (*p_sel == 'e') { - pos->col = col; - } - break; - } - pos->col = col; - } -} - -/// Get class of a character for selection: same class means same word. -/// 0: blank -/// 1: punctuation groups -/// 2: normal word character -/// >2: multi-byte word character. -static int get_mouse_class(char_u *p) -{ - if (MB_BYTE2LEN(p[0]) > 1) { - return mb_get_class(p); - } - - const int c = *p; - if (c == ' ' || c == '\t') { - return 0; - } - if (vim_iswordc(c)) { - return 2; - } - - // There are a few special cases where we want certain combinations of - // characters to be considered as a single word. These are things like - // "->", "/ *", "*=", "+=", "&=", "<=", ">=", "!=" etc. Otherwise, each - // character is in its own class. - if (c != NUL && vim_strchr("-+*/%<>&|^!=", c) != NULL) { - return 1; - } - return c; -} - /// End Visual mode. /// This function should ALWAYS be called to end Visual mode, except from /// do_pending_operator(). @@ -2342,8 +1526,7 @@ void restore_visual_mode(void) /// @param dir the direction of searching, is either FORWARD or BACKWARD /// @param *colp is in/decremented if "ptr[-dir]" should also be included. /// @param bnp points to a counter for square brackets. -static bool find_is_eval_item(const char_u *const ptr, int *const colp, int *const bnp, - const int dir) +static bool find_is_eval_item(const char *const ptr, int *const colp, int *const bnp, const int dir) { // Accept everything inside []. if ((*ptr == ']' && dir == BACKWARD) || (*ptr == '[' && dir == FORWARD)) { @@ -2414,7 +1597,7 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char **text // if i == 0: try to find an identifier // if i == 1: try to find any non-white text - char_u *ptr = (char_u *)ml_get_buf(wp->w_buffer, lnum, false); + char *ptr = ml_get_buf(wp->w_buffer, lnum, false); for (i = (find_type & FIND_IDENT) ? 0 : 1; i < 2; i++) { // 1. skip to start of identifier/text col = startcol; @@ -2427,7 +1610,7 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char **text if (this_class != 0 && (i == 1 || this_class != 1)) { break; } - col += utfc_ptr2len((char *)ptr + col); + col += utfc_ptr2len(ptr + col); } // When starting on a ']' count it, so that we include the '['. @@ -2438,12 +1621,12 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char **text // // Remember class of character under cursor. if ((find_type & FIND_EVAL) && ptr[col] == ']') { - this_class = mb_get_class((char_u *)"a"); + this_class = mb_get_class("a"); } else { this_class = mb_get_class(ptr + col); } while (col > 0 && this_class != 0) { - prevcol = col - 1 - utf_head_off((char *)ptr, (char *)ptr + col - 1); + prevcol = col - 1 - utf_head_off(ptr, ptr + col - 1); prev_class = mb_get_class(ptr + prevcol); if (this_class != prev_class && (i == 0 @@ -2477,7 +1660,7 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char **text return 0; } ptr += col; - *text = (char *)ptr; + *text = ptr; if (textcol != NULL) { *textcol = col; } @@ -2495,7 +1678,7 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char **text || ((find_type & FIND_EVAL) && col <= (int)startcol && find_is_eval_item(ptr + col, &col, &bn, FORWARD)))) { - col += utfc_ptr2len((char *)ptr + col); + col += utfc_ptr2len(ptr + col); } assert(col >= 0); @@ -2620,9 +1803,7 @@ void may_clear_cmdline(void) } // Routines for displaying a partly typed command -#define SHOWCMD_BUFLEN (SHOWCMD_COLS + 1 + 30) -static char_u showcmd_buf[SHOWCMD_BUFLEN]; -static char_u old_showcmd_buf[SHOWCMD_BUFLEN]; // For push_showcmd() +static char old_showcmd_buf[SHOWCMD_BUFLEN]; // For push_showcmd() static bool showcmd_is_clear = true; static bool showcmd_visual = false; @@ -2661,25 +1842,25 @@ void clear_showcmd(void) getvcols(curwin, &curwin->w_cursor, &VIsual, &leftcol, &rightcol); p_sbr = saved_sbr; curwin->w_p_sbr = saved_w_sbr; - snprintf((char *)showcmd_buf, SHOWCMD_BUFLEN, "%" PRId64 "x%" PRId64, + snprintf(showcmd_buf, SHOWCMD_BUFLEN, "%" PRId64 "x%" PRId64, (int64_t)lines, (int64_t)rightcol - leftcol + 1); } else if (VIsual_mode == 'V' || VIsual.lnum != curwin->w_cursor.lnum) { - snprintf((char *)showcmd_buf, SHOWCMD_BUFLEN, "%" PRId64, (int64_t)lines); + snprintf(showcmd_buf, SHOWCMD_BUFLEN, "%" PRId64, (int64_t)lines); } else { - char_u *s, *e; + char *s, *e; int l; int bytes = 0; int chars = 0; if (cursor_bot) { s = ml_get_pos(&VIsual); - e = (char_u *)get_cursor_pos_ptr(); + e = get_cursor_pos_ptr(); } else { - s = (char_u *)get_cursor_pos_ptr(); + s = get_cursor_pos_ptr(); e = ml_get_pos(&VIsual); } while ((*p_sel != 'e') ? s <= e : s < e) { - l = utfc_ptr2len((char *)s); + l = utfc_ptr2len(s); if (l == 0) { bytes++; chars++; @@ -2690,9 +1871,9 @@ void clear_showcmd(void) s += l; } if (bytes == chars) { - sprintf((char *)showcmd_buf, "%d", chars); + snprintf(showcmd_buf, SHOWCMD_BUFLEN, "%d", chars); } else { - sprintf((char *)showcmd_buf, "%d-%d", chars, bytes); + snprintf(showcmd_buf, SHOWCMD_BUFLEN, "%d-%d", chars, bytes); } } int limit = ui_has(kUIMessages) ? SHOWCMD_BUFLEN - 1 : SHOWCMD_COLS; @@ -2745,11 +1926,11 @@ bool add_to_showcmd(int c) } } - char *p = (char *)transchar(c); + char *p = transchar(c); if (*p == ' ') { STRCPY(p, "<20>"); } - size_t old_len = STRLEN(showcmd_buf); + size_t old_len = strlen(showcmd_buf); size_t extra_len = strlen(p); size_t limit = ui_has(kUIMessages) ? SHOWCMD_BUFLEN - 1 : SHOWCMD_COLS; if (old_len + extra_len > limit) { @@ -2782,7 +1963,7 @@ static void del_from_showcmd(int len) return; } - old_len = (int)STRLEN(showcmd_buf); + old_len = (int)strlen(showcmd_buf); if (len > old_len) { len = old_len; } @@ -2815,22 +1996,31 @@ void pop_showcmd(void) static void display_showcmd(void) { + int len = (int)strlen(showcmd_buf); + showcmd_is_clear = (len == 0); + + if (*p_sloc == 's') { + win_redr_status(curwin); + setcursor(); // put cursor back where it belongs + return; + } + if (*p_sloc == 't') { + draw_tabline(); + setcursor(); // put cursor back where it belongs + return; + } + // 'showcmdloc' is "last" or empty if (p_ch == 0 && !ui_has(kUIMessages)) { - // TODO(bfredl): would be nice to show in global statusline, perhaps return; } - int len; - len = (int)STRLEN(showcmd_buf); - showcmd_is_clear = (len == 0); - if (ui_has(kUIMessages)) { MAXSIZE_TEMP_ARRAY(content, 1); MAXSIZE_TEMP_ARRAY(chunk, 2); if (len > 0) { // placeholder for future highlight support ADD_C(chunk, INTEGER_OBJ(0)); - ADD_C(chunk, STRING_OBJ(cstr_as_string((char *)showcmd_buf))); + ADD_C(chunk, STRING_OBJ(cstr_as_string(showcmd_buf))); ADD_C(content, ARRAY_OBJ(chunk)); } ui_call_msg_showcmd(content); @@ -2842,7 +2032,7 @@ static void display_showcmd(void) grid_puts_line_start(&msg_grid_adj, showcmd_row); if (!showcmd_is_clear) { - grid_puts(&msg_grid_adj, (char *)showcmd_buf, showcmd_row, sc_col, + grid_puts(&msg_grid_adj, showcmd_buf, showcmd_row, sc_col, HL_ATTR(HLF_MSG)); } @@ -3021,17 +2211,19 @@ static void nv_addsub(cmdarg_T *cap) /// CTRL-F, CTRL-B, etc: Scroll page up or down. static void nv_page(cmdarg_T *cap) { - if (!checkclearop(cap->oap)) { - if (mod_mask & MOD_MASK_CTRL) { - // <C-PageUp>: tab page back; <C-PageDown>: tab page forward - if (cap->arg == BACKWARD) { - goto_tabpage(-(int)cap->count1); - } else { - goto_tabpage((int)cap->count0); - } + if (checkclearop(cap->oap)) { + return; + } + + if (mod_mask & MOD_MASK_CTRL) { + // <C-PageUp>: tab page back; <C-PageDown>: tab page forward + if (cap->arg == BACKWARD) { + goto_tabpage(-(int)cap->count1); } else { - (void)onepage(cap->arg, cap->count1); + goto_tabpage((int)cap->count0); } + } else { + (void)onepage(cap->arg, cap->count1); } } @@ -3043,22 +2235,23 @@ static void nv_gd(oparg_T *oap, int nchar, int thisblock) size_t len; char *ptr; if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0 - || !find_decl((char_u *)ptr, len, nchar == 'd', thisblock, SEARCH_START)) { + || !find_decl(ptr, len, nchar == 'd', thisblock, SEARCH_START)) { clearopbeep(oap); - } else { - if ((fdo_flags & FDO_SEARCH) && KeyTyped && oap->op_type == OP_NOP) { - foldOpenCursor(); - } - // clear any search statistics - if (messaging() && !msg_silent && !shortmess(SHM_SEARCHCOUNT)) { - clear_cmdline = true; - } + return; + } + + if ((fdo_flags & FDO_SEARCH) && KeyTyped && oap->op_type == OP_NOP) { + foldOpenCursor(); + } + // clear any search statistics + if (messaging() && !msg_silent && !shortmess(SHM_SEARCHCOUNT)) { + clear_cmdline = true; } } /// @return true if line[offset] is not inside a C-style comment or string, /// false otherwise. -static bool is_ident(char_u *line, int offset) +static bool is_ident(const char *line, int offset) { bool incomment = false; int instring = 0; @@ -3066,11 +2259,11 @@ static bool is_ident(char_u *line, int offset) for (int i = 0; i < offset && line[i] != NUL; i++) { if (instring != 0) { - if (prev != '\\' && line[i] == instring) { + if (prev != '\\' && (uint8_t)line[i] == instring) { instring = 0; } } else if ((line[i] == '"' || line[i] == '\'') && !incomment) { - instring = line[i]; + instring = (uint8_t)line[i]; } else { if (incomment) { if (prev == '*' && line[i] == '/') { @@ -3083,7 +2276,7 @@ static bool is_ident(char_u *line, int offset) } } - prev = line[i]; + prev = (uint8_t)line[i]; } return incomment == false && instring == 0; @@ -3097,9 +2290,9 @@ static bool is_ident(char_u *line, int offset) /// @param flags_arg flags passed to searchit() /// /// @return fail when not found. -bool find_decl(char_u *ptr, size_t len, bool locally, bool thisblock, int flags_arg) +bool find_decl(char *ptr, size_t len, bool locally, bool thisblock, int flags_arg) { - char_u *pat; + char *pat; pos_T old_pos; pos_T par_pos; pos_T found_pos; @@ -3115,7 +2308,7 @@ bool find_decl(char_u *ptr, size_t len, bool locally, bool thisblock, int flags_ // Put "\V" before the pattern to avoid that the special meaning of "." // and "~" causes trouble. assert(len <= INT_MAX); - sprintf((char *)pat, vim_iswordp(ptr) ? "\\V\\<%.*s\\>" : "\\V%.*s", + sprintf(pat, vim_iswordp(ptr) ? "\\V\\<%.*s\\>" : "\\V%.*s", // NOLINT(runtime/printf) (int)len, ptr); old_pos = curwin->w_cursor; save_p_ws = p_ws; @@ -3176,7 +2369,7 @@ bool find_decl(char_u *ptr, size_t len, bool locally, bool thisblock, int flags_ curwin->w_cursor.col = 0; continue; } - bool valid = is_ident((char_u *)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. @@ -3231,7 +2424,7 @@ bool find_decl(char_u *ptr, size_t len, bool locally, bool thisblock, int flags_ /// @return true if able to move cursor, false otherwise. static bool nv_screengo(oparg_T *oap, int dir, long dist) { - int linelen = linetabsize((char_u *)get_cursor_line_ptr()); + int linelen = linetabsize(get_cursor_line_ptr()); bool retval = true; bool atend = false; int n; @@ -3302,7 +2495,7 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist) } curwin->w_cursor.lnum--; - linelen = linetabsize((char_u *)get_cursor_line_ptr()); + linelen = linetabsize(get_cursor_line_ptr()); if (linelen > width1) { int w = (((linelen - width1 - 1) / width2) + 1) * width2; assert(curwin->w_curswant <= INT_MAX - w); @@ -3338,7 +2531,7 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist) if (curwin->w_curswant >= width1) { curwin->w_curswant -= width2; } - linelen = linetabsize((char_u *)get_cursor_line_ptr()); + linelen = linetabsize(get_cursor_line_ptr()); } } } @@ -3357,7 +2550,7 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist) validate_virtcol(); colnr_T virtcol = curwin->w_virtcol; if (virtcol > (colnr_T)width1 && *get_showbreak_value(curwin) != NUL) { - virtcol -= vim_strsize((char *)get_showbreak_value(curwin)); + virtcol -= vim_strsize(get_showbreak_value(curwin)); } int c = utf_ptr2char(get_cursor_pos_ptr()); @@ -3409,7 +2602,7 @@ static void nv_mousescroll(cmdarg_T *cap) if (cap->arg == MSCR_UP || cap->arg == MSCR_DOWN) { if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) { (void)onepage(cap->arg ? FORWARD : BACKWARD, 1L); - } else { + } else if (p_mousescroll_vert > 0) { cap->count1 = p_mousescroll_vert; cap->count0 = p_mousescroll_vert; nv_scroll_line(cap); @@ -3513,6 +2706,7 @@ static bool nv_z_get_count(cmdarg_T *cap, int *nchar_arg) no_mapping--; allow_keys--; (void)add_to_showcmd(nchar); + if (nchar == K_DEL || nchar == K_KDEL) { n /= 10; } else if (ascii_isdigit(nchar)) { @@ -3553,6 +2747,7 @@ static int nv_zg_zw(cmdarg_T *cap, int nchar) no_mapping--; allow_keys--; (void)add_to_showcmd(nchar); + if (vim_strchr("gGwW", nchar) == NULL) { clearopbeep(cap->oap); return OK; @@ -3578,7 +2773,7 @@ static int nv_zg_zw(cmdarg_T *cap, int nchar) len = spell_move_to(curwin, FORWARD, true, true, NULL); emsg_off--; if (len != 0 && curwin->w_cursor.col <= pos.col) { - ptr = (char *)ml_get_pos(&curwin->w_cursor); + ptr = ml_get_pos(&curwin->w_cursor); } curwin->w_cursor = pos; } @@ -3587,7 +2782,7 @@ static int nv_zg_zw(cmdarg_T *cap, int nchar) return FAIL; } assert(len <= INT_MAX); - spell_add_word((char_u *)ptr, (int)len, + spell_add_word(ptr, (int)len, nchar == 'w' || nchar == 'W' ? SPELL_ADD_BAD : SPELL_ADD_GOOD, (nchar == 'G' || nchar == 'W') ? 0 : (int)cap->count1, undo); @@ -3604,7 +2799,7 @@ static void nv_zet(cmdarg_T *cap) long old_fdl = curwin->w_p_fdl; int old_fen = curwin->w_p_fen; - int l_p_siso = (int)get_sidescrolloff_value(curwin); + int siso = (int)get_sidescrolloff_value(curwin); if (ascii_isdigit(nchar) && !nv_z_get_count(cap, &nchar)) { return; @@ -3734,8 +2929,8 @@ static void nv_zet(cmdarg_T *cap) } else { getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL); } - if (col > l_p_siso) { - col -= l_p_siso; + if (col > siso) { + col -= siso; } else { col = 0; } @@ -3755,10 +2950,10 @@ static void nv_zet(cmdarg_T *cap) getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col); } n = curwin->w_width_inner - curwin_col_off(); - if (col + l_p_siso < n) { + if (col + siso < n) { col = 0; } else { - col = col + l_p_siso - n + 1; + col = col + siso - n + 1; } if (curwin->w_leftcol != col) { curwin->w_leftcol = col; @@ -4023,44 +3218,45 @@ static void nv_colon(cmdarg_T *cap) if (VIsual_active && !is_cmdkey && !is_lua) { nv_operator(cap); - } else { - if (cap->oap->op_type != OP_NOP) { - // Using ":" as a movement is charwise exclusive. - cap->oap->motion_type = kMTCharWise; - cap->oap->inclusive = false; - } else if (cap->count0 && !is_cmdkey && !is_lua) { - // translate "count:" into ":.,.+(count - 1)" - stuffcharReadbuff('.'); - if (cap->count0 > 1) { - stuffReadbuff(",.+"); - stuffnumReadbuff(cap->count0 - 1L); - } - } + return; + } - // When typing, don't type below an old message - if (KeyTyped) { - compute_cmdrow(); + if (cap->oap->op_type != OP_NOP) { + // Using ":" as a movement is charwise exclusive. + cap->oap->motion_type = kMTCharWise; + cap->oap->inclusive = false; + } else if (cap->count0 && !is_cmdkey && !is_lua) { + // translate "count:" into ":.,.+(count - 1)" + stuffcharReadbuff('.'); + if (cap->count0 > 1) { + stuffReadbuff(",.+"); + stuffnumReadbuff(cap->count0 - 1L); } + } - if (is_lua) { - cmd_result = map_execute_lua(); - } else { - // get a command line and execute it - cmd_result = do_cmdline(NULL, is_cmdkey ? getcmdkeycmd : getexline, NULL, - cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0); - } + // When typing, don't type below an old message + if (KeyTyped) { + compute_cmdrow(); + } - if (cmd_result == false) { - // The Ex command failed, do not execute the operator. - clearop(cap->oap); - } else if (cap->oap->op_type != OP_NOP - && (cap->oap->start.lnum > curbuf->b_ml.ml_line_count - || cap->oap->start.col > - (colnr_T)strlen(ml_get(cap->oap->start.lnum)) - || did_emsg)) { - // The start of the operator has become invalid by the Ex command. - clearopbeep(cap->oap); - } + if (is_lua) { + cmd_result = map_execute_lua(); + } else { + // get a command line and execute it + cmd_result = do_cmdline(NULL, is_cmdkey ? getcmdkeycmd : getexline, NULL, + cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0); + } + + if (cmd_result == false) { + // The Ex command failed, do not execute the operator. + clearop(cap->oap); + } else if (cap->oap->op_type != OP_NOP + && (cap->oap->start.lnum > curbuf->b_ml.ml_line_count + || cap->oap->start.col > + (colnr_T)strlen(ml_get(cap->oap->start.lnum)) + || did_emsg)) { + // The start of the operator has become invalid by the Ex command. + clearopbeep(cap->oap); } } @@ -4091,14 +3287,16 @@ static void nv_ctrlh(cmdarg_T *cap) /// CTRL-L: clear screen and redraw. static void nv_clear(cmdarg_T *cap) { - if (!checkclearop(cap->oap)) { - // Clear all syntax states to force resyncing. - syn_stack_free_all(curwin->w_s); - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - wp->w_s->b_syn_slow = false; - } - redraw_later(curwin, UPD_CLEAR); + if (checkclearop(cap->oap)) { + return; } + + // Clear all syntax states to force resyncing. + syn_stack_free_all(curwin->w_s); + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + wp->w_s->b_syn_slow = false; + } + redraw_later(curwin, UPD_CLEAR); } /// CTRL-O: In Select mode: switch to Visual mode for one command. @@ -4129,21 +3327,23 @@ static void nv_hat(cmdarg_T *cap) /// "Z" commands. static void nv_Zet(cmdarg_T *cap) { - if (!checkclearopq(cap->oap)) { - switch (cap->nchar) { - // "ZZ": equivalent to ":x". - case 'Z': - do_cmdline_cmd("x"); - break; + if (checkclearopq(cap->oap)) { + return; + } - // "ZQ": equivalent to ":q!" (Elvis compatible). - case 'Q': - do_cmdline_cmd("q!"); - break; + switch (cap->nchar) { + // "ZZ": equivalent to ":x". + case 'Z': + do_cmdline_cmd("x"); + break; - default: - clearopbeep(cap->oap); - } + // "ZQ": equivalent to ":q!" (Elvis compatible). + case 'Q': + do_cmdline_cmd("q!"); + break; + + default: + clearopbeep(cap->oap); } } @@ -4274,7 +3474,7 @@ static void nv_ident(cmdarg_T *cap) // Allocate buffer to put the command in. Inserting backslashes can // double the length of the word. p_kp / curbuf->b_p_kp could be added // and some numbers. - char *kp = *curbuf->b_p_kp == NUL ? (char *)p_kp : curbuf->b_p_kp; // 'keywordprg' + char *kp = *curbuf->b_p_kp == NUL ? p_kp : curbuf->b_p_kp; // 'keywordprg' bool kp_help = (*kp == NUL || strcmp(kp, ":he") == 0 || strcmp(kp, ":help") == 0); if (kp_help && *skipwhite(ptr) == NUL) { emsg(_(e_noident)); // found white space only @@ -4295,7 +3495,7 @@ static void nv_ident(cmdarg_T *cap) setpcmark(); curwin->w_cursor.col = (colnr_T)(ptr - get_cursor_line_ptr()); - if (!g_cmd && vim_iswordp((char_u *)ptr)) { + if (!g_cmd && vim_iswordp(ptr)) { STRCPY(buf, "\\<"); } no_smartcase = true; // don't use 'smartcase' now @@ -4310,11 +3510,7 @@ static void nv_ident(cmdarg_T *cap) case ']': tag_cmd = true; - if (p_cst) { - STRCPY(buf, "cstag "); - } else { - STRCPY(buf, "ts "); - } + STRCPY(buf, "ts "); break; default: @@ -4338,7 +3534,7 @@ static void nv_ident(cmdarg_T *cap) p = vim_strsave_fnameescape((const char *)ptr, VSE_NONE); } else { // Escape the argument properly for a shell command - p = (char *)vim_strsave_shellescape((char_u *)ptr, true, true); + p = vim_strsave_shellescape(ptr, true, true); } xfree(ptr); char *newbuf = xrealloc(buf, strlen(buf) + strlen(p) + 1); @@ -4347,9 +3543,9 @@ static void nv_ident(cmdarg_T *cap) xfree(p); } else { if (cmdchar == '*') { - aux_ptr = (p_magic ? "/.*~[^$\\" : "/^$\\"); + aux_ptr = (magic_isset() ? "/.*~[^$\\" : "/^$\\"); } else if (cmdchar == '#') { - aux_ptr = (p_magic ? "/?.*~[^$\\" : "/?^$\\"); + aux_ptr = (magic_isset() ? "/?.*~[^$\\" : "/?^$\\"); } else if (tag_cmd) { if (curbuf->b_help) { // ":help" handles unescaped argument @@ -4361,10 +3557,10 @@ static void nv_ident(cmdarg_T *cap) aux_ptr = "\\|\"\n*?["; } - p = buf + STRLEN(buf); + p = buf + strlen(buf); while (n-- > 0) { // put a backslash before \ and some others - if (vim_strchr(aux_ptr, *ptr) != NULL) { + if (vim_strchr(aux_ptr, (uint8_t)(*ptr)) != NULL) { *p++ = '\\'; } // When current byte is a part of multibyte character, copy all @@ -4381,7 +3577,7 @@ static void nv_ident(cmdarg_T *cap) // Execute the command. if (cmdchar == '*' || cmdchar == '#') { if (!g_cmd - && vim_iswordp(mb_prevptr((char_u *)get_cursor_line_ptr(), (char_u *)ptr))) { + && vim_iswordp(mb_prevptr(get_cursor_line_ptr(), ptr))) { STRCAT(buf, "\\>"); } @@ -4428,10 +3624,10 @@ bool get_visual_text(cmdarg_T *cap, char **pp, size_t *lenp) *lenp = strlen(*pp); } else { if (lt(curwin->w_cursor, VIsual)) { - *pp = (char *)ml_get_pos(&curwin->w_cursor); + *pp = ml_get_pos(&curwin->w_cursor); *lenp = (size_t)VIsual.col - (size_t)curwin->w_cursor.col + 1; } else { - *pp = (char *)ml_get_pos(&VIsual); + *pp = ml_get_pos(&VIsual); *lenp = (size_t)curwin->w_cursor.col - (size_t)VIsual.col + 1; } if (**pp == NUL) { @@ -4477,7 +3673,9 @@ static void nv_scroll(cmdarg_T *cap) && curwin->w_cursor.lnum > curwin->w_topline; n--) { (void)hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL); - curwin->w_cursor.lnum--; + if (curwin->w_cursor.lnum > curwin->w_topline) { + curwin->w_cursor.lnum--; + } } } else { curwin->w_cursor.lnum -= (linenr_T)cap->count1 - 1; @@ -4647,10 +3845,10 @@ static void nv_left(cmdarg_T *cap) // Don't adjust op_end now, otherwise it won't work. if ((cap->oap->op_type == OP_DELETE || cap->oap->op_type == OP_CHANGE) && !LINEEMPTY(curwin->w_cursor.lnum)) { - char_u *cp = (char_u *)get_cursor_pos_ptr(); + char *cp = get_cursor_pos_ptr(); if (*cp != NUL) { - curwin->w_cursor.col += utfc_ptr2len((char *)cp); + curwin->w_cursor.col += utfc_ptr2len(cp); } cap->retval |= CA_NO_ADJ_OP_END; } @@ -4676,13 +3874,14 @@ static void nv_up(cmdarg_T *cap) // <S-Up> is page up cap->arg = BACKWARD; nv_page(cap); - } else { - cap->oap->motion_type = kMTLineWise; - if (cursor_up(cap->count1, cap->oap->op_type == OP_NOP) == false) { - clearopbeep(cap->oap); - } else if (cap->arg) { - beginline(BL_WHITE | BL_FIX); - } + return; + } + + cap->oap->motion_type = kMTLineWise; + if (cursor_up(cap->count1, cap->oap->op_type == OP_NOP) == false) { + clearopbeep(cap->oap); + } else if (cap->arg) { + beginline(BL_WHITE | BL_FIX); } } @@ -4722,14 +3921,10 @@ static void nv_down(cmdarg_T *cap) /// Grab the file name under the cursor and edit it. static void nv_gotofile(cmdarg_T *cap) { - char_u *ptr; + char *ptr; linenr_T lnum = -1; - if (check_text_locked(cap->oap)) { - return; - } - if (curbuf_locked()) { - clearop(cap->oap); + if (check_text_or_curbuf_locked(cap->oap)) { return; } @@ -4741,7 +3936,7 @@ static void nv_gotofile(cmdarg_T *cap) (void)autowrite(curbuf, false); } setpcmark(); - if (do_ecmd(0, (char *)ptr, NULL, NULL, ECMD_LAST, + if (do_ecmd(0, ptr, NULL, NULL, ECMD_LAST, buf_hide(curbuf) ? ECMD_HIDE : 0, curwin) == OK && cap->nchar == 'F' && lnum >= 0) { curwin->w_cursor.lnum = lnum; @@ -4802,7 +3997,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 = (char *)getcmdline(cap->cmdchar, cap->count1, 0, true); + cap->searchbuf = getcmdline(cap->cmdchar, cap->count1, 0, true); if (cap->searchbuf == NULL) { clearop(oap); @@ -4848,7 +4043,7 @@ static int normal_search(cmdarg_T *cap, int dir, char *pat, int opt, int *wrappe curwin->w_set_curswant = true; CLEAR_FIELD(sia); - int i = do_search(cap->oap, dir, dir, (char_u *)pat, cap->count1, + int i = do_search(cap->oap, dir, dir, pat, cap->count1, opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, &sia); if (wrapped != NULL) { *wrapped = sia.sa_wrapped; @@ -4888,22 +4083,23 @@ static void nv_csearch(cmdarg_T *cap) cap->oap->motion_type = kMTCharWise; if (IS_SPECIAL(cap->nchar) || searchc(cap, t_cmd) == false) { clearopbeep(cap->oap); - } else { - curwin->w_set_curswant = true; - // Include a Tab for "tx" and for "dfx". - if (gchar_cursor() == TAB && virtual_active() && cap->arg == FORWARD - && (t_cmd || cap->oap->op_type != OP_NOP)) { - colnr_T scol, ecol; + return; + } - getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol); - curwin->w_cursor.coladd = ecol - scol; - } else { - curwin->w_cursor.coladd = 0; - } - adjust_for_sel(cap); - if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP) { - foldOpenCursor(); - } + curwin->w_set_curswant = true; + // Include a Tab for "tx" and for "dfx". + if (gchar_cursor() == TAB && virtual_active() && cap->arg == FORWARD + && (t_cmd || cap->oap->op_type != OP_NOP)) { + colnr_T scol, ecol; + + getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol); + curwin->w_cursor.coladd = ecol - scol; + } else { + curwin->w_cursor.coladd = 0; + } + adjust_for_sel(cap); + if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP) { + foldOpenCursor(); } } @@ -5057,7 +4253,7 @@ static void nv_brackets(cmdarg_T *cap) } else { // Make a copy, if the line was changed it will be freed. ptr = xstrnsave(ptr, len); - find_pattern_in_path((char_u *)ptr, 0, len, true, + find_pattern_in_path(ptr, 0, len, true, cap->count0 == 0 ? !isupper(cap->nchar) : false, (((cap->nchar & 0xf) == ('d' & 0xf)) ? FIND_DEFINE @@ -5150,9 +4346,8 @@ static void nv_brackets(cmdarg_T *cap) cap->nchar == 's', false, NULL) == 0) { clearopbeep(cap->oap); break; - } else { - curwin->w_set_curswant = true; } + curwin->w_set_curswant = true; } if (cap->oap->op_type == OP_NOP && (fdo_flags & FDO_SEARCH) && KeyTyped) { foldOpenCursor(); @@ -5226,25 +4421,28 @@ static void nv_brace(cmdarg_T *cap) cap->oap->inclusive = false; curwin->w_set_curswant = true; - if (findsent(cap->arg, cap->count1) == false) { + if (findsent(cap->arg, cap->count1) == FAIL) { clearopbeep(cap->oap); - } else { - // Don't leave the cursor on the NUL past end of line. - adjust_cursor(cap->oap); - curwin->w_cursor.coladd = 0; - if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP) { - foldOpenCursor(); - } + return; + } + + // Don't leave the cursor on the NUL past end of line. + adjust_cursor(cap->oap); + curwin->w_cursor.coladd = 0; + if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP) { + foldOpenCursor(); } } /// "m" command: Mark a position. static void nv_mark(cmdarg_T *cap) { - if (!checkclearop(cap->oap)) { - if (setmark(cap->nchar) == false) { - clearopbeep(cap->oap); - } + if (checkclearop(cap->oap)) { + return; + } + + if (setmark(cap->nchar) == false) { + clearopbeep(cap->oap); } } @@ -5258,11 +4456,12 @@ static void nv_findpar(cmdarg_T *cap) curwin->w_set_curswant = true; if (!findpar(&cap->oap->inclusive, cap->arg, cap->count1, NUL, false)) { clearopbeep(cap->oap); - } else { - curwin->w_cursor.coladd = 0; - if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP) { - foldOpenCursor(); - } + return; + } + + curwin->w_cursor.coladd = 0; + if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP) { + foldOpenCursor(); } } @@ -5283,20 +4482,22 @@ static void nv_undo(cmdarg_T *cap) /// <Undo> command. 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; + if (checkclearopq(cap->oap)) { + return; + } + + if (bt_prompt(curbuf)) { + clearopbeep(cap->oap); + return; } + u_undo((int)cap->count1); + curwin->w_set_curswant = true; } /// Handle the "r" command. static void nv_replace(cmdarg_T *cap) { - char_u *ptr; + char *ptr; int had_ctrl_v; if (checkclearop(cap->oap)) { @@ -5359,8 +4560,8 @@ static void nv_replace(cmdarg_T *cap) } // Abort if not enough characters to replace. - ptr = (char_u *)get_cursor_pos_ptr(); - if (STRLEN(ptr) < (unsigned)cap->count1 + ptr = get_cursor_pos_ptr(); + if (strlen(ptr) < (unsigned)cap->count1 || (mb_charlen(ptr) < cap->count1)) { clearopbeep(cap->oap); return; @@ -5501,15 +4702,20 @@ static void nv_Replace(cmdarg_T *cap) VIsual_mode_orig = VIsual_mode; // remember original area for gv VIsual_mode = 'V'; nv_operator(cap); - } else if (!checkclearopq(cap->oap)) { - if (!MODIFIABLE(curbuf)) { - emsg(_(e_modifiable)); - } else { - if (virtual_active()) { - coladvance(getviscol()); - } - invoke_edit(cap, false, cap->arg ? 'V' : 'R', false); + return; + } + + if (checkclearopq(cap->oap)) { + return; + } + + if (!MODIFIABLE(curbuf)) { + emsg(_(e_modifiable)); + } else { + if (virtual_active()) { + coladvance(getviscol()); } + invoke_edit(cap, false, cap->arg ? 'V' : 'R', false); } } @@ -5520,20 +4726,25 @@ static void nv_vreplace(cmdarg_T *cap) cap->cmdchar = 'r'; cap->nchar = cap->extra_char; nv_replace(cap); // Do same as "r" in Visual mode for now - } else if (!checkclearopq(cap->oap)) { - if (!MODIFIABLE(curbuf)) { - emsg(_(e_modifiable)); - } else { - if (cap->extra_char == Ctrl_V) { // get another character - cap->extra_char = get_literal(false); - } - stuffcharReadbuff(cap->extra_char); - stuffcharReadbuff(ESC); - if (virtual_active()) { - coladvance(getviscol()); - } - invoke_edit(cap, true, 'v', false); + return; + } + + if (checkclearopq(cap->oap)) { + return; + } + + if (!MODIFIABLE(curbuf)) { + emsg(_(e_modifiable)); + } else { + if (cap->extra_char == Ctrl_V) { // get another character + cap->extra_char = get_literal(false); } + stuffcharReadbuff(cap->extra_char); + stuffcharReadbuff(ESC); + if (virtual_active()) { + coladvance(getviscol()); + } + invoke_edit(cap, true, 'v', false); } } @@ -5691,6 +4902,10 @@ static void nv_gomark(cmdarg_T *cap) { int name; MarkMove flags = jop_flags & JOP_VIEW ? kMarkSetView : 0; // flags for moving to the mark + if (cap->oap->op_type != OP_NOP) { + // When there is a pending operator, do not restore the view as this is usually unexpected. + flags = 0; + } MarkMoveRes move_res = 0; // Result from moving to the mark const bool old_KeyTyped = KeyTyped; // getting file may reset it @@ -5730,42 +4945,44 @@ static void nv_pcmark(cmdarg_T *cap) MarkMoveRes move_res = 0; // Result from moving to the mark const bool old_KeyTyped = KeyTyped; // getting file may reset it. - if (!checkclearopq(cap->oap)) { - if (cap->cmdchar == TAB && mod_mask == MOD_MASK_CTRL) { - if (!goto_tabpage_lastused()) { - clearopbeep(cap->oap); - } - return; - } + if (checkclearopq(cap->oap)) { + return; + } - if (cap->cmdchar == 'g') { - fm = get_changelist(curbuf, curwin, (int)cap->count1); - } else { - fm = get_jumplist(curwin, (int)cap->count1); - flags |= KMarkNoContext | kMarkJumpList; - } - // Changelist and jumplist have their own error messages. Therefore avoid - // calling nv_mark_move_to() when not found to avoid incorrect error - // messages. - if (fm != NULL) { - move_res = nv_mark_move_to(cap, flags, fm); - } else if (cap->cmdchar == 'g') { - if (curbuf->b_changelistlen == 0) { - emsg(_("E664: changelist is empty")); - } else if (cap->count1 < 0) { - emsg(_("E662: At start of changelist")); - } else { - emsg(_("E663: At end of changelist")); - } - } else { + if (cap->cmdchar == TAB && mod_mask == MOD_MASK_CTRL) { + if (!goto_tabpage_lastused()) { clearopbeep(cap->oap); } - if (cap->oap->op_type == OP_NOP - && (move_res & kMarkSwitchedBuf || move_res & kMarkChangedLine) - && (fdo_flags & FDO_MARK) - && old_KeyTyped) { - foldOpenCursor(); + return; + } + + if (cap->cmdchar == 'g') { + fm = get_changelist(curbuf, curwin, (int)cap->count1); + } else { + fm = get_jumplist(curwin, (int)cap->count1); + flags |= KMarkNoContext | kMarkJumpList; + } + // Changelist and jumplist have their own error messages. Therefore avoid + // calling nv_mark_move_to() when not found to avoid incorrect error + // messages. + if (fm != NULL) { + move_res = nv_mark_move_to(cap, flags, fm); + } else if (cap->cmdchar == 'g') { + if (curbuf->b_changelistlen == 0) { + emsg(_("E664: changelist is empty")); + } else if (cap->count1 < 0) { + emsg(_("E662: At start of changelist")); + } else { + emsg(_("E663: At end of changelist")); } + } else { + clearopbeep(cap->oap); + } + if (cap->oap->op_type == OP_NOP + && (move_res & kMarkSwitchedBuf || move_res & kMarkChangedLine) + && (fdo_flags & FDO_MARK) + && old_KeyTyped) { + foldOpenCursor(); } } @@ -5840,10 +5057,12 @@ static void nv_visual(cmdarg_T *cap) VIsual_mode = resel_VIsual_mode; if (VIsual_mode == 'v') { if (resel_VIsual_line_count <= 1) { - validate_virtcol(); + update_curswant_force(); assert(cap->count0 >= INT_MIN && cap->count0 <= INT_MAX); - curwin->w_curswant = (curwin->w_virtcol - + resel_VIsual_vcol * (int)cap->count0 - 1); + curwin->w_curswant += resel_VIsual_vcol * (int)cap->count0; + if (*p_sel != 'e') { + curwin->w_curswant--; + } } else { curwin->w_curswant = resel_VIsual_vcol; } @@ -5853,10 +5072,9 @@ static void nv_visual(cmdarg_T *cap) curwin->w_curswant = MAXCOL; coladvance(MAXCOL); } else if (VIsual_mode == Ctrl_V) { - validate_virtcol(); + update_curswant_force(); assert(cap->count0 >= INT_MIN && cap->count0 <= INT_MAX); - curwin->w_curswant = (curwin->w_virtcol - + resel_VIsual_vcol * (int)cap->count0 - 1); + curwin->w_curswant += resel_VIsual_vcol * (int)cap->count0 - 1; coladvance(curwin->w_curswant); } else { curwin->w_set_curswant = true; @@ -6067,7 +5285,7 @@ static void nv_g_underscore_cmd(cmdarg_T *cap) return; } - char_u *ptr = (char_u *)get_cursor_line_ptr(); + char *ptr = get_cursor_line_ptr(); // In Visual mode we may end up after the line. if (curwin->w_cursor.col > 0 && ptr[curwin->w_cursor.col] == NUL) { @@ -6105,9 +5323,7 @@ static void nv_g_dollar_cmd(cmdarg_T *cap) coladvance((colnr_T)i); // Make sure we stick in this column. - validate_virtcol(); - curwin->w_curswant = curwin->w_virtcol; - curwin->w_set_curswant = false; + update_curswant_force(); if (curwin->w_cursor.col > 0 && curwin->w_p_wrap) { // Check for landing on a character that got split at // the end of the line. We do not want to advance to @@ -6138,9 +5354,7 @@ static void nv_g_dollar_cmd(cmdarg_T *cap) } // Make sure we stick in this column. - validate_virtcol(); - curwin->w_curswant = curwin->w_virtcol; - curwin->w_set_curswant = false; + update_curswant_force(); } } @@ -6278,7 +5492,7 @@ static void nv_g_cmd(cmdarg_T *cap) case 'M': oap->motion_type = kMTCharWise; oap->inclusive = false; - i = linetabsize((char_u *)get_cursor_line_ptr()); + i = linetabsize(get_cursor_line_ptr()); if (cap->count0 > 0 && cap->count0 <= 100) { coladvance((colnr_T)(i * cap->count0 / 100)); } else { @@ -6499,43 +5713,46 @@ static void nv_g_cmd(cmdarg_T *cap) /// Handle "o" and "O" commands. static void n_opencmd(cmdarg_T *cap) { - if (!checkclearopq(cap->oap)) { - if (cap->cmdchar == 'O') { - // Open above the first line of a folded sequence of lines - (void)hasFolding(curwin->w_cursor.lnum, - &curwin->w_cursor.lnum, NULL); - } else { - // Open below the last line of a folded sequence of lines - (void)hasFolding(curwin->w_cursor.lnum, - NULL, &curwin->w_cursor.lnum); - } - if (u_save((linenr_T)(curwin->w_cursor.lnum - - (cap->cmdchar == 'O' ? 1 : 0)), - (linenr_T)(curwin->w_cursor.lnum + - (cap->cmdchar == 'o' ? 1 : 0)) - ) - && open_line(cap->cmdchar == 'O' ? BACKWARD : FORWARD, - has_format_option(FO_OPEN_COMS) ? OPENLINE_DO_COM : 0, - 0, NULL)) { - if (win_cursorline_standout(curwin)) { - // force redraw of cursorline - curwin->w_valid &= ~VALID_CROW; - } - invoke_edit(cap, false, cap->cmdchar, true); + if (checkclearopq(cap->oap)) { + return; + } + + if (cap->cmdchar == 'O') { + // Open above the first line of a folded sequence of lines + (void)hasFolding(curwin->w_cursor.lnum, + &curwin->w_cursor.lnum, NULL); + } else { + // Open below the last line of a folded sequence of lines + (void)hasFolding(curwin->w_cursor.lnum, + NULL, &curwin->w_cursor.lnum); + } + if (u_save((linenr_T)(curwin->w_cursor.lnum - + (cap->cmdchar == 'O' ? 1 : 0)), + (linenr_T)(curwin->w_cursor.lnum + + (cap->cmdchar == 'o' ? 1 : 0))) + && open_line(cap->cmdchar == 'O' ? BACKWARD : FORWARD, + has_format_option(FO_OPEN_COMS) ? OPENLINE_DO_COM : 0, + 0, NULL)) { + if (win_cursorline_standout(curwin)) { + // force redraw of cursorline + curwin->w_valid &= ~VALID_CROW; } + invoke_edit(cap, false, cap->cmdchar, true); } } /// "." command: redo last change. static void nv_dot(cmdarg_T *cap) { - if (!checkclearopq(cap->oap)) { - // If "restart_edit" is true, the last but one command is repeated - // instead of the last command (inserting text). This is used for - // CTRL-O <.> in insert mode. - if (start_redo(cap->count0, restart_edit != 0 && !arrow_used) == false) { - clearopbeep(cap->oap); - } + if (checkclearopq(cap->oap)) { + return; + } + + // If "restart_edit" is true, the last but one command is repeated + // instead of the last command (inserting text). This is used for + // CTRL-O <.> in insert mode. + if (start_redo(cap->count0, restart_edit != 0 && !arrow_used) == false) { + clearopbeep(cap->oap); } } @@ -6559,10 +5776,12 @@ static void nv_redo_or_register(cmdarg_T *cap) return; } - if (!checkclearopq(cap->oap)) { - u_redo((int)cap->count1); - curwin->w_set_curswant = true; + if (checkclearopq(cap->oap)) { + return; } + + u_redo((int)cap->count1); + curwin->w_set_curswant = true; } /// Handle "U" command. @@ -6574,10 +5793,15 @@ static void nv_Undo(cmdarg_T *cap) cap->cmdchar = 'g'; cap->nchar = 'U'; nv_operator(cap); - } else if (!checkclearopq(cap->oap)) { - u_undoline(); - curwin->w_set_curswant = true; + return; + } + + if (checkclearopq(cap->oap)) { + return; } + + u_undoline(); + curwin->w_set_curswant = true; } /// '~' command: If tilde is not an operator and Visual is off: swap case of a @@ -7060,7 +6284,7 @@ static void nv_object(cmdarg_T *cap) { bool flag; bool include; - char_u *mps_save; + char *mps_save; if (cap->cmdchar == 'i') { include = false; // "ix" = inner object: exclude white space @@ -7068,7 +6292,7 @@ static void nv_object(cmdarg_T *cap) include = true; // "ax" = an object: include white space } // Make sure (), [], {} and <> are in 'matchpairs' - mps_save = (char_u *)curbuf->b_p_mps; + mps_save = curbuf->b_p_mps; curbuf->b_p_mps = "(:),{:},[:],<:>"; switch (cap->nchar) { @@ -7123,7 +6347,7 @@ static void nv_object(cmdarg_T *cap) break; } - curbuf->b_p_mps = (char *)mps_save; + curbuf->b_p_mps = mps_save; if (!flag) { clearopbeep(cap->oap); } @@ -7140,16 +6364,21 @@ static void nv_record(cmdarg_T *cap) cap->cmdchar = 'g'; cap->nchar = 'q'; nv_operator(cap); - } else if (!checkclearop(cap->oap)) { - if (cap->nchar == ':' || cap->nchar == '/' || cap->nchar == '?') { - stuffcharReadbuff(cap->nchar); - stuffcharReadbuff(K_CMDWIN); - } else { - // (stop) recording into a named register, unless executing a - // register. - if (reg_executing == 0 && do_record(cap->nchar) == FAIL) { - clearopbeep(cap->oap); - } + return; + } + + if (checkclearop(cap->oap)) { + return; + } + + if (cap->nchar == ':' || cap->nchar == '/' || cap->nchar == '?') { + stuffcharReadbuff(cap->nchar); + stuffcharReadbuff(K_CMDWIN); + } else { + // (stop) recording into a named register, unless executing a + // register. + if (reg_executing == 0 && do_record(cap->nchar) == FAIL) { + clearopbeep(cap->oap); } } } @@ -7191,24 +6420,29 @@ static void nv_join(cmdarg_T *cap) { if (VIsual_active) { // join the visual lines nv_operator(cap); - } else if (!checkclearop(cap->oap)) { - if (cap->count0 <= 1) { - cap->count0 = 2; // default for join is two lines! - } - if (curwin->w_cursor.lnum + cap->count0 - 1 > - curbuf->b_ml.ml_line_count) { - // can't join when on the last line - if (cap->count0 <= 2) { - clearopbeep(cap->oap); - return; - } - cap->count0 = curbuf->b_ml.ml_line_count - curwin->w_cursor.lnum + 1; - } + return; + } - prep_redo(cap->oap->regname, cap->count0, - NUL, cap->cmdchar, NUL, NUL, cap->nchar); - do_join((size_t)cap->count0, cap->nchar == NUL, true, true, true); + if (checkclearop(cap->oap)) { + return; + } + + if (cap->count0 <= 1) { + cap->count0 = 2; // default for join is two lines! } + if (curwin->w_cursor.lnum + cap->count0 - 1 > + curbuf->b_ml.ml_line_count) { + // can't join when on the last line + if (cap->count0 <= 2) { + clearopbeep(cap->oap); + return; + } + cap->count0 = curbuf->b_ml.ml_line_count - curwin->w_cursor.lnum + 1; + } + + prep_redo(cap->oap->regname, cap->count0, + NUL, cap->cmdchar, NUL, NUL, cap->nchar); + do_join((size_t)cap->count0, cap->nchar == NUL, true, true, true); } /// "P", "gP", "p" and "gp" commands. @@ -7238,117 +6472,121 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent) } 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') - ? FORWARD : BACKWARD; - flags |= PUT_FIXINDENT; - } else { - dir = (cap->cmdchar == 'P' - || ((cap->cmdchar == 'g' || cap->cmdchar == 'z') - && cap->nchar == 'P')) ? BACKWARD : FORWARD; - } - prep_redo_cmd(cap); - if (cap->cmdchar == 'g') { - flags |= PUT_CURSEND; - } else if (cap->cmdchar == 'z') { - flags |= PUT_BLOCK_INNER; - } - - if (VIsual_active) { - // Putting in Visual mode: The put text replaces the selected - // text. First delete the selected text, then put the new text. - // Need to save and restore the registers that the delete - // overwrites if the old contents is being put. - was_visual = true; - regname = cap->oap->regname; - bool keep_registers = cap->cmdchar == 'P'; - // '+' and '*' could be the same selection - bool clipoverwrite = (regname == '+' || regname == '*') && (cb_flags & CB_UNNAMEDMASK); - if (regname == 0 || regname == '"' || clipoverwrite - || ascii_isdigit(regname) || regname == '-') { - // The delete might overwrite the register we want to put, save it first - savereg = copy_register(regname); - } + return; + } - // To place the cursor correctly after a blockwise put, and to leave the - // text in the correct position when putting over a selection with - // 'virtualedit' and past the end of the line, we use the 'c' operator in - // do_put(), which requires the visual selection to still be active. - if (!VIsual_active || VIsual_mode == 'V' || regname != '.') { - // Now delete the selected text. Avoid messages here. - cap->cmdchar = 'd'; - cap->nchar = NUL; - cap->oap->regname = keep_registers ? '_' : NUL; - msg_silent++; - nv_operator(cap); - do_pending_operator(cap, 0, false); - empty = (curbuf->b_ml.ml_flags & ML_EMPTY); - msg_silent--; + if (bt_prompt(curbuf) && !prompt_curpos_editable()) { + clearopbeep(cap->oap); + return; + } - // delete PUT_LINE_BACKWARD; - cap->oap->regname = regname; - } + if (fix_indent) { + dir = (cap->cmdchar == ']' && cap->nchar == 'p') + ? FORWARD : BACKWARD; + flags |= PUT_FIXINDENT; + } else { + dir = (cap->cmdchar == 'P' + || ((cap->cmdchar == 'g' || cap->cmdchar == 'z') + && cap->nchar == 'P')) ? BACKWARD : FORWARD; + } + prep_redo_cmd(cap); + if (cap->cmdchar == 'g') { + flags |= PUT_CURSEND; + } else if (cap->cmdchar == 'z') { + flags |= PUT_BLOCK_INNER; + } - // 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') { - flags |= PUT_LINE_SPLIT; - } - 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) - || (VIsual_mode == 'V' - && curwin->w_cursor.lnum < curbuf->b_op_start.lnum)) { - // cursor is at the end of the line or end of file, put - // forward. - dir = FORWARD; - } - // May have been reset in do_put(). - VIsual_active = true; + if (VIsual_active) { + // Putting in Visual mode: The put text replaces the selected + // text. First delete the selected text, then put the new text. + // Need to save and restore the registers that the delete + // overwrites if the old contents is being put. + was_visual = true; + regname = cap->oap->regname; + bool keep_registers = cap->cmdchar == 'P'; + // '+' and '*' could be the same selection + bool clipoverwrite = (regname == '+' || regname == '*') && (cb_flags & CB_UNNAMEDMASK); + if (regname == 0 || regname == '"' || clipoverwrite + || ascii_isdigit(regname) || regname == '-') { + // The delete might overwrite the register we want to put, save it first + savereg = copy_register(regname); + } + + // To place the cursor correctly after a blockwise put, and to leave the + // text in the correct position when putting over a selection with + // 'virtualedit' and past the end of the line, we use the 'c' operator in + // do_put(), which requires the visual selection to still be active. + if (!VIsual_active || VIsual_mode == 'V' || regname != '.') { + // Now delete the selected text. Avoid messages here. + cap->cmdchar = 'd'; + cap->nchar = NUL; + cap->oap->regname = keep_registers ? '_' : NUL; + msg_silent++; + nv_operator(cap); + do_pending_operator(cap, 0, false); + empty = (curbuf->b_ml.ml_flags & ML_EMPTY); + msg_silent--; + + // delete PUT_LINE_BACKWARD; + 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 + // charwise, split a line when putting lines. + if (VIsual_mode == 'V') { + flags |= PUT_LINE; + } else if (VIsual_mode == 'v') { + flags |= PUT_LINE_SPLIT; + } + 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) + || (VIsual_mode == 'V' + && curwin->w_cursor.lnum < curbuf->b_op_start.lnum)) { + // cursor is at the end of the line or end of file, put + // forward. + dir = FORWARD; } - do_put(cap->oap->regname, savereg, dir, cap->count1, flags); + // May have been reset in do_put(). + VIsual_active = true; + } + do_put(cap->oap->regname, savereg, dir, cap->count1, flags); - // If a register was saved, free it - if (savereg != NULL) { - free_register(savereg); - xfree(savereg); - } + // If a register was saved, free it + if (savereg != NULL) { + free_register(savereg); + xfree(savereg); + } - // What to reselect with "gv"? Selecting the just put text seems to - // be the most useful, since the original text was removed. - if (was_visual) { - curbuf->b_visual.vi_start = curbuf->b_op_start; - curbuf->b_visual.vi_end = curbuf->b_op_end; - // need to adjust cursor position - if (*p_sel == 'e') { - inc(&curbuf->b_visual.vi_end); - } + // What to reselect with "gv"? Selecting the just put text seems to + // be the most useful, since the original text was removed. + if (was_visual) { + curbuf->b_visual.vi_start = curbuf->b_op_start; + curbuf->b_visual.vi_end = curbuf->b_op_end; + // need to adjust cursor position + if (*p_sel == 'e') { + inc(&curbuf->b_visual.vi_end); } + } - // When all lines were selected and deleted do_put() leaves an empty - // line that needs to be deleted now. - if (empty && *ml_get(curbuf->b_ml.ml_line_count) == NUL) { - ml_delete(curbuf->b_ml.ml_line_count, true); - deleted_lines(curbuf->b_ml.ml_line_count + 1, 1); + // When all lines were selected and deleted do_put() leaves an empty + // line that needs to be deleted now. + if (empty && *ml_get(curbuf->b_ml.ml_line_count) == NUL) { + ml_delete(curbuf->b_ml.ml_line_count, true); + deleted_lines(curbuf->b_ml.ml_line_count + 1, 1); - // If the cursor was in that line, move it to the end of the last - // line. - if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { - curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - coladvance(MAXCOL); - } + // If the cursor was in that line, move it to the end of the last + // line. + if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { + curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; + coladvance(MAXCOL); } - auto_format(false, true); } + auto_format(false, true); } /// "o" and "O" commands. @@ -7392,12 +6630,6 @@ static void nv_event(cmdarg_T *cap) } } -/// @return true when 'mousemodel' is set to "popup" or "popup_setpos". -static bool mouse_model_popup(void) -{ - return p_mousem[0] == 'p'; -} - void normal_cmd(oparg_T *oap, bool toplevel) { NormalState s; |