comparison src/ops.c @ 6868:9798a98a1583 v7.4.754

patch 7.4.754 Problem: Using CTRL-A in Visual mode does not work well. (Gary Johnson) Solution: Make it increment all numbers in the Visual area. (Christian Brabandt)
author Bram Moolenaar <bram@vim.org>
date Thu, 25 Jun 2015 13:57:36 +0200
parents ac13f3533571
children f9876721bedc
comparison
equal deleted inserted replaced
6867:92ce9afd7729 6868:9798a98a1583
5373 * 'command' is CTRL-A for add, CTRL-X for subtract 5373 * 'command' is CTRL-A for add, CTRL-X for subtract
5374 * 5374 *
5375 * return FAIL for failure, OK otherwise 5375 * return FAIL for failure, OK otherwise
5376 */ 5376 */
5377 int 5377 int
5378 do_addsub(command, Prenum1) 5378 do_addsub(command, Prenum1, g_cmd)
5379 int command; 5379 int command;
5380 linenr_T Prenum1; 5380 linenr_T Prenum1;
5381 int g_cmd; /* was g<c-a>/g<c-x> */
5381 { 5382 {
5382 int col; 5383 int col;
5383 char_u *buf1; 5384 char_u *buf1;
5384 char_u buf2[NUMBUFLEN]; 5385 char_u buf2[NUMBUFLEN];
5385 int hex; /* 'X' or 'x': hex; '0': octal */ 5386 int hex; /* 'X' or 'x': hex; '0': octal */
5386 static int hexupper = FALSE; /* 0xABC */ 5387 static int hexupper = FALSE; /* 0xABC */
5387 unsigned long n; 5388 unsigned long n;
5389 long offset = 0; /* line offset for Ctrl_V mode */
5388 long_u oldn; 5390 long_u oldn;
5389 char_u *ptr; 5391 char_u *ptr;
5390 int c; 5392 int c;
5391 int length = 0; /* character length of the number */ 5393 int length = 0; /* character length of the number */
5392 int todel; 5394 int todel;
5393 int dohex; 5395 int dohex;
5394 int dooct; 5396 int dooct;
5395 int doalp; 5397 int doalp;
5396 int firstdigit; 5398 int firstdigit;
5397 int negative;
5398 int subtract; 5399 int subtract;
5400 int negative = FALSE;
5401 int visual = VIsual_active;
5402 int i;
5403 int lnum = curwin->w_cursor.lnum;
5404 int lnume = curwin->w_cursor.lnum;
5399 5405
5400 dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); /* "heX" */ 5406 dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); /* "heX" */
5401 dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); /* "Octal" */ 5407 dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); /* "Octal" */
5402 doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); /* "alPha" */ 5408 doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); /* "alPha" */
5403
5404 ptr = ml_get_curline();
5405 RLADDSUBFIX(ptr);
5406 5409
5407 /* 5410 /*
5408 * First check if we are on a hexadecimal number, after the "0x". 5411 * First check if we are on a hexadecimal number, after the "0x".
5409 */ 5412 */
5410 col = curwin->w_cursor.col; 5413 col = curwin->w_cursor.col;
5411 if (dohex) 5414 if (VIsual_active)
5412 while (col > 0 && vim_isxdigit(ptr[col])) 5415 {
5416 if (lt(curwin->w_cursor, VIsual))
5417 {
5418 pos_T t;
5419 t = curwin->w_cursor;
5420 curwin->w_cursor = VIsual;
5421 VIsual = t;
5422 }
5423 if (VIsual_mode == 'V')
5424 VIsual.col = 0;
5425
5426 ptr = ml_get(VIsual.lnum);
5427 RLADDSUBFIX(ptr);
5428
5429 /* store visual area for 'gv' */
5430 curbuf->b_visual.vi_start = VIsual;
5431 curbuf->b_visual.vi_end = curwin->w_cursor;
5432 curbuf->b_visual.vi_mode = VIsual_mode;
5433
5434 col = VIsual.col;
5435 lnum = VIsual.lnum;
5436 lnume = curwin->w_cursor.lnum;
5437 if (ptr[col] == '-')
5438 {
5439 negative = TRUE;
5440 col++;
5441 }
5442 }
5443 else
5444 {
5445 ptr = ml_get_curline();
5446 RLADDSUBFIX(ptr);
5447
5448 if (dohex)
5449 while (col > 0 && vim_isxdigit(ptr[col]))
5450 --col;
5451 if ( dohex
5452 && col > 0
5453 && (ptr[col] == 'X'
5454 || ptr[col] == 'x')
5455 && ptr[col - 1] == '0'
5456 && vim_isxdigit(ptr[col + 1]))
5457 {
5458 /* Found hexadecimal number, move to its start. */
5413 --col; 5459 --col;
5414 if ( dohex 5460 }
5415 && col > 0 5461 else
5416 && (ptr[col] == 'X' 5462 {
5417 || ptr[col] == 'x') 5463 /*
5418 && ptr[col - 1] == '0' 5464 * Search forward and then backward to find the start of number.
5419 && vim_isxdigit(ptr[col + 1])) 5465 */
5420 { 5466 col = curwin->w_cursor.col;
5467
5468 while (ptr[col] != NUL
5469 && !vim_isdigit(ptr[col])
5470 && !(doalp && ASCII_ISALPHA(ptr[col])))
5471 ++col;
5472
5473 while (col > 0
5474 && vim_isdigit(ptr[col - 1])
5475 && !(doalp && ASCII_ISALPHA(ptr[col])))
5476 --col;
5477 }
5478 }
5479
5480 for (i = lnum; i <= lnume; i++)
5481 {
5482 curwin->w_cursor.lnum = i;
5483 ptr = ml_get_curline();
5484 RLADDSUBFIX(ptr);
5485 if ((int)STRLEN(ptr) <= col)
5486 col = 0;
5421 /* 5487 /*
5422 * Found hexadecimal number, move to its start. 5488 * If a number was found, and saving for undo works, replace the number.
5423 */ 5489 */
5424 --col; 5490 firstdigit = ptr[col];
5425 } 5491 RLADDSUBFIX(ptr);
5426 else 5492 if ((!VIM_ISDIGIT(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit)))
5427 { 5493 || u_save_cursor() != OK)
5428 /* 5494 {
5429 * Search forward and then backward to find the start of number. 5495 if (lnum < lnume)
5430 */ 5496 /* Try again on next line */
5431 col = curwin->w_cursor.col; 5497 continue;
5432 5498 beep_flush();
5433 while (ptr[col] != NUL 5499 return FAIL;
5434 && !vim_isdigit(ptr[col]) 5500 }
5435 && !(doalp && ASCII_ISALPHA(ptr[col]))) 5501
5436 ++col; 5502 ptr = ml_get_curline();
5437 5503 RLADDSUBFIX(ptr);
5438 while (col > 0 5504
5439 && vim_isdigit(ptr[col - 1]) 5505 if (doalp && ASCII_ISALPHA(firstdigit))
5440 && !(doalp && ASCII_ISALPHA(ptr[col]))) 5506 {
5441 --col; 5507 /* decrement or increment alphabetic character */
5442 } 5508 if (command == Ctrl_X)
5443 5509 {
5444 /* 5510 if (CharOrd(firstdigit) < Prenum1)
5445 * If a number was found, and saving for undo works, replace the number. 5511 {
5446 */ 5512 if (isupper(firstdigit))
5447 firstdigit = ptr[col]; 5513 firstdigit = 'A';
5448 RLADDSUBFIX(ptr); 5514 else
5449 if ((!VIM_ISDIGIT(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit))) 5515 firstdigit = 'a';
5450 || u_save_cursor() != OK) 5516 }
5451 {
5452 beep_flush();
5453 return FAIL;
5454 }
5455
5456 /* get ptr again, because u_save() may have changed it */
5457 ptr = ml_get_curline();
5458 RLADDSUBFIX(ptr);
5459
5460 if (doalp && ASCII_ISALPHA(firstdigit))
5461 {
5462 /* decrement or increment alphabetic character */
5463 if (command == Ctrl_X)
5464 {
5465 if (CharOrd(firstdigit) < Prenum1)
5466 {
5467 if (isupper(firstdigit))
5468 firstdigit = 'A';
5469 else 5517 else
5470 firstdigit = 'a'; 5518 #ifdef EBCDIC
5519 firstdigit = EBCDIC_CHAR_ADD(firstdigit, -Prenum1);
5520 #else
5521 firstdigit -= Prenum1;
5522 #endif
5471 } 5523 }
5472 else 5524 else
5525 {
5526 if (26 - CharOrd(firstdigit) - 1 < Prenum1)
5527 {
5528 if (isupper(firstdigit))
5529 firstdigit = 'Z';
5530 else
5531 firstdigit = 'z';
5532 }
5533 else
5473 #ifdef EBCDIC 5534 #ifdef EBCDIC
5474 firstdigit = EBCDIC_CHAR_ADD(firstdigit, -Prenum1); 5535 firstdigit = EBCDIC_CHAR_ADD(firstdigit, Prenum1);
5475 #else 5536 #else
5476 firstdigit -= Prenum1; 5537 firstdigit += Prenum1;
5477 #endif 5538 #endif
5539 }
5540 curwin->w_cursor.col = col;
5541 (void)del_char(FALSE);
5542 ins_char(firstdigit);
5478 } 5543 }
5479 else 5544 else
5480 { 5545 {
5481 if (26 - CharOrd(firstdigit) - 1 < Prenum1) 5546 if (col > 0 && ptr[col - 1] == '-' && !visual)
5482 { 5547 {
5483 if (isupper(firstdigit)) 5548 /* negative number */
5484 firstdigit = 'Z'; 5549 --col;
5550 negative = TRUE;
5551 }
5552
5553 /* get the number value (unsigned) */
5554 vim_str2nr(ptr + col, &hex, &length, dooct, dohex, NULL, &n);
5555
5556 /* ignore leading '-' for hex and octal numbers */
5557 if (hex && negative)
5558 {
5559 ++col;
5560 --length;
5561 negative = FALSE;
5562 }
5563
5564 /* add or subtract */
5565 subtract = FALSE;
5566 if (command == Ctrl_X)
5567 subtract ^= TRUE;
5568 if (negative)
5569 subtract ^= TRUE;
5570
5571 oldn = n;
5572 if (subtract)
5573 n -= (unsigned long)Prenum1;
5574 else
5575 n += (unsigned long)Prenum1;
5576
5577 /* handle wraparound for decimal numbers */
5578 if (!hex)
5579 {
5580 if (subtract)
5581 {
5582 if (n > oldn)
5583 {
5584 n = 1 + (n ^ (unsigned long)-1);
5585 negative ^= TRUE;
5586 }
5587 }
5485 else 5588 else
5486 firstdigit = 'z'; 5589 {
5487 } 5590 /* add */
5591 if (n < oldn)
5592 {
5593 n = (n ^ (unsigned long)-1);
5594 negative ^= TRUE;
5595 }
5596 }
5597 if (n == 0)
5598 negative = FALSE;
5599 }
5600
5601 /*
5602 * Delete the old number.
5603 */
5604 curwin->w_cursor.col = col;
5605 todel = length;
5606 c = gchar_cursor();
5607
5608 /*
5609 * Don't include the '-' in the length, only the length of the
5610 * part after it is kept the same.
5611 */
5612 if (c == '-')
5613 --length;
5614 while (todel-- > 0)
5615 {
5616 if (c < 0x100 && isalpha(c))
5617 {
5618 if (isupper(c))
5619 hexupper = TRUE;
5620 else
5621 hexupper = FALSE;
5622 }
5623 /* del_char() will mark line needing displaying */
5624 (void)del_char(FALSE);
5625 c = gchar_cursor();
5626 }
5627
5628 /*
5629 * Prepare the leading characters in buf1[].
5630 * When there are many leading zeros it could be very long.
5631 * Allocate a bit too much.
5632 */
5633 buf1 = alloc((unsigned)length + NUMBUFLEN);
5634 if (buf1 == NULL)
5635 return FAIL;
5636 ptr = buf1;
5637 /* do not add leading '-' for visual mode */
5638 if (negative && !visual)
5639 {
5640 *ptr++ = '-';
5641 }
5642 if (hex)
5643 {
5644 *ptr++ = '0';
5645 --length;
5646 }
5647 if (hex == 'x' || hex == 'X')
5648 {
5649 *ptr++ = hex;
5650 --length;
5651 }
5652
5653 /*
5654 * Put the number characters in buf2[].
5655 */
5656 if (hex == 0)
5657 sprintf((char *)buf2, "%lu", n + offset);
5658 else if (hex == '0')
5659 sprintf((char *)buf2, "%lo", n + offset);
5660 else if (hex && hexupper)
5661 sprintf((char *)buf2, "%lX", n + offset);
5488 else 5662 else
5489 #ifdef EBCDIC 5663 sprintf((char *)buf2, "%lx", n + offset);
5490 firstdigit = EBCDIC_CHAR_ADD(firstdigit, Prenum1); 5664 length -= (int)STRLEN(buf2);
5491 #else 5665
5492 firstdigit += Prenum1; 5666 if (g_cmd)
5493 #endif 5667 {
5494 } 5668 if (subtract)
5495 curwin->w_cursor.col = col; 5669 offset -= (unsigned long)Prenum1;
5496 (void)del_char(FALSE);
5497 ins_char(firstdigit);
5498 }
5499 else
5500 {
5501 negative = FALSE;
5502 if (col > 0 && ptr[col - 1] == '-') /* negative number */
5503 {
5504 --col;
5505 negative = TRUE;
5506 }
5507
5508 /* get the number value (unsigned) */
5509 vim_str2nr(ptr + col, &hex, &length, dooct, dohex, NULL, &n);
5510
5511 /* ignore leading '-' for hex and octal numbers */
5512 if (hex && negative)
5513 {
5514 ++col;
5515 --length;
5516 negative = FALSE;
5517 }
5518
5519 /* add or subtract */
5520 subtract = FALSE;
5521 if (command == Ctrl_X)
5522 subtract ^= TRUE;
5523 if (negative)
5524 subtract ^= TRUE;
5525
5526 oldn = n;
5527 if (subtract)
5528 n -= (unsigned long)Prenum1;
5529 else
5530 n += (unsigned long)Prenum1;
5531
5532 /* handle wraparound for decimal numbers */
5533 if (!hex)
5534 {
5535 if (subtract)
5536 {
5537 if (n > oldn)
5538 {
5539 n = 1 + (n ^ (unsigned long)-1);
5540 negative ^= TRUE;
5541 }
5542 }
5543 else /* add */
5544 {
5545 if (n < oldn)
5546 {
5547 n = (n ^ (unsigned long)-1);
5548 negative ^= TRUE;
5549 }
5550 }
5551 if (n == 0)
5552 negative = FALSE;
5553 }
5554
5555 /*
5556 * Delete the old number.
5557 */
5558 curwin->w_cursor.col = col;
5559 todel = length;
5560 c = gchar_cursor();
5561 /*
5562 * Don't include the '-' in the length, only the length of the part
5563 * after it is kept the same.
5564 */
5565 if (c == '-')
5566 --length;
5567 while (todel-- > 0)
5568 {
5569 if (c < 0x100 && isalpha(c))
5570 {
5571 if (isupper(c))
5572 hexupper = TRUE;
5573 else 5670 else
5574 hexupper = FALSE; 5671 offset += (unsigned long)Prenum1;
5575 } 5672 }
5576 /* del_char() will mark line needing displaying */ 5673
5577 (void)del_char(FALSE); 5674 /*
5578 c = gchar_cursor(); 5675 * Adjust number of zeros to the new number of digits, so the
5579 } 5676 * total length of the number remains the same.
5580 5677 * Don't do this when
5581 /* 5678 * the result may look like an octal number.
5582 * Prepare the leading characters in buf1[]. 5679 */
5583 * When there are many leading zeros it could be very long. Allocate 5680 if (firstdigit == '0' && !(dooct && hex == 0))
5584 * a bit too much. 5681 while (length-- > 0)
5585 */ 5682 *ptr++ = '0';
5586 buf1 = alloc((unsigned)length + NUMBUFLEN); 5683 *ptr = NUL;
5587 if (buf1 == NULL) 5684 STRCAT(buf1, buf2);
5588 return FAIL; 5685 ins_str(buf1); /* insert the new number */
5589 ptr = buf1; 5686 vim_free(buf1);
5590 if (negative) 5687 }
5591 { 5688 --curwin->w_cursor.col;
5592 *ptr++ = '-'; 5689 curwin->w_set_curswant = TRUE;
5593 }
5594 if (hex)
5595 {
5596 *ptr++ = '0';
5597 --length;
5598 }
5599 if (hex == 'x' || hex == 'X')
5600 {
5601 *ptr++ = hex;
5602 --length;
5603 }
5604
5605 /*
5606 * Put the number characters in buf2[].
5607 */
5608 if (hex == 0)
5609 sprintf((char *)buf2, "%lu", n);
5610 else if (hex == '0')
5611 sprintf((char *)buf2, "%lo", n);
5612 else if (hex && hexupper)
5613 sprintf((char *)buf2, "%lX", n);
5614 else
5615 sprintf((char *)buf2, "%lx", n);
5616 length -= (int)STRLEN(buf2);
5617
5618 /*
5619 * Adjust number of zeros to the new number of digits, so the
5620 * total length of the number remains the same.
5621 * Don't do this when
5622 * the result may look like an octal number.
5623 */
5624 if (firstdigit == '0' && !(dooct && hex == 0))
5625 while (length-- > 0)
5626 *ptr++ = '0';
5627 *ptr = NUL;
5628 STRCAT(buf1, buf2);
5629 ins_str(buf1); /* insert the new number */
5630 vim_free(buf1);
5631 }
5632 --curwin->w_cursor.col;
5633 curwin->w_set_curswant = TRUE;
5634 #ifdef FEAT_RIGHTLEFT 5690 #ifdef FEAT_RIGHTLEFT
5635 ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE); 5691 ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE);
5636 RLADDSUBFIX(ptr); 5692 RLADDSUBFIX(ptr);
5637 #endif 5693 #endif
5694 }
5638 return OK; 5695 return OK;
5639 } 5696 }
5640 5697
5641 #ifdef FEAT_VIMINFO 5698 #ifdef FEAT_VIMINFO
5642 int 5699 int