Bram,
here is a patch, that implements Ctrl-A/Ctrl-X in visual mode. This
allows for easy incrementing of numbers, when e.g. the leading '-' is not
supposed to be considered as a negative sign. For example you have a list of
files:
foobar-1
foobar-2
and want to increment the 1, and press Ctrl-A on the number, it will be set to
foobar0. This is probably not what is wanted, so you can use visual mode to
select the number and press Ctrl-A on it, so that it will be incremented.
While I was at it, I thought it was a nice idea, to make incrementing several
numbers (a block of numbers was selected) easier to have each single value
incremented by an additional number. This allows for something like this.
1
2
3
Visually select the lines, press Ctrl-A and Vim will increment this line to:
2
3
4
This might be useful, if one puts several times the same line and then want to
increment each number so it is one more than the one above it. Now you could
simply visually select the number and press Ctrl-A. Before, one needs to
manually increment each number several times.
The attached patch includes documentation and a test, for this feature.
Best,
Christian
--
Die Welt wird nie gut, aber sie könnte besser werden.
-- Carl Zuckmayer
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -379,10 +379,22 @@ Adding and subtracting ~
CTRL-A Add [count] to the number or alphabetic character at
or after the cursor. {not in Vi}
+ *v_CTRL-A*
+{Visual}CTRL-A Add [count] to the number or alphabetic character in
+ the highlighted text. If several lines are
+ highlighted, each one will be incremented by an
+ additional [count]. {not in Vi}
+
*CTRL-X*
CTRL-X Subtract [count] from the number or alphabetic
character at or after the cursor. {not in Vi}
+ *v_CTRL-X*
+CTRL-X Subtract [count] from the number or alphabetic
+ character in the highlighted text. If several lines
+ are highlighted, each value will be decremented by an
+ additional [count]. {not in Vi}
+
The CTRL-A and CTRL-X commands work for (signed) decimal numbers, unsigned
octal and hexadecimal numbers and alphabetic characters. This depends on the
'nrformats' option.
diff --git a/src/normal.c b/src/normal.c
--- a/src/normal.c
+++ b/src/normal.c
@@ -4246,9 +4246,17 @@ nv_help(cap)
nv_addsub(cap)
cmdarg_T *cap;
{
- if (!checkclearopq(cap->oap)
+ int visual = VIsual_active;
+ if (cap->oap->op_type == OP_NOP
&& do_addsub((int)cap->cmdchar, cap->count1) == OK)
prep_redo_cmd(cap);
+ else
+ clearopbeep(cap->oap);
+ if (visual)
+ {
+ VIsual_active = FALSE;
+ redraw_later(CLEAR);
+ }
}
/*
diff --git a/src/ops.c b/src/ops.c
--- a/src/ops.c
+++ b/src/ops.c
@@ -5405,6 +5405,7 @@ do_addsub(command, Prenum1)
int hex; /* 'X' or 'x': hex; '0': octal */
static int hexupper = FALSE; /* 0xABC */
unsigned long n;
+ long offset = 0; /* line offset for Ctrl_V mode */
long_u oldn;
char_u *ptr;
int c;
@@ -5414,247 +5415,298 @@ do_addsub(command, Prenum1)
int dooct;
int doalp;
int firstdigit;
- int negative;
int subtract;
+ int negative = FALSE;
+ int visual = VIsual_active;
+ int i;
+ int lnum = curwin->w_cursor.lnum;
+ int lnume = curwin->w_cursor.lnum;
dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); /* "heX" */
dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); /* "Octal" */
doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); /* "alPha" */
- ptr = ml_get_curline();
- RLADDSUBFIX(ptr);
-
/*
* First check if we are on a hexadecimal number, after the "0x".
*/
col = curwin->w_cursor.col;
- if (dohex)
- while (col > 0 && vim_isxdigit(ptr[col]))
+ if (VIsual_active)
+ {
+ if (lt(curwin->w_cursor, VIsual))
+ {
+ pos_T t;
+ t = curwin->w_cursor;
+ curwin->w_cursor = VIsual;
+ VIsual = t;
+ }
+ if (VIsual_mode == 'V')
+ VIsual.col = 0;
+
+ ptr = ml_get(VIsual.lnum);
+ RLADDSUBFIX(ptr);
+
+ /* 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;
+
+ col = VIsual.col;
+ lnum = VIsual.lnum;
+ lnume = curwin->w_cursor.lnum;
+ if (ptr[col] == '-')
+ {
+ negative = TRUE;
+ col++;
+ }
+ }
+ else
+ {
+ ptr = ml_get_curline();
+ RLADDSUBFIX(ptr);
+
+ if (dohex)
+ while (col > 0 && vim_isxdigit(ptr[col]))
+ --col;
+ if ( dohex
+ && col > 0
+ && (ptr[col] == 'X'
+ || ptr[col] == 'x')
+ && ptr[col - 1] == '0'
+ && vim_isxdigit(ptr[col + 1]))
+ {
+ /*
+ * Found hexadecimal number, move to its start.
+ */
--col;
- if ( dohex
- && col > 0
- && (ptr[col] == 'X'
- || ptr[col] == 'x')
- && ptr[col - 1] == '0'
- && vim_isxdigit(ptr[col + 1]))
- {
- /*
- * Found hexadecimal number, move to its start.
- */
- --col;
- }
- else
- {
- /*
- * Search forward and then backward to find the start of number.
- */
- col = curwin->w_cursor.col;
-
- while (ptr[col] != NUL
- && !vim_isdigit(ptr[col])
- && !(doalp && ASCII_ISALPHA(ptr[col])))
- ++col;
-
- while (col > 0
- && vim_isdigit(ptr[col - 1])
- && !(doalp && ASCII_ISALPHA(ptr[col])))
- --col;
- }
-
- /*
- * If a number was found, and saving for undo works, replace the number.
- */
- firstdigit = ptr[col];
- RLADDSUBFIX(ptr);
- if ((!VIM_ISDIGIT(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit)))
- || u_save_cursor() != OK)
- {
- beep_flush();
- return FAIL;
- }
-
- /* get ptr again, because u_save() may have changed it */
- ptr = ml_get_curline();
- RLADDSUBFIX(ptr);
-
- 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
-#ifdef EBCDIC
- firstdigit = EBCDIC_CHAR_ADD(firstdigit, -Prenum1);
-#else
- firstdigit -= Prenum1;
-#endif
}
else
{
- if (26 - CharOrd(firstdigit) - 1 < Prenum1)
+ /*
+ * Search forward and then backward to find the start of number.
+ */
+ col = curwin->w_cursor.col;
+
+ while (ptr[col] != NUL
+ && !vim_isdigit(ptr[col])
+ && !(doalp && ASCII_ISALPHA(ptr[col])))
+ ++col;
+
+ while (col > 0
+ && vim_isdigit(ptr[col - 1])
+ && !(doalp && ASCII_ISALPHA(ptr[col])))
+ --col;
+ }
+ }
+
+ for (i = lnum; i <= lnume; i++)
+ {
+ curwin->w_cursor.lnum = i;
+ ptr = ml_get_curline();
+ RLADDSUBFIX(ptr);
+ if ((int)STRLEN(ptr) <= col)
+ col = 0;
+ /*
+ * If a number was found, and saving for undo works, replace the number.
+ */
+ firstdigit = ptr[col];
+ RLADDSUBFIX(ptr);
+ if ((!VIM_ISDIGIT(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit)))
+ || u_save_cursor() != OK)
+ {
+ if (lnum < lnume)
+ /* Try again on next line */
+ continue;
+ beep_flush();
+ return FAIL;
+ }
+
+ ptr = ml_get_curline();
+ RLADDSUBFIX(ptr);
+
+ if (doalp && ASCII_ISALPHA(firstdigit))
+ {
+ /* decrement or increment alphabetic character */
+ if (command == Ctrl_X)
{
- if (isupper(firstdigit))
- firstdigit = 'Z';
+ if (CharOrd(firstdigit) < Prenum1)
+ {
+ if (isupper(firstdigit))
+ firstdigit = 'A';
+ else
+ firstdigit = 'a';
+ }
else
- firstdigit = 'z';
+#ifdef EBCDIC
+ firstdigit = EBCDIC_CHAR_ADD(firstdigit, -Prenum1);
+#else
+ firstdigit -= Prenum1;
+#endif
}
else
+ {
+ if (26 - CharOrd(firstdigit) - 1 < Prenum1)
+ {
+ if (isupper(firstdigit))
+ firstdigit = 'Z';
+ else
+ firstdigit = 'z';
+ }
+ else
#ifdef EBCDIC
- firstdigit = EBCDIC_CHAR_ADD(firstdigit, Prenum1);
+ firstdigit = EBCDIC_CHAR_ADD(firstdigit, Prenum1);
#else
- firstdigit += Prenum1;
-#endif
+ firstdigit += Prenum1;
+#endif
+ }
+ curwin->w_cursor.col = col;
+ (void)del_char(FALSE);
+ ins_char(firstdigit);
}
- curwin->w_cursor.col = col;
- (void)del_char(FALSE);
- ins_char(firstdigit);
- }
- else
- {
- negative = FALSE;
- if (col > 0 && ptr[col - 1] == '-') /* negative number */
+ else
{
- --col;
- negative = TRUE;
+ if (col > 0 && ptr[col - 1] == '-' && !visual) /* negative number */
+ {
+ --col;
+ negative = TRUE;
+ }
+
+ /* get the number value (unsigned) */
+ vim_str2nr(ptr + col, &hex, &length, dooct, dohex, NULL, &n);
+
+ /* ignore leading '-' for hex and octal numbers */
+ if (hex && negative)
+ {
+ ++col;
+ --length;
+ negative = FALSE;
+ }
+
+ /* add or subtract */
+ subtract = FALSE;
+ if (command == Ctrl_X)
+ subtract ^= TRUE;
+ if (negative)
+ subtract ^= TRUE;
+
+ oldn = n;
+ if (subtract)
+ n -= (unsigned long)Prenum1;
+ else
+ n += (unsigned long)Prenum1;
+
+ /* handle wraparound for decimal numbers */
+ if (!hex)
+ {
+ 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;
+ }
+ }
+ if (n == 0)
+ negative = FALSE;
+ }
+
+ /*
+ * Delete the old number.
+ */
+ curwin->w_cursor.col = col;
+ todel = length;
+ 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;
+ }
+ /* 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 = alloc((unsigned)length + NUMBUFLEN);
+ if (buf1 == NULL)
+ return FAIL;
+ ptr = buf1;
+ /* do not add leading '-' for visual mode */
+ if (negative && !visual)
+ {
+ *ptr++ = '-';
+ }
+ if (hex)
+ {
+ *ptr++ = '0';
+ --length;
+ }
+ if (hex == 'x' || hex == 'X')
+ {
+ *ptr++ = hex;
+ --length;
+ }
+
+ /*
+ * Put the number characters in buf2[].
+ */
+ if (hex == 0)
+ sprintf((char *)buf2, "%lu", n + offset);
+ else if (hex == '0')
+ sprintf((char *)buf2, "%lo", n + offset);
+ else if (hex && hexupper)
+ sprintf((char *)buf2, "%lX", n + offset);
+ else
+ sprintf((char *)buf2, "%lx", n + offset);
+ length -= (int)STRLEN(buf2);
+
+ if (subtract)
+ offset -= (unsigned long)Prenum1;
+ else
+ offset += (unsigned long)Prenum1;
+
+ /*
+ * 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 && hex == 0))
+ while (length-- > 0)
+ *ptr++ = '0';
+ *ptr = NUL;
+ STRCAT(buf1, buf2);
+ ins_str(buf1); /* insert the new number */
+ vim_free(buf1);
}
-
- /* get the number value (unsigned) */
- vim_str2nr(ptr + col, &hex, &length, dooct, dohex, NULL, &n);
-
- /* ignore leading '-' for hex and octal numbers */
- if (hex && negative)
- {
- ++col;
- --length;
- negative = FALSE;
- }
-
- /* add or subtract */
- subtract = FALSE;
- if (command == Ctrl_X)
- subtract ^= TRUE;
- if (negative)
- subtract ^= TRUE;
-
- oldn = n;
- if (subtract)
- n -= (unsigned long)Prenum1;
- else
- n += (unsigned long)Prenum1;
-
- /* handle wraparound for decimal numbers */
- if (!hex)
- {
- 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;
- }
- }
- if (n == 0)
- negative = FALSE;
- }
-
- /*
- * Delete the old number.
- */
- curwin->w_cursor.col = col;
- todel = length;
- 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;
- }
- /* 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 = alloc((unsigned)length + NUMBUFLEN);
- if (buf1 == NULL)
- return FAIL;
- ptr = buf1;
- if (negative)
- {
- *ptr++ = '-';
- }
- if (hex)
- {
- *ptr++ = '0';
- --length;
- }
- if (hex == 'x' || hex == 'X')
- {
- *ptr++ = hex;
- --length;
- }
-
- /*
- * Put the number characters in buf2[].
- */
- if (hex == 0)
- sprintf((char *)buf2, "%lu", n);
- else if (hex == '0')
- sprintf((char *)buf2, "%lo", n);
- else if (hex && hexupper)
- sprintf((char *)buf2, "%lX", n);
- else
- sprintf((char *)buf2, "%lx", 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 && hex == 0))
- while (length-- > 0)
- *ptr++ = '0';
- *ptr = NUL;
- STRCAT(buf1, buf2);
- ins_str(buf1); /* insert the new number */
- vim_free(buf1);
- }
- --curwin->w_cursor.col;
- curwin->w_set_curswant = TRUE;
+ --curwin->w_cursor.col;
+ curwin->w_set_curswant = TRUE;
#ifdef FEAT_RIGHTLEFT
- ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE);
- RLADDSUBFIX(ptr);
-#endif
+ ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE);
+ RLADDSUBFIX(ptr);
+#endif
+ }
return OK;
}
diff --git a/src/testdir/Make_amiga.mak b/src/testdir/Make_amiga.mak
--- a/src/testdir/Make_amiga.mak
+++ b/src/testdir/Make_amiga.mak
@@ -45,6 +45,7 @@ SCRIPTS = test1.out test3.out test4.out
test_command_count.out \
test_erasebackword.out \
test_eval.out \
+ test_increment.out \
test_insertcount.out \
test_listchars.out \
test_listlbr.out \
diff --git a/src/testdir/Make_dos.mak b/src/testdir/Make_dos.mak
--- a/src/testdir/Make_dos.mak
+++ b/src/testdir/Make_dos.mak
@@ -44,6 +44,7 @@ SCRIPTS = test3.out test4.out test5.out
test_command_count.out \
test_erasebackword.out \
test_eval.out \
+ test_increment.out \
test_insertcount.out \
test_listchars.out \
test_listlbr.out \
diff --git a/src/testdir/Make_ming.mak b/src/testdir/Make_ming.mak
--- a/src/testdir/Make_ming.mak
+++ b/src/testdir/Make_ming.mak
@@ -66,6 +66,7 @@ SCRIPTS = test3.out test4.out test5.out
test_command_count.out \
test_erasebackword.out \
test_eval.out \
+ test_increment.out \
test_insertcount.out \
test_listchars.out \
test_listlbr.out \
diff --git a/src/testdir/Make_os2.mak b/src/testdir/Make_os2.mak
--- a/src/testdir/Make_os2.mak
+++ b/src/testdir/Make_os2.mak
@@ -46,6 +46,7 @@ SCRIPTS = test1.out test3.out test4.out
test_command_count.out \
test_erasebackword.out \
test_eval.out \
+ test_increment.out \
test_insertcount.out \
test_listchars.out \
test_listlbr.out \
diff --git a/src/testdir/Make_vms.mms b/src/testdir/Make_vms.mms
--- a/src/testdir/Make_vms.mms
+++ b/src/testdir/Make_vms.mms
@@ -105,6 +105,7 @@ SCRIPT = test1.out test2.out test3.out
test_command_count.out \
test_erasebackword.out \
test_eval.out \
+ test_increment.out \
test_insertcount.out \
test_listchars.out \
test_listlbr.out \
diff --git a/src/testdir/Makefile b/src/testdir/Makefile
--- a/src/testdir/Makefile
+++ b/src/testdir/Makefile
@@ -42,6 +42,7 @@ SCRIPTS = test1.out test2.out test3.out
test_command_count.out \
test_erasebackword.out \
test_eval.out \
+ test_increment.out \
test_insertcount.out \
test_listchars.out \
test_listlbr.out \
diff --git a/src/testdir/test_increment.ok b/src/testdir/test_increment.ok
new file mode 100644
--- /dev/null
+++ b/src/testdir/test_increment.ok
@@ -0,0 +1,66 @@
+# Test 1
+S1======
+foobar-10
+E1======
+
+foobar-9
+foobar-9
+foobar-11
+foobar-11
+foobar-9
+
+
+# Test 2
+S2=====
+10
+20
+30
+40
+E2=====
+
+11
+22
+33
+44
+
+9
+18
+27
+36
+
+# Test 3
+S3=====
+10
+
+20
+
+30
+
+40
+E3=====
+
+12
+
+24
+
+36
+
+48
+
+8
+
+16
+
+24
+
+32
+
+# Test 4
+S4=====
+foobar-10
+E4=====
+
+foobar-10
+
+ENDTEST
+