diff options
| author | Eli Zaretskii | 2017-07-17 17:50:37 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2017-07-17 17:50:37 +0300 |
| commit | d7f7fef1c1cdef206860a7075873de7d6c521d8d (patch) | |
| tree | abc7489210594cfdd4324404f1fe8155dfd58953 | |
| parent | 5e2ae74df54d4090c591c79ab13e7713c6654b9c (diff) | |
| download | emacs-d7f7fef1c1cdef206860a7075873de7d6c521d8d.tar.gz emacs-d7f7fef1c1cdef206860a7075873de7d6c521d8d.zip | |
Allow user control on what starts and ends a paragraph for bidi
* src/buffer.h (struct buffer): New members
bidi_paragraph_separate_re_ and bidi_paragraph_start_re_.
* src/buffer.c (bset_bidi_paragraph_start_re)
(bset_bidi_paragraph_separate_re): New setters/
(Fbuffer_swap_text): Swap the values of bidi-paragraph-start-re and
bidi-paragraph-separate-re.
(init_buffer_once): Init the values of bidi-paragraph-start-re and
bidi-paragraph-separate-re.
(syms_of_buffer) <bidi-paragraph-start-re, bidi-paragraph-separate-re>:
New per-buffer variables.
* src/bidi.c (bidi_at_paragraph_end, bidi_find_paragraph_start):
Support bidi-paragraph-start-re and bidi-paragraph-separate-re.
(bidi_move_to_visually_next): Handle correctly the case when the
separator matches an empty string. (Bug#27526)
* doc/emacs/mule.texi (Bidirectional Editing):
* doc/lispref/display.texi (Bidirectional Display): Document
bidi-paragraph-start-re and bidi-paragraph-separate-re.
* etc/NEWS: Mention bidi-paragraph-start-re and
bidi-paragraph-separate-re.
| -rw-r--r-- | doc/emacs/mule.texi | 40 | ||||
| -rw-r--r-- | doc/lispref/display.texi | 29 | ||||
| -rw-r--r-- | etc/NEWS | 6 | ||||
| -rw-r--r-- | src/bidi.c | 29 | ||||
| -rw-r--r-- | src/buffer.c | 59 | ||||
| -rw-r--r-- | src/buffer.h | 6 |
6 files changed, 145 insertions, 24 deletions
diff --git a/doc/emacs/mule.texi b/doc/emacs/mule.texi index 8edf2640cfe..2f27b9aa0eb 100644 --- a/doc/emacs/mule.texi +++ b/doc/emacs/mule.texi | |||
| @@ -1774,15 +1774,15 @@ Chars}). | |||
| 1774 | @cindex bidirectional editing | 1774 | @cindex bidirectional editing |
| 1775 | @cindex right-to-left text | 1775 | @cindex right-to-left text |
| 1776 | 1776 | ||
| 1777 | Emacs supports editing text written in scripts, such as Arabic and | 1777 | Emacs supports editing text written in scripts, such as Arabic, |
| 1778 | Hebrew, whose natural ordering of horizontal text for display is from | 1778 | Farsi, and Hebrew, whose natural ordering of horizontal text for |
| 1779 | right to left. However, digits and Latin text embedded in these | 1779 | display is from right to left. However, digits and Latin text |
| 1780 | scripts are still displayed left to right. It is also not uncommon to | 1780 | embedded in these scripts are still displayed left to right. It is |
| 1781 | have small portions of text in Arabic or Hebrew embedded in an otherwise | 1781 | also not uncommon to have small portions of text in Arabic or Hebrew |
| 1782 | Latin document; e.g., as comments and strings in a program source | 1782 | embedded in an otherwise Latin document; e.g., as comments and strings |
| 1783 | file. For these reasons, text that uses these scripts is actually | 1783 | in a program source file. For these reasons, text that uses these |
| 1784 | @dfn{bidirectional}: a mixture of runs of left-to-right and | 1784 | scripts is actually @dfn{bidirectional}: a mixture of runs of |
| 1785 | right-to-left characters. | 1785 | left-to-right and right-to-left characters. |
| 1786 | 1786 | ||
| 1787 | This section describes the facilities and options provided by Emacs | 1787 | This section describes the facilities and options provided by Emacs |
| 1788 | for editing bidirectional text. | 1788 | for editing bidirectional text. |
| @@ -1811,15 +1811,21 @@ directionality when they are displayed. The default value is | |||
| 1811 | 1811 | ||
| 1812 | @cindex base direction of paragraphs | 1812 | @cindex base direction of paragraphs |
| 1813 | @cindex paragraph, base direction | 1813 | @cindex paragraph, base direction |
| 1814 | @vindex bidi-paragraph-start-re | ||
| 1815 | @vindex bidi-paragraph-separate-re | ||
| 1814 | Each paragraph of bidirectional text can have its own @dfn{base | 1816 | Each paragraph of bidirectional text can have its own @dfn{base |
| 1815 | direction}, either right-to-left or left-to-right. (Paragraph | 1817 | direction}, either right-to-left or left-to-right. Text in |
| 1816 | @c paragraph-separate etc have no influence on this? | 1818 | left-to-right paragraphs begins on the screen at the left margin of |
| 1817 | boundaries are empty lines, i.e., lines consisting entirely of | 1819 | the window and is truncated or continued when it reaches the right |
| 1818 | whitespace characters.) Text in left-to-right paragraphs begins on | 1820 | margin. By contrast, text in right-to-left paragraphs is displayed |
| 1819 | the screen at the left margin of the window and is truncated or | 1821 | starting at the right margin and is continued or truncated at the left |
| 1820 | continued when it reaches the right margin. By contrast, text in | 1822 | margin. By default, paragraph boundaries are empty lines, i.e., lines |
| 1821 | right-to-left paragraphs is displayed starting at the right margin and | 1823 | consisting entirely of whitespace characters. To change that, you can |
| 1822 | is continued or truncated at the left margin. | 1824 | customize the two variables @code{bidi-paragraph-start-re} and |
| 1825 | @code{bidi-paragraph-separate-re}, whose values should be regular | ||
| 1826 | expressions (strings); e.g., to have a single newline start a new | ||
| 1827 | paragraph, set both of these variables to @code{"^"}. These two | ||
| 1828 | variables are buffer-local (@pxref{Locals}). | ||
| 1823 | 1829 | ||
| 1824 | @vindex bidi-paragraph-direction | 1830 | @vindex bidi-paragraph-direction |
| 1825 | Emacs determines the base direction of each paragraph dynamically, | 1831 | Emacs determines the base direction of each paragraph dynamically, |
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 98940cbc996..5b8f58c1fd5 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi | |||
| @@ -7456,6 +7456,35 @@ truncated or continued when the text reaches the right margin. | |||
| 7456 | Right-to-left paragraphs are displayed beginning at the right margin, | 7456 | Right-to-left paragraphs are displayed beginning at the right margin, |
| 7457 | and are continued or truncated at the left margin. | 7457 | and are continued or truncated at the left margin. |
| 7458 | 7458 | ||
| 7459 | @cindex paragraph-start, and bidirectional display | ||
| 7460 | @cindex paragraph-separate, and bidirectional display | ||
| 7461 | Where exactly paragraphs start and end, for the purpose of the Emacs | ||
| 7462 | @acronym{UBA} implementation, is determined by the following two | ||
| 7463 | buffer-local variables (note that that @code{paragraph-start} and | ||
| 7464 | @code{paragraph-separate} have no influence on this). By default both | ||
| 7465 | of these variables are @code{nil}, and paragraphs are bounded by empty | ||
| 7466 | lines, i.e., lines that consist entirely of zero or more whitespace | ||
| 7467 | characters followed by a newline. | ||
| 7468 | |||
| 7469 | @defvar bidi-paragraph-start-re | ||
| 7470 | If non-@code{nil}, this variable's value should be a regular | ||
| 7471 | expression matching a line that starts or separates two paragraphs. | ||
| 7472 | The regular expression is always matched after a newline, so it is | ||
| 7473 | best to anchor it, i.e., begin it with a @code{"^"}. | ||
| 7474 | @end defvar | ||
| 7475 | |||
| 7476 | @defvar bidi-paragraph-separate-re | ||
| 7477 | If non-@code{nil}, this variable's value should be a regular | ||
| 7478 | expression matching a line separates two paragraphs. The regular | ||
| 7479 | expression is always matched after a newline, so it is best to anch | ||
| 7480 | it, i.e., begin it with a @code{"^"}. | ||
| 7481 | @end defvar | ||
| 7482 | |||
| 7483 | If you modify any of these two variables, you should normally modify | ||
| 7484 | both, to make sure they describe paragraphs consistently. For | ||
| 7485 | example, to have each new line start a new paragraph for | ||
| 7486 | bidi-reordering purposes, set both variables to @code{"^"}. | ||
| 7487 | |||
| 7459 | By default, Emacs determines the base direction of each paragraph by | 7488 | By default, Emacs determines the base direction of each paragraph by |
| 7460 | looking at the text at its beginning. The precise method of | 7489 | looking at the text at its beginning. The precise method of |
| 7461 | determining the base direction is specified by the @acronym{UBA}; in a | 7490 | determining the base direction is specified by the @acronym{UBA}; in a |
| @@ -561,6 +561,12 @@ current buffer with the contents of the accessible portion of a | |||
| 561 | different buffer while keeping point, mark, markers, and text | 561 | different buffer while keeping point, mark, markers, and text |
| 562 | properties as intact as possible. | 562 | properties as intact as possible. |
| 563 | 563 | ||
| 564 | +++ | ||
| 565 | ** More user control of reordering bidirectional text for display. | ||
| 566 | The two new variables, 'bidi-paragraph-start-re' and | ||
| 567 | 'bidi-paragraph-separate-re', allow customization of what exactly are | ||
| 568 | paragraphs, for the purposes of bidirectional display. | ||
| 569 | |||
| 564 | 570 | ||
| 565 | * Changes in Specialized Modes and Packages in Emacs 26.1 | 571 | * Changes in Specialized Modes and Packages in Emacs 26.1 |
| 566 | 572 | ||
diff --git a/src/bidi.c b/src/bidi.c index e34da778ba0..763797488b0 100644 --- a/src/bidi.c +++ b/src/bidi.c | |||
| @@ -1448,8 +1448,14 @@ bidi_at_paragraph_end (ptrdiff_t charpos, ptrdiff_t bytepos) | |||
| 1448 | Lisp_Object start_re; | 1448 | Lisp_Object start_re; |
| 1449 | ptrdiff_t val; | 1449 | ptrdiff_t val; |
| 1450 | 1450 | ||
| 1451 | sep_re = paragraph_separate_re; | 1451 | if (STRINGP (BVAR (current_buffer, bidi_paragraph_separate_re))) |
| 1452 | start_re = paragraph_start_re; | 1452 | sep_re = BVAR (current_buffer, bidi_paragraph_separate_re); |
| 1453 | else | ||
| 1454 | sep_re = paragraph_separate_re; | ||
| 1455 | if (STRINGP (BVAR (current_buffer, bidi_paragraph_start_re))) | ||
| 1456 | start_re = BVAR (current_buffer, bidi_paragraph_start_re); | ||
| 1457 | else | ||
| 1458 | start_re = paragraph_start_re; | ||
| 1453 | 1459 | ||
| 1454 | val = fast_looking_at (sep_re, charpos, bytepos, ZV, ZV_BYTE, Qnil); | 1460 | val = fast_looking_at (sep_re, charpos, bytepos, ZV, ZV_BYTE, Qnil); |
| 1455 | if (val < 0) | 1461 | if (val < 0) |
| @@ -1523,7 +1529,10 @@ bidi_paragraph_cache_on_off (void) | |||
| 1523 | static ptrdiff_t | 1529 | static ptrdiff_t |
| 1524 | bidi_find_paragraph_start (ptrdiff_t pos, ptrdiff_t pos_byte) | 1530 | bidi_find_paragraph_start (ptrdiff_t pos, ptrdiff_t pos_byte) |
| 1525 | { | 1531 | { |
| 1526 | Lisp_Object re = paragraph_start_re; | 1532 | Lisp_Object re = |
| 1533 | STRINGP (BVAR (current_buffer, bidi_paragraph_start_re)) | ||
| 1534 | ? BVAR (current_buffer, bidi_paragraph_start_re) | ||
| 1535 | : paragraph_start_re; | ||
| 1527 | ptrdiff_t limit = ZV, limit_byte = ZV_BYTE; | 1536 | ptrdiff_t limit = ZV, limit_byte = ZV_BYTE; |
| 1528 | struct region_cache *bpc = bidi_paragraph_cache_on_off (); | 1537 | struct region_cache *bpc = bidi_paragraph_cache_on_off (); |
| 1529 | ptrdiff_t n = 0, oldpos = pos, next; | 1538 | ptrdiff_t n = 0, oldpos = pos, next; |
| @@ -3498,10 +3507,16 @@ bidi_move_to_visually_next (struct bidi_it *bidi_it) | |||
| 3498 | if (sep_len >= 0) | 3507 | if (sep_len >= 0) |
| 3499 | { | 3508 | { |
| 3500 | bidi_it->new_paragraph = 1; | 3509 | bidi_it->new_paragraph = 1; |
| 3501 | /* Record the buffer position of the last character of the | 3510 | /* Record the buffer position of the last character of |
| 3502 | paragraph separator. */ | 3511 | the paragraph separator. If the paragraph separator |
| 3503 | bidi_it->separator_limit | 3512 | is an empty string (e.g., the regex is "^"), the |
| 3504 | = bidi_it->charpos + bidi_it->nchars + sep_len; | 3513 | newline that precedes the end of the paragraph is |
| 3514 | that last character. */ | ||
| 3515 | if (sep_len > 0) | ||
| 3516 | bidi_it->separator_limit | ||
| 3517 | = bidi_it->charpos + bidi_it->nchars + sep_len; | ||
| 3518 | else | ||
| 3519 | bidi_it->separator_limit = bidi_it->charpos; | ||
| 3505 | } | 3520 | } |
| 3506 | } | 3521 | } |
| 3507 | } | 3522 | } |
diff --git a/src/buffer.c b/src/buffer.c index e0972aac33c..649ddbe1839 100644 --- a/src/buffer.c +++ b/src/buffer.c | |||
| @@ -173,6 +173,16 @@ bset_bidi_display_reordering (struct buffer *b, Lisp_Object val) | |||
| 173 | b->bidi_display_reordering_ = val; | 173 | b->bidi_display_reordering_ = val; |
| 174 | } | 174 | } |
| 175 | static void | 175 | static void |
| 176 | bset_bidi_paragraph_start_re (struct buffer *b, Lisp_Object val) | ||
| 177 | { | ||
| 178 | b->bidi_paragraph_start_re_ = val; | ||
| 179 | } | ||
| 180 | static void | ||
| 181 | bset_bidi_paragraph_separate_re (struct buffer *b, Lisp_Object val) | ||
| 182 | { | ||
| 183 | b->bidi_paragraph_separate_re_ = val; | ||
| 184 | } | ||
| 185 | static void | ||
| 176 | bset_buffer_file_coding_system (struct buffer *b, Lisp_Object val) | 186 | bset_buffer_file_coding_system (struct buffer *b, Lisp_Object val) |
| 177 | { | 187 | { |
| 178 | b->buffer_file_coding_system_ = val; | 188 | b->buffer_file_coding_system_ = val; |
| @@ -2322,6 +2332,8 @@ results, see Info node `(elisp)Swapping Text'. */) | |||
| 2322 | swapfield_ (enable_multibyte_characters, Lisp_Object); | 2332 | swapfield_ (enable_multibyte_characters, Lisp_Object); |
| 2323 | swapfield_ (bidi_display_reordering, Lisp_Object); | 2333 | swapfield_ (bidi_display_reordering, Lisp_Object); |
| 2324 | swapfield_ (bidi_paragraph_direction, Lisp_Object); | 2334 | swapfield_ (bidi_paragraph_direction, Lisp_Object); |
| 2335 | swapfield_ (bidi_paragraph_separate_re, Lisp_Object); | ||
| 2336 | swapfield_ (bidi_paragraph_start_re, Lisp_Object); | ||
| 2325 | /* FIXME: Not sure what we should do with these *_marker fields. | 2337 | /* FIXME: Not sure what we should do with these *_marker fields. |
| 2326 | Hopefully they're just nil anyway. */ | 2338 | Hopefully they're just nil anyway. */ |
| 2327 | swapfield_ (pt_marker, Lisp_Object); | 2339 | swapfield_ (pt_marker, Lisp_Object); |
| @@ -5121,6 +5133,8 @@ init_buffer_once (void) | |||
| 5121 | XSETFASTINT (BVAR (&buffer_local_flags, category_table), idx); ++idx; | 5133 | XSETFASTINT (BVAR (&buffer_local_flags, category_table), idx); ++idx; |
| 5122 | XSETFASTINT (BVAR (&buffer_local_flags, bidi_display_reordering), idx); ++idx; | 5134 | XSETFASTINT (BVAR (&buffer_local_flags, bidi_display_reordering), idx); ++idx; |
| 5123 | XSETFASTINT (BVAR (&buffer_local_flags, bidi_paragraph_direction), idx); ++idx; | 5135 | XSETFASTINT (BVAR (&buffer_local_flags, bidi_paragraph_direction), idx); ++idx; |
| 5136 | XSETFASTINT (BVAR (&buffer_local_flags, bidi_paragraph_separate_re), idx); ++idx; | ||
| 5137 | XSETFASTINT (BVAR (&buffer_local_flags, bidi_paragraph_start_re), idx); ++idx; | ||
| 5124 | XSETFASTINT (BVAR (&buffer_local_flags, buffer_file_coding_system), idx); | 5138 | XSETFASTINT (BVAR (&buffer_local_flags, buffer_file_coding_system), idx); |
| 5125 | /* Make this one a permanent local. */ | 5139 | /* Make this one a permanent local. */ |
| 5126 | buffer_permanent_local_flags[idx++] = 1; | 5140 | buffer_permanent_local_flags[idx++] = 1; |
| @@ -5202,6 +5216,8 @@ init_buffer_once (void) | |||
| 5202 | bset_ctl_arrow (&buffer_defaults, Qt); | 5216 | bset_ctl_arrow (&buffer_defaults, Qt); |
| 5203 | bset_bidi_display_reordering (&buffer_defaults, Qt); | 5217 | bset_bidi_display_reordering (&buffer_defaults, Qt); |
| 5204 | bset_bidi_paragraph_direction (&buffer_defaults, Qnil); | 5218 | bset_bidi_paragraph_direction (&buffer_defaults, Qnil); |
| 5219 | bset_bidi_paragraph_start_re (&buffer_defaults, Qnil); | ||
| 5220 | bset_bidi_paragraph_separate_re (&buffer_defaults, Qnil); | ||
| 5205 | bset_cursor_type (&buffer_defaults, Qt); | 5221 | bset_cursor_type (&buffer_defaults, Qt); |
| 5206 | bset_extra_line_spacing (&buffer_defaults, Qnil); | 5222 | bset_extra_line_spacing (&buffer_defaults, Qnil); |
| 5207 | bset_cursor_in_non_selected_windows (&buffer_defaults, Qt); | 5223 | bset_cursor_in_non_selected_windows (&buffer_defaults, Qt); |
| @@ -5616,6 +5632,49 @@ This variable is never applied to a way of decoding a file while reading it. */ | |||
| 5616 | &BVAR (current_buffer, bidi_display_reordering), Qnil, | 5632 | &BVAR (current_buffer, bidi_display_reordering), Qnil, |
| 5617 | doc: /* Non-nil means reorder bidirectional text for display in the visual order. */); | 5633 | doc: /* Non-nil means reorder bidirectional text for display in the visual order. */); |
| 5618 | 5634 | ||
| 5635 | DEFVAR_PER_BUFFER ("bidi-paragraph-start-re", | ||
| 5636 | &BVAR (current_buffer, bidi_paragraph_start_re), Qnil, | ||
| 5637 | doc: /* If non-nil, a regexp matching a line that starts OR separates paragraphs. | ||
| 5638 | |||
| 5639 | The value of nil means to use empty lines as lines that start and | ||
| 5640 | separate paragraphs. | ||
| 5641 | |||
| 5642 | When Emacs displays bidirectional text, it by default computes | ||
| 5643 | the base paragraph direction separately for each paragraph. | ||
| 5644 | Setting this variable changes the places where paragraph base | ||
| 5645 | direction is recomputed. | ||
| 5646 | |||
| 5647 | The regexp is always matched after a newline, so it is best to | ||
| 5648 | anchor it by beginning it with a "^". | ||
| 5649 | |||
| 5650 | If you change the value of this variable, be sure to change | ||
| 5651 | the value of `bidi-paragraph-separate-re' accordingly. For | ||
| 5652 | example, to have a single newline behave as a paragraph separator, | ||
| 5653 | set both these variables to "^". | ||
| 5654 | |||
| 5655 | See also `bidi-paragraph-direction'. */); | ||
| 5656 | |||
| 5657 | DEFVAR_PER_BUFFER ("bidi-paragraph-separate-re", | ||
| 5658 | &BVAR (current_buffer, bidi_paragraph_separate_re), Qnil, | ||
| 5659 | doc: /* If non-nil, a regexp matching a line that separates paragraphs. | ||
| 5660 | |||
| 5661 | The value of nil means to use empty lines as paragraph separators. | ||
| 5662 | |||
| 5663 | When Emacs displays bidirectional text, it by default computes | ||
| 5664 | the base paragraph direction separately for each paragraph. | ||
| 5665 | Setting this variable changes the places where paragraph base | ||
| 5666 | direction is recomputed. | ||
| 5667 | |||
| 5668 | The regexp is always matched after a newline, so it is best to | ||
| 5669 | anchor it by beginning it with a "^". | ||
| 5670 | |||
| 5671 | If you change the value of this variable, be sure to change | ||
| 5672 | the value of `bidi-paragraph-start-re' accordingly. For | ||
| 5673 | example, to have a single newline behave as a paragraph separator, | ||
| 5674 | set both these variables to "^". | ||
| 5675 | |||
| 5676 | See also `bidi-paragraph-direction'. */); | ||
| 5677 | |||
| 5619 | DEFVAR_PER_BUFFER ("bidi-paragraph-direction", | 5678 | DEFVAR_PER_BUFFER ("bidi-paragraph-direction", |
| 5620 | &BVAR (current_buffer, bidi_paragraph_direction), Qnil, | 5679 | &BVAR (current_buffer, bidi_paragraph_direction), Qnil, |
| 5621 | doc: /* If non-nil, forces directionality of text paragraphs in the buffer. | 5680 | doc: /* If non-nil, forces directionality of text paragraphs in the buffer. |
diff --git a/src/buffer.h b/src/buffer.h index be270fe4823..46ca6aa7384 100644 --- a/src/buffer.h +++ b/src/buffer.h | |||
| @@ -611,6 +611,12 @@ struct buffer | |||
| 611 | direction dynamically for each paragraph. */ | 611 | direction dynamically for each paragraph. */ |
| 612 | Lisp_Object bidi_paragraph_direction_; | 612 | Lisp_Object bidi_paragraph_direction_; |
| 613 | 613 | ||
| 614 | /* If non-nil, a regular expression for bidi paragraph separator. */ | ||
| 615 | Lisp_Object bidi_paragraph_separate_re_; | ||
| 616 | |||
| 617 | /* If non-nil, a regular expression for bidi paragraph start. */ | ||
| 618 | Lisp_Object bidi_paragraph_start_re_; | ||
| 619 | |||
| 614 | /* Non-nil means do selective display; | 620 | /* Non-nil means do selective display; |
| 615 | see doc string in syms_of_buffer (buffer.c) for details. */ | 621 | see doc string in syms_of_buffer (buffer.c) for details. */ |
| 616 | Lisp_Object selective_display_; | 622 | Lisp_Object selective_display_; |