diff options
Diffstat (limited to 'src/nvim/ops.c')
-rw-r--r-- | src/nvim/ops.c | 172 |
1 files changed, 114 insertions, 58 deletions
diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 190ca2e93b..f2f6803665 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -156,6 +156,9 @@ int get_op_type(int char1, int char2) // subtract return OP_NR_SUB; } + if (char1 == 'z' && char2 == 'y') { // OP_YANK + return OP_YANK; + } for (i = 0;; i++) { if (opchars[i][0] == char1 && opchars[i][1] == char2) { break; @@ -1676,17 +1679,14 @@ int op_delete(oparg_T *oap) curbuf_splice_pending++; pos_T startpos = curwin->w_cursor; // start position for delete - bcount_t deleted_bytes = (bcount_t)STRLEN( - ml_get(startpos.lnum)) + 1 - startpos.col; + bcount_t deleted_bytes = get_region_bytecount( + curbuf, startpos.lnum, oap->end.lnum, startpos.col, + oap->end.col) + oap->inclusive; truncate_line(true); // delete from cursor to end of line curpos = curwin->w_cursor; // remember curwin->w_cursor curwin->w_cursor.lnum++; - for (linenr_T i = 1; i <= oap->line_count - 2; i++) { - deleted_bytes += (bcount_t)STRLEN( - ml_get(startpos.lnum + i)) + 1; - } del_lines(oap->line_count - 2, false); // delete from start of line until op_end @@ -1694,7 +1694,6 @@ int op_delete(oparg_T *oap) curwin->w_cursor.col = 0; (void)del_bytes((colnr_T)n, !virtual_op, oap->op_type == OP_DELETE && !oap->is_VIsual); - deleted_bytes += n; curwin->w_cursor = curpos; // restore curwin->w_cursor (void)do_join(2, false, false, false, false); curbuf_splice_pending--; @@ -2567,7 +2566,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) switch (reg->y_type) { case kMTBlockWise: block_prep(oap, &bd, lnum, false); - yank_copy_line(reg, &bd, y_idx); + yank_copy_line(reg, &bd, y_idx, oap->excl_tr_ws); break; case kMTLineWise: @@ -2631,7 +2630,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) bd.textlen = endcol - startcol + oap->inclusive; } bd.textstart = p + startcol; - yank_copy_line(reg, &bd, y_idx); + yank_copy_line(reg, &bd, y_idx, false); break; } // NOTREACHED @@ -2718,7 +2717,11 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) return; } -static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx) +// Copy a block range into a register. +// If "exclude_trailing_space" is set, do not copy trailing whitespaces. +static void yank_copy_line(yankreg_T *reg, const struct block_def *bd, + size_t y_idx, bool exclude_trailing_space) + FUNC_ATTR_NONNULL_ALL { int size = bd->startspaces + bd->endspaces + bd->textlen; assert(size >= 0); @@ -2730,6 +2733,14 @@ static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx) pnew += bd->textlen; memset(pnew, ' ', (size_t)bd->endspaces); pnew += bd->endspaces; + if (exclude_trailing_space) { + int s = bd->textlen + bd->endspaces; + + while (ascii_iswhite(*(bd->textstart + s - 1)) && s > 0) { + s = s - utf_head_off(bd->textstart, bd->textstart + s - 1) - 1; + pnew--; + } + } *pnew = NUL; } @@ -2792,13 +2803,13 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg) recursive = false; } -/* - * Put contents of register "regname" into the text. - * Caller must check "regname" to be valid! - * "flags": PUT_FIXINDENT make indent look nice - * PUT_CURSEND leave cursor after end of new text - * PUT_LINE force linewise put (":put") - dir: BACKWARD for 'P', FORWARD for 'p' */ +// Put contents of register "regname" into the text. +// Caller must check "regname" to be valid! +// "flags": PUT_FIXINDENT make indent look nice +// PUT_CURSEND leave cursor after end of new text +// PUT_LINE force linewise put (":put") +// PUT_BLOCK_INNER in block mode, do not add trailing spaces +// dir: BACKWARD for 'P', FORWARD for 'p' void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) { char_u *ptr; @@ -3130,7 +3141,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) curwin->w_cursor.coladd = 0; bd.textcol = 0; for (i = 0; i < y_size; i++) { - int spaces; + int spaces = 0; char shortline; // can just be 0 or 1, needed for blockwise paste beyond the current // buffer end @@ -3181,13 +3192,16 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) yanklen = (int)STRLEN(y_array[i]); - // calculate number of spaces required to fill right side of block - spaces = y_width + 1; - for (long j = 0; j < yanklen; j++) { - spaces -= lbr_chartabsize(NULL, &y_array[i][j], 0); - } - if (spaces < 0) { - spaces = 0; + if ((flags & PUT_BLOCK_INNER) == 0) { + // calculate number of spaces required to fill right side of + // block + spaces = y_width + 1; + for (int j = 0; j < yanklen; j++) { + spaces -= lbr_chartabsize(NULL, &y_array[i][j], 0); + } + if (spaces < 0) { + spaces = 0; + } } // insert the new text @@ -3334,6 +3348,9 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) changed_cline_bef_curs(); curwin->w_cursor.col += (colnr_T)(totlen - 1); } + changed_bytes(lnum, col); + extmark_splice_cols(curbuf, (int)lnum-1, col, + 0, (int)totlen, kExtmarkUndo); } if (VIsual_active) { lnum++; @@ -3345,12 +3362,10 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) } curbuf->b_op_end = curwin->w_cursor; - /* For "CTRL-O p" in Insert mode, put cursor after last char */ - if (totlen && (restart_edit != 0 || (flags & PUT_CURSEND))) - ++curwin->w_cursor.col; - changed_bytes(lnum, col); - extmark_splice_cols(curbuf, (int)lnum-1, col, - 0, (int)totlen, kExtmarkUndo); + // For "CTRL-O p" in Insert mode, put cursor after last char + if (totlen && (restart_edit != 0 || (flags & PUT_CURSEND))) { + curwin->w_cursor.col++; + } } else { // Insert at least one line. When y_type is kMTCharWise, break the first // line in two. @@ -4731,12 +4746,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) char_u *ptr; int c; int todel; - bool dohex; - bool dooct; - bool dobin; - bool doalp; int firstdigit; - bool subtract; bool negative = false; bool was_positive = true; bool visual = VIsual_active; @@ -4747,10 +4757,12 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) pos_T endpos; colnr_T save_coladd = 0; - dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); // "heX" - dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); // "Octal" - dobin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL); // "Bin" - doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); // "alPha" + const bool do_hex = vim_strchr(curbuf->b_p_nf, 'x') != NULL; // "heX" + const bool do_oct = vim_strchr(curbuf->b_p_nf, 'o') != NULL; // "Octal" + const bool do_bin = vim_strchr(curbuf->b_p_nf, 'b') != NULL; // "Bin" + const bool do_alpha = vim_strchr(curbuf->b_p_nf, 'p') != NULL; // "alPha" + // "Unsigned" + const bool do_unsigned = vim_strchr(curbuf->b_p_nf, 'u') != NULL; if (virtual_active()) { save_coladd = pos->coladd; @@ -4767,21 +4779,21 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) // First check if we are on a hexadecimal number, after the "0x". if (!VIsual_active) { - if (dobin) { + if (do_bin) { while (col > 0 && ascii_isbdigit(ptr[col])) { col--; col -= utf_head_off(ptr, ptr + col); } } - if (dohex) { + if (do_hex) { while (col > 0 && ascii_isxdigit(ptr[col])) { col--; col -= utf_head_off(ptr, ptr + col); } } - if (dobin - && dohex + if (do_bin + && do_hex && !((col > 0 && (ptr[col] == 'X' || ptr[col] == 'x') && ptr[col - 1] == '0' @@ -4797,13 +4809,13 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) } } - if ((dohex + if ((do_hex && col > 0 && (ptr[col] == 'X' || ptr[col] == 'x') && ptr[col - 1] == '0' && !utf_head_off(ptr, ptr + col - 1) && ascii_isxdigit(ptr[col + 1])) - || (dobin + || (do_bin && col > 0 && (ptr[col] == 'B' || ptr[col] == 'b') && ptr[col - 1] == '0' @@ -4818,13 +4830,13 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) while (ptr[col] != NUL && !ascii_isdigit(ptr[col]) - && !(doalp && ASCII_ISALPHA(ptr[col]))) { + && !(do_alpha && ASCII_ISALPHA(ptr[col]))) { col++; } while (col > 0 && ascii_isdigit(ptr[col - 1]) - && !(doalp && ASCII_ISALPHA(ptr[col]))) { + && !(do_alpha && ASCII_ISALPHA(ptr[col]))) { col--; } } @@ -4832,7 +4844,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) if (visual) { while (ptr[col] != NUL && length > 0 && !ascii_isdigit(ptr[col]) - && !(doalp && ASCII_ISALPHA(ptr[col]))) { + && !(do_alpha && ASCII_ISALPHA(ptr[col]))) { int mb_len = utfc_ptr2len(ptr + col); col += mb_len; @@ -4844,7 +4856,8 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) } if (col > pos->col && ptr[col - 1] == '-' - && !utf_head_off(ptr, ptr + col - 1)) { + && !utf_head_off(ptr, ptr + col - 1) + && !do_unsigned) { negative = true; was_positive = false; } @@ -4852,12 +4865,12 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) // If a number was found, and saving for undo works, replace the number. firstdigit = ptr[col]; - if (!ascii_isdigit(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit))) { + if (!ascii_isdigit(firstdigit) && !(do_alpha && ASCII_ISALPHA(firstdigit))) { beep_flush(); goto theend; } - if (doalp && ASCII_ISALPHA(firstdigit)) { + if (do_alpha && ASCII_ISALPHA(firstdigit)) { // decrement or increment alphabetic character if (op_type == OP_NR_SUB) { if (CharOrd(firstdigit) < Prenum1) { @@ -4889,7 +4902,9 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) curwin->w_cursor.col = col; } else { if (col > 0 && ptr[col - 1] == '-' - && !utf_head_off(ptr, ptr + col - 1) && !visual) { + && !utf_head_off(ptr, ptr + col - 1) + && !visual + && !do_unsigned) { // negative number col--; negative = true; @@ -4903,9 +4918,9 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) } vim_str2nr(ptr + col, &pre, &length, - 0 + (dobin ? STR2NR_BIN : 0) - + (dooct ? STR2NR_OCT : 0) - + (dohex ? STR2NR_HEX : 0), + 0 + (do_bin ? STR2NR_BIN : 0) + + (do_oct ? STR2NR_OCT : 0) + + (do_hex ? STR2NR_HEX : 0), NULL, &n, maxlen); // ignore leading '-' for hex, octal and bin numbers @@ -4916,7 +4931,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) } // add or subtract - subtract = false; + bool subtract = false; if (op_type == OP_NR_SUB) { subtract ^= true; } @@ -4948,6 +4963,17 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) } } + if (do_unsigned && negative) { + if (subtract) { + // sticking at zero. + n = (uvarnumber_T)0; + } else { + // sticking at 2^64 - 1. + n = (uvarnumber_T)(-1); + } + negative = false; + } + if (visual && !was_positive && !negative && col > 0) { // need to remove the '-' col--; @@ -5029,7 +5055,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) // total length of the number remains the same. // Don't do this when // the result may look like an octal number. - if (firstdigit == '0' && !(dooct && pre == 0)) { + if (firstdigit == '0' && !(do_oct && pre == 0)) { while (length-- > 0) { *ptr++ = '0'; } @@ -6291,3 +6317,33 @@ bool op_reg_set_previous(const char name) y_previous = &y_regs[i]; return true; } + +/// Get the byte count of buffer region. End-exclusive. +/// +/// @return number of bytes +bcount_t get_region_bytecount(buf_T *buf, linenr_T start_lnum, + linenr_T end_lnum, colnr_T start_col, + colnr_T end_col) +{ + linenr_T max_lnum = buf->b_ml.ml_line_count; + if (start_lnum > max_lnum) { + return 0; + } + if (start_lnum == end_lnum) { + return end_col - start_col; + } + const char *first = (const char *)ml_get_buf(buf, start_lnum, false); + bcount_t deleted_bytes = (bcount_t)STRLEN(first) - start_col + 1; + + for (linenr_T i = 1; i <= end_lnum-start_lnum-1; i++) { + if (start_lnum + i > max_lnum) { + return deleted_bytes; + } + deleted_bytes += (bcount_t)STRLEN( + ml_get_buf(buf, start_lnum + i, false)) + 1; + } + if (end_lnum > max_lnum) { + return deleted_bytes; + } + return deleted_bytes + end_col; +} |