To: vim_dev@googlegroups.com Subject: Patch 8.1.2104 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.2104 Problem: The normal.c file is too big. Solution: Move do_pending_operator() to ops.c. (Yegappan Lakshmanan, closes #4999). Files: src/normal.c, src/ops.c, src/proto/normal.pro, src/proto/ops.pro, src/globals.h *** ../vim-8.1.2103/src/normal.c 2019-09-28 19:04:06.993029586 +0200 --- src/normal.c 2019-09-30 23:04:19.159910563 +0200 *************** *** 14,37 **** #include "vim.h" ! /* ! * The Visual area is remembered for reselection. ! */ ! static int resel_VIsual_mode = NUL; /* 'v', 'V', or Ctrl-V */ ! static linenr_T resel_VIsual_line_count; /* number of lines */ ! static colnr_T resel_VIsual_vcol; /* nr of cols or end col */ ! static int VIsual_mode_orig = NUL; /* saved Visual mode */ ! static int restart_VIsual_select = 0; #ifdef FEAT_EVAL static void set_vcount_ca(cmdarg_T *cap, int *set_prevcount); #endif static int nv_compare(const void *s1, const void *s2); - static void op_colon(oparg_T *oap); - static void op_function(oparg_T *oap); static void unshift_special(cmdarg_T *cap); - static void may_clear_cmdline(void); #ifdef FEAT_CMDL_INFO static void del_from_showcmd(int); #endif --- 14,27 ---- #include "vim.h" ! static int VIsual_mode_orig = NUL; // saved Visual mode static int restart_VIsual_select = 0; #ifdef FEAT_EVAL static void set_vcount_ca(cmdarg_T *cap, int *set_prevcount); #endif static int nv_compare(const void *s1, const void *s2); static void unshift_special(cmdarg_T *cap); #ifdef FEAT_CMDL_INFO static void del_from_showcmd(int); #endif *************** *** 115,121 **** static void nv_beginline(cmdarg_T *cap); static void adjust_cursor(oparg_T *oap); static void adjust_for_sel(cmdarg_T *cap); - static int unadjust_for_sel(void); static void nv_select(cmdarg_T *cap); static void nv_goto(cmdarg_T *cap); static void nv_normal(cmdarg_T *cap); --- 105,110 ---- *************** *** 139,145 **** static void nv_drop(cmdarg_T *cap); #endif static void nv_cursorhold(cmdarg_T *cap); - static void get_op_vcol(oparg_T *oap, colnr_T col, int initial); static char *e_noident = N_("E349: No identifier under cursor"); --- 128,133 ---- *************** *** 1295,2194 **** #endif /* - * Handle an operator after Visual mode or when the movement is finished. - * "gui_yank" is true when yanking text for the clipboard. - */ - void - do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank) - { - oparg_T *oap = cap->oap; - pos_T old_cursor; - int empty_region_error; - int restart_edit_save; - #ifdef FEAT_LINEBREAK - int lbr_saved = curwin->w_p_lbr; - #endif - - /* The visual area is remembered for redo */ - static int redo_VIsual_mode = NUL; /* 'v', 'V', or Ctrl-V */ - static linenr_T redo_VIsual_line_count; /* number of lines */ - static colnr_T redo_VIsual_vcol; /* number of cols or end column */ - static long redo_VIsual_count; /* count for Visual operator */ - static int redo_VIsual_arg; /* extra argument */ - int include_line_break = FALSE; - - #if defined(FEAT_CLIPBOARD) - /* - * Yank the visual area into the GUI selection register before we operate - * on it and lose it forever. - * Don't do it if a specific register was specified, so that ""x"*P works. - * This could call do_pending_operator() recursively, but that's OK - * because gui_yank will be TRUE for the nested call. - */ - if ((clip_star.available || clip_plus.available) - && oap->op_type != OP_NOP - && !gui_yank - && VIsual_active - && !redo_VIsual_busy - && oap->regname == 0) - clip_auto_select(); - #endif - old_cursor = curwin->w_cursor; - - /* - * If an operation is pending, handle it... - */ - if ((finish_op || VIsual_active) && oap->op_type != OP_NOP) - { - // Yank can be redone when 'y' is in 'cpoptions', but not when yanking - // for the clipboard. - int redo_yank = vim_strchr(p_cpo, CPO_YANK) != NULL && !gui_yank; - - #ifdef FEAT_LINEBREAK - /* Avoid a problem with unwanted linebreaks in block mode. */ - if (curwin->w_p_lbr) - curwin->w_valid &= ~VALID_VIRTCOL; - curwin->w_p_lbr = FALSE; - #endif - oap->is_VIsual = VIsual_active; - if (oap->motion_force == 'V') - oap->motion_type = MLINE; - else if (oap->motion_force == 'v') - { - /* If the motion was linewise, "inclusive" will not have been set. - * Use "exclusive" to be consistent. Makes "dvj" work nice. */ - if (oap->motion_type == MLINE) - oap->inclusive = FALSE; - /* If the motion already was characterwise, toggle "inclusive" */ - else if (oap->motion_type == MCHAR) - oap->inclusive = !oap->inclusive; - oap->motion_type = MCHAR; - } - else if (oap->motion_force == Ctrl_V) - { - /* Change line- or characterwise motion into Visual block mode. */ - if (!VIsual_active) - { - VIsual_active = TRUE; - VIsual = oap->start; - } - VIsual_mode = Ctrl_V; - VIsual_select = FALSE; - VIsual_reselect = FALSE; - } - - /* Only redo yank when 'y' flag is in 'cpoptions'. */ - /* Never redo "zf" (define fold). */ - if ((redo_yank || oap->op_type != OP_YANK) - && ((!VIsual_active || oap->motion_force) - /* Also redo Operator-pending Visual mode mappings */ - || (VIsual_active && cap->cmdchar == ':' - && oap->op_type != OP_COLON)) - && cap->cmdchar != 'D' - #ifdef FEAT_FOLDING - && oap->op_type != OP_FOLD - && oap->op_type != OP_FOLDOPEN - && oap->op_type != OP_FOLDOPENREC - && oap->op_type != OP_FOLDCLOSE - && oap->op_type != OP_FOLDCLOSEREC - && oap->op_type != OP_FOLDDEL - && oap->op_type != OP_FOLDDELREC - #endif - ) - { - prep_redo(oap->regname, cap->count0, - get_op_char(oap->op_type), get_extra_op_char(oap->op_type), - oap->motion_force, cap->cmdchar, cap->nchar); - if (cap->cmdchar == '/' || cap->cmdchar == '?') /* was a search */ - { - /* - * If 'cpoptions' does not contain 'r', insert the search - * pattern to really repeat the same command. - */ - if (vim_strchr(p_cpo, CPO_REDO) == NULL) - AppendToRedobuffLit(cap->searchbuf, -1); - AppendToRedobuff(NL_STR); - } - else if (cap->cmdchar == ':') - { - /* do_cmdline() has stored the first typed line in - * "repeat_cmdline". When several lines are typed repeating - * won't be possible. */ - if (repeat_cmdline == NULL) - ResetRedobuff(); - else - { - AppendToRedobuffLit(repeat_cmdline, -1); - AppendToRedobuff(NL_STR); - VIM_CLEAR(repeat_cmdline); - } - } - } - - if (redo_VIsual_busy) - { - /* Redo of an operation on a Visual area. Use the same size from - * redo_VIsual_line_count and redo_VIsual_vcol. */ - oap->start = curwin->w_cursor; - curwin->w_cursor.lnum += redo_VIsual_line_count - 1; - if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) - curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - VIsual_mode = redo_VIsual_mode; - if (redo_VIsual_vcol == MAXCOL || VIsual_mode == 'v') - { - if (VIsual_mode == 'v') - { - if (redo_VIsual_line_count <= 1) - { - validate_virtcol(); - curwin->w_curswant = - curwin->w_virtcol + redo_VIsual_vcol - 1; - } - else - curwin->w_curswant = redo_VIsual_vcol; - } - else - { - curwin->w_curswant = MAXCOL; - } - coladvance(curwin->w_curswant); - } - cap->count0 = redo_VIsual_count; - if (redo_VIsual_count != 0) - cap->count1 = redo_VIsual_count; - else - cap->count1 = 1; - } - else if (VIsual_active) - { - if (!gui_yank) - { - /* Save the current VIsual area for '< and '> marks, and "gv" */ - curbuf->b_visual.vi_start = VIsual; - curbuf->b_visual.vi_end = curwin->w_cursor; - curbuf->b_visual.vi_mode = VIsual_mode; - if (VIsual_mode_orig != NUL) - { - curbuf->b_visual.vi_mode = VIsual_mode_orig; - VIsual_mode_orig = NUL; - } - curbuf->b_visual.vi_curswant = curwin->w_curswant; - # ifdef FEAT_EVAL - curbuf->b_visual_mode_eval = VIsual_mode; - # endif - } - - /* In Select mode, a linewise selection is operated upon like a - * characterwise selection. - * Special case: gH deletes the last line. */ - if (VIsual_select && VIsual_mode == 'V' - && cap->oap->op_type != OP_DELETE) - { - if (LT_POS(VIsual, curwin->w_cursor)) - { - VIsual.col = 0; - curwin->w_cursor.col = - (colnr_T)STRLEN(ml_get(curwin->w_cursor.lnum)); - } - else - { - curwin->w_cursor.col = 0; - VIsual.col = (colnr_T)STRLEN(ml_get(VIsual.lnum)); - } - VIsual_mode = 'v'; - } - /* If 'selection' is "exclusive", backup one character for - * charwise selections. */ - else if (VIsual_mode == 'v') - include_line_break = unadjust_for_sel(); - - oap->start = VIsual; - if (VIsual_mode == 'V') - { - oap->start.col = 0; - oap->start.coladd = 0; - } - } - - /* - * Set oap->start to the first position of the operated text, oap->end - * to the end of the operated text. w_cursor is equal to oap->start. - */ - if (LT_POS(oap->start, curwin->w_cursor)) - { - #ifdef FEAT_FOLDING - /* Include folded lines completely. */ - if (!VIsual_active) - { - if (hasFolding(oap->start.lnum, &oap->start.lnum, NULL)) - oap->start.col = 0; - if ((curwin->w_cursor.col > 0 || oap->inclusive) - && hasFolding(curwin->w_cursor.lnum, NULL, - &curwin->w_cursor.lnum)) - curwin->w_cursor.col = (colnr_T)STRLEN(ml_get_curline()); - } - #endif - oap->end = curwin->w_cursor; - curwin->w_cursor = oap->start; - - /* w_virtcol may have been updated; if the cursor goes back to its - * previous position w_virtcol becomes invalid and isn't updated - * automatically. */ - curwin->w_valid &= ~VALID_VIRTCOL; - } - else - { - #ifdef FEAT_FOLDING - /* Include folded lines completely. */ - if (!VIsual_active && oap->motion_type == MLINE) - { - if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, - NULL)) - curwin->w_cursor.col = 0; - if (hasFolding(oap->start.lnum, NULL, &oap->start.lnum)) - oap->start.col = (colnr_T)STRLEN(ml_get(oap->start.lnum)); - } - #endif - oap->end = oap->start; - oap->start = curwin->w_cursor; - } - - /* Just in case lines were deleted that make the position invalid. */ - check_pos(curwin->w_buffer, &oap->end); - oap->line_count = oap->end.lnum - oap->start.lnum + 1; - - /* Set "virtual_op" before resetting VIsual_active. */ - virtual_op = virtual_active(); - - if (VIsual_active || redo_VIsual_busy) - { - get_op_vcol(oap, redo_VIsual_vcol, TRUE); - - if (!redo_VIsual_busy && !gui_yank) - { - /* - * Prepare to reselect and redo Visual: this is based on the - * size of the Visual text - */ - resel_VIsual_mode = VIsual_mode; - if (curwin->w_curswant == MAXCOL) - resel_VIsual_vcol = MAXCOL; - else - { - if (VIsual_mode != Ctrl_V) - getvvcol(curwin, &(oap->end), - NULL, NULL, &oap->end_vcol); - if (VIsual_mode == Ctrl_V || oap->line_count <= 1) - { - if (VIsual_mode != Ctrl_V) - getvvcol(curwin, &(oap->start), - &oap->start_vcol, NULL, NULL); - resel_VIsual_vcol = oap->end_vcol - oap->start_vcol + 1; - } - else - resel_VIsual_vcol = oap->end_vcol; - } - resel_VIsual_line_count = oap->line_count; - } - - /* can't redo yank (unless 'y' is in 'cpoptions') and ":" */ - if ((redo_yank || oap->op_type != OP_YANK) - && oap->op_type != OP_COLON - #ifdef FEAT_FOLDING - && oap->op_type != OP_FOLD - && oap->op_type != OP_FOLDOPEN - && oap->op_type != OP_FOLDOPENREC - && oap->op_type != OP_FOLDCLOSE - && oap->op_type != OP_FOLDCLOSEREC - && oap->op_type != OP_FOLDDEL - && oap->op_type != OP_FOLDDELREC - #endif - && oap->motion_force == NUL - ) - { - /* Prepare for redoing. Only use the nchar field for "r", - * otherwise it might be the second char of the operator. */ - if (cap->cmdchar == 'g' && (cap->nchar == 'n' - || cap->nchar == 'N')) - prep_redo(oap->regname, cap->count0, - get_op_char(oap->op_type), get_extra_op_char(oap->op_type), - oap->motion_force, cap->cmdchar, cap->nchar); - else if (cap->cmdchar != ':') - { - int nchar = oap->op_type == OP_REPLACE ? cap->nchar : NUL; - - /* reverse what nv_replace() did */ - if (nchar == REPLACE_CR_NCHAR) - nchar = CAR; - else if (nchar == REPLACE_NL_NCHAR) - nchar = NL; - prep_redo(oap->regname, 0L, NUL, 'v', - get_op_char(oap->op_type), - get_extra_op_char(oap->op_type), - nchar); - } - if (!redo_VIsual_busy) - { - redo_VIsual_mode = resel_VIsual_mode; - redo_VIsual_vcol = resel_VIsual_vcol; - redo_VIsual_line_count = resel_VIsual_line_count; - redo_VIsual_count = cap->count0; - redo_VIsual_arg = cap->arg; - } - } - - /* - * oap->inclusive defaults to TRUE. - * If oap->end is on a NUL (empty line) oap->inclusive becomes - * FALSE. This makes "d}P" and "v}dP" work the same. - */ - if (oap->motion_force == NUL || oap->motion_type == MLINE) - oap->inclusive = TRUE; - if (VIsual_mode == 'V') - oap->motion_type = MLINE; - else - { - oap->motion_type = MCHAR; - if (VIsual_mode != Ctrl_V && *ml_get_pos(&(oap->end)) == NUL - && (include_line_break || !virtual_op)) - { - oap->inclusive = FALSE; - /* Try to include the newline, unless it's an operator - * that works on lines only. */ - if (*p_sel != 'o' - && !op_on_lines(oap->op_type) - && oap->end.lnum < curbuf->b_ml.ml_line_count) - { - ++oap->end.lnum; - oap->end.col = 0; - oap->end.coladd = 0; - ++oap->line_count; - } - } - } - - redo_VIsual_busy = FALSE; - - /* - * Switch Visual off now, so screen updating does - * not show inverted text when the screen is redrawn. - * With OP_YANK and sometimes with OP_COLON and OP_FILTER there is - * no screen redraw, so it is done here to remove the inverted - * part. - */ - if (!gui_yank) - { - VIsual_active = FALSE; - #ifdef FEAT_MOUSE - setmouse(); - mouse_dragging = 0; - #endif - may_clear_cmdline(); - if ((oap->op_type == OP_YANK - || oap->op_type == OP_COLON - || oap->op_type == OP_FUNCTION - || oap->op_type == OP_FILTER) - && oap->motion_force == NUL) - { - #ifdef FEAT_LINEBREAK - /* make sure redrawing is correct */ - curwin->w_p_lbr = lbr_saved; - #endif - redraw_curbuf_later(INVERTED); - } - } - } - - /* 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) - oap->end.col += l - 1; - } - curwin->w_set_curswant = TRUE; - - /* - * oap->empty is set when start and end are the same. The inclusive - * flag affects this too, unless yanking and the end is on a NUL. - */ - oap->empty = (oap->motion_type == MCHAR - && (!oap->inclusive - || (oap->op_type == OP_YANK - && gchar_pos(&oap->end) == NUL)) - && EQUAL_POS(oap->start, oap->end) - && !(virtual_op && oap->start.coladd != oap->end.coladd)); - /* - * For delete, change and yank, it's an error to operate on an - * empty region, when 'E' included in 'cpoptions' (Vi compatible). - */ - empty_region_error = (oap->empty - && vim_strchr(p_cpo, CPO_EMPTYREGION) != NULL); - - /* Force a redraw when operating on an empty Visual region, when - * 'modifiable is off or creating a fold. */ - if (oap->is_VIsual && (oap->empty || !curbuf->b_p_ma - #ifdef FEAT_FOLDING - || oap->op_type == OP_FOLD - #endif - )) - { - #ifdef FEAT_LINEBREAK - curwin->w_p_lbr = lbr_saved; - #endif - redraw_curbuf_later(INVERTED); - } - - /* - * If the end of an operator is in column one while oap->motion_type - * is MCHAR and oap->inclusive is FALSE, we put op_end after the last - * character in the previous line. If op_start is on or before the - * first non-blank in the line, the operator becomes linewise - * (strange, but that's the way vi does it). - */ - if ( oap->motion_type == MCHAR - && oap->inclusive == FALSE - && !(cap->retval & CA_NO_ADJ_OP_END) - && oap->end.col == 0 - && (!oap->is_VIsual || *p_sel == 'o') - && !oap->block_mode - && oap->line_count > 1) - { - oap->end_adjusted = TRUE; /* remember that we did this */ - --oap->line_count; - --oap->end.lnum; - if (inindent(0)) - oap->motion_type = MLINE; - else - { - oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum)); - if (oap->end.col) - { - --oap->end.col; - oap->inclusive = TRUE; - } - } - } - else - oap->end_adjusted = FALSE; - - switch (oap->op_type) - { - case OP_LSHIFT: - case OP_RSHIFT: - op_shift(oap, TRUE, oap->is_VIsual ? (int)cap->count1 : 1); - auto_format(FALSE, TRUE); - break; - - case OP_JOIN_NS: - case OP_JOIN: - if (oap->line_count < 2) - oap->line_count = 2; - if (curwin->w_cursor.lnum + oap->line_count - 1 > - curbuf->b_ml.ml_line_count) - beep_flush(); - else - { - (void)do_join(oap->line_count, oap->op_type == OP_JOIN, - TRUE, TRUE, TRUE); - auto_format(FALSE, TRUE); - } - break; - - case OP_DELETE: - VIsual_reselect = FALSE; /* don't reselect now */ - if (empty_region_error) - { - vim_beep(BO_OPER); - CancelRedo(); - } - else - { - (void)op_delete(oap); - if (oap->motion_type == MLINE && has_format_option(FO_AUTO)) - u_save_cursor(); /* cursor line wasn't saved yet */ - auto_format(FALSE, TRUE); - } - break; - - case OP_YANK: - if (empty_region_error) - { - if (!gui_yank) - { - vim_beep(BO_OPER); - CancelRedo(); - } - } - else - { - #ifdef FEAT_LINEBREAK - curwin->w_p_lbr = lbr_saved; - #endif - (void)op_yank(oap, FALSE, !gui_yank); - } - check_cursor_col(); - break; - - case OP_CHANGE: - VIsual_reselect = FALSE; /* don't reselect now */ - if (empty_region_error) - { - vim_beep(BO_OPER); - CancelRedo(); - } - else - { - /* This is a new edit command, not a restart. Need to - * remember it to make 'insertmode' work with mappings for - * Visual mode. But do this only once and not when typed and - * 'insertmode' isn't set. */ - if (p_im || !KeyTyped) - restart_edit_save = restart_edit; - else - restart_edit_save = 0; - restart_edit = 0; - #ifdef FEAT_LINEBREAK - /* 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); - } - #endif - /* Reset finish_op now, don't want it set inside edit(). */ - finish_op = FALSE; - if (op_change(oap)) /* will call edit() */ - cap->retval |= CA_COMMAND_BUSY; - if (restart_edit == 0) - restart_edit = restart_edit_save; - } - break; - - case OP_FILTER: - if (vim_strchr(p_cpo, CPO_FILTER) != NULL) - AppendToRedobuff((char_u *)"!\r"); /* use any last used !cmd */ - else - bangredo = TRUE; /* do_bang() will put cmd in redo buffer */ - /* FALLTHROUGH */ - - case OP_INDENT: - case OP_COLON: - - #if defined(FEAT_LISP) || defined(FEAT_CINDENT) - /* - * If 'equalprg' is empty, do the indenting internally. - */ - if (oap->op_type == OP_INDENT && *get_equalprg() == NUL) - { - # ifdef FEAT_LISP - if (curbuf->b_p_lisp) - { - op_reindent(oap, get_lisp_indent); - break; - } - # endif - # ifdef FEAT_CINDENT - op_reindent(oap, - # ifdef FEAT_EVAL - *curbuf->b_p_inde != NUL ? get_expr_indent : - # endif - get_c_indent); - break; - # endif - } - #endif - - op_colon(oap); - break; - - case OP_TILDE: - case OP_UPPER: - case OP_LOWER: - case OP_ROT13: - if (empty_region_error) - { - vim_beep(BO_OPER); - CancelRedo(); - } - else - op_tilde(oap); - check_cursor_col(); - break; - - case OP_FORMAT: - #if defined(FEAT_EVAL) - if (*curbuf->b_p_fex != NUL) - op_formatexpr(oap); /* use expression */ - else - #endif - if (*p_fp != NUL || *curbuf->b_p_fp != NUL) - op_colon(oap); /* use external command */ - else - op_format(oap, FALSE); /* use internal function */ - break; - - case OP_FORMAT2: - op_format(oap, TRUE); /* use internal function */ - break; - - case OP_FUNCTION: - #ifdef FEAT_LINEBREAK - /* Restore linebreak, so that when the user edits it looks as - * before. */ - curwin->w_p_lbr = lbr_saved; - #endif - op_function(oap); /* call 'operatorfunc' */ - break; - - case OP_INSERT: - case OP_APPEND: - VIsual_reselect = FALSE; /* don't reselect now */ - if (empty_region_error) - { - vim_beep(BO_OPER); - CancelRedo(); - } - else - { - /* This is a new edit command, not a restart. Need to - * remember it to make 'insertmode' work with mappings for - * Visual mode. But do this only once. */ - restart_edit_save = restart_edit; - restart_edit = 0; - #ifdef FEAT_LINEBREAK - /* 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); - } - #endif - op_insert(oap, cap->count1); - #ifdef FEAT_LINEBREAK - /* Reset linebreak, so that formatting works correctly. */ - curwin->w_p_lbr = FALSE; - #endif - - /* TODO: when inserting in several lines, should format all - * the lines. */ - auto_format(FALSE, TRUE); - - if (restart_edit == 0) - restart_edit = restart_edit_save; - else - cap->retval |= CA_COMMAND_BUSY; - } - break; - - case OP_REPLACE: - VIsual_reselect = FALSE; /* don't reselect now */ - if (empty_region_error) - { - vim_beep(BO_OPER); - CancelRedo(); - } - else - { - #ifdef FEAT_LINEBREAK - /* 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); - } - #endif - op_replace(oap, cap->nchar); - } - break; - - #ifdef FEAT_FOLDING - case OP_FOLD: - VIsual_reselect = FALSE; /* don't reselect now */ - foldCreate(oap->start.lnum, oap->end.lnum); - break; - - case OP_FOLDOPEN: - case OP_FOLDOPENREC: - case OP_FOLDCLOSE: - case OP_FOLDCLOSEREC: - VIsual_reselect = FALSE; /* don't reselect now */ - opFoldRange(oap->start.lnum, oap->end.lnum, - oap->op_type == OP_FOLDOPEN - || oap->op_type == OP_FOLDOPENREC, - oap->op_type == OP_FOLDOPENREC - || oap->op_type == OP_FOLDCLOSEREC, - oap->is_VIsual); - break; - - 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); - break; - #endif - case OP_NR_ADD: - case OP_NR_SUB: - if (empty_region_error) - { - vim_beep(BO_OPER); - CancelRedo(); - } - else - { - VIsual_active = TRUE; - #ifdef FEAT_LINEBREAK - curwin->w_p_lbr = lbr_saved; - #endif - op_addsub(oap, cap->count1, redo_VIsual_arg); - VIsual_active = FALSE; - } - check_cursor_col(); - break; - default: - clearopbeep(oap); - } - virtual_op = MAYBE; - if (!gui_yank) - { - /* - * if 'sol' not set, go back to old column for some commands - */ - if (!p_sol && oap->motion_type == MLINE && !oap->end_adjusted - && (oap->op_type == OP_LSHIFT || oap->op_type == OP_RSHIFT - || oap->op_type == OP_DELETE)) - { - #ifdef FEAT_LINEBREAK - curwin->w_p_lbr = FALSE; - #endif - coladvance(curwin->w_curswant = old_col); - } - } - else - { - curwin->w_cursor = old_cursor; - } - oap->block_mode = FALSE; - clearop(oap); - motion_force = NUL; - } - #ifdef FEAT_LINEBREAK - curwin->w_p_lbr = lbr_saved; - #endif - } - - /* - * Handle indent and format operators and visual mode ":". - */ - static void - op_colon(oparg_T *oap) - { - stuffcharReadbuff(':'); - if (oap->is_VIsual) - stuffReadbuff((char_u *)"'<,'>"); - else - { - /* - * Make the range look nice, so it can be repeated. - */ - if (oap->start.lnum == curwin->w_cursor.lnum) - stuffcharReadbuff('.'); - else - stuffnumReadbuff((long)oap->start.lnum); - if (oap->end.lnum != oap->start.lnum) - { - stuffcharReadbuff(','); - if (oap->end.lnum == curwin->w_cursor.lnum) - stuffcharReadbuff('.'); - else if (oap->end.lnum == curbuf->b_ml.ml_line_count) - stuffcharReadbuff('$'); - else if (oap->start.lnum == curwin->w_cursor.lnum) - { - stuffReadbuff((char_u *)".+"); - stuffnumReadbuff((long)oap->line_count - 1); - } - else - stuffnumReadbuff((long)oap->end.lnum); - } - } - if (oap->op_type != OP_COLON) - stuffReadbuff((char_u *)"!"); - if (oap->op_type == OP_INDENT) - { - #ifndef FEAT_CINDENT - if (*get_equalprg() == NUL) - stuffReadbuff((char_u *)"indent"); - else - #endif - stuffReadbuff(get_equalprg()); - stuffReadbuff((char_u *)"\n"); - } - else if (oap->op_type == OP_FORMAT) - { - if (*curbuf->b_p_fp != NUL) - stuffReadbuff(curbuf->b_p_fp); - else if (*p_fp != NUL) - stuffReadbuff(p_fp); - else - stuffReadbuff((char_u *)"fmt"); - stuffReadbuff((char_u *)"\n']"); - } - - /* - * do_cmdline() does the rest - */ - } - - /* - * Handle the "g@" operator: call 'operatorfunc'. - */ - static void - op_function(oparg_T *oap UNUSED) - { - #ifdef FEAT_EVAL - typval_T argv[2]; - int save_virtual_op = virtual_op; - - if (*p_opfunc == NUL) - emsg(_("E774: 'operatorfunc' is empty")); - else - { - /* Set '[ and '] marks to text to be operated on. */ - curbuf->b_op_start = oap->start; - curbuf->b_op_end = oap->end; - if (oap->motion_type != MLINE && !oap->inclusive) - /* Exclude the end position. */ - decl(&curbuf->b_op_end); - - argv[0].v_type = VAR_STRING; - if (oap->block_mode) - argv[0].vval.v_string = (char_u *)"block"; - else if (oap->motion_type == MLINE) - argv[0].vval.v_string = (char_u *)"line"; - else - argv[0].vval.v_string = (char_u *)"char"; - argv[1].v_type = VAR_UNKNOWN; - - /* Reset virtual_op so that 'virtualedit' can be changed in the - * function. */ - virtual_op = MAYBE; - - (void)call_func_retnr(p_opfunc, 1, argv); - - virtual_op = save_virtual_op; - } - #else - emsg(_("E775: Eval feature not available")); - #endif - } - - /* * Check if highlighting for visual mode is possible, give a warning message * if not. */ --- 1283,1288 ---- *************** *** 2273,2278 **** --- 1367,1382 ---- } } + void + restore_visual_mode(void) + { + if (VIsual_mode_orig != NUL) + { + curbuf->b_visual.vi_mode = VIsual_mode_orig; + VIsual_mode_orig = NUL; + } + } + /* * Check for a balloon-eval special item to include when searching for an * identifier. When "dir" is BACKWARD "ptr[-1]" must be valid! *************** *** 2611,2617 **** * If the mode is currently displayed clear the command line or update the * command displayed. */ ! static void may_clear_cmdline(void) { if (mode_displayed) --- 1715,1721 ---- * If the mode is currently displayed clear the command line or update the * command displayed. */ ! void may_clear_cmdline(void) { if (mode_displayed) *************** *** 7606,7612 **** * Should check VIsual_mode before calling this. * Returns TRUE when backed up to the previous line. */ ! static int unadjust_for_sel(void) { pos_T *pp; --- 6710,6716 ---- * Should check VIsual_mode before calling this. * Returns TRUE when backed up to the previous line. */ ! int unadjust_for_sel(void) { pos_T *pp; *************** *** 8361,8434 **** did_cursorhold = TRUE; cap->retval |= CA_COMMAND_BUSY; /* don't call edit() now */ } - - /* - * Calculate start/end virtual columns for operating in block mode. - */ - static void - get_op_vcol( - oparg_T *oap, - colnr_T redo_VIsual_vcol, - int initial) /* when TRUE adjust position for 'selectmode' */ - { - colnr_T start, end; - - if (VIsual_mode != Ctrl_V - || (!initial && oap->end.col < curwin->w_width)) - return; - - oap->block_mode = TRUE; - - /* prevent from moving onto a trail byte */ - if (has_mbyte) - mb_adjustpos(curwin->w_buffer, &oap->end); - - getvvcol(curwin, &(oap->start), &oap->start_vcol, NULL, &oap->end_vcol); - - if (!redo_VIsual_busy) - { - getvvcol(curwin, &(oap->end), &start, NULL, &end); - - if (start < oap->start_vcol) - oap->start_vcol = start; - if (end > oap->end_vcol) - { - if (initial && *p_sel == 'e' && start >= 1 - && start - 1 >= oap->end_vcol) - oap->end_vcol = start - 1; - else - oap->end_vcol = end; - } - } - - /* if '$' was used, get oap->end_vcol from longest line */ - if (curwin->w_curswant == MAXCOL) - { - curwin->w_cursor.col = MAXCOL; - oap->end_vcol = 0; - for (curwin->w_cursor.lnum = oap->start.lnum; - curwin->w_cursor.lnum <= oap->end.lnum; - ++curwin->w_cursor.lnum) - { - getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &end); - if (end > oap->end_vcol) - oap->end_vcol = end; - } - } - else if (redo_VIsual_busy) - oap->end_vcol = oap->start_vcol + redo_VIsual_vcol - 1; - /* - * Correct oap->end.col and oap->start.col to be the - * upper-left and lower-right corner of the block area. - * - * (Actually, this does convert column positions into character - * positions) - */ - curwin->w_cursor.lnum = oap->end.lnum; - coladvance(oap->end_vcol); - oap->end = curwin->w_cursor; - - curwin->w_cursor = oap->start; - coladvance(oap->start_vcol); - oap->start = curwin->w_cursor; - } --- 7465,7467 ---- *** ../vim-8.1.2103/src/ops.c 2019-09-28 19:04:06.993029586 +0200 --- src/ops.c 2019-09-30 23:02:43.352227368 +0200 *************** *** 96,102 **** /* * Return TRUE if operator "op" always works on whole lines. */ ! int op_on_lines(int op) { return opchars[op][2] & OPF_LINES; --- 96,102 ---- /* * Return TRUE if operator "op" always works on whole lines. */ ! static int op_on_lines(int op) { return opchars[op][2] & OPF_LINES; *************** *** 594,600 **** /* * op_reindent - handle reindenting a block of lines. */ ! void op_reindent(oparg_T *oap, int (*how)(void)) { long i; --- 594,600 ---- /* * op_reindent - handle reindenting a block of lines. */ ! static void op_reindent(oparg_T *oap, int (*how)(void)) { long i; *************** *** 1346,1352 **** /* * Handle the (non-standard vi) tilde operator. Also for "gu", "gU" and "g?". */ ! void op_tilde(oparg_T *oap) { pos_T pos; --- 1346,1352 ---- /* * Handle the (non-standard vi) tilde operator. Also for "gu", "gU" and "g?". */ ! static void op_tilde(oparg_T *oap) { pos_T pos; *************** *** 2352,2358 **** /* * Implementation of the format operator 'gq'. */ ! void op_format( oparg_T *oap, int keep_cursor) /* keep cursor on same text char */ --- 2352,2358 ---- /* * Implementation of the format operator 'gq'. */ ! static void op_format( oparg_T *oap, int keep_cursor) /* keep cursor on same text char */ *************** *** 2425,2431 **** /* * Implementation of the format operator 'gq' for when using 'formatexpr'. */ ! void op_formatexpr(oparg_T *oap) { if (oap->is_VIsual) --- 2425,2431 ---- /* * Implementation of the format operator 'gq' for when using 'formatexpr'. */ ! static void op_formatexpr(oparg_T *oap) { if (oap->is_VIsual) *************** *** 3938,3940 **** --- 3938,4871 ---- } #endif } + + /* + * Handle indent and format operators and visual mode ":". + */ + static void + op_colon(oparg_T *oap) + { + stuffcharReadbuff(':'); + if (oap->is_VIsual) + stuffReadbuff((char_u *)"'<,'>"); + else + { + // Make the range look nice, so it can be repeated. + if (oap->start.lnum == curwin->w_cursor.lnum) + stuffcharReadbuff('.'); + else + stuffnumReadbuff((long)oap->start.lnum); + if (oap->end.lnum != oap->start.lnum) + { + stuffcharReadbuff(','); + if (oap->end.lnum == curwin->w_cursor.lnum) + stuffcharReadbuff('.'); + else if (oap->end.lnum == curbuf->b_ml.ml_line_count) + stuffcharReadbuff('$'); + else if (oap->start.lnum == curwin->w_cursor.lnum) + { + stuffReadbuff((char_u *)".+"); + stuffnumReadbuff((long)oap->line_count - 1); + } + else + stuffnumReadbuff((long)oap->end.lnum); + } + } + if (oap->op_type != OP_COLON) + stuffReadbuff((char_u *)"!"); + if (oap->op_type == OP_INDENT) + { + #ifndef FEAT_CINDENT + if (*get_equalprg() == NUL) + stuffReadbuff((char_u *)"indent"); + else + #endif + stuffReadbuff(get_equalprg()); + stuffReadbuff((char_u *)"\n"); + } + else if (oap->op_type == OP_FORMAT) + { + if (*curbuf->b_p_fp != NUL) + stuffReadbuff(curbuf->b_p_fp); + else if (*p_fp != NUL) + stuffReadbuff(p_fp); + else + stuffReadbuff((char_u *)"fmt"); + stuffReadbuff((char_u *)"\n']"); + } + + // do_cmdline() does the rest + } + + /* + * Handle the "g@" operator: call 'operatorfunc'. + */ + static void + op_function(oparg_T *oap UNUSED) + { + #ifdef FEAT_EVAL + typval_T argv[2]; + int save_virtual_op = virtual_op; + + if (*p_opfunc == NUL) + emsg(_("E774: 'operatorfunc' is empty")); + else + { + // Set '[ and '] marks to text to be operated on. + curbuf->b_op_start = oap->start; + curbuf->b_op_end = oap->end; + if (oap->motion_type != MLINE && !oap->inclusive) + // Exclude the end position. + decl(&curbuf->b_op_end); + + argv[0].v_type = VAR_STRING; + if (oap->block_mode) + argv[0].vval.v_string = (char_u *)"block"; + else if (oap->motion_type == MLINE) + argv[0].vval.v_string = (char_u *)"line"; + else + argv[0].vval.v_string = (char_u *)"char"; + argv[1].v_type = VAR_UNKNOWN; + + // Reset virtual_op so that 'virtualedit' can be changed in the + // function. + virtual_op = MAYBE; + + (void)call_func_retnr(p_opfunc, 1, argv); + + virtual_op = save_virtual_op; + } + #else + emsg(_("E775: Eval feature not available")); + #endif + } + + /* + * Calculate start/end virtual columns for operating in block mode. + */ + static void + get_op_vcol( + oparg_T *oap, + colnr_T redo_VIsual_vcol, + int initial) // when TRUE adjust position for 'selectmode' + { + colnr_T start, end; + + if (VIsual_mode != Ctrl_V + || (!initial && oap->end.col < curwin->w_width)) + return; + + oap->block_mode = TRUE; + + // prevent from moving onto a trail byte + if (has_mbyte) + mb_adjustpos(curwin->w_buffer, &oap->end); + + getvvcol(curwin, &(oap->start), &oap->start_vcol, NULL, &oap->end_vcol); + + if (!redo_VIsual_busy) + { + getvvcol(curwin, &(oap->end), &start, NULL, &end); + + if (start < oap->start_vcol) + oap->start_vcol = start; + if (end > oap->end_vcol) + { + if (initial && *p_sel == 'e' && start >= 1 + && start - 1 >= oap->end_vcol) + oap->end_vcol = start - 1; + else + oap->end_vcol = end; + } + } + + // if '$' was used, get oap->end_vcol from longest line + if (curwin->w_curswant == MAXCOL) + { + curwin->w_cursor.col = MAXCOL; + oap->end_vcol = 0; + for (curwin->w_cursor.lnum = oap->start.lnum; + curwin->w_cursor.lnum <= oap->end.lnum; + ++curwin->w_cursor.lnum) + { + getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &end); + if (end > oap->end_vcol) + oap->end_vcol = end; + } + } + else if (redo_VIsual_busy) + oap->end_vcol = oap->start_vcol + redo_VIsual_vcol - 1; + // Correct oap->end.col and oap->start.col to be the + // upper-left and lower-right corner of the block area. + // + // (Actually, this does convert column positions into character + // positions) + curwin->w_cursor.lnum = oap->end.lnum; + coladvance(oap->end_vcol); + oap->end = curwin->w_cursor; + + curwin->w_cursor = oap->start; + coladvance(oap->start_vcol); + oap->start = curwin->w_cursor; + } + + /* + * Handle an operator after Visual mode or when the movement is finished. + * "gui_yank" is true when yanking text for the clipboard. + */ + void + do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank) + { + oparg_T *oap = cap->oap; + pos_T old_cursor; + int empty_region_error; + int restart_edit_save; + #ifdef FEAT_LINEBREAK + int lbr_saved = curwin->w_p_lbr; + #endif + + // The visual area is remembered for redo + static int redo_VIsual_mode = NUL; // 'v', 'V', or Ctrl-V + static linenr_T redo_VIsual_line_count; // number of lines + static colnr_T redo_VIsual_vcol; // number of cols or end column + static long redo_VIsual_count; // count for Visual operator + static int redo_VIsual_arg; // extra argument + int include_line_break = FALSE; + + #if defined(FEAT_CLIPBOARD) + // Yank the visual area into the GUI selection register before we operate + // on it and lose it forever. + // Don't do it if a specific register was specified, so that ""x"*P works. + // This could call do_pending_operator() recursively, but that's OK + // because gui_yank will be TRUE for the nested call. + if ((clip_star.available || clip_plus.available) + && oap->op_type != OP_NOP + && !gui_yank + && VIsual_active + && !redo_VIsual_busy + && oap->regname == 0) + clip_auto_select(); + #endif + old_cursor = curwin->w_cursor; + + // If an operation is pending, handle it... + if ((finish_op || VIsual_active) && oap->op_type != OP_NOP) + { + // Yank can be redone when 'y' is in 'cpoptions', but not when yanking + // for the clipboard. + int redo_yank = vim_strchr(p_cpo, CPO_YANK) != NULL && !gui_yank; + + #ifdef FEAT_LINEBREAK + // Avoid a problem with unwanted linebreaks in block mode. + if (curwin->w_p_lbr) + curwin->w_valid &= ~VALID_VIRTCOL; + curwin->w_p_lbr = FALSE; + #endif + oap->is_VIsual = VIsual_active; + if (oap->motion_force == 'V') + oap->motion_type = MLINE; + else if (oap->motion_force == 'v') + { + // If the motion was linewise, "inclusive" will not have been set. + // Use "exclusive" to be consistent. Makes "dvj" work nice. + if (oap->motion_type == MLINE) + oap->inclusive = FALSE; + // If the motion already was characterwise, toggle "inclusive" + else if (oap->motion_type == MCHAR) + oap->inclusive = !oap->inclusive; + oap->motion_type = MCHAR; + } + else if (oap->motion_force == Ctrl_V) + { + // Change line- or characterwise motion into Visual block mode. + if (!VIsual_active) + { + VIsual_active = TRUE; + VIsual = oap->start; + } + VIsual_mode = Ctrl_V; + VIsual_select = FALSE; + VIsual_reselect = FALSE; + } + + // Only redo yank when 'y' flag is in 'cpoptions'. + // Never redo "zf" (define fold). + if ((redo_yank || oap->op_type != OP_YANK) + && ((!VIsual_active || oap->motion_force) + // Also redo Operator-pending Visual mode mappings + || (VIsual_active && cap->cmdchar == ':' + && oap->op_type != OP_COLON)) + && cap->cmdchar != 'D' + #ifdef FEAT_FOLDING + && oap->op_type != OP_FOLD + && oap->op_type != OP_FOLDOPEN + && oap->op_type != OP_FOLDOPENREC + && oap->op_type != OP_FOLDCLOSE + && oap->op_type != OP_FOLDCLOSEREC + && oap->op_type != OP_FOLDDEL + && oap->op_type != OP_FOLDDELREC + #endif + ) + { + prep_redo(oap->regname, cap->count0, + get_op_char(oap->op_type), get_extra_op_char(oap->op_type), + oap->motion_force, cap->cmdchar, cap->nchar); + if (cap->cmdchar == '/' || cap->cmdchar == '?') // was a search + { + // If 'cpoptions' does not contain 'r', insert the search + // pattern to really repeat the same command. + if (vim_strchr(p_cpo, CPO_REDO) == NULL) + AppendToRedobuffLit(cap->searchbuf, -1); + AppendToRedobuff(NL_STR); + } + else if (cap->cmdchar == ':') + { + // do_cmdline() has stored the first typed line in + // "repeat_cmdline". When several lines are typed repeating + // won't be possible. + if (repeat_cmdline == NULL) + ResetRedobuff(); + else + { + AppendToRedobuffLit(repeat_cmdline, -1); + AppendToRedobuff(NL_STR); + VIM_CLEAR(repeat_cmdline); + } + } + } + + if (redo_VIsual_busy) + { + // Redo of an operation on a Visual area. Use the same size from + // redo_VIsual_line_count and redo_VIsual_vcol. + oap->start = curwin->w_cursor; + curwin->w_cursor.lnum += redo_VIsual_line_count - 1; + if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) + curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; + VIsual_mode = redo_VIsual_mode; + if (redo_VIsual_vcol == MAXCOL || VIsual_mode == 'v') + { + if (VIsual_mode == 'v') + { + if (redo_VIsual_line_count <= 1) + { + validate_virtcol(); + curwin->w_curswant = + curwin->w_virtcol + redo_VIsual_vcol - 1; + } + else + curwin->w_curswant = redo_VIsual_vcol; + } + else + { + curwin->w_curswant = MAXCOL; + } + coladvance(curwin->w_curswant); + } + cap->count0 = redo_VIsual_count; + if (redo_VIsual_count != 0) + cap->count1 = redo_VIsual_count; + else + cap->count1 = 1; + } + else if (VIsual_active) + { + if (!gui_yank) + { + // Save the current VIsual area for '< and '> marks, and "gv" + curbuf->b_visual.vi_start = VIsual; + curbuf->b_visual.vi_end = curwin->w_cursor; + curbuf->b_visual.vi_mode = VIsual_mode; + restore_visual_mode(); + curbuf->b_visual.vi_curswant = curwin->w_curswant; + # ifdef FEAT_EVAL + curbuf->b_visual_mode_eval = VIsual_mode; + # endif + } + + // In Select mode, a linewise selection is operated upon like a + // characterwise selection. + // Special case: gH deletes the last line. + if (VIsual_select && VIsual_mode == 'V' + && cap->oap->op_type != OP_DELETE) + { + if (LT_POS(VIsual, curwin->w_cursor)) + { + VIsual.col = 0; + curwin->w_cursor.col = + (colnr_T)STRLEN(ml_get(curwin->w_cursor.lnum)); + } + else + { + curwin->w_cursor.col = 0; + VIsual.col = (colnr_T)STRLEN(ml_get(VIsual.lnum)); + } + VIsual_mode = 'v'; + } + // If 'selection' is "exclusive", backup one character for + // charwise selections. + else if (VIsual_mode == 'v') + include_line_break = unadjust_for_sel(); + + oap->start = VIsual; + if (VIsual_mode == 'V') + { + oap->start.col = 0; + oap->start.coladd = 0; + } + } + + // Set oap->start to the first position of the operated text, oap->end + // to the end of the operated text. w_cursor is equal to oap->start. + if (LT_POS(oap->start, curwin->w_cursor)) + { + #ifdef FEAT_FOLDING + // Include folded lines completely. + if (!VIsual_active) + { + if (hasFolding(oap->start.lnum, &oap->start.lnum, NULL)) + oap->start.col = 0; + if ((curwin->w_cursor.col > 0 || oap->inclusive) + && hasFolding(curwin->w_cursor.lnum, NULL, + &curwin->w_cursor.lnum)) + curwin->w_cursor.col = (colnr_T)STRLEN(ml_get_curline()); + } + #endif + oap->end = curwin->w_cursor; + curwin->w_cursor = oap->start; + + // w_virtcol may have been updated; if the cursor goes back to its + // previous position w_virtcol becomes invalid and isn't updated + // automatically. + curwin->w_valid &= ~VALID_VIRTCOL; + } + else + { + #ifdef FEAT_FOLDING + // Include folded lines completely. + if (!VIsual_active && oap->motion_type == MLINE) + { + if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, + NULL)) + curwin->w_cursor.col = 0; + if (hasFolding(oap->start.lnum, NULL, &oap->start.lnum)) + oap->start.col = (colnr_T)STRLEN(ml_get(oap->start.lnum)); + } + #endif + oap->end = oap->start; + oap->start = curwin->w_cursor; + } + + // Just in case lines were deleted that make the position invalid. + check_pos(curwin->w_buffer, &oap->end); + oap->line_count = oap->end.lnum - oap->start.lnum + 1; + + // Set "virtual_op" before resetting VIsual_active. + virtual_op = virtual_active(); + + if (VIsual_active || redo_VIsual_busy) + { + get_op_vcol(oap, redo_VIsual_vcol, TRUE); + + if (!redo_VIsual_busy && !gui_yank) + { + // Prepare to reselect and redo Visual: this is based on the + // size of the Visual text + resel_VIsual_mode = VIsual_mode; + if (curwin->w_curswant == MAXCOL) + resel_VIsual_vcol = MAXCOL; + else + { + if (VIsual_mode != Ctrl_V) + getvvcol(curwin, &(oap->end), + NULL, NULL, &oap->end_vcol); + if (VIsual_mode == Ctrl_V || oap->line_count <= 1) + { + if (VIsual_mode != Ctrl_V) + getvvcol(curwin, &(oap->start), + &oap->start_vcol, NULL, NULL); + resel_VIsual_vcol = oap->end_vcol - oap->start_vcol + 1; + } + else + resel_VIsual_vcol = oap->end_vcol; + } + resel_VIsual_line_count = oap->line_count; + } + + // can't redo yank (unless 'y' is in 'cpoptions') and ":" + if ((redo_yank || oap->op_type != OP_YANK) + && oap->op_type != OP_COLON + #ifdef FEAT_FOLDING + && oap->op_type != OP_FOLD + && oap->op_type != OP_FOLDOPEN + && oap->op_type != OP_FOLDOPENREC + && oap->op_type != OP_FOLDCLOSE + && oap->op_type != OP_FOLDCLOSEREC + && oap->op_type != OP_FOLDDEL + && oap->op_type != OP_FOLDDELREC + #endif + && oap->motion_force == NUL + ) + { + // Prepare for redoing. Only use the nchar field for "r", + // otherwise it might be the second char of the operator. + if (cap->cmdchar == 'g' && (cap->nchar == 'n' + || cap->nchar == 'N')) + prep_redo(oap->regname, cap->count0, + get_op_char(oap->op_type), get_extra_op_char(oap->op_type), + oap->motion_force, cap->cmdchar, cap->nchar); + else if (cap->cmdchar != ':') + { + int nchar = oap->op_type == OP_REPLACE ? cap->nchar : NUL; + + // reverse what nv_replace() did + if (nchar == REPLACE_CR_NCHAR) + nchar = CAR; + else if (nchar == REPLACE_NL_NCHAR) + nchar = NL; + prep_redo(oap->regname, 0L, NUL, 'v', + get_op_char(oap->op_type), + get_extra_op_char(oap->op_type), + nchar); + } + if (!redo_VIsual_busy) + { + redo_VIsual_mode = resel_VIsual_mode; + redo_VIsual_vcol = resel_VIsual_vcol; + redo_VIsual_line_count = resel_VIsual_line_count; + redo_VIsual_count = cap->count0; + redo_VIsual_arg = cap->arg; + } + } + + // oap->inclusive defaults to TRUE. + // If oap->end is on a NUL (empty line) oap->inclusive becomes + // FALSE. This makes "d}P" and "v}dP" work the same. + if (oap->motion_force == NUL || oap->motion_type == MLINE) + oap->inclusive = TRUE; + if (VIsual_mode == 'V') + oap->motion_type = MLINE; + else + { + oap->motion_type = MCHAR; + if (VIsual_mode != Ctrl_V && *ml_get_pos(&(oap->end)) == NUL + && (include_line_break || !virtual_op)) + { + oap->inclusive = FALSE; + // Try to include the newline, unless it's an operator + // that works on lines only. + if (*p_sel != 'o' + && !op_on_lines(oap->op_type) + && oap->end.lnum < curbuf->b_ml.ml_line_count) + { + ++oap->end.lnum; + oap->end.col = 0; + oap->end.coladd = 0; + ++oap->line_count; + } + } + } + + redo_VIsual_busy = FALSE; + + // Switch Visual off now, so screen updating does + // not show inverted text when the screen is redrawn. + // With OP_YANK and sometimes with OP_COLON and OP_FILTER there is + // no screen redraw, so it is done here to remove the inverted + // part. + if (!gui_yank) + { + VIsual_active = FALSE; + #ifdef FEAT_MOUSE + setmouse(); + mouse_dragging = 0; + #endif + may_clear_cmdline(); + if ((oap->op_type == OP_YANK + || oap->op_type == OP_COLON + || oap->op_type == OP_FUNCTION + || oap->op_type == OP_FILTER) + && oap->motion_force == NUL) + { + #ifdef FEAT_LINEBREAK + // make sure redrawing is correct + curwin->w_p_lbr = lbr_saved; + #endif + redraw_curbuf_later(INVERTED); + } + } + } + + // 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) + oap->end.col += l - 1; + } + curwin->w_set_curswant = TRUE; + + // oap->empty is set when start and end are the same. The inclusive + // flag affects this too, unless yanking and the end is on a NUL. + oap->empty = (oap->motion_type == MCHAR + && (!oap->inclusive + || (oap->op_type == OP_YANK + && gchar_pos(&oap->end) == NUL)) + && EQUAL_POS(oap->start, oap->end) + && !(virtual_op && oap->start.coladd != oap->end.coladd)); + // For delete, change and yank, it's an error to operate on an + // empty region, when 'E' included in 'cpoptions' (Vi compatible). + empty_region_error = (oap->empty + && vim_strchr(p_cpo, CPO_EMPTYREGION) != NULL); + + // Force a redraw when operating on an empty Visual region, when + // 'modifiable is off or creating a fold. + if (oap->is_VIsual && (oap->empty || !curbuf->b_p_ma + #ifdef FEAT_FOLDING + || oap->op_type == OP_FOLD + #endif + )) + { + #ifdef FEAT_LINEBREAK + curwin->w_p_lbr = lbr_saved; + #endif + redraw_curbuf_later(INVERTED); + } + + // If the end of an operator is in column one while oap->motion_type + // is MCHAR and oap->inclusive is FALSE, we put op_end after the last + // character in the previous line. If op_start is on or before the + // first non-blank in the line, the operator becomes linewise + // (strange, but that's the way vi does it). + if ( oap->motion_type == MCHAR + && oap->inclusive == FALSE + && !(cap->retval & CA_NO_ADJ_OP_END) + && oap->end.col == 0 + && (!oap->is_VIsual || *p_sel == 'o') + && !oap->block_mode + && oap->line_count > 1) + { + oap->end_adjusted = TRUE; // remember that we did this + --oap->line_count; + --oap->end.lnum; + if (inindent(0)) + oap->motion_type = MLINE; + else + { + oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum)); + if (oap->end.col) + { + --oap->end.col; + oap->inclusive = TRUE; + } + } + } + else + oap->end_adjusted = FALSE; + + switch (oap->op_type) + { + case OP_LSHIFT: + case OP_RSHIFT: + op_shift(oap, TRUE, oap->is_VIsual ? (int)cap->count1 : 1); + auto_format(FALSE, TRUE); + break; + + case OP_JOIN_NS: + case OP_JOIN: + if (oap->line_count < 2) + oap->line_count = 2; + if (curwin->w_cursor.lnum + oap->line_count - 1 > + curbuf->b_ml.ml_line_count) + beep_flush(); + else + { + (void)do_join(oap->line_count, oap->op_type == OP_JOIN, + TRUE, TRUE, TRUE); + auto_format(FALSE, TRUE); + } + break; + + case OP_DELETE: + VIsual_reselect = FALSE; // don't reselect now + if (empty_region_error) + { + vim_beep(BO_OPER); + CancelRedo(); + } + else + { + (void)op_delete(oap); + if (oap->motion_type == MLINE && has_format_option(FO_AUTO)) + u_save_cursor(); // cursor line wasn't saved yet + auto_format(FALSE, TRUE); + } + break; + + case OP_YANK: + if (empty_region_error) + { + if (!gui_yank) + { + vim_beep(BO_OPER); + CancelRedo(); + } + } + else + { + #ifdef FEAT_LINEBREAK + curwin->w_p_lbr = lbr_saved; + #endif + (void)op_yank(oap, FALSE, !gui_yank); + } + check_cursor_col(); + break; + + case OP_CHANGE: + VIsual_reselect = FALSE; // don't reselect now + if (empty_region_error) + { + vim_beep(BO_OPER); + CancelRedo(); + } + else + { + // This is a new edit command, not a restart. Need to + // remember it to make 'insertmode' work with mappings for + // Visual mode. But do this only once and not when typed and + // 'insertmode' isn't set. + if (p_im || !KeyTyped) + restart_edit_save = restart_edit; + else + restart_edit_save = 0; + restart_edit = 0; + #ifdef FEAT_LINEBREAK + // 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); + } + #endif + // Reset finish_op now, don't want it set inside edit(). + finish_op = FALSE; + if (op_change(oap)) // will call edit() + cap->retval |= CA_COMMAND_BUSY; + if (restart_edit == 0) + restart_edit = restart_edit_save; + } + break; + + case OP_FILTER: + if (vim_strchr(p_cpo, CPO_FILTER) != NULL) + AppendToRedobuff((char_u *)"!\r"); // use any last used !cmd + else + bangredo = TRUE; // do_bang() will put cmd in redo buffer + // FALLTHROUGH + + case OP_INDENT: + case OP_COLON: + + #if defined(FEAT_LISP) || defined(FEAT_CINDENT) + // If 'equalprg' is empty, do the indenting internally. + if (oap->op_type == OP_INDENT && *get_equalprg() == NUL) + { + # ifdef FEAT_LISP + if (curbuf->b_p_lisp) + { + op_reindent(oap, get_lisp_indent); + break; + } + # endif + # ifdef FEAT_CINDENT + op_reindent(oap, + # ifdef FEAT_EVAL + *curbuf->b_p_inde != NUL ? get_expr_indent : + # endif + get_c_indent); + break; + # endif + } + #endif + + op_colon(oap); + break; + + case OP_TILDE: + case OP_UPPER: + case OP_LOWER: + case OP_ROT13: + if (empty_region_error) + { + vim_beep(BO_OPER); + CancelRedo(); + } + else + op_tilde(oap); + check_cursor_col(); + break; + + case OP_FORMAT: + #if defined(FEAT_EVAL) + if (*curbuf->b_p_fex != NUL) + op_formatexpr(oap); // use expression + else + #endif + if (*p_fp != NUL || *curbuf->b_p_fp != NUL) + op_colon(oap); // use external command + else + op_format(oap, FALSE); // use internal function + break; + + case OP_FORMAT2: + op_format(oap, TRUE); // use internal function + break; + + case OP_FUNCTION: + #ifdef FEAT_LINEBREAK + // Restore linebreak, so that when the user edits it looks as + // before. + curwin->w_p_lbr = lbr_saved; + #endif + op_function(oap); // call 'operatorfunc' + break; + + case OP_INSERT: + case OP_APPEND: + VIsual_reselect = FALSE; // don't reselect now + if (empty_region_error) + { + vim_beep(BO_OPER); + CancelRedo(); + } + else + { + // This is a new edit command, not a restart. Need to + // remember it to make 'insertmode' work with mappings for + // Visual mode. But do this only once. + restart_edit_save = restart_edit; + restart_edit = 0; + #ifdef FEAT_LINEBREAK + // 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); + } + #endif + op_insert(oap, cap->count1); + #ifdef FEAT_LINEBREAK + // Reset linebreak, so that formatting works correctly. + curwin->w_p_lbr = FALSE; + #endif + + // TODO: when inserting in several lines, should format all + // the lines. + auto_format(FALSE, TRUE); + + if (restart_edit == 0) + restart_edit = restart_edit_save; + else + cap->retval |= CA_COMMAND_BUSY; + } + break; + + case OP_REPLACE: + VIsual_reselect = FALSE; // don't reselect now + if (empty_region_error) + { + vim_beep(BO_OPER); + CancelRedo(); + } + else + { + #ifdef FEAT_LINEBREAK + // 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); + } + #endif + op_replace(oap, cap->nchar); + } + break; + + #ifdef FEAT_FOLDING + case OP_FOLD: + VIsual_reselect = FALSE; // don't reselect now + foldCreate(oap->start.lnum, oap->end.lnum); + break; + + case OP_FOLDOPEN: + case OP_FOLDOPENREC: + case OP_FOLDCLOSE: + case OP_FOLDCLOSEREC: + VIsual_reselect = FALSE; // don't reselect now + opFoldRange(oap->start.lnum, oap->end.lnum, + oap->op_type == OP_FOLDOPEN + || oap->op_type == OP_FOLDOPENREC, + oap->op_type == OP_FOLDOPENREC + || oap->op_type == OP_FOLDCLOSEREC, + oap->is_VIsual); + break; + + 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); + break; + #endif + case OP_NR_ADD: + case OP_NR_SUB: + if (empty_region_error) + { + vim_beep(BO_OPER); + CancelRedo(); + } + else + { + VIsual_active = TRUE; + #ifdef FEAT_LINEBREAK + curwin->w_p_lbr = lbr_saved; + #endif + op_addsub(oap, cap->count1, redo_VIsual_arg); + VIsual_active = FALSE; + } + check_cursor_col(); + break; + default: + clearopbeep(oap); + } + virtual_op = MAYBE; + if (!gui_yank) + { + // if 'sol' not set, go back to old column for some commands + if (!p_sol && oap->motion_type == MLINE && !oap->end_adjusted + && (oap->op_type == OP_LSHIFT || oap->op_type == OP_RSHIFT + || oap->op_type == OP_DELETE)) + { + #ifdef FEAT_LINEBREAK + curwin->w_p_lbr = FALSE; + #endif + coladvance(curwin->w_curswant = old_col); + } + } + else + { + curwin->w_cursor = old_cursor; + } + oap->block_mode = FALSE; + clearop(oap); + motion_force = NUL; + } + #ifdef FEAT_LINEBREAK + curwin->w_p_lbr = lbr_saved; + #endif + } *** ../vim-8.1.2103/src/proto/normal.pro 2019-09-21 20:46:14.728275744 +0200 --- src/proto/normal.pro 2019-09-30 23:02:55.024189077 +0200 *************** *** 1,16 **** /* normal.c */ void init_normal_cmds(void); void normal_cmd(oparg_T *oap, int toplevel); - void do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank); void check_visual_highlight(void); void end_visual_mode(void); void reset_VIsual_and_resel(void); void reset_VIsual(void); int find_ident_under_cursor(char_u **text, int find_type); int find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char_u **text, int *textcol, int find_type); ! void prep_redo(int regname, long, int, int, int, int, int); void clearop(oparg_T *oap); void clearopbeep(oparg_T *oap); void clear_showcmd(void); int add_to_showcmd(int c); void add_to_showcmd_c(int c); --- 1,17 ---- /* normal.c */ void init_normal_cmds(void); void normal_cmd(oparg_T *oap, int toplevel); void check_visual_highlight(void); void end_visual_mode(void); void reset_VIsual_and_resel(void); void reset_VIsual(void); + void restore_visual_mode(void); int find_ident_under_cursor(char_u **text, int find_type); int find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char_u **text, int *textcol, int find_type); ! void prep_redo(int regname, long num, int cmd1, int cmd2, int cmd3, int cmd4, int cmd5); void clearop(oparg_T *oap); void clearopbeep(oparg_T *oap); + void may_clear_cmdline(void); void clear_showcmd(void); int add_to_showcmd(int c); void add_to_showcmd_c(int c); *************** *** 26,30 **** --- 27,32 ---- int get_visual_text(cmdarg_T *cap, char_u **pp, int *lenp); void start_selection(void); void may_start_select(int c); + int unadjust_for_sel(void); void set_cursor_for_append_to_line(void); /* vim: set ft=c : */ *** ../vim-8.1.2103/src/proto/ops.pro 2019-09-25 22:36:57.300103046 +0200 --- src/proto/ops.pro 2019-09-30 22:55:21.421582805 +0200 *************** *** 1,16 **** /* ops.c */ int get_op_type(int char1, int char2); - int op_on_lines(int op); int op_is_change(int op); int get_op_char(int optype); int get_extra_op_char(int optype); void op_shift(oparg_T *oap, int curs_top, int amount); void shift_line(int left, int round, int amount, int call_changed_bytes); - void op_reindent(oparg_T *oap, int (*how)(void)); void stuffescaped(char_u *arg, int literally); int op_delete(oparg_T *oap); int op_replace(oparg_T *oap, int c); - void op_tilde(oparg_T *oap); int swapchar(int op_type, pos_T *pos); void op_insert(oparg_T *oap, long count1); int op_change(oparg_T *oap); --- 1,13 ---- *************** *** 18,25 **** int preprocs_left(void); char_u *skip_comment(char_u *line, int process, int include_space, int *is_comment); int do_join(long count, int insert_space, int save_undo, int use_formatoptions, int setmark); - void op_format(oparg_T *oap, int keep_cursor); - void op_formatexpr(oparg_T *oap); int fex_format(linenr_T lnum, long count, int c); void format_lines(linenr_T line_count, int avoid_fex); int paragraph_start(linenr_T lnum); --- 15,20 ---- *************** *** 28,31 **** --- 23,27 ---- void x11_export_final_selection(void); void clear_oparg(oparg_T *oap); void cursor_pos_info(dict_T *dict); + void do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank); /* vim: set ft=c : */ *** ../vim-8.1.2103/src/globals.h 2019-09-28 19:04:06.997029566 +0200 --- src/globals.h 2019-09-30 22:59:17.384885224 +0200 *************** *** 778,783 **** --- 778,790 ---- EXTERN int redo_VIsual_busy INIT(= FALSE); // TRUE when redoing Visual + /* + * The Visual area is remembered for reselection. + */ + EXTERN int resel_VIsual_mode INIT(= NUL); // 'v', 'V', or Ctrl-V + EXTERN linenr_T resel_VIsual_line_count; // number of lines + EXTERN colnr_T resel_VIsual_vcol; // nr of cols or end col + #ifdef FEAT_MOUSE /* * When pasting text with the middle mouse button in visual mode with *** ../vim-8.1.2103/src/version.c 2019-09-30 20:47:08.122546273 +0200 --- src/version.c 2019-09-30 23:11:10.246501677 +0200 *************** *** 755,756 **** --- 755,758 ---- { /* Add new patch number below this line */ + /**/ + 2104, /**/ -- No letters of the alphabet were harmed in the creation of this message. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///