Mercurial > vim
diff src/ops.c @ 18219:5d67f207f7c3 v8.1.2104
patch 8.1.2104: the normal.c file is too big
Commit: https://github.com/vim/vim/commit/792cf5e1bec04c6d6d70cfbb9ef24c798b469731
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Sep 30 23:12:16 2019 +0200
patch 8.1.2104: the normal.c file is too big
Problem: The normal.c file is too big.
Solution: Move do_pending_operator() to ops.c. (Yegappan Lakshmanan,
closes #4999).
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Mon, 30 Sep 2019 23:15:03 +0200 |
parents | e0ec4cd7a865 |
children | c8a53c0daeed |
line wrap: on
line diff
--- a/src/ops.c +++ b/src/ops.c @@ -96,7 +96,7 @@ get_op_type(int char1, int char2) /* * Return TRUE if operator "op" always works on whole lines. */ - int + static int op_on_lines(int op) { return opchars[op][2] & OPF_LINES; @@ -594,7 +594,7 @@ block_insert( /* * op_reindent - handle reindenting a block of lines. */ - void + static void op_reindent(oparg_T *oap, int (*how)(void)) { long i; @@ -1346,7 +1346,7 @@ static int swapchars(int op_type, pos_T /* * Handle the (non-standard vi) tilde operator. Also for "gu", "gU" and "g?". */ - void + static void op_tilde(oparg_T *oap) { pos_T pos; @@ -2352,7 +2352,7 @@ same_leader( /* * Implementation of the format operator 'gq'. */ - void + static void op_format( oparg_T *oap, int keep_cursor) /* keep cursor on same text char */ @@ -2425,7 +2425,7 @@ op_format( /* * Implementation of the format operator 'gq' for when using 'formatexpr'. */ - void + static void op_formatexpr(oparg_T *oap) { if (oap->is_VIsual) @@ -3938,3 +3938,934 @@ cursor_pos_info(dict_T *dict) } #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<Del> 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 +}