diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/indent.c | 350 |
1 files changed, 310 insertions, 40 deletions
diff --git a/src/indent.c b/src/indent.c index 9cdfb3cf046..ea0de2a10d6 100644 --- a/src/indent.c +++ b/src/indent.c | |||
| @@ -22,6 +22,7 @@ Boston, MA 02111-1307, USA. */ | |||
| 22 | #include <config.h> | 22 | #include <config.h> |
| 23 | #include "lisp.h" | 23 | #include "lisp.h" |
| 24 | #include "buffer.h" | 24 | #include "buffer.h" |
| 25 | #include "charset.h" | ||
| 25 | #include "indent.h" | 26 | #include "indent.h" |
| 26 | #include "frame.h" | 27 | #include "frame.h" |
| 27 | #include "window.h" | 28 | #include "window.h" |
| @@ -52,6 +53,10 @@ int last_known_column_modified; | |||
| 52 | 53 | ||
| 53 | static int current_column_1 (); | 54 | static int current_column_1 (); |
| 54 | 55 | ||
| 56 | /* Cache of beginning of line found by the last call of | ||
| 57 | current_column. */ | ||
| 58 | int current_column_bol_cache; | ||
| 59 | |||
| 55 | /* Get the display table to use for the current buffer. */ | 60 | /* Get the display table to use for the current buffer. */ |
| 56 | 61 | ||
| 57 | struct Lisp_Char_Table * | 62 | struct Lisp_Char_Table * |
| @@ -148,7 +153,10 @@ recompute_width_table (buf, disptab) | |||
| 148 | static void | 153 | static void |
| 149 | width_run_cache_on_off () | 154 | width_run_cache_on_off () |
| 150 | { | 155 | { |
| 151 | if (NILP (current_buffer->cache_long_line_scans)) | 156 | if (NILP (current_buffer->cache_long_line_scans) |
| 157 | /* And, for the moment, this feature doesn't work on multibyte | ||
| 158 | characters. */ | ||
| 159 | || !NILP (current_buffer->enable_multibyte_characters)) | ||
| 152 | { | 160 | { |
| 153 | /* It should be off. */ | 161 | /* It should be off. */ |
| 154 | if (current_buffer->width_run_cache) | 162 | if (current_buffer->width_run_cache) |
| @@ -233,6 +241,13 @@ skip_invisible (pos, next_boundary_p, to, window) | |||
| 233 | proplimit = overlay_limit; | 241 | proplimit = overlay_limit; |
| 234 | end = Fnext_single_property_change (position, Qinvisible, | 242 | end = Fnext_single_property_change (position, Qinvisible, |
| 235 | buffer, proplimit); | 243 | buffer, proplimit); |
| 244 | /* Don't put the boundary in the middle of multibyte form if | ||
| 245 | there is no actual property change. */ | ||
| 246 | if (end == pos + 100 | ||
| 247 | && !NILP (current_buffer->enable_multibyte_characters) | ||
| 248 | && end < ZV) | ||
| 249 | while (pos < end && !CHAR_HEAD_P (POS_ADDR (end))) | ||
| 250 | end--; | ||
| 236 | *next_boundary_p = XFASTINT (end); | 251 | *next_boundary_p = XFASTINT (end); |
| 237 | } | 252 | } |
| 238 | /* if the `invisible' property is set, we can skip to | 253 | /* if the `invisible' property is set, we can skip to |
| @@ -287,18 +302,19 @@ current_column () | |||
| 287 | && MODIFF == last_known_column_modified) | 302 | && MODIFF == last_known_column_modified) |
| 288 | return last_known_column; | 303 | return last_known_column; |
| 289 | 304 | ||
| 290 | /* If the buffer has overlays or text properties, | 305 | /* If the buffer has overlays, text properties, or multibyte, |
| 291 | use a more general algorithm. */ | 306 | use a more general algorithm. */ |
| 292 | if (BUF_INTERVALS (current_buffer) | 307 | if (BUF_INTERVALS (current_buffer) |
| 293 | || !NILP (current_buffer->overlays_before) | 308 | || !NILP (current_buffer->overlays_before) |
| 294 | || !NILP (current_buffer->overlays_after)) | 309 | || !NILP (current_buffer->overlays_after) |
| 310 | || !NILP (current_buffer->enable_multibyte_characters)) | ||
| 295 | return current_column_1 (PT); | 311 | return current_column_1 (PT); |
| 296 | 312 | ||
| 297 | /* Scan backwards from point to the previous newline, | 313 | /* Scan backwards from point to the previous newline, |
| 298 | counting width. Tab characters are the only complicated case. */ | 314 | counting width. Tab characters are the only complicated case. */ |
| 299 | 315 | ||
| 300 | /* Make a pointer for decrementing through the chars before point. */ | 316 | /* Make a pointer for decrementing through the chars before point. */ |
| 301 | ptr = &FETCH_CHAR (PT - 1) + 1; | 317 | ptr = POS_ADDR (PT - 1) + 1; |
| 302 | /* Make a pointer to where consecutive chars leave off, | 318 | /* Make a pointer to where consecutive chars leave off, |
| 303 | going backwards from point. */ | 319 | going backwards from point. */ |
| 304 | if (PT == BEGV) | 320 | if (PT == BEGV) |
| @@ -355,6 +371,10 @@ current_column () | |||
| 355 | col += post_tab; | 371 | col += post_tab; |
| 356 | } | 372 | } |
| 357 | 373 | ||
| 374 | if (ptr == BEGV_ADDR) | ||
| 375 | current_column_bol_cache = BEGV; | ||
| 376 | else | ||
| 377 | current_column_bol_cache = PTR_CHAR_POS ((ptr+1)); | ||
| 358 | last_known_column = col; | 378 | last_known_column = col; |
| 359 | last_known_column_point = PT; | 379 | last_known_column_point = PT; |
| 360 | last_known_column_modified = MODIFF; | 380 | last_known_column_modified = MODIFF; |
| @@ -377,8 +397,9 @@ current_column_1 (pos) | |||
| 377 | 397 | ||
| 378 | /* Start the scan at the beginning of this line with column number 0. */ | 398 | /* Start the scan at the beginning of this line with column number 0. */ |
| 379 | register int col = 0; | 399 | register int col = 0; |
| 380 | int scan = find_next_newline (pos, -1); | 400 | int scan = current_column_bol_cache = find_next_newline (pos, -1); |
| 381 | int next_boundary = scan; | 401 | int next_boundary = scan; |
| 402 | int multibyte = !NILP (current_buffer->enable_multibyte_characters); | ||
| 382 | 403 | ||
| 383 | if (tab_width <= 0 || tab_width > 1000) tab_width = 8; | 404 | if (tab_width <= 0 || tab_width > 1000) tab_width = 8; |
| 384 | 405 | ||
| @@ -397,7 +418,7 @@ current_column_1 (pos) | |||
| 397 | goto endloop; | 418 | goto endloop; |
| 398 | } | 419 | } |
| 399 | 420 | ||
| 400 | c = FETCH_CHAR (scan); | 421 | c = FETCH_BYTE (scan); |
| 401 | if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c))) | 422 | if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c))) |
| 402 | { | 423 | { |
| 403 | col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size; | 424 | col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size; |
| @@ -415,6 +436,42 @@ current_column_1 (pos) | |||
| 415 | col += tab_width; | 436 | col += tab_width; |
| 416 | col = col / tab_width * tab_width; | 437 | col = col / tab_width * tab_width; |
| 417 | } | 438 | } |
| 439 | else if (multibyte && BASE_LEADING_CODE_P (c)) | ||
| 440 | { | ||
| 441 | scan--; | ||
| 442 | /* Start of multi-byte form. */ | ||
| 443 | if (c == LEADING_CODE_COMPOSITION) | ||
| 444 | { | ||
| 445 | unsigned char *ptr = POS_ADDR (scan); | ||
| 446 | |||
| 447 | int cmpchar_id = str_cmpchar_id (ptr, next_boundary - scan); | ||
| 448 | if (cmpchar_id >= 0) | ||
| 449 | { | ||
| 450 | scan += cmpchar_table[cmpchar_id]->len, | ||
| 451 | col += cmpchar_table[cmpchar_id]->width; | ||
| 452 | } | ||
| 453 | else | ||
| 454 | { /* invalid composite character */ | ||
| 455 | scan++; | ||
| 456 | col += 4; | ||
| 457 | } | ||
| 458 | } | ||
| 459 | else | ||
| 460 | { | ||
| 461 | /* Here, we check that the following bytes are valid | ||
| 462 | constituents of multi-byte form. */ | ||
| 463 | int len = BYTES_BY_CHAR_HEAD (c), i; | ||
| 464 | |||
| 465 | for (i = 1, scan++; i < len; i++, scan++) | ||
| 466 | /* We don't need range checking for PTR because there | ||
| 467 | are anchors (`\0') at GAP and Z. */ | ||
| 468 | if (CHAR_HEAD_P (POS_ADDR (scan))) break; | ||
| 469 | if (i < len) | ||
| 470 | col += 4, scan -= i - 1; | ||
| 471 | else | ||
| 472 | col += WIDTH_BY_CHAR_HEAD (c); | ||
| 473 | } | ||
| 474 | } | ||
| 418 | else if (ctl_arrow && (c < 040 || c == 0177)) | 475 | else if (ctl_arrow && (c < 040 || c == 0177)) |
| 419 | col += 2; | 476 | col += 2; |
| 420 | else if (c < 040 || c >= 0177) | 477 | else if (c < 040 || c >= 0177) |
| @@ -584,7 +641,7 @@ position_indentation (pos) | |||
| 584 | 641 | ||
| 585 | if (tab_width <= 0 || tab_width > 1000) tab_width = 8; | 642 | if (tab_width <= 0 || tab_width > 1000) tab_width = 8; |
| 586 | 643 | ||
| 587 | p = &FETCH_CHAR (pos); | 644 | p = POS_ADDR (pos); |
| 588 | /* STOP records the value of P at which we will need | 645 | /* STOP records the value of P at which we will need |
| 589 | to think about the gap, or about invisible text, | 646 | to think about the gap, or about invisible text, |
| 590 | or about the end of the buffer. */ | 647 | or about the end of the buffer. */ |
| @@ -615,8 +672,8 @@ position_indentation (pos) | |||
| 615 | (if STOP_POS is the position of the gap) | 672 | (if STOP_POS is the position of the gap) |
| 616 | rather than at the data after the gap. */ | 673 | rather than at the data after the gap. */ |
| 617 | 674 | ||
| 618 | stop = &FETCH_CHAR (stop_pos - 1) + 1; | 675 | stop = POS_ADDR (stop_pos - 1) + 1; |
| 619 | p = &FETCH_CHAR (pos); | 676 | p = POS_ADDR (pos); |
| 620 | } | 677 | } |
| 621 | switch (*p++) | 678 | switch (*p++) |
| 622 | { | 679 | { |
| @@ -639,7 +696,7 @@ int | |||
| 639 | indented_beyond_p (pos, column) | 696 | indented_beyond_p (pos, column) |
| 640 | int pos, column; | 697 | int pos, column; |
| 641 | { | 698 | { |
| 642 | while (pos > BEGV && FETCH_CHAR (pos) == '\n') | 699 | while (pos > BEGV && FETCH_BYTE (pos) == '\n') |
| 643 | pos = find_next_newline_no_quit (pos - 1, -1); | 700 | pos = find_next_newline_no_quit (pos - 1, -1); |
| 644 | return (position_indentation (pos) >= column); | 701 | return (position_indentation (pos) >= column); |
| 645 | } | 702 | } |
| @@ -669,6 +726,7 @@ The return value is the current column.") | |||
| 669 | register int tab_width = XINT (current_buffer->tab_width); | 726 | register int tab_width = XINT (current_buffer->tab_width); |
| 670 | register int ctl_arrow = !NILP (current_buffer->ctl_arrow); | 727 | register int ctl_arrow = !NILP (current_buffer->ctl_arrow); |
| 671 | register struct Lisp_Char_Table *dp = buffer_display_table (); | 728 | register struct Lisp_Char_Table *dp = buffer_display_table (); |
| 729 | register int multibyte = !NILP (current_buffer->enable_multibyte_characters); | ||
| 672 | 730 | ||
| 673 | Lisp_Object val; | 731 | Lisp_Object val; |
| 674 | int prev_col; | 732 | int prev_col; |
| @@ -689,7 +747,7 @@ The return value is the current column.") | |||
| 689 | if (col > goal) | 747 | if (col > goal) |
| 690 | { | 748 | { |
| 691 | end = pos; | 749 | end = pos; |
| 692 | pos = find_next_newline (pos, -1); | 750 | pos = current_column_bol_cache; |
| 693 | col = 0; | 751 | col = 0; |
| 694 | } | 752 | } |
| 695 | 753 | ||
| @@ -708,7 +766,7 @@ The return value is the current column.") | |||
| 708 | if (col >= goal) | 766 | if (col >= goal) |
| 709 | break; | 767 | break; |
| 710 | 768 | ||
| 711 | c = FETCH_CHAR (pos); | 769 | c = FETCH_BYTE (pos); |
| 712 | if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c))) | 770 | if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c))) |
| 713 | { | 771 | { |
| 714 | col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size; | 772 | col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size; |
| @@ -728,10 +786,50 @@ The return value is the current column.") | |||
| 728 | } | 786 | } |
| 729 | else if (ctl_arrow && (c < 040 || c == 0177)) | 787 | else if (ctl_arrow && (c < 040 || c == 0177)) |
| 730 | col += 2; | 788 | col += 2; |
| 731 | else if (c < 040 || c >= 0177) | 789 | else if (c < 040 || c == 0177) |
| 732 | col += 4; | 790 | col += 4; |
| 733 | else | 791 | else if (c < 0177) |
| 734 | col++; | 792 | col++; |
| 793 | else if (multibyte && BASE_LEADING_CODE_P (c)) | ||
| 794 | { | ||
| 795 | /* Start of multi-byte form. */ | ||
| 796 | unsigned char *ptr; | ||
| 797 | |||
| 798 | pos--; /* rewind to the character head */ | ||
| 799 | ptr = POS_ADDR (pos); | ||
| 800 | if (c == LEADING_CODE_COMPOSITION) | ||
| 801 | { | ||
| 802 | int cmpchar_id = str_cmpchar_id (ptr, end - pos); | ||
| 803 | |||
| 804 | if (cmpchar_id >= 0) | ||
| 805 | { | ||
| 806 | col += cmpchar_table[cmpchar_id]->width; | ||
| 807 | pos += cmpchar_table[cmpchar_id]->len; | ||
| 808 | } | ||
| 809 | else | ||
| 810 | { /* invalid composite character */ | ||
| 811 | col += 4; | ||
| 812 | pos++; | ||
| 813 | } | ||
| 814 | } | ||
| 815 | else | ||
| 816 | { | ||
| 817 | /* Here, we check that the following bytes are valid | ||
| 818 | constituents of multi-byte form. */ | ||
| 819 | int len = BYTES_BY_CHAR_HEAD (c), i; | ||
| 820 | |||
| 821 | for (i = 1, ptr++; i < len; i++, ptr++) | ||
| 822 | /* We don't need range checking for PTR because there | ||
| 823 | are anchors (`\0') both at GPT and Z. */ | ||
| 824 | if (CHAR_HEAD_P (ptr)) break; | ||
| 825 | if (i < len) | ||
| 826 | col += 4, pos++; | ||
| 827 | else | ||
| 828 | col += WIDTH_BY_CHAR_HEAD (c), pos += i; | ||
| 829 | } | ||
| 830 | } | ||
| 831 | else | ||
| 832 | col += 4; | ||
| 735 | } | 833 | } |
| 736 | endloop: | 834 | endloop: |
| 737 | 835 | ||
| @@ -848,7 +946,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, | |||
| 848 | = (INTEGERP (current_buffer->selective_display) | 946 | = (INTEGERP (current_buffer->selective_display) |
| 849 | ? XINT (current_buffer->selective_display) | 947 | ? XINT (current_buffer->selective_display) |
| 850 | : !NILP (current_buffer->selective_display) ? -1 : 0); | 948 | : !NILP (current_buffer->selective_display) ? -1 : 0); |
| 851 | int prev_vpos = vpos, prev_hpos = 0; | 949 | int prev_hpos = 0; |
| 852 | int selective_rlen | 950 | int selective_rlen |
| 853 | = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp)) | 951 | = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp)) |
| 854 | ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0); | 952 | ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0); |
| @@ -870,6 +968,13 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, | |||
| 870 | int next_width_run = from; | 968 | int next_width_run = from; |
| 871 | Lisp_Object window; | 969 | Lisp_Object window; |
| 872 | 970 | ||
| 971 | int multibyte = !NILP (current_buffer->enable_multibyte_characters); | ||
| 972 | int wide_column = 0; /* Set to 1 when a previous character | ||
| 973 | is wide-colomn. */ | ||
| 974 | int prev_pos; /* Previous buffer position. */ | ||
| 975 | int contin_hpos; /* HPOS of last column of continued line. */ | ||
| 976 | int prev_tab_offset; /* Previous tab offset. */ | ||
| 977 | |||
| 873 | XSETBUFFER (buffer, current_buffer); | 978 | XSETBUFFER (buffer, current_buffer); |
| 874 | XSETWINDOW (window, win); | 979 | XSETWINDOW (window, win); |
| 875 | 980 | ||
| @@ -885,7 +990,9 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, | |||
| 885 | 990 | ||
| 886 | if (tab_width <= 0 || tab_width > 1000) tab_width = 8; | 991 | if (tab_width <= 0 || tab_width > 1000) tab_width = 8; |
| 887 | 992 | ||
| 888 | pos = from; | 993 | pos = prev_pos = from; |
| 994 | contin_hpos = 0; | ||
| 995 | prev_tab_offset = tab_offset; | ||
| 889 | while (1) | 996 | while (1) |
| 890 | { | 997 | { |
| 891 | while (pos == next_boundary) | 998 | while (pos == next_boundary) |
| @@ -896,10 +1003,14 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, | |||
| 896 | through, so clear the flag after testing it. */ | 1003 | through, so clear the flag after testing it. */ |
| 897 | if (!did_motion) | 1004 | if (!did_motion) |
| 898 | /* We need to skip past the overlay strings. Currently those | 1005 | /* We need to skip past the overlay strings. Currently those |
| 899 | strings must contain single-column printing characters; | 1006 | strings must not contain TAB; |
| 900 | if we want to relax that restriction, something will have | 1007 | if we want to relax that restriction, something will have |
| 901 | to be changed here. */ | 1008 | to be changed here. */ |
| 902 | hpos += overlay_strings (pos, win, (char **)0); | 1009 | { |
| 1010 | unsigned char *ovstr; | ||
| 1011 | int ovlen = overlay_strings (pos, win, &ovstr); | ||
| 1012 | hpos += (multibyte ? strwidth (ovstr, ovlen) : ovlen); | ||
| 1013 | } | ||
| 903 | did_motion = 0; | 1014 | did_motion = 0; |
| 904 | 1015 | ||
| 905 | if (pos >= to) | 1016 | if (pos >= to) |
| @@ -913,9 +1024,50 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, | |||
| 913 | } | 1024 | } |
| 914 | 1025 | ||
| 915 | /* Handle right margin. */ | 1026 | /* Handle right margin. */ |
| 916 | if (hpos >= width | 1027 | /* Note on a wide-column character. |
| 917 | && (hpos > width | 1028 | |
| 918 | || (pos < ZV && FETCH_CHAR (pos) != '\n'))) | 1029 | Characters are classified into the following three categories |
| 1030 | according to the width (columns occupied on screen). | ||
| 1031 | |||
| 1032 | (1) single-column character: ex. `a' | ||
| 1033 | (2) multi-column character: ex. `^A', TAB, `\033' | ||
| 1034 | (3) wide-column character: ex. Japanese character, Chinese character | ||
| 1035 | (In the following example, `W_' stands for them.) | ||
| 1036 | |||
| 1037 | Multi-column characters can be divided around the right margin, | ||
| 1038 | but wide-column characters cannot. | ||
| 1039 | |||
| 1040 | NOTE: | ||
| 1041 | |||
| 1042 | (*) The cursor is placed on the next character after the point. | ||
| 1043 | |||
| 1044 | ---------- | ||
| 1045 | abcdefghi\ | ||
| 1046 | j ^---- next after the point | ||
| 1047 | ^--- next char. after the point. | ||
| 1048 | ---------- | ||
| 1049 | In case of sigle-column character | ||
| 1050 | |||
| 1051 | ---------- | ||
| 1052 | abcdefgh\\ | ||
| 1053 | 033 ^---- next after the point, next char. after the point. | ||
| 1054 | ---------- | ||
| 1055 | In case of multi-column character | ||
| 1056 | |||
| 1057 | ---------- | ||
| 1058 | abcdefgh\\ | ||
| 1059 | W_ ^---- next after the point | ||
| 1060 | ^---- next char. after the point. | ||
| 1061 | ---------- | ||
| 1062 | In case of wide-column character | ||
| 1063 | |||
| 1064 | The problem here is continuation at a wide-column character. | ||
| 1065 | In this case, the line may shorter less than WIDTH. | ||
| 1066 | And we find the continuation AFTER it occurs. | ||
| 1067 | |||
| 1068 | */ | ||
| 1069 | |||
| 1070 | if (hpos > width) | ||
| 919 | { | 1071 | { |
| 920 | if (hscroll | 1072 | if (hscroll |
| 921 | || (truncate_partial_width_windows | 1073 | || (truncate_partial_width_windows |
| @@ -923,31 +1075,94 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, | |||
| 923 | || !NILP (current_buffer->truncate_lines)) | 1075 | || !NILP (current_buffer->truncate_lines)) |
| 924 | { | 1076 | { |
| 925 | /* Truncating: skip to newline. */ | 1077 | /* Truncating: skip to newline. */ |
| 926 | pos = find_before_next_newline (pos, to, 1); | 1078 | if (pos <= to) /* This IF is needed because we may past TO */ |
| 1079 | pos = find_before_next_newline (pos, to, 1); | ||
| 927 | hpos = width; | 1080 | hpos = width; |
| 928 | /* If we just skipped next_boundary, | 1081 | /* If we just skipped next_boundary, |
| 929 | loop around in the main while | 1082 | loop around in the main while |
| 930 | and handle it. */ | 1083 | and handle it. */ |
| 931 | if (pos >= next_boundary) | 1084 | if (pos >= next_boundary) |
| 932 | next_boundary = pos + 1; | 1085 | next_boundary = pos + 1; |
| 1086 | prev_hpos = width; | ||
| 1087 | prev_tab_offset = tab_offset; | ||
| 933 | } | 1088 | } |
| 934 | else | 1089 | else |
| 935 | { | 1090 | { |
| 936 | /* Continuing. */ | 1091 | /* Continuing. */ |
| 937 | vpos += hpos / width; | 1092 | /* Remember the previous value. */ |
| 938 | tab_offset += hpos - hpos % width; | 1093 | prev_tab_offset = tab_offset; |
| 939 | hpos %= width; | 1094 | |
| 1095 | if (wide_column) | ||
| 1096 | { | ||
| 1097 | hpos -= prev_hpos; | ||
| 1098 | tab_offset += prev_hpos; | ||
| 1099 | } | ||
| 1100 | else | ||
| 1101 | { | ||
| 1102 | tab_offset += width; | ||
| 1103 | hpos -= width; | ||
| 1104 | } | ||
| 1105 | vpos++; | ||
| 1106 | contin_hpos = prev_hpos; | ||
| 1107 | prev_hpos = 0; | ||
| 940 | } | 1108 | } |
| 941 | } | 1109 | } |
| 942 | 1110 | ||
| 943 | /* Stop if past the target buffer position or screen position. */ | 1111 | /* Stop if past the target buffer position or screen position. */ |
| 944 | if (pos >= to) | 1112 | if (pos > to) |
| 945 | break; | 1113 | { |
| 946 | if (vpos > tovpos || (vpos == tovpos && hpos >= tohpos)) | 1114 | /* Go back to the previous position. */ |
| 1115 | pos = prev_pos; | ||
| 1116 | hpos = prev_hpos; | ||
| 1117 | tab_offset = prev_tab_offset; | ||
| 1118 | |||
| 1119 | /* NOTE on contin_hpos, hpos, and prev_hpos. | ||
| 1120 | |||
| 1121 | ---------- | ||
| 1122 | abcdefgh\\ | ||
| 1123 | W_ ^---- contin_hpos | ||
| 1124 | | ^----- hpos | ||
| 1125 | \---- prev_hpos | ||
| 1126 | ---------- | ||
| 1127 | */ | ||
| 1128 | |||
| 1129 | if (contin_hpos && prev_hpos == 0 | ||
| 1130 | && contin_hpos < width && !wide_column) | ||
| 1131 | { | ||
| 1132 | /* Line breaking occurs in the middle of multi-column | ||
| 1133 | character. Go back to previous line. */ | ||
| 1134 | hpos = contin_hpos; | ||
| 1135 | vpos = vpos - 1; | ||
| 1136 | } | ||
| 1137 | else if (c == '\n') | ||
| 1138 | /* If previous character is NEWLINE, | ||
| 1139 | set VPOS back to previous line */ | ||
| 1140 | vpos = vpos - 1; | ||
| 1141 | break; | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | if (vpos > tovpos || vpos == tovpos && hpos >= tohpos) | ||
| 1145 | { | ||
| 1146 | if (contin_hpos && prev_hpos == 0 | ||
| 1147 | && (contin_hpos == width || wide_column)) | ||
| 1148 | { /* Line breaks because we can't put the character at the | ||
| 1149 | previous line any more. It is not the multi-column | ||
| 1150 | character continued in middle. Go back to previous | ||
| 1151 | buffer position, screen position, and set tab offset | ||
| 1152 | to previous value. It's the beginning of the | ||
| 1153 | line. */ | ||
| 1154 | pos = prev_pos; | ||
| 1155 | hpos = prev_hpos; | ||
| 1156 | tab_offset = prev_tab_offset; | ||
| 1157 | } | ||
| 1158 | break; | ||
| 1159 | } | ||
| 1160 | if (pos == ZV) /* We cannot go beyond ZV. Stop here. */ | ||
| 947 | break; | 1161 | break; |
| 948 | 1162 | ||
| 949 | prev_vpos = vpos; | ||
| 950 | prev_hpos = hpos; | 1163 | prev_hpos = hpos; |
| 1164 | prev_pos = pos; | ||
| 1165 | wide_column = 0; | ||
| 951 | 1166 | ||
| 952 | /* Consult the width run cache to see if we can avoid inspecting | 1167 | /* Consult the width run cache to see if we can avoid inspecting |
| 953 | the text character-by-character. */ | 1168 | the text character-by-character. */ |
| @@ -1000,7 +1215,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, | |||
| 1000 | /* We have to scan the text character-by-character. */ | 1215 | /* We have to scan the text character-by-character. */ |
| 1001 | else | 1216 | else |
| 1002 | { | 1217 | { |
| 1003 | c = FETCH_CHAR (pos); | 1218 | c = FETCH_BYTE (pos); |
| 1004 | pos++; | 1219 | pos++; |
| 1005 | 1220 | ||
| 1006 | /* Perhaps add some info to the width_run_cache. */ | 1221 | /* Perhaps add some info to the width_run_cache. */ |
| @@ -1073,6 +1288,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, | |||
| 1073 | hpos++; | 1288 | hpos++; |
| 1074 | tab_offset = 0; | 1289 | tab_offset = 0; |
| 1075 | } | 1290 | } |
| 1291 | contin_hpos = 0; | ||
| 1076 | } | 1292 | } |
| 1077 | else if (c == CR && selective < 0) | 1293 | else if (c == CR && selective < 0) |
| 1078 | { | 1294 | { |
| @@ -1093,6 +1309,47 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, | |||
| 1093 | hpos = width; | 1309 | hpos = width; |
| 1094 | } | 1310 | } |
| 1095 | } | 1311 | } |
| 1312 | else if (multibyte && BASE_LEADING_CODE_P (c)) | ||
| 1313 | { | ||
| 1314 | /* Start of multi-byte form. */ | ||
| 1315 | unsigned char *ptr; | ||
| 1316 | |||
| 1317 | pos--; /* rewind POS */ | ||
| 1318 | ptr = POS_ADDR (pos); | ||
| 1319 | |||
| 1320 | if (c == LEADING_CODE_COMPOSITION) | ||
| 1321 | { | ||
| 1322 | int cmpchar_id = str_cmpchar_id (ptr, next_boundary - pos); | ||
| 1323 | |||
| 1324 | if (cmpchar_id >= 0) | ||
| 1325 | { | ||
| 1326 | if (cmpchar_table[cmpchar_id]->width >= 2) | ||
| 1327 | wide_column = 1; | ||
| 1328 | hpos += cmpchar_table[cmpchar_id]->width; | ||
| 1329 | pos += cmpchar_table[cmpchar_id]->len; | ||
| 1330 | } | ||
| 1331 | else | ||
| 1332 | { /* invalid composite character */ | ||
| 1333 | hpos += 4; | ||
| 1334 | pos ++; | ||
| 1335 | } | ||
| 1336 | } | ||
| 1337 | else | ||
| 1338 | { | ||
| 1339 | /* Here, we check that the following bytes are valid | ||
| 1340 | constituents of multi-byte form. */ | ||
| 1341 | int len = BYTES_BY_CHAR_HEAD (c), i; | ||
| 1342 | |||
| 1343 | for (i = 1, ptr++; i < len; i++, ptr++) | ||
| 1344 | /* We don't need range checking for PTR because | ||
| 1345 | there are anchors ('\0') both at GPT and Z. */ | ||
| 1346 | if (CHAR_HEAD_P (ptr)) break; | ||
| 1347 | if (i < len) | ||
| 1348 | hpos += 4, pos++; | ||
| 1349 | else | ||
| 1350 | hpos += WIDTH_BY_CHAR_HEAD (c), pos += i, wide_column = 1; | ||
| 1351 | } | ||
| 1352 | } | ||
| 1096 | else | 1353 | else |
| 1097 | hpos += (ctl_arrow && c < 0200) ? 2 : 4; | 1354 | hpos += (ctl_arrow && c < 0200) ? 2 : 4; |
| 1098 | } | 1355 | } |
| @@ -1113,10 +1370,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, | |||
| 1113 | val_compute_motion.ovstring_chars_done = 0; | 1370 | val_compute_motion.ovstring_chars_done = 0; |
| 1114 | 1371 | ||
| 1115 | /* Nonzero if have just continued a line */ | 1372 | /* Nonzero if have just continued a line */ |
| 1116 | val_compute_motion.contin | 1373 | val_compute_motion.contin = (contin_hpos && prev_hpos == 0); |
| 1117 | = (pos != from | ||
| 1118 | && (val_compute_motion.vpos != prev_vpos) | ||
| 1119 | && c != '\n'); | ||
| 1120 | 1374 | ||
| 1121 | return &val_compute_motion; | 1375 | return &val_compute_motion; |
| 1122 | } | 1376 | } |
| @@ -1237,17 +1491,23 @@ pos_tab_offset (w, pos) | |||
| 1237 | 1491 | ||
| 1238 | if (pos == BEGV) | 1492 | if (pos == BEGV) |
| 1239 | return MINI_WINDOW_P (w) ? -minibuf_prompt_width : 0; | 1493 | return MINI_WINDOW_P (w) ? -minibuf_prompt_width : 0; |
| 1240 | if (FETCH_CHAR (pos - 1) == '\n') | 1494 | if (FETCH_BYTE (pos - 1) == '\n') |
| 1241 | return 0; | 1495 | return 0; |
| 1242 | TEMP_SET_PT (pos); | 1496 | TEMP_SET_PT (pos); |
| 1243 | col = current_column (); | 1497 | col = current_column (); |
| 1244 | TEMP_SET_PT (opoint); | 1498 | TEMP_SET_PT (opoint); |
| 1499 | /* Modulo is no longer valid, as a line may get shorter than WIDTH | ||
| 1500 | columns by continuation of a wide-column character. Just return | ||
| 1501 | COL here. */ | ||
| 1502 | #if 0 | ||
| 1245 | /* In the continuation of the first line in a minibuffer we must | 1503 | /* In the continuation of the first line in a minibuffer we must |
| 1246 | take the width of the prompt into account. */ | 1504 | take the width of the prompt into account. */ |
| 1247 | if (MINI_WINDOW_P (w) && col >= width - minibuf_prompt_width | 1505 | if (MINI_WINDOW_P (w) && col >= width - minibuf_prompt_width |
| 1248 | && find_next_newline_no_quit (pos, -1) == BEGV) | 1506 | && find_next_newline_no_quit (pos, -1) == BEGV) |
| 1249 | return col - (col + minibuf_prompt_width) % width; | 1507 | return col - (col + minibuf_prompt_width) % width; |
| 1250 | return col - (col % width); | 1508 | return col - (col % width); |
| 1509 | #endif | ||
| 1510 | return col; | ||
| 1251 | } | 1511 | } |
| 1252 | 1512 | ||
| 1253 | 1513 | ||
| @@ -1320,7 +1580,11 @@ vmotion (from, vtarget, w) | |||
| 1320 | lmargin + (XFASTINT (prevline) == BEG | 1580 | lmargin + (XFASTINT (prevline) == BEG |
| 1321 | ? start_hpos : 0), | 1581 | ? start_hpos : 0), |
| 1322 | 0, | 1582 | 0, |
| 1323 | from, 1 << (BITS_PER_INT - 2), 0, | 1583 | from, |
| 1584 | /* Don't care for VPOS... */ | ||
| 1585 | 1 << (BITS_PER_SHORT - 1), | ||
| 1586 | /* ... nor HPOS. */ | ||
| 1587 | 1 << (BITS_PER_SHORT - 1), | ||
| 1324 | width, hscroll, | 1588 | width, hscroll, |
| 1325 | /* This compensates for start_hpos | 1589 | /* This compensates for start_hpos |
| 1326 | so that a tab as first character | 1590 | so that a tab as first character |
| @@ -1344,6 +1608,7 @@ vmotion (from, vtarget, w) | |||
| 1344 | val_vmotion.contin = 0; | 1608 | val_vmotion.contin = 0; |
| 1345 | val_vmotion.prevhpos = 0; | 1609 | val_vmotion.prevhpos = 0; |
| 1346 | val_vmotion.ovstring_chars_done = 0; | 1610 | val_vmotion.ovstring_chars_done = 0; |
| 1611 | val_vmotion.tab_offset = 0; /* For accumulating tab offset. */ | ||
| 1347 | return &val_vmotion; | 1612 | return &val_vmotion; |
| 1348 | } | 1613 | } |
| 1349 | 1614 | ||
| @@ -1351,7 +1616,7 @@ vmotion (from, vtarget, w) | |||
| 1351 | } | 1616 | } |
| 1352 | /* Moving downward is simple, but must calculate from beg of line | 1617 | /* Moving downward is simple, but must calculate from beg of line |
| 1353 | to determine hpos of starting point */ | 1618 | to determine hpos of starting point */ |
| 1354 | if (from > BEGV && FETCH_CHAR (from - 1) != '\n') | 1619 | if (from > BEGV && FETCH_BYTE (from - 1) != '\n') |
| 1355 | { | 1620 | { |
| 1356 | Lisp_Object propval; | 1621 | Lisp_Object propval; |
| 1357 | 1622 | ||
| @@ -1373,7 +1638,11 @@ vmotion (from, vtarget, w) | |||
| 1373 | lmargin + (XFASTINT (prevline) == BEG | 1638 | lmargin + (XFASTINT (prevline) == BEG |
| 1374 | ? start_hpos : 0), | 1639 | ? start_hpos : 0), |
| 1375 | 0, | 1640 | 0, |
| 1376 | from, 1 << (BITS_PER_INT - 2), 0, | 1641 | from, |
| 1642 | /* Don't care for VPOS... */ | ||
| 1643 | 1 << (BITS_PER_SHORT - 1), | ||
| 1644 | /* ... nor HPOS. */ | ||
| 1645 | 1 << (BITS_PER_SHORT - 1), | ||
| 1377 | width, hscroll, | 1646 | width, hscroll, |
| 1378 | (XFASTINT (prevline) == BEG ? -start_hpos : 0), | 1647 | (XFASTINT (prevline) == BEG ? -start_hpos : 0), |
| 1379 | w); | 1648 | w); |
| @@ -1383,12 +1652,13 @@ vmotion (from, vtarget, w) | |||
| 1383 | { | 1652 | { |
| 1384 | pos.hpos = lmargin + (from == BEG ? start_hpos : 0); | 1653 | pos.hpos = lmargin + (from == BEG ? start_hpos : 0); |
| 1385 | pos.vpos = 0; | 1654 | pos.vpos = 0; |
| 1655 | pos.tab_offset = 0; | ||
| 1386 | did_motion = 0; | 1656 | did_motion = 0; |
| 1387 | } | 1657 | } |
| 1388 | return compute_motion (from, vpos, pos.hpos, did_motion, | 1658 | return compute_motion (from, vpos, pos.hpos, did_motion, |
| 1389 | ZV, vtarget, - (1 << (BITS_PER_INT - 2)), | 1659 | ZV, vtarget, - (1 << (BITS_PER_SHORT - 1)), |
| 1390 | width, hscroll, | 1660 | width, hscroll, |
| 1391 | pos.vpos * width - (from == BEG ? start_hpos : 0), | 1661 | pos.tab_offset - (from == BEG ? start_hpos : 0), |
| 1392 | w); | 1662 | w); |
| 1393 | } | 1663 | } |
| 1394 | 1664 | ||