Mercurial > vim
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 |