diff options
| author | Eli Zaretskii | 2010-09-18 13:59:53 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2010-09-18 13:59:53 +0200 |
| commit | bea4f10c834af9eee873e16913897bbf8065b52e (patch) | |
| tree | 78a59c0d087cb1c5f0f1e27baeaa557656b286ad | |
| parent | 88ed5ce8a653a870fd4f723ee550ffbb0f90626b (diff) | |
| download | emacs-bea4f10c834af9eee873e16913897bbf8065b52e.tar.gz emacs-bea4f10c834af9eee873e16913897bbf8065b52e.zip | |
Fix bug #7038 with cursor motion in paragraphs w/o strong characters.
xdisp.c (Fcurrent_bidi_paragraph_direction): Call
bidi_paragraph_init with NO_DEFAULT_P non-zero.
bidi.c (bidi_paragraph_init): Accept an additional argument
NO_DEFAULT_P; all callers changed. If NO_DEFAULT_P is non-zero,
search back until a paragraph with a strong directional character
is found, and use that to determine paragraph's base direction.
dispextern.h (bidi_paragraph_init): Update prototype.
| -rw-r--r-- | src/ChangeLog | 12 | ||||
| -rw-r--r-- | src/bidi.c | 114 | ||||
| -rw-r--r-- | src/dispextern.h | 2 | ||||
| -rw-r--r-- | src/xdisp.c | 16 |
4 files changed, 96 insertions, 48 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 66735cd5f4e..88030b7b4ce 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,15 @@ | |||
| 1 | 2010-09-18 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * xdisp.c (Fcurrent_bidi_paragraph_direction): Call | ||
| 4 | bidi_paragraph_init with NO_DEFAULT_P non-zero. (Bug#7038) | ||
| 5 | |||
| 6 | * bidi.c (bidi_paragraph_init): Accept an additional argument | ||
| 7 | NO_DEFAULT_P; all callers changed. If NO_DEFAULT_P is non-zero, | ||
| 8 | search back until a paragraph with a strong directional character | ||
| 9 | is found, and use that to determine paragraph's base direction. | ||
| 10 | |||
| 11 | * dispextern.h (bidi_paragraph_init): Update prototype. | ||
| 12 | |||
| 1 | 2010-09-17 Eli Zaretskii <eliz@gnu.org> | 13 | 2010-09-17 Eli Zaretskii <eliz@gnu.org> |
| 2 | 14 | ||
| 3 | * w32.c (_PROCESS_MEMORY_COUNTERS_EX): Don't define with versions | 15 | * w32.c (_PROCESS_MEMORY_COUNTERS_EX): Don't define with versions |
diff --git a/src/bidi.c b/src/bidi.c index a6d4d1b2506..224ed552a6d 100644 --- a/src/bidi.c +++ b/src/bidi.c | |||
| @@ -583,18 +583,26 @@ bidi_find_paragraph_start (EMACS_INT pos, EMACS_INT pos_byte) | |||
| 583 | return pos_byte; | 583 | return pos_byte; |
| 584 | } | 584 | } |
| 585 | 585 | ||
| 586 | /* Determine the direction, a.k.a. base embedding level, of the | 586 | /* Determine the base direction, a.k.a. base embedding level, of the |
| 587 | paragraph we are about to iterate through. If DIR is either L2R or | 587 | paragraph we are about to iterate through. If DIR is either L2R or |
| 588 | R2L, just use that. Otherwise, determine the paragraph direction | 588 | R2L, just use that. Otherwise, determine the paragraph direction |
| 589 | from the first strong character of the paragraph. | 589 | from the first strong directional character of the paragraph. |
| 590 | 590 | ||
| 591 | Note that this gives the paragraph separator the same direction as | 591 | NO_DEFAULT_P non-nil means don't default to L2R if the paragraph |
| 592 | the preceding paragraph, even though Emacs generally views the | 592 | has no strong directional characters and both DIR and |
| 593 | separartor as not belonging to any paragraph. */ | 593 | bidi_it->paragraph_dir are NEUTRAL_DIR. In that case, search back |
| 594 | in the buffer until a paragraph is found with a strong character, | ||
| 595 | or until hitting BEGV. In the latter case, fall back to L2R. This | ||
| 596 | flag is used in current-bidi-paragraph-direction. | ||
| 597 | |||
| 598 | Note that this function gives the paragraph separator the same | ||
| 599 | direction as the preceding paragraph, even though Emacs generally | ||
| 600 | views the separartor as not belonging to any paragraph. */ | ||
| 594 | void | 601 | void |
| 595 | bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it) | 602 | bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p) |
| 596 | { | 603 | { |
| 597 | EMACS_INT bytepos = bidi_it->bytepos; | 604 | EMACS_INT bytepos = bidi_it->bytepos; |
| 605 | EMACS_INT pstartbyte; | ||
| 598 | 606 | ||
| 599 | /* Special case for an empty buffer. */ | 607 | /* Special case for an empty buffer. */ |
| 600 | if (bytepos == BEGV_BYTE && bytepos == ZV_BYTE) | 608 | if (bytepos == BEGV_BYTE && bytepos == ZV_BYTE) |
| @@ -643,49 +651,75 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it) | |||
| 643 | 651 | ||
| 644 | /* We are either at the beginning of a paragraph or in the | 652 | /* We are either at the beginning of a paragraph or in the |
| 645 | middle of it. Find where this paragraph starts. */ | 653 | middle of it. Find where this paragraph starts. */ |
| 646 | bytepos = bidi_find_paragraph_start (pos, bytepos); | 654 | pstartbyte = bidi_find_paragraph_start (pos, bytepos); |
| 647 | |||
| 648 | bidi_it->separator_limit = -1; | 655 | bidi_it->separator_limit = -1; |
| 649 | bidi_it->new_paragraph = 0; | 656 | bidi_it->new_paragraph = 0; |
| 650 | ch = FETCH_CHAR (bytepos); | 657 | |
| 651 | ch_len = CHAR_BYTES (ch); | 658 | /* The following loop is run more than once only if NO_DEFAULT_P |
| 652 | pos = BYTE_TO_CHAR (bytepos); | 659 | is non-zero. */ |
| 653 | type = bidi_get_type (ch, NEUTRAL_DIR); | 660 | do { |
| 654 | 661 | bytepos = pstartbyte; | |
| 655 | for (pos++, bytepos += ch_len; | 662 | ch = FETCH_CHAR (bytepos); |
| 656 | /* NOTE: UAX#9 says to search only for L, AL, or R types of | 663 | ch_len = CHAR_BYTES (ch); |
| 657 | characters, and ignore RLE, RLO, LRE, and LRO. However, | 664 | pos = BYTE_TO_CHAR (bytepos); |
| 658 | I'm not sure it makes sense to omit those 4; should try | 665 | type = bidi_get_type (ch, NEUTRAL_DIR); |
| 659 | with and without that to see the effect. */ | 666 | |
| 660 | (bidi_get_category (type) != STRONG) | 667 | for (pos++, bytepos += ch_len; |
| 661 | || (bidi_ignore_explicit_marks_for_paragraph_level | 668 | /* NOTE: UAX#9 says to search only for L, AL, or R types |
| 662 | && (type == RLE || type == RLO | 669 | of characters, and ignore RLE, RLO, LRE, and LRO. |
| 663 | || type == LRE || type == LRO)); | 670 | However, I'm not sure it makes sense to omit those 4; |
| 664 | type = bidi_get_type (ch, NEUTRAL_DIR)) | 671 | should try with and without that to see the effect. */ |
| 665 | { | 672 | (bidi_get_category (type) != STRONG) |
| 666 | if (type == NEUTRAL_B && bidi_at_paragraph_end (pos, bytepos) >= -1) | 673 | || (bidi_ignore_explicit_marks_for_paragraph_level |
| 667 | break; | 674 | && (type == RLE || type == RLO |
| 668 | if (bytepos >= ZV_BYTE) | 675 | || type == LRE || type == LRO)); |
| 669 | { | 676 | type = bidi_get_type (ch, NEUTRAL_DIR)) |
| 670 | /* Pretend there's a paragraph separator at end of buffer. */ | 677 | { |
| 671 | type = NEUTRAL_B; | 678 | if (type == NEUTRAL_B && bidi_at_paragraph_end (pos, bytepos) >= -1) |
| 672 | break; | 679 | break; |
| 673 | } | 680 | if (bytepos >= ZV_BYTE) |
| 674 | FETCH_CHAR_ADVANCE (ch, pos, bytepos); | 681 | { |
| 675 | } | 682 | /* Pretend there's a paragraph separator at end of |
| 676 | if (type == STRONG_R || type == STRONG_AL) /* P3 */ | 683 | buffer. */ |
| 677 | bidi_it->paragraph_dir = R2L; | 684 | type = NEUTRAL_B; |
| 678 | else if (type == STRONG_L) | 685 | break; |
| 679 | bidi_it->paragraph_dir = L2R; | 686 | } |
| 687 | FETCH_CHAR_ADVANCE (ch, pos, bytepos); | ||
| 688 | } | ||
| 689 | if (type == STRONG_R || type == STRONG_AL) /* P3 */ | ||
| 690 | bidi_it->paragraph_dir = R2L; | ||
| 691 | else if (type == STRONG_L) | ||
| 692 | bidi_it->paragraph_dir = L2R; | ||
| 693 | if (no_default_p && bidi_it->paragraph_dir == NEUTRAL_DIR) | ||
| 694 | { | ||
| 695 | /* If this paragraph is at BEGV, default to L2R. */ | ||
| 696 | if (pstartbyte == BEGV_BYTE) | ||
| 697 | bidi_it->paragraph_dir = L2R; /* P3 and HL1 */ | ||
| 698 | else | ||
| 699 | { | ||
| 700 | EMACS_INT prevpbyte = pstartbyte; | ||
| 701 | EMACS_INT p = BYTE_TO_CHAR (pstartbyte), pbyte = pstartbyte; | ||
| 702 | |||
| 703 | /* Find the beginning of the previous paragraph, if any. */ | ||
| 704 | while (pbyte > BEGV_BYTE && prevpbyte >= pstartbyte) | ||
| 705 | { | ||
| 706 | p--; | ||
| 707 | pbyte = CHAR_TO_BYTE (p); | ||
| 708 | prevpbyte = bidi_find_paragraph_start (p, pbyte); | ||
| 709 | } | ||
| 710 | pstartbyte = prevpbyte; | ||
| 711 | } | ||
| 712 | } | ||
| 713 | } while (no_default_p && bidi_it->paragraph_dir == NEUTRAL_DIR); | ||
| 680 | } | 714 | } |
| 681 | else | 715 | else |
| 682 | abort (); | 716 | abort (); |
| 683 | 717 | ||
| 684 | /* Contrary to UAX#9 clause P3, we only default the paragraph | 718 | /* Contrary to UAX#9 clause P3, we only default the paragraph |
| 685 | direction to L2R if we have no previous usable paragraph | 719 | direction to L2R if we have no previous usable paragraph |
| 686 | direction. */ | 720 | direction. This is allowed by the HL1 clause. */ |
| 687 | if (bidi_it->paragraph_dir != L2R && bidi_it->paragraph_dir != R2L) | 721 | if (bidi_it->paragraph_dir != L2R && bidi_it->paragraph_dir != R2L) |
| 688 | bidi_it->paragraph_dir = L2R; /* P3 and ``higher protocols'' */ | 722 | bidi_it->paragraph_dir = L2R; /* P3 and HL1 ``higher-level protocols'' */ |
| 689 | if (bidi_it->paragraph_dir == R2L) | 723 | if (bidi_it->paragraph_dir == R2L) |
| 690 | bidi_it->level_stack[0].level = 1; | 724 | bidi_it->level_stack[0].level = 1; |
| 691 | else | 725 | else |
diff --git a/src/dispextern.h b/src/dispextern.h index 5138958b6db..6fd92ba940d 100644 --- a/src/dispextern.h +++ b/src/dispextern.h | |||
| @@ -2896,7 +2896,7 @@ extern EMACS_INT tool_bar_button_relief; | |||
| 2896 | 2896 | ||
| 2897 | extern void bidi_init_it (EMACS_INT, EMACS_INT, struct bidi_it *); | 2897 | extern void bidi_init_it (EMACS_INT, EMACS_INT, struct bidi_it *); |
| 2898 | extern void bidi_move_to_visually_next (struct bidi_it *); | 2898 | extern void bidi_move_to_visually_next (struct bidi_it *); |
| 2899 | extern void bidi_paragraph_init (bidi_dir_t, struct bidi_it *); | 2899 | extern void bidi_paragraph_init (bidi_dir_t, struct bidi_it *, int); |
| 2900 | extern int bidi_mirror_char (int); | 2900 | extern int bidi_mirror_char (int); |
| 2901 | 2901 | ||
| 2902 | /* Defined in xdisp.c */ | 2902 | /* Defined in xdisp.c */ |
diff --git a/src/xdisp.c b/src/xdisp.c index 2ec271cdb6b..7b49eed4b2c 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -3821,7 +3821,8 @@ handle_invisible_prop (struct it *it) | |||
| 3821 | not have a chance to do it, if we are going to | 3821 | not have a chance to do it, if we are going to |
| 3822 | skip any text at the beginning, which resets the | 3822 | skip any text at the beginning, which resets the |
| 3823 | FIRST_ELT flag. */ | 3823 | FIRST_ELT flag. */ |
| 3824 | bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it); | 3824 | bidi_paragraph_init (it->paragraph_embedding, |
| 3825 | &it->bidi_it, 0); | ||
| 3825 | } | 3826 | } |
| 3826 | do | 3827 | do |
| 3827 | { | 3828 | { |
| @@ -5143,7 +5144,7 @@ iterate_out_of_display_property (struct it *it) | |||
| 5143 | of a new paragraph, next_element_from_buffer may not have a | 5144 | of a new paragraph, next_element_from_buffer may not have a |
| 5144 | chance to do that. */ | 5145 | chance to do that. */ |
| 5145 | if (it->bidi_it.first_elt && it->bidi_it.charpos < ZV) | 5146 | if (it->bidi_it.first_elt && it->bidi_it.charpos < ZV) |
| 5146 | bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it); | 5147 | bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 0); |
| 5147 | /* prev_stop can be zero, so check against BEGV as well. */ | 5148 | /* prev_stop can be zero, so check against BEGV as well. */ |
| 5148 | while (it->bidi_it.charpos >= BEGV | 5149 | while (it->bidi_it.charpos >= BEGV |
| 5149 | && it->prev_stop <= it->bidi_it.charpos | 5150 | && it->prev_stop <= it->bidi_it.charpos |
| @@ -6201,7 +6202,7 @@ set_iterator_to_next (struct it *it, int reseat_p) | |||
| 6201 | /* If this is a new paragraph, determine its base | 6202 | /* If this is a new paragraph, determine its base |
| 6202 | direction (a.k.a. its base embedding level). */ | 6203 | direction (a.k.a. its base embedding level). */ |
| 6203 | if (it->bidi_it.new_paragraph) | 6204 | if (it->bidi_it.new_paragraph) |
| 6204 | bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it); | 6205 | bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 0); |
| 6205 | bidi_move_to_visually_next (&it->bidi_it); | 6206 | bidi_move_to_visually_next (&it->bidi_it); |
| 6206 | IT_BYTEPOS (*it) = it->bidi_it.bytepos; | 6207 | IT_BYTEPOS (*it) = it->bidi_it.bytepos; |
| 6207 | IT_CHARPOS (*it) = it->bidi_it.charpos; | 6208 | IT_CHARPOS (*it) = it->bidi_it.charpos; |
| @@ -6673,7 +6674,7 @@ next_element_from_buffer (struct it *it) | |||
| 6673 | { | 6674 | { |
| 6674 | /* If we are at the beginning of a line, we can produce the | 6675 | /* If we are at the beginning of a line, we can produce the |
| 6675 | next element right away. */ | 6676 | next element right away. */ |
| 6676 | bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it); | 6677 | bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 0); |
| 6677 | bidi_move_to_visually_next (&it->bidi_it); | 6678 | bidi_move_to_visually_next (&it->bidi_it); |
| 6678 | } | 6679 | } |
| 6679 | else | 6680 | else |
| @@ -6687,7 +6688,7 @@ next_element_from_buffer (struct it *it) | |||
| 6687 | IT_BYTEPOS (*it) = CHAR_TO_BYTE (IT_CHARPOS (*it)); | 6688 | IT_BYTEPOS (*it) = CHAR_TO_BYTE (IT_CHARPOS (*it)); |
| 6688 | it->bidi_it.charpos = IT_CHARPOS (*it); | 6689 | it->bidi_it.charpos = IT_CHARPOS (*it); |
| 6689 | it->bidi_it.bytepos = IT_BYTEPOS (*it); | 6690 | it->bidi_it.bytepos = IT_BYTEPOS (*it); |
| 6690 | bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it); | 6691 | bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 0); |
| 6691 | do | 6692 | do |
| 6692 | { | 6693 | { |
| 6693 | /* Now return to buffer position where we were asked to | 6694 | /* Now return to buffer position where we were asked to |
| @@ -6910,7 +6911,7 @@ next_element_from_composition (struct it *it) | |||
| 6910 | if (it->bidi_p) | 6911 | if (it->bidi_p) |
| 6911 | { | 6912 | { |
| 6912 | if (it->bidi_it.new_paragraph) | 6913 | if (it->bidi_it.new_paragraph) |
| 6913 | bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it); | 6914 | bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 0); |
| 6914 | /* Resync the bidi iterator with IT's new position. | 6915 | /* Resync the bidi iterator with IT's new position. |
| 6915 | FIXME: this doesn't support bidirectional text. */ | 6916 | FIXME: this doesn't support bidirectional text. */ |
| 6916 | while (it->bidi_it.charpos < IT_CHARPOS (*it)) | 6917 | while (it->bidi_it.charpos < IT_CHARPOS (*it)) |
| @@ -17992,8 +17993,9 @@ See also `bidi-paragraph-direction'. */) | |||
| 17992 | itb.bytepos = bytepos; | 17993 | itb.bytepos = bytepos; |
| 17993 | itb.first_elt = 1; | 17994 | itb.first_elt = 1; |
| 17994 | itb.separator_limit = -1; | 17995 | itb.separator_limit = -1; |
| 17996 | itb.paragraph_dir = NEUTRAL_DIR; | ||
| 17995 | 17997 | ||
| 17996 | bidi_paragraph_init (NEUTRAL_DIR, &itb); | 17998 | bidi_paragraph_init (NEUTRAL_DIR, &itb, 1); |
| 17997 | if (buf != current_buffer) | 17999 | if (buf != current_buffer) |
| 17998 | set_buffer_temp (old); | 18000 | set_buffer_temp (old); |
| 17999 | switch (itb.paragraph_dir) | 18001 | switch (itb.paragraph_dir) |