aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ops.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/ops.c')
-rw-r--r--src/nvim/ops.c499
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, &reg, false)) {
+ if ((mode == YREG_PASTE || mode == YREG_PUT)
+ && get_clipboard(regname, &reg, 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, &regtype, 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).