diff options
Diffstat (limited to 'src/nvim/ops.c')
-rw-r--r-- | src/nvim/ops.c | 499 |
1 files changed, 252 insertions, 247 deletions
diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 8c8900710d..3222e9544e 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -9,13 +9,16 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/types.h> +#include <uv.h> #include "nvim/api/private/defs.h" #include "nvim/ascii_defs.h" #include "nvim/assert_defs.h" #include "nvim/autocmd.h" +#include "nvim/autocmd_defs.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" +#include "nvim/buffer_updates.h" #include "nvim/change.h" #include "nvim/charset.h" #include "nvim/cursor.h" @@ -30,17 +33,23 @@ #include "nvim/extmark.h" #include "nvim/fold.h" #include "nvim/garray.h" +#include "nvim/garray_defs.h" #include "nvim/getchar.h" -#include "nvim/gettext.h" +#include "nvim/getchar_defs.h" +#include "nvim/gettext_defs.h" #include "nvim/globals.h" #include "nvim/highlight.h" +#include "nvim/highlight_defs.h" #include "nvim/indent.h" #include "nvim/indent_c.h" #include "nvim/keycodes.h" #include "nvim/macros_defs.h" #include "nvim/mark.h" +#include "nvim/mark_defs.h" #include "nvim/mbyte.h" +#include "nvim/mbyte_defs.h" #include "nvim/memline.h" +#include "nvim/memline_defs.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/mouse.h" @@ -55,11 +64,13 @@ #include "nvim/plines.h" #include "nvim/search.h" #include "nvim/state.h" +#include "nvim/state_defs.h" #include "nvim/strings.h" #include "nvim/terminal.h" #include "nvim/textformat.h" #include "nvim/types_defs.h" #include "nvim/ui.h" +#include "nvim/ui_defs.h" #include "nvim/undo.h" #include "nvim/vim_defs.h" #include "nvim/window.h" @@ -90,25 +101,6 @@ static bool clipboard_delay_update = false; // delay clipboard update static bool clipboard_needs_update = false; // clipboard was updated static bool clipboard_didwarn = false; -// structure used by block_prep, op_delete and op_yank for blockwise operators -// also op_change, op_shift, op_insert, op_replace - AKelly -struct block_def { - int startspaces; // 'extra' cols before first char - int endspaces; // 'extra' cols after last char - int textlen; // chars in block - char *textstart; // pointer to 1st char (partially) in block - colnr_T textcol; // index of chars (partially) in block - colnr_T start_vcol; // start col of 1st char wholly inside block - colnr_T end_vcol; // start col of 1st char wholly after block - int is_short; // true if line is too short to fit in block - int is_MAX; // true if curswant==MAXCOL when starting - int is_oneChar; // true if block within one character - int pre_whitesp; // screen cols of ws before block - int pre_whitesp_c; // chars of ws before block - colnr_T end_char_vcols; // number of vcols of post-block char - colnr_T start_char_vcols; // number of vcols of pre-block char -}; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ops.c.generated.h" #endif @@ -230,9 +222,8 @@ int get_extra_op_char(int optype) } /// handle a shift operation -void op_shift(oparg_T *oap, int curs_top, int amount) +void op_shift(oparg_T *oap, bool curs_top, int amount) { - int i; int block_col = 0; if (u_save((linenr_T)(oap->start.lnum - 1), @@ -244,7 +235,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount) block_col = curwin->w_cursor.col; } - for (i = oap->line_count - 1; i >= 0; i--) { + for (int i = oap->line_count - 1; i >= 0; i--) { int first_char = (uint8_t)(*get_cursor_line_ptr()); if (first_char == NUL) { // empty line curwin->w_cursor.col = 0; @@ -305,7 +296,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount) /// leaves cursor on first blank in the line. /// /// @param call_changed_bytes call changed_bytes() -void shift_line(int left, int round, int amount, int call_changed_bytes) +void shift_line(bool left, bool round, int amount, int call_changed_bytes) { const int sw_val = get_sw_value_indent(curbuf); @@ -341,7 +332,7 @@ void shift_line(int left, int round, int amount, int call_changed_bytes) if (State & VREPLACE_FLAG) { change_indent(INDENT_SET, count, false, NUL, call_changed_bytes); } else { - (void)set_indent(count, call_changed_bytes ? SIN_CHANGED : 0); + set_indent(count, call_changed_bytes ? SIN_CHANGED : 0); } } @@ -395,19 +386,21 @@ static void shift_block(oparg_T *oap, int amount) } // TODO(vim): is passing bd.textstart for start of the line OK? - chartabsize_T cts; - init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, - bd.start_vcol, bd.textstart, bd.textstart); - while (ascii_iswhite(*cts.cts_ptr)) { - incr = lbr_chartabsize_adv(&cts); + CharsizeArg csarg; + CSType cstype = init_charsize_arg(&csarg, curwin, curwin->w_cursor.lnum, bd.textstart); + StrCharInfo ci = utf_ptr2StrCharInfo(bd.textstart); + int vcol = bd.start_vcol; + while (ascii_iswhite(ci.chr.value)) { + incr = win_charsize(cstype, vcol, ci.ptr, ci.chr.value, &csarg).width; + ci = utfc_next(ci); total += incr; - cts.cts_vcol += incr; + vcol += incr; } - bd.textstart = cts.cts_ptr; - bd.start_vcol = cts.cts_vcol; - clear_chartabsize_arg(&cts); + bd.textstart = ci.ptr; + bd.start_vcol = vcol; - int tabs = 0, spaces = 0; + int tabs = 0; + int spaces = 0; // OK, now total=all the VWS reqd, and textstart points at the 1st // non-ws char in the block. if (!curbuf->b_p_et) { @@ -455,16 +448,13 @@ static void shift_block(oparg_T *oap, int amount) // The character's column is in "bd.start_vcol". colnr_T non_white_col = bd.start_vcol; - chartabsize_T cts; - init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, - non_white_col, bd.textstart, non_white); - while (ascii_iswhite(*cts.cts_ptr)) { - incr = lbr_chartabsize_adv(&cts); - cts.cts_vcol += incr; + CharsizeArg csarg; + CSType cstype = init_charsize_arg(&csarg, curwin, curwin->w_cursor.lnum, bd.textstart); + while (ascii_iswhite(*non_white)) { + incr = win_charsize(cstype, non_white_col, non_white, (uint8_t)(*non_white), &csarg).width; + non_white_col += incr; + non_white++; } - non_white_col = cts.cts_vcol; - non_white = cts.cts_ptr; - clear_chartabsize_arg(&cts); const colnr_T block_space_width = non_white_col - oap->start_vcol; // We will shift by "total" or "block_space_width", whichever is less. @@ -485,19 +475,17 @@ static void shift_block(oparg_T *oap, int amount) if (bd.startspaces) { verbatim_copy_width -= bd.start_char_vcols; } - init_chartabsize_arg(&cts, curwin, 0, verbatim_copy_width, - bd.textstart, verbatim_copy_end); - while (cts.cts_vcol < destination_col) { - incr = lbr_chartabsize(&cts); - if (cts.cts_vcol + incr > destination_col) { + cstype = init_charsize_arg(&csarg, curwin, 0, bd.textstart); + StrCharInfo ci = utf_ptr2StrCharInfo(verbatim_copy_end); + while (verbatim_copy_width < destination_col) { + incr = win_charsize(cstype, verbatim_copy_width, ci.ptr, ci.chr.value, &csarg).width; + if (verbatim_copy_width + incr > destination_col) { break; } - cts.cts_vcol += incr; - MB_PTR_ADV(cts.cts_ptr); + verbatim_copy_width += incr; + ci = utfc_next(ci); } - verbatim_copy_width = cts.cts_vcol; - verbatim_copy_end = cts.cts_ptr; - clear_chartabsize_arg(&cts); + verbatim_copy_end = ci.ptr; // If "destination_col" is different from the width of the initial // part of the line that will be copied, it means we encountered a tab @@ -537,7 +525,7 @@ static void shift_block(oparg_T *oap, int amount) /// Insert string "s" (b_insert ? before : after) block :AKelly /// Caller must prepare for undo. -static void block_insert(oparg_T *oap, char *s, int b_insert, struct block_def *bdp) +static void block_insert(oparg_T *oap, char *s, bool b_insert, struct block_def *bdp) { int ts_val; int count = 0; // extra spaces to replace a cut TAB @@ -994,9 +982,15 @@ yankreg_T *get_yank_register(int regname, int mode) { yankreg_T *reg; - if (mode == YREG_PASTE && get_clipboard(regname, ®, false)) { + if ((mode == YREG_PASTE || mode == YREG_PUT) + && get_clipboard(regname, ®, false)) { // reg is set to clipboard contents. return reg; + } else if (mode == YREG_PUT && (regname == '*' || regname == '+')) { + // in case clipboard not available and we aren't actually pasting, + // return an empty register + static yankreg_T empty_reg = { .y_array = NULL }; + return &empty_reg; } else if (mode != YREG_YANK && (regname == 0 || regname == '"' || regname == '*' || regname == '+') && y_previous != NULL) { @@ -1091,15 +1085,15 @@ int do_record(int c) if (p != NULL) { // Remove escaping for K_SPECIAL in multi-byte chars. vim_unescape_ks(p); - (void)tv_dict_add_str(dict, S_LEN("regcontents"), p); + tv_dict_add_str(dict, S_LEN("regcontents"), p); } // Name of requested register, or empty string for unnamed operation. char buf[NUMBUFLEN + 5]; - int len = (*utf_char2len)(regname); + int len = utf_char2len(regname); utf_char2bytes(regname, buf); buf[len] = NUL; - (void)tv_dict_add_str(dict, S_LEN("regname"), buf); + tv_dict_add_str(dict, S_LEN("regname"), buf); tv_dict_set_keys_readonly(dict); // Get the recorded key hits. K_SPECIAL will be escaped, this @@ -1345,6 +1339,7 @@ int do_execreg(int regname, int colon, int addcr, int silent) } } reg_executing = regname == 0 ? '"' : regname; // disable the 'q' command + pending_end_reg_executing = false; } return retval; } @@ -1452,9 +1447,24 @@ int insert_reg(int regname, bool literally_arg) } else { for (size_t i = 0; i < reg->y_size; i++) { if (regname == '-') { + Direction dir = BACKWARD; + if ((State & REPLACE_FLAG) != 0) { + pos_T curpos; + if (u_save_cursor() == FAIL) { + return FAIL; + } + del_chars(mb_charlen(reg->y_array[0]), true); + curpos = curwin->w_cursor; + if (oneright() == FAIL) { + // hit end of line, need to put forward (after the current position) + dir = FORWARD; + } + curwin->w_cursor = curpos; + } + AppendCharToRedobuff(Ctrl_R); AppendCharToRedobuff(regname); - do_put(regname, NULL, BACKWARD, 1, PUT_CURSEND); + do_put(regname, NULL, dir, 1, PUT_CURSEND); } else { stuffescaped(reg->y_array[i], literally); } @@ -1768,7 +1778,7 @@ int op_delete(oparg_T *oap) // register. For the black hole register '_' don't yank anything. if (oap->regname != '_') { yankreg_T *reg = NULL; - int did_yank = false; + bool did_yank = false; if (oap->regname != 0) { // check for read-only register if (!valid_yank_reg(oap->regname, true)) { @@ -1968,8 +1978,8 @@ int op_delete(oparg_T *oap) } } - (void)del_bytes((colnr_T)n, !virtual_op, - oap->op_type == OP_DELETE && !oap->is_VIsual); + del_bytes((colnr_T)n, !virtual_op, + oap->op_type == OP_DELETE && !oap->is_VIsual); } else { // delete characters between lines pos_T curpos; @@ -1995,10 +2005,10 @@ int op_delete(oparg_T *oap) // delete from start of line until op_end int n = (oap->end.col + 1 - !oap->inclusive); curwin->w_cursor.col = 0; - (void)del_bytes((colnr_T)n, !virtual_op, - oap->op_type == OP_DELETE && !oap->is_VIsual); + del_bytes((colnr_T)n, !virtual_op, + oap->op_type == OP_DELETE && !oap->is_VIsual); curwin->w_cursor = curpos; // restore curwin->w_cursor - (void)do_join(2, false, false, false, false); + do_join(2, false, false, false, false); curbuf_splice_pending--; extmark_splice(curbuf, (int)startpos.lnum - 1, startpos.col, (int)oap->line_count - 1, n, deleted_bytes, @@ -2033,8 +2043,13 @@ static void mb_adjust_opend(oparg_T *oap) return; } - char *p = ml_get(oap->end.lnum); - oap->end.col += utf_cp_tail_off(p, p + oap->end.col); + const char *line = ml_get(oap->end.lnum); + const char *ptr = line + oap->end.col; + if (*ptr != NUL) { + ptr -= utf_head_off(line, ptr); + ptr += utfc_ptr2len(ptr) - 1; + oap->end.col = (colnr_T)(ptr - line); + } } /// Put character 'c' at position 'lp' @@ -2066,7 +2081,7 @@ static int op_replace(oparg_T *oap, int c) int n; struct block_def bd; char *after_p = NULL; - int had_ctrl_v_cr = false; + bool had_ctrl_v_cr = false; if ((curbuf->b_ml.ml_flags & ML_EMPTY) || oap->empty) { return OK; // nothing to do @@ -2088,11 +2103,6 @@ static int op_replace(oparg_T *oap, int c) // block mode replace if (oap->motion_type == kMTBlockWise) { - int numc; - int num_chars; - char *newp; - char *oldp; - colnr_T oldlen; bd.is_MAX = (curwin->w_curswant == MAXCOL); for (; curwin->w_cursor.lnum <= oap->end.lnum; curwin->w_cursor.lnum++) { curwin->w_cursor.col = 0; // make sure cursor position is valid @@ -2123,7 +2133,7 @@ static int op_replace(oparg_T *oap, int c) && !bd.is_oneChar && bd.end_char_vcols > 0) ? bd.end_char_vcols - 1 : 0; // Figure out how many characters to replace. - numc = oap->end_vcol - oap->start_vcol + 1; + int numc = oap->end_vcol - oap->start_vcol + 1; if (bd.is_short && (!virtual_op || bd.is_MAX)) { numc -= (oap->end_vcol - bd.end_vcol) + 1; } @@ -2139,11 +2149,11 @@ static int op_replace(oparg_T *oap, int c) } // Compute bytes needed, move character count to num_chars. - num_chars = numc; + int num_chars = numc; numc *= utf_char2len(c); - oldp = get_cursor_line_ptr(); - oldlen = (int)strlen(oldp); + char *oldp = get_cursor_line_ptr(); + colnr_T oldlen = (int)strlen(oldp); size_t newp_size = (size_t)bd.textcol + (size_t)bd.startspaces; if (had_ctrl_v_cr || (c != '\r' && c != '\n')) { @@ -2153,7 +2163,7 @@ static int op_replace(oparg_T *oap, int c) - bd.textcol - bd.textlen); } } - newp = xmallocz(newp_size); + char *newp = xmallocz(newp_size); // copy up to deleted part memmove(newp, oldp, (size_t)bd.textcol); oldp += bd.textcol + bd.textlen; @@ -2164,7 +2174,8 @@ static int op_replace(oparg_T *oap, int c) size_t after_p_len = 0; int col = oldlen - bd.textcol - bd.textlen + 1; assert(col >= 0); - int newrows = 0, newcols = 0; + int newrows = 0; + int newcols = 0; if (had_ctrl_v_cr || (c != '\r' && c != '\n')) { // strlen(newp) at this point int newp_len = bd.textcol + bd.startspaces; @@ -2303,7 +2314,7 @@ static int op_replace(oparg_T *oap, int c) void op_tilde(oparg_T *oap) { struct block_def bd; - int did_change = false; + bool did_change = false; if (u_save((linenr_T)(oap->start.lnum - 1), (linenr_T)(oap->end.lnum + 1)) == FAIL) { @@ -2313,11 +2324,9 @@ void op_tilde(oparg_T *oap) pos_T pos = oap->start; if (oap->motion_type == kMTBlockWise) { // Visual block mode for (; pos.lnum <= oap->end.lnum; pos.lnum++) { - int one_change; - block_prep(oap, &bd, pos.lnum, false); pos.col = bd.textcol; - one_change = swapchars(oap->op_type, &pos, bd.textlen); + bool one_change = swapchars(oap->op_type, &pos, bd.textlen); did_change |= one_change; } if (did_change) { @@ -2415,16 +2424,16 @@ bool swapchar(int op_type, pos_T *pos) return false; } - if (op_type == OP_UPPER && c == 0xdf) { + // ~ is OP_NOP, g~ is OP_TILDE, gU is OP_UPPER + if ((op_type == OP_UPPER || op_type == OP_NOP || op_type == OP_TILDE) && c == 0xdf) { pos_T sp = curwin->w_cursor; - // Special handling of German sharp s: change to "SS". + // Special handling for lowercase German sharp s (ß): convert to uppercase (ẞ). curwin->w_cursor = *pos; del_char(false); - ins_char('S'); - ins_char('S'); + ins_char(0x1E9E); curwin->w_cursor = sp; - inc(pos); + return true; } int nc = c; @@ -2543,7 +2552,7 @@ void op_insert(oparg_T *oap, int count1) pos_T t1 = oap->start; const pos_T start_insert = curwin->w_cursor; - (void)edit(NUL, false, (linenr_T)count1); + edit(NUL, false, (linenr_T)count1); // When a tab was inserted, and the characters in front of the tab // have been converted to a tab as well, the column of the cursor @@ -2745,9 +2754,6 @@ int op_change(oparg_T *oap) ins_len = (int)strlen(firstline) - pre_textlen; if (ins_len > 0) { - int offset; - char *newp; - char *oldp; // Subsequent calls to ml_get() flush the firstline data - take a // copy of the inserted text. char *ins_text = xmalloc((size_t)ins_len + 1); @@ -2762,16 +2768,16 @@ int op_change(oparg_T *oap) // initial coladd offset as part of "startspaces" if (bd.is_short) { vpos.lnum = linenr; - (void)getvpos(&vpos, oap->start_vcol); + getvpos(&vpos, oap->start_vcol); } else { vpos.coladd = 0; } - oldp = ml_get(linenr); - newp = xmalloc(strlen(oldp) + (size_t)vpos.coladd - + (size_t)ins_len + 1); + char *oldp = ml_get(linenr); + char *newp = xmalloc(strlen(oldp) + (size_t)vpos.coladd + + (size_t)ins_len + 1); // copy up to block start memmove(newp, oldp, (size_t)bd.textcol); - offset = bd.textcol; + int offset = bd.textcol; memset(newp + offset, ' ', (size_t)vpos.coladd); offset += vpos.coladd; memmove(newp + offset, ins_text, (size_t)ins_len); @@ -2925,66 +2931,11 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) reg->y_array[y_idx] = xstrdup(ml_get(lnum)); break; - case kMTCharWise: { - colnr_T startcol = 0, endcol = MAXCOL; - int is_oneChar = false; - colnr_T cs, ce; - char *p = ml_get(lnum); - bd.startspaces = 0; - bd.endspaces = 0; - - if (lnum == oap->start.lnum) { - startcol = oap->start.col; - if (virtual_op) { - getvcol(curwin, &oap->start, &cs, NULL, &ce); - if (ce != cs && oap->start.coladd > 0) { - // Part of a tab selected -- but don't double-count it. - bd.startspaces = (ce - cs + 1) - oap->start.coladd; - if (bd.startspaces < 0) { - bd.startspaces = 0; - } - startcol++; - } - } - } - - if (lnum == oap->end.lnum) { - endcol = oap->end.col; - if (virtual_op) { - getvcol(curwin, &oap->end, &cs, NULL, &ce); - if (p[endcol] == NUL || (cs + oap->end.coladd < ce - // Don't add space for double-wide - // char; endcol will be on last byte - // of multi-byte char. - && utf_head_off(p, p + endcol) == 0)) { - if (oap->start.lnum == oap->end.lnum - && oap->start.col == oap->end.col) { - // Special case: inside a single char - is_oneChar = true; - bd.startspaces = oap->end.coladd - - oap->start.coladd + oap->inclusive; - endcol = startcol; - } else { - bd.endspaces = oap->end.coladd - + oap->inclusive; - endcol -= oap->inclusive; - } - } - } - } - if (endcol == MAXCOL) { - endcol = (colnr_T)strlen(p); - } - if (startcol > endcol - || is_oneChar) { - bd.textlen = 0; - } else { - bd.textlen = endcol - startcol + oap->inclusive; - } - bd.textstart = p + startcol; + case kMTCharWise: + charwise_block_prep(oap->start, oap->end, &bd, lnum, oap->inclusive); yank_copy_line(reg, &bd, y_idx, false); break; - } + // NOTREACHED case kMTUnknown: abort(); @@ -3131,19 +3082,18 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg) tv_list_append_string(list, reg->y_array[i], -1); } tv_list_set_lock(list, VAR_FIXED); - (void)tv_dict_add_list(dict, S_LEN("regcontents"), list); + tv_dict_add_list(dict, S_LEN("regcontents"), list); // Register type. char buf[NUMBUFLEN + 6]; format_reg_type(reg->y_type, reg->y_width, buf, ARRAY_SIZE(buf)); - (void)tv_dict_add_str(dict, S_LEN("regtype"), buf); + tv_dict_add_str(dict, S_LEN("regtype"), buf); // Name of requested register, or empty string for unnamed operation. - len = (*utf_char2len)(oap->regname); + len = utf_char2len(oap->regname); buf[len] = 0; utf_char2bytes(oap->regname, buf); - recursive = true; - (void)tv_dict_add_str(dict, S_LEN("regname"), buf); + tv_dict_add_str(dict, S_LEN("regname"), buf); // Motion type: inclusive or exclusive. tv_dict_add_bool(dict, S_LEN("inclusive"), @@ -3152,11 +3102,11 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg) // Kind of operation: yank, delete, change). buf[0] = (char)get_op_char(oap->op_type); buf[1] = NUL; - (void)tv_dict_add_str(dict, S_LEN("operator"), buf); + tv_dict_add_str(dict, S_LEN("operator"), buf); // Selection type: visual or not. - (void)tv_dict_add_bool(dict, S_LEN("visual"), - oap->is_VIsual ? kBoolVarTrue : kBoolVarFalse); + tv_dict_add_bool(dict, S_LEN("visual"), + oap->is_VIsual ? kBoolVarTrue : kBoolVarFalse); tv_dict_set_keys_readonly(dict); textlock++; @@ -3225,7 +3175,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) if (flags & PUT_LINE) { stuffcharReadbuff(command_start_char); for (; count > 0; count--) { - (void)stuff_inserted(NUL, 1, count != 1); + stuff_inserted(NUL, 1, count != 1); if (count != 1) { // To avoid 'autoindent' affecting the text, use Ctrl_U to remove any // whitespace. Can't just insert Ctrl_U into readbuf1, this would go @@ -3237,7 +3187,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) } } } else { - (void)stuff_inserted(command_start_char, count, false); + stuff_inserted(command_start_char, count, false); } // Putting the text is done later, so can't move the cursor to the next @@ -3362,6 +3312,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) return; } + colnr_T split_pos = 0; if (y_type == kMTLineWise) { if (flags & PUT_LINE_SPLIT) { // "p" or "P" in Visual mode: split the lines to put the text in @@ -3369,23 +3320,24 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) if (u_save_cursor() == FAIL) { goto end; } - char *p = get_cursor_pos_ptr(); + char *curline = get_cursor_line_ptr(); + char *p = curline + curwin->w_cursor.col; if (dir == FORWARD && *p != NUL) { MB_PTR_ADV(p); } + // we need this later for the correct extmark_splice() event + split_pos = (colnr_T)(p - curline); + char *ptr = xstrdup(p); ml_append(curwin->w_cursor.lnum, ptr, 0, false); xfree(ptr); - char *oldp = get_cursor_line_ptr(); - p = oldp + curwin->w_cursor.col; - if (dir == FORWARD && *p != NUL) { - MB_PTR_ADV(p); - } - ptr = xmemdupz(oldp, (size_t)(p - oldp)); + ptr = xmemdupz(get_cursor_line_ptr(), (size_t)split_pos); ml_replace(curwin->w_cursor.lnum, ptr, false); nr_lines++; dir = FORWARD; + + buf_updates_send_changes(curbuf, curwin->w_cursor.lnum, 1, 1); } if (flags & PUT_LINE_FORWARD) { // Must be "p" for a Visual block, put lines below the block. @@ -3419,9 +3371,9 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) // Correct line number for closed fold. Don't move the cursor yet, // u_save() uses it. if (dir == BACKWARD) { - (void)hasFolding(lnum, &lnum, NULL); + hasFolding(lnum, &lnum, NULL); } else { - (void)hasFolding(lnum, NULL, &lnum); + hasFolding(lnum, NULL, &lnum); } if (dir == FORWARD) { lnum++; @@ -3526,19 +3478,19 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) } // get the old line and advance to the position to insert at char *oldp = get_cursor_line_ptr(); - size_t oldlen = strlen(oldp); - chartabsize_T cts; - init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, 0, oldp, oldp); - while (cts.cts_vcol < col && *cts.cts_ptr != NUL) { - // Count a tab for what it's worth (if list mode not on) - incr = lbr_chartabsize_adv(&cts); - cts.cts_vcol += incr; + CharsizeArg csarg; + CSType cstype = init_charsize_arg(&csarg, curwin, curwin->w_cursor.lnum, oldp); + StrCharInfo ci = utf_ptr2StrCharInfo(oldp); + vcol = 0; + while (vcol < col && *ci.ptr != NUL) { + incr = win_charsize(cstype, vcol, ci.ptr, ci.chr.value, &csarg).width; + vcol += incr; + ci = utfc_next(ci); } - vcol = cts.cts_vcol; - char *ptr = cts.cts_ptr; + size_t oldlen = (size_t)(ci.ptr - oldp) + strlen(ci.ptr); + char *ptr = ci.ptr; bd.textcol = (colnr_T)(ptr - oldp); - clear_chartabsize_arg(&cts); shortline = (vcol < col) || (vcol == col && !*ptr); @@ -3562,16 +3514,15 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) yanklen = (int)strlen(y_array[i]); if ((flags & PUT_BLOCK_INNER) == 0) { - // calculate number of spaces required to fill right side of - // block + // calculate number of spaces required to fill right side of block spaces = y_width + 1; - init_chartabsize_arg(&cts, curwin, 0, 0, y_array[i], y_array[i]); - for (int j = 0; j < yanklen; j++) { - spaces -= lbr_chartabsize(&cts); - cts.cts_ptr++; - cts.cts_vcol = 0; + + cstype = init_charsize_arg(&csarg, curwin, 0, y_array[i]); + ci = utf_ptr2StrCharInfo(y_array[i]); + while (*ci.ptr != NUL) { + spaces -= win_charsize(cstype, 0, ci.ptr, ci.chr.value, &csarg).width; + ci = utfc_next(ci); } - clear_chartabsize_arg(&cts); if (spaces < 0) { spaces = 0; } @@ -3645,13 +3596,11 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) } curbuf->b_op_end.coladd = 0; if (flags & PUT_CURSEND) { - colnr_T len; - curwin->w_cursor = curbuf->b_op_end; curwin->w_cursor.col++; // in Insert mode we might be after the NUL, correct for that - len = (colnr_T)strlen(get_cursor_line_ptr()); + colnr_T len = (colnr_T)strlen(get_cursor_line_ptr()); if (curwin->w_cursor.col > len) { curwin->w_cursor.col = len; } @@ -3834,7 +3783,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) } else if ((indent = get_indent() + indent_diff) < 0) { indent = 0; } - (void)set_indent(indent, SIN_NOMARK); + set_indent(indent, SIN_NOMARK); curwin->w_cursor = old_pos; // remember how many chars were removed if (cnt == count && i == y_size - 1) { @@ -3846,7 +3795,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) bcount_t totsize = 0; int lastsize = 0; if (y_type == kMTCharWise - || (y_type == kMTLineWise && flags & PUT_LINE_SPLIT)) { + || (y_type == kMTLineWise && (flags & PUT_LINE_SPLIT))) { for (i = 0; i < y_size - 1; i++) { totsize += (bcount_t)strlen(y_array[i]) + 1; } @@ -3857,9 +3806,9 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) extmark_splice(curbuf, (int)new_cursor.lnum - 1, col, 0, 0, 0, (int)y_size - 1, lastsize, totsize, kExtmarkUndo); - } else if (y_type == kMTLineWise && flags & PUT_LINE_SPLIT) { + } else if (y_type == kMTLineWise && (flags & PUT_LINE_SPLIT)) { // Account for last pasted NL + last NL - extmark_splice(curbuf, (int)new_cursor.lnum - 1, col + 1, 0, 0, 0, + extmark_splice(curbuf, (int)new_cursor.lnum - 1, split_pos, 0, 0, 0, (int)y_size + 1, 0, totsize + 2, kExtmarkUndo); } @@ -3997,7 +3946,7 @@ void adjust_cursor_eol(void) } /// @return true if lines starting with '#' should be left aligned. -int preprocs_left(void) +bool preprocs_left(void) { return ((curbuf->b_p_si && !curbuf->b_p_cin) || (curbuf->b_p_cin && in_cinkeys('#', ' ', true) @@ -4257,7 +4206,7 @@ char *skip_comment(char *line, bool process, bool include_space, bool *is_commen /// to set those marks. /// /// @return FAIL for failure, OK otherwise -int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions, bool setmark) +int do_join(size_t count, bool insert_space, bool save_undo, bool use_formatoptions, bool setmark) { char *curr = NULL; char *curr_start = NULL; @@ -4268,8 +4217,7 @@ int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions int sumsize = 0; // size of the long new line int ret = OK; int *comments = NULL; - int remove_comments = (use_formatoptions == true) - && has_format_option(FO_REMOVE_COMS); + bool remove_comments = use_formatoptions && has_format_option(FO_REMOVE_COMS); bool prev_was_comment = false; assert(count >= 1); @@ -4486,7 +4434,7 @@ static void restore_lbr(bool lbr_saved) /// - textlen includes the first/last char to be wholly yanked /// - start/endspaces is the number of columns of the first/last yanked char /// that are to be yanked. -static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bool is_del) +void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bool is_del) { int incr = 0; // Avoid a problem with unwanted linebreaks in block mode. @@ -4507,25 +4455,25 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bool char *line = ml_get(lnum); char *prev_pstart = line; - chartabsize_T cts; - init_chartabsize_arg(&cts, curwin, lnum, bdp->start_vcol, line, line); - while (cts.cts_vcol < oap->start_vcol && *cts.cts_ptr != NUL) { - // Count a tab for what it's worth (if list mode not on) - incr = lbr_chartabsize(&cts); - cts.cts_vcol += incr; - if (ascii_iswhite(*cts.cts_ptr)) { + CharsizeArg csarg; + CSType cstype = init_charsize_arg(&csarg, curwin, lnum, line); + StrCharInfo ci = utf_ptr2StrCharInfo(line); + int vcol = bdp->start_vcol; + while (vcol < oap->start_vcol && *ci.ptr != NUL) { + incr = win_charsize(cstype, vcol, ci.ptr, ci.chr.value, &csarg).width; + vcol += incr; + if (ascii_iswhite(ci.chr.value)) { bdp->pre_whitesp += incr; bdp->pre_whitesp_c++; } else { bdp->pre_whitesp = 0; bdp->pre_whitesp_c = 0; } - prev_pstart = cts.cts_ptr; - MB_PTR_ADV(cts.cts_ptr); + prev_pstart = ci.ptr; + ci = utfc_next(ci); } - bdp->start_vcol = cts.cts_vcol; - char *pstart = cts.cts_ptr; - clear_chartabsize_arg(&cts); + bdp->start_vcol = vcol; + char *pstart = ci.ptr; bdp->start_char_vcols = incr; if (bdp->start_vcol < oap->start_vcol) { // line too short @@ -4562,17 +4510,18 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bool } } } else { - init_chartabsize_arg(&cts, curwin, lnum, bdp->end_vcol, line, pend); + cstype = init_charsize_arg(&csarg, curwin, lnum, line); + ci = utf_ptr2StrCharInfo(pend); + vcol = bdp->end_vcol; char *prev_pend = pend; - while (cts.cts_vcol <= oap->end_vcol && *cts.cts_ptr != NUL) { - // Count a tab for what it's worth (if list mode not on) - prev_pend = cts.cts_ptr; - incr = lbr_chartabsize_adv(&cts); - cts.cts_vcol += incr; + while (vcol <= oap->end_vcol && *ci.ptr != NUL) { + prev_pend = ci.ptr; + incr = win_charsize(cstype, vcol, ci.ptr, ci.chr.value, &csarg).width; + vcol += incr; + ci = utfc_next(ci); } - bdp->end_vcol = cts.cts_vcol; - pend = cts.cts_ptr; - clear_chartabsize_arg(&cts); + bdp->end_vcol = vcol; + pend = ci.ptr; if (bdp->end_vcol <= oap->end_vcol && (!is_del @@ -4608,6 +4557,65 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bool restore_lbr(lbr_saved); } +/// Get block text from "start" to "end" +void charwise_block_prep(pos_T start, pos_T end, struct block_def *bdp, linenr_T lnum, + bool inclusive) +{ + colnr_T startcol = 0; + colnr_T endcol = MAXCOL; + bool is_oneChar = false; + colnr_T cs, ce; + char *p = ml_get(lnum); + bdp->startspaces = 0; + bdp->endspaces = 0; + + if (lnum == start.lnum) { + startcol = start.col; + if (virtual_op) { + getvcol(curwin, &start, &cs, NULL, &ce); + if (ce != cs && start.coladd > 0) { + // Part of a tab selected -- but don't double-count it. + bdp->startspaces = (ce - cs + 1) - start.coladd; + if (bdp->startspaces < 0) { + bdp->startspaces = 0; + } + startcol++; + } + } + } + + if (lnum == end.lnum) { + endcol = end.col; + if (virtual_op) { + getvcol(curwin, &end, &cs, NULL, &ce); + if (p[endcol] == NUL || (cs + end.coladd < ce + // Don't add space for double-wide + // char; endcol will be on last byte + // of multi-byte char. + && utf_head_off(p, p + endcol) == 0)) { + if (start.lnum == end.lnum && start.col == end.col) { + // Special case: inside a single char + is_oneChar = true; + bdp->startspaces = end.coladd - start.coladd + inclusive; + endcol = startcol; + } else { + bdp->endspaces = end.coladd + inclusive; + endcol -= inclusive; + } + } + } + } + if (endcol == MAXCOL) { + endcol = (colnr_T)strlen(p); + } + if (startcol > endcol || is_oneChar) { + bdp->textlen = 0; + } else { + bdp->textlen = endcol - startcol + inclusive; + } + bdp->textstart = p + startcol; +} + /// Handle the add/subtract operator. /// /// @param[in] oap Arguments of operator. @@ -4675,7 +4683,7 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd) length = oap->end.col - pos.col + 1; } } - int one_change = do_addsub(oap->op_type, &pos, length, amount); + bool one_change = do_addsub(oap->op_type, &pos, length, amount); if (one_change) { // Remember the start position of the first change. if (change_cnt == 0) { @@ -4720,7 +4728,7 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd) /// @param Prenum1 Amount of addition or subtraction. /// /// @return true if some character was changed. -int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) +bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) { char *buf1 = NULL; char buf2[NUMBUFLEN]; @@ -4876,7 +4884,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) curwin->w_cursor.col = col; startpos = curwin->w_cursor; did_change = true; - (void)del_char(false); + del_char(false); ins_char(firstdigit); endpos = curwin->w_cursor; curwin->w_cursor.col = col; @@ -4931,13 +4939,13 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) if (!pre) { if (subtract) { if (n > oldn) { - n = 1 + (n ^ (uvarnumber_T) - 1); + n = 1 + (n ^ (uvarnumber_T)(-1)); negative ^= true; } } else { // add if (n < oldn) { - n = (n ^ (uvarnumber_T) - 1); + n = (n ^ (uvarnumber_T)(-1)); negative ^= true; } } @@ -4984,7 +4992,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) } } // del_char() will mark line needing displaying - (void)del_char(false); + del_char(false); c = gchar_cursor(); } @@ -5195,7 +5203,7 @@ void *get_reg_contents(int regname, int flags) return get_reg_wrap_one_line(xstrdup(retval), flags); } - yankreg_T *reg = get_yank_register(regname, YREG_PASTE); + yankreg_T *reg = get_yank_register(regname, YREG_PUT); if (reg->y_array == NULL) { return NULL; } @@ -5529,16 +5537,16 @@ static varnumber_T line_count_info(char *line, varnumber_T *wc, varnumber_T *cc, varnumber_T i; varnumber_T words = 0; varnumber_T chars = 0; - int is_word = 0; + bool is_word = false; for (i = 0; i < limit && line[i] != NUL;) { if (is_word) { if (ascii_isspace(line[i])) { words++; - is_word = 0; + is_word = false; } } else if (!ascii_isspace(line[i])) { - is_word = 1; + is_word = true; } chars++; i += utfc_ptr2len(line + i); @@ -5826,7 +5834,7 @@ static void op_colon(oparg_T *oap) // When using !! on a closed fold the range ".!" works best to operate // on, it will be made the whole closed fold later. linenr_T endOfStartFold = oap->start.lnum; - (void)hasFolding(oap->start.lnum, NULL, &endOfStartFold); + hasFolding(oap->start.lnum, NULL, &endOfStartFold); if (oap->end.lnum != oap->start.lnum && oap->end.lnum != endOfStartFold) { // Make it a range with the end line. stuffcharReadbuff(','); @@ -6045,7 +6053,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) const bool redo_yank = vim_strchr(p_cpo, CPO_YANK) != NULL && !gui_yank; // Avoid a problem with unwanted linebreaks in block mode - (void)reset_lbr(); + reset_lbr(); oap->is_VIsual = VIsual_active; if (oap->motion_force == 'V') { oap->motion_type = kMTLineWise; @@ -6431,7 +6439,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) vim_beep(BO_OPER); CancelRedo(); } else { - (void)op_delete(oap); + op_delete(oap); // save cursor line for undo if it wasn't saved yet if (oap->motion_type == kMTLineWise && has_format_option(FO_AUTO) @@ -6450,7 +6458,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) } else { restore_lbr(lbr_saved); oap->excl_tr_ws = cap->cmdchar == 'z'; - (void)op_yank(oap, !gui_yank); + op_yank(oap, !gui_yank); } check_cursor_col(); break; @@ -6581,7 +6589,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) op_insert(oap, cap->count1); // Reset linebreak, so that formatting works correctly. - (void)reset_lbr(); + reset_lbr(); // TODO(brammool): when inserting in several lines, should format all // the lines. @@ -6655,7 +6663,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) if (!p_sol && oap->motion_type == kMTLineWise && !oap->end_adjusted && (oap->op_type == OP_LSHIFT || oap->op_type == OP_RSHIFT || oap->op_type == OP_DELETE)) { - (void)reset_lbr(); + reset_lbr(); coladvance(curwin->w_curswant = old_col); } } else { @@ -6785,8 +6793,6 @@ bool prepare_yankreg_from_object(yankreg_T *reg, String regtype, size_t lines) } } - reg->y_array = xcalloc(lines, sizeof(uint8_t *)); - reg->y_size = lines; reg->additional_data = NULL; reg->timestamp = 0; return true; @@ -6799,7 +6805,6 @@ void finish_yankreg_from_object(yankreg_T *reg, bool clipboard_adjust) // but otherwise there is no line after the final newline if (reg->y_type != kMTCharWise) { if (reg->y_type == kMTUnknown || clipboard_adjust) { - xfree(reg->y_array[reg->y_size - 1]); reg->y_size--; } if (reg->y_type == kMTUnknown) { @@ -6985,7 +6990,7 @@ static void set_clipboard(int name, yankreg_T *reg) tv_list_append_string(args, ®type, 1); tv_list_append_string(args, ((char[]) { (char)name }), 1); - (void)eval_call_provider("clipboard", "set", args, true); + eval_call_provider("clipboard", "set", args, true); } /// Avoid slow things (clipboard) during batch operations (while/for-loops). |