From 0c95fcf739dbfbae70f4e4700fdafedb4497e8df Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Thu, 25 Aug 2011 13:45:33 +0300 Subject: [PATCH] Handle `(space ...)' display spec as paragraph separator. src/xdisp.c (compute_display_string_pos): Return 2 in DISP_PROP when the display spec is of the form `(space ...)'. (handle_display_spec): Return the value returned by handle_single_display_spec, not just 1 or zero. (handle_single_display_spec): If the display spec is of the form `(space ...)', and specifies display in the text area, return 2 rather than 1. src/dispextern.h (struct bidi_it): Rename the disp_prop_p member into disp_prop; all users changed. src/bidi.c (bidi_fetch_char): If compute_display_string_pos returns DISP_PROP = 2, substitute the u+2029 PARAGRAPH SEPARATOR character for the text covered by the display property. lisp/buff-menu.el (Buffer-menu-buffer+size): Remove calls to bidi-string-mark-left-to-right; they are unnecessary now. doc/lispref/display.texi (Specified Space): Mention that `space' specs influence bidi reordering. (Bidirectional Display): Explain how to use `(space . PROPS)' for separating fields with bidirectional content. --- doc/lispref/ChangeLog | 7 ++++ doc/lispref/display.texi | 17 ++++++++-- lisp/ChangeLog | 5 +++ lisp/buff-menu.el | 4 +-- src/ChangeLog | 17 ++++++++++ src/bidi.c | 71 +++++++++++++++++++++++++--------------- src/dispextern.h | 5 +-- src/xdisp.c | 71 ++++++++++++++++++++++++++-------------- 8 files changed, 140 insertions(+), 57 deletions(-) diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog index 4bf615328b..ca9c93b563 100644 --- a/doc/lispref/ChangeLog +++ b/doc/lispref/ChangeLog @@ -1,3 +1,10 @@ +2011-08-25 Eli Zaretskii + + * display.texi (Specified Space): Mention that `space' specs + influence bidi reordering. + (Bidirectional Display): Explain how to use `(space . PROPS)' for + separating fields with bidirectional content. + 2011-08-24 Eli Zaretskii * display.texi (Bidirectional Display): Document return value in diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 0593eba8f0..bf7cd126a2 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -3794,6 +3794,10 @@ with a @dfn{pixel ascent} specification (@pxref{Pixel Specification}). non-graphic terminals, but the other space properties in this section are not. + Note that space properties are treated as paragraph separators for +the purposes of reordering bidirectional text for display. +@xref{Bidirectional Display}, for the details. + @node Pixel Specification @subsection Pixel Specification for Spaces @cindex spaces, pixel specification @@ -6126,8 +6130,8 @@ with bidirectional content can be displayed @emph{to the left} of the preceding field, producing a jumbled display and messing up the expected layout. - To countermand this, you can use one of the following techniques for -forcing correct order of fields on display: + To countermand this, we recommend that you use one of the following +techniques for forcing correct order of fields on display: @itemize @minus @item @@ -6146,6 +6150,15 @@ Include the tab character in the field separator. The tab character plays the role of @dfn{segment separator} in the @acronym{UBA} reordering, whose effect is to make each field a separate segment, and thus reorder them separately. + +@cindex @code{space} display spec, and bidirectional text +@item +Separate fields with a @code{display} property or overlay with the +property value of the form @code{(space . PROPS)} (@pxref{Specified +Space}). This display specification is treated by Emacs as a +@dfn{paragraph separator}; the text before and after the separator is +reordered separately, which avoids the influence of any field on its +neighboring fields. @end itemize @defun bidi-string-mark-left-to-right string diff --git a/lisp/ChangeLog b/lisp/ChangeLog index a42711dccc..064e745d1f 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,8 @@ +2011-08-25 Eli Zaretskii + + * buff-menu.el (Buffer-menu-buffer+size): Remove calls to + bidi-string-mark-left-to-right; they are unnecessary now. + 2011-08-25 Deniz Dogan * net/quickurl.el: Documentation typo fixes. diff --git a/lisp/buff-menu.el b/lisp/buff-menu.el index 2eac33d815..2be74cf5ef 100644 --- a/lisp/buff-menu.el +++ b/lisp/buff-menu.el @@ -681,9 +681,9 @@ For more information, see the function `buffer-menu'." (string-width tail) 2)) Buffer-menu-short-ellipsis - (bidi-string-mark-left-to-right tail)))) + tail))) ;; Don't put properties on (buffer-name). - (setq name (bidi-string-mark-left-to-right name))) + (setq name (copy-sequence name))) (add-text-properties 0 (length name) name-props name) (add-text-properties 0 (length size) size-props size) (let ((name+space-width (- Buffer-menu-buffer+size-width diff --git a/src/ChangeLog b/src/ChangeLog index 431a515def..b2f2334427 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,20 @@ +2011-08-25 Eli Zaretskii + + * xdisp.c (compute_display_string_pos): Return 2 in DISP_PROP when + the display spec is of the form `(space ...)'. + (handle_display_spec): Return the value returned by + handle_single_display_spec, not just 1 or zero. + (handle_single_display_spec): If the display spec is of the form + `(space ...)', and specifies display in the text area, return 2 + rather than 1. + + * dispextern.h (struct bidi_it): Rename the disp_prop_p member + into disp_prop; all users changed. + + * bidi.c (bidi_fetch_char): If compute_display_string_pos returns + DISP_PROP = 2, substitute the u+2029 PARAGRAPH SEPARATOR character + for the text covered by the display property. + 2011-08-25 Chong Yidong * buffer.c (Fbury_buffer_internal): Rename from Funrecord_buffer. diff --git a/src/bidi.c b/src/bidi.c index 425a0be957..79aaa03fb0 100644 --- a/src/bidi.c +++ b/src/bidi.c @@ -540,7 +540,7 @@ bidi_cache_iterator_state (struct bidi_it *bidi_it, int resolved) bidi_cache[idx].next_for_ws = bidi_it->next_for_ws; bidi_cache[idx].ignore_bn_limit = bidi_it->ignore_bn_limit; bidi_cache[idx].disp_pos = bidi_it->disp_pos; - bidi_cache[idx].disp_prop_p = bidi_it->disp_prop_p; + bidi_cache[idx].disp_prop = bidi_it->disp_prop; } bidi_cache_last_idx = idx; @@ -828,7 +828,7 @@ bidi_init_it (EMACS_INT charpos, EMACS_INT bytepos, int frame_window_p, bidi_it->prev_for_neutral.orig_type = UNKNOWN_BT; bidi_it->sor = L2R; /* FIXME: should it be user-selectable? */ bidi_it->disp_pos = -1; /* invalid/unknown */ - bidi_it->disp_prop_p = 0; + bidi_it->disp_prop = 0; /* We can only shrink the cache if we are at the bottom level of its "stack". */ if (bidi_cache_start == 0) @@ -908,19 +908,22 @@ bidi_char_at_pos (EMACS_INT bytepos, const unsigned char *s, int unibyte) /* Fetch and return the character at BYTEPOS/CHARPOS. If that character is covered by a display string, treat the entire run of - covered characters as a single character u+FFFC, and return their - combined length in CH_LEN and NCHARS. DISP_POS specifies the - character position of the next display string, or -1 if not yet - computed. DISP_PROP_P non-zero means that there's really a display - string at DISP_POS, as opposed to when we searched till DISP_POS - without findingone. When the next character is at or beyond that - position, the function updates DISP_POS with the position of the - next display string. STRING->s is the C string to iterate, or NULL - if iterating over a buffer or a Lisp string; in the latter case, - STRING->lstring is the Lisp string. */ + covered characters as a single character, either u+2029 or u+FFFC, + and return their combined length in CH_LEN and NCHARS. DISP_POS + specifies the character position of the next display string, or -1 + if not yet computed. DISP_PROP non-zero means that there's really + a display string at DISP_POS, as opposed to when we searched till + DISP_POS without finding one. If DISP_PROP is 2, it means the + display spec is of the form `(space ...)', which is replaced with + u+2029 to handle it as a paragraph separator. When the next + character is at or beyond that position, the function updates + DISP_POS with the position of the next display string. STRING->s + is the C string to iterate, or NULL if iterating over a buffer or a + Lisp string; in the latter case, STRING->lstring is the Lisp + string. */ static inline int bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos, - int *disp_prop_p, struct bidi_string_data *string, + int *disp_prop, struct bidi_string_data *string, int frame_window_p, EMACS_INT *ch_len, EMACS_INT *nchars) { int ch; @@ -934,7 +937,7 @@ bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos, { SET_TEXT_POS (pos, charpos, bytepos); *disp_pos = compute_display_string_pos (&pos, string, frame_window_p, - disp_prop_p); + disp_prop); } /* Fetch the character at BYTEPOS. */ @@ -944,9 +947,9 @@ bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos, *ch_len = 1; *nchars = 1; *disp_pos = endpos; - *disp_prop_p = 0; + *disp_prop = 0; } - else if (charpos >= *disp_pos && *disp_prop_p) + else if (charpos >= *disp_pos && *disp_prop) { EMACS_INT disp_end_pos; @@ -954,9 +957,23 @@ bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos, property. Hopefully, it will never be needed. */ if (charpos > *disp_pos) abort (); - /* Return the Unicode Object Replacement Character to represent - the entire run of characters covered by the display string. */ - ch = 0xFFFC; + /* Text covered by `display' properties and overlays with + display properties or display strings is handled as a single + character that represents the entire run of characters + covered by the display property. */ + if (*disp_prop == 2) + { + /* `(space ...)' display specs are handled as paragraph + separators for the purposes of the reordering; see UAX#9 + section 3 and clause HL1 in section 4.3 there. */ + ch = 0x2029; + } + else + { + /* All other display specs are handled as the Unicode Object + Replacement Character. */ + ch = 0xFFFC; + } disp_end_pos = compute_display_string_end (*disp_pos, string); *nchars = disp_end_pos - *disp_pos; if (*nchars <= 0) @@ -1014,11 +1031,11 @@ bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos, /* If we just entered a run of characters covered by a display string, compute the position of the next display string. */ if (charpos + *nchars <= endpos && charpos + *nchars > *disp_pos - && *disp_prop_p) + && *disp_prop) { SET_TEXT_POS (pos, charpos + *nchars, bytepos + *ch_len); *disp_pos = compute_display_string_pos (&pos, string, frame_window_p, - disp_prop_p); + disp_prop); } return ch; @@ -1126,7 +1143,7 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p) int ch; EMACS_INT ch_len, nchars; EMACS_INT pos, disp_pos = -1; - int disp_prop_p = 0; + int disp_prop = 0; bidi_type_t type; const unsigned char *s; @@ -1174,7 +1191,7 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p) bytepos = pstartbyte; if (!string_p) pos = BYTE_TO_CHAR (bytepos); - ch = bidi_fetch_char (bytepos, pos, &disp_pos, &disp_prop_p, + ch = bidi_fetch_char (bytepos, pos, &disp_pos, &disp_prop, &bidi_it->string, bidi_it->frame_window_p, &ch_len, &nchars); type = bidi_get_type (ch, NEUTRAL_DIR); @@ -1199,7 +1216,7 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p) break; /* Fetch next character and advance to get past it. */ ch = bidi_fetch_char (bytepos, pos, &disp_pos, - &disp_prop_p, &bidi_it->string, + &disp_prop, &bidi_it->string, bidi_it->frame_window_p, &ch_len, &nchars); pos += nchars; bytepos += ch_len; @@ -1336,7 +1353,7 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it) bidi_it->ch_len = 1; bidi_it->nchars = 1; bidi_it->disp_pos = (string_p ? bidi_it->string.schars : ZV); - bidi_it->disp_prop_p = 0; + bidi_it->disp_prop = 0; } else { @@ -1344,7 +1361,7 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it) display string, treat the entire run of covered characters as a single character u+FFFC. */ curchar = bidi_fetch_char (bidi_it->bytepos, bidi_it->charpos, - &bidi_it->disp_pos, &bidi_it->disp_prop_p, + &bidi_it->disp_pos, &bidi_it->disp_prop, &bidi_it->string, bidi_it->frame_window_p, &bidi_it->ch_len, &bidi_it->nchars); } @@ -2079,7 +2096,7 @@ bidi_level_of_next_char (struct bidi_it *bidi_it) struct bidi_string_data bs = bidi_it->string; bidi_type_t chtype; int fwp = bidi_it->frame_window_p; - int dpp = bidi_it->disp_prop_p; + int dpp = bidi_it->disp_prop; if (bidi_it->nchars <= 0) abort (); diff --git a/src/dispextern.h b/src/dispextern.h index 084a3f9e07..f5d20250fa 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1860,8 +1860,9 @@ struct bidi_it { bidi_dir_t sor; /* direction of start-of-run in effect */ int scan_dir; /* direction of text scan, 1: forw, -1: back */ EMACS_INT disp_pos; /* position of display string after ch */ - int disp_prop_p; /* if non-zero, there really is a - `display' property/string at disp_pos */ + int disp_prop; /* if non-zero, there really is a + `display' property/string at disp_pos; + if 2, the property is a `space' spec */ int stack_idx; /* index of current data on the stack */ /* Note: Everything from here on is not copied/saved when the bidi iterator state is saved, pushed, or popped. So only put here diff --git a/src/xdisp.c b/src/xdisp.c index 4ed08e72e1..5cbc7747f2 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -3146,11 +3146,15 @@ next_overlay_change (EMACS_INT pos) text property whose value is a string. STRING is data about the string to iterate; if STRING->lstring is nil, we are iterating a buffer. FRAME_WINDOW_P is non-zero when we are displaying a window - on a GUI frame. */ + on a GUI frame. DISP_PROP is set to zero if we searched + MAX_DISP_SCAN characters forward without finding any display + strings, non-zero otherwise. It is set to 2 if the display string + uses any kind of `(space ...)' spec that will produce a stretch of + white space in the text area. */ EMACS_INT compute_display_string_pos (struct text_pos *position, struct bidi_string_data *string, - int frame_window_p, int *disp_prop_p) + int frame_window_p, int *disp_prop) { /* OBJECT = nil means current buffer. */ Lisp_Object object = @@ -3163,8 +3167,9 @@ compute_display_string_pos (struct text_pos *position, EMACS_INT lim = (charpos < eob - MAX_DISP_SCAN) ? charpos + MAX_DISP_SCAN : eob; struct text_pos tpos; + int rv = 0; - *disp_prop_p = 1; + *disp_prop = 1; if (charpos >= eob /* We don't support display properties whose values are strings @@ -3173,7 +3178,7 @@ compute_display_string_pos (struct text_pos *position, /* C strings cannot have display properties. */ || (string->s && !STRINGP (object))) { - *disp_prop_p = 0; + *disp_prop = 0; return eob; } @@ -3190,9 +3195,11 @@ compute_display_string_pos (struct text_pos *position, || !EQ (Fget_char_property (make_number (charpos - 1), Qdisplay, object), spec)) - && handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos, - frame_window_p)) + && (rv = handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos, + frame_window_p))) { + if (rv == 2) + *disp_prop = 2; return charpos; } @@ -3204,7 +3211,7 @@ compute_display_string_pos (struct text_pos *position, CHARPOS (tpos) = XFASTINT (pos); if (CHARPOS (tpos) >= lim) { - *disp_prop_p = 0; + *disp_prop = 0; break; } if (STRINGP (object)) @@ -3215,8 +3222,10 @@ compute_display_string_pos (struct text_pos *position, if (!STRINGP (object)) bufpos = CHARPOS (tpos); } while (NILP (spec) - || !handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos, - frame_window_p)); + || !(rv = handle_display_spec (NULL, spec, object, Qnil, &tpos, + bufpos, frame_window_p))); + if (rv == 2) + *disp_prop = 2; return CHARPOS (tpos); } @@ -4078,7 +4087,9 @@ handle_display_prop (struct it *it) /* Subroutine of handle_display_prop. Returns non-zero if the display specification in SPEC is a replacing specification, i.e. it would replace the text covered by `display' property with something else, - such as an image or a display string. + such as an image or a display string. If SPEC includes any kind or + `(space ...) specification, the value is 2; this is used by + compute_display_string_pos, which see. See handle_single_display_spec for documentation of arguments. frame_window_p is non-zero if the window being redisplayed is on a @@ -4095,6 +4106,7 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, EMACS_INT bufpos, int frame_window_p) { int replacing_p = 0; + int rv; if (CONSP (spec) /* Simple specerties. */ @@ -4113,11 +4125,11 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, { for (; CONSP (spec); spec = XCDR (spec)) { - if (handle_single_display_spec (it, XCAR (spec), object, overlay, - position, bufpos, replacing_p, - frame_window_p)) + if ((rv = handle_single_display_spec (it, XCAR (spec), object, + overlay, position, bufpos, + replacing_p, frame_window_p))) { - replacing_p = 1; + replacing_p = rv; /* If some text in a string is replaced, `position' no longer points to the position of `object'. */ if (!it || STRINGP (object)) @@ -4129,11 +4141,11 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, { int i; for (i = 0; i < ASIZE (spec); ++i) - if (handle_single_display_spec (it, AREF (spec, i), object, overlay, - position, bufpos, replacing_p, - frame_window_p)) + if ((rv = handle_single_display_spec (it, AREF (spec, i), object, + overlay, position, bufpos, + replacing_p, frame_window_p))) { - replacing_p = 1; + replacing_p = rv; /* If some text in a string is replaced, `position' no longer points to the position of `object'. */ if (!it || STRINGP (object)) @@ -4142,9 +4154,10 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, } else { - if (handle_single_display_spec (it, spec, object, overlay, - position, bufpos, 0, frame_window_p)) - replacing_p = 1; + if ((rv = handle_single_display_spec (it, spec, object, overlay, + position, bufpos, 0, + frame_window_p))) + replacing_p = rv; } return replacing_p; @@ -4520,8 +4533,17 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, if (valid_p && !display_replaced_p) { + int retval = 1; + if (!it) - return 1; + { + /* Callers need to know whether the display spec is any kind + of `(space ...)' spec that is about to affect text-area + display. */ + if (CONSP (value) && EQ (XCAR (value), Qspace) && NILP (location)) + retval = 2; + return retval; + } /* Save current settings of IT so that we can restore them when we are finished with the glyph property value. */ @@ -4579,6 +4601,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, it->method = GET_FROM_STRETCH; it->object = value; *position = it->position = start_pos; + retval = 1 + (it->area == TEXT_AREA); } #ifdef HAVE_WINDOW_SYSTEM else @@ -4596,7 +4619,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, } #endif /* HAVE_WINDOW_SYSTEM */ - return 1; + return retval; } /* Invalid property or property not supported. Restore @@ -5557,7 +5580,7 @@ forward_to_next_line_start (struct it *it, int *skipped_p, if (it->bidi_it.disp_pos < limit) { it->bidi_it.disp_pos = limit; - it->bidi_it.disp_prop_p = 0; + it->bidi_it.disp_prop = 0; } do { bprev = it->bidi_it; -- 2.20.1