mirror of
https://github.com/neovim/neovim.git
synced 2025-10-03 00:18:33 +00:00
vim-patch:7.4.1087
Problem: CTRL-A and CTRL-X do not work properly with blockwise visual
selection if there is a mix of Tab and spaces.
Solution: Add OP_NR_ADD and OP_NR_SUB. (Hirohito Higashi)
d79e55016c
This commit is contained in:
@@ -1414,11 +1414,12 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
|
||||
int lbr_saved = curwin->w_p_lbr;
|
||||
|
||||
|
||||
/* 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 */
|
||||
// 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
|
||||
bool include_line_break = false;
|
||||
|
||||
old_cursor = curwin->w_cursor;
|
||||
@@ -1656,6 +1657,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
|
||||
redo_VIsual_vcol = resel_VIsual_vcol;
|
||||
redo_VIsual_line_count = resel_VIsual_line_count;
|
||||
redo_VIsual_count = cap->count0;
|
||||
redo_VIsual_arg = cap->arg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1990,6 +1992,20 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
|
||||
deleteFold(oap->start.lnum, oap->end.lnum,
|
||||
oap->op_type == OP_FOLDDELREC, oap->is_VIsual);
|
||||
break;
|
||||
|
||||
case OP_NR_ADD:
|
||||
case OP_NR_SUB:
|
||||
if (empty_region_error) {
|
||||
vim_beep(BO_OPER);
|
||||
CancelRedo();
|
||||
} else {
|
||||
VIsual_active = true;
|
||||
curwin->w_p_lbr = lbr_saved;
|
||||
op_addsub(oap, cap->count1, redo_VIsual_arg);
|
||||
VIsual_active = false;
|
||||
}
|
||||
check_cursor_col();
|
||||
break;
|
||||
default:
|
||||
clearopbeep(oap);
|
||||
}
|
||||
@@ -3022,34 +3038,6 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol,
|
||||
return (size_t)col;
|
||||
}
|
||||
|
||||
// Add commands to reselect Visual mode into the redo buffer.
|
||||
static void prep_redo_visual(cmdarg_T *cap)
|
||||
{
|
||||
ResetRedobuff();
|
||||
AppendCharToRedobuff(VIsual_mode);
|
||||
if (VIsual_mode == 'V' &&
|
||||
curbuf->b_visual.vi_end.lnum != curbuf->b_visual.vi_start.lnum) {
|
||||
AppendNumberToRedobuff(curbuf->b_visual.vi_end.lnum -
|
||||
curbuf->b_visual.vi_start.lnum);
|
||||
AppendCharToRedobuff('j');
|
||||
} else if (VIsual_mode == 'v' || VIsual_mode == Ctrl_V) {
|
||||
// block visual mode or char visual mmode
|
||||
if (curbuf->b_visual.vi_end.lnum != curbuf->b_visual.vi_start.lnum) {
|
||||
AppendNumberToRedobuff(curbuf->b_visual.vi_end.lnum -
|
||||
curbuf->b_visual.vi_start.lnum);
|
||||
AppendCharToRedobuff('j');
|
||||
}
|
||||
if (curbuf->b_visual.vi_curswant == MAXCOL) {
|
||||
AppendCharToRedobuff('$');
|
||||
} else if (curbuf->b_visual.vi_end.col > curbuf->b_visual.vi_start.col) {
|
||||
AppendNumberToRedobuff(curbuf->b_visual.vi_end.col -
|
||||
curbuf->b_visual.vi_start.col);
|
||||
AppendCharToRedobuff(' ');
|
||||
}
|
||||
}
|
||||
AppendNumberToRedobuff(cap->count1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare for redo of a normal command.
|
||||
*/
|
||||
@@ -3534,27 +3522,14 @@ static void nv_help(cmdarg_T *cap)
|
||||
*/
|
||||
static void nv_addsub(cmdarg_T *cap)
|
||||
{
|
||||
bool visual = VIsual_active;
|
||||
|
||||
if (cap->oap->op_type == OP_NOP
|
||||
&& do_addsub((int)cap->cmdchar, cap->count1, cap->arg) == OK) {
|
||||
if (visual) {
|
||||
prep_redo_visual(cap);
|
||||
if (cap->arg) {
|
||||
AppendCharToRedobuff('g');
|
||||
}
|
||||
AppendCharToRedobuff(cap->cmdchar);
|
||||
} else {
|
||||
prep_redo_cmd(cap);
|
||||
}
|
||||
if (!VIsual_active && cap->oap->op_type == OP_NOP) {
|
||||
cap->oap->op_type = cap->cmdchar == Ctrl_A ? OP_NR_ADD : OP_NR_SUB;
|
||||
op_addsub(cap->oap, cap->count1, cap->arg);
|
||||
cap->oap->op_type = OP_NOP;
|
||||
} else if (VIsual_active) {
|
||||
nv_operator(cap);
|
||||
} else {
|
||||
clearopbeep(cap->oap);
|
||||
}
|
||||
if (visual) {
|
||||
VIsual_active = false;
|
||||
redo_VIsual_busy = false;
|
||||
may_clear_cmdline();
|
||||
redraw_later(INVERTED);
|
||||
clearop(cap->oap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6383,6 +6358,7 @@ static void nv_g_cmd(cmdarg_T *cap)
|
||||
if (VIsual_active) {
|
||||
cap->arg = true;
|
||||
cap->cmdchar = cap->nchar;
|
||||
cap->nchar = NUL;
|
||||
nv_addsub(cap);
|
||||
} else {
|
||||
clearopbeep(oap);
|
||||
|
620
src/nvim/ops.c
620
src/nvim/ops.c
@@ -115,6 +115,8 @@ static char opchars[][3] =
|
||||
{'z', 'D', TRUE}, /* OP_FOLDDELREC */
|
||||
{'g', 'w', TRUE}, /* OP_FORMAT2 */
|
||||
{'g', '@', FALSE}, /* OP_FUNCTION */
|
||||
{Ctrl_A, NUL, false}, // OP_NR_ADD
|
||||
{Ctrl_X, NUL, false}, // OP_NR_SUB
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -125,13 +127,27 @@ int get_op_type(int char1, int char2)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (char1 == 'r') /* ignore second character */
|
||||
if (char1 == 'r') {
|
||||
// ignore second character
|
||||
return OP_REPLACE;
|
||||
if (char1 == '~') /* when tilde is an operator */
|
||||
}
|
||||
if (char1 == '~') {
|
||||
// when tilde is an operator
|
||||
return OP_TILDE;
|
||||
for (i = 0;; i++)
|
||||
if (opchars[i][0] == char1 && opchars[i][1] == char2)
|
||||
}
|
||||
if (char1 == 'g' && char2 == Ctrl_A) {
|
||||
// add
|
||||
return OP_NR_ADD;
|
||||
}
|
||||
if (char1 == 'g' && char2 == Ctrl_X) {
|
||||
// subtract
|
||||
return OP_NR_SUB;
|
||||
}
|
||||
for (i = 0;; i++) {
|
||||
if (opchars[i][0] == char1 && opchars[i][1] == char2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -4181,14 +4197,115 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, int i
|
||||
bdp->textstart = pstart;
|
||||
}
|
||||
|
||||
/// Handle the add/subtract operator.
|
||||
///
|
||||
/// @param[in] oap Arguments of operator.
|
||||
/// @param[in] Prenum1 Amount of addition or subtraction.
|
||||
/// @param[in] g_cmd Prefixed with `g`.
|
||||
void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd)
|
||||
{
|
||||
pos_T pos;
|
||||
struct block_def bd;
|
||||
ssize_t change_cnt = 0;
|
||||
linenr_T amount = Prenum1;
|
||||
|
||||
if (!VIsual_active) {
|
||||
pos = curwin->w_cursor;
|
||||
if (u_save_cursor() == FAIL) {
|
||||
return;
|
||||
}
|
||||
change_cnt = do_addsub(oap->op_type, &pos, 0, amount);
|
||||
if (change_cnt) {
|
||||
changed_lines(pos.lnum, 0, pos.lnum + 1, 0L);
|
||||
}
|
||||
} else {
|
||||
int one_change;
|
||||
int length;
|
||||
pos_T startpos;
|
||||
|
||||
if (u_save((linenr_T)(oap->start.lnum - 1),
|
||||
(linenr_T)(oap->end.lnum + 1)) == FAIL) {
|
||||
return;
|
||||
}
|
||||
|
||||
pos = oap->start;
|
||||
for (; pos.lnum <= oap->end.lnum; ++pos.lnum) {
|
||||
if (oap->motion_type == MBLOCK) {
|
||||
// Visual block mode
|
||||
block_prep(oap, &bd, pos.lnum, false);
|
||||
pos.col = bd.textcol;
|
||||
length = bd.textlen;
|
||||
} else {
|
||||
if (oap->motion_type == MLINE) {
|
||||
curwin->w_cursor.col = 0;
|
||||
pos.col = 0;
|
||||
length = (colnr_T)STRLEN(ml_get(pos.lnum));
|
||||
} else if (oap->motion_type == MCHAR) {
|
||||
if (!oap->inclusive) {
|
||||
dec(&(oap->end));
|
||||
}
|
||||
length = (colnr_T)STRLEN(ml_get(pos.lnum));
|
||||
pos.col = 0;
|
||||
if (pos.lnum == oap->start.lnum) {
|
||||
pos.col += oap->start.col;
|
||||
length -= oap->start.col;
|
||||
}
|
||||
if (pos.lnum == oap->end.lnum) {
|
||||
length = (int)STRLEN(ml_get(oap->end.lnum));
|
||||
if (oap->end.col >= length) {
|
||||
oap->end.col = length - 1;
|
||||
}
|
||||
length = oap->end.col - pos.col + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
startpos = curbuf->b_op_start;
|
||||
}
|
||||
change_cnt++;
|
||||
}
|
||||
|
||||
if (g_cmd && one_change) {
|
||||
amount += Prenum1;
|
||||
}
|
||||
}
|
||||
if (change_cnt) {
|
||||
changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L);
|
||||
}
|
||||
|
||||
if (!change_cnt && oap->is_VIsual) {
|
||||
// No change: need to remove the Visual selection
|
||||
redraw_curbuf_later(INVERTED);
|
||||
}
|
||||
|
||||
// Set '[ mark if something changed. Keep the last end
|
||||
// position from do_addsub().
|
||||
if (change_cnt > 0) {
|
||||
curbuf->b_op_start = startpos;
|
||||
}
|
||||
|
||||
if (change_cnt > p_report) {
|
||||
if (change_cnt == 1) {
|
||||
MSG(_("1 line changed"));
|
||||
} else {
|
||||
smsg((char *)_("%" PRId64 " lines changed"), (int64_t)change_cnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add or subtract from a number in a line.
|
||||
///
|
||||
/// @param command CTRL-A for add, CTRL-X for subtract
|
||||
/// @param Prenum1 number to add or subtract
|
||||
/// @param g_cmd Prefixed with `g`.
|
||||
/// @param op_type OP_NR_ADD or OP_NR_SUB.
|
||||
/// @param pos Cursor position.
|
||||
/// @param length Target number length.
|
||||
/// @param Prenum1 Amount of addition or subtraction.
|
||||
///
|
||||
/// @return FAIL for failure, OK otherwise
|
||||
int do_addsub(int command, linenr_T Prenum1, bool g_cmd)
|
||||
/// @return true if some character was changed.
|
||||
int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
|
||||
{
|
||||
int col;
|
||||
char_u *buf1;
|
||||
@@ -4196,11 +4313,9 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd)
|
||||
int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin
|
||||
static bool hexupper = false; // 0xABC
|
||||
unsigned long n;
|
||||
unsigned long offset = 0;
|
||||
unsigned long oldn;
|
||||
char_u *ptr;
|
||||
int c;
|
||||
int length = 0; // character length of the number
|
||||
int todel;
|
||||
bool dohex;
|
||||
bool dooct;
|
||||
@@ -4211,9 +4326,6 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd)
|
||||
bool negative = false;
|
||||
bool was_positive = true;
|
||||
bool visual = VIsual_active;
|
||||
int lnum = curwin->w_cursor.lnum;
|
||||
int lnume = curwin->w_cursor.lnum;
|
||||
int startcol = 0;
|
||||
bool did_change = false;
|
||||
pos_T t = curwin->w_cursor;
|
||||
int maxlen = 0;
|
||||
@@ -4225,44 +4337,16 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd)
|
||||
dobin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL); // "Bin"
|
||||
doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); // "alPha"
|
||||
|
||||
curwin->w_cursor = *pos;
|
||||
ptr = ml_get(pos->lnum);
|
||||
col = pos->col;
|
||||
|
||||
if (*ptr == NUL) {
|
||||
goto theend;
|
||||
}
|
||||
|
||||
// First check if we are on a hexadecimal number, after the "0x".
|
||||
col = curwin->w_cursor.col;
|
||||
if (VIsual_active) {
|
||||
if (lt(curwin->w_cursor, VIsual)) {
|
||||
curwin->w_cursor = VIsual;
|
||||
VIsual = t;
|
||||
}
|
||||
|
||||
ptr = ml_get(VIsual.lnum);
|
||||
if (VIsual_mode == 'V') {
|
||||
VIsual.col = 0;
|
||||
curwin->w_cursor.col = STRLEN(ptr);
|
||||
} else if (VIsual_mode == Ctrl_V
|
||||
&& VIsual.col > curwin->w_cursor.col) {
|
||||
t = VIsual;
|
||||
VIsual.col = curwin->w_cursor.col;
|
||||
curwin->w_cursor.col = t.col;
|
||||
}
|
||||
|
||||
// store visual area for 'gv'
|
||||
curbuf->b_visual.vi_start = VIsual;
|
||||
curbuf->b_visual.vi_end = curwin->w_cursor;
|
||||
curbuf->b_visual.vi_mode = VIsual_mode;
|
||||
curbuf->b_visual.vi_curswant = curwin->w_curswant;
|
||||
|
||||
if (VIsual_mode != 'v') {
|
||||
startcol = VIsual.col < curwin->w_cursor.col
|
||||
? VIsual.col : curwin->w_cursor.col;
|
||||
} else {
|
||||
startcol = VIsual.col;
|
||||
}
|
||||
col = startcol;
|
||||
|
||||
lnum = VIsual.lnum;
|
||||
lnume = curwin->w_cursor.lnum;
|
||||
} else {
|
||||
ptr = get_cursor_line_ptr();
|
||||
|
||||
if (!VIsual_active) {
|
||||
if (dobin) {
|
||||
while (col > 0 && ascii_isbdigit(ptr[col])) {
|
||||
col--;
|
||||
@@ -4306,7 +4390,7 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd)
|
||||
col--;
|
||||
} else {
|
||||
// Search forward and then backward to find the start of number.
|
||||
col = curwin->w_cursor.col;
|
||||
col = pos->col;
|
||||
|
||||
while (ptr[col] != NUL
|
||||
&& !ascii_isdigit(ptr[col])
|
||||
@@ -4322,279 +4406,227 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd)
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = lnum; i <= lnume; i++) {
|
||||
colnr_T stop = 0;
|
||||
|
||||
t = curwin->w_cursor;
|
||||
curwin->w_cursor.lnum = i;
|
||||
ptr = get_cursor_line_ptr();
|
||||
if ((int)STRLEN(ptr) <= col) {
|
||||
// try again on next line
|
||||
continue;
|
||||
if (visual) {
|
||||
while (ptr[col] != NUL && length > 0 && !ascii_isdigit(ptr[col]) &&
|
||||
!(doalp && ASCII_ISALPHA(ptr[col]))) {
|
||||
col++;
|
||||
length--;
|
||||
}
|
||||
if (visual) {
|
||||
if (VIsual_mode == 'v' && i == lnume) {
|
||||
stop = curwin->w_cursor.col;
|
||||
} else if (VIsual_mode == Ctrl_V &&
|
||||
curbuf->b_visual.vi_curswant != MAXCOL) {
|
||||
stop = curwin->w_cursor.col;
|
||||
}
|
||||
|
||||
while (ptr[col] != NUL
|
||||
&& !ascii_isdigit(ptr[col])
|
||||
&& !(doalp && ASCII_ISALPHA(ptr[col]))) {
|
||||
if (col > 0 && col == stop) {
|
||||
break;
|
||||
}
|
||||
col++;
|
||||
}
|
||||
|
||||
if (col > startcol && ptr[col - 1] == '-') {
|
||||
negative = true;
|
||||
was_positive = false;
|
||||
}
|
||||
if (length == 0) {
|
||||
goto theend;
|
||||
}
|
||||
// If a number was found, and saving for undo works, replace the number.
|
||||
firstdigit = ptr[col];
|
||||
if ((!ascii_isdigit(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit)))
|
||||
|| u_save_cursor() != OK) {
|
||||
if (lnum < lnume) {
|
||||
if (visual && VIsual_mode != Ctrl_V) {
|
||||
col = 0;
|
||||
|
||||
if (col > pos->col && ptr[col - 1] == '-') {
|
||||
negative = true;
|
||||
was_positive = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If a number was found, and saving for undo works, replace the number.
|
||||
firstdigit = ptr[col];
|
||||
if (!ascii_isdigit(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit))) {
|
||||
beep_flush();
|
||||
goto theend;
|
||||
}
|
||||
|
||||
if (doalp && ASCII_ISALPHA(firstdigit)) {
|
||||
// decrement or increment alphabetic character
|
||||
if (op_type == OP_NR_SUB) {
|
||||
if (CharOrd(firstdigit) < Prenum1) {
|
||||
if (isupper(firstdigit)) {
|
||||
firstdigit = 'A';
|
||||
} else {
|
||||
col = startcol;
|
||||
}
|
||||
// Try again on next line
|
||||
continue;
|
||||
}
|
||||
beep_flush();
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (doalp && ASCII_ISALPHA(firstdigit)) {
|
||||
// decrement or increment alphabetic character
|
||||
if (command == Ctrl_X) {
|
||||
if (CharOrd(firstdigit) < Prenum1) {
|
||||
if (isupper(firstdigit)) {
|
||||
firstdigit = 'A';
|
||||
} else {
|
||||
firstdigit = 'a';
|
||||
}
|
||||
} else {
|
||||
firstdigit -= Prenum1;
|
||||
firstdigit = 'a';
|
||||
}
|
||||
} else {
|
||||
if (26 - CharOrd(firstdigit) - 1 < Prenum1) {
|
||||
if (isupper(firstdigit)) {
|
||||
firstdigit = 'Z';
|
||||
} else {
|
||||
firstdigit = 'z';
|
||||
}
|
||||
} else {
|
||||
firstdigit += Prenum1;
|
||||
}
|
||||
firstdigit -= Prenum1;
|
||||
}
|
||||
curwin->w_cursor.col = col;
|
||||
if (!did_change) {
|
||||
startpos = curwin->w_cursor;
|
||||
}
|
||||
did_change = true;
|
||||
(void)del_char(false);
|
||||
ins_char(firstdigit);
|
||||
endpos = curwin->w_cursor;
|
||||
curwin->w_cursor.col = col;
|
||||
} else {
|
||||
if (col > 0 && ptr[col - 1] == '-' && !visual) {
|
||||
// negative number
|
||||
col--;
|
||||
negative = true;
|
||||
if (26 - CharOrd(firstdigit) - 1 < Prenum1) {
|
||||
if (isupper(firstdigit)) {
|
||||
firstdigit = 'Z';
|
||||
} else {
|
||||
firstdigit = 'z';
|
||||
}
|
||||
} else {
|
||||
firstdigit += Prenum1;
|
||||
}
|
||||
}
|
||||
curwin->w_cursor.col = col;
|
||||
if (!did_change) {
|
||||
startpos = curwin->w_cursor;
|
||||
}
|
||||
did_change = true;
|
||||
(void)del_char(false);
|
||||
ins_char(firstdigit);
|
||||
endpos = curwin->w_cursor;
|
||||
curwin->w_cursor.col = col;
|
||||
} else {
|
||||
if (col > 0 && ptr[col - 1] == '-' && !visual) {
|
||||
// negative number
|
||||
col--;
|
||||
negative = true;
|
||||
}
|
||||
|
||||
// get the number value (unsigned)
|
||||
if (visual && VIsual_mode != 'V') {
|
||||
if (VIsual_mode == 'v') {
|
||||
if (i == lnum) {
|
||||
maxlen = (lnum == lnume
|
||||
? curwin->w_cursor.col - col + 1
|
||||
: (int)STRLEN(ptr) - col);
|
||||
} else {
|
||||
maxlen = (i == lnume
|
||||
? curwin->w_cursor.col - col + 1
|
||||
: (int)STRLEN(ptr) - col);
|
||||
}
|
||||
} else if (VIsual_mode == Ctrl_V) {
|
||||
maxlen = (curbuf->b_visual.vi_curswant == MAXCOL
|
||||
? (int)STRLEN(ptr) - col
|
||||
: curwin->w_cursor.col - col + 1);
|
||||
// get the number value (unsigned)
|
||||
if (visual && VIsual_mode != 'V') {
|
||||
maxlen = (curbuf->b_visual.vi_curswant == MAXCOL
|
||||
? (int)STRLEN(ptr) - col
|
||||
: length);
|
||||
}
|
||||
|
||||
vim_str2nr(ptr + col, &pre, &length,
|
||||
0 + (dobin ? STR2NR_BIN : 0)
|
||||
+ (dooct ? STR2NR_OCT : 0)
|
||||
+ (dohex ? STR2NR_HEX : 0),
|
||||
NULL, &n, maxlen);
|
||||
|
||||
// ignore leading '-' for hex, octal and bin numbers
|
||||
if (pre && negative) {
|
||||
col++;
|
||||
length--;
|
||||
negative = false;
|
||||
}
|
||||
|
||||
// add or subtract
|
||||
subtract = false;
|
||||
if (op_type == OP_NR_SUB) {
|
||||
subtract ^= true;
|
||||
}
|
||||
if (negative) {
|
||||
subtract ^= true;
|
||||
}
|
||||
|
||||
oldn = n;
|
||||
|
||||
n = subtract ? n - (unsigned long) Prenum1
|
||||
: n + (unsigned long) Prenum1;
|
||||
|
||||
// handle wraparound for decimal numbers
|
||||
if (!pre) {
|
||||
if (subtract) {
|
||||
if (n > oldn) {
|
||||
n = 1 + (n ^ (unsigned long)-1);
|
||||
negative ^= true;
|
||||
}
|
||||
} else {
|
||||
// add
|
||||
if (n < oldn) {
|
||||
n = (n ^ (unsigned long)-1);
|
||||
negative ^= true;
|
||||
}
|
||||
}
|
||||
|
||||
vim_str2nr(ptr + col, &pre, &length,
|
||||
0 + (dobin ? STR2NR_BIN : 0)
|
||||
+ (dooct ? STR2NR_OCT : 0)
|
||||
+ (dohex ? STR2NR_HEX : 0),
|
||||
NULL, &n, maxlen);
|
||||
|
||||
// ignore leading '-' for hex, octal and bin numbers
|
||||
if (pre && negative) {
|
||||
col++;
|
||||
length--;
|
||||
if (n == 0) {
|
||||
negative = false;
|
||||
}
|
||||
}
|
||||
|
||||
// add or subtract
|
||||
subtract = false;
|
||||
if (command == Ctrl_X) {
|
||||
subtract ^= true;
|
||||
}
|
||||
if (negative) {
|
||||
subtract ^= true;
|
||||
}
|
||||
if (visual && !was_positive && !negative && col > 0) {
|
||||
// need to remove the '-'
|
||||
col--;
|
||||
length++;
|
||||
}
|
||||
|
||||
oldn = n;
|
||||
// Delete the old number.
|
||||
curwin->w_cursor.col = col;
|
||||
if (!did_change) {
|
||||
startpos = curwin->w_cursor;
|
||||
}
|
||||
did_change = true;
|
||||
todel = length;
|
||||
c = gchar_cursor();
|
||||
|
||||
n = subtract ? n - (unsigned long) Prenum1
|
||||
: n + (unsigned long) Prenum1;
|
||||
|
||||
// handle wraparound for decimal numbers
|
||||
if (!pre) {
|
||||
if (subtract) {
|
||||
if (n > oldn) {
|
||||
n = 1 + (n ^ (unsigned long)-1);
|
||||
negative ^= true;
|
||||
}
|
||||
// Don't include the '-' in the length, only the length of the part
|
||||
// after it is kept the same.
|
||||
if (c == '-') {
|
||||
length--;
|
||||
}
|
||||
while (todel-- > 0) {
|
||||
if (c < 0x100 && isalpha(c)) {
|
||||
if (isupper(c)) {
|
||||
hexupper = true;
|
||||
} else {
|
||||
// add
|
||||
if (n < oldn) {
|
||||
n = (n ^ (unsigned long)-1);
|
||||
negative ^= true;
|
||||
}
|
||||
}
|
||||
if (n == 0) {
|
||||
negative = false;
|
||||
hexupper = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (visual && !was_positive && !negative && col > 0) {
|
||||
// need to remove the '-'
|
||||
col--;
|
||||
length++;
|
||||
}
|
||||
|
||||
// Delete the old number.
|
||||
curwin->w_cursor.col = col;
|
||||
if (!did_change) {
|
||||
startpos = curwin->w_cursor;
|
||||
}
|
||||
did_change = true;
|
||||
todel = length;
|
||||
// del_char() will mark line needing displaying
|
||||
(void)del_char(false);
|
||||
c = gchar_cursor();
|
||||
}
|
||||
|
||||
// Don't include the '-' in the length, only the length of the part
|
||||
// after it is kept the same.
|
||||
if (c == '-') {
|
||||
length--;
|
||||
}
|
||||
while (todel-- > 0) {
|
||||
if (c < 0x100 && isalpha(c)) {
|
||||
if (isupper(c)) {
|
||||
hexupper = true;
|
||||
} else {
|
||||
hexupper = false;
|
||||
// Prepare the leading characters in buf1[].
|
||||
// When there are many leading zeros it could be very long.
|
||||
// Allocate a bit too much.
|
||||
buf1 = xmalloc(length + NUMBUFLEN);
|
||||
if (buf1 == NULL) {
|
||||
goto theend;
|
||||
}
|
||||
ptr = buf1;
|
||||
if (negative && (!visual || (visual && was_positive))) {
|
||||
*ptr++ = '-';
|
||||
}
|
||||
if (pre) {
|
||||
*ptr++ = '0';
|
||||
length--;
|
||||
}
|
||||
if (pre == 'b' || pre == 'B' ||
|
||||
pre == 'x' || pre == 'X') {
|
||||
*ptr++ = pre;
|
||||
length--;
|
||||
}
|
||||
|
||||
// Put the number characters in buf2[].
|
||||
if (pre == 'b' || pre == 'B') {
|
||||
size_t bits = 0;
|
||||
size_t i = 0;
|
||||
|
||||
// leading zeros
|
||||
for (bits = 8 * sizeof(n); bits > 0; bits--) {
|
||||
if ((n >> (bits - 1)) & 0x1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// del_char() will mark line needing displaying
|
||||
(void)del_char(false);
|
||||
c = gchar_cursor();
|
||||
}
|
||||
|
||||
// Prepare the leading characters in buf1[].
|
||||
// When there are many leading zeros it could be very long.
|
||||
// Allocate a bit too much.
|
||||
buf1 = xmalloc(length + NUMBUFLEN);
|
||||
ptr = buf1;
|
||||
if (negative && (!visual || (visual && was_positive))) {
|
||||
*ptr++ = '-';
|
||||
}
|
||||
if (pre) {
|
||||
*ptr++ = '0';
|
||||
length--;
|
||||
}
|
||||
if (pre == 'b' || pre == 'B' ||
|
||||
pre == 'x' || pre == 'X') {
|
||||
*ptr++ = pre;
|
||||
length--;
|
||||
while (bits > 0) {
|
||||
buf2[i++] = ((n >> --bits) & 0x1) ? '1' : '0';
|
||||
}
|
||||
|
||||
// Put the number characters in buf2[].
|
||||
if (pre == 'b' || pre == 'B') {
|
||||
size_t bits = 0;
|
||||
size_t pos = 0;
|
||||
buf2[i] = '\0';
|
||||
|
||||
// leading zeros
|
||||
for (bits = 8 * sizeof(n); bits > 0; bits--) {
|
||||
if ((n >> (bits - 1)) & 0x1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (bits > 0) {
|
||||
buf2[pos++] = ((n >> --bits) & 0x1) ? '1' : '0';
|
||||
}
|
||||
|
||||
buf2[pos] = '\0';
|
||||
|
||||
} else if (pre == 0) {
|
||||
vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIu64, (uint64_t)n);
|
||||
} else if (pre == '0') {
|
||||
vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIo64, (uint64_t)n);
|
||||
} else if (pre && hexupper) {
|
||||
vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIX64, (uint64_t)n);
|
||||
} else {
|
||||
vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIx64, (uint64_t)n);
|
||||
}
|
||||
length -= (int)STRLEN(buf2);
|
||||
|
||||
// Adjust number of zeros to the new number of digits, so the
|
||||
// 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)) {
|
||||
while (length-- > 0) {
|
||||
*ptr++ = '0';
|
||||
}
|
||||
}
|
||||
*ptr = NUL;
|
||||
STRCAT(buf1, buf2);
|
||||
ins_str(buf1); // insert the new number
|
||||
xfree(buf1);
|
||||
endpos = curwin->w_cursor;
|
||||
if (lnum < lnume) {
|
||||
curwin->w_cursor.col = t.col;
|
||||
} else if (did_change && curwin->w_cursor.col) {
|
||||
curwin->w_cursor.col--;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_cmd) {
|
||||
offset = (unsigned long)Prenum1;
|
||||
g_cmd = 0;
|
||||
}
|
||||
// reset
|
||||
subtract = false;
|
||||
negative = false;
|
||||
was_positive = true;
|
||||
if (visual && VIsual_mode == Ctrl_V) {
|
||||
col = startcol;
|
||||
} else if (pre == 0) {
|
||||
vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIu64, (uint64_t)n);
|
||||
} else if (pre == '0') {
|
||||
vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIo64, (uint64_t)n);
|
||||
} else if (pre && hexupper) {
|
||||
vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIX64, (uint64_t)n);
|
||||
} else {
|
||||
col = 0;
|
||||
vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIx64, (uint64_t)n);
|
||||
}
|
||||
length -= (int)STRLEN(buf2);
|
||||
|
||||
// Adjust number of zeros to the new number of digits, so the
|
||||
// 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)) {
|
||||
while (length-- > 0) {
|
||||
*ptr++ = '0';
|
||||
}
|
||||
}
|
||||
*ptr = NUL;
|
||||
STRCAT(buf1, buf2);
|
||||
ins_str(buf1); // insert the new number
|
||||
xfree(buf1);
|
||||
endpos = curwin->w_cursor;
|
||||
if (did_change && curwin->w_cursor.col) {
|
||||
curwin->w_cursor.col--;
|
||||
}
|
||||
Prenum1 += offset;
|
||||
curwin->w_set_curswant = true;
|
||||
}
|
||||
|
||||
theend:
|
||||
if (visual) {
|
||||
// cursor at the top of the selection
|
||||
curwin->w_cursor = VIsual;
|
||||
curwin->w_cursor = t;
|
||||
}
|
||||
if (did_change) {
|
||||
// set the '[ and '] marks
|
||||
@@ -4604,7 +4636,7 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd)
|
||||
curbuf->b_op_end.col--;
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
return did_change;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -66,6 +66,10 @@ typedef int (*Indenter)(void);
|
||||
#define OP_FOLDDELREC 25 /* "zD" delete folds recursively */
|
||||
#define OP_FORMAT2 26 /* "gw" format operator, keeps cursor pos */
|
||||
#define OP_FUNCTION 27 /* "g@" call 'operatorfunc' */
|
||||
#define OP_NR_ADD 28 // "<C-A>" Add to the number or alphabetic
|
||||
// character (OP_ADD conflicts with Perl)
|
||||
#define OP_NR_SUB 29 // "<C-X>" Subtract from the number or
|
||||
// alphabetic character
|
||||
|
||||
/// Flags for get_reg_contents().
|
||||
enum GRegFlags {
|
||||
|
@@ -133,7 +133,7 @@ func Test_visual_increment_04()
|
||||
exec "norm! vf-\<C-A>"
|
||||
call assert_equal(["foobar-10"], getline(1, '$'))
|
||||
" NOTE: I think this is correct behavior...
|
||||
"call assert_equal([0, 1, 1, 0], getpos('.'))
|
||||
call assert_equal([0, 1, 1, 0], getpos('.'))
|
||||
endfunc
|
||||
|
||||
" 5) g<Ctrl-A> on letter
|
||||
@@ -576,7 +576,111 @@ func Test_visual_increment_27()
|
||||
endif
|
||||
endfunc
|
||||
|
||||
" 28) block-wise increment and dot-repeat
|
||||
" Tab code and linewise-visual inc/dec
|
||||
func Test_visual_increment_28()
|
||||
call setline(1, ["x\<TAB>10", "\<TAB>-1"])
|
||||
exec "norm! Vj\<C-A>"
|
||||
call assert_equal(["x\<TAB>11", "\<TAB>0"], getline(1, '$'))
|
||||
call assert_equal([0, 1, 1, 0], getpos('.'))
|
||||
|
||||
call setline(1, ["x\<TAB>10", "\<TAB>-1"])
|
||||
exec "norm! ggVj\<C-X>"
|
||||
call assert_equal(["x\<TAB>9", "\<TAB>-2"], getline(1, '$'))
|
||||
call assert_equal([0, 1, 1, 0], getpos('.'))
|
||||
endfunc
|
||||
|
||||
" Tab code and linewise-visual inc/dec with 'nrformats'+=alpha
|
||||
func Test_visual_increment_29()
|
||||
set nrformats+=alpha
|
||||
call setline(1, ["x\<TAB>10", "\<TAB>-1"])
|
||||
exec "norm! Vj\<C-A>"
|
||||
call assert_equal(["y\<TAB>10", "\<TAB>0"], getline(1, '$'))
|
||||
call assert_equal([0, 1, 1, 0], getpos('.'))
|
||||
|
||||
call setline(1, ["x\<TAB>10", "\<TAB>-1"])
|
||||
exec "norm! ggVj\<C-X>"
|
||||
call assert_equal(["w\<TAB>10", "\<TAB>-2"], getline(1, '$'))
|
||||
call assert_equal([0, 1, 1, 0], getpos('.'))
|
||||
endfunc
|
||||
|
||||
" Tab code and character-visual inc/dec
|
||||
func Test_visual_increment_30()
|
||||
call setline(1, ["x\<TAB>10", "\<TAB>-1"])
|
||||
exec "norm! f1vjf1\<C-A>"
|
||||
call assert_equal(["x\<TAB>11", "\<TAB>0"], getline(1, '$'))
|
||||
call assert_equal([0, 1, 3, 0], getpos('.'))
|
||||
|
||||
call setline(1, ["x\<TAB>10", "\<TAB>-1"])
|
||||
exec "norm! ggf1vjf1\<C-X>"
|
||||
call assert_equal(["x\<TAB>9", "\<TAB>-2"], getline(1, '$'))
|
||||
call assert_equal([0, 1, 3, 0], getpos('.'))
|
||||
endfunc
|
||||
|
||||
" Tab code and blockwise-visual inc/dec
|
||||
func Test_visual_increment_31()
|
||||
call setline(1, ["x\<TAB>10", "\<TAB>-1"])
|
||||
exec "norm! f1\<C-V>jl\<C-A>"
|
||||
call assert_equal(["x\<TAB>11", "\<TAB>0"], getline(1, '$'))
|
||||
call assert_equal([0, 1, 3, 0], getpos('.'))
|
||||
|
||||
call setline(1, ["x\<TAB>10", "\<TAB>-1"])
|
||||
exec "norm! ggf1\<C-V>jl\<C-X>"
|
||||
call assert_equal(["x\<TAB>9", "\<TAB>-2"], getline(1, '$'))
|
||||
call assert_equal([0, 1, 3, 0], getpos('.'))
|
||||
endfunc
|
||||
|
||||
" Tab code and blockwise-visual decrement with 'linebreak' and 'showbreak'
|
||||
func Test_visual_increment_32()
|
||||
28vnew dummy_31
|
||||
set linebreak showbreak=+
|
||||
call setline(1, ["x\<TAB>\<TAB>\<TAB>10", "\<TAB>\<TAB>\<TAB>\<TAB>-1"])
|
||||
exec "norm! ggf0\<C-V>jg_\<C-X>"
|
||||
call assert_equal(["x\<TAB>\<TAB>\<TAB>1-1", "\<TAB>\<TAB>\<TAB>\<TAB>-2"], getline(1, '$'))
|
||||
call assert_equal([0, 1, 6, 0], getpos('.'))
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
" Tab code and blockwise-visual increment with $
|
||||
func Test_visual_increment_33()
|
||||
call setline(1, ["\<TAB>123", "456"])
|
||||
exec "norm! gg0\<C-V>j$\<C-A>"
|
||||
call assert_equal(["\<TAB>124", "457"], getline(1, '$'))
|
||||
call assert_equal([0, 1, 1, 0], getpos('.'))
|
||||
endfunc
|
||||
|
||||
" Tab code and blockwise-visual increment and redo
|
||||
func Test_visual_increment_34()
|
||||
call setline(1, ["\<TAB>123", " 456789"])
|
||||
exec "norm! gg0\<C-V>j\<C-A>"
|
||||
call assert_equal(["\<TAB>123", " 457789"], getline(1, '$'))
|
||||
call assert_equal([0, 1, 1, 0], getpos('.'))
|
||||
|
||||
exec "norm! .."
|
||||
call assert_equal(["\<TAB>123", " 459789"], getline(1, '$'))
|
||||
call assert_equal([0, 1, 1, 0], getpos('.'))
|
||||
endfunc
|
||||
|
||||
" Tab code, spaces and character-visual increment and redo
|
||||
func Test_visual_increment_35()
|
||||
call setline(1, ["\<TAB>123", " 123", "\<TAB>123", "\<TAB>123"])
|
||||
exec "norm! ggvjf3\<C-A>..."
|
||||
call assert_equal(["\<TAB>127", " 127", "\<TAB>123", "\<TAB>123"], getline(1, '$'))
|
||||
call assert_equal([0, 1, 2, 0], getpos('.'))
|
||||
endfunc
|
||||
|
||||
" Tab code, spaces and blockwise-visual increment and redo
|
||||
func Test_visual_increment_36()
|
||||
call setline(1, [" 123", "\<TAB>456789"])
|
||||
exec "norm! G0\<C-V>kl\<C-A>"
|
||||
call assert_equal([" 123", "\<TAB>556789"], getline(1, '$'))
|
||||
call assert_equal([0, 1, 1, 0], getpos('.'))
|
||||
|
||||
exec "norm! ..."
|
||||
call assert_equal([" 123", "\<TAB>856789"], getline(1, '$'))
|
||||
call assert_equal([0, 1, 1, 0], getpos('.'))
|
||||
endfunc
|
||||
|
||||
" block-wise increment and dot-repeat
|
||||
" Text:
|
||||
" 1 23
|
||||
" 4 56
|
||||
@@ -587,7 +691,7 @@ endfunc
|
||||
" 4 59
|
||||
"
|
||||
" Try with and without indent.
|
||||
func Test_visual_increment_28()
|
||||
func Test_visual_increment_37()
|
||||
call setline(1, [" 1 23", " 4 56"])
|
||||
exec "norm! ggf2\<C-V>jl\<C-A>.."
|
||||
call assert_equal([" 1 26", " 4 59"], getline(1, 2))
|
||||
|
@@ -73,6 +73,8 @@ static int included_patches[] = {
|
||||
|
||||
|
||||
|
||||
1087,
|
||||
// 1086,
|
||||
1085,
|
||||
1084,
|
||||
// 1083,
|
||||
|
Reference in New Issue
Block a user