Continue working on paragraph base direction.
Support per-buffer default paragraph direction.
buffer.h (struct buffer): New member paragraph_direction.
buffer.c (init_buffer_once): Initialize it.
(syms_of_buffer): Declare Lisp variables
default-paragraph-direction and paragraph-direction.
dispextern.h (struct it): New member paragraph_embedding.
xdisp.c (init_iterator): Initialize it from the buffer's value
of paragraph-direction.
<Qright_to_left, Qleft_to_right>: New variables.
(syms_of_xdisp): Initialize and staticpro them.
(set_iterator_to_next, next_element_from_buffer): Use the value of
paragraph_embedding to determine the paragraph direction.
bidi.c (bidi_line_init): Fix second argument to
bidi_set_sor_type.
(bidi_init_it): Initialize paragraph_dir to NEUTRAL_DIR.
(bidi_get_next_char_visually): Record the last character of the
separator in separator_limit, not the character after that.
(bidi_find_paragraph_start): Accept character and byte positions
instead of the whole iterator stricture. All callers changed.
+2009-10-05 Eli Zaretskii <eliz@gnu.org>
+
+ * buffer.h (struct buffer): New member paragraph_direction.
+ * buffer.c (init_buffer_once): Initialize it.
+ (syms_of_buffer): Declare Lisp variables
+ default-paragraph-direction and paragraph-direction.
+
+ * dispextern.h (struct it): New member paragraph_embedding.
+ * xdisp.c (init_iterator): Initialize it from the buffer's value
+ of paragraph-direction.
+ <Qright_to_left, Qleft_to_right>: New variables.
+ (syms_of_xdisp): Initialize and staticpro them.
+ (set_iterator_to_next, next_element_from_buffer): Use the value of
+ paragraph_embedding to determine the paragraph direction.
+
+ * bidi.c (bidi_line_init): Fix second argument to
+ bidi_set_sor_type.
+ (bidi_init_it): Initialize paragraph_dir to NEUTRAL_DIR.
+ (bidi_get_next_char_visually): Record the last character of the
+ separator in separator_limit, not the character after that.
+ (bidi_find_paragraph_start): Accept character and byte positions
+ instead of the whole iterator stricture. All callers changed.
+
2009-10-04 Eli Zaretskii <eliz@gnu.org>
* bidi.c (bidi_at_paragraph_end): Check for paragraph-start if
bidi_it->invalid_rl_levels = -1;
bidi_it->next_en_pos = -1;
bidi_it->next_for_ws.type = UNKNOWN_BT;
- bidi_set_sor_type (bidi_it, bidi_it->paragraph_dir,
+ bidi_set_sor_type (bidi_it,
+ bidi_it->paragraph_dir == R2L ? 1 : 0,
bidi_it->level_stack[0].level); /* X10 */
bidi_cache_reset ();
/* Find the beginning of this paragraph by looking back in the buffer.
Value is the byte position of the paragraph's beginning. */
static EMACS_INT
-bidi_find_paragraph_start (struct bidi_it *bidi_it)
+bidi_find_paragraph_start (EMACS_INT pos, EMACS_INT pos_byte)
{
Lisp_Object re = Fbuffer_local_value (Qparagraph_start, Fcurrent_buffer ());
- EMACS_INT pos = bidi_it->charpos;
- EMACS_INT pos_byte = bidi_it->bytepos;
EMACS_INT limit = ZV, limit_byte = ZV_BYTE;
if (!STRINGP (re))
}
/* Determine the direction, a.k.a. base embedding level, of the
- paragraph we are about to iterate through. */
+ paragraph we are about to iterate through. If DIR is either L2R or
+ R2L, just use that. Otherwise, determine the paragraph direction
+ from the first strong character of the paragraph.
+
+ Note that this gives the paragraph separator the same direction as
+ the preceding paragraph, even though Emacs generally views the
+ separartor as not belonging to any paragraph. */
void
bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it)
{
if (bidi_it->charpos < bidi_it->separator_limit)
return;
- /* If we are before another paragraph separator, continue
- through that with the previous paragraph direction. */
- sep_len = bidi_at_paragraph_end (bidi_it->charpos, bytepos);
- if (sep_len >= 0)
+ /* If we are on a newline, get past it to where the next
+ paragraph might start. */
+ if (FETCH_CHAR (bytepos) == '\n')
{
- bidi_it->separator_limit += sep_len + 1;
- return;
+ bytepos++;
+ pos = bidi_it->charpos + 1;
}
- else if (sep_len == -2)
- /* We are in the middle of a paragraph. Search back to where
- this paragraph starts. */
- bytepos = bidi_find_paragraph_start (bidi_it);
+
+ /* We are either at the beginning of a paragraph or in the
+ middle of it. Find where this paragraph starts. */
+ bytepos = bidi_find_paragraph_start (pos, bytepos);
/* We should always be at the beginning of a new line at this
point. */
- if (!(bytepos == BEGV_BYTE
- || FETCH_CHAR (bytepos) == '\n'
- || FETCH_CHAR (bytepos - 1) == '\n'))
+ if (!(bytepos == BEGV_BYTE || FETCH_CHAR (bytepos - 1) == '\n'))
abort ();
bidi_it->separator_limit = -1;
else
abort ();
- /* Contrary to UAX#9 clause P3, we only default to L2R if we have no
- previous usable paragraph direction. */
+ /* Contrary to UAX#9 clause P3, we only default the paragraph
+ direction to L2R if we have no previous usable paragraph
+ direction. */
if (bidi_it->paragraph_dir == NEUTRAL_DIR)
- bidi_it->paragraph_dir = L2R; /* P3 */
+ bidi_it->paragraph_dir = L2R; /* P3 and ``higher protocols'' */
if (bidi_it->paragraph_dir == R2L)
- bidi_it->level_stack[0].level == 1;
+ bidi_it->level_stack[0].level = 1;
else
- bidi_it->level_stack[0].level == 0;
+ bidi_it->level_stack[0].level = 0;
bidi_line_init (bidi_it);
}
bidi_set_paragraph_end (bidi_it);
bidi_it->new_paragraph = 1;
bidi_it->separator_limit = -1;
+ bidi_it->paragraph_dir = NEUTRAL_DIR;
bidi_it->type = NEUTRAL_B;
bidi_it->type_after_w1 = UNKNOWN_BT;
bidi_it->orig_type = UNKNOWN_BT;
next_level = bidi_level_of_next_char (bidi_it);
}
- /* Take note when we are at the end of the paragraph. The next time
- we are about to be called, set_iterator_to_next will
- automatically reinit the paragraph direction, if needed. */
+ /* Take note when we have just processed the newline that precedes
+ the end of the paragraph. The next time we are about to be
+ called, set_iterator_to_next will automatically reinit the
+ paragraph direction, if needed. We do this at the newline before
+ the paragraph separator, because the next character might not be
+ the first character of the next paragraph, due to the bidi
+ reordering. */
if (bidi_it->scan_dir == 1
&& bidi_it->orig_type == NEUTRAL_B
&& bidi_it->bytepos < ZV_BYTE)
if (sep_len >= 0)
{
bidi_it->new_paragraph = 1;
- /* Record the buffer position of the first character after
- the paragraph separator. */
- bidi_it->separator_limit = bidi_it->charpos + 1 + sep_len + 1;
+ /* Record the buffer position of the last character of the
+ paragraph separator. */
+ bidi_it->separator_limit = bidi_it->charpos + 1 + sep_len;
}
}
buffer_defaults.ctl_arrow = Qt;
buffer_defaults.bidi_display_reordering = Qnil;
buffer_defaults.direction_reversed = Qnil;
+ buffer_defaults.paragraph_direction = Qnil;
buffer_defaults.cursor_type = Qt;
buffer_defaults.extra_line_spacing = Qnil;
buffer_defaults.cursor_in_non_selected_windows = Qt;
XSETFASTINT (buffer_local_flags.category_table, idx); ++idx;
XSETFASTINT (buffer_local_flags.bidi_display_reordering, idx); ++idx;
XSETFASTINT (buffer_local_flags.direction_reversed, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.paragraph_direction, idx); ++idx;
XSETFASTINT (buffer_local_flags.buffer_file_coding_system, idx);
/* Make this one a permanent local. */
buffer_permanent_local_flags[idx++] = 1;
doc: /* *Default value of `enable-multibyte-characters' for buffers not overriding it.
This is the same as (default-value 'enable-multibyte-characters). */);
+ DEFVAR_LISP_NOPRO ("default-paragraph-direction",
+ &buffer_defaults.paragraph_direction,
+ doc: /* Default value of `paragraph-direction' for buffers that do not override it.
+This is the same as (default-value 'paragraph-direction). */);
+
DEFVAR_LISP_NOPRO ("default-buffer-file-coding-system",
&buffer_defaults.buffer_file_coding_system,
doc: /* Default value of `buffer-file-coding-system' for buffers not overriding it.
doc: /*Non-nil means reorder bidirectional text for display in the visual order.
See also the variable `direction-reversed'. */);
+ DEFVAR_PER_BUFFER ("paragraph-direction",
+ ¤t_buffer->paragraph_direction, Qnil,
+ doc: /* *If non-nil, forces directionality of text paragraphs in the buffer.
+
+If this is nil (the default), the direction of each paragraph is
+determined by the first strong directional character of its text.
+The values of `right-to-left' and `left-to-right' override that.
+Any other value is treated as nil.
+
+This variable has no effect unless the buffer's value of
+\`bidi-display-reordering' is non-nil. */);
+
DEFVAR_PER_BUFFER ("truncate-lines", ¤t_buffer->truncate_lines, Qnil,
doc: /* *Non-nil means do not display continuation lines.
Instead, give each line of text just one screen line.
/* Non-nil means set beginning of lines at the right edge of
windows. */
Lisp_Object direction_reversed;
+ /* If non-nil, specifies which direction of text to force in each
+ paragraph. Nil means determine paragraph direction dynamically
+ for each paragraph. */
+ Lisp_Object paragraph_direction;
/* Non-nil means do selective display;
see doc string in syms_of_buffer (buffer.c) for details. */
Lisp_Object selective_display;
/* For iterating over bidirectional text. */
struct bidi_it bidi_it;
+ bidi_dir_t paragraph_embedding;
};
Lisp_Object Qgrow_only;
Lisp_Object Qinhibit_eval_during_redisplay;
Lisp_Object Qbuffer_position, Qposition, Qobject;
+Lisp_Object Qright_to_left, Qleft_to_right;
/* Cursor shapes */
Lisp_Object Qbar, Qhbar, Qbox, Qhollow;
/* If we are to reorder bidirectional text, init the bidi
iterator. */
if (it->bidi_p)
- bidi_init_it (charpos, bytepos, &it->bidi_it);
+ {
+ /* Note the paragraph direction that this buffer wants to
+ use. */
+ if (EQ (current_buffer->paragraph_direction, Qleft_to_right))
+ it->paragraph_embedding = L2R;
+ else if (EQ (current_buffer->paragraph_direction, Qright_to_left))
+ it->paragraph_embedding = R2L;
+ else
+ it->paragraph_embedding = NEUTRAL_DIR;
+ bidi_init_it (charpos, bytepos, &it->bidi_it);
+ }
/* If a buffer position was specified, set the iterator there,
getting overlays and face properties from that position. */
/* If this is a new paragraph, determine its base
direction (a.k.a. its base embedding level). */
if (it->bidi_it.new_paragraph)
- bidi_paragraph_init (NEUTRAL_DIR, &it->bidi_it);
+ bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it);
bidi_get_next_char_visually (&it->bidi_it);
IT_BYTEPOS (*it) = it->bidi_it.bytepos;
IT_CHARPOS (*it) = it->bidi_it.charpos;
|| FETCH_CHAR (it->bidi_it.bytepos - 1) == '\n'
|| FETCH_CHAR (it->bidi_it.bytepos) == '\n')
{
- /* FIXME: NEUTRAL_DIR below should be user-definable and/or
- come from some ``higher protocol''. */
- bidi_paragraph_init (NEUTRAL_DIR, &it->bidi_it);
+ bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it);
bidi_get_next_char_visually (&it->bidi_it);
}
else
IT_BYTEPOS (*it) = CHAR_TO_BYTE (IT_CHARPOS (*it));
it->bidi_it.charpos = IT_CHARPOS (*it);
it->bidi_it.bytepos = IT_BYTEPOS (*it);
- bidi_paragraph_init (NEUTRAL_DIR, &it->bidi_it);
+ bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it);
do {
/* Now return to buffer position where we were asked to
get the next display element, and produce that. */
staticpro (&previous_help_echo_string);
help_echo_pos = -1;
+ Qright_to_left = intern ("right-to-left");
+ staticpro (&Qright_to_left);
+ Qleft_to_right = intern ("left-to-right");
+ staticpro (&Qleft_to_right);
+
#ifdef HAVE_WINDOW_SYSTEM
DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
doc: /* *Non-nil means draw block cursor as wide as the glyph under it.