aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Mackenzie2015-12-20 12:33:30 +0000
committerAlan Mackenzie2015-12-20 12:33:30 +0000
commitdf32db2f5f3dcad4b2b16fd52e51e1c7bd846609 (patch)
tree74c24ce0fd04942ec496aab04d8f25482944107e
parent6a8a41c5104b29846ed6e69da7576e0960f2bf14 (diff)
parenta72a9fbbbc9cd5f5933719b11489c2578eb0aa59 (diff)
downloademacs-df32db2f5f3dcad4b2b16fd52e51e1c7bd846609.tar.gz
emacs-df32db2f5f3dcad4b2b16fd52e51e1c7bd846609.zip
Merge branch 'scratch/follow' into emacs-25
This allows Isearch, etc., to work well when Follow Mode is active.
-rw-r--r--doc/lispref/functions.texi17
-rw-r--r--doc/lispref/positions.texi12
-rw-r--r--doc/lispref/windows.texi88
-rw-r--r--lisp/follow.el176
-rw-r--r--lisp/isearch.el125
-rw-r--r--lisp/replace.el8
-rw-r--r--lisp/textmodes/ispell.el79
-rw-r--r--lisp/window.el146
8 files changed, 577 insertions, 74 deletions
diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi
index 8835667b82d..7cc041fa77e 100644
--- a/doc/lispref/functions.texi
+++ b/doc/lispref/functions.texi
@@ -861,15 +861,18 @@ into a list. @code{mapc} always returns @var{sequence}.
861 861
862@defun mapconcat function sequence separator 862@defun mapconcat function sequence separator
863@code{mapconcat} applies @var{function} to each element of 863@code{mapconcat} applies @var{function} to each element of
864@var{sequence}: the results, which must be strings, are concatenated. 864@var{sequence}; the results, which must be sequences of characters
865Between each pair of result strings, @code{mapconcat} inserts the string 865(strings, vectors, or lists), are concatenated into a single string
866@var{separator}. Usually @var{separator} contains a space or comma or 866return value. Between each pair of result sequences, @code{mapconcat}
867other suitable punctuation. 867inserts the characters from @var{separator}, which also must be a
868string, or a vector or list of characters. @xref{Sequences Arrays
869Vectors}.
868 870
869The argument @var{function} must be a function that can take one 871The argument @var{function} must be a function that can take one
870argument and return a string. The argument @var{sequence} can be any 872argument and returns a sequence of characters: a string, a vector, or
871kind of sequence except a char-table; that is, a list, a vector, a 873a list. The argument @var{sequence} can be any kind of sequence
872bool-vector, or a string. 874except a char-table; that is, a list, a vector, a bool-vector, or a
875string.
873 876
874@example 877@example
875@group 878@group
diff --git a/doc/lispref/positions.texi b/doc/lispref/positions.texi
index 72b76ce5c8f..9daf5cef059 100644
--- a/doc/lispref/positions.texi
+++ b/doc/lispref/positions.texi
@@ -572,6 +572,18 @@ The value returned is the window line number point has moved to, with
572the top line in the window numbered 0. 572the top line in the window numbered 0.
573@end deffn 573@end deffn
574 574
575@vindex move-to-window-group-line-function
576@defun move-to-window-group-line count
577This function is like @code{move-to-window-line}, except that when the
578selected window is a part of a group of windows (@pxref{Window
579Group}), @code{move-to-window-group-line} will move to a position with
580respect to the entire group, not just the single window. This
581condition holds when the buffer local variable
582@code{move-to-window-group-line-function} is set to a function. In
583this case, @code{move-to-window-group-line} calls the function with
584the argument @var{count}, then returns its result.
585@end defun
586
575@defun compute-motion from frompos to topos width offsets window 587@defun compute-motion from frompos to topos width offsets window
576This function scans the current buffer, calculating screen positions. 588This function scans the current buffer, calculating screen positions.
577It scans the buffer forward from position @var{from}, assuming that is 589It scans the buffer forward from position @var{from}, assuming that is
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 5c7947eeca6..e45201b0570 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -133,6 +133,30 @@ This function returns the selected window (which is always a live
133window). 133window).
134@end defun 134@end defun
135 135
136@anchor{Window Group}Sometimes several windows collectively and
137cooperatively display a buffer, for example, under the management of
138Follow Mode (@pxref{Follow Mode,,, emacs}), where the windows together
139display a bigger portion of the buffer than one window could alone.
140It is often useful to consider such a @dfn{window group} as a single
141entity. Several functions such as @code{window-group-start}
142(@pxref{Window Start and End}) allow you to do this by supplying, as
143an argument, one of the windows as a stand in for the whole group.
144
145@defun selected-window-group
146@vindex selected-window-group-function
147When the selected window is a member of a group of windows, this
148function returns a list of the windows in the group, ordered such that
149the first window in the list is displaying the earliest part of the
150buffer, and so on. Otherwise the function returns a list containing
151just the selected window.
152
153The selected window is considered part of a group when the buffer
154local variable @code{selected-window-group-function} is set to a
155function. In this case, @code{selected-window-group} calls it with no
156arguments and returns its result (which should be the list of windows
157in the group).
158@end defun
159
136@node Windows and Frames 160@node Windows and Frames
137@section Windows and Frames 161@section Windows and Frames
138 162
@@ -3098,6 +3122,17 @@ window-start position; if you move point, do not expect the window-start
3098position to change in response until after the next redisplay. 3122position to change in response until after the next redisplay.
3099@end defun 3123@end defun
3100 3124
3125@defun window-group-start &optional window
3126@vindex window-group-start-function
3127This function is like @code{window-start}, except that when
3128@var{window} is a part of a group of windows (@pxref{Window Group}),
3129@code{window-group-start} returns the start position of the entire
3130group. This condition holds when the buffer local variable
3131@code{window-group-start-function} is set to a function. In this
3132case, @code{window-group-start} calls the function with the single
3133argument @var{window}, then returns its result.
3134@end defun
3135
3101@cindex window end position 3136@cindex window end position
3102@defun window-end &optional window update 3137@defun window-end &optional window update
3103This function returns the position where display of its buffer ends in 3138This function returns the position where display of its buffer ends in
@@ -3124,6 +3159,18 @@ way real redisplay would do. It does not alter the
3124text will end if scrolling is not required. 3159text will end if scrolling is not required.
3125@end defun 3160@end defun
3126 3161
3162@vindex window-group-end-function
3163@defun window-group-end window update
3164This function is like @code{window-end}, except that when @var{window}
3165is a part of a group of windows (@pxref{Window Group}),
3166@code{window-group-end} returns the end position of the entire group.
3167This condition holds when the buffer local variable
3168@code{window-group-end-function} is set to a function. In this case,
3169@code{window-group-end} calls the function with the two arguments
3170@var{window} and @var{update}, then returns its result. The argument
3171@var{update} has the same meaning as in @code{window-end}.
3172@end defun
3173
3127@defun set-window-start window position &optional noforce 3174@defun set-window-start window position &optional noforce
3128This function sets the display-start position of @var{window} to 3175This function sets the display-start position of @var{window} to
3129@var{position} in @var{window}'s buffer. It returns @var{position}. 3176@var{position} in @var{window}'s buffer. It returns @var{position}.
@@ -3187,6 +3234,19 @@ off screen at the next redisplay, then redisplay computes a new window-start
3187position that works well with point, and thus @var{position} is not used. 3234position that works well with point, and thus @var{position} is not used.
3188@end defun 3235@end defun
3189 3236
3237@vindex set-window-group-start-function
3238@defun set-window-group-start window position &optional noforce
3239This function is like @code{set-window-start}, except that when
3240@var{window} is a part of a group of windows (@pxref{Window Group}),
3241@code{set-window-group-start} sets the start position of the entire
3242group. This condition holds when the buffer local variable
3243@code{set-window-group-start-function} is set to a function. In this
3244case, @code{set-window-group-start} calls the function with the three
3245arguments @var{window}, @var{position}, and @var{noforce}, then
3246returns its result. The arguments @var{position} and @var{noforce} in
3247this function have the same meaning as in @code{set-window-start}.
3248@end defun
3249
3190@defun pos-visible-in-window-p &optional position window partially 3250@defun pos-visible-in-window-p &optional position window partially
3191This function returns non-@code{nil} if @var{position} is within the 3251This function returns non-@code{nil} if @var{position} is within the
3192range of text currently visible on the screen in @var{window}. It 3252range of text currently visible on the screen in @var{window}. It
@@ -3228,6 +3288,21 @@ Here is an example:
3228@end example 3288@end example
3229@end defun 3289@end defun
3230 3290
3291@vindex pos-visible-in-window-group-p-function
3292@defun pos-visible-in-window-group-p &optional position window partially
3293This function is like @code{pos-visible-in-window-p}, except that when
3294@var{window} is a part of a group of windows (@pxref{Window Group}),
3295@code{pos-visible-in-window-group-p} tests the visibility of @var{pos}
3296in the entire group, not just in the single @var{window}. This
3297condition holds when the buffer local variable
3298@code{pos-visible-in-window-group-p-function} is set to a function.
3299In this case @code{pos-visible-in-window-group-p} calls the function
3300with the three arguments @var{position}, @var{window}, and
3301@var{partially}, then returns its result. The arguments
3302@var{position} and @var{partially} have the same meaning as in
3303@code{pos-visible-in-window-p}.
3304@end defun
3305
3231@defun window-line-height &optional line window 3306@defun window-line-height &optional line window
3232This function returns the height of text line @var{line} in 3307This function returns the height of text line @var{line} in
3233@var{window}. If @var{line} is one of @code{header-line} or 3308@var{window}. If @var{line} is one of @code{header-line} or
@@ -3471,6 +3546,19 @@ the top of the window. The command @code{recenter-top-bottom} offers
3471a more convenient way to achieve this. 3546a more convenient way to achieve this.
3472@end deffn 3547@end deffn
3473 3548
3549@vindex recenter-window-group-function
3550@defun recenter-window-group &optional count
3551This function is like @code{recenter}, except that when the selected
3552window is part of a group of windows (@pxref{Window Group}),
3553@code{recenter-window-group} scrolls the entire group. This condition
3554holds when the buffer local variable
3555@code{recenter-window-group-function} is set to a function. In this
3556case, @code{recenter-window-group} calls the function with the
3557argument @var{count}, then returns its result. The argument
3558@var{count} has the same meaning as in @code{recenter}, but with
3559respect to the entire window group.
3560@end defun
3561
3474@defopt recenter-redisplay 3562@defopt recenter-redisplay
3475If this variable is non-@code{nil}, calling @code{recenter} with a 3563If this variable is non-@code{nil}, calling @code{recenter} with a
3476@code{nil} argument redraws the frame. The default value is 3564@code{nil} argument redraws the frame. The default value is
diff --git a/lisp/follow.el b/lisp/follow.el
index 37de923e6a5..71e8824947d 100644
--- a/lisp/follow.el
+++ b/lisp/follow.el
@@ -421,7 +421,21 @@ Keys specific to Follow mode:
421 (progn 421 (progn
422 (add-hook 'compilation-filter-hook 'follow-align-compilation-windows t t) 422 (add-hook 'compilation-filter-hook 'follow-align-compilation-windows t t)
423 (add-hook 'post-command-hook 'follow-post-command-hook t) 423 (add-hook 'post-command-hook 'follow-post-command-hook t)
424 (add-hook 'window-size-change-functions 'follow-window-size-change t)) 424 (add-hook 'window-size-change-functions 'follow-window-size-change t)
425 (add-hook 'after-change-functions 'follow-after-change nil t)
426 (add-hook 'isearch-update-post-hook 'follow-post-command-hook nil t)
427 (add-hook 'replace-update-post-hook 'follow-post-command-hook nil t)
428 (add-hook 'ispell-update-post-hook 'follow-post-command-hook nil t)
429
430 (setq window-group-start-function 'follow-window-start)
431 (setq window-group-end-function 'follow-window-end)
432 (setq set-window-group-start-function 'follow-set-window-start)
433 (setq recenter-window-group-function 'follow-recenter)
434 (setq pos-visible-in-window-group-p-function
435 'follow-pos-visible-in-window-p)
436 (setq selected-window-group-function 'follow-all-followers)
437 (setq move-to-window-group-line-function 'follow-move-to-window-line))
438
425 ;; Remove globally-installed hook functions only if there is no 439 ;; Remove globally-installed hook functions only if there is no
426 ;; other Follow mode buffer. 440 ;; other Follow mode buffer.
427 (let ((buffers (buffer-list)) 441 (let ((buffers (buffer-list))
@@ -432,6 +446,19 @@ Keys specific to Follow mode:
432 (unless following 446 (unless following
433 (remove-hook 'post-command-hook 'follow-post-command-hook) 447 (remove-hook 'post-command-hook 'follow-post-command-hook)
434 (remove-hook 'window-size-change-functions 'follow-window-size-change))) 448 (remove-hook 'window-size-change-functions 'follow-window-size-change)))
449
450 (kill-local-variable 'move-to-window-group-line-function)
451 (kill-local-variable 'selected-window-group-function)
452 (kill-local-variable 'pos-visible-in-window-group-p-function)
453 (kill-local-variable 'recenter-window-group-function)
454 (kill-local-variable 'set-window-group-start-function)
455 (kill-local-variable 'window-group-end-function)
456 (kill-local-variable 'window-group-start-function)
457
458 (remove-hook 'ispell-update-post-hook 'follow-post-command-hook t)
459 (remove-hook 'replace-update-post-hook 'follow-post-command-hook t)
460 (remove-hook 'isearch-update-post-hook 'follow-post-command-hook t)
461 (remove-hook 'after-change-functions 'follow-after-change t)
435 (remove-hook 'compilation-filter-hook 'follow-align-compilation-windows t))) 462 (remove-hook 'compilation-filter-hook 'follow-align-compilation-windows t)))
436 463
437(defun follow-find-file-hook () 464(defun follow-find-file-hook ()
@@ -1015,6 +1042,10 @@ Otherwise, return nil."
1015;; is nil. Start every window directly after the end of the previous 1042;; is nil. Start every window directly after the end of the previous
1016;; window, to make sure long lines are displayed correctly. 1043;; window, to make sure long lines are displayed correctly.
1017 1044
1045(defvar follow-start-end-invalid t
1046 "When non-nil, indicates `follow-windows-start-end-cache' is invalid.")
1047(make-variable-buffer-local 'follow-start-end-invalid)
1048
1018(defun follow-redisplay (&optional windows win preserve-win) 1049(defun follow-redisplay (&optional windows win preserve-win)
1019 "Reposition the WINDOWS around WIN. 1050 "Reposition the WINDOWS around WIN.
1020Should point be too close to the roof we redisplay everything 1051Should point be too close to the roof we redisplay everything
@@ -1047,7 +1078,8 @@ repositioning the other windows."
1047 (dolist (w windows) 1078 (dolist (w windows)
1048 (unless (and preserve-win (eq w win)) 1079 (unless (and preserve-win (eq w win))
1049 (set-window-start w start)) 1080 (set-window-start w start))
1050 (setq start (car (follow-calc-win-end w)))))) 1081 (setq start (car (follow-calc-win-end w))))
1082 (setq follow-start-end-invalid nil)))
1051 1083
1052(defun follow-estimate-first-window-start (windows win start) 1084(defun follow-estimate-first-window-start (windows win start)
1053 "Estimate the position of the first window. 1085 "Estimate the position of the first window.
@@ -1443,6 +1475,146 @@ non-first windows in Follow mode."
1443 1475
1444(add-hook 'window-scroll-functions 'follow-avoid-tail-recenter t) 1476(add-hook 'window-scroll-functions 'follow-avoid-tail-recenter t)
1445 1477
1478;;; Low level window start and end.
1479
1480;; These routines are the Follow Mode versions of the low level
1481;; functions described on page "Window Start and End" of the elisp
1482;; manual, e.g. `window-group-start'. The aim is to be able to handle
1483;; Follow Mode windows by replacing `window-start' by
1484;; `window-group-start', etc.
1485
1486(defun follow-after-change (_beg _end _old-len)
1487 "After change function: set `follow-start-end-invalid'."
1488 (setq follow-start-end-invalid t))
1489
1490(defun follow-window-start (&optional window)
1491 "Return position at which display currently starts in the
1492Follow Mode group of windows which includes WINDOW.
1493
1494WINDOW must be a live window and defaults to the selected one.
1495This is updated by redisplay or by calling
1496`follow-set-window-start'."
1497 (let ((windows (follow-all-followers window)))
1498 (window-start (car windows))))
1499
1500(defun follow-window-end (&optional window update)
1501 "Return position at which display currently ends in the Follow
1502 Mode group of windows which includes WINDOW.
1503
1504 WINDOW must be a live window and defaults to the selected one.
1505 This is updated by redisplay, when it runs to completion.
1506 Simply changing the buffer text or setting `window-start' does
1507 not update this value.
1508
1509 Return nil if there is no recorded value. (This can happen if
1510 the last redisplay of WINDOW was preempted, and did not
1511 finish.) If UPDATE is non-nil, compute the up-to-date position
1512 if it isn't already recorded."
1513 (let* ((windows (follow-all-followers window))
1514 (last (car (last windows))))
1515 (when (and update follow-start-end-invalid)
1516 (follow-redisplay windows (car windows)))
1517 (window-end last update)))
1518
1519(defun follow-set-window-start (window pos &optional noforce)
1520 "Make display in the Follow Mode group of windows which includes
1521WINDOW start at position POS in WINDOW's buffer.
1522
1523WINDOW must be a live window and defaults to the selected one. Return
1524POS. Optional third arg NOFORCE non-nil inhibits next redisplay from
1525overriding motion of point in order to display at this exact start."
1526 (let ((windows (follow-all-followers window)))
1527 (setq follow-start-end-invalid t)
1528 (set-window-start (car windows) pos noforce)))
1529
1530(defun follow-pos-visible-in-window-p (&optional pos window partially)
1531 "Return non-nil if position POS is currently on the frame in one of
1532 the windows in the Follow Mode group which includes WINDOW.
1533
1534WINDOW must be a live window and defaults to the selected one.
1535
1536Return nil if that position is scrolled vertically out of view. If a
1537character is only partially visible, nil is returned, unless the
1538optional argument PARTIALLY is non-nil. If POS is only out of view
1539because of horizontal scrolling, return non-nil. If POS is t, it
1540specifies the position of the last visible glyph in WINDOW. POS
1541defaults to point in WINDOW; WINDOW defaults to the selected window.
1542
1543If POS is visible, return t if PARTIALLY is nil; if PARTIALLY is non-nil,
1544the return value is a list of 2 or 6 elements (X Y [RTOP RBOT ROWH VPOS]),
1545where X and Y are the pixel coordinates relative to the top left corner
1546of the actual window containing it. The remaining elements are
1547omitted if the character after POS is fully visible; otherwise, RTOP
1548and RBOT are the number of pixels off-window at the top and bottom of
1549the screen line (\"row\") containing POS, ROWH is the visible height
1550of that row, and VPOS is the row number \(zero-based)."
1551 (let* ((windows (follow-all-followers window))
1552 (last (car (last windows))))
1553 (when follow-start-end-invalid
1554 (follow-redisplay windows (car windows)))
1555 (let* ((cache (follow-windows-start-end windows))
1556 (last-elt (car (last cache)))
1557 our-pos pertinent-elt)
1558 (setq pertinent-elt
1559 (if (eq pos t)
1560 last-elt
1561 (setq our-pos (or pos (point)))
1562 (catch 'element
1563 (while cache
1564 (when (< our-pos (nth 2 (car cache)))
1565 (throw 'element (car cache)))
1566 (setq cache (cdr cache)))
1567 last-elt)))
1568 (pos-visible-in-window-p our-pos (car pertinent-elt) partially))))
1569
1570(defun follow-move-to-window-line (arg)
1571 "Position point relative to the Follow mode group containing the selected window.
1572ARG nil means position point at center of the window group.
1573Else, ARG specifies vertical position within the window group;
1574zero means top of the first window in the group, negative means
1575 relative to bottom of the last window in the group."
1576 (let* ((windows (follow-all-followers))
1577 (start-end (follow-windows-start-end windows))
1578 (rev-start-end (reverse start-end))
1579 (lines 0)
1580 middle-window elt count)
1581 (select-window
1582 (cond
1583 ((null arg)
1584 (setq rev-start-end (nthcdr (/ (length windows) 2) rev-start-end))
1585 (prog1 (car (car rev-start-end))
1586 (while (setq rev-start-end (cdr rev-start-end))
1587 (setq elt (car rev-start-end)
1588 count (count-screen-lines (cadr elt) (nth 2 elt)
1589 nil (car elt))
1590 lines (+ lines count)))))
1591 ((>= arg 0)
1592 (while (and (cdr start-end)
1593 (progn
1594 (setq elt (car start-end)
1595 count (count-screen-lines (cadr elt) (nth 2 elt)
1596 nil (car elt)))
1597 (>= arg count)))
1598 (setq arg (- arg count)
1599 lines (+ lines count)
1600 start-end (cdr start-end)))
1601 (car (car start-end)))
1602 (t ; (< arg 0)
1603 (while (and (cadr rev-start-end)
1604 (progn
1605 (setq elt (car rev-start-end)
1606 count (count-lines (cadr elt) (nth 2 elt)))
1607 (<= arg (- count))))
1608 (setq arg (+ arg count)
1609 rev-start-end (cdr rev-start-end)))
1610 (prog1 (car (car rev-start-end))
1611 (while (setq rev-start-end (cdr rev-start-end))
1612 (setq elt (car rev-start-end)
1613 count (count-screen-lines (cadr elt) (nth 2 elt)
1614 nil (car elt))
1615 lines (+ lines count)))))))
1616 (+ lines (move-to-window-line arg))))
1617
1446;;; Profile support 1618;;; Profile support
1447 1619
1448;; The following (non-evaluated) section can be used to 1620;; The following (non-evaluated) section can be used to
diff --git a/lisp/isearch.el b/lisp/isearch.el
index 8c98d36f4aa..05dc2931d93 100644
--- a/lisp/isearch.el
+++ b/lisp/isearch.el
@@ -961,7 +961,8 @@ used to set the value of `isearch-regexp-function'."
961 961
962(defun isearch-update () 962(defun isearch-update ()
963 "This is called after every isearch command to update the display. 963 "This is called after every isearch command to update the display.
964The last thing it does is to run `isearch-update-post-hook'." 964The second last thing it does is to run `isearch-update-post-hook'.
965The last thing is to trigger a new round of lazy highlighting."
965 (unless (eq (current-buffer) isearch--current-buffer) 966 (unless (eq (current-buffer) isearch--current-buffer)
966 (when (buffer-live-p isearch--current-buffer) 967 (when (buffer-live-p isearch--current-buffer)
967 (with-current-buffer isearch--current-buffer 968 (with-current-buffer isearch--current-buffer
@@ -978,12 +979,10 @@ The last thing it does is to run `isearch-update-post-hook'."
978 (null executing-kbd-macro)) 979 (null executing-kbd-macro))
979 (progn 980 (progn
980 (if (not (input-pending-p)) 981 (if (not (input-pending-p))
981 (if isearch-message-function 982 (funcall (or isearch-message-function #'isearch-message)))
982 (funcall isearch-message-function)
983 (isearch-message)))
984 (if (and isearch-slow-terminal-mode 983 (if (and isearch-slow-terminal-mode
985 (not (or isearch-small-window 984 (not (or isearch-small-window
986 (pos-visible-in-window-p)))) 985 (pos-visible-in-window-group-p))))
987 (let ((found-point (point))) 986 (let ((found-point (point)))
988 (setq isearch-small-window t) 987 (setq isearch-small-window t)
989 (move-to-window-line 0) 988 (move-to-window-line 0)
@@ -1004,10 +1003,10 @@ The last thing it does is to run `isearch-update-post-hook'."
1004 (let ((current-scroll (window-hscroll)) 1003 (let ((current-scroll (window-hscroll))
1005 visible-p) 1004 visible-p)
1006 (set-window-hscroll (selected-window) isearch-start-hscroll) 1005 (set-window-hscroll (selected-window) isearch-start-hscroll)
1007 (setq visible-p (pos-visible-in-window-p nil nil t)) 1006 (setq visible-p (pos-visible-in-window-group-p nil nil t))
1008 (if (or (not visible-p) 1007 (if (or (not visible-p)
1009 ;; When point is not visible because of hscroll, 1008 ;; When point is not visible because of hscroll,
1010 ;; pos-visible-in-window-p returns non-nil, but 1009 ;; pos-visible-in-window-group-p returns non-nil, but
1011 ;; the X coordinate it returns is 1 pixel beyond 1010 ;; the X coordinate it returns is 1 pixel beyond
1012 ;; the last visible one. 1011 ;; the last visible one.
1013 (>= (car visible-p) (window-body-width nil t))) 1012 (>= (car visible-p) (window-body-width nil t)))
@@ -1020,12 +1019,12 @@ The last thing it does is to run `isearch-update-post-hook'."
1020 (setq ;; quit-flag nil not for isearch-mode 1019 (setq ;; quit-flag nil not for isearch-mode
1021 isearch-adjusted nil 1020 isearch-adjusted nil
1022 isearch-yank-flag nil) 1021 isearch-yank-flag nil)
1023 (when isearch-lazy-highlight
1024 (isearch-lazy-highlight-new-loop))
1025 ;; We must prevent the point moving to the end of composition when a 1022 ;; We must prevent the point moving to the end of composition when a
1026 ;; part of the composition has just been searched. 1023 ;; part of the composition has just been searched.
1027 (setq disable-point-adjustment t) 1024 (setq disable-point-adjustment t)
1028 (run-hooks 'isearch-update-post-hook)) 1025 (run-hooks 'isearch-update-post-hook)
1026 (when isearch-lazy-highlight
1027 (isearch-lazy-highlight-new-loop)))
1029 1028
1030(defun isearch-done (&optional nopush edit) 1029(defun isearch-done (&optional nopush edit)
1031 "Exit Isearch mode. 1030 "Exit Isearch mode.
@@ -1058,7 +1057,7 @@ NOPUSH is t and EDIT is t."
1058 (setq minibuffer-message-timeout isearch-original-minibuffer-message-timeout) 1057 (setq minibuffer-message-timeout isearch-original-minibuffer-message-timeout)
1059 (isearch-dehighlight) 1058 (isearch-dehighlight)
1060 (lazy-highlight-cleanup lazy-highlight-cleanup) 1059 (lazy-highlight-cleanup lazy-highlight-cleanup)
1061 (let ((found-start (window-start)) 1060 (let ((found-start (window-group-start))
1062 (found-point (point))) 1061 (found-point (point)))
1063 (when isearch-window-configuration 1062 (when isearch-window-configuration
1064 (set-window-configuration isearch-window-configuration) 1063 (set-window-configuration isearch-window-configuration)
@@ -1068,7 +1067,7 @@ NOPUSH is t and EDIT is t."
1068 ;; This has an annoying side effect of clearing the last_modiff 1067 ;; This has an annoying side effect of clearing the last_modiff
1069 ;; field of the window, which can cause unwanted scrolling, 1068 ;; field of the window, which can cause unwanted scrolling,
1070 ;; so don't do it unless truly necessary. 1069 ;; so don't do it unless truly necessary.
1071 (set-window-start (selected-window) found-start t)))) 1070 (set-window-group-start (selected-window) found-start t))))
1072 1071
1073 (setq isearch-mode nil) 1072 (setq isearch-mode nil)
1074 (if isearch-input-method-local-p 1073 (if isearch-input-method-local-p
@@ -1299,13 +1298,6 @@ You can update the global isearch variables by setting new values to
1299 (unwind-protect 1298 (unwind-protect
1300 (progn ,@body) 1299 (progn ,@body)
1301 1300
1302 ;; Set point at the start (end) of old match if forward (backward),
1303 ;; so after exiting minibuffer isearch resumes at the start (end)
1304 ;; of this match and can find it again.
1305 (if (and old-other-end (eq old-point (point))
1306 (eq isearch-forward isearch-new-forward))
1307 (goto-char old-other-end))
1308
1309 ;; Always resume isearching by restarting it. 1301 ;; Always resume isearching by restarting it.
1310 (isearch-mode isearch-forward 1302 (isearch-mode isearch-forward
1311 isearch-regexp 1303 isearch-regexp
@@ -1318,7 +1310,17 @@ You can update the global isearch variables by setting new values to
1318 isearch-message isearch-new-message 1310 isearch-message isearch-new-message
1319 isearch-forward isearch-new-forward 1311 isearch-forward isearch-new-forward
1320 isearch-regexp-function isearch-new-regexp-function 1312 isearch-regexp-function isearch-new-regexp-function
1321 isearch-case-fold-search isearch-new-case-fold)) 1313 isearch-case-fold-search isearch-new-case-fold)
1314
1315 ;; Restore the minibuffer message before moving point.
1316 (funcall (or isearch-message-function #'isearch-message) nil t)
1317
1318 ;; Set point at the start (end) of old match if forward (backward),
1319 ;; so after exiting minibuffer isearch resumes at the start (end)
1320 ;; of this match and can find it again.
1321 (if (and old-other-end (eq old-point (point))
1322 (eq isearch-forward isearch-new-forward))
1323 (goto-char old-other-end)))
1322 1324
1323 ;; Empty isearch-string means use default. 1325 ;; Empty isearch-string means use default.
1324 (when (= 0 (length isearch-string)) 1326 (when (= 0 (length isearch-string))
@@ -1931,6 +1933,8 @@ If search string is empty, just beep."
1931 (length isearch-string)))) 1933 (length isearch-string))))
1932 isearch-message (mapconcat 'isearch-text-char-description 1934 isearch-message (mapconcat 'isearch-text-char-description
1933 isearch-string ""))) 1935 isearch-string "")))
1936 ;; Do the following before moving point.
1937 (funcall (or isearch-message-function #'isearch-message) nil t)
1934 ;; Use the isearch-other-end as new starting point to be able 1938 ;; Use the isearch-other-end as new starting point to be able
1935 ;; to find the remaining part of the search string again. 1939 ;; to find the remaining part of the search string again.
1936 ;; This is like what `isearch-search-and-update' does, 1940 ;; This is like what `isearch-search-and-update' does,
@@ -2107,6 +2111,8 @@ With argument, add COUNT copies of the character."
2107 (setq isearch-case-fold-search 2111 (setq isearch-case-fold-search
2108 (isearch-no-upper-case-p isearch-string isearch-regexp)))) 2112 (isearch-no-upper-case-p isearch-string isearch-regexp))))
2109 ;; Not regexp, not reverse, or no match at point. 2113 ;; Not regexp, not reverse, or no match at point.
2114 ;; Do the following before moving point.
2115 (funcall (or isearch-message-function #'isearch-message) nil t)
2110 (if (and isearch-other-end (not isearch-adjusted)) 2116 (if (and isearch-other-end (not isearch-adjusted))
2111 (goto-char (if isearch-forward isearch-other-end 2117 (goto-char (if isearch-forward isearch-other-end
2112 (min isearch-opoint 2118 (min isearch-opoint
@@ -2273,10 +2279,12 @@ Return nil if it's completely visible, or if point is visible,
2273together with as much of the search string as will fit; the symbol 2279together with as much of the search string as will fit; the symbol
2274`above' if we need to scroll the text downwards; the symbol `below', 2280`above' if we need to scroll the text downwards; the symbol `below',
2275if upwards." 2281if upwards."
2276 (let ((w-start (window-start)) 2282 (let ((w-start (window-group-start))
2277 (w-end (window-end nil t)) 2283 (w-end (window-group-end nil t))
2278 (w-L1 (save-excursion (move-to-window-line 1) (point))) 2284 (w-L1 (save-excursion
2279 (w-L-1 (save-excursion (move-to-window-line -1) (point))) 2285 (save-selected-window (move-to-window-group-line 1) (point))))
2286 (w-L-1 (save-excursion
2287 (save-selected-window (move-to-window-group-line -1) (point))))
2280 start end) ; start and end of search string in buffer 2288 start end) ; start and end of search string in buffer
2281 (if isearch-forward 2289 (if isearch-forward
2282 (setq end isearch-point start (or isearch-other-end isearch-point)) 2290 (setq end isearch-point start (or isearch-other-end isearch-point))
@@ -2303,15 +2311,15 @@ the bottom."
2303 (if above 2311 (if above
2304 (progn 2312 (progn
2305 (goto-char start) 2313 (goto-char start)
2306 (recenter 0) 2314 (recenter-window-group 0)
2307 (when (>= isearch-point (window-end nil t)) 2315 (when (>= isearch-point (window-group-end nil t))
2308 (goto-char isearch-point) 2316 (goto-char isearch-point)
2309 (recenter -1))) 2317 (recenter-window-group -1)))
2310 (goto-char end) 2318 (goto-char end)
2311 (recenter -1) 2319 (recenter-window-group -1)
2312 (when (< isearch-point (window-start)) 2320 (when (< isearch-point (window-group-start))
2313 (goto-char isearch-point) 2321 (goto-char isearch-point)
2314 (recenter 0)))) 2322 (recenter-window-group 0))))
2315 (goto-char isearch-point)) 2323 (goto-char isearch-point))
2316 2324
2317(defvar isearch-pre-scroll-point nil) 2325(defvar isearch-pre-scroll-point nil)
@@ -2458,6 +2466,7 @@ Search is updated accordingly."
2458 (isearch-ring-adjust1 advance) 2466 (isearch-ring-adjust1 advance)
2459 (if search-ring-update 2467 (if search-ring-update
2460 (progn 2468 (progn
2469 (funcall (or isearch-message-function #'isearch-message) nil t)
2461 (isearch-search) 2470 (isearch-search)
2462 (isearch-push-state) 2471 (isearch-push-state)
2463 (isearch-update)) 2472 (isearch-update))
@@ -2530,6 +2539,13 @@ If there is no completion possible, say so and continue searching."
2530 2539
2531(defun isearch-message (&optional c-q-hack ellipsis) 2540(defun isearch-message (&optional c-q-hack ellipsis)
2532 ;; Generate and print the message string. 2541 ;; Generate and print the message string.
2542
2543 ;; N.B.: This function should always be called with point at the
2544 ;; search point, because in certain (rare) circumstances, undesired
2545 ;; scrolling can happen when point is elsewhere. These
2546 ;; circumstances are when follow-mode is active, the search string
2547 ;; spans two (or several) windows, and the message about to be
2548 ;; displayed will cause the echo area to expand.
2533 (let ((cursor-in-echo-area ellipsis) 2549 (let ((cursor-in-echo-area ellipsis)
2534 (m isearch-message) 2550 (m isearch-message)
2535 (fail-pos (isearch-fail-pos t))) 2551 (fail-pos (isearch-fail-pos t)))
@@ -2723,9 +2739,6 @@ update the match data, and return point."
2723 2739
2724(defun isearch-search () 2740(defun isearch-search ()
2725 ;; Do the search with the current search string. 2741 ;; Do the search with the current search string.
2726 (if isearch-message-function
2727 (funcall isearch-message-function nil t)
2728 (isearch-message nil t))
2729 (if (and (eq isearch-case-fold-search t) search-upper-case) 2742 (if (and (eq isearch-case-fold-search t) search-upper-case)
2730 (setq isearch-case-fold-search 2743 (setq isearch-case-fold-search
2731 (isearch-no-upper-case-p isearch-string isearch-regexp))) 2744 (isearch-no-upper-case-p isearch-string isearch-regexp)))
@@ -3023,6 +3036,7 @@ since they have special meaning in a regexp."
3023(defvar isearch-lazy-highlight-timer nil) 3036(defvar isearch-lazy-highlight-timer nil)
3024(defvar isearch-lazy-highlight-last-string nil) 3037(defvar isearch-lazy-highlight-last-string nil)
3025(defvar isearch-lazy-highlight-window nil) 3038(defvar isearch-lazy-highlight-window nil)
3039(defvar isearch-lazy-highlight-window-group nil)
3026(defvar isearch-lazy-highlight-window-start nil) 3040(defvar isearch-lazy-highlight-window-start nil)
3027(defvar isearch-lazy-highlight-window-end nil) 3041(defvar isearch-lazy-highlight-window-end nil)
3028(defvar isearch-lazy-highlight-case-fold-search nil) 3042(defvar isearch-lazy-highlight-case-fold-search nil)
@@ -3064,8 +3078,8 @@ by other Emacs features."
3064 (sit-for 0) ;make sure (window-start) is credible 3078 (sit-for 0) ;make sure (window-start) is credible
3065 (or (not (equal isearch-string 3079 (or (not (equal isearch-string
3066 isearch-lazy-highlight-last-string)) 3080 isearch-lazy-highlight-last-string))
3067 (not (eq (selected-window) 3081 (not (memq (selected-window)
3068 isearch-lazy-highlight-window)) 3082 isearch-lazy-highlight-window-group))
3069 (not (eq isearch-lazy-highlight-case-fold-search 3083 (not (eq isearch-lazy-highlight-case-fold-search
3070 isearch-case-fold-search)) 3084 isearch-case-fold-search))
3071 (not (eq isearch-lazy-highlight-regexp 3085 (not (eq isearch-lazy-highlight-regexp
@@ -3076,9 +3090,9 @@ by other Emacs features."
3076 isearch-lax-whitespace)) 3090 isearch-lax-whitespace))
3077 (not (eq isearch-lazy-highlight-regexp-lax-whitespace 3091 (not (eq isearch-lazy-highlight-regexp-lax-whitespace
3078 isearch-regexp-lax-whitespace)) 3092 isearch-regexp-lax-whitespace))
3079 (not (= (window-start) 3093 (not (= (window-group-start)
3080 isearch-lazy-highlight-window-start)) 3094 isearch-lazy-highlight-window-start))
3081 (not (= (window-end) ; Window may have been split/joined. 3095 (not (= (window-group-end) ; Window may have been split/joined.
3082 isearch-lazy-highlight-window-end)) 3096 isearch-lazy-highlight-window-end))
3083 (not (eq isearch-forward 3097 (not (eq isearch-forward
3084 isearch-lazy-highlight-forward)) 3098 isearch-lazy-highlight-forward))
@@ -3086,7 +3100,7 @@ by other Emacs features."
3086 (not (equal isearch-error 3100 (not (equal isearch-error
3087 isearch-lazy-highlight-error)))) 3101 isearch-lazy-highlight-error))))
3088 ;; something important did indeed change 3102 ;; something important did indeed change
3089 (lazy-highlight-cleanup t) ;kill old loop & remove overlays 3103 (lazy-highlight-cleanup t) ;kill old loop & remove overlays
3090 (setq isearch-lazy-highlight-error isearch-error) 3104 (setq isearch-lazy-highlight-error isearch-error)
3091 ;; It used to check for `(not isearch-error)' here, but actually 3105 ;; It used to check for `(not isearch-error)' here, but actually
3092 ;; lazy-highlighting might find matches to highlight even when 3106 ;; lazy-highlighting might find matches to highlight even when
@@ -3094,8 +3108,9 @@ by other Emacs features."
3094 (setq isearch-lazy-highlight-start-limit beg 3108 (setq isearch-lazy-highlight-start-limit beg
3095 isearch-lazy-highlight-end-limit end) 3109 isearch-lazy-highlight-end-limit end)
3096 (setq isearch-lazy-highlight-window (selected-window) 3110 (setq isearch-lazy-highlight-window (selected-window)
3097 isearch-lazy-highlight-window-start (window-start) 3111 isearch-lazy-highlight-window-group (selected-window-group)
3098 isearch-lazy-highlight-window-end (window-end) 3112 isearch-lazy-highlight-window-start (window-group-start)
3113 isearch-lazy-highlight-window-end (window-group-end)
3099 ;; Start lazy-highlighting at the beginning of the found 3114 ;; Start lazy-highlighting at the beginning of the found
3100 ;; match (`isearch-other-end'). If no match, use point. 3115 ;; match (`isearch-other-end'). If no match, use point.
3101 ;; One of the next two variables (depending on search direction) 3116 ;; One of the next two variables (depending on search direction)
@@ -3113,10 +3128,10 @@ by other Emacs features."
3113 isearch-lazy-highlight-regexp-lax-whitespace isearch-regexp-lax-whitespace 3128 isearch-lazy-highlight-regexp-lax-whitespace isearch-regexp-lax-whitespace
3114 isearch-lazy-highlight-regexp-function isearch-regexp-function 3129 isearch-lazy-highlight-regexp-function isearch-regexp-function
3115 isearch-lazy-highlight-forward isearch-forward) 3130 isearch-lazy-highlight-forward isearch-forward)
3116 (unless (equal isearch-string "") 3131 (unless (equal isearch-string "")
3117 (setq isearch-lazy-highlight-timer 3132 (setq isearch-lazy-highlight-timer
3118 (run-with-idle-timer lazy-highlight-initial-delay nil 3133 (run-with-idle-timer lazy-highlight-initial-delay nil
3119 'isearch-lazy-highlight-update))))) 3134 'isearch-lazy-highlight-update)))))
3120 3135
3121(defun isearch-lazy-highlight-search () 3136(defun isearch-lazy-highlight-search ()
3122 "Search ahead for the next or previous match, for lazy highlighting. 3137 "Search ahead for the next or previous match, for lazy highlighting.
@@ -3139,13 +3154,13 @@ Attempt to do the search exactly the way the pending Isearch would."
3139 (+ isearch-lazy-highlight-start 3154 (+ isearch-lazy-highlight-start
3140 ;; Extend bound to match whole string at point 3155 ;; Extend bound to match whole string at point
3141 (1- (length isearch-lazy-highlight-last-string))) 3156 (1- (length isearch-lazy-highlight-last-string)))
3142 (window-end))) 3157 (window-group-end)))
3143 (max (or isearch-lazy-highlight-start-limit (point-min)) 3158 (max (or isearch-lazy-highlight-start-limit (point-min))
3144 (if isearch-lazy-highlight-wrapped 3159 (if isearch-lazy-highlight-wrapped
3145 (- isearch-lazy-highlight-end 3160 (- isearch-lazy-highlight-end
3146 ;; Extend bound to match whole string at point 3161 ;; Extend bound to match whole string at point
3147 (1- (length isearch-lazy-highlight-last-string))) 3162 (1- (length isearch-lazy-highlight-last-string)))
3148 (window-start)))))) 3163 (window-group-start))))))
3149 ;; Use a loop like in `isearch-search'. 3164 ;; Use a loop like in `isearch-search'.
3150 (while retry 3165 (while retry
3151 (setq success (isearch-search-string 3166 (setq success (isearch-search-string
@@ -3169,7 +3184,7 @@ Attempt to do the search exactly the way the pending Isearch would."
3169 (with-local-quit 3184 (with-local-quit
3170 (save-selected-window 3185 (save-selected-window
3171 (if (and (window-live-p isearch-lazy-highlight-window) 3186 (if (and (window-live-p isearch-lazy-highlight-window)
3172 (not (eq (selected-window) isearch-lazy-highlight-window))) 3187 (not (memq (selected-window) isearch-lazy-highlight-window-group)))
3173 (select-window isearch-lazy-highlight-window)) 3188 (select-window isearch-lazy-highlight-window))
3174 (save-excursion 3189 (save-excursion
3175 (save-match-data 3190 (save-match-data
@@ -3189,12 +3204,12 @@ Attempt to do the search exactly the way the pending Isearch would."
3189 (if isearch-lazy-highlight-forward 3204 (if isearch-lazy-highlight-forward
3190 (if (= mb (if isearch-lazy-highlight-wrapped 3205 (if (= mb (if isearch-lazy-highlight-wrapped
3191 isearch-lazy-highlight-start 3206 isearch-lazy-highlight-start
3192 (window-end))) 3207 (window-group-end)))
3193 (setq found nil) 3208 (setq found nil)
3194 (forward-char 1)) 3209 (forward-char 1))
3195 (if (= mb (if isearch-lazy-highlight-wrapped 3210 (if (= mb (if isearch-lazy-highlight-wrapped
3196 isearch-lazy-highlight-end 3211 isearch-lazy-highlight-end
3197 (window-start))) 3212 (window-group-start)))
3198 (setq found nil) 3213 (setq found nil)
3199 (forward-char -1))) 3214 (forward-char -1)))
3200 3215
@@ -3204,8 +3219,8 @@ Attempt to do the search exactly the way the pending Isearch would."
3204 ;; 1000 is higher than ediff's 100+, 3219 ;; 1000 is higher than ediff's 100+,
3205 ;; but lower than isearch main overlay's 1001 3220 ;; but lower than isearch main overlay's 1001
3206 (overlay-put ov 'priority 1000) 3221 (overlay-put ov 'priority 1000)
3207 (overlay-put ov 'face lazy-highlight-face) 3222 (overlay-put ov 'face lazy-highlight-face)))
3208 (overlay-put ov 'window (selected-window)))) 3223 ;(overlay-put ov 'window (selected-window))))
3209 ;; Remember the current position of point for 3224 ;; Remember the current position of point for
3210 ;; the next call of `isearch-lazy-highlight-update' 3225 ;; the next call of `isearch-lazy-highlight-update'
3211 ;; when `lazy-highlight-max-at-a-time' is too small. 3226 ;; when `lazy-highlight-max-at-a-time' is too small.
@@ -3221,12 +3236,12 @@ Attempt to do the search exactly the way the pending Isearch would."
3221 (setq isearch-lazy-highlight-wrapped t) 3236 (setq isearch-lazy-highlight-wrapped t)
3222 (if isearch-lazy-highlight-forward 3237 (if isearch-lazy-highlight-forward
3223 (progn 3238 (progn
3224 (setq isearch-lazy-highlight-end (window-start)) 3239 (setq isearch-lazy-highlight-end (window-group-start))
3225 (goto-char (max (or isearch-lazy-highlight-start-limit (point-min)) 3240 (goto-char (max (or isearch-lazy-highlight-start-limit (point-min))
3226 (window-start)))) 3241 (window-group-start))))
3227 (setq isearch-lazy-highlight-start (window-end)) 3242 (setq isearch-lazy-highlight-start (window-group-end))
3228 (goto-char (min (or isearch-lazy-highlight-end-limit (point-max)) 3243 (goto-char (min (or isearch-lazy-highlight-end-limit (point-max))
3229 (window-end)))))))) 3244 (window-group-end))))))))
3230 (unless nomore 3245 (unless nomore
3231 (setq isearch-lazy-highlight-timer 3246 (setq isearch-lazy-highlight-timer
3232 (run-at-time lazy-highlight-interval nil 3247 (run-at-time lazy-highlight-interval nil
diff --git a/lisp/replace.el b/lisp/replace.el
index 54b3a71bda2..d48f4f3fdf9 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -2011,6 +2011,9 @@ passed in. If LITERAL is set, no checking is done, anyway."
2011 (when backward (goto-char (nth 0 match-data))) 2011 (when backward (goto-char (nth 0 match-data)))
2012 noedit) 2012 noedit)
2013 2013
2014(defvar replace-update-post-hook nil
2015 "Function(s) to call after query-replace has found a match in the buffer.")
2016
2014(defvar replace-search-function nil 2017(defvar replace-search-function nil
2015 "Function to use when searching for strings to replace. 2018 "Function to use when searching for strings to replace.
2016It is used by `query-replace' and `replace-string', and is called 2019It is used by `query-replace' and `replace-string', and is called
@@ -2264,7 +2267,7 @@ It must return a string."
2264 (and nonempty-match 2267 (and nonempty-match
2265 (or (not regexp-flag) 2268 (or (not regexp-flag)
2266 (and (if backward 2269 (and (if backward
2267 (looking-back search-string) 2270 (looking-back search-string nil)
2268 (looking-at search-string)) 2271 (looking-at search-string))
2269 (let ((match (match-data))) 2272 (let ((match (match-data)))
2270 (and (/= (nth 0 match) (nth 1 match)) 2273 (and (/= (nth 0 match) (nth 1 match))
@@ -2318,7 +2321,8 @@ It must return a string."
2318 ;; `real-match-data'. 2321 ;; `real-match-data'.
2319 (while (not done) 2322 (while (not done)
2320 (set-match-data real-match-data) 2323 (set-match-data real-match-data)
2321 (replace-highlight 2324 (run-hooks 'replace-update-post-hook) ; Before `replace-highlight'.
2325 (replace-highlight
2322 (match-beginning 0) (match-end 0) 2326 (match-beginning 0) (match-end 0)
2323 start end search-string 2327 start end search-string
2324 regexp-flag delimited-flag case-fold-search backward) 2328 regexp-flag delimited-flag case-fold-search backward)
diff --git a/lisp/textmodes/ispell.el b/lisp/textmodes/ispell.el
index aa51446d6b4..05a5da57b66 100644
--- a/lisp/textmodes/ispell.el
+++ b/lisp/textmodes/ispell.el
@@ -1782,6 +1782,51 @@ Extended character mode can be changed for this buffer by placing
1782a `~' followed by an extended-character mode -- such as `~.tex'. 1782a `~' followed by an extended-character mode -- such as `~.tex'.
1783The last occurring definition in the buffer will be used.") 1783The last occurring definition in the buffer will be used.")
1784 1784
1785(defun ispell--\\w-filter (char)
1786 "Return CHAR in a string when CHAR doesn't have \"word\" syntax,
1787nil otherwise. CHAR must be a character."
1788 (let ((str (string char)))
1789 (and
1790 (not (string-match "\\w" str))
1791 str)))
1792
1793(defun ispell--make-\\w-expression (chars)
1794 "Make a regular expression like \"\\(\\w\\|[-_]\\)\".
1795This (parenthesized) expression matches either a character of
1796\"word\" syntax or one in CHARS.
1797
1798CHARS is a string of characters. A member of CHARS is omitted
1799from the expression if it already has word syntax. (Be careful
1800about special characters such as ?\\, ?^, ?], and ?- in CHARS.)
1801If after this filtering there are no chars left, or only one, a
1802special form of the expression is generated."
1803 (let ((filtered
1804 (mapconcat #'ispell--\\w-filter chars "")))
1805 (concat
1806 "\\(\\w"
1807 (cond
1808 ((equal filtered "")
1809 "\\)")
1810 ((eq (length filtered) 1)
1811 (concat "\\|" filtered "\\)"))
1812 (t
1813 (concat "\\|[" filtered "]\\)"))))))
1814
1815(defun ispell--make-filename-or-URL-re ()
1816 "Construct a regexp to match some file names or URLs or email addresses.
1817The expression is crafted to match as great a variety of these
1818objects as practicable, without too many false matches happening."
1819 (concat ;"\\(--+\\|_+\\|"
1820 "\\(/\\w\\|\\("
1821 (ispell--make-\\w-expression "-_")
1822 "+[.:@]\\)\\)"
1823 (ispell--make-\\w-expression "-_")
1824 "*\\([.:/@]+"
1825 (ispell--make-\\w-expression "-_~=?&")
1826 "+\\)+"
1827 ;"\\)"
1828 ))
1829
1785;;;###autoload 1830;;;###autoload
1786(defvar ispell-skip-region-alist 1831(defvar ispell-skip-region-alist
1787 `((ispell-words-keyword forward-line) 1832 `((ispell-words-keyword forward-line)
@@ -1798,7 +1843,7 @@ The last occurring definition in the buffer will be used.")
1798 ;; Matches e-mail addresses, file names, http addresses, etc. The 1843 ;; Matches e-mail addresses, file names, http addresses, etc. The
1799 ;; `-+' `_+' patterns are necessary for performance reasons when 1844 ;; `-+' `_+' patterns are necessary for performance reasons when
1800 ;; `-' or `_' part of word syntax. 1845 ;; `-' or `_' part of word syntax.
1801 (,(purecopy "\\(--+\\|_+\\|\\(/\\w\\|\\(\\(\\w\\|[-_]\\)+[.:@]\\)\\)\\(\\w\\|[-_]\\)*\\([.:/@]+\\(\\w\\|[-_~=?&]\\)+\\)+\\)")) 1846; (,(purecopy "\\(--+\\|_+\\|\\(/\\w\\|\\(\\(\\w\\|[-_]\\)+[.:@]\\)\\)\\(\\w\\|[-_]\\)*\\([.:/@]+\\(\\w\\|[-_~=?&]\\)+\\)+\\)"))
1802 ;; above checks /.\w sequences 1847 ;; above checks /.\w sequences
1803 ;;("\\(--+\\|\\(/\\|\\(\\(\\w\\|[-_]\\)+[.:@]\\)\\)\\(\\w\\|[-_]\\)*\\([.:/@]+\\(\\w\\|[-_~=?&]\\)+\\)+\\)") 1848 ;;("\\(--+\\|\\(/\\|\\(\\(\\w\\|[-_]\\)+[.:@]\\)\\)\\(\\w\\|[-_]\\)*\\([.:/@]+\\(\\w\\|[-_~=?&]\\)+\\)+\\)")
1804 ;; This is a pretty complex regexp. It can be simplified to the following: 1849 ;; This is a pretty complex regexp. It can be simplified to the following:
@@ -2248,6 +2293,11 @@ If so, ask if it needs to be saved."
2248 (setq ispell-pdict-modified-p nil)) 2293 (setq ispell-pdict-modified-p nil))
2249 2294
2250 2295
2296(defvar ispell-update-post-hook nil
2297 "A normal hook invoked from the ispell command loop.
2298It is called once per iteration, before displaying a prompt to
2299the user.")
2300
2251(defun ispell-command-loop (miss guess word start end) 2301(defun ispell-command-loop (miss guess word start end)
2252 "Display possible corrections from list MISS. 2302 "Display possible corrections from list MISS.
2253GUESS lists possibly valid affix construction of WORD. 2303GUESS lists possibly valid affix construction of WORD.
@@ -2315,8 +2365,10 @@ Global `ispell-quit' set to start location to continue spell session."
2315 count (ispell-int-char (1+ count)))) 2365 count (ispell-int-char (1+ count))))
2316 (setq count (ispell-int-char (- count ?0 skipped)))) 2366 (setq count (ispell-int-char (- count ?0 skipped))))
2317 2367
2368 (run-hooks 'ispell-update-post-hook)
2369
2318 ;; ensure word is visible 2370 ;; ensure word is visible
2319 (if (not (pos-visible-in-window-p end)) 2371 (if (not (pos-visible-in-window-group-p end))
2320 (sit-for 0)) 2372 (sit-for 0))
2321 2373
2322 ;; Display choices for misspelled word. 2374 ;; Display choices for misspelled word.
@@ -2845,13 +2897,20 @@ Also position fit window to BUFFER and select it."
2845 (prog1 2897 (prog1
2846 (condition-case nil 2898 (condition-case nil
2847 (split-window 2899 (split-window
2848 nil (- ispell-choices-win-default-height) 'above) 2900 ;; Chose the last of a window group, since
2901 ;; otherwise, the lowering of another window's
2902 ;; TL corner would cause the logical order of
2903 ;; the windows to be changed.
2904 (car (last (selected-window-group)))
2905 (- ispell-choices-win-default-height) 'above)
2849 (error nil)) 2906 (error nil))
2850 (modify-frame-parameters frame '((unsplittable . t)))))) 2907 (modify-frame-parameters frame '((unsplittable . t))))))
2851 (and (not unsplittable) 2908 (and (not unsplittable)
2852 (condition-case nil 2909 (condition-case nil
2853 (split-window 2910 (split-window
2854 nil (- ispell-choices-win-default-height) 'above) 2911 ;; See comment above.
2912 (car (last (selected-window-group)))
2913 (- ispell-choices-win-default-height) 'above)
2855 (error nil))) 2914 (error nil)))
2856 (display-buffer buffer)))) 2915 (display-buffer buffer))))
2857 (if (not window) 2916 (if (not window)
@@ -3374,7 +3433,8 @@ Must be called after `ispell-buffer-local-parsing' due to dependence on mode."
3374 (if (string= "" comment-end) "^" (regexp-quote comment-end))) 3433 (if (string= "" comment-end) "^" (regexp-quote comment-end)))
3375 (if (and (null ispell-check-comments) comment-start) 3434 (if (and (null ispell-check-comments) comment-start)
3376 (regexp-quote comment-start)) 3435 (regexp-quote comment-start))
3377 (ispell-begin-skip-region ispell-skip-region-alist))) 3436 (ispell-begin-skip-region ispell-skip-region-alist)
3437 (ispell--make-filename-or-URL-re)))
3378 "\\|")) 3438 "\\|"))
3379 3439
3380 3440
@@ -3413,6 +3473,8 @@ Manual checking must include comments and tib references.
3413The list is of the form described by variable `ispell-skip-region-alist'. 3473The list is of the form described by variable `ispell-skip-region-alist'.
3414Must be called after `ispell-buffer-local-parsing' due to dependence on mode." 3474Must be called after `ispell-buffer-local-parsing' due to dependence on mode."
3415 (let ((skip-alist ispell-skip-region-alist)) 3475 (let ((skip-alist ispell-skip-region-alist))
3476 (setq skip-alist (append (list (list (ispell--make-filename-or-URL-re)))
3477 skip-alist))
3416 ;; only additional explicit region definition is tex. 3478 ;; only additional explicit region definition is tex.
3417 (if (eq ispell-parser 'tex) 3479 (if (eq ispell-parser 'tex)
3418 (setq case-fold-search nil 3480 (setq case-fold-search nil
@@ -4106,9 +4168,10 @@ You can bind this to the key C-c i in GNUS or mail by adding to
4106 (ispell-non-empty-string vm-included-text-prefix))) 4168 (ispell-non-empty-string vm-included-text-prefix)))
4107 (t default-prefix))) 4169 (t default-prefix)))
4108 (ispell-skip-region-alist 4170 (ispell-skip-region-alist
4109 (cons (list (concat "^\\(" cite-regexp "\\)") 4171 (cons (list (ispell--make-filename-or-URL-re))
4110 (function forward-line)) 4172 (cons (list (concat "^\\(" cite-regexp "\\)")
4111 ispell-skip-region-alist)) 4173 (function forward-line))
4174 ispell-skip-region-alist)))
4112 (old-case-fold-search case-fold-search) 4175 (old-case-fold-search case-fold-search)
4113 (dictionary-alist ispell-message-dictionary-alist) 4176 (dictionary-alist ispell-message-dictionary-alist)
4114 (ispell-checking-message t)) 4177 (ispell-checking-message t))
diff --git a/lisp/window.el b/lisp/window.el
index 54ac8115727..c57fef441f5 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -7870,6 +7870,152 @@ Return non-nil if the window was shrunk, nil otherwise."
7870 (remove-hook 'kill-buffer-hook delete-window-hook t)))))) 7870 (remove-hook 'kill-buffer-hook delete-window-hook t))))))
7871 7871
7872 7872
7873;;;
7874;; Groups of windows (Follow Mode).
7875;;
7876;; This section of functions extends the functionality of some window
7877;; manipulating commands to groups of windows co-operatively
7878;; displaying a buffer, typically with Follow Mode.
7879;;
7880;; The xxx-function variables are permanent locals so that their local
7881;; status is undone only when explicitly programmed, not when a buffer
7882;; is reverted or a mode function is called.
7883
7884(defvar window-group-start-function nil)
7885(make-variable-buffer-local 'window-group-start-function)
7886(put 'window-group-start-function 'permanent-local t)
7887(defun window-group-start (&optional window)
7888 "Return position at which display currently starts in the group of
7889windows containing WINDOW. When a grouping mode (such as Follow Mode)
7890is not active, this function is identical to `window-start'.
7891
7892WINDOW must be a live window and defaults to the selected one.
7893This is updated by redisplay or by calling `set-window*-start'."
7894 (if (functionp window-group-start-function)
7895 (funcall window-group-start-function window)
7896 (window-start window)))
7897
7898(defvar window-group-end-function nil)
7899(make-variable-buffer-local 'window-group-end-function)
7900(put 'window-group-end-function 'permanent-local t)
7901(defun window-group-end (&optional window update)
7902 "Return position at which display currently ends in the group of
7903windows containing WINDOW. When a grouping mode (such as Follow Mode)
7904is not active, this function is identical to `window-end'.
7905
7906WINDOW must be a live window and defaults to the selected one.
7907This is updated by redisplay, when it runs to completion.
7908Simply changing the buffer text or setting `window-group-start'
7909does not update this value.
7910Return nil if there is no recorded value. (This can happen if the
7911last redisplay of WINDOW was preempted, and did not finish.)
7912If UPDATE is non-nil, compute the up-to-date position
7913if it isn't already recorded."
7914 (if (functionp window-group-end-function)
7915 (funcall window-group-end-function window update)
7916 (window-end window update)))
7917
7918(defvar set-window-group-start-function nil)
7919(make-variable-buffer-local 'set-window-group-start-function)
7920(put 'set-window-group-start-function 'permanent-local t)
7921(defun set-window-group-start (window pos &optional noforce)
7922 "Make display in the group of windows containing WINDOW start at
7923position POS in WINDOW's buffer. When a grouping mode (such as Follow
7924Mode) is not active, this function is identical to `set-window-start'.
7925
7926WINDOW must be a live window and defaults to the selected one. Return
7927POS. Optional third arg NOFORCE non-nil inhibits next redisplay from
7928overriding motion of point in order to display at this exact start."
7929 (if (functionp set-window-group-start-function)
7930 (funcall set-window-group-start-function window pos noforce)
7931 (set-window-start window pos noforce)))
7932
7933(defvar recenter-window-group-function nil)
7934(make-variable-buffer-local 'recenter-window-group-function)
7935(put 'recenter-window-group-function 'permanent-local t)
7936(defun recenter-window-group (&optional arg)
7937 "Center point in the group of windows containing the selected window
7938and maybe redisplay frame. When a grouping mode (such as Follow Mode)
7939is not active, this function is identical to `recenter'.
7940
7941With a numeric prefix argument ARG, recenter putting point on screen line ARG
7942relative to the first window in the selected window group. If ARG is
7943negative, it counts up from the bottom of the last window in the
7944group. (ARG should be less than the total height of the window group.)
7945
7946If ARG is omitted or nil, then recenter with point on the middle line of
7947the selected window group; if the variable `recenter-redisplay' is
7948non-nil, also erase the entire frame and redraw it (when
7949`auto-resize-tool-bars' is set to `grow-only', this resets the
7950tool-bar's height to the minimum height needed); if
7951`recenter-redisplay' has the special value `tty', then only tty frames
7952are redrawn.
7953
7954Just C-u as prefix means put point in the center of the window
7955and redisplay normally--don't erase and redraw the frame."
7956 (if (functionp recenter-window-group-function)
7957 (funcall recenter-window-group-function arg)
7958 (recenter arg)))
7959
7960(defvar pos-visible-in-window-group-p-function nil)
7961(make-variable-buffer-local 'pos-visible-in-window-group-p-function)
7962(put 'pos-visible-in-window-group-p-function 'permanent-local t)
7963(defun pos-visible-in-window-group-p (&optional pos window partially)
7964 "Return non-nil if position POS is currently on the frame in the
7965window group containing WINDOW. When a grouping mode (such as Follow
7966Mode) is not active, this function is identical to
7967`pos-visible-in-window-p'.
7968
7969WINDOW must be a live window and defaults to the selected one.
7970
7971Return nil if that position is scrolled vertically out of view. If a
7972character is only partially visible, nil is returned, unless the
7973optional argument PARTIALLY is non-nil. If POS is only out of view
7974because of horizontal scrolling, return non-nil. If POS is t, it
7975specifies the position of the last visible glyph in the window group.
7976POS defaults to point in WINDOW; WINDOW defaults to the selected
7977window.
7978
7979If POS is visible, return t if PARTIALLY is nil; if PARTIALLY is non-nil,
7980the return value is a list of 2 or 6 elements (X Y [RTOP RBOT ROWH VPOS]),
7981where X and Y are the pixel coordinates relative to the top left corner
7982of the window. The remaining elements are omitted if the character after
7983POS is fully visible; otherwise, RTOP and RBOT are the number of pixels
7984off-window at the top and bottom of the screen line (\"row\") containing
7985POS, ROWH is the visible height of that row, and VPOS is the row number
7986\(zero-based)."
7987 (if (functionp pos-visible-in-window-group-p-function)
7988 (funcall pos-visible-in-window-group-p-function pos window partially)
7989 (pos-visible-in-window-p pos window partially)))
7990
7991(defvar selected-window-group-function nil)
7992(make-variable-buffer-local 'selected-window-group-function)
7993(put 'selected-window-group-function 'permanent-local t)
7994(defun selected-window-group ()
7995 "Return the list of windows in the group containing the selected window.
7996When a grouping mode (such as Follow Mode) is not active, the
7997result is a list containing only the selected window."
7998 (if (functionp selected-window-group-function)
7999 (funcall selected-window-group-function)
8000 (list (selected-window))))
8001
8002(defvar move-to-window-group-line-function nil)
8003(make-variable-buffer-local 'move-to-window-group-line-function)
8004(put 'move-to-window-group-line-function 'permanent-local t)
8005(defun move-to-window-group-line (arg)
8006 "Position point relative to the the current group of windows.
8007When a grouping mode (such as Follow Mode) is not active, this
8008function is identical to `move-to-window-line'.
8009
8010ARG nil means position point at center of the window group.
8011Else, ARG specifies the vertical position within the window
8012group; zero means top of first window in the group, negative
8013means relative to the bottom of the last window in the group."
8014 (if (functionp move-to-window-group-line-function)
8015 (funcall move-to-window-group-line-function arg)
8016 (move-to-window-line arg)))
8017
8018
7873(defvar recenter-last-op nil 8019(defvar recenter-last-op nil
7874 "Indicates the last recenter operation performed. 8020 "Indicates the last recenter operation performed.
7875Possible values: `top', `middle', `bottom', integer or float numbers. 8021Possible values: `top', `middle', `bottom', integer or float numbers.