diff options
| author | Stefan Monnier | 2008-03-26 18:10:51 +0000 |
|---|---|---|
| committer | Stefan Monnier | 2008-03-26 18:10:51 +0000 |
| commit | ef6f5c0eef1d798d5be1c6fe1ac4d55fc8e3886e (patch) | |
| tree | f5882c03cb46ab5af04ec510ecacef1c58acfeaa /src | |
| parent | 8c01c0d4ebbe1b4baa88dabe0995538feb1d9b80 (diff) | |
| download | emacs-ef6f5c0eef1d798d5be1c6fe1ac4d55fc8e3886e.tar.gz emacs-ef6f5c0eef1d798d5be1c6fe1ac4d55fc8e3886e.zip | |
(scan_for_column): Extract from current_column_1.
Merge with the same code from Fmove_to_column.
(current_column_1, Fmove_to_column): Use it.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 6 | ||||
| -rw-r--r-- | src/indent.c | 273 |
2 files changed, 93 insertions, 186 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 0e571c82623..3dd9051e454 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,9 @@ | |||
| 1 | 2008-03-26 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * indent.c (scan_for_column): Extract from current_column_1. | ||
| 4 | Merge with the same code from Fmove_to_column. | ||
| 5 | (current_column_1, Fmove_to_column): Use it. | ||
| 6 | |||
| 1 | 2008-03-25 Stefan Monnier <monnier@iro.umontreal.ca> | 7 | 2008-03-25 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 8 | ||
| 3 | * keymap.c (map_keymap_internal): New fun. | 9 | * keymap.c (map_keymap_internal): New fun. |
diff --git a/src/indent.c b/src/indent.c index b4443825c5d..b4a47782e3e 100644 --- a/src/indent.c +++ b/src/indent.c | |||
| @@ -504,13 +504,14 @@ current_column () | |||
| 504 | return col; | 504 | return col; |
| 505 | } | 505 | } |
| 506 | 506 | ||
| 507 | /* Return the column number of position POS | 507 | /* Scanning from the beginning of the current line, stop at the buffer |
| 508 | by scanning forward from the beginning of the line. | 508 | position ENDPOS or at the column GOALCOL or at the end of line, whichever |
| 509 | This function handles characters that are invisible | 509 | comes first. |
| 510 | due to text properties or overlays. */ | 510 | Return the resulting buffer position and column in ENDPOS and GOALCOL. |
| 511 | 511 | PREVCOL gets set to the column of the previous position (it's always | |
| 512 | static double | 512 | strictly smaller than the goal column). */ |
| 513 | current_column_1 () | 513 | static void |
| 514 | scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol) | ||
| 514 | { | 515 | { |
| 515 | register EMACS_INT tab_width = XINT (current_buffer->tab_width); | 516 | register EMACS_INT tab_width = XINT (current_buffer->tab_width); |
| 516 | register int ctl_arrow = !NILP (current_buffer->ctl_arrow); | 517 | register int ctl_arrow = !NILP (current_buffer->ctl_arrow); |
| @@ -518,47 +519,57 @@ current_column_1 () | |||
| 518 | int multibyte = !NILP (current_buffer->enable_multibyte_characters); | 519 | int multibyte = !NILP (current_buffer->enable_multibyte_characters); |
| 519 | 520 | ||
| 520 | /* Start the scan at the beginning of this line with column number 0. */ | 521 | /* Start the scan at the beginning of this line with column number 0. */ |
| 521 | register EMACS_INT col = 0; | 522 | register EMACS_INT col = 0, prev_col = 0; |
| 523 | EMACS_INT goal = goalcol ? *goalcol : MOST_POSITIVE_FIXNUM; | ||
| 524 | EMACS_INT end = endpos ? *endpos : PT; | ||
| 522 | EMACS_INT scan, scan_byte; | 525 | EMACS_INT scan, scan_byte; |
| 523 | EMACS_INT next_boundary; | 526 | EMACS_INT next_boundary; |
| 527 | { | ||
| 524 | EMACS_INT opoint = PT, opoint_byte = PT_BYTE; | 528 | EMACS_INT opoint = PT, opoint_byte = PT_BYTE; |
| 525 | |||
| 526 | scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, 1); | 529 | scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, 1); |
| 527 | current_column_bol_cache = PT; | 530 | current_column_bol_cache = PT; |
| 528 | scan = PT, scan_byte = PT_BYTE; | 531 | scan = PT, scan_byte = PT_BYTE; |
| 529 | SET_PT_BOTH (opoint, opoint_byte); | 532 | SET_PT_BOTH (opoint, opoint_byte); |
| 530 | next_boundary = scan; | 533 | next_boundary = scan; |
| 534 | } | ||
| 531 | 535 | ||
| 532 | if (tab_width <= 0 || tab_width > 1000) tab_width = 8; | 536 | if (tab_width <= 0 || tab_width > 1000) tab_width = 8; |
| 533 | 537 | ||
| 534 | /* Scan forward to the target position. */ | 538 | /* Scan forward to the target position. */ |
| 535 | while (scan < opoint) | 539 | while (scan < end) |
| 536 | { | 540 | { |
| 537 | int c; | 541 | int c; |
| 538 | 542 | ||
| 539 | /* Occasionally we may need to skip invisible text. */ | 543 | /* Occasionally we may need to skip invisible text. */ |
| 540 | while (scan == next_boundary) | 544 | while (scan == next_boundary) |
| 541 | { | 545 | { |
| 542 | int old_scan = scan; | 546 | EMACS_INT old_scan = scan; |
| 543 | /* This updates NEXT_BOUNDARY to the next place | 547 | /* This updates NEXT_BOUNDARY to the next place |
| 544 | where we might need to skip more invisible text. */ | 548 | where we might need to skip more invisible text. */ |
| 545 | scan = skip_invisible (scan, &next_boundary, opoint, Qnil); | 549 | scan = skip_invisible (scan, &next_boundary, end, Qnil); |
| 546 | if (scan >= opoint) | ||
| 547 | goto endloop; | ||
| 548 | if (scan != old_scan) | 550 | if (scan != old_scan) |
| 549 | scan_byte = CHAR_TO_BYTE (scan); | 551 | scan_byte = CHAR_TO_BYTE (scan); |
| 552 | if (scan >= end) | ||
| 553 | goto endloop; | ||
| 550 | } | 554 | } |
| 551 | 555 | ||
| 556 | /* Test reaching the goal column. We do this after skipping | ||
| 557 | invisible characters, so that we put point before the | ||
| 558 | character on which the cursor will appear. */ | ||
| 559 | if (col >= goal) | ||
| 560 | break; | ||
| 561 | prev_col = col; | ||
| 562 | |||
| 552 | /* Check composition sequence. */ | 563 | /* Check composition sequence. */ |
| 553 | { | 564 | { |
| 554 | int len, len_byte, width; | 565 | int len, len_byte, width; |
| 555 | 566 | ||
| 556 | if (check_composition (scan, scan_byte, opoint, | 567 | if (check_composition (scan, scan_byte, end, |
| 557 | &len, &len_byte, &width)) | 568 | &len, &len_byte, &width)) |
| 558 | { | 569 | { |
| 559 | scan += len; | 570 | scan += len; |
| 560 | scan_byte += len_byte; | 571 | scan_byte += len_byte; |
| 561 | if (scan <= opoint) | 572 | if (scan <= end) |
| 562 | col += width; | 573 | col += width; |
| 563 | continue; | 574 | continue; |
| 564 | } | 575 | } |
| @@ -566,6 +577,9 @@ current_column_1 () | |||
| 566 | 577 | ||
| 567 | c = FETCH_BYTE (scan_byte); | 578 | c = FETCH_BYTE (scan_byte); |
| 568 | 579 | ||
| 580 | /* See if there is a display table and it relates | ||
| 581 | to this character. */ | ||
| 582 | |||
| 569 | if (dp != 0 | 583 | if (dp != 0 |
| 570 | && ! (multibyte && BASE_LEADING_CODE_P (c)) | 584 | && ! (multibyte && BASE_LEADING_CODE_P (c)) |
| 571 | && VECTORP (DISP_CHAR_VECTOR (dp, c))) | 585 | && VECTORP (DISP_CHAR_VECTOR (dp, c))) |
| @@ -574,7 +588,7 @@ current_column_1 () | |||
| 574 | EMACS_INT i, n; | 588 | EMACS_INT i, n; |
| 575 | 589 | ||
| 576 | /* This character is displayed using a vector of glyphs. | 590 | /* This character is displayed using a vector of glyphs. |
| 577 | Update the column based on those glyphs. */ | 591 | Update the column/position based on those glyphs. */ |
| 578 | 592 | ||
| 579 | charvec = DISP_CHAR_VECTOR (dp, c); | 593 | charvec = DISP_CHAR_VECTOR (dp, c); |
| 580 | n = ASIZE (charvec); | 594 | n = ASIZE (charvec); |
| @@ -606,8 +620,8 @@ current_column_1 () | |||
| 606 | } | 620 | } |
| 607 | else | 621 | else |
| 608 | { | 622 | { |
| 609 | /* The display table says nothing for this character. | 623 | /* The display table doesn't affect this character; |
| 610 | Display it as itself. */ | 624 | it displays as itself. */ |
| 611 | 625 | ||
| 612 | if (c == '\n') | 626 | if (c == '\n') |
| 613 | goto endloop; | 627 | goto endloop; |
| @@ -620,15 +634,15 @@ current_column_1 () | |||
| 620 | } | 634 | } |
| 621 | else if (multibyte && BASE_LEADING_CODE_P (c)) | 635 | else if (multibyte && BASE_LEADING_CODE_P (c)) |
| 622 | { | 636 | { |
| 637 | /* Start of multi-byte form. */ | ||
| 623 | unsigned char *ptr; | 638 | unsigned char *ptr; |
| 624 | int bytes, width, wide_column; | 639 | int bytes, width, wide_column; |
| 625 | 640 | ||
| 626 | ptr = BYTE_POS_ADDR (scan_byte); | 641 | ptr = BYTE_POS_ADDR (scan_byte); |
| 627 | MULTIBYTE_BYTES_WIDTH (ptr, dp); | 642 | MULTIBYTE_BYTES_WIDTH (ptr, dp); |
| 628 | scan_byte += bytes; | ||
| 629 | /* Subtract one to compensate for the increment | 643 | /* Subtract one to compensate for the increment |
| 630 | that is going to happen below. */ | 644 | that is going to happen below. */ |
| 631 | scan_byte--; | 645 | scan_byte += bytes - 1; |
| 632 | col += width; | 646 | col += width; |
| 633 | } | 647 | } |
| 634 | else if (ctl_arrow && (c < 040 || c == 0177)) | 648 | else if (ctl_arrow && (c < 040 || c == 0177)) |
| @@ -648,6 +662,26 @@ current_column_1 () | |||
| 648 | last_known_column_point = PT; | 662 | last_known_column_point = PT; |
| 649 | last_known_column_modified = MODIFF; | 663 | last_known_column_modified = MODIFF; |
| 650 | 664 | ||
| 665 | if (goalcol) | ||
| 666 | *goalcol = col; | ||
| 667 | if (endpos) | ||
| 668 | *endpos = scan; | ||
| 669 | if (prevcol) | ||
| 670 | *prevcol = prev_col; | ||
| 671 | } | ||
| 672 | |||
| 673 | /* Return the column number of position POS | ||
| 674 | by scanning forward from the beginning of the line. | ||
| 675 | This function handles characters that are invisible | ||
| 676 | due to text properties or overlays. */ | ||
| 677 | |||
| 678 | static double | ||
| 679 | current_column_1 () | ||
| 680 | { | ||
| 681 | EMACS_INT col = MOST_POSITIVE_FIXNUM; | ||
| 682 | EMACS_INT opoint = PT; | ||
| 683 | |||
| 684 | scan_for_column (&opoint, &col, NULL); | ||
| 651 | return col; | 685 | return col; |
| 652 | } | 686 | } |
| 653 | 687 | ||
| @@ -933,179 +967,47 @@ The return value is the current column. */) | |||
| 933 | (column, force) | 967 | (column, force) |
| 934 | Lisp_Object column, force; | 968 | Lisp_Object column, force; |
| 935 | { | 969 | { |
| 936 | register EMACS_INT pos; | 970 | EMACS_INT pos; |
| 937 | register EMACS_INT col = current_column (); | 971 | EMACS_INT col, prev_col; |
| 938 | register EMACS_INT goal; | 972 | EMACS_INT goal; |
| 939 | register EMACS_INT end; | ||
| 940 | register int tab_width = XINT (current_buffer->tab_width); | ||
| 941 | register int ctl_arrow = !NILP (current_buffer->ctl_arrow); | ||
| 942 | register struct Lisp_Char_Table *dp = buffer_display_table (); | ||
| 943 | register int multibyte = !NILP (current_buffer->enable_multibyte_characters); | ||
| 944 | 973 | ||
| 945 | Lisp_Object val; | ||
| 946 | EMACS_INT prev_col = 0; | ||
| 947 | int c = 0; | ||
| 948 | EMACS_INT next_boundary, pos_byte; | ||
| 949 | |||
| 950 | if (tab_width <= 0 || tab_width > 1000) tab_width = 8; | ||
| 951 | CHECK_NATNUM (column); | 974 | CHECK_NATNUM (column); |
| 952 | goal = XINT (column); | 975 | goal = XINT (column); |
| 953 | 976 | ||
| 954 | pos = PT; | 977 | col = goal; |
| 955 | pos_byte = PT_BYTE; | 978 | pos = ZV; |
| 956 | end = ZV; | 979 | scan_for_column (&pos, &col, &prev_col); |
| 957 | 980 | ||
| 958 | /* If we're starting past the desired column, | 981 | SET_PT (pos); |
| 959 | back up to beginning of line and scan from there. */ | ||
| 960 | if (col > goal) | ||
| 961 | { | ||
| 962 | end = pos; | ||
| 963 | pos = current_column_bol_cache; | ||
| 964 | pos_byte = CHAR_TO_BYTE (pos); | ||
| 965 | col = 0; | ||
| 966 | } | ||
| 967 | 982 | ||
| 968 | next_boundary = pos; | 983 | /* If a tab char made us overshoot, change it to spaces |
| 969 | 984 | and scan through it again. */ | |
| 970 | while (pos < end) | 985 | if (!NILP (force) && col > goal) |
| 971 | { | 986 | { |
| 972 | while (pos == next_boundary) | 987 | EMACS_INT pos_byte = PT_BYTE; |
| 973 | { | 988 | DEC_POS (pos_byte); |
| 974 | EMACS_INT prev = pos; | 989 | int c = FETCH_CHAR (pos_byte); |
| 975 | pos = skip_invisible (pos, &next_boundary, end, Qnil); | ||
| 976 | if (pos != prev) | ||
| 977 | pos_byte = CHAR_TO_BYTE (pos); | ||
| 978 | if (pos >= end) | ||
| 979 | goto endloop; | ||
| 980 | } | ||
| 981 | |||
| 982 | /* Test reaching the goal column. We do this after skipping | ||
| 983 | invisible characters, so that we put point before the | ||
| 984 | character on which the cursor will appear. */ | ||
| 985 | if (col >= goal) | ||
| 986 | break; | ||
| 987 | |||
| 988 | /* Check composition sequence. */ | ||
| 989 | { | ||
| 990 | int len, len_byte, width; | ||
| 991 | |||
| 992 | if (check_composition (pos, pos_byte, Z, &len, &len_byte, &width)) | ||
| 993 | { | ||
| 994 | pos += len; | ||
| 995 | pos_byte += len_byte; | ||
| 996 | col += width; | ||
| 997 | continue; | ||
| 998 | } | ||
| 999 | } | ||
| 1000 | |||
| 1001 | c = FETCH_BYTE (pos_byte); | ||
| 1002 | |||
| 1003 | /* See if there is a display table and it relates | ||
| 1004 | to this character. */ | ||
| 1005 | |||
| 1006 | if (dp != 0 | ||
| 1007 | && ! (multibyte && BASE_LEADING_CODE_P (c)) | ||
| 1008 | && VECTORP (DISP_CHAR_VECTOR (dp, c))) | ||
| 1009 | { | ||
| 1010 | Lisp_Object charvec; | ||
| 1011 | EMACS_INT i, n; | ||
| 1012 | |||
| 1013 | /* This character is displayed using a vector of glyphs. | ||
| 1014 | Update the position based on those glyphs. */ | ||
| 1015 | |||
| 1016 | charvec = DISP_CHAR_VECTOR (dp, c); | ||
| 1017 | n = ASIZE (charvec); | ||
| 1018 | |||
| 1019 | for (i = 0; i < n; i++) | ||
| 1020 | { | ||
| 1021 | /* This should be handled the same as | ||
| 1022 | next_element_from_display_vector does it. */ | ||
| 1023 | Lisp_Object entry = AREF (charvec, i); | ||
| 1024 | |||
| 1025 | if (GLYPH_CODE_P (entry) | ||
| 1026 | && GLYPH_CODE_CHAR_VALID_P (entry)) | ||
| 1027 | c = GLYPH_CODE_CHAR (entry); | ||
| 1028 | else | ||
| 1029 | c = ' '; | ||
| 1030 | 990 | ||
| 1031 | if (c == '\n') | 991 | if (c == '\t' && prev_col < goal) |
| 1032 | goto endloop; | ||
| 1033 | if (c == '\r' && EQ (current_buffer->selective_display, Qt)) | ||
| 1034 | goto endloop; | ||
| 1035 | if (c == '\t') | ||
| 1036 | { | ||
| 1037 | prev_col = col; | ||
| 1038 | col += tab_width; | ||
| 1039 | col = col / tab_width * tab_width; | ||
| 1040 | } | ||
| 1041 | else | ||
| 1042 | ++col; | ||
| 1043 | } | ||
| 1044 | } | ||
| 1045 | else | ||
| 1046 | { | 992 | { |
| 1047 | /* The display table doesn't affect this character; | 993 | EMACS_INT goal_pt, goal_pt_byte; |
| 1048 | it displays as itself. */ | 994 | |
| 1049 | 995 | /* Insert spaces in front of the tab to reach GOAL. Do this | |
| 1050 | if (c == '\n') | 996 | first so that a marker at the end of the tab gets |
| 1051 | goto endloop; | 997 | adjusted. */ |
| 1052 | if (c == '\r' && EQ (current_buffer->selective_display, Qt)) | 998 | SET_PT_BOTH (PT - 1, PT_BYTE - 1); |
| 1053 | goto endloop; | 999 | Finsert_char (make_number (' '), make_number (goal - prev_col), Qt); |
| 1054 | if (c == '\t') | 1000 | |
| 1055 | { | 1001 | /* Now delete the tab, and indent to COL. */ |
| 1056 | prev_col = col; | 1002 | del_range (PT, PT + 1); |
| 1057 | col += tab_width; | 1003 | goal_pt = PT; |
| 1058 | col = col / tab_width * tab_width; | 1004 | goal_pt_byte = PT_BYTE; |
| 1059 | } | 1005 | Findent_to (make_number (col), Qnil); |
| 1060 | else if (ctl_arrow && (c < 040 || c == 0177)) | 1006 | SET_PT_BOTH (goal_pt, goal_pt_byte); |
| 1061 | col += 2; | 1007 | |
| 1062 | else if (c < 040 || c == 0177) | 1008 | /* Set the last_known... vars consistently. */ |
| 1063 | col += 4; | 1009 | col = goal; |
| 1064 | else if (c < 0177) | ||
| 1065 | col++; | ||
| 1066 | else if (multibyte && BASE_LEADING_CODE_P (c)) | ||
| 1067 | { | ||
| 1068 | /* Start of multi-byte form. */ | ||
| 1069 | unsigned char *ptr; | ||
| 1070 | int bytes, width, wide_column; | ||
| 1071 | |||
| 1072 | ptr = BYTE_POS_ADDR (pos_byte); | ||
| 1073 | MULTIBYTE_BYTES_WIDTH (ptr, dp); | ||
| 1074 | pos_byte += bytes - 1; | ||
| 1075 | col += width; | ||
| 1076 | } | ||
| 1077 | else | ||
| 1078 | col += 4; | ||
| 1079 | } | 1010 | } |
| 1080 | |||
| 1081 | pos++; | ||
| 1082 | pos_byte++; | ||
| 1083 | } | ||
| 1084 | endloop: | ||
| 1085 | |||
| 1086 | SET_PT_BOTH (pos, pos_byte); | ||
| 1087 | |||
| 1088 | /* If a tab char made us overshoot, change it to spaces | ||
| 1089 | and scan through it again. */ | ||
| 1090 | if (!NILP (force) && col > goal && c == '\t' && prev_col < goal) | ||
| 1091 | { | ||
| 1092 | EMACS_INT goal_pt, goal_pt_byte; | ||
| 1093 | |||
| 1094 | /* Insert spaces in front of the tab to reach GOAL. Do this | ||
| 1095 | first so that a marker at the end of the tab gets | ||
| 1096 | adjusted. */ | ||
| 1097 | SET_PT_BOTH (PT - 1, PT_BYTE - 1); | ||
| 1098 | Finsert_char (make_number (' '), make_number (goal - prev_col), Qt); | ||
| 1099 | |||
| 1100 | /* Now delete the tab, and indent to COL. */ | ||
| 1101 | del_range (PT, PT + 1); | ||
| 1102 | goal_pt = PT; | ||
| 1103 | goal_pt_byte = PT_BYTE; | ||
| 1104 | Findent_to (make_number (col), Qnil); | ||
| 1105 | SET_PT_BOTH (goal_pt, goal_pt_byte); | ||
| 1106 | |||
| 1107 | /* Set the last_known... vars consistently. */ | ||
| 1108 | col = goal; | ||
| 1109 | } | 1011 | } |
| 1110 | 1012 | ||
| 1111 | /* If line ends prematurely, add space to the end. */ | 1013 | /* If line ends prematurely, add space to the end. */ |
| @@ -1116,8 +1018,7 @@ The return value is the current column. */) | |||
| 1116 | last_known_column_point = PT; | 1018 | last_known_column_point = PT; |
| 1117 | last_known_column_modified = MODIFF; | 1019 | last_known_column_modified = MODIFF; |
| 1118 | 1020 | ||
| 1119 | XSETFASTINT (val, col); | 1021 | return make_number (col); |
| 1120 | return val; | ||
| 1121 | } | 1022 | } |
| 1122 | 1023 | ||
| 1123 | /* compute_motion: compute buffer posn given screen posn and vice versa */ | 1024 | /* compute_motion: compute buffer posn given screen posn and vice versa */ |