diff options
| author | Alan Mackenzie | 2015-11-11 12:02:48 +0000 |
|---|---|---|
| committer | Alan Mackenzie | 2015-11-11 12:02:48 +0000 |
| commit | 2c56fc2a3f106a1286ad793eed9bfaafd09a7411 (patch) | |
| tree | 6082e9df4733fb39a9d1423568a703c93f7ead62 | |
| parent | 25775a12c5168b0494dff15639ac25d8e1017530 (diff) | |
| download | emacs-2c56fc2a3f106a1286ad793eed9bfaafd09a7411.tar.gz emacs-2c56fc2a3f106a1286ad793eed9bfaafd09a7411.zip | |
First commit to scratch/follow. Make Isearch work with Follow Mode, etc.
doc/lispref/window.texi (Basic Windows): Add paragraph defining "Group of
Windows" and new @defun selected-window-group.
(Window Start and End): Describe new &optional parameter GROUP and
...-group-function for window-start, window-end, set-window-start, and
pos-visible-in-window-p.
(Textual Scrolling) Describe the same for recenter.
doc/lispref/positions.texi (Screen Lines): Describe the same for
move-to-window-line.
src/window.c (Fwindow_start, Fwindow_end, Fset_window_start)
(Fpos_visible_in_window_p, Frecenter, Fmove_to_window_line): To each, add ar
new optional parameter "group". At the beginning of each, check whether the
corresponding ...-group-function is set to a function, and if so execute this
function in place of the normal processing.
(syms_of_window): Define symbols for the six new variables below.
(window-start-group-function, window-end-group-function)
(set-window-start-group-function, recenter-group-function)
(pos-visible-in-window-p-group-function, move-to-window-line-group-function):
New permanent local buffer local variables.
src/keyboard.c (Fposn_at_point): Add extra parameter in call to
Fpos_visible_in_window_p.
lisp/window.el (selected-window-group-function): New permanent local buffer
local variable.
(selected-window-group): New function.
lisp/follow.el (follow-mode): Set the ...-group-function variables at mode
enable, kill them at mode disable. Add/remove follow-after-change to/from
after-change-functions.
(follow-start-end-invalid): New variable.
(follow-redisplay): Manipulate follow-start-end-invalid.
(follow-after-change, follow-window-start, follow-window-end)
(follow-set-window-start, follow-pos-visible-in-window-p)
(follow-move-to-window-line, follow-sit-for): New functions.
lisp/isearch.el (isearch-call-message): New macro.
(isearch-update, with-isearch-suspended, isearch-del-char)
(isearch-search-and-update, isearch-ring-adjust): Invoke above new macro.
(with-isearch-suspended): Rearrange code such that isearch-call-message is
invoked before point is moved.
(isearch-message): Add comment about where point must be at function call.
(isearch-search): Remove call to isearch-message.
(isearch-lazy-highlight-window-group): New variable.
(isearch-lazy-highlight-new-loop): Unconditionally start idle timer. Move
the battery of tests to ...
(isearch-lazy-highlight-maybe-new-loop): New function, started by idle timer.
Note: (sit-for 0) is still called.
(isearch-lazy-highlight-update): Check membership of
isearch-lazy-highlight-window-group. Don't set the `window' overlay
property.
(isearch-update, isearch-done, isearch-string-out-of-window)
(isearch-back-into-window, isearch-lazy-highlight-maybe-new-loop)
(isearch-lazy-highlight-search, isearch-lazy-highlight-update)
(isearch-lazy-highlight-update): Call the six amended primitives (see
src/window.c above) with the new `group' argument set to t, to cooperate
with Follow Mode.
| -rw-r--r-- | doc/lispref/positions.texi | 13 | ||||
| -rw-r--r-- | doc/lispref/windows.texi | 87 | ||||
| -rw-r--r-- | lisp/follow.el | 193 | ||||
| -rw-r--r-- | lisp/isearch.el | 133 | ||||
| -rw-r--r-- | lisp/window.el | 11 | ||||
| -rw-r--r-- | src/keyboard.c | 2 | ||||
| -rw-r--r-- | src/window.c | 772 |
7 files changed, 838 insertions, 373 deletions
diff --git a/doc/lispref/positions.texi b/doc/lispref/positions.texi index 72b76ce5c8f..e0496e30848 100644 --- a/doc/lispref/positions.texi +++ b/doc/lispref/positions.texi | |||
| @@ -551,7 +551,8 @@ current buffer, regardless of which buffer is displayed in | |||
| 551 | any buffer, whether or not it is currently displayed in some window. | 551 | any buffer, whether or not it is currently displayed in some window. |
| 552 | @end defun | 552 | @end defun |
| 553 | 553 | ||
| 554 | @deffn Command move-to-window-line count | 554 | @deffn Command move-to-window-line count group |
| 555 | @vindex move-to-window-line-group-function | ||
| 555 | This function moves point with respect to the text currently displayed | 556 | This function moves point with respect to the text currently displayed |
| 556 | in the selected window. It moves point to the beginning of the screen | 557 | in the selected window. It moves point to the beginning of the screen |
| 557 | line @var{count} screen lines from the top of the window. If | 558 | line @var{count} screen lines from the top of the window. If |
| @@ -570,6 +571,16 @@ In an interactive call, @var{count} is the numeric prefix argument. | |||
| 570 | 571 | ||
| 571 | The value returned is the window line number point has moved to, with | 572 | The value returned is the window line number point has moved to, with |
| 572 | the top line in the window numbered 0. | 573 | the top line in the window numbered 0. |
| 574 | |||
| 575 | If @var{group} is non-@code{nil}, and the selected window is a part of | ||
| 576 | a group of windows (@pxref{Basic Windows}), @code{move-to-window-line} | ||
| 577 | will move to a position with respect to the entire group, not just the | ||
| 578 | single window. This condition holds when the buffer local variable | ||
| 579 | @code{move-to-window-line-group-function} is set to a function. In | ||
| 580 | this case, @code{move-to-window-line} calls the function with the | ||
| 581 | argument @var{count}, then returns its result, instead of performing | ||
| 582 | the actions described above. Typically, the function will call | ||
| 583 | @code{move-to-window-line} recursively. | ||
| 573 | @end deffn | 584 | @end deffn |
| 574 | 585 | ||
| 575 | @defun compute-motion from frompos to topos width offsets window | 586 | @defun compute-motion from frompos to topos width offsets window |
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index 357247ef433..832ced719cd 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 | |||
| 133 | window). | 133 | window). |
| 134 | @end defun | 134 | @end defun |
| 135 | 135 | ||
| 136 | Sometimes several windows collectively and cooperatively display a | ||
| 137 | buffer, for example, under the management of Follow Mode, where the | ||
| 138 | windows together display a bigger portion of the buffer than one | ||
| 139 | window could alone. It is often useful to consider such a @dfn{group | ||
| 140 | of windows} as a single entity. Several functions such as | ||
| 141 | @code{window-start} (@pxref{Window Start and End}) allow you to do | ||
| 142 | this by supplying, as an argument, one of the windows as a stand in | ||
| 143 | for the whole group. | ||
| 144 | |||
| 145 | @defun selected-window-group | ||
| 146 | @vindex selected-window-group-function | ||
| 147 | When the selected window is a member of a group of windows, this | ||
| 148 | function returns a list of the windows in the group, ordered such that | ||
| 149 | the first window in the list is displaying the earliest part of the | ||
| 150 | buffer, and so on. Otherwise the function returns a list containing | ||
| 151 | just the selected window. | ||
| 152 | |||
| 153 | The selected window is considered part of a group when the buffer | ||
| 154 | local variable @code{selected-window-group-function} is set to a | ||
| 155 | function. In this case, @code{selected-window-group} calls it with no | ||
| 156 | arguments and returns its result (which should be the list of windows | ||
| 157 | in 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 | ||
| @@ -3064,7 +3088,8 @@ using the commands of Lisp mode, because they trigger this | |||
| 3064 | readjustment. To test such code, put it into a command and bind the | 3088 | readjustment. To test such code, put it into a command and bind the |
| 3065 | command to a key. | 3089 | command to a key. |
| 3066 | 3090 | ||
| 3067 | @defun window-start &optional window | 3091 | @defun window-start &optional window group |
| 3092 | @vindex window-start-group-function | ||
| 3068 | @cindex window top line | 3093 | @cindex window top line |
| 3069 | This function returns the display-start position of window | 3094 | This function returns the display-start position of window |
| 3070 | @var{window}. If @var{window} is @code{nil}, the selected window is | 3095 | @var{window}. If @var{window} is @code{nil}, the selected window is |
| @@ -3080,10 +3105,20 @@ it explicitly since the previous redisplay)---to make sure point appears | |||
| 3080 | on the screen. Nothing except redisplay automatically changes the | 3105 | on the screen. Nothing except redisplay automatically changes the |
| 3081 | window-start position; if you move point, do not expect the window-start | 3106 | window-start position; if you move point, do not expect the window-start |
| 3082 | position to change in response until after the next redisplay. | 3107 | position to change in response until after the next redisplay. |
| 3108 | |||
| 3109 | If @var{group} is non-@code{nil}, and @var{window} is a part of a | ||
| 3110 | group of windows (@pxref{Basic Windows}), @code{window-start} returns | ||
| 3111 | the start position of the entire group. This condition holds when the | ||
| 3112 | buffer local variable @code{window-start-group-function} is set to a | ||
| 3113 | function. In this case, @code{window-start} calls the function with | ||
| 3114 | the single argument @var{window}, then returns its result, instead of | ||
| 3115 | performing the actions described above. Typically, the function will | ||
| 3116 | call @code{window-start} recursively. | ||
| 3083 | @end defun | 3117 | @end defun |
| 3084 | 3118 | ||
| 3119 | @vindex window-end-group-function | ||
| 3085 | @cindex window end position | 3120 | @cindex window end position |
| 3086 | @defun window-end &optional window update | 3121 | @defun window-end &optional window update group |
| 3087 | This function returns the position where display of its buffer ends in | 3122 | This function returns the position where display of its buffer ends in |
| 3088 | @var{window}. The default for @var{window} is the selected window. | 3123 | @var{window}. The default for @var{window} is the selected window. |
| 3089 | 3124 | ||
| @@ -3106,9 +3141,19 @@ attempt to scroll the display if point has moved off the screen, the | |||
| 3106 | way real redisplay would do. It does not alter the | 3141 | way real redisplay would do. It does not alter the |
| 3107 | @code{window-start} value. In effect, it reports where the displayed | 3142 | @code{window-start} value. In effect, it reports where the displayed |
| 3108 | text will end if scrolling is not required. | 3143 | text will end if scrolling is not required. |
| 3144 | |||
| 3145 | If @var{group} is non-@code{nil}, and @var{window} is a part of a | ||
| 3146 | group of windows (@pxref{Basic Windows}), `window-end' returns the end | ||
| 3147 | position of the entire group. This condition holds when the buffer | ||
| 3148 | local variable @code{window-end-group-function} is set to a function. | ||
| 3149 | In this case, @code{window-end} calls the function with the two | ||
| 3150 | arguments @var{window} and @var{update}, then returns its result, | ||
| 3151 | instead of performing the actions described above. Typically, the | ||
| 3152 | function will call @code{window-end} recursively. | ||
| 3109 | @end defun | 3153 | @end defun |
| 3110 | 3154 | ||
| 3111 | @defun set-window-start window position &optional noforce | 3155 | @vindex set-window-start-group-function |
| 3156 | @defun set-window-start window position &optional noforce group | ||
| 3112 | This function sets the display-start position of @var{window} to | 3157 | This function sets the display-start position of @var{window} to |
| 3113 | @var{position} in @var{window}'s buffer. It returns @var{position}. | 3158 | @var{position} in @var{window}'s buffer. It returns @var{position}. |
| 3114 | 3159 | ||
| @@ -3169,9 +3214,20 @@ it is still 1 when redisplay occurs. Here is an example: | |||
| 3169 | If @var{noforce} is non-@code{nil}, and @var{position} would place point | 3214 | If @var{noforce} is non-@code{nil}, and @var{position} would place point |
| 3170 | off screen at the next redisplay, then redisplay computes a new window-start | 3215 | off screen at the next redisplay, then redisplay computes a new window-start |
| 3171 | position that works well with point, and thus @var{position} is not used. | 3216 | position that works well with point, and thus @var{position} is not used. |
| 3217 | |||
| 3218 | If @var{group} is non-@code{nil}, and @var{window} is a part of a | ||
| 3219 | group of windows (@pxref{Basic Windows}), @code{set-window-start} sets | ||
| 3220 | the start position of the entire group. This condition holds when the | ||
| 3221 | buffer local variable @code{set-window-start-group-function} is set to | ||
| 3222 | a function. In this case, @code{set-window-start} calls the function | ||
| 3223 | with the three arguments @var{window}, @var{position}, and | ||
| 3224 | @var{noforce}, then returns its result, instead of performing the | ||
| 3225 | actions described above. Typically, the function will call | ||
| 3226 | @code{set-window-start} recursively. | ||
| 3172 | @end defun | 3227 | @end defun |
| 3173 | 3228 | ||
| 3174 | @defun pos-visible-in-window-p &optional position window partially | 3229 | @defun pos-visible-in-window-p &optional position window partially group |
| 3230 | @vindex pos-visible-in-window-p-group-function | ||
| 3175 | This function returns non-@code{nil} if @var{position} is within the | 3231 | This function returns non-@code{nil} if @var{position} is within the |
| 3176 | range of text currently visible on the screen in @var{window}. It | 3232 | range of text currently visible on the screen in @var{window}. It |
| 3177 | returns @code{nil} if @var{position} is scrolled vertically out of | 3233 | returns @code{nil} if @var{position} is scrolled vertically out of |
| @@ -3210,6 +3266,18 @@ Here is an example: | |||
| 3210 | (recenter 0)) | 3266 | (recenter 0)) |
| 3211 | @end group | 3267 | @end group |
| 3212 | @end example | 3268 | @end example |
| 3269 | |||
| 3270 | If @var{group} is non-@code{nil}, and @var{window} is a part of a | ||
| 3271 | group of windows (@pxref{Basic Windows}), | ||
| 3272 | @code{pos-visible-in-window-p} tests the visibility of @var{pos} in | ||
| 3273 | the entire group, not just in the single @var{window}. This condition | ||
| 3274 | holds when the buffer local variable | ||
| 3275 | @code{pos-visible-in-window-p-group-function} is set to a function. | ||
| 3276 | In this case @code{pos-visible-in-window-p} calls the function with | ||
| 3277 | the three arguments @var{position}, @var{window}, and @var{partially}, | ||
| 3278 | then returns its result, instead of performing the actions described | ||
| 3279 | above. Typically, the function will call | ||
| 3280 | @code{pos-visible-in-window-p} recursively. | ||
| 3213 | @end defun | 3281 | @end defun |
| 3214 | 3282 | ||
| 3215 | @defun window-line-height &optional line window | 3283 | @defun window-line-height &optional line window |
| @@ -3427,7 +3495,8 @@ beginning or end of the buffer (depending on scrolling direction); | |||
| 3427 | only if point is already on that position do they signal an error. | 3495 | only if point is already on that position do they signal an error. |
| 3428 | @end defopt | 3496 | @end defopt |
| 3429 | 3497 | ||
| 3430 | @deffn Command recenter &optional count | 3498 | @deffn Command recenter &optional count group |
| 3499 | @vindex recenter-group-function | ||
| 3431 | @cindex centering point | 3500 | @cindex centering point |
| 3432 | This function scrolls the text in the selected window so that point is | 3501 | This function scrolls the text in the selected window so that point is |
| 3433 | displayed at a specified vertical position within the window. It does | 3502 | displayed at a specified vertical position within the window. It does |
| @@ -3444,6 +3513,14 @@ If @var{count} is @code{nil} (or a non-@code{nil} list), | |||
| 3444 | window. If @var{count} is @code{nil}, this function may redraw the | 3513 | window. If @var{count} is @code{nil}, this function may redraw the |
| 3445 | frame, according to the value of @code{recenter-redisplay}. | 3514 | frame, according to the value of @code{recenter-redisplay}. |
| 3446 | 3515 | ||
| 3516 | If @var{group} is non-@code{nil}, and the selected window is part of a | ||
| 3517 | group of windows (@pxref{Basic Windows}), @code{recenter} scrolls the | ||
| 3518 | entire group. This condition holds when the buffer local variable | ||
| 3519 | @code{recenter-group-function} is set to a function. In this case, | ||
| 3520 | @code{recenter} calls the function with the argument @var{count}, then | ||
| 3521 | returns its result, instead of performing the actions described above. | ||
| 3522 | Typically, the function will call @code{recenter} recursively. | ||
| 3523 | |||
| 3447 | When @code{recenter} is called interactively, @var{count} is the raw | 3524 | When @code{recenter} is called interactively, @var{count} is the raw |
| 3448 | prefix argument. Thus, typing @kbd{C-u} as the prefix sets the | 3525 | prefix argument. Thus, typing @kbd{C-u} as the prefix sets the |
| 3449 | @var{count} to a non-@code{nil} list, while typing @kbd{C-u 4} sets | 3526 | @var{count} to a non-@code{nil} list, while typing @kbd{C-u 4} sets |
diff --git a/lisp/follow.el b/lisp/follow.el index 938c59e8506..f2427374f24 100644 --- a/lisp/follow.el +++ b/lisp/follow.el | |||
| @@ -421,7 +421,19 @@ 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 | |||
| 427 | (setq window-start-group-function 'follow-window-start) | ||
| 428 | (setq window-end-group-function 'follow-window-end) | ||
| 429 | (setq set-window-start-group-function 'follow-set-window-start) | ||
| 430 | (setq recenter-group-function 'follow-recenter) | ||
| 431 | (setq pos-visible-in-window-p-group-function | ||
| 432 | 'follow-pos-visible-in-window-p) | ||
| 433 | (setq selected-window-group-function 'follow-all-followers) | ||
| 434 | (setq move-to-window-line-group-function 'follow-move-to-window-line) | ||
| 435 | (setq sit*-for-function 'follow-sit-for)) | ||
| 436 | |||
| 425 | ;; Remove globally-installed hook functions only if there is no | 437 | ;; Remove globally-installed hook functions only if there is no |
| 426 | ;; other Follow mode buffer. | 438 | ;; other Follow mode buffer. |
| 427 | (let ((buffers (buffer-list)) | 439 | (let ((buffers (buffer-list)) |
| @@ -432,6 +444,17 @@ Keys specific to Follow mode: | |||
| 432 | (unless following | 444 | (unless following |
| 433 | (remove-hook 'post-command-hook 'follow-post-command-hook) | 445 | (remove-hook 'post-command-hook 'follow-post-command-hook) |
| 434 | (remove-hook 'window-size-change-functions 'follow-window-size-change))) | 446 | (remove-hook 'window-size-change-functions 'follow-window-size-change))) |
| 447 | |||
| 448 | (kill-local-variable 'sit*-for-function) | ||
| 449 | (kill-local-variable 'move-to-window-line-group-function) | ||
| 450 | (kill-local-variable 'selected-window-group-function) | ||
| 451 | (kill-local-variable 'pos-visible-in-window-p-group-function) | ||
| 452 | (kill-local-variable 'recenter-group-function) | ||
| 453 | (kill-local-variable 'set-window-start-group-function) | ||
| 454 | (kill-local-variable 'window-end-group-function) | ||
| 455 | (kill-local-variable 'window-start-group-function) | ||
| 456 | |||
| 457 | (remove-hook 'after-change-functions 'follow-after-change t) | ||
| 435 | (remove-hook 'compilation-filter-hook 'follow-align-compilation-windows t))) | 458 | (remove-hook 'compilation-filter-hook 'follow-align-compilation-windows t))) |
| 436 | 459 | ||
| 437 | (defun follow-find-file-hook () | 460 | (defun follow-find-file-hook () |
| @@ -1015,6 +1038,10 @@ Otherwise, return nil." | |||
| 1015 | ;; is nil. Start every window directly after the end of the previous | 1038 | ;; is nil. Start every window directly after the end of the previous |
| 1016 | ;; window, to make sure long lines are displayed correctly. | 1039 | ;; window, to make sure long lines are displayed correctly. |
| 1017 | 1040 | ||
| 1041 | (defvar follow-start-end-invalid t | ||
| 1042 | "When non-nil, indicates `follow-windows-start-end-cache' is invalid.") | ||
| 1043 | (make-variable-buffer-local 'follow-start-end-invalid) | ||
| 1044 | |||
| 1018 | (defun follow-redisplay (&optional windows win preserve-win) | 1045 | (defun follow-redisplay (&optional windows win preserve-win) |
| 1019 | "Reposition the WINDOWS around WIN. | 1046 | "Reposition the WINDOWS around WIN. |
| 1020 | Should point be too close to the roof we redisplay everything | 1047 | Should point be too close to the roof we redisplay everything |
| @@ -1047,7 +1074,8 @@ repositioning the other windows." | |||
| 1047 | (dolist (w windows) | 1074 | (dolist (w windows) |
| 1048 | (unless (and preserve-win (eq w win)) | 1075 | (unless (and preserve-win (eq w win)) |
| 1049 | (set-window-start w start)) | 1076 | (set-window-start w start)) |
| 1050 | (setq start (car (follow-calc-win-end w)))))) | 1077 | (setq start (car (follow-calc-win-end w)))) |
| 1078 | (setq follow-start-end-invalid nil))) | ||
| 1051 | 1079 | ||
| 1052 | (defun follow-estimate-first-window-start (windows win start) | 1080 | (defun follow-estimate-first-window-start (windows win start) |
| 1053 | "Estimate the position of the first window. | 1081 | "Estimate the position of the first window. |
| @@ -1446,6 +1474,167 @@ non-first windows in Follow mode." | |||
| 1446 | 1474 | ||
| 1447 | (add-hook 'window-scroll-functions 'follow-avoid-tail-recenter t) | 1475 | (add-hook 'window-scroll-functions 'follow-avoid-tail-recenter t) |
| 1448 | 1476 | ||
| 1477 | ;;; Low level window start and end. | ||
| 1478 | |||
| 1479 | ;; These routines are the Follow Mode versions of the low level | ||
| 1480 | ;; functions described on page "Window Start and End" of the elisp | ||
| 1481 | ;; manual, e.g. `window*-start'. The aim is to be able to handle | ||
| 1482 | ;; Follow Mode windows by replacing `window-start' by `window*-start', | ||
| 1483 | ;; etc. | ||
| 1484 | |||
| 1485 | (defun follow-after-change (_beg _end _old-len) | ||
| 1486 | "After change function: set `follow-start-end-invalid'." | ||
| 1487 | (setq follow-start-end-invalid t)) | ||
| 1488 | |||
| 1489 | (defun follow-window-start (&optional window) | ||
| 1490 | "Return position at which display currently starts in the | ||
| 1491 | Follow Mode group of windows which includes WINDOW. | ||
| 1492 | |||
| 1493 | WINDOW must be a live window and defaults to the selected one. | ||
| 1494 | This is updated by redisplay or by calling | ||
| 1495 | `follow-set-window-start'." | ||
| 1496 | (let ((windows (follow-all-followers window))) | ||
| 1497 | (window-start (car windows)))) | ||
| 1498 | |||
| 1499 | (defun follow-window-end (&optional window update) | ||
| 1500 | "Return position at which display currently ends in the Follow | ||
| 1501 | Mode group of windows which includes WINDOW. | ||
| 1502 | |||
| 1503 | WINDOW must be a live window and defaults to the selected one. | ||
| 1504 | This is updated by redisplay, when it runs to completion. | ||
| 1505 | Simply changing the buffer text or setting `window-start' does | ||
| 1506 | not update this value. | ||
| 1507 | |||
| 1508 | Return nil if there is no recorded value. (This can happen if | ||
| 1509 | the last redisplay of WINDOW was preempted, and did not | ||
| 1510 | finish.) If UPDATE is non-nil, compute the up-to-date position | ||
| 1511 | if it isn't already recorded." | ||
| 1512 | (let* ((windows (follow-all-followers window)) | ||
| 1513 | (last (car (last windows)))) | ||
| 1514 | (when (and update follow-start-end-invalid) | ||
| 1515 | (follow-redisplay windows (car windows))) | ||
| 1516 | (window-end last update))) | ||
| 1517 | |||
| 1518 | (defun follow-set-window-start (window pos &optional noforce) | ||
| 1519 | "Make display in the Follow Mode group of windows which includes | ||
| 1520 | WINDOW start at position POS in WINDOW's buffer. | ||
| 1521 | |||
| 1522 | WINDOW must be a live window and defaults to the selected one. Return | ||
| 1523 | POS. Optional third arg NOFORCE non-nil inhibits next redisplay from | ||
| 1524 | overriding motion of point in order to display at this exact start." | ||
| 1525 | (let ((windows (follow-all-followers window))) | ||
| 1526 | (setq follow-start-end-invalid t) | ||
| 1527 | (set-window-start (car windows) pos noforce))) | ||
| 1528 | |||
| 1529 | (defun follow-pos-visible-in-window-p (&optional pos window partially) | ||
| 1530 | "Return non-nil if position POS is currently on the frame in one of | ||
| 1531 | the windows in the Follow Mode group which includes WINDOW. | ||
| 1532 | |||
| 1533 | WINDOW must be a live window and defaults to the selected one. | ||
| 1534 | |||
| 1535 | Return nil if that position is scrolled vertically out of view. If a | ||
| 1536 | character is only partially visible, nil is returned, unless the | ||
| 1537 | optional argument PARTIALLY is non-nil. If POS is only out of view | ||
| 1538 | because of horizontal scrolling, return non-nil. If POS is t, it | ||
| 1539 | specifies the position of the last visible glyph in WINDOW. POS | ||
| 1540 | defaults to point in WINDOW; WINDOW defaults to the selected window. | ||
| 1541 | |||
| 1542 | If POS is visible, return t if PARTIALLY is nil; if PARTIALLY is non-nil, | ||
| 1543 | the return value is a list of 2 or 6 elements (X Y [RTOP RBOT ROWH VPOS]), | ||
| 1544 | where X and Y are the pixel coordinates relative to the top left corner | ||
| 1545 | of the actual window containing it. The remaining elements are | ||
| 1546 | omitted if the character after POS is fully visible; otherwise, RTOP | ||
| 1547 | and RBOT are the number of pixels off-window at the top and bottom of | ||
| 1548 | the screen line (\"row\") containing POS, ROWH is the visible height | ||
| 1549 | of that row, and VPOS is the row number \(zero-based)." | ||
| 1550 | (let* ((windows (follow-all-followers window)) | ||
| 1551 | (last (car (last windows)))) | ||
| 1552 | (when follow-start-end-invalid | ||
| 1553 | (follow-redisplay windows (car windows))) | ||
| 1554 | (let* ((cache (follow-windows-start-end windows)) | ||
| 1555 | (last-elt (car (last cache))) | ||
| 1556 | our-pos pertinent-elt) | ||
| 1557 | (setq pertinent-elt | ||
| 1558 | (if (eq pos t) | ||
| 1559 | last-elt | ||
| 1560 | (setq our-pos (or pos (point))) | ||
| 1561 | (catch 'element | ||
| 1562 | (while cache | ||
| 1563 | (when (< our-pos (nth 2 (car cache))) | ||
| 1564 | (throw 'element (car cache))) | ||
| 1565 | (setq cache (cdr cache))) | ||
| 1566 | last-elt))) | ||
| 1567 | (pos-visible-in-window-p our-pos (car pertinent-elt) partially)))) | ||
| 1568 | |||
| 1569 | (defun follow-move-to-window-line (arg) | ||
| 1570 | "Position point relative to the Follow mode group containing the selected window. | ||
| 1571 | ARG nil means position point at center of the window group. | ||
| 1572 | Else, ARG specifies vertical position within the window group; | ||
| 1573 | zero means top of the first window in the group, negative means | ||
| 1574 | relative to bottom of the last window in the group." | ||
| 1575 | (let* ((windows (follow-all-followers)) | ||
| 1576 | (start-end (follow-windows-start-end windows)) | ||
| 1577 | (rev-start-end (reverse start-end)) | ||
| 1578 | (lines 0) | ||
| 1579 | middle-window elt count) | ||
| 1580 | (select-window | ||
| 1581 | (cond | ||
| 1582 | ((null arg) | ||
| 1583 | (setq rev-start-end (nthcdr (/ (length windows) 2) rev-start-end)) | ||
| 1584 | (prog1 (car (car rev-start-end)) | ||
| 1585 | (while (setq rev-start-end (cdr rev-start-end)) | ||
| 1586 | (setq elt (car rev-start-end) | ||
| 1587 | count (count-screen-lines (cadr elt) (nth 2 elt) | ||
| 1588 | nil (car elt)) | ||
| 1589 | lines (+ lines count))))) | ||
| 1590 | ((>= arg 0) | ||
| 1591 | (while (and (cdr start-end) | ||
| 1592 | (progn | ||
| 1593 | (setq elt (car start-end) | ||
| 1594 | count (count-screen-lines (cadr elt) (nth 2 elt) | ||
| 1595 | nil (car elt))) | ||
| 1596 | (>= arg count))) | ||
| 1597 | (setq arg (- arg count) | ||
| 1598 | lines (+ lines count) | ||
| 1599 | start-end (cdr start-end))) | ||
| 1600 | (car (car start-end))) | ||
| 1601 | (t ; (< arg 0) | ||
| 1602 | (while (and (cadr rev-start-end) | ||
| 1603 | (progn | ||
| 1604 | (setq elt (car rev-start-end) | ||
| 1605 | count (count-lines (cadr elt) (nth 2 elt))) | ||
| 1606 | (<= arg (- count)))) | ||
| 1607 | (setq arg (+ arg count) | ||
| 1608 | rev-start-end (cdr rev-start-end))) | ||
| 1609 | (prog1 (car (car rev-start-end)) | ||
| 1610 | (while (setq rev-start-end (cdr rev-start-end)) | ||
| 1611 | (setq elt (car rev-start-end) | ||
| 1612 | count (count-screen-lines (cadr elt) (nth 2 elt) | ||
| 1613 | nil (car elt)) | ||
| 1614 | lines (+ lines count))))))) | ||
| 1615 | (+ lines (move-to-window-line arg)))) | ||
| 1616 | |||
| 1617 | (defun follow-sit-for (seconds &optional nodisp) | ||
| 1618 | "Redisplay, then wait for SECONDS seconds. Stop when input is available. | ||
| 1619 | Before redisplaying, synchronise all Follow windows. | ||
| 1620 | |||
| 1621 | SECONDS may be a floating-point value. | ||
| 1622 | \(On operating systems that do not support waiting for fractions of a | ||
| 1623 | second, floating-point values are rounded down to the nearest integer.) | ||
| 1624 | |||
| 1625 | Redisplay does not happen if input is available before it starts. | ||
| 1626 | If optional arg NODISP is t, don't synchronise or redisplay, just | ||
| 1627 | wait for input. | ||
| 1628 | |||
| 1629 | Value is t if waited the full time with no input arriving, and nil | ||
| 1630 | otherwise. | ||
| 1631 | |||
| 1632 | The functionality is intended to be the same as `sit-for''s." | ||
| 1633 | (when (and (not (input-pending-p t)) | ||
| 1634 | (not nodisp)) | ||
| 1635 | (follow-adjust-window (selected-window))) | ||
| 1636 | (sit-for seconds nodisp)) | ||
| 1637 | |||
| 1449 | ;;; Profile support | 1638 | ;;; Profile support |
| 1450 | 1639 | ||
| 1451 | ;; The following (non-evaluated) section can be used to | 1640 | ;; The following (non-evaluated) section can be used to |
diff --git a/lisp/isearch.el b/lisp/isearch.el index 9f8ba8d8d7b..92d7894d2e7 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el | |||
| @@ -171,6 +171,11 @@ is non-nil if the user quits the search.") | |||
| 171 | "Function to call to display the search prompt. | 171 | "Function to call to display the search prompt. |
| 172 | If nil, use function `isearch-message'.") | 172 | If nil, use function `isearch-message'.") |
| 173 | 173 | ||
| 174 | (defmacro isearch-call-message (&optional cqh ellip) | ||
| 175 | `(if isearch-message-function | ||
| 176 | (funcall isearch-message-function ,cqh ,ellip) | ||
| 177 | (isearch-message ,cqh ,ellip))) | ||
| 178 | |||
| 174 | (defvar isearch-wrap-function nil | 179 | (defvar isearch-wrap-function nil |
| 175 | "Function to call to wrap the search when search is failed. | 180 | "Function to call to wrap the search when search is failed. |
| 176 | If nil, move point to the beginning of the buffer for a forward search, | 181 | If nil, move point to the beginning of the buffer for a forward search, |
| @@ -969,12 +974,10 @@ The last thing it does is to run `isearch-update-post-hook'." | |||
| 969 | (null executing-kbd-macro)) | 974 | (null executing-kbd-macro)) |
| 970 | (progn | 975 | (progn |
| 971 | (if (not (input-pending-p)) | 976 | (if (not (input-pending-p)) |
| 972 | (if isearch-message-function | 977 | (isearch-call-message)) |
| 973 | (funcall isearch-message-function) | ||
| 974 | (isearch-message))) | ||
| 975 | (if (and isearch-slow-terminal-mode | 978 | (if (and isearch-slow-terminal-mode |
| 976 | (not (or isearch-small-window | 979 | (not (or isearch-small-window |
| 977 | (pos-visible-in-window-p)))) | 980 | (pos-visible-in-window-p nil nil nil t)))) |
| 978 | (let ((found-point (point))) | 981 | (let ((found-point (point))) |
| 979 | (setq isearch-small-window t) | 982 | (setq isearch-small-window t) |
| 980 | (move-to-window-line 0) | 983 | (move-to-window-line 0) |
| @@ -995,7 +998,7 @@ The last thing it does is to run `isearch-update-post-hook'." | |||
| 995 | (let ((current-scroll (window-hscroll)) | 998 | (let ((current-scroll (window-hscroll)) |
| 996 | visible-p) | 999 | visible-p) |
| 997 | (set-window-hscroll (selected-window) isearch-start-hscroll) | 1000 | (set-window-hscroll (selected-window) isearch-start-hscroll) |
| 998 | (setq visible-p (pos-visible-in-window-p nil nil t)) | 1001 | (setq visible-p (pos-visible-in-window-p nil nil t t)) |
| 999 | (if (or (not visible-p) | 1002 | (if (or (not visible-p) |
| 1000 | ;; When point is not visible because of hscroll, | 1003 | ;; When point is not visible because of hscroll, |
| 1001 | ;; pos-visible-in-window-p returns non-nil, but | 1004 | ;; pos-visible-in-window-p returns non-nil, but |
| @@ -1049,7 +1052,7 @@ NOPUSH is t and EDIT is t." | |||
| 1049 | (setq minibuffer-message-timeout isearch-original-minibuffer-message-timeout) | 1052 | (setq minibuffer-message-timeout isearch-original-minibuffer-message-timeout) |
| 1050 | (isearch-dehighlight) | 1053 | (isearch-dehighlight) |
| 1051 | (lazy-highlight-cleanup lazy-highlight-cleanup) | 1054 | (lazy-highlight-cleanup lazy-highlight-cleanup) |
| 1052 | (let ((found-start (window-start)) | 1055 | (let ((found-start (window-start nil t)) |
| 1053 | (found-point (point))) | 1056 | (found-point (point))) |
| 1054 | (when isearch-window-configuration | 1057 | (when isearch-window-configuration |
| 1055 | (set-window-configuration isearch-window-configuration) | 1058 | (set-window-configuration isearch-window-configuration) |
| @@ -1059,7 +1062,7 @@ NOPUSH is t and EDIT is t." | |||
| 1059 | ;; This has an annoying side effect of clearing the last_modiff | 1062 | ;; This has an annoying side effect of clearing the last_modiff |
| 1060 | ;; field of the window, which can cause unwanted scrolling, | 1063 | ;; field of the window, which can cause unwanted scrolling, |
| 1061 | ;; so don't do it unless truly necessary. | 1064 | ;; so don't do it unless truly necessary. |
| 1062 | (set-window-start (selected-window) found-start t)))) | 1065 | (set-window-start (selected-window) found-start t t)))) |
| 1063 | 1066 | ||
| 1064 | (setq isearch-mode nil) | 1067 | (setq isearch-mode nil) |
| 1065 | (if isearch-input-method-local-p | 1068 | (if isearch-input-method-local-p |
| @@ -1282,13 +1285,6 @@ You can update the global isearch variables by setting new values to | |||
| 1282 | (unwind-protect | 1285 | (unwind-protect |
| 1283 | (progn ,@body) | 1286 | (progn ,@body) |
| 1284 | 1287 | ||
| 1285 | ;; Set point at the start (end) of old match if forward (backward), | ||
| 1286 | ;; so after exiting minibuffer isearch resumes at the start (end) | ||
| 1287 | ;; of this match and can find it again. | ||
| 1288 | (if (and old-other-end (eq old-point (point)) | ||
| 1289 | (eq isearch-forward isearch-new-forward)) | ||
| 1290 | (goto-char old-other-end)) | ||
| 1291 | |||
| 1292 | ;; Always resume isearching by restarting it. | 1288 | ;; Always resume isearching by restarting it. |
| 1293 | (isearch-mode isearch-forward | 1289 | (isearch-mode isearch-forward |
| 1294 | isearch-regexp | 1290 | isearch-regexp |
| @@ -1301,7 +1297,17 @@ You can update the global isearch variables by setting new values to | |||
| 1301 | isearch-message isearch-new-message | 1297 | isearch-message isearch-new-message |
| 1302 | isearch-forward isearch-new-forward | 1298 | isearch-forward isearch-new-forward |
| 1303 | isearch-regexp-function isearch-new-regexp-function | 1299 | isearch-regexp-function isearch-new-regexp-function |
| 1304 | isearch-case-fold-search isearch-new-case-fold)) | 1300 | isearch-case-fold-search isearch-new-case-fold) |
| 1301 | |||
| 1302 | ;; Restore the minibuffer message before moving point. | ||
| 1303 | (isearch-call-message nil t) | ||
| 1304 | |||
| 1305 | ;; Set point at the start (end) of old match if forward (backward), | ||
| 1306 | ;; so after exiting minibuffer isearch resumes at the start (end) | ||
| 1307 | ;; of this match and can find it again. | ||
| 1308 | (if (and old-other-end (eq old-point (point)) | ||
| 1309 | (eq isearch-forward isearch-new-forward)) | ||
| 1310 | (goto-char old-other-end))) | ||
| 1305 | 1311 | ||
| 1306 | ;; Empty isearch-string means use default. | 1312 | ;; Empty isearch-string means use default. |
| 1307 | (when (= 0 (length isearch-string)) | 1313 | (when (= 0 (length isearch-string)) |
| @@ -1895,6 +1901,7 @@ If search string is empty, just beep." | |||
| 1895 | (length isearch-string)))) | 1901 | (length isearch-string)))) |
| 1896 | isearch-message (mapconcat 'isearch-text-char-description | 1902 | isearch-message (mapconcat 'isearch-text-char-description |
| 1897 | isearch-string ""))) | 1903 | isearch-string ""))) |
| 1904 | (isearch-call-message nil t) ; Do this before moving point. | ||
| 1898 | ;; Use the isearch-other-end as new starting point to be able | 1905 | ;; Use the isearch-other-end as new starting point to be able |
| 1899 | ;; to find the remaining part of the search string again. | 1906 | ;; to find the remaining part of the search string again. |
| 1900 | ;; This is like what `isearch-search-and-update' does, | 1907 | ;; This is like what `isearch-search-and-update' does, |
| @@ -2071,6 +2078,7 @@ With argument, add COUNT copies of the character." | |||
| 2071 | (setq isearch-case-fold-search | 2078 | (setq isearch-case-fold-search |
| 2072 | (isearch-no-upper-case-p isearch-string isearch-regexp)))) | 2079 | (isearch-no-upper-case-p isearch-string isearch-regexp)))) |
| 2073 | ;; Not regexp, not reverse, or no match at point. | 2080 | ;; Not regexp, not reverse, or no match at point. |
| 2081 | (isearch-call-message nil t) ; Do this before moving point. | ||
| 2074 | (if (and isearch-other-end (not isearch-adjusted)) | 2082 | (if (and isearch-other-end (not isearch-adjusted)) |
| 2075 | (goto-char (if isearch-forward isearch-other-end | 2083 | (goto-char (if isearch-forward isearch-other-end |
| 2076 | (min isearch-opoint | 2084 | (min isearch-opoint |
| @@ -2237,10 +2245,12 @@ Return nil if it's completely visible, or if point is visible, | |||
| 2237 | together with as much of the search string as will fit; the symbol | 2245 | together with as much of the search string as will fit; the symbol |
| 2238 | `above' if we need to scroll the text downwards; the symbol `below', | 2246 | `above' if we need to scroll the text downwards; the symbol `below', |
| 2239 | if upwards." | 2247 | if upwards." |
| 2240 | (let ((w-start (window-start)) | 2248 | (let ((w-start (window-start nil t)) |
| 2241 | (w-end (window-end nil t)) | 2249 | (w-end (window-end nil t t)) |
| 2242 | (w-L1 (save-excursion (move-to-window-line 1) (point))) | 2250 | (w-L1 (save-excursion |
| 2243 | (w-L-1 (save-excursion (move-to-window-line -1) (point))) | 2251 | (save-selected-window (move-to-window-line 1 t) (point)))) |
| 2252 | (w-L-1 (save-excursion | ||
| 2253 | (save-selected-window (move-to-window-line -1 t) (point)))) | ||
| 2244 | start end) ; start and end of search string in buffer | 2254 | start end) ; start and end of search string in buffer |
| 2245 | (if isearch-forward | 2255 | (if isearch-forward |
| 2246 | (setq end isearch-point start (or isearch-other-end isearch-point)) | 2256 | (setq end isearch-point start (or isearch-other-end isearch-point)) |
| @@ -2267,15 +2277,15 @@ the bottom." | |||
| 2267 | (if above | 2277 | (if above |
| 2268 | (progn | 2278 | (progn |
| 2269 | (goto-char start) | 2279 | (goto-char start) |
| 2270 | (recenter 0) | 2280 | (recenter 0 t) |
| 2271 | (when (>= isearch-point (window-end nil t)) | 2281 | (when (>= isearch-point (window-end nil t t)) |
| 2272 | (goto-char isearch-point) | 2282 | (goto-char isearch-point) |
| 2273 | (recenter -1))) | 2283 | (recenter -1 t))) |
| 2274 | (goto-char end) | 2284 | (goto-char end) |
| 2275 | (recenter -1) | 2285 | (recenter -1 t) |
| 2276 | (when (< isearch-point (window-start)) | 2286 | (when (< isearch-point (window-start nil t)) |
| 2277 | (goto-char isearch-point) | 2287 | (goto-char isearch-point) |
| 2278 | (recenter 0)))) | 2288 | (recenter 0 t)))) |
| 2279 | (goto-char isearch-point)) | 2289 | (goto-char isearch-point)) |
| 2280 | 2290 | ||
| 2281 | (defvar isearch-pre-scroll-point nil) | 2291 | (defvar isearch-pre-scroll-point nil) |
| @@ -2422,6 +2432,7 @@ Search is updated accordingly." | |||
| 2422 | (isearch-ring-adjust1 advance) | 2432 | (isearch-ring-adjust1 advance) |
| 2423 | (if search-ring-update | 2433 | (if search-ring-update |
| 2424 | (progn | 2434 | (progn |
| 2435 | (isearch-call-message nil t) | ||
| 2425 | (isearch-search) | 2436 | (isearch-search) |
| 2426 | (isearch-push-state) | 2437 | (isearch-push-state) |
| 2427 | (isearch-update)) | 2438 | (isearch-update)) |
| @@ -2494,6 +2505,13 @@ If there is no completion possible, say so and continue searching." | |||
| 2494 | 2505 | ||
| 2495 | (defun isearch-message (&optional c-q-hack ellipsis) | 2506 | (defun isearch-message (&optional c-q-hack ellipsis) |
| 2496 | ;; Generate and print the message string. | 2507 | ;; Generate and print the message string. |
| 2508 | |||
| 2509 | ;; N.B.: This function should always be called with point at the | ||
| 2510 | ;; search point, because in certain (rare) circumstances, undesired | ||
| 2511 | ;; scrolling can happen when point is elsewhere. These | ||
| 2512 | ;; circumstances are when follow-mode is active, the search string | ||
| 2513 | ;; spans two (or several) windows, and the message about to be | ||
| 2514 | ;; displayed will cause the echo area to expand. | ||
| 2497 | (let ((cursor-in-echo-area ellipsis) | 2515 | (let ((cursor-in-echo-area ellipsis) |
| 2498 | (m isearch-message) | 2516 | (m isearch-message) |
| 2499 | (fail-pos (isearch-fail-pos t))) | 2517 | (fail-pos (isearch-fail-pos t))) |
| @@ -2680,9 +2698,6 @@ update the match data, and return point." | |||
| 2680 | 2698 | ||
| 2681 | (defun isearch-search () | 2699 | (defun isearch-search () |
| 2682 | ;; Do the search with the current search string. | 2700 | ;; Do the search with the current search string. |
| 2683 | (if isearch-message-function | ||
| 2684 | (funcall isearch-message-function nil t) | ||
| 2685 | (isearch-message nil t)) | ||
| 2686 | (if (and (eq isearch-case-fold-search t) search-upper-case) | 2701 | (if (and (eq isearch-case-fold-search t) search-upper-case) |
| 2687 | (setq isearch-case-fold-search | 2702 | (setq isearch-case-fold-search |
| 2688 | (isearch-no-upper-case-p isearch-string isearch-regexp))) | 2703 | (isearch-no-upper-case-p isearch-string isearch-regexp))) |
| @@ -2980,6 +2995,7 @@ since they have special meaning in a regexp." | |||
| 2980 | (defvar isearch-lazy-highlight-timer nil) | 2995 | (defvar isearch-lazy-highlight-timer nil) |
| 2981 | (defvar isearch-lazy-highlight-last-string nil) | 2996 | (defvar isearch-lazy-highlight-last-string nil) |
| 2982 | (defvar isearch-lazy-highlight-window nil) | 2997 | (defvar isearch-lazy-highlight-window nil) |
| 2998 | (defvar isearch-lazy-highlight-window-group nil) | ||
| 2983 | (defvar isearch-lazy-highlight-window-start nil) | 2999 | (defvar isearch-lazy-highlight-window-start nil) |
| 2984 | (defvar isearch-lazy-highlight-window-end nil) | 3000 | (defvar isearch-lazy-highlight-window-end nil) |
| 2985 | (defvar isearch-lazy-highlight-case-fold-search nil) | 3001 | (defvar isearch-lazy-highlight-case-fold-search nil) |
| @@ -3012,7 +3028,21 @@ is nil. This function is called when exiting an incremental search if | |||
| 3012 | "22.1") | 3028 | "22.1") |
| 3013 | 3029 | ||
| 3014 | (defun isearch-lazy-highlight-new-loop (&optional beg end) | 3030 | (defun isearch-lazy-highlight-new-loop (&optional beg end) |
| 3015 | "Cleanup any previous `lazy-highlight' loop and begin a new one. | 3031 | "Set an idle timer, which will trigger a new `lazy-highlight' loop. |
| 3032 | BEG and END specify the bounds within which highlighting should | ||
| 3033 | occur. This is called when `isearch-update' is invoked (which | ||
| 3034 | can cause the search string to change or the window(s) to | ||
| 3035 | scroll). It is also used by other Emacs features. Do not start | ||
| 3036 | the loop when we are executing a keyboard macro." | ||
| 3037 | (setq isearch-lazy-highlight-start-limit beg | ||
| 3038 | isearch-lazy-highlight-end-limit end) | ||
| 3039 | (when (null executing-kbd-macro) | ||
| 3040 | (setq isearch-lazy-highlight-timer | ||
| 3041 | (run-with-idle-timer lazy-highlight-initial-delay nil | ||
| 3042 | 'isearch-lazy-highlight-maybe-new-loop)))) | ||
| 3043 | |||
| 3044 | (defun isearch-lazy-highlight-maybe-new-loop () | ||
| 3045 | "If needed cleanup any previous `lazy-highlight' loop and begin a new one. | ||
| 3016 | BEG and END specify the bounds within which highlighting should occur. | 3046 | BEG and END specify the bounds within which highlighting should occur. |
| 3017 | This is called when `isearch-update' is invoked (which can cause the | 3047 | This is called when `isearch-update' is invoked (which can cause the |
| 3018 | search string to change or the window to scroll). It is also used | 3048 | search string to change or the window to scroll). It is also used |
| @@ -3021,8 +3051,8 @@ by other Emacs features." | |||
| 3021 | (sit-for 0) ;make sure (window-start) is credible | 3051 | (sit-for 0) ;make sure (window-start) is credible |
| 3022 | (or (not (equal isearch-string | 3052 | (or (not (equal isearch-string |
| 3023 | isearch-lazy-highlight-last-string)) | 3053 | isearch-lazy-highlight-last-string)) |
| 3024 | (not (eq (selected-window) | 3054 | (not (memq (selected-window) |
| 3025 | isearch-lazy-highlight-window)) | 3055 | isearch-lazy-highlight-window-group)) |
| 3026 | (not (eq isearch-lazy-highlight-case-fold-search | 3056 | (not (eq isearch-lazy-highlight-case-fold-search |
| 3027 | isearch-case-fold-search)) | 3057 | isearch-case-fold-search)) |
| 3028 | (not (eq isearch-lazy-highlight-regexp | 3058 | (not (eq isearch-lazy-highlight-regexp |
| @@ -3033,9 +3063,9 @@ by other Emacs features." | |||
| 3033 | isearch-lax-whitespace)) | 3063 | isearch-lax-whitespace)) |
| 3034 | (not (eq isearch-lazy-highlight-regexp-lax-whitespace | 3064 | (not (eq isearch-lazy-highlight-regexp-lax-whitespace |
| 3035 | isearch-regexp-lax-whitespace)) | 3065 | isearch-regexp-lax-whitespace)) |
| 3036 | (not (= (window-start) | 3066 | (not (= (window-start nil t) |
| 3037 | isearch-lazy-highlight-window-start)) | 3067 | isearch-lazy-highlight-window-start)) |
| 3038 | (not (= (window-end) ; Window may have been split/joined. | 3068 | (not (= (window-end nil nil t) ; Window may have been split/joined. |
| 3039 | isearch-lazy-highlight-window-end)) | 3069 | isearch-lazy-highlight-window-end)) |
| 3040 | (not (eq isearch-forward | 3070 | (not (eq isearch-forward |
| 3041 | isearch-lazy-highlight-forward)) | 3071 | isearch-lazy-highlight-forward)) |
| @@ -3043,16 +3073,15 @@ by other Emacs features." | |||
| 3043 | (not (equal isearch-error | 3073 | (not (equal isearch-error |
| 3044 | isearch-lazy-highlight-error)))) | 3074 | isearch-lazy-highlight-error)))) |
| 3045 | ;; something important did indeed change | 3075 | ;; something important did indeed change |
| 3046 | (lazy-highlight-cleanup t) ;kill old loop & remove overlays | 3076 | (lazy-highlight-cleanup t) ;kill old loop & remove overlays |
| 3047 | (setq isearch-lazy-highlight-error isearch-error) | 3077 | (setq isearch-lazy-highlight-error isearch-error) |
| 3048 | ;; It used to check for `(not isearch-error)' here, but actually | 3078 | ;; It used to check for `(not isearch-error)' here, but actually |
| 3049 | ;; lazy-highlighting might find matches to highlight even when | 3079 | ;; lazy-highlighting might find matches to highlight even when |
| 3050 | ;; `isearch-error' is non-nil. (Bug#9918) | 3080 | ;; `isearch-error' is non-nil. (Bug#9918) |
| 3051 | (setq isearch-lazy-highlight-start-limit beg | ||
| 3052 | isearch-lazy-highlight-end-limit end) | ||
| 3053 | (setq isearch-lazy-highlight-window (selected-window) | 3081 | (setq isearch-lazy-highlight-window (selected-window) |
| 3054 | isearch-lazy-highlight-window-start (window-start) | 3082 | isearch-lazy-highlight-window-group (selected-window-group) |
| 3055 | isearch-lazy-highlight-window-end (window-end) | 3083 | isearch-lazy-highlight-window-start (window-start nil t) |
| 3084 | isearch-lazy-highlight-window-end (window-end nil nil t) | ||
| 3056 | ;; Start lazy-highlighting at the beginning of the found | 3085 | ;; Start lazy-highlighting at the beginning of the found |
| 3057 | ;; match (`isearch-other-end'). If no match, use point. | 3086 | ;; match (`isearch-other-end'). If no match, use point. |
| 3058 | ;; One of the next two variables (depending on search direction) | 3087 | ;; One of the next two variables (depending on search direction) |
| @@ -3070,10 +3099,8 @@ by other Emacs features." | |||
| 3070 | isearch-lazy-highlight-regexp-lax-whitespace isearch-regexp-lax-whitespace | 3099 | isearch-lazy-highlight-regexp-lax-whitespace isearch-regexp-lax-whitespace |
| 3071 | isearch-lazy-highlight-regexp-function isearch-regexp-function | 3100 | isearch-lazy-highlight-regexp-function isearch-regexp-function |
| 3072 | isearch-lazy-highlight-forward isearch-forward) | 3101 | isearch-lazy-highlight-forward isearch-forward) |
| 3073 | (unless (equal isearch-string "") | 3102 | (unless (equal isearch-string "") |
| 3074 | (setq isearch-lazy-highlight-timer | 3103 | (isearch-lazy-highlight-update)))) |
| 3075 | (run-with-idle-timer lazy-highlight-initial-delay nil | ||
| 3076 | 'isearch-lazy-highlight-update))))) | ||
| 3077 | 3104 | ||
| 3078 | (defun isearch-lazy-highlight-search () | 3105 | (defun isearch-lazy-highlight-search () |
| 3079 | "Search ahead for the next or previous match, for lazy highlighting. | 3106 | "Search ahead for the next or previous match, for lazy highlighting. |
| @@ -3096,13 +3123,13 @@ Attempt to do the search exactly the way the pending Isearch would." | |||
| 3096 | (+ isearch-lazy-highlight-start | 3123 | (+ isearch-lazy-highlight-start |
| 3097 | ;; Extend bound to match whole string at point | 3124 | ;; Extend bound to match whole string at point |
| 3098 | (1- (length isearch-lazy-highlight-last-string))) | 3125 | (1- (length isearch-lazy-highlight-last-string))) |
| 3099 | (window-end))) | 3126 | (window-end nil nil t))) |
| 3100 | (max (or isearch-lazy-highlight-start-limit (point-min)) | 3127 | (max (or isearch-lazy-highlight-start-limit (point-min)) |
| 3101 | (if isearch-lazy-highlight-wrapped | 3128 | (if isearch-lazy-highlight-wrapped |
| 3102 | (- isearch-lazy-highlight-end | 3129 | (- isearch-lazy-highlight-end |
| 3103 | ;; Extend bound to match whole string at point | 3130 | ;; Extend bound to match whole string at point |
| 3104 | (1- (length isearch-lazy-highlight-last-string))) | 3131 | (1- (length isearch-lazy-highlight-last-string))) |
| 3105 | (window-start)))))) | 3132 | (window-start nil t)))))) |
| 3106 | ;; Use a loop like in `isearch-search'. | 3133 | ;; Use a loop like in `isearch-search'. |
| 3107 | (while retry | 3134 | (while retry |
| 3108 | (setq success (isearch-search-string | 3135 | (setq success (isearch-search-string |
| @@ -3126,7 +3153,7 @@ Attempt to do the search exactly the way the pending Isearch would." | |||
| 3126 | (with-local-quit | 3153 | (with-local-quit |
| 3127 | (save-selected-window | 3154 | (save-selected-window |
| 3128 | (if (and (window-live-p isearch-lazy-highlight-window) | 3155 | (if (and (window-live-p isearch-lazy-highlight-window) |
| 3129 | (not (eq (selected-window) isearch-lazy-highlight-window))) | 3156 | (not (memq (selected-window) isearch-lazy-highlight-window-group))) |
| 3130 | (select-window isearch-lazy-highlight-window)) | 3157 | (select-window isearch-lazy-highlight-window)) |
| 3131 | (save-excursion | 3158 | (save-excursion |
| 3132 | (save-match-data | 3159 | (save-match-data |
| @@ -3146,12 +3173,12 @@ Attempt to do the search exactly the way the pending Isearch would." | |||
| 3146 | (if isearch-lazy-highlight-forward | 3173 | (if isearch-lazy-highlight-forward |
| 3147 | (if (= mb (if isearch-lazy-highlight-wrapped | 3174 | (if (= mb (if isearch-lazy-highlight-wrapped |
| 3148 | isearch-lazy-highlight-start | 3175 | isearch-lazy-highlight-start |
| 3149 | (window-end))) | 3176 | (window-end nil nil t))) |
| 3150 | (setq found nil) | 3177 | (setq found nil) |
| 3151 | (forward-char 1)) | 3178 | (forward-char 1)) |
| 3152 | (if (= mb (if isearch-lazy-highlight-wrapped | 3179 | (if (= mb (if isearch-lazy-highlight-wrapped |
| 3153 | isearch-lazy-highlight-end | 3180 | isearch-lazy-highlight-end |
| 3154 | (window-start))) | 3181 | (window-start nil t))) |
| 3155 | (setq found nil) | 3182 | (setq found nil) |
| 3156 | (forward-char -1))) | 3183 | (forward-char -1))) |
| 3157 | 3184 | ||
| @@ -3161,8 +3188,8 @@ Attempt to do the search exactly the way the pending Isearch would." | |||
| 3161 | ;; 1000 is higher than ediff's 100+, | 3188 | ;; 1000 is higher than ediff's 100+, |
| 3162 | ;; but lower than isearch main overlay's 1001 | 3189 | ;; but lower than isearch main overlay's 1001 |
| 3163 | (overlay-put ov 'priority 1000) | 3190 | (overlay-put ov 'priority 1000) |
| 3164 | (overlay-put ov 'face lazy-highlight-face) | 3191 | (overlay-put ov 'face lazy-highlight-face))) |
| 3165 | (overlay-put ov 'window (selected-window)))) | 3192 | ;(overlay-put ov 'window (selected-window)))) |
| 3166 | ;; Remember the current position of point for | 3193 | ;; Remember the current position of point for |
| 3167 | ;; the next call of `isearch-lazy-highlight-update' | 3194 | ;; the next call of `isearch-lazy-highlight-update' |
| 3168 | ;; when `lazy-highlight-max-at-a-time' is too small. | 3195 | ;; when `lazy-highlight-max-at-a-time' is too small. |
| @@ -3178,12 +3205,12 @@ Attempt to do the search exactly the way the pending Isearch would." | |||
| 3178 | (setq isearch-lazy-highlight-wrapped t) | 3205 | (setq isearch-lazy-highlight-wrapped t) |
| 3179 | (if isearch-lazy-highlight-forward | 3206 | (if isearch-lazy-highlight-forward |
| 3180 | (progn | 3207 | (progn |
| 3181 | (setq isearch-lazy-highlight-end (window-start)) | 3208 | (setq isearch-lazy-highlight-end (window-start nil t)) |
| 3182 | (goto-char (max (or isearch-lazy-highlight-start-limit (point-min)) | 3209 | (goto-char (max (or isearch-lazy-highlight-start-limit (point-min)) |
| 3183 | (window-start)))) | 3210 | (window-start nil t)))) |
| 3184 | (setq isearch-lazy-highlight-start (window-end)) | 3211 | (setq isearch-lazy-highlight-start (window-end nil nil t)) |
| 3185 | (goto-char (min (or isearch-lazy-highlight-end-limit (point-max)) | 3212 | (goto-char (min (or isearch-lazy-highlight-end-limit (point-max)) |
| 3186 | (window-end)))))))) | 3213 | (window-end nil nil t)))))))) |
| 3187 | (unless nomore | 3214 | (unless nomore |
| 3188 | (setq isearch-lazy-highlight-timer | 3215 | (setq isearch-lazy-highlight-timer |
| 3189 | (run-at-time lazy-highlight-interval nil | 3216 | (run-at-time lazy-highlight-interval nil |
diff --git a/lisp/window.el b/lisp/window.el index 6d189055c15..0c403eb184a 100644 --- a/lisp/window.el +++ b/lisp/window.el | |||
| @@ -28,6 +28,17 @@ | |||
| 28 | 28 | ||
| 29 | ;;; Code: | 29 | ;;; Code: |
| 30 | 30 | ||
| 31 | (defvar selected-window-group-function nil) | ||
| 32 | (make-variable-buffer-local 'selected-window-group-function) | ||
| 33 | (put 'selected-window-group-function 'permanent-local t) | ||
| 34 | (defun selected-window-group () | ||
| 35 | "Return the list of windows in the group containing the selected window. | ||
| 36 | When a grouping mode (such as Follow Mode) is not active, the | ||
| 37 | result is a list containing only the selected window." | ||
| 38 | (if (functionp selected-window-group-function) | ||
| 39 | (funcall selected-window-group-function) | ||
| 40 | (list (selected-window)))) | ||
| 41 | |||
| 31 | (defun internal--before-save-selected-window () | 42 | (defun internal--before-save-selected-window () |
| 32 | (cons (selected-window) | 43 | (cons (selected-window) |
| 33 | ;; We save and restore all frames' selected windows, because | 44 | ;; We save and restore all frames' selected windows, because |
diff --git a/src/keyboard.c b/src/keyboard.c index 851207874db..c7733568e7f 100644 --- a/src/keyboard.c +++ b/src/keyboard.c | |||
| @@ -10663,7 +10663,7 @@ The `posn-' functions access elements of such lists. */) | |||
| 10663 | if (NILP (window)) | 10663 | if (NILP (window)) |
| 10664 | window = selected_window; | 10664 | window = selected_window; |
| 10665 | 10665 | ||
| 10666 | tem = Fpos_visible_in_window_p (pos, window, Qt); | 10666 | tem = Fpos_visible_in_window_p (pos, window, Qt, Qnil); |
| 10667 | if (!NILP (tem)) | 10667 | if (!NILP (tem)) |
| 10668 | { | 10668 | { |
| 10669 | Lisp_Object x = XCAR (tem); | 10669 | Lisp_Object x = XCAR (tem); |
diff --git a/src/window.c b/src/window.c index 0ac76d41861..efb4c9b4f8c 100644 --- a/src/window.c +++ b/src/window.c | |||
| @@ -1540,13 +1540,23 @@ WINDOW must be a live window and defaults to the selected one. */) | |||
| 1540 | return Fmarker_position (decode_live_window (window)->old_pointm); | 1540 | return Fmarker_position (decode_live_window (window)->old_pointm); |
| 1541 | } | 1541 | } |
| 1542 | 1542 | ||
| 1543 | DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0, | 1543 | DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 2, 0, |
| 1544 | doc: /* Return position at which display currently starts in WINDOW. | 1544 | doc: /* Return position at which display currently starts in WINDOW. |
| 1545 | WINDOW must be a live window and defaults to the selected one. | 1545 | WINDOW must be a live window and defaults to the selected one. |
| 1546 | This is updated by redisplay or by calling `set-window-start'. */) | 1546 | This is updated by redisplay or by calling `set-window-start'. |
| 1547 | (Lisp_Object window) | 1547 | |
| 1548 | If GROUP is non-nil, and WINDOW is part of a group of windows collectively | ||
| 1549 | displaying a buffer (such as with Follow Mode), return the start position of | ||
| 1550 | the group rather than of the individual WINDOW. This condition holds when | ||
| 1551 | `window-start-group-function' is set to a function, in which case | ||
| 1552 | `window-start' calls the function with the argument WINDOW, then returns its | ||
| 1553 | result, instead of doing its normal processing. */) | ||
| 1554 | (Lisp_Object window, Lisp_Object group) | ||
| 1548 | { | 1555 | { |
| 1549 | return Fmarker_position (decode_live_window (window)->start); | 1556 | return (!NILP (group) |
| 1557 | && FUNCTIONP (Vwindow_start_group_function)) | ||
| 1558 | ? call1 (Vwindow_start_group_function, window) | ||
| 1559 | : Fmarker_position (decode_live_window (window)->start); | ||
| 1550 | } | 1560 | } |
| 1551 | 1561 | ||
| 1552 | /* This is text temporarily removed from the doc string below. | 1562 | /* This is text temporarily removed from the doc string below. |
| @@ -1560,7 +1570,7 @@ have been if redisplay had finished, do this: | |||
| 1560 | (vertical-motion (1- (window-height window)) window) | 1570 | (vertical-motion (1- (window-height window)) window) |
| 1561 | (point))") */ | 1571 | (point))") */ |
| 1562 | 1572 | ||
| 1563 | DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0, | 1573 | DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 3, 0, |
| 1564 | doc: /* Return position at which display currently ends in WINDOW. | 1574 | doc: /* Return position at which display currently ends in WINDOW. |
| 1565 | WINDOW must be a live window and defaults to the selected one. | 1575 | WINDOW must be a live window and defaults to the selected one. |
| 1566 | This is updated by redisplay, when it runs to completion. | 1576 | This is updated by redisplay, when it runs to completion. |
| @@ -1569,65 +1579,77 @@ does not update this value. | |||
| 1569 | Return nil if there is no recorded value. (This can happen if the | 1579 | Return nil if there is no recorded value. (This can happen if the |
| 1570 | last redisplay of WINDOW was preempted, and did not finish.) | 1580 | last redisplay of WINDOW was preempted, and did not finish.) |
| 1571 | If UPDATE is non-nil, compute the up-to-date position | 1581 | If UPDATE is non-nil, compute the up-to-date position |
| 1572 | if it isn't already recorded. */) | 1582 | if it isn't already recorded. |
| 1573 | (Lisp_Object window, Lisp_Object update) | 1583 | |
| 1574 | { | 1584 | If GROUP is non-nil, and WINDOW is part of a group of windows collectively |
| 1575 | Lisp_Object value; | 1585 | displaying a buffer (such as with Follow Mode), return the end position of |
| 1576 | struct window *w = decode_live_window (window); | 1586 | the group rather than of the individual WINDOW. This condition holds when |
| 1577 | Lisp_Object buf; | 1587 | `window-end-group-function' is set to a function, in which case `window-end' |
| 1578 | struct buffer *b; | 1588 | calls the function with the two arguments WINDOW and UPDATE, then returns its |
| 1579 | 1589 | result, instead of doing its normal processing. */) | |
| 1580 | buf = w->contents; | 1590 | (Lisp_Object window, Lisp_Object update, Lisp_Object group) |
| 1581 | CHECK_BUFFER (buf); | 1591 | { |
| 1582 | b = XBUFFER (buf); | 1592 | if (!NILP (group) |
| 1583 | 1593 | && FUNCTIONP (Vwindow_end_group_function)) | |
| 1584 | if (! NILP (update) | 1594 | return call2 (Vwindow_end_group_function, window, update); |
| 1585 | && (windows_or_buffers_changed | 1595 | { |
| 1586 | || !w->window_end_valid | 1596 | Lisp_Object value; |
| 1587 | || b->clip_changed | 1597 | struct window *w = decode_live_window (window); |
| 1588 | || b->prevent_redisplay_optimizations_p | 1598 | Lisp_Object buf; |
| 1589 | || window_outdated (w)) | 1599 | struct buffer *b; |
| 1590 | /* Don't call display routines if we didn't yet create any real | 1600 | |
| 1591 | frames, because the glyph matrices are not yet allocated in | 1601 | buf = w->contents; |
| 1592 | that case. This could happen in some code that runs in the | 1602 | CHECK_BUFFER (buf); |
| 1593 | daemon during initialization (e.g., see bug#20565). */ | 1603 | b = XBUFFER (buf); |
| 1594 | && !(noninteractive || FRAME_INITIAL_P (WINDOW_XFRAME (w)))) | 1604 | |
| 1595 | { | 1605 | if (! NILP (update) |
| 1596 | struct text_pos startp; | 1606 | && (windows_or_buffers_changed |
| 1597 | struct it it; | 1607 | || !w->window_end_valid |
| 1598 | struct buffer *old_buffer = NULL; | 1608 | || b->clip_changed |
| 1599 | void *itdata = NULL; | 1609 | || b->prevent_redisplay_optimizations_p |
| 1600 | 1610 | || window_outdated (w)) | |
| 1601 | /* Cannot use Fvertical_motion because that function doesn't | 1611 | /* Don't call display routines if we didn't yet create any real |
| 1602 | cope with variable-height lines. */ | 1612 | frames, because the glyph matrices are not yet allocated in |
| 1603 | if (b != current_buffer) | 1613 | that case. This could happen in some code that runs in the |
| 1604 | { | 1614 | daemon during initialization (e.g., see bug#20565). */ |
| 1605 | old_buffer = current_buffer; | 1615 | && !(noninteractive || FRAME_INITIAL_P (WINDOW_XFRAME (w)))) |
| 1606 | set_buffer_internal (b); | 1616 | { |
| 1607 | } | 1617 | struct text_pos startp; |
| 1608 | 1618 | struct it it; | |
| 1609 | /* In case W->start is out of the range, use something | 1619 | struct buffer *old_buffer = NULL; |
| 1610 | reasonable. This situation occurred when loading a file with | 1620 | void *itdata = NULL; |
| 1611 | `-l' containing a call to `rmail' with subsequent other | 1621 | |
| 1612 | commands. At the end, W->start happened to be BEG, while | 1622 | /* Cannot use Fvertical_motion because that function doesn't |
| 1613 | rmail had already narrowed the buffer. */ | 1623 | cope with variable-height lines. */ |
| 1614 | CLIP_TEXT_POS_FROM_MARKER (startp, w->start); | 1624 | if (b != current_buffer) |
| 1615 | 1625 | { | |
| 1616 | itdata = bidi_shelve_cache (); | 1626 | old_buffer = current_buffer; |
| 1617 | start_display (&it, w, startp); | 1627 | set_buffer_internal (b); |
| 1618 | move_it_vertically (&it, window_box_height (w)); | 1628 | } |
| 1619 | if (it.current_y < it.last_visible_y) | 1629 | |
| 1620 | move_it_past_eol (&it); | 1630 | /* In case W->start is out of the range, use something |
| 1621 | value = make_number (IT_CHARPOS (it)); | 1631 | reasonable. This situation occurred when loading a file with |
| 1622 | bidi_unshelve_cache (itdata, false); | 1632 | `-l' containing a call to `rmail' with subsequent other |
| 1623 | 1633 | commands. At the end, W->start happened to be BEG, while | |
| 1624 | if (old_buffer) | 1634 | rmail had already narrowed the buffer. */ |
| 1625 | set_buffer_internal (old_buffer); | 1635 | CLIP_TEXT_POS_FROM_MARKER (startp, w->start); |
| 1626 | } | 1636 | |
| 1627 | else | 1637 | itdata = bidi_shelve_cache (); |
| 1628 | XSETINT (value, BUF_Z (b) - w->window_end_pos); | 1638 | start_display (&it, w, startp); |
| 1639 | move_it_vertically (&it, window_box_height (w)); | ||
| 1640 | if (it.current_y < it.last_visible_y) | ||
| 1641 | move_it_past_eol (&it); | ||
| 1642 | value = make_number (IT_CHARPOS (it)); | ||
| 1643 | bidi_unshelve_cache (itdata, false); | ||
| 1644 | |||
| 1645 | if (old_buffer) | ||
| 1646 | set_buffer_internal (old_buffer); | ||
| 1647 | } | ||
| 1648 | else | ||
| 1649 | XSETINT (value, BUF_Z (b) - w->window_end_pos); | ||
| 1629 | 1650 | ||
| 1630 | return value; | 1651 | return value; |
| 1652 | } | ||
| 1631 | } | 1653 | } |
| 1632 | 1654 | ||
| 1633 | DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0, | 1655 | DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0, |
| @@ -1666,30 +1688,43 @@ Return POS. */) | |||
| 1666 | return pos; | 1688 | return pos; |
| 1667 | } | 1689 | } |
| 1668 | 1690 | ||
| 1669 | DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0, | 1691 | DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 4, 0, |
| 1670 | doc: /* Make display in WINDOW start at position POS in WINDOW's buffer. | 1692 | doc: /* Make display in WINDOW start at position POS in WINDOW's buffer. |
| 1671 | WINDOW must be a live window and defaults to the selected one. Return | 1693 | WINDOW must be a live window and defaults to the selected one. Return |
| 1672 | POS. Optional third arg NOFORCE non-nil inhibits next redisplay from | 1694 | POS. Optional third arg NOFORCE non-nil inhibits next redisplay from |
| 1673 | overriding motion of point in order to display at this exact start. */) | 1695 | overriding motion of point in order to display at this exact start. |
| 1674 | (Lisp_Object window, Lisp_Object pos, Lisp_Object noforce) | 1696 | |
| 1675 | { | 1697 | If GROUP is non-nil, and WINDOW is part of a group of windows collectively |
| 1676 | register struct window *w = decode_live_window (window); | 1698 | displaying a buffer (such as with Follow Mode), set the start position of |
| 1699 | the group rather than of the individual WINDOW. This condition holds when | ||
| 1700 | `set-window-start-group-function' is set to a function, in which case | ||
| 1701 | `set-window-start' calls the function with the three arguments WINDOW, POS, | ||
| 1702 | and NOFORCE, then returns its result, instead of doing its normal | ||
| 1703 | processing. */) | ||
| 1704 | (Lisp_Object window, Lisp_Object pos, Lisp_Object noforce, Lisp_Object group) | ||
| 1705 | { | ||
| 1706 | if (!NILP (group) | ||
| 1707 | && FUNCTIONP (Vset_window_start_group_function)) | ||
| 1708 | return call3 (Vset_window_start_group_function, window, pos, noforce); | ||
| 1709 | { | ||
| 1710 | register struct window *w = decode_live_window (window); | ||
| 1677 | 1711 | ||
| 1678 | set_marker_restricted (w->start, pos, w->contents); | 1712 | set_marker_restricted (w->start, pos, w->contents); |
| 1679 | /* This is not right, but much easier than doing what is right. */ | 1713 | /* This is not right, but much easier than doing what is right. */ |
| 1680 | w->start_at_line_beg = false; | 1714 | w->start_at_line_beg = false; |
| 1681 | if (NILP (noforce)) | 1715 | if (NILP (noforce)) |
| 1682 | w->force_start = true; | 1716 | w->force_start = true; |
| 1683 | wset_update_mode_line (w); | 1717 | wset_update_mode_line (w); |
| 1684 | /* Bug#15957. */ | 1718 | /* Bug#15957. */ |
| 1685 | w->window_end_valid = false; | 1719 | w->window_end_valid = false; |
| 1686 | wset_redisplay (w); | 1720 | wset_redisplay (w); |
| 1687 | 1721 | ||
| 1688 | return pos; | 1722 | return pos; |
| 1723 | } | ||
| 1689 | } | 1724 | } |
| 1690 | 1725 | ||
| 1691 | DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p, | 1726 | DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p, |
| 1692 | Spos_visible_in_window_p, 0, 3, 0, | 1727 | Spos_visible_in_window_p, 0, 4, 0, |
| 1693 | doc: /* Return non-nil if position POS is currently on the frame in WINDOW. | 1728 | doc: /* Return non-nil if position POS is currently on the frame in WINDOW. |
| 1694 | WINDOW must be a live window and defaults to the selected one. | 1729 | WINDOW must be a live window and defaults to the selected one. |
| 1695 | 1730 | ||
| @@ -1709,9 +1744,21 @@ of the window. The remaining elements are omitted if the character after | |||
| 1709 | POS is fully visible; otherwise, RTOP and RBOT are the number of pixels | 1744 | POS is fully visible; otherwise, RTOP and RBOT are the number of pixels |
| 1710 | off-window at the top and bottom of the screen line ("row") containing | 1745 | off-window at the top and bottom of the screen line ("row") containing |
| 1711 | POS, ROWH is the visible height of that row, and VPOS is the row number | 1746 | POS, ROWH is the visible height of that row, and VPOS is the row number |
| 1712 | (zero-based). */) | 1747 | (zero-based). |
| 1713 | (Lisp_Object pos, Lisp_Object window, Lisp_Object partially) | 1748 | |
| 1714 | { | 1749 | If GROUP is non-nil, and WINDOW is part of a group of windows collectively |
| 1750 | displaying a buffer (such as with Follow Mode), test whether POS is visible | ||
| 1751 | in the group of windows rather than in the individual WINDOW. This | ||
| 1752 | condition holds when `pos-visible-in-window-p-function' is set to a | ||
| 1753 | function, in which case `pos-visible-in-window-p' calls the function with | ||
| 1754 | the three arguments POS, WINDOW, and PARTIALLY, then returns its result, | ||
| 1755 | instead of doing its normal processing. */) | ||
| 1756 | (Lisp_Object pos, Lisp_Object window, Lisp_Object partially, Lisp_Object group) | ||
| 1757 | { | ||
| 1758 | if (!NILP (group) | ||
| 1759 | && FUNCTIONP (Vpos_visible_in_window_p_group_function)) | ||
| 1760 | return call3 (Vpos_visible_in_window_p_group_function, pos, window, partially); | ||
| 1761 | { | ||
| 1715 | struct window *w; | 1762 | struct window *w; |
| 1716 | EMACS_INT posint; | 1763 | EMACS_INT posint; |
| 1717 | struct buffer *buf; | 1764 | struct buffer *buf; |
| @@ -1760,6 +1807,7 @@ POS, ROWH is the visible height of that row, and VPOS is the row number | |||
| 1760 | } | 1807 | } |
| 1761 | 1808 | ||
| 1762 | return in_window; | 1809 | return in_window; |
| 1810 | } | ||
| 1763 | } | 1811 | } |
| 1764 | 1812 | ||
| 1765 | DEFUN ("window-line-height", Fwindow_line_height, | 1813 | DEFUN ("window-line-height", Fwindow_line_height, |
| @@ -5185,7 +5233,7 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror) | |||
| 5185 | } | 5233 | } |
| 5186 | 5234 | ||
| 5187 | XSETFASTINT (tem, PT); | 5235 | XSETFASTINT (tem, PT); |
| 5188 | tem = Fpos_visible_in_window_p (tem, window, Qnil); | 5236 | tem = Fpos_visible_in_window_p (tem, window, Qnil, Qnil); |
| 5189 | 5237 | ||
| 5190 | if (NILP (tem)) | 5238 | if (NILP (tem)) |
| 5191 | { | 5239 | { |
| @@ -5574,7 +5622,7 @@ displayed_window_lines (struct window *w) | |||
| 5574 | } | 5622 | } |
| 5575 | 5623 | ||
| 5576 | 5624 | ||
| 5577 | DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P", | 5625 | DEFUN ("recenter", Frecenter, Srecenter, 0, 2, "P\ni", |
| 5578 | doc: /* Center point in selected window and maybe redisplay frame. | 5626 | doc: /* Center point in selected window and maybe redisplay frame. |
| 5579 | With a numeric prefix argument ARG, recenter putting point on screen line ARG | 5627 | With a numeric prefix argument ARG, recenter putting point on screen line ARG |
| 5580 | relative to the selected window. If ARG is negative, it counts up from the | 5628 | relative to the selected window. If ARG is negative, it counts up from the |
| @@ -5588,208 +5636,221 @@ height needed); if `recenter-redisplay' has the special value `tty', | |||
| 5588 | then only tty frames are redrawn. | 5636 | then only tty frames are redrawn. |
| 5589 | 5637 | ||
| 5590 | Just C-u as prefix means put point in the center of the window | 5638 | Just C-u as prefix means put point in the center of the window |
| 5591 | and redisplay normally--don't erase and redraw the frame. */) | 5639 | and redisplay normally--don't erase and redraw the frame. |
| 5592 | (register Lisp_Object arg) | 5640 | |
| 5593 | { | 5641 | When `recenter' is called from a program, GROUP is non-nil, and WINDOW is |
| 5594 | struct window *w = XWINDOW (selected_window); | 5642 | part of a group of windows collectively displaying a buffer (such as with |
| 5595 | struct buffer *buf = XBUFFER (w->contents); | 5643 | Follow Mode), perform `recenter''s actions on the group rather than on the |
| 5596 | bool center_p = false; | 5644 | individual WINDOW. This condition holds when `recenter-group-function' is |
| 5597 | ptrdiff_t charpos, bytepos; | 5645 | set to a function, in which case `recenter' calls the function with the |
| 5598 | EMACS_INT iarg IF_LINT (= 0); | 5646 | argument ARG, then returns its value, instead of doing its normal |
| 5599 | int this_scroll_margin; | 5647 | processing. */) |
| 5600 | 5648 | (register Lisp_Object arg, Lisp_Object group) | |
| 5601 | if (buf != current_buffer) | 5649 | { |
| 5602 | error ("`recenter'ing a window that does not display current-buffer."); | 5650 | if (!NILP (group) |
| 5651 | && FUNCTIONP (Vrecenter_group_function)) | ||
| 5652 | return call1 (Vrecenter_group_function, arg); | ||
| 5653 | { | ||
| 5654 | struct window *w = XWINDOW (selected_window); | ||
| 5655 | struct buffer *buf = XBUFFER (w->contents); | ||
| 5656 | bool center_p = false; | ||
| 5657 | ptrdiff_t charpos, bytepos; | ||
| 5658 | EMACS_INT iarg IF_LINT (= 0); | ||
| 5659 | int this_scroll_margin; | ||
| 5603 | 5660 | ||
| 5604 | /* If redisplay is suppressed due to an error, try again. */ | 5661 | if (buf != current_buffer) |
| 5605 | buf->display_error_modiff = 0; | 5662 | error ("`recenter'ing a window that does not display current-buffer."); |
| 5606 | 5663 | ||
| 5607 | if (NILP (arg)) | 5664 | /* If redisplay is suppressed due to an error, try again. */ |
| 5608 | { | 5665 | buf->display_error_modiff = 0; |
| 5609 | if (!NILP (Vrecenter_redisplay) | ||
| 5610 | && (!EQ (Vrecenter_redisplay, Qtty) | ||
| 5611 | || !NILP (Ftty_type (selected_frame)))) | ||
| 5612 | { | ||
| 5613 | ptrdiff_t i; | ||
| 5614 | 5666 | ||
| 5615 | /* Invalidate pixel data calculated for all compositions. */ | 5667 | if (NILP (arg)) |
| 5616 | for (i = 0; i < n_compositions; i++) | 5668 | { |
| 5617 | composition_table[i]->font = NULL; | 5669 | if (!NILP (Vrecenter_redisplay) |
| 5670 | && (!EQ (Vrecenter_redisplay, Qtty) | ||
| 5671 | || !NILP (Ftty_type (selected_frame)))) | ||
| 5672 | { | ||
| 5673 | ptrdiff_t i; | ||
| 5674 | |||
| 5675 | /* Invalidate pixel data calculated for all compositions. */ | ||
| 5676 | for (i = 0; i < n_compositions; i++) | ||
| 5677 | composition_table[i]->font = NULL; | ||
| 5618 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (USE_GTK) && ! defined (HAVE_NS) | 5678 | #if defined (HAVE_WINDOW_SYSTEM) && ! defined (USE_GTK) && ! defined (HAVE_NS) |
| 5619 | WINDOW_XFRAME (w)->minimize_tool_bar_window_p = 1; | 5679 | WINDOW_XFRAME (w)->minimize_tool_bar_window_p = 1; |
| 5620 | #endif | 5680 | #endif |
| 5621 | Fredraw_frame (WINDOW_FRAME (w)); | 5681 | Fredraw_frame (WINDOW_FRAME (w)); |
| 5622 | SET_FRAME_GARBAGED (WINDOW_XFRAME (w)); | 5682 | SET_FRAME_GARBAGED (WINDOW_XFRAME (w)); |
| 5623 | } | 5683 | } |
| 5624 | 5684 | ||
| 5685 | center_p = true; | ||
| 5686 | } | ||
| 5687 | else if (CONSP (arg)) /* Just C-u. */ | ||
| 5625 | center_p = true; | 5688 | center_p = true; |
| 5626 | } | 5689 | else |
| 5627 | else if (CONSP (arg)) /* Just C-u. */ | 5690 | { |
| 5628 | center_p = true; | 5691 | arg = Fprefix_numeric_value (arg); |
| 5629 | else | 5692 | CHECK_NUMBER (arg); |
| 5630 | { | 5693 | iarg = XINT (arg); |
| 5631 | arg = Fprefix_numeric_value (arg); | 5694 | } |
| 5632 | CHECK_NUMBER (arg); | ||
| 5633 | iarg = XINT (arg); | ||
| 5634 | } | ||
| 5635 | |||
| 5636 | /* Do this after making BUF current | ||
| 5637 | in case scroll_margin is buffer-local. */ | ||
| 5638 | this_scroll_margin | ||
| 5639 | = max (0, min (scroll_margin, w->total_lines / 4)); | ||
| 5640 | |||
| 5641 | /* Don't use redisplay code for initial frames, as the necessary | ||
| 5642 | data structures might not be set up yet then. */ | ||
| 5643 | if (!FRAME_INITIAL_P (XFRAME (w->frame))) | ||
| 5644 | { | ||
| 5645 | if (center_p) | ||
| 5646 | { | ||
| 5647 | struct it it; | ||
| 5648 | struct text_pos pt; | ||
| 5649 | void *itdata = bidi_shelve_cache (); | ||
| 5650 | |||
| 5651 | SET_TEXT_POS (pt, PT, PT_BYTE); | ||
| 5652 | start_display (&it, w, pt); | ||
| 5653 | move_it_vertically_backward (&it, window_box_height (w) / 2); | ||
| 5654 | charpos = IT_CHARPOS (it); | ||
| 5655 | bytepos = IT_BYTEPOS (it); | ||
| 5656 | bidi_unshelve_cache (itdata, false); | ||
| 5657 | } | ||
| 5658 | else if (iarg < 0) | ||
| 5659 | { | ||
| 5660 | struct it it; | ||
| 5661 | struct text_pos pt; | ||
| 5662 | ptrdiff_t nlines = min (PTRDIFF_MAX, -iarg); | ||
| 5663 | int extra_line_spacing; | ||
| 5664 | int h = window_box_height (w); | ||
| 5665 | int ht = window_internal_height (w); | ||
| 5666 | void *itdata = bidi_shelve_cache (); | ||
| 5667 | |||
| 5668 | nlines = clip_to_bounds (this_scroll_margin + 1, nlines, | ||
| 5669 | ht - this_scroll_margin); | ||
| 5670 | |||
| 5671 | SET_TEXT_POS (pt, PT, PT_BYTE); | ||
| 5672 | start_display (&it, w, pt); | ||
| 5673 | |||
| 5674 | /* Be sure we have the exact height of the full line containing PT. */ | ||
| 5675 | move_it_by_lines (&it, 0); | ||
| 5676 | |||
| 5677 | /* The amount of pixels we have to move back is the window | ||
| 5678 | height minus what's displayed in the line containing PT, | ||
| 5679 | and the lines below. */ | ||
| 5680 | it.current_y = 0; | ||
| 5681 | it.vpos = 0; | ||
| 5682 | move_it_by_lines (&it, nlines); | ||
| 5683 | |||
| 5684 | if (it.vpos == nlines) | ||
| 5685 | h -= it.current_y; | ||
| 5686 | else | ||
| 5687 | { | ||
| 5688 | /* Last line has no newline. */ | ||
| 5689 | h -= line_bottom_y (&it); | ||
| 5690 | it.vpos++; | ||
| 5691 | } | ||
| 5692 | |||
| 5693 | /* Don't reserve space for extra line spacing of last line. */ | ||
| 5694 | extra_line_spacing = it.max_extra_line_spacing; | ||
| 5695 | |||
| 5696 | /* If we can't move down NLINES lines because we hit | ||
| 5697 | the end of the buffer, count in some empty lines. */ | ||
| 5698 | if (it.vpos < nlines) | ||
| 5699 | { | ||
| 5700 | nlines -= it.vpos; | ||
| 5701 | extra_line_spacing = it.extra_line_spacing; | ||
| 5702 | h -= nlines * (FRAME_LINE_HEIGHT (it.f) + extra_line_spacing); | ||
| 5703 | } | ||
| 5704 | if (h <= 0) | ||
| 5705 | { | ||
| 5706 | bidi_unshelve_cache (itdata, false); | ||
| 5707 | return Qnil; | ||
| 5708 | } | ||
| 5709 | |||
| 5710 | /* Now find the new top line (starting position) of the window. */ | ||
| 5711 | start_display (&it, w, pt); | ||
| 5712 | it.current_y = 0; | ||
| 5713 | move_it_vertically_backward (&it, h); | ||
| 5714 | |||
| 5715 | /* If extra line spacing is present, we may move too far | ||
| 5716 | back. This causes the last line to be only partially | ||
| 5717 | visible (which triggers redisplay to recenter that line | ||
| 5718 | in the middle), so move forward. | ||
| 5719 | But ignore extra line spacing on last line, as it is not | ||
| 5720 | considered to be part of the visible height of the line. | ||
| 5721 | */ | ||
| 5722 | h += extra_line_spacing; | ||
| 5723 | while (-it.current_y > h) | ||
| 5724 | move_it_by_lines (&it, 1); | ||
| 5725 | |||
| 5726 | charpos = IT_CHARPOS (it); | ||
| 5727 | bytepos = IT_BYTEPOS (it); | ||
| 5728 | |||
| 5729 | bidi_unshelve_cache (itdata, false); | ||
| 5730 | } | ||
| 5731 | else | ||
| 5732 | { | ||
| 5733 | struct it it; | ||
| 5734 | struct text_pos pt; | ||
| 5735 | ptrdiff_t nlines = min (PTRDIFF_MAX, iarg); | ||
| 5736 | int ht = window_internal_height (w); | ||
| 5737 | void *itdata = bidi_shelve_cache (); | ||
| 5738 | |||
| 5739 | nlines = clip_to_bounds (this_scroll_margin, nlines, | ||
| 5740 | ht - this_scroll_margin - 1); | ||
| 5741 | |||
| 5742 | SET_TEXT_POS (pt, PT, PT_BYTE); | ||
| 5743 | start_display (&it, w, pt); | ||
| 5744 | |||
| 5745 | /* Move to the beginning of screen line containing PT. */ | ||
| 5746 | move_it_by_lines (&it, 0); | ||
| 5747 | |||
| 5748 | /* Move back to find the point which is ARG screen lines above PT. */ | ||
| 5749 | if (nlines > 0) | ||
| 5750 | { | ||
| 5751 | it.current_y = 0; | ||
| 5752 | it.vpos = 0; | ||
| 5753 | move_it_by_lines (&it, -nlines); | ||
| 5754 | } | ||
| 5755 | 5695 | ||
| 5756 | charpos = IT_CHARPOS (it); | 5696 | /* Do this after making BUF current |
| 5757 | bytepos = IT_BYTEPOS (it); | 5697 | in case scroll_margin is buffer-local. */ |
| 5698 | this_scroll_margin | ||
| 5699 | = max (0, min (scroll_margin, w->total_lines / 4)); | ||
| 5758 | 5700 | ||
| 5759 | bidi_unshelve_cache (itdata, false); | 5701 | /* Don't use redisplay code for initial frames, as the necessary |
| 5760 | } | 5702 | data structures might not be set up yet then. */ |
| 5761 | } | 5703 | if (!FRAME_INITIAL_P (XFRAME (w->frame))) |
| 5762 | else | 5704 | { |
| 5763 | { | 5705 | if (center_p) |
| 5764 | struct position pos; | 5706 | { |
| 5765 | int ht = window_internal_height (w); | 5707 | struct it it; |
| 5708 | struct text_pos pt; | ||
| 5709 | void *itdata = bidi_shelve_cache (); | ||
| 5710 | |||
| 5711 | SET_TEXT_POS (pt, PT, PT_BYTE); | ||
| 5712 | start_display (&it, w, pt); | ||
| 5713 | move_it_vertically_backward (&it, window_box_height (w) / 2); | ||
| 5714 | charpos = IT_CHARPOS (it); | ||
| 5715 | bytepos = IT_BYTEPOS (it); | ||
| 5716 | bidi_unshelve_cache (itdata, false); | ||
| 5717 | } | ||
| 5718 | else if (iarg < 0) | ||
| 5719 | { | ||
| 5720 | struct it it; | ||
| 5721 | struct text_pos pt; | ||
| 5722 | ptrdiff_t nlines = min (PTRDIFF_MAX, -iarg); | ||
| 5723 | int extra_line_spacing; | ||
| 5724 | int h = window_box_height (w); | ||
| 5725 | int ht = window_internal_height (w); | ||
| 5726 | void *itdata = bidi_shelve_cache (); | ||
| 5727 | |||
| 5728 | nlines = clip_to_bounds (this_scroll_margin + 1, nlines, | ||
| 5729 | ht - this_scroll_margin); | ||
| 5730 | |||
| 5731 | SET_TEXT_POS (pt, PT, PT_BYTE); | ||
| 5732 | start_display (&it, w, pt); | ||
| 5733 | |||
| 5734 | /* Be sure we have the exact height of the full line containing PT. */ | ||
| 5735 | move_it_by_lines (&it, 0); | ||
| 5736 | |||
| 5737 | /* The amount of pixels we have to move back is the window | ||
| 5738 | height minus what's displayed in the line containing PT, | ||
| 5739 | and the lines below. */ | ||
| 5740 | it.current_y = 0; | ||
| 5741 | it.vpos = 0; | ||
| 5742 | move_it_by_lines (&it, nlines); | ||
| 5743 | |||
| 5744 | if (it.vpos == nlines) | ||
| 5745 | h -= it.current_y; | ||
| 5746 | else | ||
| 5747 | { | ||
| 5748 | /* Last line has no newline. */ | ||
| 5749 | h -= line_bottom_y (&it); | ||
| 5750 | it.vpos++; | ||
| 5751 | } | ||
| 5752 | |||
| 5753 | /* Don't reserve space for extra line spacing of last line. */ | ||
| 5754 | extra_line_spacing = it.max_extra_line_spacing; | ||
| 5755 | |||
| 5756 | /* If we can't move down NLINES lines because we hit | ||
| 5757 | the end of the buffer, count in some empty lines. */ | ||
| 5758 | if (it.vpos < nlines) | ||
| 5759 | { | ||
| 5760 | nlines -= it.vpos; | ||
| 5761 | extra_line_spacing = it.extra_line_spacing; | ||
| 5762 | h -= nlines * (FRAME_LINE_HEIGHT (it.f) + extra_line_spacing); | ||
| 5763 | } | ||
| 5764 | if (h <= 0) | ||
| 5765 | { | ||
| 5766 | bidi_unshelve_cache (itdata, false); | ||
| 5767 | return Qnil; | ||
| 5768 | } | ||
| 5769 | |||
| 5770 | /* Now find the new top line (starting position) of the window. */ | ||
| 5771 | start_display (&it, w, pt); | ||
| 5772 | it.current_y = 0; | ||
| 5773 | move_it_vertically_backward (&it, h); | ||
| 5774 | |||
| 5775 | /* If extra line spacing is present, we may move too far | ||
| 5776 | back. This causes the last line to be only partially | ||
| 5777 | visible (which triggers redisplay to recenter that line | ||
| 5778 | in the middle), so move forward. | ||
| 5779 | But ignore extra line spacing on last line, as it is not | ||
| 5780 | considered to be part of the visible height of the line. | ||
| 5781 | */ | ||
| 5782 | h += extra_line_spacing; | ||
| 5783 | while (-it.current_y > h) | ||
| 5784 | move_it_by_lines (&it, 1); | ||
| 5785 | |||
| 5786 | charpos = IT_CHARPOS (it); | ||
| 5787 | bytepos = IT_BYTEPOS (it); | ||
| 5788 | |||
| 5789 | bidi_unshelve_cache (itdata, false); | ||
| 5790 | } | ||
| 5791 | else | ||
| 5792 | { | ||
| 5793 | struct it it; | ||
| 5794 | struct text_pos pt; | ||
| 5795 | ptrdiff_t nlines = min (PTRDIFF_MAX, iarg); | ||
| 5796 | int ht = window_internal_height (w); | ||
| 5797 | void *itdata = bidi_shelve_cache (); | ||
| 5798 | |||
| 5799 | nlines = clip_to_bounds (this_scroll_margin, nlines, | ||
| 5800 | ht - this_scroll_margin - 1); | ||
| 5801 | |||
| 5802 | SET_TEXT_POS (pt, PT, PT_BYTE); | ||
| 5803 | start_display (&it, w, pt); | ||
| 5804 | |||
| 5805 | /* Move to the beginning of screen line containing PT. */ | ||
| 5806 | move_it_by_lines (&it, 0); | ||
| 5807 | |||
| 5808 | /* Move back to find the point which is ARG screen lines above PT. */ | ||
| 5809 | if (nlines > 0) | ||
| 5810 | { | ||
| 5811 | it.current_y = 0; | ||
| 5812 | it.vpos = 0; | ||
| 5813 | move_it_by_lines (&it, -nlines); | ||
| 5814 | } | ||
| 5815 | |||
| 5816 | charpos = IT_CHARPOS (it); | ||
| 5817 | bytepos = IT_BYTEPOS (it); | ||
| 5818 | |||
| 5819 | bidi_unshelve_cache (itdata, false); | ||
| 5820 | } | ||
| 5821 | } | ||
| 5822 | else | ||
| 5823 | { | ||
| 5824 | struct position pos; | ||
| 5825 | int ht = window_internal_height (w); | ||
| 5766 | 5826 | ||
| 5767 | if (center_p) | 5827 | if (center_p) |
| 5768 | iarg = ht / 2; | 5828 | iarg = ht / 2; |
| 5769 | else if (iarg < 0) | 5829 | else if (iarg < 0) |
| 5770 | iarg += ht; | 5830 | iarg += ht; |
| 5771 | 5831 | ||
| 5772 | /* Don't let it get into the margin at either top or bottom. */ | 5832 | /* Don't let it get into the margin at either top or bottom. */ |
| 5773 | iarg = clip_to_bounds (this_scroll_margin, iarg, | 5833 | iarg = clip_to_bounds (this_scroll_margin, iarg, |
| 5774 | ht - this_scroll_margin - 1); | 5834 | ht - this_scroll_margin - 1); |
| 5775 | 5835 | ||
| 5776 | pos = *vmotion (PT, PT_BYTE, - iarg, w); | 5836 | pos = *vmotion (PT, PT_BYTE, - iarg, w); |
| 5777 | charpos = pos.bufpos; | 5837 | charpos = pos.bufpos; |
| 5778 | bytepos = pos.bytepos; | 5838 | bytepos = pos.bytepos; |
| 5779 | } | 5839 | } |
| 5780 | 5840 | ||
| 5781 | /* Set the new window start. */ | 5841 | /* Set the new window start. */ |
| 5782 | set_marker_both (w->start, w->contents, charpos, bytepos); | 5842 | set_marker_both (w->start, w->contents, charpos, bytepos); |
| 5783 | w->window_end_valid = false; | 5843 | w->window_end_valid = false; |
| 5784 | 5844 | ||
| 5785 | w->optional_new_start = true; | 5845 | w->optional_new_start = true; |
| 5786 | 5846 | ||
| 5787 | w->start_at_line_beg = (bytepos == BEGV_BYTE | 5847 | w->start_at_line_beg = (bytepos == BEGV_BYTE |
| 5788 | || FETCH_BYTE (bytepos - 1) == '\n'); | 5848 | || FETCH_BYTE (bytepos - 1) == '\n'); |
| 5789 | 5849 | ||
| 5790 | wset_redisplay (w); | 5850 | wset_redisplay (w); |
| 5791 | 5851 | ||
| 5792 | return Qnil; | 5852 | return Qnil; |
| 5853 | } | ||
| 5793 | } | 5854 | } |
| 5794 | 5855 | ||
| 5795 | DEFUN ("window-text-width", Fwindow_text_width, Swindow_text_width, | 5856 | DEFUN ("window-text-width", Fwindow_text_width, Swindow_text_width, |
| @@ -5836,52 +5897,68 @@ pixels. */) | |||
| 5836 | } | 5897 | } |
| 5837 | 5898 | ||
| 5838 | DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line, | 5899 | DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line, |
| 5839 | 1, 1, "P", | 5900 | 1, 2, "P\ni", |
| 5840 | doc: /* Position point relative to window. | 5901 | doc: /* Position point relative to window. |
| 5841 | ARG nil means position point at center of window. | 5902 | ARG nil means position point at center of window. |
| 5842 | Else, ARG specifies vertical position within the window; | 5903 | Else, ARG specifies vertical position within the window; |
| 5843 | zero means top of window, negative means relative to bottom of window. */) | 5904 | zero means top of window, negative means relative to bottom of window. |
| 5844 | (Lisp_Object arg) | 5905 | |
| 5845 | { | 5906 | When GROUP is non-nil, and `move-to-window-line-group-function' is set to a |
| 5846 | struct window *w = XWINDOW (selected_window); | 5907 | function, then instead of the above, that function is called with the |
| 5847 | int lines, start; | 5908 | single argument ARG, and its result returned. |
| 5848 | Lisp_Object window; | 5909 | |
| 5910 | If GROUP is non-nil, and WINDOW is part of a group of windows collectively | ||
| 5911 | displaying a buffer (such as with Follow Mode), position point relative to | ||
| 5912 | the group of windows as a whole rather than the individual WINDOW. This | ||
| 5913 | condition holds when `move-to-window-line-group-function' is set to a | ||
| 5914 | function, in which case `move-to-window-line' calls the function with the | ||
| 5915 | argument ARG, then returns its result, instead of doing its normal | ||
| 5916 | processing. */) | ||
| 5917 | (Lisp_Object arg, Lisp_Object group) | ||
| 5918 | { | ||
| 5919 | if (!NILP (group) | ||
| 5920 | && FUNCTIONP (Vmove_to_window_line_group_function)) | ||
| 5921 | return call1 (Vmove_to_window_line_group_function, arg); | ||
| 5922 | { | ||
| 5923 | struct window *w = XWINDOW (selected_window); | ||
| 5924 | int lines, start; | ||
| 5925 | Lisp_Object window; | ||
| 5849 | #if false | 5926 | #if false |
| 5850 | int this_scroll_margin; | 5927 | int this_scroll_margin; |
| 5851 | #endif | 5928 | #endif |
| 5852 | 5929 | ||
| 5853 | if (!(BUFFERP (w->contents) && XBUFFER (w->contents) == current_buffer)) | 5930 | if (!(BUFFERP (w->contents) && XBUFFER (w->contents) == current_buffer)) |
| 5854 | /* This test is needed to make sure PT/PT_BYTE make sense in w->contents | 5931 | /* This test is needed to make sure PT/PT_BYTE make sense in w->contents |
| 5855 | when passed below to set_marker_both. */ | 5932 | when passed below to set_marker_both. */ |
| 5856 | error ("move-to-window-line called from unrelated buffer"); | 5933 | error ("move-to-window-line called from unrelated buffer"); |
| 5857 | 5934 | ||
| 5858 | window = selected_window; | 5935 | window = selected_window; |
| 5859 | start = marker_position (w->start); | 5936 | start = marker_position (w->start); |
| 5860 | if (start < BEGV || start > ZV) | 5937 | if (start < BEGV || start > ZV) |
| 5861 | { | 5938 | { |
| 5862 | int height = window_internal_height (w); | 5939 | int height = window_internal_height (w); |
| 5863 | Fvertical_motion (make_number (- (height / 2)), window, Qnil); | 5940 | Fvertical_motion (make_number (- (height / 2)), window, Qnil); |
| 5864 | set_marker_both (w->start, w->contents, PT, PT_BYTE); | 5941 | set_marker_both (w->start, w->contents, PT, PT_BYTE); |
| 5865 | w->start_at_line_beg = !NILP (Fbolp ()); | 5942 | w->start_at_line_beg = !NILP (Fbolp ()); |
| 5866 | w->force_start = true; | 5943 | w->force_start = true; |
| 5867 | } | 5944 | } |
| 5868 | else | 5945 | else |
| 5869 | Fgoto_char (w->start); | 5946 | Fgoto_char (w->start); |
| 5870 | 5947 | ||
| 5871 | lines = displayed_window_lines (w); | 5948 | lines = displayed_window_lines (w); |
| 5872 | 5949 | ||
| 5873 | #if false | 5950 | #if false |
| 5874 | this_scroll_margin = max (0, min (scroll_margin, lines / 4)); | 5951 | this_scroll_margin = max (0, min (scroll_margin, lines / 4)); |
| 5875 | #endif | 5952 | #endif |
| 5876 | 5953 | ||
| 5877 | if (NILP (arg)) | 5954 | if (NILP (arg)) |
| 5878 | XSETFASTINT (arg, lines / 2); | 5955 | XSETFASTINT (arg, lines / 2); |
| 5879 | else | 5956 | else |
| 5880 | { | 5957 | { |
| 5881 | EMACS_INT iarg = XINT (Fprefix_numeric_value (arg)); | 5958 | EMACS_INT iarg = XINT (Fprefix_numeric_value (arg)); |
| 5882 | 5959 | ||
| 5883 | if (iarg < 0) | 5960 | if (iarg < 0) |
| 5884 | iarg = iarg + lines; | 5961 | iarg = iarg + lines; |
| 5885 | 5962 | ||
| 5886 | #if false /* This code would prevent move-to-window-line from moving point | 5963 | #if false /* This code would prevent move-to-window-line from moving point |
| 5887 | to a place inside the scroll margins (which would cause the | 5964 | to a place inside the scroll margins (which would cause the |
| @@ -5889,19 +5966,20 @@ zero means top of window, negative means relative to bottom of window. */) | |||
| 5889 | it is probably better not to install it. However, it is here | 5966 | it is probably better not to install it. However, it is here |
| 5890 | inside #if false so as not to lose it. -- rms. */ | 5967 | inside #if false so as not to lose it. -- rms. */ |
| 5891 | 5968 | ||
| 5892 | /* Don't let it get into the margin at either top or bottom. */ | 5969 | /* Don't let it get into the margin at either top or bottom. */ |
| 5893 | iarg = max (iarg, this_scroll_margin); | 5970 | iarg = max (iarg, this_scroll_margin); |
| 5894 | iarg = min (iarg, lines - this_scroll_margin - 1); | 5971 | iarg = min (iarg, lines - this_scroll_margin - 1); |
| 5895 | #endif | 5972 | #endif |
| 5896 | 5973 | ||
| 5897 | arg = make_number (iarg); | 5974 | arg = make_number (iarg); |
| 5898 | } | 5975 | } |
| 5899 | 5976 | ||
| 5900 | /* Skip past a partially visible first line. */ | 5977 | /* Skip past a partially visible first line. */ |
| 5901 | if (w->vscroll) | 5978 | if (w->vscroll) |
| 5902 | XSETINT (arg, XINT (arg) + 1); | 5979 | XSETINT (arg, XINT (arg) + 1); |
| 5903 | 5980 | ||
| 5904 | return Fvertical_motion (arg, window, Qnil); | 5981 | return Fvertical_motion (arg, window, Qnil); |
| 5982 | } | ||
| 5905 | } | 5983 | } |
| 5906 | 5984 | ||
| 5907 | 5985 | ||
| @@ -7175,6 +7253,12 @@ syms_of_window (void) | |||
| 7175 | DEFSYM (Qclone_of, "clone-of"); | 7253 | DEFSYM (Qclone_of, "clone-of"); |
| 7176 | DEFSYM (Qfloor, "floor"); | 7254 | DEFSYM (Qfloor, "floor"); |
| 7177 | DEFSYM (Qceiling, "ceiling"); | 7255 | DEFSYM (Qceiling, "ceiling"); |
| 7256 | DEFSYM (Qwindow_start_group_function, "window-start-group-function"); | ||
| 7257 | DEFSYM (Qwindow_end_group_function, "window-end-group-function"); | ||
| 7258 | DEFSYM (Qset_window_start_group_function, "set-window-start-group-function"); | ||
| 7259 | DEFSYM (Qrecenter_group_function, "recenter-group-function"); | ||
| 7260 | DEFSYM (Qpos_visible_in_window_p_group_function, "pos-visible-in-window-p-group-function"); | ||
| 7261 | DEFSYM (Qmove_to_window_line_group_function, "move-to-window-line-group-function"); | ||
| 7178 | 7262 | ||
| 7179 | staticpro (&Vwindow_list); | 7263 | staticpro (&Vwindow_list); |
| 7180 | 7264 | ||
| @@ -7346,6 +7430,72 @@ Note that this optimization can cause the portion of the buffer | |||
| 7346 | displayed after a scrolling operation to be somewhat inaccurate. */); | 7430 | displayed after a scrolling operation to be somewhat inaccurate. */); |
| 7347 | Vfast_but_imprecise_scrolling = false; | 7431 | Vfast_but_imprecise_scrolling = false; |
| 7348 | 7432 | ||
| 7433 | DEFVAR_LISP ("window-start-group-function", Vwindow_start_group_function, | ||
| 7434 | doc: /* Function to call for `window-start' when its GROUP parameter is non-nil. | ||
| 7435 | When this variable contains a function, and `window-start' is called with a | ||
| 7436 | non-nil GROUP parameter, the function is called instead of `window-start''s | ||
| 7437 | normal action. `window-start' passes the function its argument WINDOW, which | ||
| 7438 | might be nil. The function may recursively call `window-start'. */); | ||
| 7439 | Vwindow_start_group_function = Qnil; | ||
| 7440 | Fmake_variable_buffer_local (Qwindow_start_group_function); | ||
| 7441 | Fput (Qwindow_start_group_function, Qpermanent_local, Qt); | ||
| 7442 | |||
| 7443 | DEFVAR_LISP ("window-end-group-function", Vwindow_end_group_function, | ||
| 7444 | doc: /* Function to call for `window-end' if its GROUP parameter is non-nil. | ||
| 7445 | When this variable contains a function, and `window-end' is called with a | ||
| 7446 | non-nil GROUP parameter, the function is called instead of `window-end''s | ||
| 7447 | normal action. `window-end' passes the function its two parameters WINDOW, | ||
| 7448 | and UPDATE. The function may call `window-end' recursively. */); | ||
| 7449 | Vwindow_end_group_function = Qnil; | ||
| 7450 | Fmake_variable_buffer_local (Qwindow_end_group_function); | ||
| 7451 | Fput (Qwindow_end_group_function, Qpermanent_local, Qt); | ||
| 7452 | |||
| 7453 | DEFVAR_LISP ("set-window-start-group-function", | ||
| 7454 | Vset_window_start_group_function, | ||
| 7455 | doc: /* The function to call for `set-window-start' when its GROUP parameter is non-nil. | ||
| 7456 | When this variable contains a function, and `set-window-start' is called | ||
| 7457 | with a non-nil GROUP parameter, the function is called instead of | ||
| 7458 | `set-window-start''s normal action. `set-window-start' passes the function | ||
| 7459 | its three parameters WINDOW, POS, and NOFORCE. The function may call | ||
| 7460 | `set-window-start' recursively. */); | ||
| 7461 | Vset_window_start_group_function = Qnil; | ||
| 7462 | Fmake_variable_buffer_local (Qset_window_start_group_function); | ||
| 7463 | Fput (Qset_window_start_group_function, Qpermanent_local, Qt); | ||
| 7464 | |||
| 7465 | DEFVAR_LISP ("recenter-group-function", Vrecenter_group_function, | ||
| 7466 | doc: /* Function to call for `recenter' when its GROUP parameter is non-nil. | ||
| 7467 | When this variable contains a function, and `recenter' is called with a | ||
| 7468 | non-nil GROUP parameter, the function is called instead of `recenter''s | ||
| 7469 | normal action. `recenter' passes the function its parameter ARG. The | ||
| 7470 | function may call `recenter' recursively. */); | ||
| 7471 | Vrecenter_group_function = Qnil; | ||
| 7472 | Fmake_variable_buffer_local (Qrecenter_group_function); | ||
| 7473 | Fput (Qrecenter_group_function, Qpermanent_local, Qt); | ||
| 7474 | |||
| 7475 | DEFVAR_LISP ("pos-visible-in-window-p-group-function", | ||
| 7476 | Vpos_visible_in_window_p_group_function, | ||
| 7477 | doc: /* Function for `pos-visible-in-window-p' when its GROUP parameter is non-nil. | ||
| 7478 | When this variable contains a function, and `pos-visible-in-window-p' is | ||
| 7479 | called with a non-nil GROUP parameter, the function is called instead of | ||
| 7480 | `pos-visible-in-window-p''s normal action. `pos-visible-in-window-p' | ||
| 7481 | passes the function its three parameters POS, WINDOW, and PARTIALLY. The | ||
| 7482 | function may call `pos-visible-in-window-p' recursively. */); | ||
| 7483 | Vpos_visible_in_window_p_group_function = Qnil; | ||
| 7484 | Fmake_variable_buffer_local (Qpos_visible_in_window_p_group_function); | ||
| 7485 | Fput (Qpos_visible_in_window_p_group_function, Qpermanent_local, Qt); | ||
| 7486 | |||
| 7487 | DEFVAR_LISP ("move-to-window-line-group-function", | ||
| 7488 | Vmove_to_window_line_group_function, | ||
| 7489 | doc: /* Function for `move-to-window-line' when its GROUP parameter is non-nil. | ||
| 7490 | When this variable contains a function, and `move-to-window-line' is | ||
| 7491 | called with a non-nil GROUP parameter, the function is called instead of | ||
| 7492 | `move-to-window-line''s normal action. `move-to-window-line' passes the | ||
| 7493 | function its parameter ARG. The function may call `move-to-window-line' | ||
| 7494 | recursively. */); | ||
| 7495 | Vmove_to_window_line_group_function = Qnil; | ||
| 7496 | Fmake_variable_buffer_local (Qmove_to_window_line_group_function); | ||
| 7497 | Fput (Qmove_to_window_line_group_function, Qpermanent_local, Qt); | ||
| 7498 | |||
| 7349 | defsubr (&Sselected_window); | 7499 | defsubr (&Sselected_window); |
| 7350 | defsubr (&Sminibuffer_window); | 7500 | defsubr (&Sminibuffer_window); |
| 7351 | defsubr (&Swindow_minibuffer_p); | 7501 | defsubr (&Swindow_minibuffer_p); |