Now on revision 105225. ------------------------------------------------------------ revno: 105225 fixes bug(s): http://debbugs.gnu.org/8460 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Fri 2011-07-15 14:57:20 +0200 message: `lexical-binding' doc clarification * lread.c (syms_of_lread): Clarify that is isn't only `eval-buffer' and `eval-defun' that's affected by `lexical-binding'. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2011-07-15 10:50:03 +0000 +++ src/ChangeLog 2011-07-15 12:57:20 +0000 @@ -1,3 +1,9 @@ +2011-07-15 Lars Magne Ingebrigtsen + + * lread.c (syms_of_lread): Clarify that is isn't only + `eval-buffer' and `eval-defun' that's affected by + `lexical-binding' (bug#8460). + 2011-07-15 Eli Zaretskii * xdisp.c (move_it_in_display_line_to): Fix vertical motion with === modified file 'src/lread.c' --- src/lread.c 2011-07-10 08:20:10 +0000 +++ src/lread.c 2011-07-15 12:57:20 +0000 @@ -4510,9 +4510,11 @@ staticpro (&Qlexical_binding); DEFVAR_LISP ("lexical-binding", Vlexical_binding, doc: /* If non-nil, use lexical binding when evaluating code. -This only applies to code evaluated by `eval-buffer' and `eval-region'. -This variable is automatically set from the file variables of an interpreted - Lisp file read using `load'. */); +This applies to code evaluated by `eval-buffer' and `eval-region' and +other commands that call these functions, like `eval-defun' and +the like. +This variable is automatically set from the file variables of an +interpreted Lisp file read using `load'. */); Fmake_variable_buffer_local (Qlexical_binding); DEFVAR_LISP ("eval-buffer-list", Veval_buffer_list, ------------------------------------------------------------ revno: 105224 fixes bug(s): http://debbugs.gnu.org/8459 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Fri 2011-07-15 14:45:51 +0200 message: * variables.texi (Lexical Binding): Mention `defcustom'. diff: === modified file 'doc/lispref/variables.texi' --- doc/lispref/variables.texi 2011-07-12 17:33:18 +0000 +++ doc/lispref/variables.texi 2011-07-15 12:45:51 +0000 @@ -1099,11 +1099,12 @@ @node Lexical Binding @subsection Use of Lexical Scoping -Emacs Lisp can be evaluated in two different modes: in dynamic binding mode or -lexical binding mode. In dynamic binding mode, all local variables use dynamic -scoping, whereas in lexical binding mode variables that have been declared -@dfn{special} (i.e., declared with @code{defvar} or @code{defconst}) use -dynamic scoping and all others use lexical scoping. +Emacs Lisp can be evaluated in two different modes: in dynamic binding +mode or lexical binding mode. In dynamic binding mode, all local +variables use dynamic scoping, whereas in lexical binding mode +variables that have been declared @dfn{special} (i.e., declared with +@code{defvar}, @code{defcustom} or @code{defconst}) use dynamic +scoping and all others use lexical scoping. @defvar lexical-binding When non-nil, evaluation of Lisp code uses lexical scoping for non-special ------------------------------------------------------------ revno: 105223 committer: Eli Zaretskii branch nick: trunk timestamp: Fri 2011-07-15 13:50:03 +0300 message: Fix vertical cursor motion in Speedbar frames under bidi display. src/xdisp.c (move_it_in_display_line_to): Fix vertical motion with bidi redisplay when a line includes both an image and is truncated. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2011-07-15 02:18:02 +0000 +++ src/ChangeLog 2011-07-15 10:50:03 +0000 @@ -1,3 +1,9 @@ +2011-07-15 Eli Zaretskii + + * xdisp.c (move_it_in_display_line_to): Fix vertical motion with + bidi redisplay when a line includes both an image and is + truncated. + 2011-07-14 Paul Eggert Fix minor problems found by static checking. === modified file 'src/xdisp.c' --- src/xdisp.c 2011-07-14 21:34:18 +0000 +++ src/xdisp.c 2011-07-15 10:50:03 +0000 @@ -7928,7 +7928,14 @@ || IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) { if (!get_next_display_element (it) - || BUFFER_POS_REACHED_P ()) + || BUFFER_POS_REACHED_P () + /* If we are past TO_CHARPOS, but never saw any + character positions smaller than TO_CHARPOS, + return MOVE_POS_MATCH_OR_ZV, like the + unidirectional display did. */ + || ((op & MOVE_TO_POS) != 0 + && !saw_smaller_pos + && IT_CHARPOS (*it) > to_charpos)) { result = MOVE_POS_MATCH_OR_ZV; break; @@ -7939,6 +7946,13 @@ break; } } + else if ((op & MOVE_TO_POS) != 0 + && !saw_smaller_pos + && IT_CHARPOS (*it) > to_charpos) + { + result = MOVE_POS_MATCH_OR_ZV; + break; + } result = MOVE_LINE_TRUNCATED; break; } ------------------------------------------------------------ revno: 105222 committer: martin rudalics branch nick: trunk timestamp: Fri 2011-07-15 09:12:09 +0200 message: Fix pop-to-buffer call in switch-to-buffer. * window.el (switch-to-buffer): Call pop-to-buffer with normalized buffer argument (Bug#9083) and self-identifying label argument. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-07-15 02:16:55 +0000 +++ lisp/ChangeLog 2011-07-15 07:12:09 +0000 @@ -1,3 +1,8 @@ +2011-07-15 Martin Rudalics + + * window.el (switch-to-buffer): Call pop-to-buffer with normalized + buffer argument (Bug#9083) and self-identifying label argument. + 2011-07-15 Glenn Morris * emacs-lisp/debug.el (debug): Doc fix. (Bug#8273) === modified file 'lisp/window.el' --- lisp/window.el 2011-07-14 08:30:34 +0000 +++ lisp/window.el 2011-07-15 07:12:09 +0000 @@ -5953,13 +5953,13 @@ (list (read-buffer-to-switch "Switch to buffer: ") nil nil)) (let ((buffer (window-normalize-buffer-to-switch-to buffer-or-name))) (if (null force-same-window) - (pop-to-buffer buffer-or-name - '(same-window (reuse-window-dedicated . weak)) - norecord nil) + (pop-to-buffer + buffer '(same-window (reuse-window-dedicated . weak)) + norecord 'switch-to-buffer) (cond ;; Don't call set-window-buffer if it's not needed since it ;; might signal an error (e.g. if the window is dedicated). - ((eq buffer (window-buffer)) nil) + ((eq buffer (window-buffer))) ((window-minibuffer-p) (error "Cannot switch buffers in minibuffer window")) ((eq (window-dedicated-p) t) ------------------------------------------------------------ revno: 105221 committer: Glenn Morris branch nick: trunk timestamp: Thu 2011-07-14 22:18:02 -0400 message: No need for ChangeLog entry about quickly reverted change. (Also confusing since the original ChangeLog entry was removed.) diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2011-07-14 21:43:31 +0000 +++ src/ChangeLog 2011-07-15 02:18:02 +0000 @@ -12,9 +12,6 @@ 2011-07-14 Lars Magne Ingebrigtsen - * data.c (Fcdr, Fcar): Revert the last change, since it didn't - really clarify much. - * search.c (Fre_search_backward): Mention `case-fold-search' in all the re_search_* functions (bug#8138). ------------------------------------------------------------ revno: 105220 committer: Glenn Morris branch nick: trunk timestamp: Thu 2011-07-14 22:16:55 -0400 message: * lisp/emacs-lisp/debug.el (debug): Doc fix. (Bug#8273) diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-07-14 17:43:29 +0000 +++ lisp/ChangeLog 2011-07-15 02:16:55 +0000 @@ -1,3 +1,7 @@ +2011-07-15 Glenn Morris + + * emacs-lisp/debug.el (debug): Doc fix. (Bug#8273) + 2011-07-14 Lars Magne Ingebrigtsen * man.el (Man-fontify-manpage): Fix message when formatting the === modified file 'lisp/emacs-lisp/debug.el' --- lisp/emacs-lisp/debug.el 2011-06-15 18:39:04 +0000 +++ lisp/emacs-lisp/debug.el 2011-07-15 02:16:55 +0000 @@ -102,7 +102,7 @@ (setq debugger 'debug) ;;;###autoload (defun debug (&rest debugger-args) - "Enter debugger. To return, type \\`\\[debugger-continue]'. + "Enter debugger. \\`\\[debugger-continue]' returns from the debugger. Arguments are mainly for use when this is called from the internals of the evaluator. ------------------------------------------------------------ revno: 105219 committer: Glenn Morris branch nick: trunk timestamp: Thu 2011-07-14 22:15:05 -0400 message: * admin/notes/bugtracker: How to add new tags. diff: === modified file 'admin/notes/bugtracker' --- admin/notes/bugtracker 2011-05-14 19:11:47 +0000 +++ admin/notes/bugtracker 2011-07-15 02:15:05 +0000 @@ -632,3 +632,11 @@ Then if you do all your testing with 'Package: mytest', the resulting mails should only go to your email address. + +** Adding new tags + +Add them to @gTags in /etc/debbugs/config. +I think you also have to add them to 'tags' and 'tags_single_letter' +in /usr/share/perl5/Debbugs/Config.pm. +And update /var/www/Developer.html with a description of what the tag means. +And the "valid tags" list in /var/www/index.html. ------------------------------------------------------------ revno: 105218 committer: Katsumi Yamaoka branch nick: trunk timestamp: Thu 2011-07-14 22:20:24 +0000 message: lisp/gnus/ChangeLog (2011-07-14): Fix function name. diff: === modified file 'lisp/gnus/ChangeLog' --- lisp/gnus/ChangeLog 2011-07-14 14:19:53 +0000 +++ lisp/gnus/ChangeLog 2011-07-14 22:20:24 +0000 @@ -5,7 +5,7 @@ * gnus-int.el (gnus-request-thread): Add group argument. - * gnus-sum.el (gnus-request-thread): Use it. + * gnus-sum.el (gnus-summary-refer-thread): Use it. 2011-07-10 Lars Magne Ingebrigtsen ------------------------------------------------------------ revno: 105217 [merge] committer: Paul Eggert branch nick: trunk timestamp: Thu 2011-07-14 14:45:06 -0700 message: Merge: Fix minor problems found by static checking. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2011-07-14 20:08:05 +0000 +++ src/ChangeLog 2011-07-14 21:43:31 +0000 @@ -1,3 +1,15 @@ +2011-07-14 Paul Eggert + + Fix minor problems found by static checking. + * bidi.c (bidi_cache_size): Now EMACS_INT, not size_t. + (elsz): Now a signed constant, not a size_t var. We prefer signed + types to unsigned, to avoid integer comparison confusion. Without + this change, GCC 4.6.1 with -Wunsafe-loop-optimizations complains + "cannot optimize loop, the loop counter may overflow", a symptom + of the confusion. + * indent.c (Fvertical_motion): Mark locals as initialized. + * xdisp.c (reseat_to_string): Fix pointer signedness issue. + 2011-07-14 Lars Magne Ingebrigtsen * data.c (Fcdr, Fcar): Revert the last change, since it didn't === modified file 'src/bidi.c' --- src/bidi.c 2011-07-14 17:43:50 +0000 +++ src/bidi.c 2011-07-14 21:43:31 +0000 @@ -299,8 +299,8 @@ #define BIDI_CACHE_CHUNK 200 static struct bidi_it *bidi_cache; -static size_t bidi_cache_size = 0; -static size_t elsz = sizeof (struct bidi_it); +static EMACS_INT bidi_cache_size = 0; +enum { elsz = sizeof (struct bidi_it) }; static EMACS_INT bidi_cache_idx; /* next unused cache slot */ static EMACS_INT bidi_cache_last_idx; /* slot of last cache hit */ static EMACS_INT bidi_cache_start = 0; /* start of cache for this === modified file 'src/indent.c' --- src/indent.c 2011-07-14 17:28:42 +0000 +++ src/indent.c 2011-07-14 21:35:23 +0000 @@ -1985,7 +1985,7 @@ struct text_pos pt; struct window *w; Lisp_Object old_buffer; - EMACS_INT old_charpos, old_bytepos; + EMACS_INT old_charpos IF_LINT (= 0), old_bytepos IF_LINT (= 0); struct gcpro gcpro1, gcpro2, gcpro3; Lisp_Object lcols = Qnil; double cols IF_LINT (= 0); === modified file 'src/xdisp.c' --- src/xdisp.c 2011-07-14 17:28:42 +0000 +++ src/xdisp.c 2011-07-14 21:34:18 +0000 @@ -5890,7 +5890,7 @@ if (it->bidi_p) { it->bidi_it.string.lstring = Qnil; - it->bidi_it.string.s = s; + it->bidi_it.string.s = (const unsigned char *) s; it->bidi_it.string.schars = it->end_charpos; it->bidi_it.string.bufpos = 0; it->bidi_it.string.from_disp_str = 0; ------------------------------------------------------------ revno: 105216 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 22:08:05 +0200 message: * data.c (Fcdr, Fcar): Revert the last change, since it didn't really clarify much. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2011-07-14 18:45:36 +0000 +++ src/ChangeLog 2011-07-14 20:08:05 +0000 @@ -1,15 +1,14 @@ 2011-07-14 Lars Magne Ingebrigtsen + * data.c (Fcdr, Fcar): Revert the last change, since it didn't + really clarify much. + * search.c (Fre_search_backward): Mention `case-fold-search' in all the re_search_* functions (bug#8138). * keyboard.c (Fopen_dribble_file): Document when the file is closed (bug#8056). -2011-07-14 Adam Sjøgren - - * data.c (car, cdr): add functionality hints to documentation. - 2011-07-14 Eli Zaretskii * bidi.c (bidi_dump_cached_states): Fix format of displaying === modified file 'src/data.c' --- src/data.c 2011-07-14 18:29:19 +0000 +++ src/data.c 2011-07-14 20:08:05 +0000 @@ -463,7 +463,7 @@ /* Extract and set components of lists */ DEFUN ("car", Fcar, Scar, 1, 1, 0, - doc: /* Return the car (first element) of LIST. If arg is nil, return nil. + doc: /* Return the car of LIST. If arg is nil, return nil. Error if arg is not nil and not a cons cell. See also `car-safe'. See Info node `(elisp)Cons Cells' for a discussion of related basic @@ -481,7 +481,7 @@ } DEFUN ("cdr", Fcdr, Scdr, 1, 1, 0, - doc: /* Return the cdr (rest) of LIST. If arg is nil, return nil. + doc: /* Return the cdr of LIST. If arg is nil, return nil. Error if arg is not nil and not a cons cell. See also `cdr-safe'. See Info node `(elisp)Cons Cells' for a discussion of related basic ------------------------------------------------------------ revno: 105215 fixes bug(s): http://debbugs.gnu.org/8138 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 20:45:36 +0200 message: Mention `case-fold-search' in all the re_search_* functions diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2011-07-14 18:34:54 +0000 +++ src/ChangeLog 2011-07-14 18:45:36 +0000 @@ -1,5 +1,8 @@ 2011-07-14 Lars Magne Ingebrigtsen + * search.c (Fre_search_backward): Mention `case-fold-search' in + all the re_search_* functions (bug#8138). + * keyboard.c (Fopen_dribble_file): Document when the file is closed (bug#8056). === modified file 'src/search.c' --- src/search.c 2011-06-24 21:25:22 +0000 +++ src/search.c 2011-07-14 18:45:36 +0000 @@ -2284,6 +2284,10 @@ Optional third argument, if t, means if fail just return nil (no error). If not nil and not t, move to limit of search and return nil. Optional fourth argument is repeat count--search for successive occurrences. + +Search case-sensitivity is determined by the value of the variable +`case-fold-search', which see. + See also the functions `match-beginning', `match-end', `match-string', and `replace-match'. */) (Lisp_Object regexp, Lisp_Object bound, Lisp_Object noerror, Lisp_Object count) @@ -2300,6 +2304,10 @@ Optional third argument, if t, means if fail just return nil (no error). If not nil and not t, move to limit of search and return nil. Optional fourth argument is repeat count--search for successive occurrences. + +Search case-sensitivity is determined by the value of the variable +`case-fold-search', which see. + See also the functions `match-beginning', `match-end', `match-string', and `replace-match'. */) (Lisp_Object regexp, Lisp_Object bound, Lisp_Object noerror, Lisp_Object count) @@ -2319,6 +2327,10 @@ Optional third argument, if t, means if fail just return nil (no error). If not nil and not t, move to limit of search and return nil. Optional fourth argument is repeat count--search for successive occurrences. + +Search case-sensitivity is determined by the value of the variable +`case-fold-search', which see. + See also the functions `match-beginning', `match-end', `match-string', and `replace-match'. */) (Lisp_Object regexp, Lisp_Object bound, Lisp_Object noerror, Lisp_Object count) @@ -2336,6 +2348,10 @@ Optional third argument, if t, means if fail just return nil (no error). If not nil and not t, move to limit of search and return nil. Optional fourth argument is repeat count--search for successive occurrences. + +Search case-sensitivity is determined by the value of the variable +`case-fold-search', which see. + See also the functions `match-beginning', `match-end', `match-string', and `replace-match'. */) (Lisp_Object regexp, Lisp_Object bound, Lisp_Object noerror, Lisp_Object count) ------------------------------------------------------------ revno: 105214 fixes bug(s): http://debbugs.gnu.org/8056 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 20:37:53 +0200 message: Manual fix for the dribble file * trouble.texi (Checklist): Use an `M-x' example instead of an Emacs Lisp form to switch on the dribble file. diff: === modified file 'doc/emacs/ChangeLog' --- doc/emacs/ChangeLog 2011-07-13 21:38:56 +0000 +++ doc/emacs/ChangeLog 2011-07-14 18:37:53 +0000 @@ -1,3 +1,8 @@ +2011-07-14 Lars Magne Ingebrigtsen + + * trouble.texi (Checklist): Use an `M-x' example instead of an + Emacs Lisp form to switch on the dribble file (bug#8056). + 2011-07-13 Lars Magne Ingebrigtsen * custom.texi (Hooks): Mention buffer-local hooks (bug#6218). === modified file 'doc/emacs/trouble.texi' --- doc/emacs/trouble.texi 2011-05-17 02:26:56 +0000 +++ doc/emacs/trouble.texi 2011-07-14 18:37:53 +0000 @@ -698,15 +698,8 @@ @cindex dribble file @cindex logging keystrokes One way to record the input to Emacs precisely is to write a dribble -file. To start the file, execute the Lisp expression - -@example -(open-dribble-file "~/dribble") -@end example - -@noindent -using @kbd{M-:} or from the @samp{*scratch*} buffer just after -starting Emacs. From then on, Emacs copies all your input to the +file. To start the file, use the @kbd{M-x open-dribble-file +@key{RET}} command. From then on, Emacs copies all your input to the specified dribble file until the Emacs process is killed. @item ------------------------------------------------------------ revno: 105213 fixes bug(s): http://debbugs.gnu.org/8056 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 20:34:54 +0200 message: * keyboard.c (Fopen_dribble_file): Document when the file is closed. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2011-07-14 18:29:19 +0000 +++ src/ChangeLog 2011-07-14 18:34:54 +0000 @@ -1,3 +1,8 @@ +2011-07-14 Lars Magne Ingebrigtsen + + * keyboard.c (Fopen_dribble_file): Document when the file is + closed (bug#8056). + 2011-07-14 Adam Sjøgren * data.c (car, cdr): add functionality hints to documentation. === modified file 'src/keyboard.c' --- src/keyboard.c 2011-07-02 23:40:04 +0000 +++ src/keyboard.c 2011-07-14 18:34:54 +0000 @@ -10643,7 +10643,8 @@ DEFUN ("open-dribble-file", Fopen_dribble_file, Sopen_dribble_file, 1, 1, "FOpen dribble file: ", doc: /* Start writing all keyboard characters to a dribble file called FILE. -If FILE is nil, close any open dribble file. */) +If FILE is nil, close any open dribble file. +The file will be closed when Emacs exits. */) (Lisp_Object file) { if (dribble) ------------------------------------------------------------ revno: 105212 author: Adam Sjøgren committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 20:29:19 +0200 message: * data.c (car, cdr): add functionality hints to documentation. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2011-07-14 17:43:50 +0000 +++ src/ChangeLog 2011-07-14 18:29:19 +0000 @@ -1,3 +1,7 @@ +2011-07-14 Adam Sjøgren + + * data.c (car, cdr): add functionality hints to documentation. + 2011-07-14 Eli Zaretskii * bidi.c (bidi_dump_cached_states): Fix format of displaying === modified file 'src/data.c' --- src/data.c 2011-07-10 08:20:10 +0000 +++ src/data.c 2011-07-14 18:29:19 +0000 @@ -463,7 +463,7 @@ /* Extract and set components of lists */ DEFUN ("car", Fcar, Scar, 1, 1, 0, - doc: /* Return the car of LIST. If arg is nil, return nil. + doc: /* Return the car (first element) of LIST. If arg is nil, return nil. Error if arg is not nil and not a cons cell. See also `car-safe'. See Info node `(elisp)Cons Cells' for a discussion of related basic @@ -481,7 +481,7 @@ } DEFUN ("cdr", Fcdr, Scdr, 1, 1, 0, - doc: /* Return the cdr of LIST. If arg is nil, return nil. + doc: /* Return the cdr (rest) of LIST. If arg is nil, return nil. Error if arg is not nil and not a cons cell. See also `cdr-safe'. See Info node `(elisp)Cons Cells' for a discussion of related basic ------------------------------------------------------------ revno: 105211 fixes bug(s): http://debbugs.gnu.org/7929 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 19:43:29 +0200 message: * man.el (Man-fontify-manpage): Fix message when formatting the man page. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-07-14 17:39:00 +0000 +++ lisp/ChangeLog 2011-07-14 17:43:29 +0000 @@ -1,3 +1,8 @@ +2011-07-14 Lars Magne Ingebrigtsen + + * man.el (Man-fontify-manpage): Fix message when formatting the + man page (bug#7929). + 2011-07-14 Eli Zaretskii * buff-menu.el (Buffer-menu-buffer+size): Accept an additional === modified file 'lisp/man.el' --- lisp/man.el 2011-07-14 17:39:00 +0000 +++ lisp/man.el 2011-07-14 17:43:29 +0000 @@ -1108,7 +1108,7 @@ (put-text-property (match-beginning 0) (match-end 0) 'face Man-overstrike-face))) - (message "%s man page formatted" Man-arguments)) + (message "%s man page formatted" (Man-page-from-arguments Man-arguments))) (defun Man-highlight-references (&optional xref-man-type) "Highlight the references on mouse-over. @@ -1260,16 +1260,7 @@ (let ((args Man-arguments)) (kill-buffer (current-buffer)) (error "Can't find the %s manpage" - ;; Skip arguments and only print the page name. - (mapconcat - 'identity - (delete nil - (mapcar - (lambda (elem) - (and (not (string-match "^-" elem)) - elem)) - (split-string args " "))) - " "))) + (Man-page-from-arguments args))) (set-buffer-modified-p nil)))) ;; Restore case-fold-search before calling ;; Man-notify-when-ready because it may switch buffers. @@ -1281,6 +1272,18 @@ (error "%s" err-mess)) )))) +(defun Man-page-from-arguments (args) + ;; Skip arguments and only print the page name. + (mapconcat + 'identity + (delete nil + (mapcar + (lambda (elem) + (and (not (string-match "^-" elem)) + elem)) + (split-string args " "))) + " ")) + ;; ====================================================================== ;; set up manual mode in buffer and build alists ------------------------------------------------------------ revno: 105210 committer: Eli Zaretskii branch nick: trunk timestamp: Thu 2011-07-14 20:43:50 +0300 message: Fix format conversion in bidi.c. src/bidi.c (bidi_dump_cached_states): Fix format of displaying bidi_cache_idx. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2011-07-14 17:28:42 +0000 +++ src/ChangeLog 2011-07-14 17:43:50 +0000 @@ -1,5 +1,8 @@ 2011-07-14 Eli Zaretskii + * bidi.c (bidi_dump_cached_states): Fix format of displaying + bidi_cache_idx. + Support bidi reordering of display and overlay strings. * xdisp.c (compute_display_string_pos) (compute_display_string_end): Accept additional argument STRING. === modified file 'src/bidi.c' --- src/bidi.c 2011-07-14 17:28:42 +0000 +++ src/bidi.c 2011-07-14 17:43:50 +0000 @@ -2308,7 +2308,7 @@ fprintf (stderr, "The cache is empty.\n"); return; } - fprintf (stderr, "Total of %d state%s in cache:\n", + fprintf (stderr, "Total of %"pD"d state%s in cache:\n", bidi_cache_idx, bidi_cache_idx == 1 ? "" : "s"); for (i = bidi_cache[bidi_cache_idx - 1].charpos; i > 0; i /= 10) ------------------------------------------------------------ revno: 105209 fixes bug(s): http://debbugs.gnu.org/6935 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 19:39:00 +0200 message: Only output the man page name on failures * man.el (Man-bgproc-sentinel): Skip any arguments and only output the man page name. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-07-14 17:28:42 +0000 +++ lisp/ChangeLog 2011-07-14 17:39:00 +0000 @@ -10,6 +10,9 @@ 2011-07-14 Lars Magne Ingebrigtsen + * man.el (Man-bgproc-sentinel): Skip any arguments and only output + the man page name (bug#7929). + * image.el (put-image): Mention the `put-image' overlay property (bug#7834). === modified file 'lisp/man.el' --- lisp/man.el 2011-07-03 01:35:35 +0000 +++ lisp/man.el 2011-07-14 17:39:00 +0000 @@ -1257,12 +1257,20 @@ (Man-mode) (if (not Man-page-list) - (let ((args Man-arguments)) + (let ((args Man-arguments)) (kill-buffer (current-buffer)) - (error "Can't find the %s manpage" args))) - - (set-buffer-modified-p nil) - )) + (error "Can't find the %s manpage" + ;; Skip arguments and only print the page name. + (mapconcat + 'identity + (delete nil + (mapcar + (lambda (elem) + (and (not (string-match "^-" elem)) + elem)) + (split-string args " "))) + " "))) + (set-buffer-modified-p nil)))) ;; Restore case-fold-search before calling ;; Man-notify-when-ready because it may switch buffers. ------------------------------------------------------------ revno: 105208 [merge] fixes bug(s): http://debbugs.gnu.org/7616 http://debbugs.gnu.org/8133 http://debbugs.gnu.org/8867 committer: Eli Zaretskii branch nick: trunk timestamp: Thu 2011-07-14 20:28:42 +0300 message: Support bidi reordering of overlay and display strings. Fix bugs #7616, #8133, #8867. src/xdisp.c (compute_display_string_pos) (compute_display_string_end): Accept additional argument STRING. (init_iterator, reseat_1): Initialize bidi_it->string.s to NULL. (reseat_to_string): Initialize bidi_it->string.s and bidi_it->string.schars. (Fcurrent_bidi_paragraph_direction): Initialize itb.string.s to NULL (avoids a crash in bidi_paragraph_init). Initialize itb.string.lstring. (init_iterator): Call bidi_init_it only of a valid buffer position was specified. Initialize paragraph_embedding to L2R. (reseat_to_string): Initialize the bidi iterator. (display_string): If we need to ignore text properties of LISP_STRING, set IT->stop_charpos to IT->end_charpos. (The original value of -1 will not work with bidi.) (compute_display_string_pos): First arg is now struct `text_pos *'; all callers changed. Support display properties on Lisp strings. (compute_display_string_end): Support display properties on Lisp strings. (init_iterator, reseat_1, reseat_to_string): Initialize the string.bufpos member to 0 (zero, for compatibility with IT_CHARPOS when iterating on a string not from display properties). (compute_display_string_pos, compute_display_string_end): Fix calculation of the object to scan. Fixes an error when using arrow keys. (next_element_from_buffer): Don't abort when IT_CHARPOS is before base_level_stop; instead, set base_level_stop to BEGV. Fixes crashes in vertical-motion. (next_element_from_buffer): Improve commentary for when the iterator is before prev_stop. (init_iterator): Initialize bidi_p from the default value of bidi-display-reordering, not from buffer-local value. Use the buffer-local value only if initializing for buffer iteration. (handle_invisible_prop): Support invisible properties on strings that are being bidi-reordered. (set_iterator_to_next): Support bidi reordering of C strings and Lisp strings. (next_element_from_string): Support bidi reordering of Lisp strings. (handle_stop_backwards): Support Lisp strings as well. (display_string): Support display of R2L glyph rows. Use IT_STRING_CHARPOS when displaying from a Lisp string. (init_iterator): Don't initialize it->bidi_p for strings here. (reseat_to_string): Initialize it->bidi_p for strings here. (next_element_from_string, next_element_from_c_string) (next_element_from_buffer): Add xassert's for correspondence between IT's object being iterated and it->bidi_it.string structure. (face_before_or_after_it_pos): Support bidi iteration. (next_element_from_c_string): Handle the case of the first string character that is not the first one in the visual order. (get_visually_first_element): New function, refactored from common parts of next_element_from_buffer, next_element_from_string, and next_element_from_c_string. (tool_bar_lines_needed, redisplay_tool_bar) (display_menu_bar): Force left-to-right direction. Add a FIXME comment for making that be controlled by a user option. (push_it, pop_it): Save and restore the state of the bidi iterator. Save and restore the bidi_p flag. (pop_it): Iterate out of display property for string iteration as well. (iterate_out_of_display_property): Support iteration over strings. (handle_single_display_spec): Set up it->bidi_it for iteration over a display string, and call bidi_init_it. (handle_single_display_spec, next_overlay_string) (get_overlay_strings_1, push_display_prop): Set up the bidi iterator for displaying display or overlay strings. (forward_to_next_line_start): Don't use the shortcut if bidi-iterating. (back_to_previous_visible_line_start): If handle_display_prop pushed the iterator stack, restore the internal state of the bidi iterator by calling bidi_pop_it same number of times. (reseat_at_next_visible_line_start): If ON_NEWLINE_P is non-zero, and we are bidi-iterating, don't decrement the iterator position; instead, set the first_elt flag in the bidi iterator, to produce the same effect. (reseat_1): Remove redundant setting of string_from_display_prop_p. (push_display_prop): xassert that we are iterating a buffer. (push_it, pop_it): Save and restore paragraph_embedding member. (handle_single_display_spec, next_overlay_string) (get_overlay_strings_1, reseat_1, reseat_to_string) (push_display_prop): Set up the `unibyte' member of bidi_it.string correctly. Don't assume unibyte strings are not bidi-reordered. (compute_display_string_pos) (compute_display_string_end): Fix handling the case of C string. (push_it, pop_it): Save and restore from_disp_prop_p. (handle_single_display_spec, push_display_prop): Set the from_disp_prop_p flag. (get_overlay_strings_1): Reset the from_disp_prop_p flag. (pop_it): Call iterate_out_of_display_property only if we are popping after iteration over a string that came from a display property. Fix a typo in popping stretch info. Add an assertion for verifying that the iterator position is in sync with the bidi iterator. (handle_single_display_spec, get_overlay_strings_1) (push_display_prop): Fix initialization of paragraph direction for string when that of the parent object is not yet determined. (reseat_1): Call bidi_init_it to resync the bidi iterator with IT's position. (Bug#7616) (find_row_edges): If ROW->start.pos gives position smaller than min_pos, use it as ROW->minpos. (Bug#7616) (handle_stop, back_to_previous_visible_line_start, reseat_1): Reset the from_disp_prop_p flag. (SAVE_IT, RESTORE_IT): New macros. (pos_visible_p, face_before_or_after_it_pos) (back_to_previous_visible_line_start) (move_it_in_display_line_to, move_it_in_display_line) (move_it_to, move_it_vertically_backward, move_it_by_lines) (try_scrolling, redisplay_window, display_line): Use them when saving a temporary copy of the iterator and restoring it back. (back_to_previous_visible_line_start, reseat_1) (init_iterator): Empty the bidi cache "stack". (move_it_in_display_line_to): If iterator ended up at EOL, but we never saw any buffer positions smaller than to_charpos, return MOVE_POS_MATCH_OR_ZV. Fixes vertical cursor motion in bidi-reordered lines. (move_it_in_display_line_to): Record prev_method and prev_pos immediately before the call to set_iterator_to_next. Fixes cursor motion in bidi-reordered lines with stretch glyphs and strings displayed in margins. (Bug#8133) (Bug#8867) Return MOVE_POS_MATCH_OR_ZV only if iterator position is past TO_CHARPOS. (pos_visible_p): Support positions in bidi-reordered lines. Save and restore bidi cache. src/bidi.c (bidi_level_of_next_char): clen should be EMACS_NT, not int. (bidi_paragraph_info): Delete unused struct. (bidi_cache_idx, bidi_cache_last_idx): Declare EMACS_INT. (bidi_cache_start): New variable. (bidi_cache_reset): Reset bidi_cache_idx to bidi_cache_start, not to zero. (bidi_cache_fetch_state, bidi_cache_search) (bidi_cache_find_level_change, bidi_cache_iterator_state) (bidi_cache_find, bidi_peek_at_next_level) (bidi_level_of_next_char, bidi_find_other_level_edge) (bidi_move_to_visually_next): Compare cache index with bidi_cache_start rather than with zero. (bidi_fetch_char): Accept new argument STRING; all callers changed. Support iteration over a string. Support strings with display properties. Support unibyte strings. Fix the type of `len' according to what STRING_CHAR_AND_LENGTH expects. (bidi_paragraph_init, bidi_resolve_explicit_1) (bidi_resolve_explicit, bidi_resolve_weak) (bidi_level_of_next_char, bidi_move_to_visually_next): Support iteration over a string. (bidi_set_sor_type, bidi_resolve_explicit_1) (bidi_resolve_explicit, bidi_type_of_next_char): ignore_bn_limit can now be zero (for strings); special values 0 and -1 were changed to -1 and -2, respectively. (bidi_char_at_pos): New function. (bidi_paragraph_init, bidi_resolve_explicit, bidi_resolve_weak): Call it instead of FETCH_MULTIBYTE_CHAR. (bidi_move_to_visually_next): Abort if charpos or bytepos were not initialized to valid values. (bidi_init_it): Don't initialize charpos and bytepos with invalid values. (bidi_level_of_next_char): Allow the sentinel "position" to pass the test for valid cached positions. Fix the logic for looking up the sentinel state in the cache. GCPRO the Lisp string we are iterating. (bidi_push_it, bidi_pop_it): New functions. (bidi_initialize): Initialize the bidi cache start stack pointer. (bidi_cache_ensure_space): New function, refactored from part of bidi_cache_iterator_state. Don't assume the required size is just one BIDI_CACHE_CHUNK away. (bidi_cache_start_stack, bidi_push_it): Use IT_STACK_SIZE. (bidi_count_bytes, bidi_char_at_pos): New functions. (bidi_cache_search): Don't assume bidi_cache_last_idx is always valid if bidi_cache_idx is valid. (bidi_cache_find_level_change): xassert that bidi_cache_last_idx is valid if it's going to be used. (bidi_shelve_cache, bidi_unshelve_cache): New functions. (bidi_cache_fetch_state, bidi_cache_search) (bidi_cache_find_level_change, bidi_cache_ensure_space) (bidi_cache_iterator_state, bidi_cache_find) (bidi_find_other_level_edge, bidi_cache_start_stack): All variables related to cache indices are now EMACS_INT. src/dispextern.h (struct bidi_string_data): New structure. (struct bidi_it): New member `string'. Make flag members be 1-bit fields, and put them last in the struct. (compute_display_string_pos, compute_display_string_end): Update prototypes. (bidi_push_it, bidi_pop_it): Add prototypes. (struct iterator_stack_entry): New members bidi_p, paragraph_embedding, and from_disp_prop_p. (struct it): Member bidi_p is now a bit field 1 bit wide. (bidi_shelve_cache, bidi_unshelve_cache): Declare prototypes. src/.gdbinit (xvectype, xvector, xcompiled, xchartable, xboolvector) (xpr, xfont, xbacktrace): Use "header.size" when accessing vectors and vector-like objects. src/dispnew.c (buffer_posn_from_coords): Save and restore the bidi cache around display iteration. src/window.c (Fwindow_end, window_scroll_pixel_based) (displayed_window_lines, Frecenter): Save and restore the bidi cache around display iteration. lisp/buff-menu.el (Buffer-menu-buffer+size): Accept an additional argument LRM; if non-nil, append an invisible LRM character to the buffer name. (list-buffers-noselect): Call Buffer-menu-buffer+size with the last argument non-nil, when formatting buffer names. (Buffer-menu-mode, list-buffers-noselect): Force left-to-right paragraph direction. doc/lispref/display.texi (Other Display Specs): Document that `left-fringe' and `right-fringe' display specifications are of the "replacing" kind. diff: === modified file 'doc/lispref/ChangeLog' --- doc/lispref/ChangeLog 2011-07-14 00:02:09 +0000 +++ doc/lispref/ChangeLog 2011-07-14 17:28:42 +0000 @@ -1,3 +1,9 @@ +2011-07-14 Eli Zaretskii + + * display.texi (Other Display Specs): Document that `left-fringe' + and `right-fringe' display specifications are of the "replacing" + kind. + 2011-07-14 Lars Magne Ingebrigtsen * help.texi (Documentation Basics): Add a link to the Function === modified file 'doc/lispref/display.texi' --- doc/lispref/display.texi 2011-07-12 22:09:28 +0000 +++ doc/lispref/display.texi 2011-07-14 17:28:42 +0000 @@ -3899,7 +3899,8 @@ @itemx (right-fringe @var{bitmap} @r{[}@var{face}@r{]}) This display specification on any character of a line of text causes the specified @var{bitmap} be displayed in the left or right fringes -for that line. The optional @var{face} specifies the colors to be +for that line, instead of the characters that have the display +specification. The optional @var{face} specifies the colors to be used for the bitmap. @xref{Fringe Bitmaps}, for the details. @item (space-width @var{factor}) === modified file 'etc/NEWS' --- etc/NEWS 2011-07-13 22:00:48 +0000 +++ etc/NEWS 2011-07-14 17:28:42 +0000 @@ -171,7 +171,7 @@ *** Emacs now supports display and editing of bidirectional text. See the node "Bidirectional Editing" in the Emacs Manual for some -initial documentation. +additional documentation. To turn this on in any given buffer, set the buffer-local variable `bidi-display-reordering' to a non-nil value. The default is nil. @@ -190,10 +190,6 @@ bidirectionality" class implementation of the Unicode Bidirectional Algorithm. -Note that some advanced display features, such as overlay strings and -`display' text properties, do not yet work correctly when -bidirectional text is reordered for display. - +++ *** Enhanced support for characters that have no glyphs in available fonts. If a character has no glyphs in any of the available fonts, Emacs by === modified file 'etc/TODO' --- etc/TODO 2011-06-30 02:56:12 +0000 +++ etc/TODO 2011-07-14 17:28:42 +0000 @@ -639,6 +639,37 @@ **** Undo for color-drag face customization. +** Bidirectional editing + +*** Allow the user to control the direction of the UI + +**** Introduce user option to control direction of mode line. +This requires to figure out what to do with unibyte strings that are +used in constructing the mode line. Currently, unibyte strings are +not reordered by bidi.c, without which R2L mode line will not display +correctly. One possibility would be to STRING_SET_MULTIBYTE all Lisp +strings involved in the mode line, and then pass them through bidi.c. + +Another problem is the header line, which is produced by the same +routines as the mode line. While it makes sense to have the mode-line +direction controlled by a single global variable, header lines are +buffer-specific, so they need a separate treatment in this regard. + +**** User options to control direction of menu bar and tool bar. +For the tool bar, it's relatively easy: set it.paragraph_embedding +in redisplay_tool_bar according to the user variable, and make +f->desired_tool_bar_string multibyte with STRING_SET_MULTIBYTE. Some +minor changes will be needed to set the right_box_line_p and +left_box_line_p flags correctly for the R2L tool bar. + +However, it makes no sense to display the tool bar right to left if +the menu bar cannot be displayed in the same direction. + +R2L menu bar is tricky for the same reasons as the mode line. In +addition, toolkit builds create their menu bars in toolkit-specific +parts of code, bypassing xdisp.c, so those parts need to be enhanced +with toolkit-specific code to display the menu bar right to left. + ** ImageMagick support *** image-type-header-regexps priorities the jpeg loader over the @@ -663,8 +694,8 @@ *** Integrate with image-dired. -*** Integrate with docview. - +*** Integrate with docview. + *** Integrate with image-mode. Some work has been done, e.g. M-x image-transform-fit-to-height will fit the image to the height of the Emacs window. === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-07-14 17:20:37 +0000 +++ lisp/ChangeLog 2011-07-14 17:28:42 +0000 @@ -1,3 +1,13 @@ +2011-07-14 Eli Zaretskii + + * buff-menu.el (Buffer-menu-buffer+size): Accept an additional + argument LRM; if non-nil, append an invisible LRM character to the + buffer name. + (list-buffers-noselect): Call Buffer-menu-buffer+size with the + last argument non-nil, when formatting buffer names. + (Buffer-menu-mode, list-buffers-noselect): Force left-to-right + paragraph direction. + 2011-07-14 Lars Magne Ingebrigtsen * image.el (put-image): Mention the `put-image' overlay property === modified file 'lisp/buff-menu.el' --- lisp/buff-menu.el 2011-05-28 20:08:05 +0000 +++ lisp/buff-menu.el 2011-07-14 17:28:42 +0000 @@ -266,7 +266,10 @@ (set (make-local-variable 'buffer-stale-function) (lambda (&optional _noconfirm) 'fast)) (setq truncate-lines t) - (setq buffer-read-only t)) + (setq buffer-read-only t) + ;; Force L2R direction, to avoid messing the display if the first + ;; buffer in the list happens to begin with a strong R2L character. + (setq bidi-paragraph-direction 'left-to-right)) (define-obsolete-variable-alias 'buffer-menu-mode-hook 'Buffer-menu-mode-hook "23.1") @@ -663,7 +666,7 @@ ":" ;; (if (char-displayable-p ?…) "…" ":") ) -(defun Buffer-menu-buffer+size (name size &optional name-props size-props) +(defun Buffer-menu-buffer+size (name size &optional name-props size-props lrm) (if (> (+ (string-width name) (string-width size) 2) Buffer-menu-buffer+size-width) (setq name @@ -678,9 +681,17 @@ (string-width tail) 2)) Buffer-menu-short-ellipsis - tail))) + tail + ;; Append an invisible LRM character to the + ;; buffer's name to avoid ugly display with the + ;; buffer size to the left of the name, when the + ;; name begins with R2L character. + (if lrm (propertize (string ?\x200e) 'invisible t) "")))) ;; Don't put properties on (buffer-name). - (setq name (copy-sequence name))) + (setq name (concat (copy-sequence name) + (if lrm + (propertize (string ?\x200e) 'invisible t) + "")))) (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 @@ -813,6 +824,10 @@ (setq buffer-read-only nil) (erase-buffer) (setq standard-output (current-buffer)) + ;; Force L2R direction, to avoid messing the display if the + ;; first buffer in the list happens to begin with a strong R2L + ;; character. + (setq bidi-paragraph-direction 'left-to-right) (unless Buffer-menu-use-header-line ;; Use U+2014 (EM DASH) to underline if possible, else use ASCII ;; (i.e. U+002D, HYPHEN-MINUS). @@ -914,7 +929,8 @@ (max (length size) 3) 2)) name - "mouse-2: select this buffer")))) + "mouse-2: select this buffer")) + nil t)) " " (if (> (string-width (nth 4 buffer)) Buffer-menu-mode-width) (truncate-string-to-width (nth 4 buffer) === modified file 'src/.gdbinit' --- src/.gdbinit 2011-03-11 00:19:57 +0000 +++ src/.gdbinit 2011-06-18 13:28:53 +0000 @@ -677,7 +677,7 @@ define xvectype xgetptr $ - set $size = ((struct Lisp_Vector *) $ptr)->size + set $size = ((struct Lisp_Vector *) $ptr)->header.size output ($size & PVEC_FLAG) ? (enum pvec_type) ($size & PVEC_TYPE_MASK) : $size & ~gdb_array_mark_flag echo \n end @@ -818,7 +818,7 @@ define xvector xgetptr $ print (struct Lisp_Vector *) $ptr - output ($->size > 50) ? 0 : ($->contents[0])@($->size & ~gdb_array_mark_flag) + output ($->header.size > 50) ? 0 : ($->contents[0])@($->header.size & ~gdb_array_mark_flag) echo \n end document xvector @@ -853,7 +853,7 @@ define xcompiled xgetptr $ print (struct Lisp_Vector *) $ptr - output ($->contents[0])@($->size & 0xff) + output ($->contents[0])@($->header.size & 0xff) end document xcompiled Print $ as a compiled function pointer. @@ -903,7 +903,7 @@ print (struct Lisp_Char_Table *) $ptr printf "Purpose: " xprintsym $->purpose - printf " %d extra slots", ($->size & 0x1ff) - 68 + printf " %d extra slots", ($->header.size & 0x1ff) - 68 echo \n end document xchartable @@ -927,7 +927,7 @@ define xboolvector xgetptr $ print (struct Lisp_Bool_Vector *) $ptr - output ($->size > 256) ? 0 : ($->data[0])@((($->size & ~gdb_array_mark_flag) + 7)/ 8) + output ($->header.size > 256) ? 0 : ($->data[0])@((($->header.size & ~gdb_array_mark_flag) + 7)/ 8) echo \n end document xboolvector @@ -1093,7 +1093,7 @@ # end end if $type == Lisp_Vectorlike - set $size = ((struct Lisp_Vector *) $ptr)->size + set $size = ((struct Lisp_Vector *) $ptr)->header.size if ($size & PVEC_FLAG) set $vec = (enum pvec_type) ($size & PVEC_TYPE_MASK) if $vec == PVEC_NORMAL_VECTOR @@ -1202,7 +1202,7 @@ define xfont xgetptr $ - set $size = (((struct Lisp_Vector *) $ptr)->size & 0x1FF) + set $size = (((struct Lisp_Vector *) $ptr)->header.size & 0x1FF) if $size == FONT_SPEC_MAX print (struct font_spec *) $ptr else @@ -1229,7 +1229,7 @@ printf "0x%x ", $ptr if $type == Lisp_Vectorlike xgetptr (*$bt->function) - set $size = ((struct Lisp_Vector *) $ptr)->size + set $size = ((struct Lisp_Vector *) $ptr)->header.size output ($size & PVEC_FLAG) ? (enum pvec_type) ($size & PVEC_TYPE_MASK) : $size & ~gdb_array_mark_flag else printf "Lisp type %d", $type === modified file 'src/ChangeLog' --- src/ChangeLog 2011-07-14 13:37:20 +0000 +++ src/ChangeLog 2011-07-14 17:28:42 +0000 @@ -1,3 +1,209 @@ +2011-07-14 Eli Zaretskii + + Support bidi reordering of display and overlay strings. + * xdisp.c (compute_display_string_pos) + (compute_display_string_end): Accept additional argument STRING. + (init_iterator, reseat_1): Initialize bidi_it->string.s to NULL. + (reseat_to_string): Initialize bidi_it->string.s and + bidi_it->string.schars. + (Fcurrent_bidi_paragraph_direction): Initialize itb.string.s to + NULL (avoids a crash in bidi_paragraph_init). Initialize + itb.string.lstring. + (init_iterator): Call bidi_init_it only of a valid + buffer position was specified. Initialize paragraph_embedding to + L2R. + (reseat_to_string): Initialize the bidi iterator. + (display_string): If we need to ignore text properties of + LISP_STRING, set IT->stop_charpos to IT->end_charpos. (The + original value of -1 will not work with bidi.) + (compute_display_string_pos): First arg is now struct + `text_pos *'; all callers changed. Support display properties on + Lisp strings. + (compute_display_string_end): Support display properties on Lisp + strings. + (init_iterator, reseat_1, reseat_to_string): Initialize the + string.bufpos member to 0 (zero, for compatibility with IT_CHARPOS + when iterating on a string not from display properties). + (compute_display_string_pos, compute_display_string_end): Fix + calculation of the object to scan. Fixes an error when using + arrow keys. + (next_element_from_buffer): Don't abort when IT_CHARPOS is before + base_level_stop; instead, set base_level_stop to BEGV. Fixes + crashes in vertical-motion. + (next_element_from_buffer): Improve commentary for when + the iterator is before prev_stop. + (init_iterator): Initialize bidi_p from the default value of + bidi-display-reordering, not from buffer-local value. Use the + buffer-local value only if initializing for buffer iteration. + (handle_invisible_prop): Support invisible properties on strings + that are being bidi-reordered. + (set_iterator_to_next): Support bidi reordering of C strings and + Lisp strings. + (next_element_from_string): Support bidi reordering of Lisp + strings. + (handle_stop_backwards): Support Lisp strings as well. + (display_string): Support display of R2L glyph rows. Use + IT_STRING_CHARPOS when displaying from a Lisp string. + (init_iterator): Don't initialize it->bidi_p for strings + here. + (reseat_to_string): Initialize it->bidi_p for strings here. + (next_element_from_string, next_element_from_c_string) + (next_element_from_buffer): Add xassert's for correspondence + between IT's object being iterated and it->bidi_it.string + structure. + (face_before_or_after_it_pos): Support bidi iteration. + (next_element_from_c_string): Handle the case of the first string + character that is not the first one in the visual order. + (get_visually_first_element): New function, refactored from common + parts of next_element_from_buffer, next_element_from_string, and + next_element_from_c_string. + (tool_bar_lines_needed, redisplay_tool_bar) + (display_menu_bar): Force left-to-right direction. Add a FIXME + comment for making that be controlled by a user option. + (push_it, pop_it): Save and restore the state of the + bidi iterator. Save and restore the bidi_p flag. + (pop_it): Iterate out of display property for string iteration as + well. + (iterate_out_of_display_property): Support iteration over strings. + (handle_single_display_spec): Set up it->bidi_it for iteration + over a display string, and call bidi_init_it. + (handle_single_display_spec, next_overlay_string) + (get_overlay_strings_1, push_display_prop): Set up the bidi + iterator for displaying display or overlay strings. + (forward_to_next_line_start): Don't use the shortcut if + bidi-iterating. + (back_to_previous_visible_line_start): If handle_display_prop + pushed the iterator stack, restore the internal state of the bidi + iterator by calling bidi_pop_it same number of times. + (reseat_at_next_visible_line_start): If ON_NEWLINE_P is non-zero, + and we are bidi-iterating, don't decrement the iterator position; + instead, set the first_elt flag in the bidi iterator, to produce + the same effect. + (reseat_1): Remove redundant setting of string_from_display_prop_p. + (push_display_prop): xassert that we are iterating a buffer. + (push_it, pop_it): Save and restore paragraph_embedding member. + (handle_single_display_spec, next_overlay_string) + (get_overlay_strings_1, reseat_1, reseat_to_string) + (push_display_prop): Set up the `unibyte' member of bidi_it.string + correctly. Don't assume unibyte strings are not bidi-reordered. + (compute_display_string_pos) + (compute_display_string_end): Fix handling the case of C string. + (push_it, pop_it): Save and restore from_disp_prop_p. + (handle_single_display_spec, push_display_prop): Set the + from_disp_prop_p flag. + (get_overlay_strings_1): Reset the from_disp_prop_p flag. + (pop_it): Call iterate_out_of_display_property only if we are + popping after iteration over a string that came from a display + property. Fix a typo in popping stretch info. Add an assertion + for verifying that the iterator position is in sync with the bidi + iterator. + (handle_single_display_spec, get_overlay_strings_1) + (push_display_prop): Fix initialization of paragraph direction for + string when that of the parent object is not yet determined. + (reseat_1): Call bidi_init_it to resync the bidi + iterator with IT's position. (Bug#7616) + (find_row_edges): If ROW->start.pos gives position + smaller than min_pos, use it as ROW->minpos. (Bug#7616) + (handle_stop, back_to_previous_visible_line_start, reseat_1): + Reset the from_disp_prop_p flag. + (SAVE_IT, RESTORE_IT): New macros. + (pos_visible_p, face_before_or_after_it_pos) + (back_to_previous_visible_line_start) + (move_it_in_display_line_to, move_it_in_display_line) + (move_it_to, move_it_vertically_backward, move_it_by_lines) + (try_scrolling, redisplay_window, display_line): Use them when + saving a temporary copy of the iterator and restoring it back. + (back_to_previous_visible_line_start, reseat_1) + (init_iterator): Empty the bidi cache "stack". + (move_it_in_display_line_to): If iterator ended up at + EOL, but we never saw any buffer positions smaller than + to_charpos, return MOVE_POS_MATCH_OR_ZV. Fixes vertical cursor + motion in bidi-reordered lines. + (move_it_in_display_line_to): Record prev_method and prev_pos + immediately before the call to set_iterator_to_next. Fixes cursor + motion in bidi-reordered lines with stretch glyphs and strings + displayed in margins. (Bug#8133) (Bug#8867) + Return MOVE_POS_MATCH_OR_ZV only if iterator position is past + TO_CHARPOS. + (pos_visible_p): Support positions in bidi-reordered lines. Save + and restore bidi cache. + + * bidi.c (bidi_level_of_next_char): clen should be EMACS_NT, not int. + (bidi_paragraph_info): Delete unused struct. + (bidi_cache_idx, bidi_cache_last_idx): Declare EMACS_INT. + (bidi_cache_start): New variable. + (bidi_cache_reset): Reset bidi_cache_idx to bidi_cache_start, not + to zero. + (bidi_cache_fetch_state, bidi_cache_search) + (bidi_cache_find_level_change, bidi_cache_iterator_state) + (bidi_cache_find, bidi_peek_at_next_level) + (bidi_level_of_next_char, bidi_find_other_level_edge) + (bidi_move_to_visually_next): Compare cache index with + bidi_cache_start rather than with zero. + (bidi_fetch_char): Accept new argument STRING; all callers + changed. Support iteration over a string. Support strings with + display properties. Support unibyte strings. Fix the type of + `len' according to what STRING_CHAR_AND_LENGTH expects. + (bidi_paragraph_init, bidi_resolve_explicit_1) + (bidi_resolve_explicit, bidi_resolve_weak) + (bidi_level_of_next_char, bidi_move_to_visually_next): Support + iteration over a string. + (bidi_set_sor_type, bidi_resolve_explicit_1) + (bidi_resolve_explicit, bidi_type_of_next_char): ignore_bn_limit + can now be zero (for strings); special values 0 and -1 were + changed to -1 and -2, respectively. + (bidi_char_at_pos): New function. + (bidi_paragraph_init, bidi_resolve_explicit, bidi_resolve_weak): + Call it instead of FETCH_MULTIBYTE_CHAR. + (bidi_move_to_visually_next): Abort if charpos or bytepos were not + initialized to valid values. + (bidi_init_it): Don't initialize charpos and bytepos with invalid + values. + (bidi_level_of_next_char): Allow the sentinel "position" to pass + the test for valid cached positions. Fix the logic for looking up + the sentinel state in the cache. GCPRO the Lisp string we are + iterating. + (bidi_push_it, bidi_pop_it): New functions. + (bidi_initialize): Initialize the bidi cache start stack pointer. + (bidi_cache_ensure_space): New function, refactored from part of + bidi_cache_iterator_state. Don't assume the required size is just + one BIDI_CACHE_CHUNK away. + (bidi_cache_start_stack, bidi_push_it): Use IT_STACK_SIZE. + (bidi_count_bytes, bidi_char_at_pos): New functions. + (bidi_cache_search): Don't assume bidi_cache_last_idx is + always valid if bidi_cache_idx is valid. + (bidi_cache_find_level_change): xassert that bidi_cache_last_idx + is valid if it's going to be used. + (bidi_shelve_cache, bidi_unshelve_cache): New functions. + (bidi_cache_fetch_state, bidi_cache_search) + (bidi_cache_find_level_change, bidi_cache_ensure_space) + (bidi_cache_iterator_state, bidi_cache_find) + (bidi_find_other_level_edge, bidi_cache_start_stack): All + variables related to cache indices are now EMACS_INT. + + * dispextern.h (struct bidi_string_data): New structure. + (struct bidi_it): New member `string'. Make flag members be 1-bit + fields, and put them last in the struct. + (compute_display_string_pos, compute_display_string_end): Update + prototypes. + (bidi_push_it, bidi_pop_it): Add prototypes. + (struct iterator_stack_entry): New members bidi_p, + paragraph_embedding, and from_disp_prop_p. + (struct it): Member bidi_p is now a bit field 1 bit wide. + (bidi_shelve_cache, bidi_unshelve_cache): Declare + prototypes. + + * .gdbinit (xvectype, xvector, xcompiled, xchartable, xboolvector) + (xpr, xfont, xbacktrace): Use "header.size" when accessing vectors + and vector-like objects. + + * dispnew.c (buffer_posn_from_coords): Save and restore the bidi + cache around display iteration. + + * window.c (Fwindow_end, window_scroll_pixel_based) + (displayed_window_lines, Frecenter): Save and restore the bidi + cache around display iteration. + 2011-07-14 Lars Magne Ingebrigtsen * editfns.c (Fdelete_region): Clarify the use of the named === modified file 'src/bidi.c' --- src/bidi.c 2011-06-26 17:23:40 +0000 +++ src/bidi.c 2011-07-14 17:28:42 +0000 @@ -1,4 +1,4 @@ -/* Low-level bidirectional buffer-scanning functions for GNU Emacs. +/* Low-level bidirectional buffer/string-scanning functions for GNU Emacs. Copyright (C) 2000-2001, 2004-2005, 2009-2011 Free Software Foundation, Inc. @@ -20,7 +20,7 @@ /* Written by Eli Zaretskii . A sequential implementation of the Unicode Bidirectional algorithm, - as per UAX#9, a part of the Unicode Standard. + (UBA) as per UAX#9, a part of the Unicode Standard. Unlike the reference and most other implementations, this one is designed to be called once for every character in the buffer or @@ -35,11 +35,16 @@ details about its algorithm that finds the next visual-order character by resolving their levels on the fly. - The two other entry points are bidi_paragraph_init and + Two other entry points are bidi_paragraph_init and bidi_mirror_char. The first determines the base direction of a paragraph, while the second returns the mirrored version of its argument character. + A few auxiliary entry points are used to initialize the bidi + iterator for iterating an object (buffer or string), push and pop + the bidi iterator state, and save and restore the state of the bidi + cache. + If you want to understand the code, you will have to read it together with the relevant portions of UAX#9. The comments include references to UAX#9 rules, for that very reason. @@ -66,16 +71,6 @@ #define RLM_CHAR 0x200F #define BIDI_EOB -1 -/* Local data structures. (Look in dispextern.h for the rest.) */ - -/* What we need to know about the current paragraph. */ -struct bidi_paragraph_info { - EMACS_INT start_bytepos; /* byte position where it begins */ - EMACS_INT end_bytepos; /* byte position where it ends */ - int embedding_level; /* its basic embedding level */ - bidi_dir_t base_dir; /* its base direction */ -}; - /* Data type for describing the bidirectional character categories. */ typedef enum { UNKNOWN_BC, @@ -90,43 +85,10 @@ static Lisp_Object paragraph_start_re, paragraph_separate_re; static Lisp_Object Qparagraph_start, Qparagraph_separate; -static void -bidi_initialize (void) -{ - -#include "biditype.h" -#include "bidimirror.h" - - int i; - - bidi_type_table = Fmake_char_table (Qnil, make_number (STRONG_L)); - staticpro (&bidi_type_table); - - for (i = 0; i < sizeof bidi_type / sizeof bidi_type[0]; i++) - char_table_set_range (bidi_type_table, bidi_type[i].from, bidi_type[i].to, - make_number (bidi_type[i].type)); - - bidi_mirror_table = Fmake_char_table (Qnil, Qnil); - staticpro (&bidi_mirror_table); - - for (i = 0; i < sizeof bidi_mirror / sizeof bidi_mirror[0]; i++) - char_table_set (bidi_mirror_table, bidi_mirror[i].from, - make_number (bidi_mirror[i].to)); - - Qparagraph_start = intern ("paragraph-start"); - staticpro (&Qparagraph_start); - paragraph_start_re = Fsymbol_value (Qparagraph_start); - if (!STRINGP (paragraph_start_re)) - paragraph_start_re = build_string ("\f\\|[ \t]*$"); - staticpro (¶graph_start_re); - Qparagraph_separate = intern ("paragraph-separate"); - staticpro (&Qparagraph_separate); - paragraph_separate_re = Fsymbol_value (Qparagraph_separate); - if (!STRINGP (paragraph_separate_re)) - paragraph_separate_re = build_string ("[ \t\f]*$"); - staticpro (¶graph_separate_re); - bidi_initialized = 1; -} + +/*********************************************************************** + Utilities + ***********************************************************************/ /* Return the bidi type of a character CH, subject to the current directional OVERRIDE. */ @@ -243,6 +205,77 @@ return c; } +/* Determine the start-of-run (sor) directional type given the two + embedding levels on either side of the run boundary. Also, update + the saved info about previously seen characters, since that info is + generally valid for a single level run. */ +static inline void +bidi_set_sor_type (struct bidi_it *bidi_it, int level_before, int level_after) +{ + int higher_level = level_before > level_after ? level_before : level_after; + + /* The prev_was_pdf gork is required for when we have several PDFs + in a row. In that case, we want to compute the sor type for the + next level run only once: when we see the first PDF. That's + because the sor type depends only on the higher of the two levels + that we find on the two sides of the level boundary (see UAX#9, + clause X10), and so we don't need to know the final embedding + level to which we descend after processing all the PDFs. */ + if (!bidi_it->prev_was_pdf || level_before < level_after) + /* FIXME: should the default sor direction be user selectable? */ + bidi_it->sor = (higher_level & 1) != 0 ? R2L : L2R; + if (level_before > level_after) + bidi_it->prev_was_pdf = 1; + + bidi_it->prev.type = UNKNOWN_BT; + bidi_it->last_strong.type = bidi_it->last_strong.type_after_w1 = + bidi_it->last_strong.orig_type = UNKNOWN_BT; + bidi_it->prev_for_neutral.type = bidi_it->sor == R2L ? STRONG_R : STRONG_L; + bidi_it->prev_for_neutral.charpos = bidi_it->charpos; + bidi_it->prev_for_neutral.bytepos = bidi_it->bytepos; + bidi_it->next_for_neutral.type = bidi_it->next_for_neutral.type_after_w1 = + bidi_it->next_for_neutral.orig_type = UNKNOWN_BT; + bidi_it->ignore_bn_limit = -1; /* meaning it's unknown */ +} + +/* Push the current embedding level and override status; reset the + current level to LEVEL and the current override status to OVERRIDE. */ +static inline void +bidi_push_embedding_level (struct bidi_it *bidi_it, + int level, bidi_dir_t override) +{ + bidi_it->stack_idx++; + xassert (bidi_it->stack_idx < BIDI_MAXLEVEL); + bidi_it->level_stack[bidi_it->stack_idx].level = level; + bidi_it->level_stack[bidi_it->stack_idx].override = override; +} + +/* Pop the embedding level and directional override status from the + stack, and return the new level. */ +static inline int +bidi_pop_embedding_level (struct bidi_it *bidi_it) +{ + /* UAX#9 says to ignore invalid PDFs. */ + if (bidi_it->stack_idx > 0) + bidi_it->stack_idx--; + return bidi_it->level_stack[bidi_it->stack_idx].level; +} + +/* Record in SAVED_INFO the information about the current character. */ +static inline void +bidi_remember_char (struct bidi_saved_info *saved_info, + struct bidi_it *bidi_it) +{ + saved_info->charpos = bidi_it->charpos; + saved_info->bytepos = bidi_it->bytepos; + saved_info->type = bidi_it->type; + bidi_check_type (bidi_it->type); + saved_info->type_after_w1 = bidi_it->type_after_w1; + bidi_check_type (bidi_it->type_after_w1); + saved_info->orig_type = bidi_it->orig_type; + bidi_check_type (bidi_it->orig_type); +} + /* Copy the bidi iterator from FROM to TO. To save cycles, this only copies the part of the level stack that is actually in use. */ static inline void @@ -259,22 +292,37 @@ to->level_stack[i] = from->level_stack[i]; } -/* Caching the bidi iterator states. */ + +/*********************************************************************** + Caching the bidi iterator states + ***********************************************************************/ #define BIDI_CACHE_CHUNK 200 static struct bidi_it *bidi_cache; static size_t bidi_cache_size = 0; static size_t elsz = sizeof (struct bidi_it); -static int bidi_cache_idx; /* next unused cache slot */ -static int bidi_cache_last_idx; /* slot of last cache hit */ +static EMACS_INT bidi_cache_idx; /* next unused cache slot */ +static EMACS_INT bidi_cache_last_idx; /* slot of last cache hit */ +static EMACS_INT bidi_cache_start = 0; /* start of cache for this + "stack" level */ +/* Reset the cache state to the empty state. We only reset the part + of the cache relevant to iteration of the current object. Previous + objects, which are pushed on the display iterator's stack, are left + intact. This is called when the cached information is no more + useful for the current iteration, e.g. when we were reseated to a + new position on the same object. */ static inline void bidi_cache_reset (void) { - bidi_cache_idx = 0; + bidi_cache_idx = bidi_cache_start; bidi_cache_last_idx = -1; } +/* Shrink the cache to its minimal size. Called when we init the bidi + iterator for reordering a buffer or a string that does not come + from display properties, because that means all the previously + cached info is of no further use. */ static inline void bidi_cache_shrink (void) { @@ -288,11 +336,11 @@ } static inline void -bidi_cache_fetch_state (int idx, struct bidi_it *bidi_it) +bidi_cache_fetch_state (EMACS_INT idx, struct bidi_it *bidi_it) { int current_scan_dir = bidi_it->scan_dir; - if (idx < 0 || idx >= bidi_cache_idx) + if (idx < bidi_cache_start || idx >= bidi_cache_idx) abort (); bidi_copy_it (bidi_it, &bidi_cache[idx]); @@ -304,13 +352,15 @@ level less or equal to LEVEL. if LEVEL is -1, disregard the resolved levels in cached states. DIR, if non-zero, means search in that direction from the last cache hit. */ -static inline int +static inline EMACS_INT bidi_cache_search (EMACS_INT charpos, int level, int dir) { - int i, i_start; + EMACS_INT i, i_start; - if (bidi_cache_idx) + if (bidi_cache_idx > bidi_cache_start) { + if (bidi_cache_last_idx == -1) + bidi_cache_last_idx = bidi_cache_idx - 1; if (charpos < bidi_cache[bidi_cache_last_idx].charpos) { dir = -1; @@ -333,7 +383,7 @@ if (dir < 0) { /* Linear search for now; FIXME! */ - for (i = i_start; i >= 0; i--) + for (i = i_start; i >= bidi_cache_start; i--) if (bidi_cache[i].charpos <= charpos && charpos < bidi_cache[i].charpos + bidi_cache[i].nchars && (level == -1 || bidi_cache[i].resolved_level <= level)) @@ -355,8 +405,9 @@ /* Find a cached state where the resolved level changes to a value that is lower than LEVEL, and return its cache slot index. DIR is the direction to search, starting with the last used cache slot. - BEFORE, if non-zero, means return the index of the slot that is - ``before'' the level change in the search direction. That is, + If DIR is zero, we search backwards from the last occupied cache + slot. BEFORE, if non-zero, means return the index of the slot that + is ``before'' the level change in the search direction. That is, given the cached levels like this: 1122333442211 @@ -366,14 +417,16 @@ C, searching backwards (DIR = -1) for LEVEL = 2 will return the index of slot B or A, depending whether BEFORE is, respectively, non-zero or zero. */ -static int +static EMACS_INT bidi_cache_find_level_change (int level, int dir, int before) { if (bidi_cache_idx) { - int i = dir ? bidi_cache_last_idx : bidi_cache_idx - 1; + EMACS_INT i = dir ? bidi_cache_last_idx : bidi_cache_idx - 1; int incr = before ? 1 : 0; + xassert (!dir || bidi_cache_last_idx >= 0); + if (!dir) dir = -1; else if (!incr) @@ -381,7 +434,7 @@ if (dir < 0) { - while (i >= incr) + while (i >= bidi_cache_start + incr) { if (bidi_cache[i - incr].resolved_level >= 0 && bidi_cache[i - incr].resolved_level < level) @@ -405,9 +458,22 @@ } static inline void +bidi_cache_ensure_space (EMACS_INT idx) +{ + /* Enlarge the cache as needed. */ + if (idx >= bidi_cache_size) + { + while (idx >= bidi_cache_size) + bidi_cache_size += BIDI_CACHE_CHUNK; + bidi_cache = + (struct bidi_it *) xrealloc (bidi_cache, bidi_cache_size * elsz); + } +} + +static inline void bidi_cache_iterator_state (struct bidi_it *bidi_it, int resolved) { - int idx; + EMACS_INT idx; /* We should never cache on backward scans. */ if (bidi_it->scan_dir == -1) @@ -417,23 +483,17 @@ if (idx < 0) { idx = bidi_cache_idx; - /* Enlarge the cache as needed. */ - if (idx >= bidi_cache_size) - { - bidi_cache_size += BIDI_CACHE_CHUNK; - bidi_cache = - (struct bidi_it *) xrealloc (bidi_cache, bidi_cache_size * elsz); - } + bidi_cache_ensure_space (idx); /* Character positions should correspond to cache positions 1:1. If we are outside the range of cached positions, the cache is useless and must be reset. */ - if (idx > 0 && + if (idx > bidi_cache_start && (bidi_it->charpos > (bidi_cache[idx - 1].charpos + bidi_cache[idx - 1].nchars) - || bidi_it->charpos < bidi_cache[0].charpos)) + || bidi_it->charpos < bidi_cache[bidi_cache_start].charpos)) { bidi_cache_reset (); - idx = 0; + idx = bidi_cache_start; } if (bidi_it->nchars <= 0) abort (); @@ -468,9 +528,9 @@ static inline bidi_type_t bidi_cache_find (EMACS_INT charpos, int level, struct bidi_it *bidi_it) { - int i = bidi_cache_search (charpos, level, bidi_it->scan_dir); + EMACS_INT i = bidi_cache_search (charpos, level, bidi_it->scan_dir); - if (i >= 0) + if (i >= bidi_cache_start) { bidi_dir_t current_scan_dir = bidi_it->scan_dir; @@ -488,69 +548,245 @@ static inline int bidi_peek_at_next_level (struct bidi_it *bidi_it) { - if (bidi_cache_idx == 0 || bidi_cache_last_idx == -1) + if (bidi_cache_idx == bidi_cache_start || bidi_cache_last_idx == -1) abort (); return bidi_cache[bidi_cache_last_idx + bidi_it->scan_dir].resolved_level; } -/* Check if buffer position CHARPOS/BYTEPOS is the end of a paragraph. - Value is the non-negative length of the paragraph separator - following the buffer position, -1 if position is at the beginning - of a new paragraph, or -2 if position is neither at beginning nor - at end of a paragraph. */ -static EMACS_INT -bidi_at_paragraph_end (EMACS_INT charpos, EMACS_INT bytepos) -{ - Lisp_Object sep_re; - Lisp_Object start_re; - EMACS_INT val; - - sep_re = paragraph_separate_re; - start_re = paragraph_start_re; - - val = fast_looking_at (sep_re, charpos, bytepos, ZV, ZV_BYTE, Qnil); - if (val < 0) - { - if (fast_looking_at (start_re, charpos, bytepos, ZV, ZV_BYTE, Qnil) >= 0) - val = -1; - else - val = -2; - } - - return val; -} - -/* Determine the start-of-run (sor) directional type given the two - embedding levels on either side of the run boundary. Also, update - the saved info about previously seen characters, since that info is - generally valid for a single level run. */ + +/*********************************************************************** + Pushing and popping the bidi iterator state + ***********************************************************************/ +/* 5-slot stack for saving the start of the previous level of the + cache. xdisp.c maintains a 5-slot stack for its iterator state, + and we need the same size of our stack. */ +static EMACS_INT bidi_cache_start_stack[IT_STACK_SIZE]; +static int bidi_cache_sp; + +/* Push the bidi iterator state in preparation for reordering a + different object, e.g. display string found at certain buffer + position. Pushing the bidi iterator boils down to saving its + entire state on the cache and starting a new cache "stacked" on top + of the current cache. */ +void +bidi_push_it (struct bidi_it *bidi_it) +{ + /* Save the current iterator state in its entirety after the last + used cache slot. */ + bidi_cache_ensure_space (bidi_cache_idx); + memcpy (&bidi_cache[bidi_cache_idx++], bidi_it, sizeof (struct bidi_it)); + + /* Push the current cache start onto the stack. */ + xassert (bidi_cache_sp < IT_STACK_SIZE); + bidi_cache_start_stack[bidi_cache_sp++] = bidi_cache_start; + + /* Start a new level of cache, and make it empty. */ + bidi_cache_start = bidi_cache_idx; + bidi_cache_last_idx = -1; +} + +/* Restore the iterator state saved by bidi_push_it and return the + cache to the corresponding state. */ +void +bidi_pop_it (struct bidi_it *bidi_it) +{ + if (bidi_cache_start <= 0) + abort (); + + /* Reset the next free cache slot index to what it was before the + call to bidi_push_it. */ + bidi_cache_idx = bidi_cache_start - 1; + + /* Restore the bidi iterator state saved in the cache. */ + memcpy (bidi_it, &bidi_cache[bidi_cache_idx], sizeof (struct bidi_it)); + + /* Pop the previous cache start from the stack. */ + if (bidi_cache_sp <= 0) + abort (); + bidi_cache_start = bidi_cache_start_stack[--bidi_cache_sp]; + + /* Invalidate the last-used cache slot data. */ + bidi_cache_last_idx = -1; +} + +/* Stash away a copy of the cache and its control variables. */ +void * +bidi_shelve_cache (void) +{ + unsigned char *databuf; + + if (bidi_cache_idx == 0) + return NULL; + + databuf = xmalloc (sizeof (bidi_cache_idx) + + bidi_cache_idx * sizeof (struct bidi_it) + + sizeof (bidi_cache_start_stack) + + sizeof (bidi_cache_sp) + sizeof (bidi_cache_start) + + sizeof (bidi_cache_last_idx)); + memcpy (databuf, &bidi_cache_idx, sizeof (bidi_cache_idx)); + memcpy (databuf + sizeof (bidi_cache_idx), + bidi_cache, bidi_cache_idx * sizeof (struct bidi_it)); + memcpy (databuf + sizeof (bidi_cache_idx) + + bidi_cache_idx * sizeof (struct bidi_it), + bidi_cache_start_stack, sizeof (bidi_cache_start_stack)); + memcpy (databuf + sizeof (bidi_cache_idx) + + bidi_cache_idx * sizeof (struct bidi_it) + + sizeof (bidi_cache_start_stack), + &bidi_cache_sp, sizeof (bidi_cache_sp)); + memcpy (databuf + sizeof (bidi_cache_idx) + + bidi_cache_idx * sizeof (struct bidi_it) + + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp), + &bidi_cache_start, sizeof (bidi_cache_start)); + memcpy (databuf + sizeof (bidi_cache_idx) + + bidi_cache_idx * sizeof (struct bidi_it) + + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp) + + sizeof (bidi_cache_start), + &bidi_cache_last_idx, sizeof (bidi_cache_last_idx)); + + return databuf; +} + +/* Restore the cache state from a copy stashed away by bidi_shelve_cache. */ +void +bidi_unshelve_cache (void *databuf) +{ + unsigned char *p = databuf; + + if (!p) + { + /* A NULL pointer means an empty cache. */ + bidi_cache_start = 0; + bidi_cache_sp = 0; + bidi_cache_reset (); + } + else + { + memcpy (&bidi_cache_idx, p, sizeof (bidi_cache_idx)); + bidi_cache_ensure_space (bidi_cache_idx); + memcpy (bidi_cache, p + sizeof (bidi_cache_idx), + bidi_cache_idx * sizeof (struct bidi_it)); + memcpy (bidi_cache_start_stack, + p + sizeof (bidi_cache_idx) + + bidi_cache_idx * sizeof (struct bidi_it), + sizeof (bidi_cache_start_stack)); + memcpy (&bidi_cache_sp, + p + sizeof (bidi_cache_idx) + + bidi_cache_idx * sizeof (struct bidi_it) + + sizeof (bidi_cache_start_stack), + sizeof (bidi_cache_sp)); + memcpy (&bidi_cache_start, + p + sizeof (bidi_cache_idx) + + bidi_cache_idx * sizeof (struct bidi_it) + + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp), + sizeof (bidi_cache_start)); + memcpy (&bidi_cache_last_idx, + p + sizeof (bidi_cache_idx) + + bidi_cache_idx * sizeof (struct bidi_it) + + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp) + + sizeof (bidi_cache_start), + sizeof (bidi_cache_last_idx)); + + xfree (p); + } +} + + +/*********************************************************************** + Initialization + ***********************************************************************/ +static void +bidi_initialize (void) +{ + +#include "biditype.h" +#include "bidimirror.h" + + int i; + + bidi_type_table = Fmake_char_table (Qnil, make_number (STRONG_L)); + staticpro (&bidi_type_table); + + for (i = 0; i < sizeof bidi_type / sizeof bidi_type[0]; i++) + char_table_set_range (bidi_type_table, bidi_type[i].from, bidi_type[i].to, + make_number (bidi_type[i].type)); + + bidi_mirror_table = Fmake_char_table (Qnil, Qnil); + staticpro (&bidi_mirror_table); + + for (i = 0; i < sizeof bidi_mirror / sizeof bidi_mirror[0]; i++) + char_table_set (bidi_mirror_table, bidi_mirror[i].from, + make_number (bidi_mirror[i].to)); + + Qparagraph_start = intern ("paragraph-start"); + staticpro (&Qparagraph_start); + paragraph_start_re = Fsymbol_value (Qparagraph_start); + if (!STRINGP (paragraph_start_re)) + paragraph_start_re = build_string ("\f\\|[ \t]*$"); + staticpro (¶graph_start_re); + Qparagraph_separate = intern ("paragraph-separate"); + staticpro (&Qparagraph_separate); + paragraph_separate_re = Fsymbol_value (Qparagraph_separate); + if (!STRINGP (paragraph_separate_re)) + paragraph_separate_re = build_string ("[ \t\f]*$"); + staticpro (¶graph_separate_re); + + bidi_cache_sp = 0; + + bidi_initialized = 1; +} + +/* Do whatever UAX#9 clause X8 says should be done at paragraph's + end. */ static inline void -bidi_set_sor_type (struct bidi_it *bidi_it, int level_before, int level_after) -{ - int higher_level = level_before > level_after ? level_before : level_after; - - /* The prev_was_pdf gork is required for when we have several PDFs - in a row. In that case, we want to compute the sor type for the - next level run only once: when we see the first PDF. That's - because the sor type depends only on the higher of the two levels - that we find on the two sides of the level boundary (see UAX#9, - clause X10), and so we don't need to know the final embedding - level to which we descend after processing all the PDFs. */ - if (!bidi_it->prev_was_pdf || level_before < level_after) - /* FIXME: should the default sor direction be user selectable? */ - bidi_it->sor = (higher_level & 1) != 0 ? R2L : L2R; - if (level_before > level_after) - bidi_it->prev_was_pdf = 1; - - bidi_it->prev.type = UNKNOWN_BT; +bidi_set_paragraph_end (struct bidi_it *bidi_it) +{ + bidi_it->invalid_levels = 0; + bidi_it->invalid_rl_levels = -1; + bidi_it->stack_idx = 0; + bidi_it->resolved_level = bidi_it->level_stack[0].level; +} + +/* Initialize the bidi iterator from buffer/string position CHARPOS. */ +void +bidi_init_it (EMACS_INT charpos, EMACS_INT bytepos, int frame_window_p, + struct bidi_it *bidi_it) +{ + if (! bidi_initialized) + bidi_initialize (); + if (charpos >= 0) + bidi_it->charpos = charpos; + if (bytepos >= 0) + bidi_it->bytepos = bytepos; + bidi_it->frame_window_p = frame_window_p; + bidi_it->nchars = -1; /* to be computed in bidi_resolve_explicit_1 */ + bidi_it->first_elt = 1; + bidi_set_paragraph_end (bidi_it); + bidi_it->new_paragraph = 1; + bidi_it->separator_limit = -1; + bidi_it->type = NEUTRAL_B; + bidi_it->type_after_w1 = NEUTRAL_B; + bidi_it->orig_type = NEUTRAL_B; + bidi_it->prev_was_pdf = 0; + bidi_it->prev.type = bidi_it->prev.type_after_w1 = + bidi_it->prev.orig_type = UNKNOWN_BT; bidi_it->last_strong.type = bidi_it->last_strong.type_after_w1 = bidi_it->last_strong.orig_type = UNKNOWN_BT; - bidi_it->prev_for_neutral.type = bidi_it->sor == R2L ? STRONG_R : STRONG_L; - bidi_it->prev_for_neutral.charpos = bidi_it->charpos; - bidi_it->prev_for_neutral.bytepos = bidi_it->bytepos; - bidi_it->next_for_neutral.type = bidi_it->next_for_neutral.type_after_w1 = + bidi_it->next_for_neutral.charpos = -1; + bidi_it->next_for_neutral.type = + bidi_it->next_for_neutral.type_after_w1 = bidi_it->next_for_neutral.orig_type = UNKNOWN_BT; - bidi_it->ignore_bn_limit = 0; /* meaning it's unknown */ + bidi_it->prev_for_neutral.charpos = -1; + bidi_it->prev_for_neutral.type = + bidi_it->prev_for_neutral.type_after_w1 = + 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 */ + /* We can only shrink the cache if we are at the bottom level of its + "stack". */ + if (bidi_cache_start == 0) + bidi_cache_shrink (); + else + bidi_cache_reset (); } /* Perform initializations for reordering a new line of bidi text. */ @@ -571,6 +807,57 @@ bidi_cache_reset (); } + +/*********************************************************************** + Fetching characters + ***********************************************************************/ + +/* Count bytes in string S between BEG/BEGBYTE and END. BEG and END + are zero-based character positions in S, BEGBYTE is byte position + corresponding to BEG. UNIBYTE, if non-zero, means S is a unibyte + string. */ +static inline EMACS_INT +bidi_count_bytes (const unsigned char *s, const EMACS_INT beg, + const EMACS_INT begbyte, const EMACS_INT end, int unibyte) +{ + EMACS_INT pos = beg; + const unsigned char *p = s + begbyte, *start = p; + + if (unibyte) + p = s + end; + else + { + if (!CHAR_HEAD_P (*p)) + abort (); + + while (pos < end) + { + p += BYTES_BY_CHAR_HEAD (*p); + pos++; + } + } + + return p - start; +} + +/* Fetch and returns the character at byte position BYTEPOS. If S is + non-NULL, fetch the character from string S; otherwise fetch the + character from the current buffer. UNIBYTE non-zero means S is a + unibyte string. */ +static inline int +bidi_char_at_pos (EMACS_INT bytepos, const unsigned char *s, int unibyte) +{ + if (s) + { + if (unibyte) + return s[bytepos]; + else + return STRING_CHAR (s + bytepos); + } + else + return FETCH_MULTIBYTE_CHAR (bytepos); +} + /* 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 @@ -578,26 +865,34 @@ character position of the next display string, or -1 if not yet computed. When the next character is at or beyond that position, the function updates DISP_POS with the position of the next display - string. */ + 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, + struct bidi_string_data *string, int frame_window_p, EMACS_INT *ch_len, EMACS_INT *nchars) { int ch; + EMACS_INT endpos = + (string->s || STRINGP (string->lstring)) ? string->schars : ZV; + struct text_pos pos; - /* FIXME: Support strings in addition to buffers. */ /* If we got past the last known position of display string, compute - the position of the next one. That position could be at BYTEPOS. */ - if (charpos < ZV && charpos > *disp_pos) - *disp_pos = compute_display_string_pos (charpos, frame_window_p); + the position of the next one. That position could be at CHARPOS. */ + if (charpos < endpos && charpos > *disp_pos) + { + SET_TEXT_POS (pos, charpos, bytepos); + *disp_pos = compute_display_string_pos (&pos, string, frame_window_p); + } /* Fetch the character at BYTEPOS. */ - if (bytepos >= ZV_BYTE) + if (charpos >= endpos) { ch = BIDI_EOB; *ch_len = 1; *nchars = 1; - *disp_pos = ZV; + *disp_pos = endpos; } else if (charpos >= *disp_pos) { @@ -608,28 +903,105 @@ if (charpos > *disp_pos) abort (); /* Return the Unicode Object Replacement Character to represent - the entire run of characters covered by the display - string. */ + the entire run of characters covered by the display string. */ ch = 0xFFFC; - disp_end_pos = compute_display_string_end (*disp_pos); + disp_end_pos = compute_display_string_end (*disp_pos, string); *nchars = disp_end_pos - *disp_pos; - *ch_len = CHAR_TO_BYTE (disp_end_pos) - bytepos; + if (*nchars <= 0) + abort (); + if (string->s) + *ch_len = bidi_count_bytes (string->s, *disp_pos, bytepos, + disp_end_pos, string->unibyte); + else if (STRINGP (string->lstring)) + *ch_len = bidi_count_bytes (SDATA (string->lstring), *disp_pos, + bytepos, disp_end_pos, string->unibyte); + else + *ch_len = CHAR_TO_BYTE (disp_end_pos) - bytepos; } else { - ch = FETCH_MULTIBYTE_CHAR (bytepos); + if (string->s) + { + int len; + + if (!string->unibyte) + { + ch = STRING_CHAR_AND_LENGTH (string->s + bytepos, len); + *ch_len = len; + } + else + { + ch = UNIBYTE_TO_CHAR (string->s[bytepos]); + *ch_len = 1; + } + } + else if (STRINGP (string->lstring)) + { + int len; + + if (!string->unibyte) + { + ch = STRING_CHAR_AND_LENGTH (SDATA (string->lstring) + bytepos, + len); + *ch_len = len; + } + else + { + ch = UNIBYTE_TO_CHAR (SREF (string->lstring, bytepos)); + *ch_len = 1; + } + } + else + { + ch = FETCH_MULTIBYTE_CHAR (bytepos); + *ch_len = CHAR_BYTES (ch); + } *nchars = 1; - *ch_len = CHAR_BYTES (ch); } /* If we just entered a run of characters covered by a display string, compute the position of the next display string. */ - if (charpos + *nchars <= ZV && charpos + *nchars > *disp_pos) - *disp_pos = compute_display_string_pos (charpos + *nchars, frame_window_p); + if (charpos + *nchars <= endpos && charpos + *nchars > *disp_pos) + { + SET_TEXT_POS (pos, charpos + *nchars, bytepos + *ch_len); + *disp_pos = compute_display_string_pos (&pos, string, frame_window_p); + } return ch; } + +/*********************************************************************** + Determining paragraph direction + ***********************************************************************/ + +/* Check if buffer position CHARPOS/BYTEPOS is the end of a paragraph. + Value is the non-negative length of the paragraph separator + following the buffer position, -1 if position is at the beginning + of a new paragraph, or -2 if position is neither at beginning nor + at end of a paragraph. */ +static EMACS_INT +bidi_at_paragraph_end (EMACS_INT charpos, EMACS_INT bytepos) +{ + Lisp_Object sep_re; + Lisp_Object start_re; + EMACS_INT val; + + sep_re = paragraph_separate_re; + start_re = paragraph_start_re; + + val = fast_looking_at (sep_re, charpos, bytepos, ZV, ZV_BYTE, Qnil); + if (val < 0) + { + if (fast_looking_at (start_re, charpos, bytepos, ZV, ZV_BYTE, Qnil) >= 0) + val = -1; + else + val = -2; + } + + return val; +} + /* 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 @@ -670,13 +1042,19 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p) { EMACS_INT bytepos = bidi_it->bytepos; + int string_p = bidi_it->string.s != NULL || STRINGP (bidi_it->string.lstring); EMACS_INT pstartbyte; + /* Note that begbyte is a byte position, while end is a character + position. Yes, this is ugly, but we are trying to avoid costly + calls to BYTE_TO_CHAR and its ilk. */ + EMACS_INT begbyte = string_p ? 0 : BEGV_BYTE; + EMACS_INT end = string_p ? bidi_it->string.schars : ZV; /* Special case for an empty buffer. */ - if (bytepos == BEGV_BYTE && bytepos == ZV_BYTE) + if (bytepos == begbyte && bidi_it->charpos == end) dir = L2R; /* We should never be called at EOB or before BEGV. */ - else if (bytepos >= ZV_BYTE || bytepos < BEGV_BYTE) + else if (bidi_it->charpos >= end || bytepos < begbyte) abort (); if (dir == L2R) @@ -695,6 +1073,7 @@ EMACS_INT ch_len, nchars; EMACS_INT pos, disp_pos = -1; bidi_type_t type; + const unsigned char *s; if (!bidi_initialized) bidi_initialize (); @@ -712,7 +1091,10 @@ we are potentially in a new paragraph that doesn't yet exist. */ pos = bidi_it->charpos; - if (bytepos > BEGV_BYTE && FETCH_CHAR (bytepos) == '\n') + s = STRINGP (bidi_it->string.lstring) ? + SDATA (bidi_it->string.lstring) : bidi_it->string.s; + if (bytepos > begbyte + && bidi_char_at_pos (bytepos, s, bidi_it->string.unibyte) == '\n') { bytepos++; pos++; @@ -720,17 +1102,25 @@ /* We are either at the beginning of a paragraph or in the middle of it. Find where this paragraph starts. */ - pstartbyte = bidi_find_paragraph_start (pos, bytepos); + if (string_p) + { + /* We don't support changes of paragraph direction inside a + string. It is treated as a single paragraph. */ + pstartbyte = 0; + } + else + pstartbyte = bidi_find_paragraph_start (pos, bytepos); bidi_it->separator_limit = -1; bidi_it->new_paragraph = 0; /* The following loop is run more than once only if NO_DEFAULT_P - is non-zero. */ + is non-zero, and only if we are iterating on a buffer. */ do { bytepos = pstartbyte; - pos = BYTE_TO_CHAR (bytepos); - ch = bidi_fetch_char (bytepos, pos, &disp_pos, bidi_it->frame_window_p, - &ch_len, &nchars); + if (!string_p) + pos = BYTE_TO_CHAR (bytepos); + ch = bidi_fetch_char (bytepos, pos, &disp_pos, &bidi_it->string, + bidi_it->frame_window_p, &ch_len, &nchars); type = bidi_get_type (ch, NEUTRAL_DIR); for (pos += nchars, bytepos += ch_len; @@ -744,17 +1134,19 @@ || type == LRE || type == LRO)); type = bidi_get_type (ch, NEUTRAL_DIR)) { - if (bytepos >= ZV_BYTE) + if (pos >= end) { /* Pretend there's a paragraph separator at end of - buffer. */ + buffer/string. */ type = NEUTRAL_B; break; } - if (type == NEUTRAL_B && bidi_at_paragraph_end (pos, bytepos) >= -1) + if (!string_p + && type == NEUTRAL_B + && bidi_at_paragraph_end (pos, bytepos) >= -1) break; /* Fetch next character and advance to get past it. */ - ch = bidi_fetch_char (bytepos, pos, &disp_pos, + ch = bidi_fetch_char (bytepos, pos, &disp_pos, &bidi_it->string, bidi_it->frame_window_p, &ch_len, &nchars); pos += nchars; bytepos += ch_len; @@ -763,7 +1155,8 @@ bidi_it->paragraph_dir = R2L; else if (type == STRONG_L) bidi_it->paragraph_dir = L2R; - if (no_default_p && bidi_it->paragraph_dir == NEUTRAL_DIR) + if (!string_p + && no_default_p && bidi_it->paragraph_dir == NEUTRAL_DIR) { /* If this paragraph is at BEGV, default to L2R. */ if (pstartbyte == BEGV_BYTE) @@ -786,7 +1179,8 @@ pstartbyte = prevpbyte; } } - } while (no_default_p && bidi_it->paragraph_dir == NEUTRAL_DIR); + } while (!string_p + && no_default_p && bidi_it->paragraph_dir == NEUTRAL_DIR); } else abort (); @@ -804,110 +1198,11 @@ bidi_line_init (bidi_it); } -/* Do whatever UAX#9 clause X8 says should be done at paragraph's - end. */ -static inline void -bidi_set_paragraph_end (struct bidi_it *bidi_it) -{ - bidi_it->invalid_levels = 0; - bidi_it->invalid_rl_levels = -1; - bidi_it->stack_idx = 0; - bidi_it->resolved_level = bidi_it->level_stack[0].level; -} - -/* Initialize the bidi iterator from buffer/string position CHARPOS. */ -void -bidi_init_it (EMACS_INT charpos, EMACS_INT bytepos, int frame_window_p, - struct bidi_it *bidi_it) -{ - if (! bidi_initialized) - bidi_initialize (); - bidi_it->charpos = charpos; - bidi_it->bytepos = bytepos; - bidi_it->frame_window_p = frame_window_p; - bidi_it->nchars = -1; /* to be computed in bidi_resolve_explicit_1 */ - bidi_it->first_elt = 1; - bidi_set_paragraph_end (bidi_it); - bidi_it->new_paragraph = 1; - bidi_it->separator_limit = -1; - bidi_it->type = NEUTRAL_B; - bidi_it->type_after_w1 = NEUTRAL_B; - bidi_it->orig_type = NEUTRAL_B; - bidi_it->prev_was_pdf = 0; - bidi_it->prev.type = bidi_it->prev.type_after_w1 = - bidi_it->prev.orig_type = UNKNOWN_BT; - bidi_it->last_strong.type = bidi_it->last_strong.type_after_w1 = - bidi_it->last_strong.orig_type = UNKNOWN_BT; - bidi_it->next_for_neutral.charpos = -1; - bidi_it->next_for_neutral.type = - bidi_it->next_for_neutral.type_after_w1 = - bidi_it->next_for_neutral.orig_type = UNKNOWN_BT; - bidi_it->prev_for_neutral.charpos = -1; - bidi_it->prev_for_neutral.type = - bidi_it->prev_for_neutral.type_after_w1 = - 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_cache_shrink (); -} - -/* Push the current embedding level and override status; reset the - current level to LEVEL and the current override status to OVERRIDE. */ -static inline void -bidi_push_embedding_level (struct bidi_it *bidi_it, - int level, bidi_dir_t override) -{ - bidi_it->stack_idx++; - if (bidi_it->stack_idx >= BIDI_MAXLEVEL) - abort (); - bidi_it->level_stack[bidi_it->stack_idx].level = level; - bidi_it->level_stack[bidi_it->stack_idx].override = override; -} - -/* Pop the embedding level and directional override status from the - stack, and return the new level. */ -static inline int -bidi_pop_embedding_level (struct bidi_it *bidi_it) -{ - /* UAX#9 says to ignore invalid PDFs. */ - if (bidi_it->stack_idx > 0) - bidi_it->stack_idx--; - return bidi_it->level_stack[bidi_it->stack_idx].level; -} - -/* Record in SAVED_INFO the information about the current character. */ -static inline void -bidi_remember_char (struct bidi_saved_info *saved_info, - struct bidi_it *bidi_it) -{ - saved_info->charpos = bidi_it->charpos; - saved_info->bytepos = bidi_it->bytepos; - saved_info->type = bidi_it->type; - bidi_check_type (bidi_it->type); - saved_info->type_after_w1 = bidi_it->type_after_w1; - bidi_check_type (bidi_it->type_after_w1); - saved_info->orig_type = bidi_it->orig_type; - bidi_check_type (bidi_it->orig_type); -} - -/* Resolve the type of a neutral character according to the type of - surrounding strong text and the current embedding level. */ -static inline bidi_type_t -bidi_resolve_neutral_1 (bidi_type_t prev_type, bidi_type_t next_type, int lev) -{ - /* N1: European and Arabic numbers are treated as though they were R. */ - if (next_type == WEAK_EN || next_type == WEAK_AN) - next_type = STRONG_R; - if (prev_type == WEAK_EN || prev_type == WEAK_AN) - prev_type = STRONG_R; - - if (next_type == prev_type) /* N1 */ - return next_type; - else if ((lev & 1) == 0) /* N2 */ - return STRONG_L; - else - return STRONG_R; -} + +/*********************************************************************** + Resolving explicit and implicit levels. + The rest of this file constitutes the core of the UBA implementation. + ***********************************************************************/ static inline int bidi_explicit_dir_char (int ch) @@ -934,19 +1229,35 @@ int current_level; int new_level; bidi_dir_t override; + int string_p = bidi_it->string.s != NULL || STRINGP (bidi_it->string.lstring); /* If reseat()'ed, don't advance, so as to start iteration from the position where we were reseated. bidi_it->bytepos can be less than BEGV_BYTE after reseat to BEGV. */ - if (bidi_it->bytepos < BEGV_BYTE + if (bidi_it->bytepos < (string_p ? 0 : BEGV_BYTE) || bidi_it->first_elt) { bidi_it->first_elt = 0; - if (bidi_it->charpos < BEGV) - bidi_it->charpos = BEGV; - bidi_it->bytepos = CHAR_TO_BYTE (bidi_it->charpos); + if (string_p) + { + const unsigned char *p = + STRINGP (bidi_it->string.lstring) + ? SDATA (bidi_it->string.lstring) : bidi_it->string.s; + + if (bidi_it->charpos < 0) + bidi_it->charpos = 0; + bidi_it->bytepos = bidi_count_bytes (p, 0, 0, bidi_it->charpos, + bidi_it->string.unibyte); + } + else + { + if (bidi_it->charpos < BEGV) + bidi_it->charpos = BEGV; + bidi_it->bytepos = CHAR_TO_BYTE (bidi_it->charpos); + } } - else if (bidi_it->bytepos < ZV_BYTE) /* don't move at ZV */ + /* Don't move at end of buffer/string. */ + else if (bidi_it->charpos < (string_p ? bidi_it->string.schars : ZV)) { /* Advance to the next character, skipping characters covered by display strings (nchars > 1). */ @@ -962,12 +1273,12 @@ override = bidi_it->level_stack[bidi_it->stack_idx].override; new_level = current_level; - if (bidi_it->bytepos >= ZV_BYTE) + if (bidi_it->charpos >= (string_p ? bidi_it->string.schars : ZV)) { curchar = BIDI_EOB; bidi_it->ch_len = 1; bidi_it->nchars = 1; - bidi_it->disp_pos = ZV; + bidi_it->disp_pos = (string_p ? bidi_it->string.schars : ZV); } else { @@ -975,7 +1286,8 @@ 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->frame_window_p, + &bidi_it->disp_pos, &bidi_it->string, + bidi_it->frame_window_p, &bidi_it->ch_len, &bidi_it->nchars); } bidi_it->ch = curchar; @@ -1000,7 +1312,7 @@ bidi_it->type_after_w1 = type; bidi_check_type (bidi_it->type_after_w1); type = WEAK_BN; /* X9/Retaining */ - if (bidi_it->ignore_bn_limit <= 0) + if (bidi_it->ignore_bn_limit <= -1) { if (current_level <= BIDI_MAXLEVEL - 4) { @@ -1033,7 +1345,7 @@ bidi_it->type_after_w1 = type; bidi_check_type (bidi_it->type_after_w1); type = WEAK_BN; /* X9/Retaining */ - if (bidi_it->ignore_bn_limit <= 0) + if (bidi_it->ignore_bn_limit <= -1) { if (current_level <= BIDI_MAXLEVEL - 5) { @@ -1068,7 +1380,7 @@ bidi_it->type_after_w1 = type; bidi_check_type (bidi_it->type_after_w1); type = WEAK_BN; /* X9/Retaining */ - if (bidi_it->ignore_bn_limit <= 0) + if (bidi_it->ignore_bn_limit <= -1) { if (!bidi_it->invalid_rl_levels) { @@ -1111,13 +1423,17 @@ { int prev_level = bidi_it->level_stack[bidi_it->stack_idx].level; int new_level = bidi_resolve_explicit_1 (bidi_it); + EMACS_INT eob = bidi_it->string.s ? bidi_it->string.schars : ZV; + const unsigned char *s = STRINGP (bidi_it->string.lstring) + ? SDATA (bidi_it->string.lstring) : bidi_it->string.s; if (prev_level < new_level && bidi_it->type == WEAK_BN - && bidi_it->ignore_bn_limit == 0 /* only if not already known */ - && bidi_it->bytepos < ZV_BYTE /* not already at EOB */ - && bidi_explicit_dir_char (FETCH_MULTIBYTE_CHAR (bidi_it->bytepos - + bidi_it->ch_len))) + && bidi_it->ignore_bn_limit == -1 /* only if not already known */ + && bidi_it->charpos < eob /* not already at EOB */ + && bidi_explicit_dir_char (bidi_char_at_pos (bidi_it->bytepos + + bidi_it->ch_len, s, + bidi_it->string.unibyte))) { /* Avoid pushing and popping embedding levels if the level run is empty, as this breaks level runs where it shouldn't. @@ -1129,12 +1445,17 @@ bidi_copy_it (&saved_it, bidi_it); - while (bidi_explicit_dir_char (FETCH_MULTIBYTE_CHAR (bidi_it->bytepos - + bidi_it->ch_len))) + while (bidi_explicit_dir_char (bidi_char_at_pos (bidi_it->bytepos + + bidi_it->ch_len, s, + bidi_it->string.unibyte))) { /* This advances to the next character, skipping any characters covered by display strings. */ level = bidi_resolve_explicit_1 (bidi_it); + /* If string.lstring was relocated inside bidi_resolve_explicit_1, + a pointer to its data is no longer valid. */ + if (STRINGP (bidi_it->string.lstring)) + s = SDATA (bidi_it->string.lstring); } if (bidi_it->nchars <= 0) @@ -1142,10 +1463,10 @@ if (level == prev_level) /* empty embedding */ saved_it.ignore_bn_limit = bidi_it->charpos + bidi_it->nchars; else /* this embedding is non-empty */ - saved_it.ignore_bn_limit = -1; + saved_it.ignore_bn_limit = -2; bidi_copy_it (bidi_it, &saved_it); - if (bidi_it->ignore_bn_limit > 0) + if (bidi_it->ignore_bn_limit > -1) { /* We pushed a level, but we shouldn't have. Undo that. */ if (!bidi_it->invalid_rl_levels) @@ -1188,6 +1509,9 @@ int next_char; bidi_type_t type_of_next; struct bidi_it saved_it; + EMACS_INT eob = + (STRINGP (bidi_it->string.lstring) || bidi_it->string.s) + ? bidi_it->string.schars : ZV; type = bidi_it->type; override = bidi_it->level_stack[bidi_it->stack_idx].override; @@ -1254,10 +1578,15 @@ && bidi_it->prev.orig_type == WEAK_EN) || bidi_it->prev.type_after_w1 == WEAK_AN))) { + const unsigned char *s = + STRINGP (bidi_it->string.lstring) + ? SDATA (bidi_it->string.lstring) : bidi_it->string.s; + next_char = - bidi_it->bytepos + bidi_it->ch_len >= ZV_BYTE - ? BIDI_EOB : FETCH_MULTIBYTE_CHAR (bidi_it->bytepos - + bidi_it->ch_len); + bidi_it->charpos + bidi_it->nchars >= eob + ? BIDI_EOB + : bidi_char_at_pos (bidi_it->bytepos + bidi_it->ch_len, s, + bidi_it->string.unibyte); type_of_next = bidi_get_type (next_char, override); if (type_of_next == WEAK_BN @@ -1306,13 +1635,17 @@ else /* W5: ET/BN with EN after it. */ { EMACS_INT en_pos = bidi_it->charpos + bidi_it->nchars; + const unsigned char *s = + STRINGP (bidi_it->string.lstring) + ? SDATA (bidi_it->string.lstring) : bidi_it->string.s; if (bidi_it->nchars <= 0) abort (); next_char = - bidi_it->bytepos + bidi_it->ch_len >= ZV_BYTE - ? BIDI_EOB : FETCH_MULTIBYTE_CHAR (bidi_it->bytepos - + bidi_it->ch_len); + bidi_it->charpos + bidi_it->nchars >= eob + ? BIDI_EOB + : bidi_char_at_pos (bidi_it->bytepos + bidi_it->ch_len, s, + bidi_it->string.unibyte); type_of_next = bidi_get_type (next_char, override); if (type_of_next == WEAK_ET @@ -1373,6 +1706,25 @@ return type; } +/* Resolve the type of a neutral character according to the type of + surrounding strong text and the current embedding level. */ +static inline bidi_type_t +bidi_resolve_neutral_1 (bidi_type_t prev_type, bidi_type_t next_type, int lev) +{ + /* N1: European and Arabic numbers are treated as though they were R. */ + if (next_type == WEAK_EN || next_type == WEAK_AN) + next_type = STRONG_R; + if (prev_type == WEAK_EN || prev_type == WEAK_AN) + prev_type = STRONG_R; + + if (next_type == prev_type) /* N1 */ + return next_type; + else if ((lev & 1) == 0) /* N2 */ + return STRONG_L; + else + return STRONG_R; +} + static bidi_type_t bidi_resolve_neutral (struct bidi_it *bidi_it) { @@ -1509,11 +1861,11 @@ /* Reset the limit until which to ignore BNs if we step out of the area where we found only empty levels. */ - if ((bidi_it->ignore_bn_limit > 0 + if ((bidi_it->ignore_bn_limit > -1 && bidi_it->ignore_bn_limit <= bidi_it->charpos) - || (bidi_it->ignore_bn_limit == -1 + || (bidi_it->ignore_bn_limit == -2 && !bidi_explicit_dir_char (bidi_it->ch))) - bidi_it->ignore_bn_limit = 0; + bidi_it->ignore_bn_limit = -1; type = bidi_resolve_neutral (bidi_it); @@ -1530,12 +1882,16 @@ bidi_type_t type; int level, prev_level = -1; struct bidi_saved_info next_for_neutral; - EMACS_INT next_char_pos; + EMACS_INT next_char_pos = -2; if (bidi_it->scan_dir == 1) { + EMACS_INT eob = + (bidi_it->string.s || STRINGP (bidi_it->string.lstring)) + ? bidi_it->string.schars : ZV; + /* There's no sense in trying to advance if we hit end of text. */ - if (bidi_it->bytepos >= ZV_BYTE) + if (bidi_it->charpos >= eob) return bidi_it->resolved_level; /* Record the info about the previous character. */ @@ -1575,17 +1931,27 @@ /* Perhaps the character we want is already cached. If it is, the call to bidi_cache_find below will return a type other than UNKNOWN_BT. */ - if (bidi_cache_idx && !bidi_it->first_elt) + if (bidi_cache_idx > bidi_cache_start && !bidi_it->first_elt) { + int bob = + (bidi_it->string.s || STRINGP (bidi_it->string.lstring)) ? 0 : 1; + if (bidi_it->scan_dir > 0) { if (bidi_it->nchars <= 0) abort (); next_char_pos = bidi_it->charpos + bidi_it->nchars; } - else + else if (bidi_it->charpos >= bob) + /* Implementation note: we allow next_char_pos to be as low as + 0 for buffers or -1 for strings, and that is okay because + that's the "position" of the sentinel iterator state we + cached at the beginning of the iteration. */ next_char_pos = bidi_it->charpos - 1; - type = bidi_cache_find (next_char_pos, -1, bidi_it); + if (next_char_pos >= bob - 1) + type = bidi_cache_find (next_char_pos, -1, bidi_it); + else + type = UNKNOWN_BT; } else type = UNKNOWN_BT; @@ -1652,13 +2018,14 @@ EMACS_INT cpos = bidi_it->charpos; EMACS_INT disp_pos = bidi_it->disp_pos; EMACS_INT nc = bidi_it->nchars; + struct bidi_string_data bs = bidi_it->string; bidi_type_t chtype; int fwp = bidi_it->frame_window_p; if (bidi_it->nchars <= 0) abort (); do { - ch = bidi_fetch_char (bpos += clen, cpos += nc, &disp_pos, fwp, + ch = bidi_fetch_char (bpos += clen, cpos += nc, &disp_pos, &bs, fwp, &clen, &nc); if (ch == '\n' || ch == BIDI_EOB /* || ch == LINESEP_CHAR */) chtype = NEUTRAL_B; @@ -1756,10 +2123,11 @@ bidi_find_other_level_edge (struct bidi_it *bidi_it, int level, int end_flag) { int dir = end_flag ? -bidi_it->scan_dir : bidi_it->scan_dir; - int idx; + EMACS_INT idx; /* Try the cache first. */ - if ((idx = bidi_cache_find_level_change (level, dir, end_flag)) >= 0) + if ((idx = bidi_cache_find_level_change (level, dir, end_flag)) + >= bidi_cache_start) bidi_cache_fetch_state (idx, bidi_it); else { @@ -1781,12 +2149,21 @@ { int old_level, new_level, next_level; struct bidi_it sentinel; + struct gcpro gcpro1; + + if (bidi_it->charpos < 0 || bidi_it->bytepos < 0) + abort (); if (bidi_it->scan_dir == 0) { bidi_it->scan_dir = 1; /* default to logical order */ } + /* The code below can call eval, and thus cause GC. If we are + iterating a Lisp string, make sure it won't be GCed. */ + if (STRINGP (bidi_it->string.lstring)) + GCPRO1 (bidi_it->string.lstring); + /* If we just passed a newline, initialize for the next line. */ if (!bidi_it->first_elt && bidi_it->orig_type == NEUTRAL_B) bidi_line_init (bidi_it); @@ -1794,7 +2171,7 @@ /* Prepare the sentinel iterator state, and cache it. When we bump into it, scanning backwards, we'll know that the last non-base level is exhausted. */ - if (bidi_cache_idx == 0) + if (bidi_cache_idx == bidi_cache_start) { bidi_copy_it (&sentinel, bidi_it); if (bidi_it->first_elt) @@ -1869,26 +2246,34 @@ reordering, whereas we _must_ know the paragraph base direction _before_ we process the paragraph's text, since the base direction affects the reordering. */ - if (bidi_it->scan_dir == 1 - && bidi_it->orig_type == NEUTRAL_B - && bidi_it->bytepos < ZV_BYTE) + if (bidi_it->scan_dir == 1 && bidi_it->orig_type == NEUTRAL_B) { - EMACS_INT sep_len = - bidi_at_paragraph_end (bidi_it->charpos + bidi_it->nchars, - bidi_it->bytepos + bidi_it->ch_len); - if (bidi_it->nchars <= 0) - abort (); - if (sep_len >= 0) + /* The paragraph direction of the entire string, once + determined, is in effect for the entire string. Setting the + separator limit to the end of the string prevents + bidi_paragraph_init from being called automatically on this + string. */ + if (bidi_it->string.s || STRINGP (bidi_it->string.lstring)) + bidi_it->separator_limit = bidi_it->string.schars; + else if (bidi_it->bytepos < ZV_BYTE) { - bidi_it->new_paragraph = 1; - /* Record the buffer position of the last character of the - paragraph separator. */ - bidi_it->separator_limit = - bidi_it->charpos + bidi_it->nchars + sep_len; + EMACS_INT sep_len = + bidi_at_paragraph_end (bidi_it->charpos + bidi_it->nchars, + bidi_it->bytepos + bidi_it->ch_len); + if (bidi_it->nchars <= 0) + abort (); + if (sep_len >= 0) + { + bidi_it->new_paragraph = 1; + /* Record the buffer position of the last character of the + paragraph separator. */ + bidi_it->separator_limit = + bidi_it->charpos + bidi_it->nchars + sep_len; + } } } - if (bidi_it->scan_dir == 1 && bidi_cache_idx) + if (bidi_it->scan_dir == 1 && bidi_cache_idx > bidi_cache_start) { /* If we are at paragraph's base embedding level and beyond the last cached position, the cache's job is done and we can @@ -1904,6 +2289,9 @@ else bidi_cache_iterator_state (bidi_it, 1); } + + if (STRINGP (bidi_it->string.lstring)) + UNGCPRO; } /* This is meant to be called from within the debugger, whenever you === modified file 'src/dispextern.h' --- src/dispextern.h 2011-07-06 22:43:48 +0000 +++ src/dispextern.h 2011-07-14 17:28:42 +0000 @@ -1820,9 +1820,21 @@ bidi_dir_t override; }; +/* Data type for storing information about a string being iterated on. */ +struct bidi_string_data { + Lisp_Object lstring; /* Lisp string to reorder, or nil */ + const unsigned char *s; /* string data, or NULL if reordering buffer */ + EMACS_INT schars; /* the number of characters in the string, + excluding the terminating null */ + EMACS_INT bufpos; /* buffer position of lstring, or 0 if N/A */ + unsigned from_disp_str : 1; /* 1 means the string comes from a + display property */ + unsigned unibyte : 1; /* 1 means the string is unibyte */ +}; + /* Data type for reordering bidirectional text. */ struct bidi_it { - EMACS_INT bytepos; /* iterator's position in buffer */ + EMACS_INT bytepos; /* iterator's position in buffer/string */ EMACS_INT charpos; int ch; /* character at that position, or u+FFFC ("object replacement character") for a run @@ -1852,12 +1864,13 @@ iterator state is saved, pushed, or popped. So only put here stuff that is not part of the bidi iterator's state! */ struct bidi_stack level_stack[BIDI_MAXLEVEL]; /* stack of embedding levels */ - int first_elt; /* if non-zero, examine current char first */ + struct bidi_string_data string; /* string to reorder */ bidi_dir_t paragraph_dir; /* current paragraph direction */ - int new_paragraph; /* if non-zero, we expect a new paragraph */ - int frame_window_p; /* non-zero if displaying on a GUI frame */ EMACS_INT separator_limit; /* where paragraph separator should end */ EMACS_INT disp_pos; /* position of display string after ch */ + unsigned first_elt : 1; /* if non-zero, examine current char first */ + unsigned new_paragraph : 1; /* if non-zero, we expect a new paragraph */ + unsigned frame_window_p : 1; /* non-zero if displaying on a GUI frame */ }; /* Value is non-zero when the bidi iterator is at base paragraph @@ -2134,6 +2147,10 @@ Don't handle some `display' properties in these strings. */ unsigned string_from_display_prop_p : 1; + /* 1 means we are iterating an object that came from a value of a + `display' property. */ + unsigned from_disp_prop_p : 1; + /* When METHOD == next_element_from_display_vector, this is 1 if we're doing an ellipsis. Otherwise meaningless. */ unsigned ellipsis_p : 1; @@ -2153,7 +2170,9 @@ Lisp_Object *dpvec, *dpend; /* Length in bytes of the char that filled dpvec. A value of zero - means that no such character is involved. */ + means that no such character is involved. A negative value means + the rest of the line from the current iterator position onwards + is hidden by selective display or ellipsis. */ int dpvec_char_len; /* Face id to use for all characters in display vector. -1 if unused. */ @@ -2245,10 +2264,13 @@ Lisp_Object from_overlay; enum glyph_row_area area; enum it_method method; + bidi_dir_t paragraph_embedding; unsigned multibyte_p : 1; unsigned string_from_display_prop_p : 1; unsigned display_ellipsis_p : 1; unsigned avoid_cursor_p : 1; + unsigned bidi_p:1; + unsigned from_disp_prop_p : 1; enum line_wrap_method line_wrap; /* properties from display property that are reset by another display property. */ @@ -2469,7 +2491,7 @@ /* Non-zero means we need to reorder bidirectional text for display in the visual order. */ - int bidi_p; + unsigned bidi_p : 1; /* For iterating over bidirectional text. */ struct bidi_it bidi_it; @@ -2951,6 +2973,10 @@ extern void bidi_move_to_visually_next (struct bidi_it *); extern void bidi_paragraph_init (bidi_dir_t, struct bidi_it *, int); extern int bidi_mirror_char (int); +extern void bidi_push_it (struct bidi_it *); +extern void bidi_pop_it (struct bidi_it *); +extern void *bidi_shelve_cache (void); +extern void bidi_unshelve_cache (void *); /* Defined in xdisp.c */ @@ -3008,8 +3034,10 @@ extern Lisp_Object lookup_glyphless_char_display (int, struct it *); extern int calc_pixel_width_or_height (double *, struct it *, Lisp_Object, struct font *, int, int *); -extern EMACS_INT compute_display_string_pos (EMACS_INT, int); -extern EMACS_INT compute_display_string_end (EMACS_INT); +extern EMACS_INT compute_display_string_pos (struct text_pos *, + struct bidi_string_data *, int); +extern EMACS_INT compute_display_string_end (EMACS_INT, + struct bidi_string_data *); #ifdef HAVE_WINDOW_SYSTEM === modified file 'src/dispnew.c' --- src/dispnew.c 2011-07-10 08:20:10 +0000 +++ src/dispnew.c 2011-07-14 17:28:42 +0000 @@ -5275,10 +5275,12 @@ struct image *img = 0; #endif int x0, x1, to_x; + void *itdata = NULL; /* We used to set current_buffer directly here, but that does the wrong thing with `face-remapping-alist' (bug#2044). */ Fset_buffer (w->buffer); + itdata = bidi_shelve_cache (); SET_TEXT_POS_FROM_MARKER (startp, w->start); CHARPOS (startp) = min (ZV, max (BEGV, CHARPOS (startp))); BYTEPOS (startp) = min (ZV_BYTE, max (BEGV_BYTE, BYTEPOS (startp))); @@ -5312,6 +5314,7 @@ argument is ZV to prevent move_it_in_display_line from matching based on buffer positions. */ move_it_in_display_line (&it, ZV, to_x, MOVE_TO_X); + bidi_unshelve_cache (itdata); Fset_buffer (old_current_buffer); === modified file 'src/indent.c' --- src/indent.c 2011-07-14 08:30:34 +0000 +++ src/indent.c 2011-07-14 17:28:42 +0000 @@ -1989,6 +1989,7 @@ struct gcpro gcpro1, gcpro2, gcpro3; Lisp_Object lcols = Qnil; double cols IF_LINT (= 0); + void *itdata = NULL; /* Allow LINES to be of the form (HPOS . VPOS) aka (COLUMNS . LINES). */ if (CONSP (lines) && (NUMBERP (XCAR (lines)))) @@ -2029,6 +2030,7 @@ EMACS_INT it_start; int first_x, it_overshoot_expected IF_LINT (= 0); + itdata = bidi_shelve_cache (); SET_TEXT_POS (pt, PT, PT_BYTE); start_display (&it, w, pt); first_x = it.first_visible_x; @@ -2133,6 +2135,7 @@ } SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it)); + bidi_unshelve_cache (itdata); } if (BUFFERP (old_buffer)) === modified file 'src/window.c' --- src/window.c 2011-07-12 21:09:01 +0000 +++ src/window.c 2011-07-14 17:28:42 +0000 @@ -1351,6 +1351,7 @@ struct text_pos startp; struct it it; struct buffer *old_buffer = NULL; + void *itdata = NULL; /* Cannot use Fvertical_motion because that function doesn't cope with variable-height lines. */ @@ -1372,11 +1373,13 @@ else SET_TEXT_POS_FROM_MARKER (startp, w->start); + itdata = bidi_shelve_cache (); start_display (&it, w, startp); move_it_vertically (&it, window_box_height (w)); if (it.current_y < it.last_visible_y) move_it_past_eol (&it); value = make_number (IT_CHARPOS (it)); + bidi_unshelve_cache (itdata); if (old_buffer) set_buffer_internal (old_buffer); @@ -4238,6 +4241,7 @@ /* True if we fiddled the window vscroll field without really scrolling. */ int vscrolled = 0; int x, y, rtop, rbot, rowh, vpos; + void *itdata = NULL; SET_TEXT_POS_FROM_MARKER (start, w->start); @@ -4248,6 +4252,7 @@ if (!pos_visible_p (w, PT, &x, &y, &rtop, &rbot, &rowh, &vpos)) { + itdata = bidi_shelve_cache (); /* Move backward half the height of the window. Performance note: vmotion used here is about 10% faster, but would give wrong results for variable height lines. */ @@ -4268,6 +4273,7 @@ } start = it.current.pos; + bidi_unshelve_cache (itdata); } else if (auto_window_vscroll_p) { @@ -4330,6 +4336,7 @@ Fset_window_vscroll (window, make_number (0), Qt); } + itdata = bidi_shelve_cache (); /* If scroll_preserve_screen_position is non-nil, we try to set point in the same window line as it is now, so get that line. */ if (!NILP (Vscroll_preserve_screen_position)) @@ -4408,12 +4415,16 @@ - it.current_y + it.max_ascent + it.max_descent); adjust_glyphs (it.f); } - else if (noerror) - return; - else if (n < 0) /* could happen with empty buffers */ - xsignal0 (Qbeginning_of_buffer); else - xsignal0 (Qend_of_buffer); + { + bidi_unshelve_cache (itdata); + if (noerror) + return; + else if (n < 0) /* could happen with empty buffers */ + xsignal0 (Qbeginning_of_buffer); + else + xsignal0 (Qend_of_buffer); + } } else { @@ -4421,10 +4432,14 @@ /* The first line was only partially visible, make it fully visible. */ w->vscroll = 0; - else if (noerror) - return; else - xsignal0 (Qbeginning_of_buffer); + { + bidi_unshelve_cache (itdata); + if (noerror) + return; + else + xsignal0 (Qbeginning_of_buffer); + } } /* If control gets here, then we vscrolled. */ @@ -4568,6 +4583,7 @@ SET_PT_BOTH (charpos, bytepos); } } + bidi_unshelve_cache (itdata); } @@ -4970,6 +4986,7 @@ int height = window_box_height (w); struct buffer *old_buffer; int bottom_y; + void *itdata = NULL; if (XBUFFER (w->buffer) != current_buffer) { @@ -4989,9 +5006,11 @@ else SET_TEXT_POS_FROM_MARKER (start, w->start); + itdata = bidi_shelve_cache (); start_display (&it, w, start); move_it_vertically (&it, height); bottom_y = line_bottom_y (&it); + bidi_unshelve_cache (itdata); /* rms: On a non-window display, the value of it.vpos at the bottom of the screen @@ -5090,12 +5109,14 @@ { struct it it; struct text_pos pt; + void *itdata = bidi_shelve_cache (); SET_TEXT_POS (pt, PT, PT_BYTE); start_display (&it, w, pt); move_it_vertically_backward (&it, window_box_height (w) / 2); charpos = IT_CHARPOS (it); bytepos = IT_BYTEPOS (it); + bidi_unshelve_cache (itdata); } else if (iarg < 0) { @@ -5104,6 +5125,7 @@ int nlines = -iarg; int extra_line_spacing; int h = window_box_height (w); + void *itdata = bidi_shelve_cache (); iarg = - max (-iarg, this_scroll_margin); @@ -5141,7 +5163,10 @@ h -= nlines * (FRAME_LINE_HEIGHT (it.f) + extra_line_spacing); } if (h <= 0) - return Qnil; + { + bidi_unshelve_cache (itdata); + return Qnil; + } /* Now find the new top line (starting position) of the window. */ start_display (&it, w, pt); @@ -5161,6 +5186,8 @@ charpos = IT_CHARPOS (it); bytepos = IT_BYTEPOS (it); + + bidi_unshelve_cache (itdata); } else { === modified file 'src/xdisp.c' --- src/xdisp.c 2011-07-12 03:04:06 +0000 +++ src/xdisp.c 2011-07-14 17:28:42 +0000 @@ -129,9 +129,13 @@ argument. Iteration over things to be displayed is then simple. It is - started by initializing an iterator with a call to init_iterator. - Calls to get_next_display_element fill the iterator structure with - relevant information about the next thing to display. Calls to + started by initializing an iterator with a call to init_iterator, + passing it the buffer position where to start iteration. For + iteration over strings, pass -1 as the position to init_iterator, + and call reseat_to_string when the string is ready, to initialize + the iterator for that string. Thereafter, calls to + get_next_display_element fill the iterator structure with relevant + information about the next thing to display. Calls to set_iterator_to_next move the iterator to the next thing. Besides this, an iterator also contains information about the @@ -590,6 +594,29 @@ #define TEXT_PROP_DISTANCE_LIMIT 100 +/* SAVE_IT and RESTORE_IT are called when we save a snapshot of the + iterator state and later restore it. This is needed because the + bidi iterator on bidi.c keeps a stacked cache of its states, which + is really a singleton. When we use scratch iterator objects to + move around the buffer, we can cause the bidi cache to be pushed or + popped, and therefore we need to restore the cache state when we + return to the original iterator. */ +#define SAVE_IT(ITCOPY,ITORIG,CACHE) \ + do { \ + if (CACHE) \ + xfree (CACHE); \ + ITCOPY = ITORIG; \ + CACHE = bidi_shelve_cache(); \ + } while (0) + +#define RESTORE_IT(pITORIG,pITCOPY,CACHE) \ + do { \ + if (pITORIG != pITCOPY) \ + *(pITORIG) = *(pITCOPY); \ + bidi_unshelve_cache (CACHE); \ + CACHE = NULL; \ + } while (0) + #if GLYPH_DEBUG /* Non-zero means print traces of redisplay if compiled with @@ -1195,6 +1222,7 @@ int *rtop, int *rbot, int *rowh, int *vpos) { struct it it; + void *itdata = bidi_shelve_cache (); struct text_pos top; int visible_p = 0; struct buffer *old_buffer = NULL; @@ -1225,13 +1253,21 @@ move_it_to (&it, charpos, -1, it.last_visible_y-1, -1, (charpos >= 0 ? MOVE_TO_POS : 0) | MOVE_TO_Y); - if (charpos >= 0 && IT_CHARPOS (it) >= charpos) + if (charpos >= 0 + && (((!it.bidi_p || it.bidi_it.scan_dir == 1) + && IT_CHARPOS (it) >= charpos) + /* When scanning backwards under bidi iteration, move_it_to + stops at or _before_ CHARPOS, because it stops at or to + the _right_ of the character at CHARPOS. */ + || (it.bidi_p && it.bidi_it.scan_dir == -1 + && IT_CHARPOS (it) <= charpos))) { /* We have reached CHARPOS, or passed it. How the call to - move_it_to can overshoot: (i) If CHARPOS is on invisible - text, move_it_to stops at the end of the invisible text, - after CHARPOS. (ii) If CHARPOS is in a display vector, - move_it_to stops on its last glyph. */ + move_it_to can overshoot: (i) If CHARPOS is on invisible text + or covered by a display property, move_it_to stops at the end + of the invisible text, to the right of CHARPOS. (ii) If + CHARPOS is in a display vector, move_it_to stops on its last + glyph. */ int top_x = it.current_x; int top_y = it.current_y; enum it_method it_method = it.method; @@ -1280,15 +1316,18 @@ } else { + /* We were asked to provide info about WINDOW_END. */ struct it it2; + void *it2data = NULL; - it2 = it; + SAVE_IT (it2, it, it2data); if (IT_CHARPOS (it) < ZV && FETCH_BYTE (IT_BYTEPOS (it)) != '\n') move_it_by_lines (&it, 1); if (charpos < IT_CHARPOS (it) || (it.what == IT_EOB && charpos == IT_CHARPOS (it))) { visible_p = 1; + RESTORE_IT (&it2, &it2, it2data); move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS); *x = it2.current_x; *y = it2.current_y + it2.max_ascent - it2.ascent; @@ -1301,7 +1340,10 @@ WINDOW_HEADER_LINE_HEIGHT (w)))); *vpos = it2.vpos; } + else + xfree (it2data); } + bidi_unshelve_cache (itdata); if (old_buffer) set_buffer_internal_1 (old_buffer); @@ -2339,6 +2381,10 @@ it->base_face_id = remapped_base_face_id; it->string = Qnil; IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1; + it->paragraph_embedding = L2R; + it->bidi_it.string.lstring = Qnil; + it->bidi_it.string.s = NULL; + it->bidi_it.string.bufpos = 0; /* The window in which we iterate over current_buffer: */ XSETWINDOW (it->window, w); @@ -2395,13 +2441,6 @@ /* Are multibyte characters enabled in current_buffer? */ it->multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters)); - /* Do we need to reorder bidirectional text? Not if this is a - unibyte buffer: by definition, none of the single-byte characters - are strong R2L, so no reordering is needed. And bidi.c doesn't - support unibyte buffers anyway. */ - it->bidi_p - = !NILP (BVAR (current_buffer, bidi_display_reordering)) && it->multibyte_p; - /* Non-zero if we should highlight the region. */ highlight_region_p = (!NILP (Vtransient_mark_mode) @@ -2551,21 +2590,6 @@ it->start_of_box_run_p = 1; } - /* If we are to reorder bidirectional text, init the bidi - iterator. */ - if (it->bidi_p) - { - /* Note the paragraph direction that this buffer wants to - use. */ - if (EQ (BVAR (current_buffer, bidi_paragraph_direction), Qleft_to_right)) - it->paragraph_embedding = L2R; - else if (EQ (BVAR (current_buffer, bidi_paragraph_direction), Qright_to_left)) - it->paragraph_embedding = R2L; - else - it->paragraph_embedding = NEUTRAL_DIR; - bidi_init_it (charpos, bytepos, FRAME_WINDOW_P (it->f), &it->bidi_it); - } - /* If a buffer position was specified, set the iterator there, getting overlays and face properties from that position. */ if (charpos >= BUF_BEG (current_buffer)) @@ -2581,6 +2605,32 @@ IT_BYTEPOS (*it) = bytepos; it->start = it->current; + /* Do we need to reorder bidirectional text? Not if this is a + unibyte buffer: by definition, none of the single-byte + characters are strong R2L, so no reordering is needed. And + bidi.c doesn't support unibyte buffers anyway. */ + it->bidi_p = + !NILP (BVAR (current_buffer, bidi_display_reordering)) + && it->multibyte_p; + + /* If we are to reorder bidirectional text, init the bidi + iterator. */ + if (it->bidi_p) + { + /* Note the paragraph direction that this buffer wants to + use. */ + if (EQ (BVAR (current_buffer, bidi_paragraph_direction), + Qleft_to_right)) + it->paragraph_embedding = L2R; + else if (EQ (BVAR (current_buffer, bidi_paragraph_direction), + Qright_to_left)) + it->paragraph_embedding = R2L; + else + it->paragraph_embedding = NEUTRAL_DIR; + bidi_unshelve_cache (NULL); + bidi_init_it (charpos, IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f), + &it->bidi_it); + } /* Compute faces etc. */ reseat (it, it->current.pos, 1); @@ -2902,6 +2952,7 @@ { it->ignore_overlay_strings_at_pos_p = 1; it->string_from_display_prop_p = 0; + it->from_disp_prop_p = 0; handle_overlay_change_p = 0; } handled = HANDLED_RECOMPUTE_PROPS; @@ -3083,37 +3134,50 @@ return endpos; } -/* Return the character position of a display string at or after CHARPOS. - If no display string exists at or after CHARPOS, return ZV. A - display string is either an overlay with `display' property whose - value is a string, or a `display' text property whose value is a - string. FRAME_WINDOW_P is non-zero when we are displaying a window +/* Return the character position of a display string at or after + position specified by POSITION. If no display string exists at or + after POSITION, return ZV. A display string is either an overlay + with `display' property whose value is a string, or a `display' + 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. */ EMACS_INT -compute_display_string_pos (EMACS_INT charpos, int frame_window_p) +compute_display_string_pos (struct text_pos *position, + struct bidi_string_data *string, int frame_window_p) { - /* FIXME: Support display properties on strings (object = Qnil means - current buffer). */ - Lisp_Object object = Qnil; + /* OBJECT = nil means current buffer. */ + Lisp_Object object = + (string && STRINGP (string->lstring)) ? string->lstring : Qnil; Lisp_Object pos, spec; - struct text_pos position; - EMACS_INT bufpos; + int string_p = (string && (STRINGP (string->lstring) || string->s)); + EMACS_INT eob = string_p ? string->schars : ZV; + EMACS_INT begb = string_p ? 0 : BEGV; + EMACS_INT bufpos, charpos = CHARPOS (*position); + struct text_pos tpos; - if (charpos >= ZV) - return ZV; + if (charpos >= eob + /* We don't support display properties whose values are strings + that have display string properties. */ + || string->from_disp_str + /* C strings cannot have display properties. */ + || (string->s && !STRINGP (object))) + return eob; /* If the character at CHARPOS is where the display string begins, return CHARPOS. */ pos = make_number (charpos); - CHARPOS (position) = charpos; - BYTEPOS (position) = CHAR_TO_BYTE (charpos); - bufpos = charpos; /* FIXME! support strings as well */ + if (STRINGP (object)) + bufpos = string->bufpos; + else + bufpos = charpos; + tpos = *position; if (!NILP (spec = Fget_char_property (pos, Qdisplay, object)) - && (charpos <= BEGV + && (charpos <= begb || !EQ (Fget_char_property (make_number (charpos - 1), Qdisplay, object), spec)) - && handle_display_spec (NULL, spec, object, Qnil, &position, bufpos, + && handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos, frame_window_p)) return charpos; @@ -3121,17 +3185,21 @@ that will replace the underlying text when displayed. */ do { pos = Fnext_single_char_property_change (pos, Qdisplay, object, Qnil); - CHARPOS (position) = XFASTINT (pos); - BYTEPOS (position) = CHAR_TO_BYTE (CHARPOS (position)); - if (CHARPOS (position) >= ZV) + CHARPOS (tpos) = XFASTINT (pos); + if (STRINGP (object)) + BYTEPOS (tpos) = string_char_to_byte (object, CHARPOS (tpos)); + else + BYTEPOS (tpos) = CHAR_TO_BYTE (CHARPOS (tpos)); + if (CHARPOS (tpos) >= eob) break; spec = Fget_char_property (pos, Qdisplay, object); - bufpos = CHARPOS (position); /* FIXME! support strings as well */ + if (!STRINGP (object)) + bufpos = CHARPOS (tpos); } while (NILP (spec) - || !handle_display_spec (NULL, spec, object, Qnil, &position, bufpos, + || !handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos, frame_window_p)); - return CHARPOS (position); + return CHARPOS (tpos); } /* Return the character position of the end of the display string that @@ -3139,15 +3207,17 @@ `display' property whose value is a string or a `display' text property whose value is a string. */ EMACS_INT -compute_display_string_end (EMACS_INT charpos) +compute_display_string_end (EMACS_INT charpos, struct bidi_string_data *string) { - /* FIXME: Support display properties on strings (object = Qnil means - current buffer). */ - Lisp_Object object = Qnil; + /* OBJECT = nil means current buffer. */ + Lisp_Object object = + (string && STRINGP (string->lstring)) ? string->lstring : Qnil; Lisp_Object pos = make_number (charpos); + EMACS_INT eob = + (STRINGP (object) || (string && string->s)) ? string->schars : ZV; - if (charpos >= ZV) - return ZV; + if (charpos >= eob || (string->s && !STRINGP (object))) + return eob; if (NILP (Fget_char_property (pos, Qdisplay, object))) abort (); @@ -3440,21 +3510,23 @@ /* Compute the face one character before or after the current position - of IT. BEFORE_P non-zero means get the face in front of IT's - position. Value is the id of the face. */ + of IT, in the visual order. BEFORE_P non-zero means get the face + in front (to the left in L2R paragraphs, to the right in R2L + paragraphs) of IT's screen position. Value is the ID of the face. */ static int face_before_or_after_it_pos (struct it *it, int before_p) { int face_id, limit; EMACS_INT next_check_charpos; - struct text_pos pos; + struct it it_copy; + void *it_copy_data = NULL; xassert (it->s == NULL); if (STRINGP (it->string)) { - EMACS_INT bufpos; + EMACS_INT bufpos, charpos; int base_face_id; /* No face change past the end of the string (for the case @@ -3464,16 +3536,59 @@ || (IT_STRING_CHARPOS (*it) == 0 && before_p)) return it->face_id; - /* Set pos to the position before or after IT's current position. */ - if (before_p) - pos = string_pos (IT_STRING_CHARPOS (*it) - 1, it->string); + if (!it->bidi_p) + { + /* Set charpos to the position before or after IT's current + position, in the logical order, which in the non-bidi + case is the same as the visual order. */ + if (before_p) + charpos = IT_STRING_CHARPOS (*it) - 1; + else if (it->what == IT_COMPOSITION) + /* For composition, we must check the character after the + composition. */ + charpos = IT_STRING_CHARPOS (*it) + it->cmp_it.nchars; + else + charpos = IT_STRING_CHARPOS (*it) + 1; + } else - /* For composition, we must check the character after the - composition. */ - pos = (it->what == IT_COMPOSITION - ? string_pos (IT_STRING_CHARPOS (*it) - + it->cmp_it.nchars, it->string) - : string_pos (IT_STRING_CHARPOS (*it) + 1, it->string)); + { + if (before_p) + { + /* With bidi iteration, the character before the current + in the visual order cannot be found by simple + iteration, because "reverse" reordering is not + supported. Instead, we need to use the move_it_* + family of functions. */ + /* Ignore face changes before the first visible + character on this display line. */ + if (it->current_x <= it->first_visible_x) + return it->face_id; + SAVE_IT (it_copy, *it, it_copy_data); + /* Implementation note: Since move_it_in_display_line + works in the iterator geometry, and thinks the first + character is always the leftmost, even in R2L lines, + we don't need to distinguish between the R2L and L2R + cases here. */ + move_it_in_display_line (&it_copy, SCHARS (it_copy.string), + it_copy.current_x - 1, MOVE_TO_X); + charpos = IT_STRING_CHARPOS (it_copy); + RESTORE_IT (it, it, it_copy_data); + } + else + { + /* Set charpos to the string position of the character + that comes after IT's current position in the visual + order. */ + int n = (it->what == IT_COMPOSITION ? it->cmp_it.nchars : 1); + + it_copy = *it; + while (n--) + bidi_move_to_visually_next (&it_copy.bidi_it); + + charpos = it_copy.bidi_it.charpos; + } + } + xassert (0 <= charpos && charpos <= SCHARS (it->string)); if (it->current.overlay_string_index >= 0) bufpos = IT_CHARPOS (*it); @@ -3485,7 +3600,7 @@ /* Get the face for ASCII, or unibyte. */ face_id = face_at_string_position (it->w, it->string, - CHARPOS (pos), + charpos, bufpos, it->region_beg_charpos, it->region_end_charpos, @@ -3497,16 +3612,19 @@ suitable for unibyte text if IT->string is unibyte. */ if (STRING_MULTIBYTE (it->string)) { - const unsigned char *p = SDATA (it->string) + BYTEPOS (pos); + struct text_pos pos1 = string_pos (charpos, it->string); + const unsigned char *p = SDATA (it->string) + BYTEPOS (pos1); int c, len; struct face *face = FACE_FROM_ID (it->f, face_id); c = string_char_and_length (p, &len); - face_id = FACE_FOR_CHAR (it->f, face, c, CHARPOS (pos), it->string); + face_id = FACE_FOR_CHAR (it->f, face, c, charpos, it->string); } } else { + struct text_pos pos; + if ((IT_CHARPOS (*it) >= ZV && !before_p) || (IT_CHARPOS (*it) <= BEGV && before_p)) return it->face_id; @@ -3514,17 +3632,63 @@ limit = IT_CHARPOS (*it) + TEXT_PROP_DISTANCE_LIMIT; pos = it->current.pos; - if (before_p) - DEC_TEXT_POS (pos, it->multibyte_p); + if (!it->bidi_p) + { + if (before_p) + DEC_TEXT_POS (pos, it->multibyte_p); + else + { + if (it->what == IT_COMPOSITION) + { + /* For composition, we must check the position after + the composition. */ + pos.charpos += it->cmp_it.nchars; + pos.bytepos += it->len; + } + else + INC_TEXT_POS (pos, it->multibyte_p); + } + } else { - if (it->what == IT_COMPOSITION) - /* For composition, we must check the position after the - composition. */ - pos.charpos += it->cmp_it.nchars, pos.bytepos += it->len; + if (before_p) + { + /* With bidi iteration, the character before the current + in the visual order cannot be found by simple + iteration, because "reverse" reordering is not + supported. Instead, we need to use the move_it_* + family of functions. */ + /* Ignore face changes before the first visible + character on this display line. */ + if (it->current_x <= it->first_visible_x) + return it->face_id; + SAVE_IT (it_copy, *it, it_copy_data); + /* Implementation note: Since move_it_in_display_line + works in the iterator geometry, and thinks the first + character is always the leftmost, even in R2L lines, + we don't need to distinguish between the R2L and L2R + cases here. */ + move_it_in_display_line (&it_copy, ZV, + it_copy.current_x - 1, MOVE_TO_X); + pos = it_copy.current.pos; + RESTORE_IT (it, it, it_copy_data); + } else - INC_TEXT_POS (pos, it->multibyte_p); + { + /* Set charpos to the buffer position of the character + that comes after IT's current position in the visual + order. */ + int n = (it->what == IT_COMPOSITION ? it->cmp_it.nchars : 1); + + it_copy = *it; + while (n--) + bidi_move_to_visually_next (&it_copy.bidi_it); + + SET_TEXT_POS (pos, + it_copy.bidi_it.charpos, it_copy.bidi_it.bytepos); + } } + xassert (BEGV <= CHARPOS (pos) && CHARPOS (pos) <= ZV); /* Determine face for CHARSET_ASCII, or unibyte. */ face_id = face_at_buffer_position (it->w, @@ -3575,6 +3739,8 @@ if (!NILP (prop) && IT_STRING_CHARPOS (*it) < it->end_charpos) { + EMACS_INT endpos; + handled = HANDLED_RECOMPUTE_PROPS; /* Get the position at which the next change of the @@ -3589,12 +3755,37 @@ change in the property is at position end_charpos. Move IT's current position to that position. */ if (INTEGERP (end_charpos) - && XFASTINT (end_charpos) < XFASTINT (limit)) + && (endpos = XFASTINT (end_charpos)) < XFASTINT (limit)) { struct text_pos old; + EMACS_INT oldpos; + old = it->current.string_pos; - IT_STRING_CHARPOS (*it) = XFASTINT (end_charpos); - compute_string_pos (&it->current.string_pos, old, it->string); + oldpos = CHARPOS (old); + if (it->bidi_p) + { + if (it->bidi_it.first_elt + && it->bidi_it.charpos < SCHARS (it->string)) + bidi_paragraph_init (it->paragraph_embedding, + &it->bidi_it, 1); + /* Bidi-iterate out of the invisible text. */ + do + { + bidi_move_to_visually_next (&it->bidi_it); + } + while (oldpos <= it->bidi_it.charpos + && it->bidi_it.charpos < endpos); + + IT_STRING_CHARPOS (*it) = it->bidi_it.charpos; + IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos; + if (IT_CHARPOS (*it) >= endpos) + it->prev_stop = endpos; + } + else + { + IT_STRING_CHARPOS (*it) = XFASTINT (end_charpos); + compute_string_pos (&it->current.string_pos, old, it->string); + } } else { @@ -4244,6 +4435,7 @@ it->method = GET_FROM_IMAGE; it->from_overlay = Qnil; it->face_id = face_id; + it->from_disp_prop_p = 1; /* Say that we haven't consumed the characters with `display' property yet. The call to pop_it in @@ -4316,6 +4508,7 @@ when we are finished with the glyph property value. */ push_it (it, position); it->from_overlay = overlay; + it->from_disp_prop_p = 1; if (NILP (location)) it->area = TEXT_AREA; @@ -4333,12 +4526,34 @@ it->end_charpos = it->string_nchars = SCHARS (it->string); it->method = GET_FROM_STRING; it->stop_charpos = 0; + it->prev_stop = 0; + it->base_level_stop = 0; it->string_from_display_prop_p = 1; /* Say that we haven't consumed the characters with `display' property yet. The call to pop_it in set_iterator_to_next will clean this up. */ if (BUFFERP (object)) *position = start_pos; + + /* Force paragraph direction to be that of the parent + object. If the parent object's paragraph direction is + not yet determined, default to L2R. */ + if (it->bidi_p && it->bidi_it.paragraph_dir == R2L) + it->paragraph_embedding = it->bidi_it.paragraph_dir; + else + it->paragraph_embedding = L2R; + + /* Set up the bidi iterator for this display string. */ + if (it->bidi_p) + { + it->bidi_it.string.lstring = it->string; + it->bidi_it.string.s = NULL; + it->bidi_it.string.schars = it->end_charpos; + it->bidi_it.string.bufpos = bufpos; + it->bidi_it.string.from_disp_str = 1; + it->bidi_it.string.unibyte = !it->multibyte_p; + bidi_init_it (0, 0, FRAME_WINDOW_P (it->f), &it->bidi_it); + } } else if (CONSP (value) && EQ (XCAR (value), Qspace)) { @@ -4695,6 +4910,20 @@ it->stop_charpos = 0; if (it->cmp_it.stop_pos >= 0) it->cmp_it.stop_pos = 0; + it->prev_stop = 0; + it->base_level_stop = 0; + + /* Set up the bidi iterator for this overlay string. */ + if (it->bidi_p) + { + it->bidi_it.string.lstring = it->string; + it->bidi_it.string.s = NULL; + it->bidi_it.string.schars = SCHARS (it->string); + it->bidi_it.string.bufpos = it->overlay_strings_charpos; + it->bidi_it.string.from_disp_str = it->string_from_display_prop_p; + it->bidi_it.string.unibyte = !it->multibyte_p; + bidi_init_it (0, 0, FRAME_WINDOW_P (it->f), &it->bidi_it); + } } CHECK_IT (it); @@ -4961,8 +5190,32 @@ it->stop_charpos = 0; xassert (STRINGP (it->string)); it->end_charpos = SCHARS (it->string); + it->prev_stop = 0; + it->base_level_stop = 0; it->multibyte_p = STRING_MULTIBYTE (it->string); it->method = GET_FROM_STRING; + it->from_disp_prop_p = 0; + + /* Force paragraph direction to be that of the parent + buffer. */ + if (it->bidi_p && it->bidi_it.paragraph_dir == R2L) + it->paragraph_embedding = it->bidi_it.paragraph_dir; + else + it->paragraph_embedding = L2R; + + /* Set up the bidi iterator for this overlay string. */ + if (it->bidi_p) + { + EMACS_INT pos = (charpos > 0 ? charpos : IT_CHARPOS (*it)); + + it->bidi_it.string.lstring = it->string; + it->bidi_it.string.s = NULL; + it->bidi_it.string.schars = SCHARS (it->string); + it->bidi_it.string.bufpos = pos; + it->bidi_it.string.from_disp_str = it->string_from_display_prop_p; + it->bidi_it.string.unibyte = !it->multibyte_p; + bidi_init_it (0, 0, FRAME_WINDOW_P (it->f), &it->bidi_it); + } return 1; } @@ -5037,19 +5290,30 @@ p->string_from_display_prop_p = it->string_from_display_prop_p; p->display_ellipsis_p = 0; p->line_wrap = it->line_wrap; + p->bidi_p = it->bidi_p; + p->paragraph_embedding = it->paragraph_embedding; + p->from_disp_prop_p = it->from_disp_prop_p; ++it->sp; + + /* Save the state of the bidi iterator as well. */ + if (it->bidi_p) + bidi_push_it (&it->bidi_it); } static void iterate_out_of_display_property (struct it *it) { + int buffer_p = BUFFERP (it->object); + EMACS_INT eob = (buffer_p ? ZV : it->end_charpos); + EMACS_INT bob = (buffer_p ? BEGV : 0); + /* Maybe initialize paragraph direction. If we are at the beginning of a new paragraph, next_element_from_buffer may not have a chance to do that. */ - if (it->bidi_it.first_elt && it->bidi_it.charpos < ZV) + if (it->bidi_it.first_elt && it->bidi_it.charpos < eob) bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 1); /* prev_stop can be zero, so check against BEGV as well. */ - while (it->bidi_it.charpos >= BEGV + while (it->bidi_it.charpos >= bob && it->prev_stop <= it->bidi_it.charpos && it->bidi_it.charpos < CHARPOS (it->position)) bidi_move_to_visually_next (&it->bidi_it); @@ -5063,7 +5327,10 @@ { SET_TEXT_POS (it->position, it->bidi_it.charpos, it->bidi_it.bytepos); - it->current.pos = it->position; + if (buffer_p) + it->current.pos = it->position; + else + it->current.string_pos = it->position; } } @@ -5077,6 +5344,7 @@ pop_it (struct it *it) { struct iterator_stack_entry *p; + int from_display_prop = it->from_disp_prop_p; xassert (it->sp > 0); --it->sp; @@ -5101,22 +5369,10 @@ it->slice = p->u.image.slice; break; case GET_FROM_STRETCH: - it->object = p->u.comp.object; + it->object = p->u.stretch.object; break; case GET_FROM_BUFFER: it->object = it->w->buffer; - if (it->bidi_p) - { - /* Bidi-iterate until we get out of the portion of text, if - any, covered by a `display' text property or an overlay - with `display' property. (We cannot just jump there, - because the internal coherency of the bidi iterator state - can not be preserved across such jumps.) We also must - determine the paragraph base direction if the overlay we - just processed is at the beginning of a new - paragraph. */ - iterate_out_of_display_property (it); - } break; case GET_FROM_STRING: it->object = it->string; @@ -5142,6 +5398,30 @@ it->voffset = p->voffset; it->string_from_display_prop_p = p->string_from_display_prop_p; it->line_wrap = p->line_wrap; + it->bidi_p = p->bidi_p; + it->paragraph_embedding = p->paragraph_embedding; + it->from_disp_prop_p = p->from_disp_prop_p; + if (it->bidi_p) + { + bidi_pop_it (&it->bidi_it); + /* Bidi-iterate until we get out of the portion of text, if any, + covered by a `display' text property or by an overlay with + `display' property. (We cannot just jump there, because the + internal coherency of the bidi iterator state can not be + preserved across such jumps.) We also must determine the + paragraph base direction if the overlay we just processed is + at the beginning of a new paragraph. */ + if (from_display_prop + && (it->method == GET_FROM_BUFFER || it->method == GET_FROM_STRING)) + iterate_out_of_display_property (it); + + xassert ((BUFFERP (it->object) + && IT_CHARPOS (*it) == it->bidi_it.charpos + && IT_BYTEPOS (*it) == it->bidi_it.bytepos) + || (STRINGP (it->object) + && IT_STRING_CHARPOS (*it) == it->bidi_it.charpos + && IT_STRING_BYTEPOS (*it) == it->bidi_it.bytepos)); + } } @@ -5225,15 +5505,16 @@ xassert (!STRINGP (it->string)); - /* If there isn't any `display' property in sight, and no - overlays, we can just use the position of the newline in - buffer text. */ - if (it->stop_charpos >= limit - || ((pos = Fnext_single_property_change (make_number (start), - Qdisplay, - Qnil, make_number (limit)), - NILP (pos)) - && next_overlay_change (start) == ZV)) + /* If we are not bidi-reordering, and there isn't any `display' + property in sight, and no overlays, we can just use the + position of the newline in buffer text. */ + if (!it->bidi_p + && (it->stop_charpos >= limit + || ((pos = Fnext_single_property_change (make_number (start), + Qdisplay, Qnil, + make_number (limit)), + NILP (pos)) + && next_overlay_change (start) == ZV))) { IT_CHARPOS (*it) = limit; IT_BYTEPOS (*it) = CHAR_TO_BYTE (limit); @@ -5291,10 +5572,13 @@ { struct it it2; + void *it2data = NULL; EMACS_INT pos; EMACS_INT beg, end; Lisp_Object val, overlay; + SAVE_IT (it2, *it, it2data); + /* If newline is part of a composition, continue from start of composition */ if (find_composition (IT_CHARPOS (*it), -1, &beg, &end, &val, Qnil) && beg < IT_CHARPOS (*it)) @@ -5302,20 +5586,25 @@ /* If newline is replaced by a display property, find start of overlay or interval and continue search from that point. */ - it2 = *it; pos = --IT_CHARPOS (it2); --IT_BYTEPOS (it2); it2.sp = 0; + bidi_unshelve_cache (NULL); it2.string_from_display_prop_p = 0; + it2.from_disp_prop_p = 0; if (handle_display_prop (&it2) == HANDLED_RETURN && !NILP (val = get_char_property_and_overlay (make_number (pos), Qdisplay, Qnil, &overlay)) && (OVERLAYP (overlay) ? (beg = OVERLAY_POSITION (OVERLAY_START (overlay))) : get_property_and_range (pos, Qdisplay, &val, &beg, &end, Qnil))) - goto replaced; + { + RESTORE_IT (it, it, it2data); + goto replaced; + } /* Newline is not replaced by anything -- so we are done. */ + RESTORE_IT (it, it, it2data); break; replaced: @@ -5382,14 +5671,29 @@ { if (IT_STRING_CHARPOS (*it) > 0) { - --IT_STRING_CHARPOS (*it); - --IT_STRING_BYTEPOS (*it); + if (!it->bidi_p) + { + --IT_STRING_CHARPOS (*it); + --IT_STRING_BYTEPOS (*it); + } + else + /* Setting this flag will cause + bidi_move_to_visually_next not to advance, but + instead deliver the current character (newline), + which is what the ON_NEWLINE_P flag wants. */ + it->bidi_it.first_elt = 1; } } else if (IT_CHARPOS (*it) > BEGV) { - --IT_CHARPOS (*it); - --IT_BYTEPOS (*it); + if (!it->bidi_p) + { + --IT_CHARPOS (*it); + --IT_BYTEPOS (*it); + } + /* With bidi iteration, the call to `reseat' will cause + bidi_move_to_visually_next deliver the current character, + the newline, instead of advancing. */ reseat (it, it->current.pos, 0); } } @@ -5471,19 +5775,24 @@ IT_STRING_CHARPOS (*it) = -1; IT_STRING_BYTEPOS (*it) = -1; it->string = Qnil; - it->string_from_display_prop_p = 0; it->method = GET_FROM_BUFFER; it->object = it->w->buffer; it->area = TEXT_AREA; it->multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters)); it->sp = 0; it->string_from_display_prop_p = 0; + it->from_disp_prop_p = 0; it->face_before_selective_p = 0; if (it->bidi_p) { - it->bidi_it.first_elt = 1; + bidi_init_it (IT_CHARPOS (*it), IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f), + &it->bidi_it); + bidi_unshelve_cache (NULL); it->bidi_it.paragraph_dir = NEUTRAL_DIR; - it->bidi_it.disp_pos = -1; + it->bidi_it.string.s = NULL; + it->bidi_it.string.lstring = Qnil; + it->bidi_it.string.bufpos = 0; + it->bidi_it.string.unibyte = 0; } if (set_stop_p) @@ -5534,6 +5843,10 @@ if (multibyte >= 0) it->multibyte_p = multibyte > 0; + /* Bidirectional reordering of strings is controlled by the default + value of bidi-display-reordering. */ + it->bidi_p = !NILP (BVAR (&buffer_defaults, bidi_display_reordering)); + if (s == NULL) { xassert (STRINGP (string)); @@ -5542,6 +5855,18 @@ it->end_charpos = it->string_nchars = SCHARS (string); it->method = GET_FROM_STRING; it->current.string_pos = string_pos (charpos, string); + + if (it->bidi_p) + { + it->bidi_it.string.lstring = string; + it->bidi_it.string.s = NULL; + it->bidi_it.string.schars = it->end_charpos; + it->bidi_it.string.bufpos = 0; + it->bidi_it.string.from_disp_str = 0; + it->bidi_it.string.unibyte = !it->multibyte_p; + bidi_init_it (charpos, IT_STRING_BYTEPOS (*it), + FRAME_WINDOW_P (it->f), &it->bidi_it); + } } else { @@ -5562,13 +5887,28 @@ it->end_charpos = it->string_nchars = strlen (s); } + if (it->bidi_p) + { + it->bidi_it.string.lstring = Qnil; + it->bidi_it.string.s = s; + it->bidi_it.string.schars = it->end_charpos; + it->bidi_it.string.bufpos = 0; + it->bidi_it.string.from_disp_str = 0; + it->bidi_it.string.unibyte = !it->multibyte_p; + bidi_init_it (charpos, IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f), + &it->bidi_it); + } it->method = GET_FROM_C_STRING; } /* PRECISION > 0 means don't return more than PRECISION characters from the string. */ if (precision > 0 && it->end_charpos - charpos > precision) - it->end_charpos = it->string_nchars = charpos + precision; + { + it->end_charpos = it->string_nchars = charpos + precision; + if (it->bidi_p) + it->bidi_it.string.schars = it->end_charpos; + } /* FIELD_WIDTH > 0 means pad with spaces until FIELD_WIDTH characters have been returned. FIELD_WIDTH == 0 means don't pad, @@ -5576,6 +5916,9 @@ padding with `-' at the end of a mode line. */ if (field_width < 0) field_width = INFINITY; + /* Implementation note: We deliberately don't enlarge + it->bidi_it.string.schars here to fit it->end_charpos, because + the bidi iterator cannot produce characters out of thin air. */ if (field_width > it->end_charpos - charpos) it->end_charpos = charpos + field_width; @@ -5584,6 +5927,14 @@ it->dp = XCHAR_TABLE (Vstandard_display_table); it->stop_charpos = charpos; + it->prev_stop = charpos; + it->base_level_stop = 0; + if (it->bidi_p) + { + it->bidi_it.first_elt = 1; + it->bidi_it.paragraph_dir = NEUTRAL_DIR; + it->bidi_it.disp_pos = -1; + } if (s == NULL && it->multibyte_p) { EMACS_INT endpos = SCHARS (it->string); @@ -6218,8 +6569,22 @@ case GET_FROM_C_STRING: /* Current display element of IT is from a C string. */ - IT_BYTEPOS (*it) += it->len; - IT_CHARPOS (*it) += 1; + if (!it->bidi_p + /* If the string position is beyond string's end, it means + next_element_from_c_string is padding the string with + blanks, in which case we bypass the bidi iterator, + because it cannot deal with such virtual characters. */ + || IT_CHARPOS (*it) >= it->bidi_it.string.schars) + { + IT_BYTEPOS (*it) += it->len; + IT_CHARPOS (*it) += 1; + } + else + { + bidi_move_to_visually_next (&it->bidi_it); + IT_BYTEPOS (*it) = it->bidi_it.bytepos; + IT_CHARPOS (*it) = it->bidi_it.charpos; + } break; case GET_FROM_DISPLAY_VECTOR: @@ -6273,23 +6638,95 @@ xassert (it->s == NULL && STRINGP (it->string)); if (it->cmp_it.id >= 0) { - IT_STRING_CHARPOS (*it) += it->cmp_it.nchars; - IT_STRING_BYTEPOS (*it) += it->cmp_it.nbytes; - if (it->cmp_it.to < it->cmp_it.nglyphs) - it->cmp_it.from = it->cmp_it.to; + int i; + + if (! it->bidi_p) + { + IT_STRING_CHARPOS (*it) += it->cmp_it.nchars; + IT_STRING_BYTEPOS (*it) += it->cmp_it.nbytes; + if (it->cmp_it.to < it->cmp_it.nglyphs) + it->cmp_it.from = it->cmp_it.to; + else + { + it->cmp_it.id = -1; + composition_compute_stop_pos (&it->cmp_it, + IT_STRING_CHARPOS (*it), + IT_STRING_BYTEPOS (*it), + it->end_charpos, it->string); + } + } + else if (! it->cmp_it.reversed_p) + { + for (i = 0; i < it->cmp_it.nchars; i++) + bidi_move_to_visually_next (&it->bidi_it); + IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos; + IT_STRING_CHARPOS (*it) = it->bidi_it.charpos; + + if (it->cmp_it.to < it->cmp_it.nglyphs) + it->cmp_it.from = it->cmp_it.to; + else + { + EMACS_INT stop = it->end_charpos; + if (it->bidi_it.scan_dir < 0) + stop = -1; + composition_compute_stop_pos (&it->cmp_it, + IT_STRING_CHARPOS (*it), + IT_STRING_BYTEPOS (*it), stop, + it->string); + } + } else { - it->cmp_it.id = -1; - composition_compute_stop_pos (&it->cmp_it, - IT_STRING_CHARPOS (*it), - IT_STRING_BYTEPOS (*it), - it->end_charpos, it->string); + for (i = 0; i < it->cmp_it.nchars; i++) + bidi_move_to_visually_next (&it->bidi_it); + IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos; + IT_STRING_CHARPOS (*it) = it->bidi_it.charpos; + if (it->cmp_it.from > 0) + it->cmp_it.to = it->cmp_it.from; + else + { + EMACS_INT stop = it->end_charpos; + if (it->bidi_it.scan_dir < 0) + stop = -1; + composition_compute_stop_pos (&it->cmp_it, + IT_STRING_CHARPOS (*it), + IT_STRING_BYTEPOS (*it), stop, + it->string); + } } } else { - IT_STRING_BYTEPOS (*it) += it->len; - IT_STRING_CHARPOS (*it) += 1; + if (!it->bidi_p + /* If the string position is beyond string's end, it + means next_element_from_string is padding the string + with blanks, in which case we bypass the bidi + iterator, because it cannot deal with such virtual + characters. */ + || IT_STRING_CHARPOS (*it) >= it->bidi_it.string.schars) + { + IT_STRING_BYTEPOS (*it) += it->len; + IT_STRING_CHARPOS (*it) += 1; + } + else + { + int prev_scan_dir = it->bidi_it.scan_dir; + + bidi_move_to_visually_next (&it->bidi_it); + IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos; + IT_STRING_CHARPOS (*it) = it->bidi_it.charpos; + if (prev_scan_dir != it->bidi_it.scan_dir) + { + EMACS_INT stop = it->end_charpos; + + if (it->bidi_it.scan_dir < 0) + stop = -1; + composition_compute_stop_pos (&it->cmp_it, + IT_STRING_CHARPOS (*it), + IT_STRING_BYTEPOS (*it), stop, + it->string); + } + } } consider_string_end: @@ -6395,6 +6832,107 @@ return 1; } +/* Get the first element of string/buffer in the visual order, after + being reseated to a new position in a string or a buffer. */ +static void +get_visually_first_element (struct it *it) +{ + int string_p = STRINGP (it->string) || it->s; + EMACS_INT eob = (string_p ? it->bidi_it.string.schars : ZV); + EMACS_INT bob = (string_p ? 0 : BEGV); + + if (STRINGP (it->string)) + { + it->bidi_it.charpos = IT_STRING_CHARPOS (*it); + it->bidi_it.bytepos = IT_STRING_BYTEPOS (*it); + } + else + { + it->bidi_it.charpos = IT_CHARPOS (*it); + it->bidi_it.bytepos = IT_BYTEPOS (*it); + } + + if (it->bidi_it.charpos == eob) + { + /* Nothing to do, but reset the FIRST_ELT flag, like + bidi_paragraph_init does, because we are not going to + call it. */ + it->bidi_it.first_elt = 0; + } + else if (it->bidi_it.charpos == bob + || (!string_p + /* FIXME: Should support all Unicode line separators. */ + && (FETCH_CHAR (it->bidi_it.bytepos - 1) == '\n' + || FETCH_CHAR (it->bidi_it.bytepos) == '\n'))) + { + /* If we are at the beginning of a line/string, we can produce + the next element right away. */ + bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 1); + bidi_move_to_visually_next (&it->bidi_it); + } + else + { + EMACS_INT orig_bytepos = it->bidi_it.bytepos; + + /* We need to prime the bidi iterator starting at the line's or + string's beginning, before we will be able to produce the + next element. */ + if (string_p) + it->bidi_it.charpos = it->bidi_it.bytepos = 0; + else + { + it->bidi_it.charpos = find_next_newline_no_quit (IT_CHARPOS (*it), + -1); + it->bidi_it.bytepos = CHAR_TO_BYTE (it->bidi_it.charpos); + } + bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 1); + do + { + /* Now return to buffer/string position where we were asked + to get the next display element, and produce that. */ + bidi_move_to_visually_next (&it->bidi_it); + } + while (it->bidi_it.bytepos != orig_bytepos + && it->bidi_it.charpos < eob); + } + + /* Adjust IT's position information to where we ended up. */ + if (STRINGP (it->string)) + { + IT_STRING_CHARPOS (*it) = it->bidi_it.charpos; + IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos; + } + else + { + IT_CHARPOS (*it) = it->bidi_it.charpos; + IT_BYTEPOS (*it) = it->bidi_it.bytepos; + } + + if (STRINGP (it->string) || !it->s) + { + EMACS_INT stop, charpos, bytepos; + + if (STRINGP (it->string)) + { + xassert (!it->s); + stop = SCHARS (it->string); + if (stop > it->end_charpos) + stop = it->end_charpos; + charpos = IT_STRING_CHARPOS (*it); + bytepos = IT_STRING_BYTEPOS (*it); + } + else + { + stop = it->end_charpos; + charpos = IT_CHARPOS (*it); + bytepos = IT_BYTEPOS (*it); + } + if (it->bidi_it.scan_dir < 0) + stop = -1; + composition_compute_stop_pos (&it->cmp_it, charpos, bytepos, stop, + it->string); + } +} /* Load IT with the next display element from Lisp string IT->string. IT->current.string_pos is the current position within the string. @@ -6407,18 +6945,79 @@ struct text_pos position; xassert (STRINGP (it->string)); + xassert (!it->bidi_p || it->string == it->bidi_it.string.lstring); xassert (IT_STRING_CHARPOS (*it) >= 0); position = it->current.string_pos; + /* With bidi reordering, the character to display might not be the + character at IT_STRING_CHARPOS. BIDI_IT.FIRST_ELT non-zero means + that we were reseat()ed to a new string, whose paragraph + direction is not known. */ + if (it->bidi_p && it->bidi_it.first_elt) + { + get_visually_first_element (it); + SET_TEXT_POS (position, IT_STRING_CHARPOS (*it), IT_STRING_BYTEPOS (*it)); + } + /* Time to check for invisible text? */ - if (IT_STRING_CHARPOS (*it) < it->end_charpos - && IT_STRING_CHARPOS (*it) == it->stop_charpos) + if (IT_STRING_CHARPOS (*it) < it->end_charpos) { - handle_stop (it); + if (IT_STRING_CHARPOS (*it) >= it->stop_charpos) + { + if (!(!it->bidi_p + || BIDI_AT_BASE_LEVEL (it->bidi_it) + || IT_STRING_CHARPOS (*it) == it->stop_charpos)) + { + /* With bidi non-linear iteration, we could find + ourselves far beyond the last computed stop_charpos, + with several other stop positions in between that we + missed. Scan them all now, in buffer's logical + order, until we find and handle the last stop_charpos + that precedes our current position. */ + handle_stop_backwards (it, it->stop_charpos); + return GET_NEXT_DISPLAY_ELEMENT (it); + } + else + { + if (it->bidi_p) + { + /* Take note of the stop position we just moved + across, for when we will move back across it. */ + it->prev_stop = it->stop_charpos; + /* If we are at base paragraph embedding level, take + note of the last stop position seen at this + level. */ + if (BIDI_AT_BASE_LEVEL (it->bidi_it)) + it->base_level_stop = it->stop_charpos; + } + handle_stop (it); - /* Since a handler may have changed IT->method, we must - recurse here. */ - return GET_NEXT_DISPLAY_ELEMENT (it); + /* Since a handler may have changed IT->method, we must + recurse here. */ + return GET_NEXT_DISPLAY_ELEMENT (it); + } + } + else if (it->bidi_p + /* If we are before prev_stop, we may have overstepped + on our way backwards a stop_pos, and if so, we need + to handle that stop_pos. */ + && IT_STRING_CHARPOS (*it) < it->prev_stop + /* We can sometimes back up for reasons that have nothing + to do with bidi reordering. E.g., compositions. The + code below is only needed when we are above the base + embedding level, so test for that explicitly. */ + && !BIDI_AT_BASE_LEVEL (it->bidi_it)) + { + /* If we lost track of base_level_stop, we have no better place + for handle_stop_backwards to start from than BEGV. This + happens, e.g., when we were reseated to the previous + screenful of text by vertical-motion. */ + if (it->base_level_stop <= 0 + || IT_STRING_CHARPOS (*it) < it->base_level_stop) + it->base_level_stop = 0; + handle_stop_backwards (it, it->base_level_stop); + return GET_NEXT_DISPLAY_ELEMENT (it); + } } if (it->current.overlay_string_index >= 0) @@ -6432,7 +7031,10 @@ return 0; } else if (CHAR_COMPOSED_P (it, IT_STRING_CHARPOS (*it), - IT_STRING_BYTEPOS (*it), SCHARS (it->string)) + IT_STRING_BYTEPOS (*it), + it->bidi_it.scan_dir < 0 + ? -1 + : SCHARS (it->string)) && next_element_from_composition (it)) { return 1; @@ -6467,7 +7069,10 @@ CHARPOS (position) = BYTEPOS (position) = -1; } else if (CHAR_COMPOSED_P (it, IT_STRING_CHARPOS (*it), - IT_STRING_BYTEPOS (*it), it->string_nchars) + IT_STRING_BYTEPOS (*it), + it->bidi_it.scan_dir < 0 + ? -1 + : it->string_nchars) && next_element_from_composition (it)) { return 1; @@ -6506,12 +7111,20 @@ int success_p = 1; xassert (it->s); + xassert (!it->bidi_p || it->s == it->bidi_it.string.s); it->what = IT_CHARACTER; BYTEPOS (it->position) = CHARPOS (it->position) = 0; it->object = Qnil; - /* IT's position can be greater IT->string_nchars in case a field - width or precision has been specified when the iterator was + /* With bidi reordering, the character to display might not be the + character at IT_CHARPOS. BIDI_IT.FIRST_ELT non-zero means that + we were reseated to a new string, whose paragraph direction is + not known. */ + if (it->bidi_p && it->bidi_it.first_elt) + get_visually_first_element (it); + + /* IT's position can be greater than IT->string_nchars in case a + field width or precision has been specified when the iterator was initialized. */ if (IT_CHARPOS (*it) >= it->end_charpos) { @@ -6586,18 +7199,19 @@ return 1; } -/* Scan forward from CHARPOS in the current buffer, until we find a - stop position > current IT's position. Then handle the stop +/* Scan forward from CHARPOS in the current buffer/string, until we + find a stop position > current IT's position. Then handle the stop position before that. This is called when we bump into a stop position while reordering bidirectional text. CHARPOS should be - the last previously processed stop_pos (or BEGV, if none were + the last previously processed stop_pos (or BEGV/0, if none were processed yet) whose position is less that IT's current position. */ static void handle_stop_backwards (struct it *it, EMACS_INT charpos) { - EMACS_INT where_we_are = IT_CHARPOS (*it); + int bufp = !STRINGP (it->string); + EMACS_INT where_we_are = (bufp ? IT_CHARPOS (*it) : IT_STRING_CHARPOS (*it)); struct display_pos save_current = it->current; struct text_pos save_position = it->position; struct text_pos pos1; @@ -6608,8 +7222,13 @@ do { it->prev_stop = charpos; - SET_TEXT_POS (pos1, charpos, CHAR_TO_BYTE (charpos)); - reseat_1 (it, pos1, 0); + if (bufp) + { + SET_TEXT_POS (pos1, charpos, CHAR_TO_BYTE (charpos)); + reseat_1 (it, pos1, 0); + } + else + it->current.string_pos = string_pos (charpos, it->string); compute_stop_pos (it); /* We must advance forward, right? */ if (it->stop_charpos <= it->prev_stop) @@ -6638,6 +7257,10 @@ int success_p = 1; xassert (IT_CHARPOS (*it) >= BEGV); + xassert (NILP (it->string) && !it->s); + xassert (!it->bidi_p + || (it->bidi_it.string.lstring == Qnil + && it->bidi_it.string.s == NULL)); /* With bidi reordering, the character to display might not be the character at IT_CHARPOS. BIDI_IT.FIRST_ELT non-zero means that @@ -6645,59 +7268,8 @@ a different paragraph. */ if (it->bidi_p && it->bidi_it.first_elt) { - it->bidi_it.charpos = IT_CHARPOS (*it); - it->bidi_it.bytepos = IT_BYTEPOS (*it); - if (it->bidi_it.bytepos == ZV_BYTE) - { - /* Nothing to do, but reset the FIRST_ELT flag, like - bidi_paragraph_init does, because we are not going to - call it. */ - it->bidi_it.first_elt = 0; - } - else if (it->bidi_it.bytepos == BEGV_BYTE - /* FIXME: Should support all Unicode line separators. */ - || FETCH_CHAR (it->bidi_it.bytepos - 1) == '\n' - || FETCH_CHAR (it->bidi_it.bytepos) == '\n') - { - /* If we are at the beginning of a line, we can produce the - next element right away. */ - bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 1); - bidi_move_to_visually_next (&it->bidi_it); - } - else - { - EMACS_INT orig_bytepos = IT_BYTEPOS (*it); - - /* We need to prime the bidi iterator starting at the line's - beginning, before we will be able to produce the next - element. */ - IT_CHARPOS (*it) = find_next_newline_no_quit (IT_CHARPOS (*it), -1); - 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 (it->paragraph_embedding, &it->bidi_it, 1); - do - { - /* Now return to buffer position where we were asked to - get the next display element, and produce that. */ - bidi_move_to_visually_next (&it->bidi_it); - } - while (it->bidi_it.bytepos != orig_bytepos - && it->bidi_it.bytepos < ZV_BYTE); - } - - it->bidi_it.first_elt = 0; /* paranoia: bidi.c does this */ - /* Adjust IT's position information to where we ended up. */ - IT_CHARPOS (*it) = it->bidi_it.charpos; - IT_BYTEPOS (*it) = it->bidi_it.bytepos; + get_visually_first_element (it); SET_TEXT_POS (it->position, IT_CHARPOS (*it), IT_BYTEPOS (*it)); - { - EMACS_INT stop = it->end_charpos; - if (it->bidi_it.scan_dir < 0) - stop = -1; - composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it), - IT_BYTEPOS (*it), stop, Qnil); - } } if (IT_CHARPOS (*it) >= it->stop_charpos) @@ -6756,17 +7328,23 @@ } } else if (it->bidi_p + /* If we are before prev_stop, we may have overstepped on + our way backwards a stop_pos, and if so, we need to + handle that stop_pos. */ + && IT_CHARPOS (*it) < it->prev_stop /* We can sometimes back up for reasons that have nothing to do with bidi reordering. E.g., compositions. The code below is only needed when we are above the base embedding level, so test for that explicitly. */ - && !BIDI_AT_BASE_LEVEL (it->bidi_it) - && IT_CHARPOS (*it) < it->prev_stop) + && !BIDI_AT_BASE_LEVEL (it->bidi_it)) { - if (it->base_level_stop <= 0) + /* If we lost track of base_level_stop, we have no better place + for handle_stop_backwards to start from than BEGV. This + happens, e.g., when we were reseated to the previous + screenful of text by vertical-motion. */ + if (it->base_level_stop <= 0 + || IT_CHARPOS (*it) < it->base_level_stop) it->base_level_stop = BEGV; - if (IT_CHARPOS (*it) < it->base_level_stop) - abort (); handle_stop_backwards (it, it->base_level_stop); return GET_NEXT_DISPLAY_ELEMENT (it); } @@ -6970,9 +7548,11 @@ enum move_it_result result = MOVE_UNDEFINED; struct glyph_row *saved_glyph_row; struct it wrap_it, atpos_it, atx_it; + void *wrap_data = NULL, *atpos_data = NULL, *atx_data = NULL; int may_wrap = 0; enum it_method prev_method = it->method; EMACS_INT prev_pos = IT_CHARPOS (*it); + int saw_smaller_pos = prev_pos < to_charpos; /* Don't produce glyphs in produce_glyphs. */ saved_glyph_row = it->glyph_row; @@ -7013,15 +7593,16 @@ ((IT)->current_x = x, (IT)->max_ascent = ascent, \ (IT)->max_descent = descent) - /* Stop if we move beyond TO_CHARPOS (after an image or stretch - glyph). */ + /* Stop if we move beyond TO_CHARPOS (after an image or a + display string or stretch glyph). */ if ((op & MOVE_TO_POS) != 0 && BUFFERP (it->object) && it->method == GET_FROM_BUFFER && ((!it->bidi_p && IT_CHARPOS (*it) > to_charpos) || (it->bidi_p && (prev_method == GET_FROM_IMAGE - || prev_method == GET_FROM_STRETCH) + || prev_method == GET_FROM_STRETCH + || prev_method == GET_FROM_STRING) /* Passed TO_CHARPOS from left to right. */ && ((prev_pos < to_charpos && IT_CHARPOS (*it) > to_charpos) @@ -7038,12 +7619,9 @@ /* If wrap_it is valid, the current position might be in a word that is wrapped. So, save the iterator in atpos_it and continue to see if wrapping happens. */ - atpos_it = *it; + SAVE_IT (atpos_it, *it, atpos_data); } - prev_method = it->method; - if (it->method == GET_FROM_BUFFER) - prev_pos = IT_CHARPOS (*it); /* Stop when ZV reached. We used to stop here when TO_CHARPOS reached as well, but that is too soon if this glyph does not fit on this line. So we handle it @@ -7075,18 +7653,18 @@ already found, we are done. */ if (atpos_it.sp >= 0) { - *it = atpos_it; + RESTORE_IT (it, &atpos_it, atpos_data); result = MOVE_POS_MATCH_OR_ZV; goto done; } if (atx_it.sp >= 0) { - *it = atx_it; + RESTORE_IT (it, &atx_it, atx_data); result = MOVE_X_REACHED; goto done; } /* Otherwise, we can wrap here. */ - wrap_it = *it; + SAVE_IT (wrap_it, *it, wrap_data); may_wrap = 0; } } @@ -7107,6 +7685,9 @@ if (it->area != TEXT_AREA) { + prev_method = it->method; + if (it->method == GET_FROM_BUFFER) + prev_pos = IT_CHARPOS (*it); set_iterator_to_next (it, 1); if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos)) SET_TEXT_POS (this_line_min_pos, @@ -7154,7 +7735,7 @@ goto buffer_pos_reached; if (atpos_it.sp < 0) { - atpos_it = *it; + SAVE_IT (atpos_it, *it, atpos_data); IT_RESET_X_ASCENT_DESCENT (&atpos_it); } } @@ -7168,7 +7749,7 @@ } if (atx_it.sp < 0) { - atx_it = *it; + SAVE_IT (atx_it, *it, atx_data); IT_RESET_X_ASCENT_DESCENT (&atx_it); } } @@ -7212,12 +7793,15 @@ if (it->line_wrap == WORD_WRAP && atpos_it.sp < 0) { - atpos_it = *it; + SAVE_IT (atpos_it, *it, atpos_data); atpos_it.current_x = x_before_this_char; atpos_it.hpos = hpos_before_this_char; } } + prev_method = it->method; + if (it->method == GET_FROM_BUFFER) + prev_pos = IT_CHARPOS (*it); set_iterator_to_next (it, 1); if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos)) SET_TEXT_POS (this_line_min_pos, @@ -7257,7 +7841,7 @@ if (wrap_it.sp >= 0) { - *it = wrap_it; + RESTORE_IT (it, &wrap_it, wrap_data); atpos_it.sp = -1; atx_it.sp = -1; } @@ -7274,7 +7858,7 @@ goto buffer_pos_reached; if (it->line_wrap == WORD_WRAP && atpos_it.sp < 0) { - atpos_it = *it; + SAVE_IT (atpos_it, *it, atpos_data); IT_RESET_X_ASCENT_DESCENT (&atpos_it); } } @@ -7311,10 +7895,20 @@ /* Is this a line end? If yes, we're done. */ if (ITERATOR_AT_END_OF_LINE_P (it)) { - result = MOVE_NEWLINE_OR_CR; + /* If we are past TO_CHARPOS, but never saw any character + positions smaller than TO_CHARPOS, return + MOVE_POS_MATCH_OR_ZV, like the unidirectional display + did. */ + if ((op & MOVE_TO_POS) != 0 + && !saw_smaller_pos + && IT_CHARPOS (*it) > to_charpos) + result = MOVE_POS_MATCH_OR_ZV; + else + result = MOVE_NEWLINE_OR_CR; break; } + prev_method = it->method; if (it->method == GET_FROM_BUFFER) prev_pos = IT_CHARPOS (*it); /* The current display element has been consumed. Advance @@ -7322,6 +7916,8 @@ set_iterator_to_next (it, 1); if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos)) SET_TEXT_POS (this_line_min_pos, IT_CHARPOS (*it), IT_BYTEPOS (*it)); + if (IT_CHARPOS (*it) < to_charpos) + saw_smaller_pos = 1; /* Stop if lines are truncated and IT's current x-position is past the right edge of the window now. */ @@ -7354,12 +7950,19 @@ /* If we scanned beyond to_pos and didn't find a point to wrap at, restore the saved iterator. */ if (atpos_it.sp >= 0) - *it = atpos_it; + RESTORE_IT (it, &atpos_it, atpos_data); else if (atx_it.sp >= 0) - *it = atx_it; + RESTORE_IT (it, &atx_it, atx_data); done: + if (atpos_data) + xfree (atpos_data); + if (atx_data) + xfree (atx_data); + if (wrap_data) + xfree (wrap_data); + /* Restore the iterator settings altered at the beginning of this function. */ it->glyph_row = saved_glyph_row; @@ -7375,8 +7978,12 @@ if (it->line_wrap == WORD_WRAP && (op & MOVE_TO_X)) { - struct it save_it = *it; - int skip = move_it_in_display_line_to (it, to_charpos, to_x, op); + struct it save_it; + void *save_data = NULL; + int skip; + + SAVE_IT (save_it, *it, save_data); + skip = move_it_in_display_line_to (it, to_charpos, to_x, op); /* When word-wrap is on, TO_X may lie past the end of a wrapped line. Then it->current is the character on the next line, so backtrack to the @@ -7384,10 +7991,12 @@ if (skip == MOVE_LINE_CONTINUED) { int prev_x = max (it->current_x - 1, 0); - *it = save_it; + RESTORE_IT (it, &save_it, save_data); move_it_in_display_line_to (it, -1, prev_x, MOVE_TO_X); } + else + xfree (save_data); } else move_it_in_display_line_to (it, to_charpos, to_x, op); @@ -7402,14 +8011,15 @@ description of enum move_operation_enum. If TO_CHARPOS is in invisible text, e.g. a truncated part of a - screen line, this function will set IT to the next position > - TO_CHARPOS. */ + screen line, this function will set IT to the next position that is + displayed to the right of TO_CHARPOS on the screen. */ void move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos, int op) { enum move_it_result skip, skip2 = MOVE_X_REACHED; int line_height, line_start_x = 0, reached = 0; + void *backup_data = NULL; for (;;) { @@ -7462,7 +8072,7 @@ struct it it_backup; if (it->line_wrap == WORD_WRAP) - it_backup = *it; + SAVE_IT (it_backup, *it, backup_data); /* TO_Y specified means stop at TO_X in the line containing TO_Y---or at TO_CHARPOS if this is reached first. The @@ -7496,7 +8106,7 @@ reached = 6; break; } - it_backup = *it; + SAVE_IT (it_backup, *it, backup_data); TRACE_MOVE ((stderr, "move_it: from %d\n", IT_CHARPOS (*it))); skip2 = move_it_in_display_line_to (it, to_charpos, -1, op & MOVE_TO_POS); @@ -7510,7 +8120,7 @@ /* If TO_Y is in this line and TO_X was reached above, we scanned too far. We have to restore IT's settings to the ones before skipping. */ - *it = it_backup; + RESTORE_IT (it, &it_backup, backup_data); reached = 6; } else @@ -7537,7 +8147,7 @@ && it->line_wrap == WORD_WRAP) { int prev_x = max (it->current_x - 1, 0); - *it = it_backup; + RESTORE_IT (it, &it_backup, backup_data); skip = move_it_in_display_line_to (it, -1, prev_x, MOVE_TO_X); } @@ -7644,6 +8254,9 @@ last_max_ascent = it->max_ascent; } + if (backup_data) + xfree (backup_data); + TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached)); } @@ -7661,6 +8274,7 @@ { int nlines, h; struct it it2, it3; + void *it2data = NULL, *it3data = NULL; EMACS_INT start_pos; move_further_back: @@ -7689,7 +8303,7 @@ start of the next line so that we get its height. We need this height to be able to tell whether we reached the specified y-distance. */ - it2 = *it; + SAVE_IT (it2, *it, it2data); it2.max_ascent = it2.max_descent = 0; do { @@ -7698,7 +8312,7 @@ } while (!IT_POS_VALID_AFTER_MOVE_P (&it2)); xassert (IT_CHARPOS (*it) >= BEGV); - it3 = it2; + SAVE_IT (it3, it2, it3data); move_it_to (&it2, start_pos, -1, -1, -1, MOVE_TO_POS); xassert (IT_CHARPOS (*it) >= BEGV); @@ -7717,8 +8331,10 @@ { /* DY == 0 means move to the start of the screen line. The value of nlines is > 0 if continuation lines were involved. */ + RESTORE_IT (it, it, it2data); if (nlines > 0) move_it_by_lines (it, nlines); + xfree (it3data); } else { @@ -7726,9 +8342,13 @@ Note that H has been subtracted in front of the if-statement. */ int target_y = it->current_y + h - dy; int y0 = it3.current_y; - int y1 = line_bottom_y (&it3); - int line_height = y1 - y0; + int y1; + int line_height; + RESTORE_IT (&it3, &it3, it3data); + y1 = line_bottom_y (&it3); + line_height = y1 - y0; + RESTORE_IT (it, it, it2data); /* If we did not reach target_y, try to move further backward if we can. If we moved too far backward, try to move forward. */ if (target_y < it->current_y @@ -7855,6 +8475,7 @@ else { struct it it2; + void *it2data = NULL; EMACS_INT start_charpos, i; /* Start at the beginning of the screen line containing IT's @@ -7890,7 +8511,7 @@ /* Above call may have moved too far if continuation lines are involved. Scan forward and see if it did. */ - it2 = *it; + SAVE_IT (it2, *it, it2data); it2.vpos = it2.current_y = 0; move_it_to (&it2, start_charpos, -1, -1, -1, MOVE_TO_POS); it->vpos -= it2.vpos; @@ -7901,12 +8522,18 @@ if (it2.vpos > -dvpos) { int delta = it2.vpos + dvpos; - it2 = *it; + + RESTORE_IT (&it2, &it2, it2data); + SAVE_IT (it2, *it, it2data); move_it_to (it, -1, -1, -1, it->vpos + delta, MOVE_TO_VPOS); /* Move back again if we got too far ahead. */ if (IT_CHARPOS (*it) >= start_charpos) - *it = it2; + RESTORE_IT (it, &it2, it2data); + else + xfree (it2data); } + else + RESTORE_IT (it, it, it2data); } } @@ -10393,7 +11020,7 @@ ++i; } - /* Stop at line ends. */ + /* Stop at line end. */ if (ITERATOR_AT_END_OF_LINE_P (it)) break; @@ -10476,6 +11103,7 @@ it.first_visible_x = 0; it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f); reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1); + it.paragraph_embedding = L2R; while (!ITERATOR_AT_END_P (&it)) { @@ -10558,6 +11186,14 @@ /* Build a string that represents the contents of the tool-bar. */ build_desired_tool_bar_string (f); reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1); + /* FIXME: This should be controlled by a user option. But it + doesn't make sense to have an R2L tool bar if the menu bar cannot + be drawn also R2L, and making the menu bar R2L is tricky due + toolkit-specific code that implements it. If an R2L tool bar is + ever supported, display_tool_bar_line should also be augmented to + call unproduce_glyphs like display_line and display_string + do. */ + it.paragraph_embedding = L2R; if (f->n_tool_bar_rows == 0) { @@ -13245,14 +13881,18 @@ which was computed as distance from window bottom to point. This matters when lines at window top and lines below window bottom have different height. */ - struct it it1 = it; + struct it it1; + void *it1data = NULL; /* We use a temporary it1 because line_bottom_y can modify its argument, if it moves one line down; see there. */ - int start_y = line_bottom_y (&it1); + int start_y; + SAVE_IT (it1, it, it1data); + start_y = line_bottom_y (&it1); do { + RESTORE_IT (&it, &it, it1data); move_it_by_lines (&it, 1); - it1 = it; + SAVE_IT (it1, it, it1data); } while (line_bottom_y (&it1) - start_y < amount_to_scroll); } @@ -14360,10 +15000,13 @@ && BEGV <= CHARPOS (startp) && CHARPOS (startp) <= ZV) { struct it it1; + void *it1data = NULL; + SAVE_IT (it1, it, it1data); start_display (&it1, w, startp); move_it_vertically (&it1, margin); margin_pos = IT_CHARPOS (it1); + RESTORE_IT (&it, &it, it1data); } scrolling_up = PT > margin_pos; aggressive = @@ -17229,6 +17872,8 @@ static int push_display_prop (struct it *it, Lisp_Object prop) { + xassert (it->method == GET_FROM_BUFFER); + push_it (it, NULL); if (STRINGP (prop)) @@ -17246,6 +17891,29 @@ it->end_charpos = it->string_nchars = SCHARS (it->string); it->method = GET_FROM_STRING; it->stop_charpos = 0; + it->prev_stop = 0; + it->base_level_stop = 0; + it->string_from_display_prop_p = 1; + it->from_disp_prop_p = 1; + + /* Force paragraph direction to be that of the parent + buffer. */ + if (it->bidi_p && it->bidi_it.paragraph_dir == R2L) + it->paragraph_embedding = it->bidi_it.paragraph_dir; + else + it->paragraph_embedding = L2R; + + /* Set up the bidi iterator for this display string. */ + if (it->bidi_p) + { + it->bidi_it.string.lstring = it->string; + it->bidi_it.string.s = NULL; + it->bidi_it.string.schars = it->end_charpos; + it->bidi_it.string.bufpos = IT_CHARPOS (*it); + it->bidi_it.string.from_disp_str = 1; + it->bidi_it.string.unibyte = !it->multibyte_p; + bidi_init_it (0, 0, FRAME_WINDOW_P (it->f), &it->bidi_it); + } } else if (CONSP (prop) && EQ (XCAR (prop), Qspace)) { @@ -17292,6 +17960,7 @@ handle_line_prefix (struct it *it) { Lisp_Object prefix; + if (it->continuation_lines_width > 0) { prefix = get_it_property (it, Qwrap_prefix); @@ -17317,9 +17986,9 @@ /* Remove N glyphs at the start of a reversed IT->glyph_row. Called - only for R2L lines from display_line, when it decides that too many - glyphs were produced by PRODUCE_GLYPHS, and the line needs to be - continued. */ + only for R2L lines from display_line and display_string, when they + decide that too many glyphs were produced by PRODUCE_GLYPHS, and + the line/string needs to be continued on the next glyph row. */ static void unproduce_glyphs (struct it *it, int n) { @@ -17349,12 +18018,13 @@ lines' rows is implemented for bidi-reordered rows. */ /* ROW->minpos is the value of min_pos, the minimal buffer position - we have in ROW. */ - if (min_pos <= ZV) + we have in ROW, or ROW->start.pos if that is smaller. */ + if (min_pos <= ZV && min_pos < row->start.pos.charpos) SET_TEXT_POS (row->minpos, min_pos, min_bpos); else - /* We didn't find _any_ valid buffer positions in any of the - glyphs, so we must trust the iterator's computed positions. */ + /* We didn't find buffer positions smaller than ROW->start, or + didn't find _any_ valid buffer positions in any of the glyphs, + so we must trust the iterator's computed positions. */ row->minpos = row->start.pos; if (max_pos <= 0) { @@ -17429,6 +18099,7 @@ struct glyph_row *row = it->glyph_row; Lisp_Object overlay_arrow_string; struct it wrap_it; + void *wrap_data = NULL; int may_wrap = 0, wrap_x IF_LINT (= 0); int wrap_row_used = -1; int wrap_row_ascent IF_LINT (= 0), wrap_row_height IF_LINT (= 0); @@ -17583,7 +18254,7 @@ may_wrap = 1; else if (may_wrap) { - wrap_it = *it; + SAVE_IT (wrap_it, *it, wrap_data); wrap_x = x; wrap_row_used = row->used[TEXT_AREA]; wrap_row_ascent = row->ascent; @@ -17753,7 +18424,7 @@ if (row->reversed_p) unproduce_glyphs (it, row->used[TEXT_AREA] - wrap_row_used); - *it = wrap_it; + RESTORE_IT (it, &wrap_it, wrap_data); it->continuation_lines_width += wrap_x; row->used[TEXT_AREA] = wrap_row_used; row->ascent = wrap_row_ascent; @@ -18159,6 +18830,8 @@ itb.charpos = pos; itb.bytepos = bytepos; itb.nchars = -1; + itb.string.s = NULL; + itb.string.lstring = Qnil; itb.frame_window_p = FRAME_WINDOW_P (SELECTED_FRAME ()); /* guesswork */ itb.first_elt = 1; itb.separator_limit = -1; @@ -18248,6 +18921,11 @@ } #endif /* not USE_X_TOOLKIT */ + /* FIXME: This should be controlled by a user option. See the + comments in redisplay_tool_bar and display_mode_line about + this. */ + it.paragraph_embedding = L2R; + if (! mode_line_inverse_video) /* Force the menu-bar to be displayed in the default face. */ it.base_face_id = it.face_id = DEFAULT_FACE_ID; @@ -18425,6 +19103,11 @@ /* Force the mode-line to be displayed in the default face. */ it.base_face_id = it.face_id = DEFAULT_FACE_ID; + /* FIXME: This should be controlled by a user option. But + supporting such an option is not trivial, since the mode line is + made up of many separate strings. */ + it.paragraph_embedding = L2R; + record_unwind_protect (unwind_format_mode_line, format_mode_line_unwind_data (NULL, Qnil, 0)); @@ -19970,6 +20653,7 @@ int hpos_at_start = it->hpos; int saved_face_id = it->face_id; struct glyph_row *row = it->glyph_row; + EMACS_INT it_charpos; /* Initialize the iterator IT for iteration over STRING beginning with index START. */ @@ -19978,10 +20662,10 @@ if (string && STRINGP (lisp_string)) /* LISP_STRING is the one returned by decode_mode_spec. We should ignore its text properties. */ - it->stop_charpos = -1; + it->stop_charpos = it->end_charpos; - /* If displaying STRING, set up the face of the iterator - from LISP_STRING, if that's given. */ + /* If displaying STRING, set up the face of the iterator from + FACE_STRING, if that's given. */ if (STRINGP (face_string)) { EMACS_INT endptr; @@ -20015,6 +20699,11 @@ row->phys_height = it->max_phys_ascent + it->max_phys_descent; row->extra_line_spacing = it->max_extra_line_spacing; + if (STRINGP (it->string)) + it_charpos = IT_STRING_CHARPOS (*it); + else + it_charpos = IT_CHARPOS (*it); + /* This condition is for the case that we are called with current_x past last_visible_x. */ while (it->current_x < max_x) @@ -20027,10 +20716,10 @@ /* Produce glyphs. */ x_before = it->current_x; - n_glyphs_before = it->glyph_row->used[TEXT_AREA]; + n_glyphs_before = row->used[TEXT_AREA]; PRODUCE_GLYPHS (it); - nglyphs = it->glyph_row->used[TEXT_AREA] - n_glyphs_before; + nglyphs = row->used[TEXT_AREA] - n_glyphs_before; i = 0; x = x_before; while (i < nglyphs) @@ -20044,12 +20733,18 @@ if (CHAR_GLYPH_PADDING_P (*glyph)) { /* A wide character is unbreakable. */ - it->glyph_row->used[TEXT_AREA] = n_glyphs_before; + if (row->reversed_p) + unproduce_glyphs (it, row->used[TEXT_AREA] + - n_glyphs_before); + row->used[TEXT_AREA] = n_glyphs_before; it->current_x = x_before; } else { - it->glyph_row->used[TEXT_AREA] = n_glyphs_before + i; + if (row->reversed_p) + unproduce_glyphs (it, row->used[TEXT_AREA] + - (n_glyphs_before + i)); + row->used[TEXT_AREA] = n_glyphs_before + i; it->current_x = x; } break; @@ -20059,7 +20754,7 @@ /* Glyph is at least partially visible. */ ++it->hpos; if (x < it->first_visible_x) - it->glyph_row->x = x - it->first_visible_x; + row->x = x - it->first_visible_x; } else { @@ -20091,6 +20786,10 @@ } set_iterator_to_next (it, 1); + if (STRINGP (it->string)) + it_charpos = IT_STRING_CHARPOS (*it); + else + it_charpos = IT_CHARPOS (*it); /* Stop if truncating at the right edge. */ if (it->line_wrap == TRUNCATE @@ -20098,7 +20797,7 @@ { /* Add truncation mark, but don't do it if the line is truncated at a padding space. */ - if (IT_CHARPOS (*it) < it->string_nchars) + if (it_charpos < it->string_nchars) { if (!FRAME_WINDOW_P (it->f)) { @@ -20106,9 +20805,20 @@ if (it->current_x > it->last_visible_x) { - for (ii = row->used[TEXT_AREA] - 1; ii > 0; --ii) - if (!CHAR_GLYPH_PADDING_P (row->glyphs[TEXT_AREA][ii])) - break; + if (!row->reversed_p) + { + for (ii = row->used[TEXT_AREA] - 1; ii > 0; --ii) + if (!CHAR_GLYPH_PADDING_P (row->glyphs[TEXT_AREA][ii])) + break; + } + else + { + for (ii = 0; ii < row->used[TEXT_AREA]; ii++) + if (!CHAR_GLYPH_PADDING_P (row->glyphs[TEXT_AREA][ii])) + break; + unproduce_glyphs (it, ii + 1); + ii = row->used[TEXT_AREA] - (ii + 1); + } for (n = row->used[TEXT_AREA]; ii < n; ++ii) { row->used[TEXT_AREA] = ii; @@ -20117,7 +20827,7 @@ } produce_special_glyphs (it, IT_TRUNCATION); } - it->glyph_row->truncated_on_right_p = 1; + row->truncated_on_right_p = 1; } break; } @@ -20125,11 +20835,11 @@ /* Maybe insert a truncation at the left. */ if (it->first_visible_x - && IT_CHARPOS (*it) > 0) + && it_charpos > 0) { if (!FRAME_WINDOW_P (it->f)) insert_left_trunc_glyphs (it); - it->glyph_row->truncated_on_left_p = 1; + row->truncated_on_left_p = 1; } it->face_id = saved_face_id; ------------------------------------------------------------ revno: 105207 fixes bug(s): http://debbugs.gnu.org/7834 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 19:20:37 +0200 message: `put-image' doc fix * image.el (put-image): Mention the `put-image' overlay property (bug#7834). diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-07-14 17:11:49 +0000 +++ lisp/ChangeLog 2011-07-14 17:20:37 +0000 @@ -1,5 +1,8 @@ 2011-07-14 Lars Magne Ingebrigtsen + * image.el (put-image): Mention the `put-image' overlay property + (bug#7834). + * scroll-bar.el (set-scroll-bar-mode): Mention that `scroll-bar-mode' lists the values (bug#7772). === modified file 'lisp/image.el' --- lisp/image.el 2011-06-11 23:03:16 +0000 +++ lisp/image.el 2011-07-14 17:20:37 +0000 @@ -389,6 +389,7 @@ IMAGE is displayed by putting an overlay into the current buffer with a `before-string' STRING that has a `display' property whose value is the image. STRING is defaulted if you omit it. +The overlay created will have the `put-overlay' property set to t. POS may be an integer or marker. AREA is where to display the image. AREA nil or omitted means display it in the text area, a value of `left-margin' means ------------------------------------------------------------ revno: 105206 fixes bug(s): http://debbugs.gnu.org/7772 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 19:11:49 +0200 message: `set-scroll-bar-mode' doc clarification * scroll-bar.el (set-scroll-bar-mode): Mention that `scroll-bar-mode' lists the values (bug#7772). diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-07-14 17:05:43 +0000 +++ lisp/ChangeLog 2011-07-14 17:11:49 +0000 @@ -1,5 +1,8 @@ 2011-07-14 Lars Magne Ingebrigtsen + * scroll-bar.el (set-scroll-bar-mode): Mention that + `scroll-bar-mode' lists the values (bug#7772). + * image-mode.el (image-mode-fit-frame): Mention that it's a toggle command (bug#7729). === modified file 'lisp/scroll-bar.el' --- lisp/scroll-bar.el 2011-04-19 13:44:55 +0000 +++ lisp/scroll-bar.el 2011-07-14 17:11:49 +0000 @@ -81,7 +81,8 @@ This is nil while loading `scroll-bar.el', and t afterward.") (defun set-scroll-bar-mode (value) - "Set `scroll-bar-mode' to VALUE and put the new value into effect." + "Set the scroll bar mode to VALUE and put the new value into effect. +See the `scroll-bar-mode' variable for possible values to use." (if scroll-bar-mode (setq previous-scroll-bar-mode scroll-bar-mode)) ------------------------------------------------------------ revno: 105205 fixes bug(s): http://debbugs.gnu.org/7729 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 19:05:43 +0200 message: `image-mode-fit-frame' doc fix * image-mode.el (image-mode-fit-frame): Mention that it's a toggle command diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-07-14 15:23:08 +0000 +++ lisp/ChangeLog 2011-07-14 17:05:43 +0000 @@ -1,5 +1,8 @@ 2011-07-14 Lars Magne Ingebrigtsen + * image-mode.el (image-mode-fit-frame): Mention that it's a toggle + command (bug#7729). + * rect.el (apply-on-rectangle): Return the point after the last operation. (string-rectangle): Go to the point after the last operation === modified file 'lisp/image-mode.el' --- lisp/image-mode.el 2011-06-07 18:32:12 +0000 +++ lisp/image-mode.el 2011-07-14 17:05:43 +0000 @@ -271,7 +271,7 @@ ;; Adjust frame and image size. (defun image-mode-fit-frame () - "Fit the frame to the current image. + "Toggle whether to fit the frame to the current image. This function assumes the current frame has only one window." ;; FIXME: This does not take into account decorations like mode-line, ;; minibuffer, header-line, ... ------------------------------------------------------------ revno: 105204 fixes bug(s): http://debbugs.gnu.org/7522 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 17:23:08 +0200 message: Leave point at the end of the rectangle after replacing text * rect.el (apply-on-rectangle): Return the point after the last operation. (string-rectangle): Go to the point after the last operation (bug#7522). diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-07-14 15:05:08 +0000 +++ lisp/ChangeLog 2011-07-14 15:23:08 +0000 @@ -1,5 +1,10 @@ 2011-07-14 Lars Magne Ingebrigtsen + * rect.el (apply-on-rectangle): Return the point after the last + operation. + (string-rectangle): Go to the point after the last operation + (bug#7522). + * simple.el (current-kill): Clarify what `interprogram-paste-function' does (bug#7500). === modified file 'lisp/rect.el' --- lisp/rect.el 2011-04-19 13:44:55 +0000 +++ lisp/rect.el 2011-07-14 15:23:08 +0000 @@ -93,8 +93,9 @@ "Call FUNCTION for each line of rectangle with corners at START, END. FUNCTION is called with two arguments: the start and end columns of the rectangle, plus ARGS extra arguments. Point is at the beginning of line when -the function is called." - (let (startcol startpt endcol endpt) +the function is called. +The final point after the last operation will be returned." + (let (startcol startpt endcol endpt final-point) (save-excursion (goto-char start) (setq startcol (current-column)) @@ -112,8 +113,9 @@ (goto-char startpt) (while (< (point) endpt) (apply function startcol endcol args) + (setq final-point (point)) (forward-line 1))) - )) + final-point)) (defun delete-rectangle-line (startcol endcol fill) (when (= (move-to-column startcol (if fill t 'coerce)) startcol) @@ -323,7 +325,8 @@ (or (car string-rectangle-history) "")) nil 'string-rectangle-history (car string-rectangle-history))))) - (apply-on-rectangle 'string-rectangle-line start end string t)) + (goto-char + (apply-on-rectangle 'string-rectangle-line start end string t))) ;;;###autoload (defalias 'replace-rectangle 'string-rectangle) ------------------------------------------------------------ revno: 105203 fixes bug(s): http://debbugs.gnu.org/7500 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 17:05:08 +0200 message: `current-kill' doc clarification * simple.el (current-kill): Clarify what `interprogram-paste-function' does (bug#7500). diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-07-14 14:54:32 +0000 +++ lisp/ChangeLog 2011-07-14 15:05:08 +0000 @@ -1,5 +1,8 @@ 2011-07-14 Lars Magne Ingebrigtsen + * simple.el (current-kill): Clarify what + `interprogram-paste-function' does (bug#7500). + * printing.el (pr-toggle-region): Clarify the documentation slightly (bug#7493). ------------------------------------------------------------ revno: 105202 fixes bug(s): http://debbugs.gnu.org/7493 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 16:54:32 +0200 message: pr-toggle-region doc clarification * printing.el (pr-toggle-region): Clarify the documentation slightly (bug#7493). diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-07-14 14:30:35 +0000 +++ lisp/ChangeLog 2011-07-14 14:54:32 +0000 @@ -1,5 +1,8 @@ 2011-07-14 Lars Magne Ingebrigtsen + * printing.el (pr-toggle-region): Clarify the documentation + slightly (bug#7493). + * time.el (display-time-update): Allow `display-time-mail-function' to return nil (bug#7158). Fix suggested by Detlev Zundel. === modified file 'lisp/printing.el' --- lisp/printing.el 2011-07-11 14:52:48 +0000 +++ lisp/printing.el 2011-07-14 14:54:32 +0000 @@ -4611,7 +4611,7 @@ ;;;###autoload (defun pr-toggle-region () - "Toggle auto region." + "Toggle whether the region is automagically detected." (interactive) (pr-toggle-region-menu t)) ------------------------------------------------------------ revno: 105201 fixes bug(s): http://debbugs.gnu.org/7158 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 16:30:35 +0200 message: Allow display-time-mail-function to return nil * time.el (display-time-update): Allow `display-time-mail-function' to return nil (bug#7158). Fix suggested by Detlev Zundel. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-07-14 14:15:06 +0000 +++ lisp/ChangeLog 2011-07-14 14:30:35 +0000 @@ -1,5 +1,9 @@ 2011-07-14 Lars Magne Ingebrigtsen + * time.el (display-time-update): Allow + `display-time-mail-function' to return nil (bug#7158). Fix + suggested by Detlev Zundel. + * vc/diff.el (diff): Clarify the order the file names are read (bug#7111). === modified file 'lisp/time.el' --- lisp/time.el 2011-04-19 13:44:55 +0000 +++ lisp/time.el 2011-07-14 14:30:35 +0000 @@ -423,30 +423,31 @@ (getenv "MAIL") (concat rmail-spool-directory (user-login-name)))) - (mail (or (and display-time-mail-function - (funcall display-time-mail-function)) - (and display-time-mail-directory - (display-time-mail-check-directory)) - (and (stringp mail-spool-file) - (or (null display-time-server-down-time) - ;; If have been down for 20 min, try again. - (> (- (nth 1 now) display-time-server-down-time) - 1200) - (and (< (nth 1 now) display-time-server-down-time) - (> (- (nth 1 now) - display-time-server-down-time) - -64336))) - (let ((start-time (current-time))) - (prog1 - (display-time-file-nonempty-p mail-spool-file) - (if (> (- (nth 1 (current-time)) - (nth 1 start-time)) - 20) - ;; Record that mail file is not accessible. - (setq display-time-server-down-time - (nth 1 (current-time))) - ;; Record that mail file is accessible. - (setq display-time-server-down-time nil))))))) + (mail (cond + (display-time-mail-function + (funcall display-time-mail-function)) + (display-time-mail-directory + (display-time-mail-check-directory)) + ((and (stringp mail-spool-file) + (or (null display-time-server-down-time) + ;; If have been down for 20 min, try again. + (> (- (nth 1 now) display-time-server-down-time) + 1200) + (and (< (nth 1 now) display-time-server-down-time) + (> (- (nth 1 now) + display-time-server-down-time) + -64336)))) + (let ((start-time (current-time))) + (prog1 + (display-time-file-nonempty-p mail-spool-file) + (if (> (- (nth 1 (current-time)) + (nth 1 start-time)) + 20) + ;; Record that mail file is not accessible. + (setq display-time-server-down-time + (nth 1 (current-time))) + ;; Record that mail file is accessible. + (setq display-time-server-down-time nil))))))) (24-hours (substring time 11 13)) (hour (string-to-number 24-hours)) (12-hours (int-to-string (1+ (% (+ hour 11) 12)))) ------------------------------------------------------------ revno: 105200 author: Andrew Cohen committer: Katsumi Yamaoka branch nick: trunk timestamp: Thu 2011-07-14 14:19:53 +0000 message: Merge changes made in Gnus trunk. nnimap.el (nnimap-request-thread): Ensure search is performed in correct group. gnus-int.el (gnus-request-thread): Add group argument. gnus-sum.el (gnus-request-thread): Use it. diff: === modified file 'lisp/gnus/ChangeLog' --- lisp/gnus/ChangeLog 2011-07-10 22:17:49 +0000 +++ lisp/gnus/ChangeLog 2011-07-14 14:19:53 +0000 @@ -1,3 +1,12 @@ +2011-07-14 Andrew Cohen + + * nnimap.el (nnimap-request-thread): Ensure search is performed in + correct group. + + * gnus-int.el (gnus-request-thread): Add group argument. + + * gnus-sum.el (gnus-request-thread): Use it. + 2011-07-10 Lars Magne Ingebrigtsen * gnus-group.el (gnus-read-ephemeral-emacs-bug-group): `debbugs-*' === modified file 'lisp/gnus/gnus-int.el' --- lisp/gnus/gnus-int.el 2011-03-15 22:38:41 +0000 +++ lisp/gnus/gnus-int.el 2011-07-14 14:19:53 +0000 @@ -516,11 +516,12 @@ article (gnus-group-real-name group) (nth 1 gnus-command-method) buffer))) -(defun gnus-request-thread (header) +(defun gnus-request-thread (header group) "Request the headers in the thread containing the article specified by HEADER." - (let ((gnus-command-method (gnus-find-method-for-group gnus-newsgroup-name))) + (let ((gnus-command-method (gnus-find-method-for-group group))) (funcall (gnus-get-function gnus-command-method 'request-thread) - header))) + header + (gnus-group-real-name group)))) (defun gnus-warp-to-article () "Warps from an article in a virtual group to the article in its === modified file 'lisp/gnus/gnus-sum.el' --- lisp/gnus/gnus-sum.el 2011-06-30 22:20:32 +0000 +++ lisp/gnus/gnus-sum.el 2011-07-14 14:19:53 +0000 @@ -8970,7 +8970,7 @@ 'list gnus-newsgroup-headers (if (gnus-check-backend-function 'request-thread gnus-newsgroup-name) - (gnus-request-thread header) + (gnus-request-thread header gnus-newsgroup-name) (let* ((last (if (numberp limit) (min (+ (mail-header-number header) limit) === modified file 'lisp/gnus/nnimap.el' --- lisp/gnus/nnimap.el 2011-07-04 13:11:52 +0000 +++ lisp/gnus/nnimap.el 2011-07-14 14:19:53 +0000 @@ -1565,8 +1565,9 @@ (declare-function gnus-fetch-headers "gnus-sum" (articles &optional limit force-new dependencies)) -(deffoo nnimap-request-thread (header) - (let* ((id (mail-header-id header)) +(deffoo nnimap-request-thread (header &optional group server) + (when (nnimap-possibly-change-group group server) + (let* ((id (mail-header-id header)) (refs (split-string (or (mail-header-references header) ""))) @@ -1584,7 +1585,7 @@ (gnus-fetch-headers (and (car result) (delete 0 (mapcar #'string-to-number (cdr (assoc "SEARCH" (cdr result)))))) - nil t)))) + nil t))))) (defun nnimap-possibly-change-group (group server) (let ((open-result t)) ------------------------------------------------------------ revno: 105199 fixes bug(s): http://debbugs.gnu.org/7111 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 16:15:06 +0200 message: `diff' doc clarification * vc/diff.el (diff): Clarify the order the file names are read (bug#7111). diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-07-14 14:01:16 +0000 +++ lisp/ChangeLog 2011-07-14 14:15:06 +0000 @@ -1,5 +1,8 @@ 2011-07-14 Lars Magne Ingebrigtsen + * vc/diff.el (diff): Clarify the order the file names are read + (bug#7111). + * mouse.el (mouse-set-region): Link to `mouse-drag-copy-region' in the doc string (bug#7015). === modified file 'lisp/vc/diff.el' --- lisp/vc/diff.el 2011-05-02 12:22:38 +0000 +++ lisp/vc/diff.el 2011-07-14 14:15:06 +0000 @@ -76,10 +76,10 @@ ;;;###autoload (defun diff (old new &optional switches no-async) "Find and display the differences between OLD and NEW files. -When called interactively, read OLD and NEW using the minibuffer; -the default for NEW is the current buffer's file name, and the -default for OLD is a backup file for NEW, if one exists. -If NO-ASYNC is non-nil, call diff synchronously. +When called interactively, read NEW, then OLD, using the +minibuffer. The default for NEW is the current buffer's file +name, and the default for OLD is a backup file for NEW, if one +exists. If NO-ASYNC is non-nil, call diff synchronously. When called interactively with a prefix argument, prompt interactively for diff switches. Otherwise, the switches ------------------------------------------------------------ revno: 105198 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 16:10:51 +0200 message: Manual for for widget-keymap * widget.texi (Setting Up the Buffer): Remove mention of the global keymap parent, which doesn't seem to be accurate (bug#7045). diff: === modified file 'doc/misc/ChangeLog' --- doc/misc/ChangeLog 2011-07-14 00:14:35 +0000 +++ doc/misc/ChangeLog 2011-07-14 14:10:51 +0000 @@ -1,3 +1,9 @@ +2011-07-14 Lars Magne Ingebrigtsen + + * widget.texi (Setting Up the Buffer): Remove mention of the + global keymap parent, which doesn't seem to be accurate + (bug#7045). + 2010-07-10 Kevin Ryde * cl.texi (For Clauses): Add destructuring example processing an === modified file 'doc/misc/widget.texi' --- doc/misc/widget.texi 2011-02-19 19:40:59 +0000 +++ doc/misc/widget.texi 2011-07-14 14:10:51 +0000 @@ -450,7 +450,6 @@ @findex widget-button-press @findex widget-button-click @defvr Const widget-keymap -A keymap with the global keymap as its parent.@* @key{TAB} and @kbd{C-@key{TAB}} are bound to @code{widget-forward} and @code{widget-backward}, respectively. @key{RET} and @kbd{Mouse-2} are bound to @code{widget-button-press} and ------------------------------------------------------------ revno: 105197 fixes bug(s): http://debbugs.gnu.org/7015 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 16:01:16 +0200 message: mouse-set-region doc fix * mouse.el (mouse-set-region): Link to `mouse-drag-copy-region' in the doc string (bug#7015). diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-07-14 13:50:25 +0000 +++ lisp/ChangeLog 2011-07-14 14:01:16 +0000 @@ -1,5 +1,8 @@ 2011-07-14 Lars Magne Ingebrigtsen + * mouse.el (mouse-set-region): Link to `mouse-drag-copy-region' in + the doc string (bug#7015). + * font-lock.el (font-lock-maximum-decoration): Mention what numeric levels mean (bug#6935). === modified file 'lisp/mouse.el' --- lisp/mouse.el 2011-07-01 17:58:14 +0000 +++ lisp/mouse.el 2011-07-14 14:01:16 +0000 @@ -687,7 +687,9 @@ (defun mouse-set-region (click) "Set the region to the text dragged over, and copy to kill ring. -This should be bound to a mouse drag event." +This should be bound to a mouse drag event. +See the `mouse-drag-copy-region' variable to control whether this +command alters the kill ring or not." (interactive "e") (mouse-minibuffer-check click) (select-window (posn-window (event-start click))) ------------------------------------------------------------ revno: 105196 fixes bug(s): http://debbugs.gnu.org/6935 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 15:50:25 +0200 message: * font-lock.el (font-lock-maximum-decoration): Mention what numeric levels mean. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-07-14 12:57:06 +0000 +++ lisp/ChangeLog 2011-07-14 13:50:25 +0000 @@ -1,5 +1,8 @@ 2011-07-14 Lars Magne Ingebrigtsen + * font-lock.el (font-lock-maximum-decoration): Mention what + numeric levels mean (bug#6935). + * startup.el (initial-buffer-choice): Don't mention the `none' selection, which is against policy. === modified file 'lisp/font-lock.el' --- lisp/font-lock.el 2011-07-13 15:33:08 +0000 +++ lisp/font-lock.el 2011-07-14 13:50:25 +0000 @@ -254,6 +254,7 @@ If nil, use the default decoration (typically the minimum available). If t, use the maximum decoration available. If a number, use that level of decoration (or if not available the maximum). +The higher the number, the more decoration is done. If a list, each element should be a cons pair of the form (MAJOR-MODE . LEVEL), where MAJOR-MODE is a symbol or t (meaning the default). For example: ((c-mode . t) (c++-mode . 2) (t . 1)) ------------------------------------------------------------ revno: 105195 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 15:40:24 +0200 message: Mention that `delete-region' doesn't alter the kill ring. diff: === modified file 'src/editfns.c' --- src/editfns.c 2011-07-14 13:37:20 +0000 +++ src/editfns.c 2011-07-14 13:40:24 +0000 @@ -3161,7 +3161,8 @@ DEFUN ("delete-region", Fdelete_region, Sdelete_region, 2, 2, "r", doc: /* Delete the text between START and END. -If called interactively, delete the region between point and mark. */) +If called interactively, delete the region between point and mark. +This command deletes buffer text without modifying the kill ring. */) (Lisp_Object start, Lisp_Object end) { validate_region (&start, &end); ------------------------------------------------------------ revno: 105194 fixes bug(s): http://debbugs.gnu.org/6788 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 15:37:20 +0200 message: * editfns.c (Fdelete_region): Clarify the use of the named parameters. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2011-07-14 08:30:34 +0000 +++ src/ChangeLog 2011-07-14 13:37:20 +0000 @@ -1,3 +1,8 @@ +2011-07-14 Lars Magne Ingebrigtsen + + * editfns.c (Fdelete_region): Clarify the use of the named + parameters (bug#6788). + 2011-07-14 Martin Rudalics * indent.c (Fvertical_motion): Set and restore w->pointm when === modified file 'src/editfns.c' --- src/editfns.c 2011-07-13 23:48:35 +0000 +++ src/editfns.c 2011-07-14 13:37:20 +0000 @@ -3160,10 +3160,8 @@ } DEFUN ("delete-region", Fdelete_region, Sdelete_region, 2, 2, "r", - doc: /* Delete the text between point and mark. - -When called from a program, expects two arguments, -positions (integers or markers) specifying the stretch to be deleted. */) + doc: /* Delete the text between START and END. +If called interactively, delete the region between point and mark. */) (Lisp_Object start, Lisp_Object end) { validate_region (&start, &end); ------------------------------------------------------------ revno: 105193 committer: Lars Magne Ingebrigtsen branch nick: trunk timestamp: Thu 2011-07-14 14:57:06 +0200 message: (initial-buffer-choice): Don't mention the `none' selection, which is against policy. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2011-07-14 08:30:34 +0000 +++ lisp/ChangeLog 2011-07-14 12:57:06 +0000 @@ -1,3 +1,8 @@ +2011-07-14 Lars Magne Ingebrigtsen + + * startup.el (initial-buffer-choice): Don't mention the `none' + selection, which is against policy. + 2011-07-14 Martin Rudalics * window.el (display-buffer-normalize-special): Replace === modified file 'lisp/startup.el' --- lisp/startup.el 2011-07-13 21:53:41 +0000 +++ lisp/startup.el 2011-07-14 12:57:06 +0000 @@ -43,14 +43,12 @@ If the value is nil and `inhibit-startup-screen' is nil, show the startup screen. If the value is string, visit the specified file or directory using `find-file'. If t, open the `*scratch*' -buffer. If `none', don't select anything, but show the -buffer (if any) selected by the startup file." +buffer." :type '(choice (const :tag "Startup screen" nil) (directory :tag "Directory" :value "~/") (file :tag "File" :value "~/.emacs") - (const :tag "Lisp scratch buffer" t) - (const :tag "Select no buffer" 'none)) + (const :tag "Lisp scratch buffer" t)) :version "23.1" :group 'initialization) ------------------------------------------------------------ Use --include-merges or -n0 to see merged revisions.