mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-26 07:33:47 +00:00
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.
This commit is contained in:
parent
25775a12c5
commit
2c56fc2a3f
@ -551,7 +551,8 @@ current buffer, regardless of which buffer is displayed in
|
||||
any buffer, whether or not it is currently displayed in some window.
|
||||
@end defun
|
||||
|
||||
@deffn Command move-to-window-line count
|
||||
@deffn Command move-to-window-line count group
|
||||
@vindex move-to-window-line-group-function
|
||||
This function moves point with respect to the text currently displayed
|
||||
in the selected window. It moves point to the beginning of the screen
|
||||
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.
|
||||
|
||||
The value returned is the window line number point has moved to, with
|
||||
the top line in the window numbered 0.
|
||||
|
||||
If @var{group} is non-@code{nil}, and the selected window is a part of
|
||||
a group of windows (@pxref{Basic Windows}), @code{move-to-window-line}
|
||||
will move to a position with respect to the entire group, not just the
|
||||
single window. This condition holds when the buffer local variable
|
||||
@code{move-to-window-line-group-function} is set to a function. In
|
||||
this case, @code{move-to-window-line} calls the function with the
|
||||
argument @var{count}, then returns its result, instead of performing
|
||||
the actions described above. Typically, the function will call
|
||||
@code{move-to-window-line} recursively.
|
||||
@end deffn
|
||||
|
||||
@defun compute-motion from frompos to topos width offsets window
|
||||
|
@ -131,6 +131,30 @@ frame is ever selected. @xref{Selecting Windows}.
|
||||
@defun selected-window
|
||||
This function returns the selected window (which is always a live
|
||||
window).
|
||||
@end defun
|
||||
|
||||
Sometimes several windows collectively and cooperatively display a
|
||||
buffer, for example, under the management of Follow Mode, where the
|
||||
windows together display a bigger portion of the buffer than one
|
||||
window could alone. It is often useful to consider such a @dfn{group
|
||||
of windows} as a single entity. Several functions such as
|
||||
@code{window-start} (@pxref{Window Start and End}) allow you to do
|
||||
this by supplying, as an argument, one of the windows as a stand in
|
||||
for the whole group.
|
||||
|
||||
@defun selected-window-group
|
||||
@vindex selected-window-group-function
|
||||
When the selected window is a member of a group of windows, this
|
||||
function returns a list of the windows in the group, ordered such that
|
||||
the first window in the list is displaying the earliest part of the
|
||||
buffer, and so on. Otherwise the function returns a list containing
|
||||
just the selected window.
|
||||
|
||||
The selected window is considered part of a group when the buffer
|
||||
local variable @code{selected-window-group-function} is set to a
|
||||
function. In this case, @code{selected-window-group} calls it with no
|
||||
arguments and returns its result (which should be the list of windows
|
||||
in the group).
|
||||
@end defun
|
||||
|
||||
@node Windows and Frames
|
||||
@ -3064,7 +3088,8 @@ using the commands of Lisp mode, because they trigger this
|
||||
readjustment. To test such code, put it into a command and bind the
|
||||
command to a key.
|
||||
|
||||
@defun window-start &optional window
|
||||
@defun window-start &optional window group
|
||||
@vindex window-start-group-function
|
||||
@cindex window top line
|
||||
This function returns the display-start position of window
|
||||
@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
|
||||
on the screen. Nothing except redisplay automatically changes the
|
||||
window-start position; if you move point, do not expect the window-start
|
||||
position to change in response until after the next redisplay.
|
||||
|
||||
If @var{group} is non-@code{nil}, and @var{window} is a part of a
|
||||
group of windows (@pxref{Basic Windows}), @code{window-start} returns
|
||||
the start position of the entire group. This condition holds when the
|
||||
buffer local variable @code{window-start-group-function} is set to a
|
||||
function. In this case, @code{window-start} calls the function with
|
||||
the single argument @var{window}, then returns its result, instead of
|
||||
performing the actions described above. Typically, the function will
|
||||
call @code{window-start} recursively.
|
||||
@end defun
|
||||
|
||||
@vindex window-end-group-function
|
||||
@cindex window end position
|
||||
@defun window-end &optional window update
|
||||
@defun window-end &optional window update group
|
||||
This function returns the position where display of its buffer ends in
|
||||
@var{window}. The default for @var{window} is the selected window.
|
||||
|
||||
@ -3106,9 +3141,19 @@ attempt to scroll the display if point has moved off the screen, the
|
||||
way real redisplay would do. It does not alter the
|
||||
@code{window-start} value. In effect, it reports where the displayed
|
||||
text will end if scrolling is not required.
|
||||
|
||||
If @var{group} is non-@code{nil}, and @var{window} is a part of a
|
||||
group of windows (@pxref{Basic Windows}), `window-end' returns the end
|
||||
position of the entire group. This condition holds when the buffer
|
||||
local variable @code{window-end-group-function} is set to a function.
|
||||
In this case, @code{window-end} calls the function with the two
|
||||
arguments @var{window} and @var{update}, then returns its result,
|
||||
instead of performing the actions described above. Typically, the
|
||||
function will call @code{window-end} recursively.
|
||||
@end defun
|
||||
|
||||
@defun set-window-start window position &optional noforce
|
||||
@vindex set-window-start-group-function
|
||||
@defun set-window-start window position &optional noforce group
|
||||
This function sets the display-start position of @var{window} to
|
||||
@var{position} in @var{window}'s buffer. It returns @var{position}.
|
||||
|
||||
@ -3169,9 +3214,20 @@ it is still 1 when redisplay occurs. Here is an example:
|
||||
If @var{noforce} is non-@code{nil}, and @var{position} would place point
|
||||
off screen at the next redisplay, then redisplay computes a new window-start
|
||||
position that works well with point, and thus @var{position} is not used.
|
||||
|
||||
If @var{group} is non-@code{nil}, and @var{window} is a part of a
|
||||
group of windows (@pxref{Basic Windows}), @code{set-window-start} sets
|
||||
the start position of the entire group. This condition holds when the
|
||||
buffer local variable @code{set-window-start-group-function} is set to
|
||||
a function. In this case, @code{set-window-start} calls the function
|
||||
with the three arguments @var{window}, @var{position}, and
|
||||
@var{noforce}, then returns its result, instead of performing the
|
||||
actions described above. Typically, the function will call
|
||||
@code{set-window-start} recursively.
|
||||
@end defun
|
||||
|
||||
@defun pos-visible-in-window-p &optional position window partially
|
||||
@defun pos-visible-in-window-p &optional position window partially group
|
||||
@vindex pos-visible-in-window-p-group-function
|
||||
This function returns non-@code{nil} if @var{position} is within the
|
||||
range of text currently visible on the screen in @var{window}. It
|
||||
returns @code{nil} if @var{position} is scrolled vertically out of
|
||||
@ -3210,6 +3266,18 @@ Here is an example:
|
||||
(recenter 0))
|
||||
@end group
|
||||
@end example
|
||||
|
||||
If @var{group} is non-@code{nil}, and @var{window} is a part of a
|
||||
group of windows (@pxref{Basic Windows}),
|
||||
@code{pos-visible-in-window-p} tests the visibility of @var{pos} in
|
||||
the entire group, not just in the single @var{window}. This condition
|
||||
holds when the buffer local variable
|
||||
@code{pos-visible-in-window-p-group-function} is set to a function.
|
||||
In this case @code{pos-visible-in-window-p} calls the function with
|
||||
the three arguments @var{position}, @var{window}, and @var{partially},
|
||||
then returns its result, instead of performing the actions described
|
||||
above. Typically, the function will call
|
||||
@code{pos-visible-in-window-p} recursively.
|
||||
@end defun
|
||||
|
||||
@defun window-line-height &optional line window
|
||||
@ -3427,7 +3495,8 @@ beginning or end of the buffer (depending on scrolling direction);
|
||||
only if point is already on that position do they signal an error.
|
||||
@end defopt
|
||||
|
||||
@deffn Command recenter &optional count
|
||||
@deffn Command recenter &optional count group
|
||||
@vindex recenter-group-function
|
||||
@cindex centering point
|
||||
This function scrolls the text in the selected window so that point is
|
||||
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),
|
||||
window. If @var{count} is @code{nil}, this function may redraw the
|
||||
frame, according to the value of @code{recenter-redisplay}.
|
||||
|
||||
If @var{group} is non-@code{nil}, and the selected window is part of a
|
||||
group of windows (@pxref{Basic Windows}), @code{recenter} scrolls the
|
||||
entire group. This condition holds when the buffer local variable
|
||||
@code{recenter-group-function} is set to a function. In this case,
|
||||
@code{recenter} calls the function with the argument @var{count}, then
|
||||
returns its result, instead of performing the actions described above.
|
||||
Typically, the function will call @code{recenter} recursively.
|
||||
|
||||
When @code{recenter} is called interactively, @var{count} is the raw
|
||||
prefix argument. Thus, typing @kbd{C-u} as the prefix sets the
|
||||
@var{count} to a non-@code{nil} list, while typing @kbd{C-u 4} sets
|
||||
|
193
lisp/follow.el
193
lisp/follow.el
@ -421,7 +421,19 @@ Keys specific to Follow mode:
|
||||
(progn
|
||||
(add-hook 'compilation-filter-hook 'follow-align-compilation-windows t t)
|
||||
(add-hook 'post-command-hook 'follow-post-command-hook t)
|
||||
(add-hook 'window-size-change-functions 'follow-window-size-change t))
|
||||
(add-hook 'window-size-change-functions 'follow-window-size-change t)
|
||||
(add-hook 'after-change-functions 'follow-after-change nil t)
|
||||
|
||||
(setq window-start-group-function 'follow-window-start)
|
||||
(setq window-end-group-function 'follow-window-end)
|
||||
(setq set-window-start-group-function 'follow-set-window-start)
|
||||
(setq recenter-group-function 'follow-recenter)
|
||||
(setq pos-visible-in-window-p-group-function
|
||||
'follow-pos-visible-in-window-p)
|
||||
(setq selected-window-group-function 'follow-all-followers)
|
||||
(setq move-to-window-line-group-function 'follow-move-to-window-line)
|
||||
(setq sit*-for-function 'follow-sit-for))
|
||||
|
||||
;; Remove globally-installed hook functions only if there is no
|
||||
;; other Follow mode buffer.
|
||||
(let ((buffers (buffer-list))
|
||||
@ -432,6 +444,17 @@ Keys specific to Follow mode:
|
||||
(unless following
|
||||
(remove-hook 'post-command-hook 'follow-post-command-hook)
|
||||
(remove-hook 'window-size-change-functions 'follow-window-size-change)))
|
||||
|
||||
(kill-local-variable 'sit*-for-function)
|
||||
(kill-local-variable 'move-to-window-line-group-function)
|
||||
(kill-local-variable 'selected-window-group-function)
|
||||
(kill-local-variable 'pos-visible-in-window-p-group-function)
|
||||
(kill-local-variable 'recenter-group-function)
|
||||
(kill-local-variable 'set-window-start-group-function)
|
||||
(kill-local-variable 'window-end-group-function)
|
||||
(kill-local-variable 'window-start-group-function)
|
||||
|
||||
(remove-hook 'after-change-functions 'follow-after-change t)
|
||||
(remove-hook 'compilation-filter-hook 'follow-align-compilation-windows t)))
|
||||
|
||||
(defun follow-find-file-hook ()
|
||||
@ -1015,6 +1038,10 @@ Otherwise, return nil."
|
||||
;; is nil. Start every window directly after the end of the previous
|
||||
;; window, to make sure long lines are displayed correctly.
|
||||
|
||||
(defvar follow-start-end-invalid t
|
||||
"When non-nil, indicates `follow-windows-start-end-cache' is invalid.")
|
||||
(make-variable-buffer-local 'follow-start-end-invalid)
|
||||
|
||||
(defun follow-redisplay (&optional windows win preserve-win)
|
||||
"Reposition the WINDOWS around WIN.
|
||||
Should point be too close to the roof we redisplay everything
|
||||
@ -1047,7 +1074,8 @@ repositioning the other windows."
|
||||
(dolist (w windows)
|
||||
(unless (and preserve-win (eq w win))
|
||||
(set-window-start w start))
|
||||
(setq start (car (follow-calc-win-end w))))))
|
||||
(setq start (car (follow-calc-win-end w))))
|
||||
(setq follow-start-end-invalid nil)))
|
||||
|
||||
(defun follow-estimate-first-window-start (windows win start)
|
||||
"Estimate the position of the first window.
|
||||
@ -1446,6 +1474,167 @@ non-first windows in Follow mode."
|
||||
|
||||
(add-hook 'window-scroll-functions 'follow-avoid-tail-recenter t)
|
||||
|
||||
;;; Low level window start and end.
|
||||
|
||||
;; These routines are the Follow Mode versions of the low level
|
||||
;; functions described on page "Window Start and End" of the elisp
|
||||
;; manual, e.g. `window*-start'. The aim is to be able to handle
|
||||
;; Follow Mode windows by replacing `window-start' by `window*-start',
|
||||
;; etc.
|
||||
|
||||
(defun follow-after-change (_beg _end _old-len)
|
||||
"After change function: set `follow-start-end-invalid'."
|
||||
(setq follow-start-end-invalid t))
|
||||
|
||||
(defun follow-window-start (&optional window)
|
||||
"Return position at which display currently starts in the
|
||||
Follow Mode group of windows which includes WINDOW.
|
||||
|
||||
WINDOW must be a live window and defaults to the selected one.
|
||||
This is updated by redisplay or by calling
|
||||
`follow-set-window-start'."
|
||||
(let ((windows (follow-all-followers window)))
|
||||
(window-start (car windows))))
|
||||
|
||||
(defun follow-window-end (&optional window update)
|
||||
"Return position at which display currently ends in the Follow
|
||||
Mode group of windows which includes WINDOW.
|
||||
|
||||
WINDOW must be a live window and defaults to the selected one.
|
||||
This is updated by redisplay, when it runs to completion.
|
||||
Simply changing the buffer text or setting `window-start' does
|
||||
not update this value.
|
||||
|
||||
Return nil if there is no recorded value. (This can happen if
|
||||
the last redisplay of WINDOW was preempted, and did not
|
||||
finish.) If UPDATE is non-nil, compute the up-to-date position
|
||||
if it isn't already recorded."
|
||||
(let* ((windows (follow-all-followers window))
|
||||
(last (car (last windows))))
|
||||
(when (and update follow-start-end-invalid)
|
||||
(follow-redisplay windows (car windows)))
|
||||
(window-end last update)))
|
||||
|
||||
(defun follow-set-window-start (window pos &optional noforce)
|
||||
"Make display in the Follow Mode group of windows which includes
|
||||
WINDOW start at position POS in WINDOW's buffer.
|
||||
|
||||
WINDOW must be a live window and defaults to the selected one. Return
|
||||
POS. Optional third arg NOFORCE non-nil inhibits next redisplay from
|
||||
overriding motion of point in order to display at this exact start."
|
||||
(let ((windows (follow-all-followers window)))
|
||||
(setq follow-start-end-invalid t)
|
||||
(set-window-start (car windows) pos noforce)))
|
||||
|
||||
(defun follow-pos-visible-in-window-p (&optional pos window partially)
|
||||
"Return non-nil if position POS is currently on the frame in one of
|
||||
the windows in the Follow Mode group which includes WINDOW.
|
||||
|
||||
WINDOW must be a live window and defaults to the selected one.
|
||||
|
||||
Return nil if that position is scrolled vertically out of view. If a
|
||||
character is only partially visible, nil is returned, unless the
|
||||
optional argument PARTIALLY is non-nil. If POS is only out of view
|
||||
because of horizontal scrolling, return non-nil. If POS is t, it
|
||||
specifies the position of the last visible glyph in WINDOW. POS
|
||||
defaults to point in WINDOW; WINDOW defaults to the selected window.
|
||||
|
||||
If POS is visible, return t if PARTIALLY is nil; if PARTIALLY is non-nil,
|
||||
the return value is a list of 2 or 6 elements (X Y [RTOP RBOT ROWH VPOS]),
|
||||
where X and Y are the pixel coordinates relative to the top left corner
|
||||
of the actual window containing it. The remaining elements are
|
||||
omitted if the character after POS is fully visible; otherwise, RTOP
|
||||
and RBOT are the number of pixels off-window at the top and bottom of
|
||||
the screen line (\"row\") containing POS, ROWH is the visible height
|
||||
of that row, and VPOS is the row number \(zero-based)."
|
||||
(let* ((windows (follow-all-followers window))
|
||||
(last (car (last windows))))
|
||||
(when follow-start-end-invalid
|
||||
(follow-redisplay windows (car windows)))
|
||||
(let* ((cache (follow-windows-start-end windows))
|
||||
(last-elt (car (last cache)))
|
||||
our-pos pertinent-elt)
|
||||
(setq pertinent-elt
|
||||
(if (eq pos t)
|
||||
last-elt
|
||||
(setq our-pos (or pos (point)))
|
||||
(catch 'element
|
||||
(while cache
|
||||
(when (< our-pos (nth 2 (car cache)))
|
||||
(throw 'element (car cache)))
|
||||
(setq cache (cdr cache)))
|
||||
last-elt)))
|
||||
(pos-visible-in-window-p our-pos (car pertinent-elt) partially))))
|
||||
|
||||
(defun follow-move-to-window-line (arg)
|
||||
"Position point relative to the Follow mode group containing the selected window.
|
||||
ARG nil means position point at center of the window group.
|
||||
Else, ARG specifies vertical position within the window group;
|
||||
zero means top of the first window in the group, negative means
|
||||
relative to bottom of the last window in the group."
|
||||
(let* ((windows (follow-all-followers))
|
||||
(start-end (follow-windows-start-end windows))
|
||||
(rev-start-end (reverse start-end))
|
||||
(lines 0)
|
||||
middle-window elt count)
|
||||
(select-window
|
||||
(cond
|
||||
((null arg)
|
||||
(setq rev-start-end (nthcdr (/ (length windows) 2) rev-start-end))
|
||||
(prog1 (car (car rev-start-end))
|
||||
(while (setq rev-start-end (cdr rev-start-end))
|
||||
(setq elt (car rev-start-end)
|
||||
count (count-screen-lines (cadr elt) (nth 2 elt)
|
||||
nil (car elt))
|
||||
lines (+ lines count)))))
|
||||
((>= arg 0)
|
||||
(while (and (cdr start-end)
|
||||
(progn
|
||||
(setq elt (car start-end)
|
||||
count (count-screen-lines (cadr elt) (nth 2 elt)
|
||||
nil (car elt)))
|
||||
(>= arg count)))
|
||||
(setq arg (- arg count)
|
||||
lines (+ lines count)
|
||||
start-end (cdr start-end)))
|
||||
(car (car start-end)))
|
||||
(t ; (< arg 0)
|
||||
(while (and (cadr rev-start-end)
|
||||
(progn
|
||||
(setq elt (car rev-start-end)
|
||||
count (count-lines (cadr elt) (nth 2 elt)))
|
||||
(<= arg (- count))))
|
||||
(setq arg (+ arg count)
|
||||
rev-start-end (cdr rev-start-end)))
|
||||
(prog1 (car (car rev-start-end))
|
||||
(while (setq rev-start-end (cdr rev-start-end))
|
||||
(setq elt (car rev-start-end)
|
||||
count (count-screen-lines (cadr elt) (nth 2 elt)
|
||||
nil (car elt))
|
||||
lines (+ lines count)))))))
|
||||
(+ lines (move-to-window-line arg))))
|
||||
|
||||
(defun follow-sit-for (seconds &optional nodisp)
|
||||
"Redisplay, then wait for SECONDS seconds. Stop when input is available.
|
||||
Before redisplaying, synchronise all Follow windows.
|
||||
|
||||
SECONDS may be a floating-point value.
|
||||
\(On operating systems that do not support waiting for fractions of a
|
||||
second, floating-point values are rounded down to the nearest integer.)
|
||||
|
||||
Redisplay does not happen if input is available before it starts.
|
||||
If optional arg NODISP is t, don't synchronise or redisplay, just
|
||||
wait for input.
|
||||
|
||||
Value is t if waited the full time with no input arriving, and nil
|
||||
otherwise.
|
||||
|
||||
The functionality is intended to be the same as `sit-for''s."
|
||||
(when (and (not (input-pending-p t))
|
||||
(not nodisp))
|
||||
(follow-adjust-window (selected-window)))
|
||||
(sit-for seconds nodisp))
|
||||
|
||||
;;; Profile support
|
||||
|
||||
;; The following (non-evaluated) section can be used to
|
||||
|
133
lisp/isearch.el
133
lisp/isearch.el
@ -171,6 +171,11 @@ is non-nil if the user quits the search.")
|
||||
"Function to call to display the search prompt.
|
||||
If nil, use function `isearch-message'.")
|
||||
|
||||
(defmacro isearch-call-message (&optional cqh ellip)
|
||||
`(if isearch-message-function
|
||||
(funcall isearch-message-function ,cqh ,ellip)
|
||||
(isearch-message ,cqh ,ellip)))
|
||||
|
||||
(defvar isearch-wrap-function nil
|
||||
"Function to call to wrap the search when search is failed.
|
||||
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'."
|
||||
(null executing-kbd-macro))
|
||||
(progn
|
||||
(if (not (input-pending-p))
|
||||
(if isearch-message-function
|
||||
(funcall isearch-message-function)
|
||||
(isearch-message)))
|
||||
(isearch-call-message))
|
||||
(if (and isearch-slow-terminal-mode
|
||||
(not (or isearch-small-window
|
||||
(pos-visible-in-window-p))))
|
||||
(pos-visible-in-window-p nil nil nil t))))
|
||||
(let ((found-point (point)))
|
||||
(setq isearch-small-window t)
|
||||
(move-to-window-line 0)
|
||||
@ -995,7 +998,7 @@ The last thing it does is to run `isearch-update-post-hook'."
|
||||
(let ((current-scroll (window-hscroll))
|
||||
visible-p)
|
||||
(set-window-hscroll (selected-window) isearch-start-hscroll)
|
||||
(setq visible-p (pos-visible-in-window-p nil nil t))
|
||||
(setq visible-p (pos-visible-in-window-p nil nil t t))
|
||||
(if (or (not visible-p)
|
||||
;; When point is not visible because of hscroll,
|
||||
;; pos-visible-in-window-p returns non-nil, but
|
||||
@ -1049,7 +1052,7 @@ NOPUSH is t and EDIT is t."
|
||||
(setq minibuffer-message-timeout isearch-original-minibuffer-message-timeout)
|
||||
(isearch-dehighlight)
|
||||
(lazy-highlight-cleanup lazy-highlight-cleanup)
|
||||
(let ((found-start (window-start))
|
||||
(let ((found-start (window-start nil t))
|
||||
(found-point (point)))
|
||||
(when isearch-window-configuration
|
||||
(set-window-configuration isearch-window-configuration)
|
||||
@ -1059,7 +1062,7 @@ NOPUSH is t and EDIT is t."
|
||||
;; This has an annoying side effect of clearing the last_modiff
|
||||
;; field of the window, which can cause unwanted scrolling,
|
||||
;; so don't do it unless truly necessary.
|
||||
(set-window-start (selected-window) found-start t))))
|
||||
(set-window-start (selected-window) found-start t t))))
|
||||
|
||||
(setq isearch-mode nil)
|
||||
(if isearch-input-method-local-p
|
||||
@ -1282,13 +1285,6 @@ You can update the global isearch variables by setting new values to
|
||||
(unwind-protect
|
||||
(progn ,@body)
|
||||
|
||||
;; Set point at the start (end) of old match if forward (backward),
|
||||
;; so after exiting minibuffer isearch resumes at the start (end)
|
||||
;; of this match and can find it again.
|
||||
(if (and old-other-end (eq old-point (point))
|
||||
(eq isearch-forward isearch-new-forward))
|
||||
(goto-char old-other-end))
|
||||
|
||||
;; Always resume isearching by restarting it.
|
||||
(isearch-mode isearch-forward
|
||||
isearch-regexp
|
||||
@ -1301,7 +1297,17 @@ You can update the global isearch variables by setting new values to
|
||||
isearch-message isearch-new-message
|
||||
isearch-forward isearch-new-forward
|
||||
isearch-regexp-function isearch-new-regexp-function
|
||||
isearch-case-fold-search isearch-new-case-fold))
|
||||
isearch-case-fold-search isearch-new-case-fold)
|
||||
|
||||
;; Restore the minibuffer message before moving point.
|
||||
(isearch-call-message nil t)
|
||||
|
||||
;; Set point at the start (end) of old match if forward (backward),
|
||||
;; so after exiting minibuffer isearch resumes at the start (end)
|
||||
;; of this match and can find it again.
|
||||
(if (and old-other-end (eq old-point (point))
|
||||
(eq isearch-forward isearch-new-forward))
|
||||
(goto-char old-other-end)))
|
||||
|
||||
;; Empty isearch-string means use default.
|
||||
(when (= 0 (length isearch-string))
|
||||
@ -1895,6 +1901,7 @@ If search string is empty, just beep."
|
||||
(length isearch-string))))
|
||||
isearch-message (mapconcat 'isearch-text-char-description
|
||||
isearch-string "")))
|
||||
(isearch-call-message nil t) ; Do this before moving point.
|
||||
;; Use the isearch-other-end as new starting point to be able
|
||||
;; to find the remaining part of the search string again.
|
||||
;; This is like what `isearch-search-and-update' does,
|
||||
@ -2071,6 +2078,7 @@ With argument, add COUNT copies of the character."
|
||||
(setq isearch-case-fold-search
|
||||
(isearch-no-upper-case-p isearch-string isearch-regexp))))
|
||||
;; Not regexp, not reverse, or no match at point.
|
||||
(isearch-call-message nil t) ; Do this before moving point.
|
||||
(if (and isearch-other-end (not isearch-adjusted))
|
||||
(goto-char (if isearch-forward isearch-other-end
|
||||
(min isearch-opoint
|
||||
@ -2237,10 +2245,12 @@ Return nil if it's completely visible, or if point is visible,
|
||||
together with as much of the search string as will fit; the symbol
|
||||
`above' if we need to scroll the text downwards; the symbol `below',
|
||||
if upwards."
|
||||
(let ((w-start (window-start))
|
||||
(w-end (window-end nil t))
|
||||
(w-L1 (save-excursion (move-to-window-line 1) (point)))
|
||||
(w-L-1 (save-excursion (move-to-window-line -1) (point)))
|
||||
(let ((w-start (window-start nil t))
|
||||
(w-end (window-end nil t t))
|
||||
(w-L1 (save-excursion
|
||||
(save-selected-window (move-to-window-line 1 t) (point))))
|
||||
(w-L-1 (save-excursion
|
||||
(save-selected-window (move-to-window-line -1 t) (point))))
|
||||
start end) ; start and end of search string in buffer
|
||||
(if isearch-forward
|
||||
(setq end isearch-point start (or isearch-other-end isearch-point))
|
||||
@ -2267,15 +2277,15 @@ the bottom."
|
||||
(if above
|
||||
(progn
|
||||
(goto-char start)
|
||||
(recenter 0)
|
||||
(when (>= isearch-point (window-end nil t))
|
||||
(recenter 0 t)
|
||||
(when (>= isearch-point (window-end nil t t))
|
||||
(goto-char isearch-point)
|
||||
(recenter -1)))
|
||||
(recenter -1 t)))
|
||||
(goto-char end)
|
||||
(recenter -1)
|
||||
(when (< isearch-point (window-start))
|
||||
(recenter -1 t)
|
||||
(when (< isearch-point (window-start nil t))
|
||||
(goto-char isearch-point)
|
||||
(recenter 0))))
|
||||
(recenter 0 t))))
|
||||
(goto-char isearch-point))
|
||||
|
||||
(defvar isearch-pre-scroll-point nil)
|
||||
@ -2422,6 +2432,7 @@ Search is updated accordingly."
|
||||
(isearch-ring-adjust1 advance)
|
||||
(if search-ring-update
|
||||
(progn
|
||||
(isearch-call-message nil t)
|
||||
(isearch-search)
|
||||
(isearch-push-state)
|
||||
(isearch-update))
|
||||
@ -2494,6 +2505,13 @@ If there is no completion possible, say so and continue searching."
|
||||
|
||||
(defun isearch-message (&optional c-q-hack ellipsis)
|
||||
;; Generate and print the message string.
|
||||
|
||||
;; N.B.: This function should always be called with point at the
|
||||
;; search point, because in certain (rare) circumstances, undesired
|
||||
;; scrolling can happen when point is elsewhere. These
|
||||
;; circumstances are when follow-mode is active, the search string
|
||||
;; spans two (or several) windows, and the message about to be
|
||||
;; displayed will cause the echo area to expand.
|
||||
(let ((cursor-in-echo-area ellipsis)
|
||||
(m isearch-message)
|
||||
(fail-pos (isearch-fail-pos t)))
|
||||
@ -2680,9 +2698,6 @@ update the match data, and return point."
|
||||
|
||||
(defun isearch-search ()
|
||||
;; Do the search with the current search string.
|
||||
(if isearch-message-function
|
||||
(funcall isearch-message-function nil t)
|
||||
(isearch-message nil t))
|
||||
(if (and (eq isearch-case-fold-search t) search-upper-case)
|
||||
(setq isearch-case-fold-search
|
||||
(isearch-no-upper-case-p isearch-string isearch-regexp)))
|
||||
@ -2980,6 +2995,7 @@ since they have special meaning in a regexp."
|
||||
(defvar isearch-lazy-highlight-timer nil)
|
||||
(defvar isearch-lazy-highlight-last-string nil)
|
||||
(defvar isearch-lazy-highlight-window nil)
|
||||
(defvar isearch-lazy-highlight-window-group nil)
|
||||
(defvar isearch-lazy-highlight-window-start nil)
|
||||
(defvar isearch-lazy-highlight-window-end nil)
|
||||
(defvar isearch-lazy-highlight-case-fold-search nil)
|
||||
@ -3012,7 +3028,21 @@ is nil. This function is called when exiting an incremental search if
|
||||
"22.1")
|
||||
|
||||
(defun isearch-lazy-highlight-new-loop (&optional beg end)
|
||||
"Cleanup any previous `lazy-highlight' loop and begin a new one.
|
||||
"Set an idle timer, which will trigger a new `lazy-highlight' loop.
|
||||
BEG and END specify the bounds within which highlighting should
|
||||
occur. This is called when `isearch-update' is invoked (which
|
||||
can cause the search string to change or the window(s) to
|
||||
scroll). It is also used by other Emacs features. Do not start
|
||||
the loop when we are executing a keyboard macro."
|
||||
(setq isearch-lazy-highlight-start-limit beg
|
||||
isearch-lazy-highlight-end-limit end)
|
||||
(when (null executing-kbd-macro)
|
||||
(setq isearch-lazy-highlight-timer
|
||||
(run-with-idle-timer lazy-highlight-initial-delay nil
|
||||
'isearch-lazy-highlight-maybe-new-loop))))
|
||||
|
||||
(defun isearch-lazy-highlight-maybe-new-loop ()
|
||||
"If needed cleanup any previous `lazy-highlight' loop and begin a new one.
|
||||
BEG and END specify the bounds within which highlighting should occur.
|
||||
This is called when `isearch-update' is invoked (which can cause the
|
||||
search string to change or the window to scroll). It is also used
|
||||
@ -3021,8 +3051,8 @@ by other Emacs features."
|
||||
(sit-for 0) ;make sure (window-start) is credible
|
||||
(or (not (equal isearch-string
|
||||
isearch-lazy-highlight-last-string))
|
||||
(not (eq (selected-window)
|
||||
isearch-lazy-highlight-window))
|
||||
(not (memq (selected-window)
|
||||
isearch-lazy-highlight-window-group))
|
||||
(not (eq isearch-lazy-highlight-case-fold-search
|
||||
isearch-case-fold-search))
|
||||
(not (eq isearch-lazy-highlight-regexp
|
||||
@ -3033,9 +3063,9 @@ by other Emacs features."
|
||||
isearch-lax-whitespace))
|
||||
(not (eq isearch-lazy-highlight-regexp-lax-whitespace
|
||||
isearch-regexp-lax-whitespace))
|
||||
(not (= (window-start)
|
||||
(not (= (window-start nil t)
|
||||
isearch-lazy-highlight-window-start))
|
||||
(not (= (window-end) ; Window may have been split/joined.
|
||||
(not (= (window-end nil nil t) ; Window may have been split/joined.
|
||||
isearch-lazy-highlight-window-end))
|
||||
(not (eq isearch-forward
|
||||
isearch-lazy-highlight-forward))
|
||||
@ -3043,16 +3073,15 @@ by other Emacs features."
|
||||
(not (equal isearch-error
|
||||
isearch-lazy-highlight-error))))
|
||||
;; something important did indeed change
|
||||
(lazy-highlight-cleanup t) ;kill old loop & remove overlays
|
||||
(lazy-highlight-cleanup t) ;kill old loop & remove overlays
|
||||
(setq isearch-lazy-highlight-error isearch-error)
|
||||
;; It used to check for `(not isearch-error)' here, but actually
|
||||
;; lazy-highlighting might find matches to highlight even when
|
||||
;; `isearch-error' is non-nil. (Bug#9918)
|
||||
(setq isearch-lazy-highlight-start-limit beg
|
||||
isearch-lazy-highlight-end-limit end)
|
||||
(setq isearch-lazy-highlight-window (selected-window)
|
||||
isearch-lazy-highlight-window-start (window-start)
|
||||
isearch-lazy-highlight-window-end (window-end)
|
||||
isearch-lazy-highlight-window-group (selected-window-group)
|
||||
isearch-lazy-highlight-window-start (window-start nil t)
|
||||
isearch-lazy-highlight-window-end (window-end nil nil t)
|
||||
;; Start lazy-highlighting at the beginning of the found
|
||||
;; match (`isearch-other-end'). If no match, use point.
|
||||
;; One of the next two variables (depending on search direction)
|
||||
@ -3070,10 +3099,8 @@ by other Emacs features."
|
||||
isearch-lazy-highlight-regexp-lax-whitespace isearch-regexp-lax-whitespace
|
||||
isearch-lazy-highlight-regexp-function isearch-regexp-function
|
||||
isearch-lazy-highlight-forward isearch-forward)
|
||||
(unless (equal isearch-string "")
|
||||
(setq isearch-lazy-highlight-timer
|
||||
(run-with-idle-timer lazy-highlight-initial-delay nil
|
||||
'isearch-lazy-highlight-update)))))
|
||||
(unless (equal isearch-string "")
|
||||
(isearch-lazy-highlight-update))))
|
||||
|
||||
(defun isearch-lazy-highlight-search ()
|
||||
"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."
|
||||
(+ isearch-lazy-highlight-start
|
||||
;; Extend bound to match whole string at point
|
||||
(1- (length isearch-lazy-highlight-last-string)))
|
||||
(window-end)))
|
||||
(window-end nil nil t)))
|
||||
(max (or isearch-lazy-highlight-start-limit (point-min))
|
||||
(if isearch-lazy-highlight-wrapped
|
||||
(- isearch-lazy-highlight-end
|
||||
;; Extend bound to match whole string at point
|
||||
(1- (length isearch-lazy-highlight-last-string)))
|
||||
(window-start))))))
|
||||
(window-start nil t))))))
|
||||
;; Use a loop like in `isearch-search'.
|
||||
(while retry
|
||||
(setq success (isearch-search-string
|
||||
@ -3126,7 +3153,7 @@ Attempt to do the search exactly the way the pending Isearch would."
|
||||
(with-local-quit
|
||||
(save-selected-window
|
||||
(if (and (window-live-p isearch-lazy-highlight-window)
|
||||
(not (eq (selected-window) isearch-lazy-highlight-window)))
|
||||
(not (memq (selected-window) isearch-lazy-highlight-window-group)))
|
||||
(select-window isearch-lazy-highlight-window))
|
||||
(save-excursion
|
||||
(save-match-data
|
||||
@ -3146,12 +3173,12 @@ Attempt to do the search exactly the way the pending Isearch would."
|
||||
(if isearch-lazy-highlight-forward
|
||||
(if (= mb (if isearch-lazy-highlight-wrapped
|
||||
isearch-lazy-highlight-start
|
||||
(window-end)))
|
||||
(window-end nil nil t)))
|
||||
(setq found nil)
|
||||
(forward-char 1))
|
||||
(if (= mb (if isearch-lazy-highlight-wrapped
|
||||
isearch-lazy-highlight-end
|
||||
(window-start)))
|
||||
(window-start nil t)))
|
||||
(setq found nil)
|
||||
(forward-char -1)))
|
||||
|
||||
@ -3161,8 +3188,8 @@ Attempt to do the search exactly the way the pending Isearch would."
|
||||
;; 1000 is higher than ediff's 100+,
|
||||
;; but lower than isearch main overlay's 1001
|
||||
(overlay-put ov 'priority 1000)
|
||||
(overlay-put ov 'face lazy-highlight-face)
|
||||
(overlay-put ov 'window (selected-window))))
|
||||
(overlay-put ov 'face lazy-highlight-face)))
|
||||
;(overlay-put ov 'window (selected-window))))
|
||||
;; Remember the current position of point for
|
||||
;; the next call of `isearch-lazy-highlight-update'
|
||||
;; 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."
|
||||
(setq isearch-lazy-highlight-wrapped t)
|
||||
(if isearch-lazy-highlight-forward
|
||||
(progn
|
||||
(setq isearch-lazy-highlight-end (window-start))
|
||||
(setq isearch-lazy-highlight-end (window-start nil t))
|
||||
(goto-char (max (or isearch-lazy-highlight-start-limit (point-min))
|
||||
(window-start))))
|
||||
(setq isearch-lazy-highlight-start (window-end))
|
||||
(window-start nil t))))
|
||||
(setq isearch-lazy-highlight-start (window-end nil nil t))
|
||||
(goto-char (min (or isearch-lazy-highlight-end-limit (point-max))
|
||||
(window-end))))))))
|
||||
(window-end nil nil t))))))))
|
||||
(unless nomore
|
||||
(setq isearch-lazy-highlight-timer
|
||||
(run-at-time lazy-highlight-interval nil
|
||||
|
@ -28,6 +28,17 @@
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defvar selected-window-group-function nil)
|
||||
(make-variable-buffer-local 'selected-window-group-function)
|
||||
(put 'selected-window-group-function 'permanent-local t)
|
||||
(defun selected-window-group ()
|
||||
"Return the list of windows in the group containing the selected window.
|
||||
When a grouping mode (such as Follow Mode) is not active, the
|
||||
result is a list containing only the selected window."
|
||||
(if (functionp selected-window-group-function)
|
||||
(funcall selected-window-group-function)
|
||||
(list (selected-window))))
|
||||
|
||||
(defun internal--before-save-selected-window ()
|
||||
(cons (selected-window)
|
||||
;; We save and restore all frames' selected windows, because
|
||||
|
@ -10663,7 +10663,7 @@ The `posn-' functions access elements of such lists. */)
|
||||
if (NILP (window))
|
||||
window = selected_window;
|
||||
|
||||
tem = Fpos_visible_in_window_p (pos, window, Qt);
|
||||
tem = Fpos_visible_in_window_p (pos, window, Qt, Qnil);
|
||||
if (!NILP (tem))
|
||||
{
|
||||
Lisp_Object x = XCAR (tem);
|
||||
|
712
src/window.c
712
src/window.c
@ -1540,13 +1540,23 @@ WINDOW must be a live window and defaults to the selected one. */)
|
||||
return Fmarker_position (decode_live_window (window)->old_pointm);
|
||||
}
|
||||
|
||||
DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
|
||||
DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 2, 0,
|
||||
doc: /* Return position at which display currently starts in WINDOW.
|
||||
WINDOW must be a live window and defaults to the selected one.
|
||||
This is updated by redisplay or by calling `set-window-start'. */)
|
||||
(Lisp_Object window)
|
||||
This is updated by redisplay or by calling `set-window-start'.
|
||||
|
||||
If GROUP is non-nil, and WINDOW is part of a group of windows collectively
|
||||
displaying a buffer (such as with Follow Mode), return the start position of
|
||||
the group rather than of the individual WINDOW. This condition holds when
|
||||
`window-start-group-function' is set to a function, in which case
|
||||
`window-start' calls the function with the argument WINDOW, then returns its
|
||||
result, instead of doing its normal processing. */)
|
||||
(Lisp_Object window, Lisp_Object group)
|
||||
{
|
||||
return Fmarker_position (decode_live_window (window)->start);
|
||||
return (!NILP (group)
|
||||
&& FUNCTIONP (Vwindow_start_group_function))
|
||||
? call1 (Vwindow_start_group_function, window)
|
||||
: Fmarker_position (decode_live_window (window)->start);
|
||||
}
|
||||
|
||||
/* This is text temporarily removed from the doc string below.
|
||||
@ -1560,7 +1570,7 @@ have been if redisplay had finished, do this:
|
||||
(vertical-motion (1- (window-height window)) window)
|
||||
(point))") */
|
||||
|
||||
DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0,
|
||||
DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 3, 0,
|
||||
doc: /* Return position at which display currently ends in WINDOW.
|
||||
WINDOW must be a live window and defaults to the selected one.
|
||||
This is updated by redisplay, when it runs to completion.
|
||||
@ -1569,65 +1579,77 @@ does not update this value.
|
||||
Return nil if there is no recorded value. (This can happen if the
|
||||
last redisplay of WINDOW was preempted, and did not finish.)
|
||||
If UPDATE is non-nil, compute the up-to-date position
|
||||
if it isn't already recorded. */)
|
||||
(Lisp_Object window, Lisp_Object update)
|
||||
if it isn't already recorded.
|
||||
|
||||
If GROUP is non-nil, and WINDOW is part of a group of windows collectively
|
||||
displaying a buffer (such as with Follow Mode), return the end position of
|
||||
the group rather than of the individual WINDOW. This condition holds when
|
||||
`window-end-group-function' is set to a function, in which case `window-end'
|
||||
calls the function with the two arguments WINDOW and UPDATE, then returns its
|
||||
result, instead of doing its normal processing. */)
|
||||
(Lisp_Object window, Lisp_Object update, Lisp_Object group)
|
||||
{
|
||||
Lisp_Object value;
|
||||
struct window *w = decode_live_window (window);
|
||||
Lisp_Object buf;
|
||||
struct buffer *b;
|
||||
if (!NILP (group)
|
||||
&& FUNCTIONP (Vwindow_end_group_function))
|
||||
return call2 (Vwindow_end_group_function, window, update);
|
||||
{
|
||||
Lisp_Object value;
|
||||
struct window *w = decode_live_window (window);
|
||||
Lisp_Object buf;
|
||||
struct buffer *b;
|
||||
|
||||
buf = w->contents;
|
||||
CHECK_BUFFER (buf);
|
||||
b = XBUFFER (buf);
|
||||
buf = w->contents;
|
||||
CHECK_BUFFER (buf);
|
||||
b = XBUFFER (buf);
|
||||
|
||||
if (! NILP (update)
|
||||
&& (windows_or_buffers_changed
|
||||
|| !w->window_end_valid
|
||||
|| b->clip_changed
|
||||
|| b->prevent_redisplay_optimizations_p
|
||||
|| window_outdated (w))
|
||||
/* Don't call display routines if we didn't yet create any real
|
||||
frames, because the glyph matrices are not yet allocated in
|
||||
that case. This could happen in some code that runs in the
|
||||
daemon during initialization (e.g., see bug#20565). */
|
||||
&& !(noninteractive || FRAME_INITIAL_P (WINDOW_XFRAME (w))))
|
||||
{
|
||||
struct text_pos startp;
|
||||
struct it it;
|
||||
struct buffer *old_buffer = NULL;
|
||||
void *itdata = NULL;
|
||||
if (! NILP (update)
|
||||
&& (windows_or_buffers_changed
|
||||
|| !w->window_end_valid
|
||||
|| b->clip_changed
|
||||
|| b->prevent_redisplay_optimizations_p
|
||||
|| window_outdated (w))
|
||||
/* Don't call display routines if we didn't yet create any real
|
||||
frames, because the glyph matrices are not yet allocated in
|
||||
that case. This could happen in some code that runs in the
|
||||
daemon during initialization (e.g., see bug#20565). */
|
||||
&& !(noninteractive || FRAME_INITIAL_P (WINDOW_XFRAME (w))))
|
||||
{
|
||||
struct text_pos startp;
|
||||
struct it it;
|
||||
struct buffer *old_buffer = NULL;
|
||||
void *itdata = NULL;
|
||||
|
||||
/* Cannot use Fvertical_motion because that function doesn't
|
||||
cope with variable-height lines. */
|
||||
if (b != current_buffer)
|
||||
{
|
||||
old_buffer = current_buffer;
|
||||
set_buffer_internal (b);
|
||||
}
|
||||
/* Cannot use Fvertical_motion because that function doesn't
|
||||
cope with variable-height lines. */
|
||||
if (b != current_buffer)
|
||||
{
|
||||
old_buffer = current_buffer;
|
||||
set_buffer_internal (b);
|
||||
}
|
||||
|
||||
/* In case W->start is out of the range, use something
|
||||
reasonable. This situation occurred when loading a file with
|
||||
`-l' containing a call to `rmail' with subsequent other
|
||||
commands. At the end, W->start happened to be BEG, while
|
||||
rmail had already narrowed the buffer. */
|
||||
CLIP_TEXT_POS_FROM_MARKER (startp, w->start);
|
||||
/* In case W->start is out of the range, use something
|
||||
reasonable. This situation occurred when loading a file with
|
||||
`-l' containing a call to `rmail' with subsequent other
|
||||
commands. At the end, W->start happened to be BEG, while
|
||||
rmail had already narrowed the buffer. */
|
||||
CLIP_TEXT_POS_FROM_MARKER (startp, w->start);
|
||||
|
||||
itdata = bidi_shelve_cache ();
|
||||
start_display (&it, w, startp);
|
||||
move_it_vertically (&it, window_box_height (w));
|
||||
if (it.current_y < it.last_visible_y)
|
||||
move_it_past_eol (&it);
|
||||
value = make_number (IT_CHARPOS (it));
|
||||
bidi_unshelve_cache (itdata, false);
|
||||
itdata = bidi_shelve_cache ();
|
||||
start_display (&it, w, startp);
|
||||
move_it_vertically (&it, window_box_height (w));
|
||||
if (it.current_y < it.last_visible_y)
|
||||
move_it_past_eol (&it);
|
||||
value = make_number (IT_CHARPOS (it));
|
||||
bidi_unshelve_cache (itdata, false);
|
||||
|
||||
if (old_buffer)
|
||||
set_buffer_internal (old_buffer);
|
||||
}
|
||||
else
|
||||
XSETINT (value, BUF_Z (b) - w->window_end_pos);
|
||||
if (old_buffer)
|
||||
set_buffer_internal (old_buffer);
|
||||
}
|
||||
else
|
||||
XSETINT (value, BUF_Z (b) - w->window_end_pos);
|
||||
|
||||
return value;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
|
||||
@ -1666,30 +1688,43 @@ Return POS. */)
|
||||
return pos;
|
||||
}
|
||||
|
||||
DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
|
||||
DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 4, 0,
|
||||
doc: /* Make display in WINDOW start at position POS in WINDOW's buffer.
|
||||
WINDOW must be a live window and defaults to the selected one. Return
|
||||
POS. Optional third arg NOFORCE non-nil inhibits next redisplay from
|
||||
overriding motion of point in order to display at this exact start. */)
|
||||
(Lisp_Object window, Lisp_Object pos, Lisp_Object noforce)
|
||||
overriding motion of point in order to display at this exact start.
|
||||
|
||||
If GROUP is non-nil, and WINDOW is part of a group of windows collectively
|
||||
displaying a buffer (such as with Follow Mode), set the start position of
|
||||
the group rather than of the individual WINDOW. This condition holds when
|
||||
`set-window-start-group-function' is set to a function, in which case
|
||||
`set-window-start' calls the function with the three arguments WINDOW, POS,
|
||||
and NOFORCE, then returns its result, instead of doing its normal
|
||||
processing. */)
|
||||
(Lisp_Object window, Lisp_Object pos, Lisp_Object noforce, Lisp_Object group)
|
||||
{
|
||||
register struct window *w = decode_live_window (window);
|
||||
if (!NILP (group)
|
||||
&& FUNCTIONP (Vset_window_start_group_function))
|
||||
return call3 (Vset_window_start_group_function, window, pos, noforce);
|
||||
{
|
||||
register struct window *w = decode_live_window (window);
|
||||
|
||||
set_marker_restricted (w->start, pos, w->contents);
|
||||
/* This is not right, but much easier than doing what is right. */
|
||||
w->start_at_line_beg = false;
|
||||
if (NILP (noforce))
|
||||
w->force_start = true;
|
||||
wset_update_mode_line (w);
|
||||
/* Bug#15957. */
|
||||
w->window_end_valid = false;
|
||||
wset_redisplay (w);
|
||||
set_marker_restricted (w->start, pos, w->contents);
|
||||
/* This is not right, but much easier than doing what is right. */
|
||||
w->start_at_line_beg = false;
|
||||
if (NILP (noforce))
|
||||
w->force_start = true;
|
||||
wset_update_mode_line (w);
|
||||
/* Bug#15957. */
|
||||
w->window_end_valid = false;
|
||||
wset_redisplay (w);
|
||||
|
||||
return pos;
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
|
||||
Spos_visible_in_window_p, 0, 3, 0,
|
||||
Spos_visible_in_window_p, 0, 4, 0,
|
||||
doc: /* Return non-nil if position POS is currently on the frame in WINDOW.
|
||||
WINDOW must be a live window and defaults to the selected one.
|
||||
|
||||
@ -1709,9 +1744,21 @@ of the window. The remaining elements are omitted if the character after
|
||||
POS is fully visible; otherwise, RTOP and RBOT are the number of pixels
|
||||
off-window at the top and bottom of the screen line ("row") containing
|
||||
POS, ROWH is the visible height of that row, and VPOS is the row number
|
||||
(zero-based). */)
|
||||
(Lisp_Object pos, Lisp_Object window, Lisp_Object partially)
|
||||
(zero-based).
|
||||
|
||||
If GROUP is non-nil, and WINDOW is part of a group of windows collectively
|
||||
displaying a buffer (such as with Follow Mode), test whether POS is visible
|
||||
in the group of windows rather than in the individual WINDOW. This
|
||||
condition holds when `pos-visible-in-window-p-function' is set to a
|
||||
function, in which case `pos-visible-in-window-p' calls the function with
|
||||
the three arguments POS, WINDOW, and PARTIALLY, then returns its result,
|
||||
instead of doing its normal processing. */)
|
||||
(Lisp_Object pos, Lisp_Object window, Lisp_Object partially, Lisp_Object group)
|
||||
{
|
||||
if (!NILP (group)
|
||||
&& FUNCTIONP (Vpos_visible_in_window_p_group_function))
|
||||
return call3 (Vpos_visible_in_window_p_group_function, pos, window, partially);
|
||||
{
|
||||
struct window *w;
|
||||
EMACS_INT posint;
|
||||
struct buffer *buf;
|
||||
@ -1760,6 +1807,7 @@ POS, ROWH is the visible height of that row, and VPOS is the row number
|
||||
}
|
||||
|
||||
return in_window;
|
||||
}
|
||||
}
|
||||
|
||||
DEFUN ("window-line-height", Fwindow_line_height,
|
||||
@ -5185,7 +5233,7 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror)
|
||||
}
|
||||
|
||||
XSETFASTINT (tem, PT);
|
||||
tem = Fpos_visible_in_window_p (tem, window, Qnil);
|
||||
tem = Fpos_visible_in_window_p (tem, window, Qnil, Qnil);
|
||||
|
||||
if (NILP (tem))
|
||||
{
|
||||
@ -5574,7 +5622,7 @@ displayed_window_lines (struct window *w)
|
||||
}
|
||||
|
||||
|
||||
DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
|
||||
DEFUN ("recenter", Frecenter, Srecenter, 0, 2, "P\ni",
|
||||
doc: /* Center point in selected window and maybe redisplay frame.
|
||||
With a numeric prefix argument ARG, recenter putting point on screen line ARG
|
||||
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',
|
||||
then only tty frames are redrawn.
|
||||
|
||||
Just C-u as prefix means put point in the center of the window
|
||||
and redisplay normally--don't erase and redraw the frame. */)
|
||||
(register Lisp_Object arg)
|
||||
and redisplay normally--don't erase and redraw the frame.
|
||||
|
||||
When `recenter' is called from a program, GROUP is non-nil, and WINDOW is
|
||||
part of a group of windows collectively displaying a buffer (such as with
|
||||
Follow Mode), perform `recenter''s actions on the group rather than on the
|
||||
individual WINDOW. This condition holds when `recenter-group-function' is
|
||||
set to a function, in which case `recenter' calls the function with the
|
||||
argument ARG, then returns its value, instead of doing its normal
|
||||
processing. */)
|
||||
(register Lisp_Object arg, Lisp_Object group)
|
||||
{
|
||||
struct window *w = XWINDOW (selected_window);
|
||||
struct buffer *buf = XBUFFER (w->contents);
|
||||
bool center_p = false;
|
||||
ptrdiff_t charpos, bytepos;
|
||||
EMACS_INT iarg IF_LINT (= 0);
|
||||
int this_scroll_margin;
|
||||
if (!NILP (group)
|
||||
&& FUNCTIONP (Vrecenter_group_function))
|
||||
return call1 (Vrecenter_group_function, arg);
|
||||
{
|
||||
struct window *w = XWINDOW (selected_window);
|
||||
struct buffer *buf = XBUFFER (w->contents);
|
||||
bool center_p = false;
|
||||
ptrdiff_t charpos, bytepos;
|
||||
EMACS_INT iarg IF_LINT (= 0);
|
||||
int this_scroll_margin;
|
||||
|
||||
if (buf != current_buffer)
|
||||
error ("`recenter'ing a window that does not display current-buffer.");
|
||||
if (buf != current_buffer)
|
||||
error ("`recenter'ing a window that does not display current-buffer.");
|
||||
|
||||
/* If redisplay is suppressed due to an error, try again. */
|
||||
buf->display_error_modiff = 0;
|
||||
/* If redisplay is suppressed due to an error, try again. */
|
||||
buf->display_error_modiff = 0;
|
||||
|
||||
if (NILP (arg))
|
||||
{
|
||||
if (!NILP (Vrecenter_redisplay)
|
||||
&& (!EQ (Vrecenter_redisplay, Qtty)
|
||||
|| !NILP (Ftty_type (selected_frame))))
|
||||
{
|
||||
ptrdiff_t i;
|
||||
if (NILP (arg))
|
||||
{
|
||||
if (!NILP (Vrecenter_redisplay)
|
||||
&& (!EQ (Vrecenter_redisplay, Qtty)
|
||||
|| !NILP (Ftty_type (selected_frame))))
|
||||
{
|
||||
ptrdiff_t i;
|
||||
|
||||
/* Invalidate pixel data calculated for all compositions. */
|
||||
for (i = 0; i < n_compositions; i++)
|
||||
composition_table[i]->font = NULL;
|
||||
/* Invalidate pixel data calculated for all compositions. */
|
||||
for (i = 0; i < n_compositions; i++)
|
||||
composition_table[i]->font = NULL;
|
||||
#if defined (HAVE_WINDOW_SYSTEM) && ! defined (USE_GTK) && ! defined (HAVE_NS)
|
||||
WINDOW_XFRAME (w)->minimize_tool_bar_window_p = 1;
|
||||
WINDOW_XFRAME (w)->minimize_tool_bar_window_p = 1;
|
||||
#endif
|
||||
Fredraw_frame (WINDOW_FRAME (w));
|
||||
SET_FRAME_GARBAGED (WINDOW_XFRAME (w));
|
||||
}
|
||||
Fredraw_frame (WINDOW_FRAME (w));
|
||||
SET_FRAME_GARBAGED (WINDOW_XFRAME (w));
|
||||
}
|
||||
|
||||
center_p = true;
|
||||
}
|
||||
else if (CONSP (arg)) /* Just C-u. */
|
||||
center_p = true;
|
||||
}
|
||||
else if (CONSP (arg)) /* Just C-u. */
|
||||
center_p = true;
|
||||
else
|
||||
{
|
||||
arg = Fprefix_numeric_value (arg);
|
||||
CHECK_NUMBER (arg);
|
||||
iarg = XINT (arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
arg = Fprefix_numeric_value (arg);
|
||||
CHECK_NUMBER (arg);
|
||||
iarg = XINT (arg);
|
||||
}
|
||||
|
||||
/* Do this after making BUF current
|
||||
in case scroll_margin is buffer-local. */
|
||||
this_scroll_margin
|
||||
= max (0, min (scroll_margin, w->total_lines / 4));
|
||||
/* Do this after making BUF current
|
||||
in case scroll_margin is buffer-local. */
|
||||
this_scroll_margin
|
||||
= max (0, min (scroll_margin, w->total_lines / 4));
|
||||
|
||||
/* Don't use redisplay code for initial frames, as the necessary
|
||||
data structures might not be set up yet then. */
|
||||
if (!FRAME_INITIAL_P (XFRAME (w->frame)))
|
||||
{
|
||||
if (center_p)
|
||||
{
|
||||
struct it it;
|
||||
struct text_pos pt;
|
||||
void *itdata = bidi_shelve_cache ();
|
||||
/* Don't use redisplay code for initial frames, as the necessary
|
||||
data structures might not be set up yet then. */
|
||||
if (!FRAME_INITIAL_P (XFRAME (w->frame)))
|
||||
{
|
||||
if (center_p)
|
||||
{
|
||||
struct it it;
|
||||
struct text_pos pt;
|
||||
void *itdata = bidi_shelve_cache ();
|
||||
|
||||
SET_TEXT_POS (pt, PT, PT_BYTE);
|
||||
start_display (&it, w, pt);
|
||||
move_it_vertically_backward (&it, window_box_height (w) / 2);
|
||||
charpos = IT_CHARPOS (it);
|
||||
bytepos = IT_BYTEPOS (it);
|
||||
bidi_unshelve_cache (itdata, false);
|
||||
}
|
||||
else if (iarg < 0)
|
||||
{
|
||||
struct it it;
|
||||
struct text_pos pt;
|
||||
ptrdiff_t nlines = min (PTRDIFF_MAX, -iarg);
|
||||
int extra_line_spacing;
|
||||
int h = window_box_height (w);
|
||||
int ht = window_internal_height (w);
|
||||
void *itdata = bidi_shelve_cache ();
|
||||
SET_TEXT_POS (pt, PT, PT_BYTE);
|
||||
start_display (&it, w, pt);
|
||||
move_it_vertically_backward (&it, window_box_height (w) / 2);
|
||||
charpos = IT_CHARPOS (it);
|
||||
bytepos = IT_BYTEPOS (it);
|
||||
bidi_unshelve_cache (itdata, false);
|
||||
}
|
||||
else if (iarg < 0)
|
||||
{
|
||||
struct it it;
|
||||
struct text_pos pt;
|
||||
ptrdiff_t nlines = min (PTRDIFF_MAX, -iarg);
|
||||
int extra_line_spacing;
|
||||
int h = window_box_height (w);
|
||||
int ht = window_internal_height (w);
|
||||
void *itdata = bidi_shelve_cache ();
|
||||
|
||||
nlines = clip_to_bounds (this_scroll_margin + 1, nlines,
|
||||
ht - this_scroll_margin);
|
||||
nlines = clip_to_bounds (this_scroll_margin + 1, nlines,
|
||||
ht - this_scroll_margin);
|
||||
|
||||
SET_TEXT_POS (pt, PT, PT_BYTE);
|
||||
start_display (&it, w, pt);
|
||||
SET_TEXT_POS (pt, PT, PT_BYTE);
|
||||
start_display (&it, w, pt);
|
||||
|
||||
/* Be sure we have the exact height of the full line containing PT. */
|
||||
move_it_by_lines (&it, 0);
|
||||
/* Be sure we have the exact height of the full line containing PT. */
|
||||
move_it_by_lines (&it, 0);
|
||||
|
||||
/* The amount of pixels we have to move back is the window
|
||||
height minus what's displayed in the line containing PT,
|
||||
and the lines below. */
|
||||
it.current_y = 0;
|
||||
it.vpos = 0;
|
||||
move_it_by_lines (&it, nlines);
|
||||
/* The amount of pixels we have to move back is the window
|
||||
height minus what's displayed in the line containing PT,
|
||||
and the lines below. */
|
||||
it.current_y = 0;
|
||||
it.vpos = 0;
|
||||
move_it_by_lines (&it, nlines);
|
||||
|
||||
if (it.vpos == nlines)
|
||||
h -= it.current_y;
|
||||
else
|
||||
{
|
||||
/* Last line has no newline. */
|
||||
h -= line_bottom_y (&it);
|
||||
it.vpos++;
|
||||
}
|
||||
if (it.vpos == nlines)
|
||||
h -= it.current_y;
|
||||
else
|
||||
{
|
||||
/* Last line has no newline. */
|
||||
h -= line_bottom_y (&it);
|
||||
it.vpos++;
|
||||
}
|
||||
|
||||
/* Don't reserve space for extra line spacing of last line. */
|
||||
extra_line_spacing = it.max_extra_line_spacing;
|
||||
/* Don't reserve space for extra line spacing of last line. */
|
||||
extra_line_spacing = it.max_extra_line_spacing;
|
||||
|
||||
/* If we can't move down NLINES lines because we hit
|
||||
the end of the buffer, count in some empty lines. */
|
||||
if (it.vpos < nlines)
|
||||
{
|
||||
nlines -= it.vpos;
|
||||
extra_line_spacing = it.extra_line_spacing;
|
||||
h -= nlines * (FRAME_LINE_HEIGHT (it.f) + extra_line_spacing);
|
||||
}
|
||||
if (h <= 0)
|
||||
{
|
||||
bidi_unshelve_cache (itdata, false);
|
||||
return Qnil;
|
||||
}
|
||||
/* If we can't move down NLINES lines because we hit
|
||||
the end of the buffer, count in some empty lines. */
|
||||
if (it.vpos < nlines)
|
||||
{
|
||||
nlines -= it.vpos;
|
||||
extra_line_spacing = it.extra_line_spacing;
|
||||
h -= nlines * (FRAME_LINE_HEIGHT (it.f) + extra_line_spacing);
|
||||
}
|
||||
if (h <= 0)
|
||||
{
|
||||
bidi_unshelve_cache (itdata, false);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/* Now find the new top line (starting position) of the window. */
|
||||
start_display (&it, w, pt);
|
||||
it.current_y = 0;
|
||||
move_it_vertically_backward (&it, h);
|
||||
/* Now find the new top line (starting position) of the window. */
|
||||
start_display (&it, w, pt);
|
||||
it.current_y = 0;
|
||||
move_it_vertically_backward (&it, h);
|
||||
|
||||
/* If extra line spacing is present, we may move too far
|
||||
back. This causes the last line to be only partially
|
||||
visible (which triggers redisplay to recenter that line
|
||||
in the middle), so move forward.
|
||||
But ignore extra line spacing on last line, as it is not
|
||||
considered to be part of the visible height of the line.
|
||||
*/
|
||||
h += extra_line_spacing;
|
||||
while (-it.current_y > h)
|
||||
move_it_by_lines (&it, 1);
|
||||
/* If extra line spacing is present, we may move too far
|
||||
back. This causes the last line to be only partially
|
||||
visible (which triggers redisplay to recenter that line
|
||||
in the middle), so move forward.
|
||||
But ignore extra line spacing on last line, as it is not
|
||||
considered to be part of the visible height of the line.
|
||||
*/
|
||||
h += extra_line_spacing;
|
||||
while (-it.current_y > h)
|
||||
move_it_by_lines (&it, 1);
|
||||
|
||||
charpos = IT_CHARPOS (it);
|
||||
bytepos = IT_BYTEPOS (it);
|
||||
charpos = IT_CHARPOS (it);
|
||||
bytepos = IT_BYTEPOS (it);
|
||||
|
||||
bidi_unshelve_cache (itdata, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct it it;
|
||||
struct text_pos pt;
|
||||
ptrdiff_t nlines = min (PTRDIFF_MAX, iarg);
|
||||
int ht = window_internal_height (w);
|
||||
void *itdata = bidi_shelve_cache ();
|
||||
bidi_unshelve_cache (itdata, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct it it;
|
||||
struct text_pos pt;
|
||||
ptrdiff_t nlines = min (PTRDIFF_MAX, iarg);
|
||||
int ht = window_internal_height (w);
|
||||
void *itdata = bidi_shelve_cache ();
|
||||
|
||||
nlines = clip_to_bounds (this_scroll_margin, nlines,
|
||||
ht - this_scroll_margin - 1);
|
||||
nlines = clip_to_bounds (this_scroll_margin, nlines,
|
||||
ht - this_scroll_margin - 1);
|
||||
|
||||
SET_TEXT_POS (pt, PT, PT_BYTE);
|
||||
start_display (&it, w, pt);
|
||||
SET_TEXT_POS (pt, PT, PT_BYTE);
|
||||
start_display (&it, w, pt);
|
||||
|
||||
/* Move to the beginning of screen line containing PT. */
|
||||
move_it_by_lines (&it, 0);
|
||||
/* Move to the beginning of screen line containing PT. */
|
||||
move_it_by_lines (&it, 0);
|
||||
|
||||
/* Move back to find the point which is ARG screen lines above PT. */
|
||||
if (nlines > 0)
|
||||
{
|
||||
it.current_y = 0;
|
||||
it.vpos = 0;
|
||||
move_it_by_lines (&it, -nlines);
|
||||
}
|
||||
/* Move back to find the point which is ARG screen lines above PT. */
|
||||
if (nlines > 0)
|
||||
{
|
||||
it.current_y = 0;
|
||||
it.vpos = 0;
|
||||
move_it_by_lines (&it, -nlines);
|
||||
}
|
||||
|
||||
charpos = IT_CHARPOS (it);
|
||||
bytepos = IT_BYTEPOS (it);
|
||||
charpos = IT_CHARPOS (it);
|
||||
bytepos = IT_BYTEPOS (it);
|
||||
|
||||
bidi_unshelve_cache (itdata, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct position pos;
|
||||
int ht = window_internal_height (w);
|
||||
bidi_unshelve_cache (itdata, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct position pos;
|
||||
int ht = window_internal_height (w);
|
||||
|
||||
if (center_p)
|
||||
iarg = ht / 2;
|
||||
else if (iarg < 0)
|
||||
iarg += ht;
|
||||
if (center_p)
|
||||
iarg = ht / 2;
|
||||
else if (iarg < 0)
|
||||
iarg += ht;
|
||||
|
||||
/* Don't let it get into the margin at either top or bottom. */
|
||||
iarg = clip_to_bounds (this_scroll_margin, iarg,
|
||||
ht - this_scroll_margin - 1);
|
||||
/* Don't let it get into the margin at either top or bottom. */
|
||||
iarg = clip_to_bounds (this_scroll_margin, iarg,
|
||||
ht - this_scroll_margin - 1);
|
||||
|
||||
pos = *vmotion (PT, PT_BYTE, - iarg, w);
|
||||
charpos = pos.bufpos;
|
||||
bytepos = pos.bytepos;
|
||||
}
|
||||
pos = *vmotion (PT, PT_BYTE, - iarg, w);
|
||||
charpos = pos.bufpos;
|
||||
bytepos = pos.bytepos;
|
||||
}
|
||||
|
||||
/* Set the new window start. */
|
||||
set_marker_both (w->start, w->contents, charpos, bytepos);
|
||||
w->window_end_valid = false;
|
||||
/* Set the new window start. */
|
||||
set_marker_both (w->start, w->contents, charpos, bytepos);
|
||||
w->window_end_valid = false;
|
||||
|
||||
w->optional_new_start = true;
|
||||
w->optional_new_start = true;
|
||||
|
||||
w->start_at_line_beg = (bytepos == BEGV_BYTE
|
||||
|| FETCH_BYTE (bytepos - 1) == '\n');
|
||||
w->start_at_line_beg = (bytepos == BEGV_BYTE
|
||||
|| FETCH_BYTE (bytepos - 1) == '\n');
|
||||
|
||||
wset_redisplay (w);
|
||||
wset_redisplay (w);
|
||||
|
||||
return Qnil;
|
||||
return Qnil;
|
||||
}
|
||||
}
|
||||
|
||||
DEFUN ("window-text-width", Fwindow_text_width, Swindow_text_width,
|
||||
@ -5836,52 +5897,68 @@ pixels. */)
|
||||
}
|
||||
|
||||
DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
|
||||
1, 1, "P",
|
||||
1, 2, "P\ni",
|
||||
doc: /* Position point relative to window.
|
||||
ARG nil means position point at center of window.
|
||||
Else, ARG specifies vertical position within the window;
|
||||
zero means top of window, negative means relative to bottom of window. */)
|
||||
(Lisp_Object arg)
|
||||
zero means top of window, negative means relative to bottom of window.
|
||||
|
||||
When GROUP is non-nil, and `move-to-window-line-group-function' is set to a
|
||||
function, then instead of the above, that function is called with the
|
||||
single argument ARG, and its result returned.
|
||||
|
||||
If GROUP is non-nil, and WINDOW is part of a group of windows collectively
|
||||
displaying a buffer (such as with Follow Mode), position point relative to
|
||||
the group of windows as a whole rather than the individual WINDOW. This
|
||||
condition holds when `move-to-window-line-group-function' is set to a
|
||||
function, in which case `move-to-window-line' calls the function with the
|
||||
argument ARG, then returns its result, instead of doing its normal
|
||||
processing. */)
|
||||
(Lisp_Object arg, Lisp_Object group)
|
||||
{
|
||||
struct window *w = XWINDOW (selected_window);
|
||||
int lines, start;
|
||||
Lisp_Object window;
|
||||
if (!NILP (group)
|
||||
&& FUNCTIONP (Vmove_to_window_line_group_function))
|
||||
return call1 (Vmove_to_window_line_group_function, arg);
|
||||
{
|
||||
struct window *w = XWINDOW (selected_window);
|
||||
int lines, start;
|
||||
Lisp_Object window;
|
||||
#if false
|
||||
int this_scroll_margin;
|
||||
int this_scroll_margin;
|
||||
#endif
|
||||
|
||||
if (!(BUFFERP (w->contents) && XBUFFER (w->contents) == current_buffer))
|
||||
/* This test is needed to make sure PT/PT_BYTE make sense in w->contents
|
||||
when passed below to set_marker_both. */
|
||||
error ("move-to-window-line called from unrelated buffer");
|
||||
if (!(BUFFERP (w->contents) && XBUFFER (w->contents) == current_buffer))
|
||||
/* This test is needed to make sure PT/PT_BYTE make sense in w->contents
|
||||
when passed below to set_marker_both. */
|
||||
error ("move-to-window-line called from unrelated buffer");
|
||||
|
||||
window = selected_window;
|
||||
start = marker_position (w->start);
|
||||
if (start < BEGV || start > ZV)
|
||||
{
|
||||
int height = window_internal_height (w);
|
||||
Fvertical_motion (make_number (- (height / 2)), window, Qnil);
|
||||
set_marker_both (w->start, w->contents, PT, PT_BYTE);
|
||||
w->start_at_line_beg = !NILP (Fbolp ());
|
||||
w->force_start = true;
|
||||
}
|
||||
else
|
||||
Fgoto_char (w->start);
|
||||
window = selected_window;
|
||||
start = marker_position (w->start);
|
||||
if (start < BEGV || start > ZV)
|
||||
{
|
||||
int height = window_internal_height (w);
|
||||
Fvertical_motion (make_number (- (height / 2)), window, Qnil);
|
||||
set_marker_both (w->start, w->contents, PT, PT_BYTE);
|
||||
w->start_at_line_beg = !NILP (Fbolp ());
|
||||
w->force_start = true;
|
||||
}
|
||||
else
|
||||
Fgoto_char (w->start);
|
||||
|
||||
lines = displayed_window_lines (w);
|
||||
lines = displayed_window_lines (w);
|
||||
|
||||
#if false
|
||||
this_scroll_margin = max (0, min (scroll_margin, lines / 4));
|
||||
this_scroll_margin = max (0, min (scroll_margin, lines / 4));
|
||||
#endif
|
||||
|
||||
if (NILP (arg))
|
||||
XSETFASTINT (arg, lines / 2);
|
||||
else
|
||||
{
|
||||
EMACS_INT iarg = XINT (Fprefix_numeric_value (arg));
|
||||
if (NILP (arg))
|
||||
XSETFASTINT (arg, lines / 2);
|
||||
else
|
||||
{
|
||||
EMACS_INT iarg = XINT (Fprefix_numeric_value (arg));
|
||||
|
||||
if (iarg < 0)
|
||||
iarg = iarg + lines;
|
||||
if (iarg < 0)
|
||||
iarg = iarg + lines;
|
||||
|
||||
#if false /* This code would prevent move-to-window-line from moving point
|
||||
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. */)
|
||||
it is probably better not to install it. However, it is here
|
||||
inside #if false so as not to lose it. -- rms. */
|
||||
|
||||
/* Don't let it get into the margin at either top or bottom. */
|
||||
iarg = max (iarg, this_scroll_margin);
|
||||
iarg = min (iarg, lines - this_scroll_margin - 1);
|
||||
/* Don't let it get into the margin at either top or bottom. */
|
||||
iarg = max (iarg, this_scroll_margin);
|
||||
iarg = min (iarg, lines - this_scroll_margin - 1);
|
||||
#endif
|
||||
|
||||
arg = make_number (iarg);
|
||||
}
|
||||
arg = make_number (iarg);
|
||||
}
|
||||
|
||||
/* Skip past a partially visible first line. */
|
||||
if (w->vscroll)
|
||||
XSETINT (arg, XINT (arg) + 1);
|
||||
/* Skip past a partially visible first line. */
|
||||
if (w->vscroll)
|
||||
XSETINT (arg, XINT (arg) + 1);
|
||||
|
||||
return Fvertical_motion (arg, window, Qnil);
|
||||
return Fvertical_motion (arg, window, Qnil);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7175,6 +7253,12 @@ syms_of_window (void)
|
||||
DEFSYM (Qclone_of, "clone-of");
|
||||
DEFSYM (Qfloor, "floor");
|
||||
DEFSYM (Qceiling, "ceiling");
|
||||
DEFSYM (Qwindow_start_group_function, "window-start-group-function");
|
||||
DEFSYM (Qwindow_end_group_function, "window-end-group-function");
|
||||
DEFSYM (Qset_window_start_group_function, "set-window-start-group-function");
|
||||
DEFSYM (Qrecenter_group_function, "recenter-group-function");
|
||||
DEFSYM (Qpos_visible_in_window_p_group_function, "pos-visible-in-window-p-group-function");
|
||||
DEFSYM (Qmove_to_window_line_group_function, "move-to-window-line-group-function");
|
||||
|
||||
staticpro (&Vwindow_list);
|
||||
|
||||
@ -7346,6 +7430,72 @@ Note that this optimization can cause the portion of the buffer
|
||||
displayed after a scrolling operation to be somewhat inaccurate. */);
|
||||
Vfast_but_imprecise_scrolling = false;
|
||||
|
||||
DEFVAR_LISP ("window-start-group-function", Vwindow_start_group_function,
|
||||
doc: /* Function to call for `window-start' when its GROUP parameter is non-nil.
|
||||
When this variable contains a function, and `window-start' is called with a
|
||||
non-nil GROUP parameter, the function is called instead of `window-start''s
|
||||
normal action. `window-start' passes the function its argument WINDOW, which
|
||||
might be nil. The function may recursively call `window-start'. */);
|
||||
Vwindow_start_group_function = Qnil;
|
||||
Fmake_variable_buffer_local (Qwindow_start_group_function);
|
||||
Fput (Qwindow_start_group_function, Qpermanent_local, Qt);
|
||||
|
||||
DEFVAR_LISP ("window-end-group-function", Vwindow_end_group_function,
|
||||
doc: /* Function to call for `window-end' if its GROUP parameter is non-nil.
|
||||
When this variable contains a function, and `window-end' is called with a
|
||||
non-nil GROUP parameter, the function is called instead of `window-end''s
|
||||
normal action. `window-end' passes the function its two parameters WINDOW,
|
||||
and UPDATE. The function may call `window-end' recursively. */);
|
||||
Vwindow_end_group_function = Qnil;
|
||||
Fmake_variable_buffer_local (Qwindow_end_group_function);
|
||||
Fput (Qwindow_end_group_function, Qpermanent_local, Qt);
|
||||
|
||||
DEFVAR_LISP ("set-window-start-group-function",
|
||||
Vset_window_start_group_function,
|
||||
doc: /* The function to call for `set-window-start' when its GROUP parameter is non-nil.
|
||||
When this variable contains a function, and `set-window-start' is called
|
||||
with a non-nil GROUP parameter, the function is called instead of
|
||||
`set-window-start''s normal action. `set-window-start' passes the function
|
||||
its three parameters WINDOW, POS, and NOFORCE. The function may call
|
||||
`set-window-start' recursively. */);
|
||||
Vset_window_start_group_function = Qnil;
|
||||
Fmake_variable_buffer_local (Qset_window_start_group_function);
|
||||
Fput (Qset_window_start_group_function, Qpermanent_local, Qt);
|
||||
|
||||
DEFVAR_LISP ("recenter-group-function", Vrecenter_group_function,
|
||||
doc: /* Function to call for `recenter' when its GROUP parameter is non-nil.
|
||||
When this variable contains a function, and `recenter' is called with a
|
||||
non-nil GROUP parameter, the function is called instead of `recenter''s
|
||||
normal action. `recenter' passes the function its parameter ARG. The
|
||||
function may call `recenter' recursively. */);
|
||||
Vrecenter_group_function = Qnil;
|
||||
Fmake_variable_buffer_local (Qrecenter_group_function);
|
||||
Fput (Qrecenter_group_function, Qpermanent_local, Qt);
|
||||
|
||||
DEFVAR_LISP ("pos-visible-in-window-p-group-function",
|
||||
Vpos_visible_in_window_p_group_function,
|
||||
doc: /* Function for `pos-visible-in-window-p' when its GROUP parameter is non-nil.
|
||||
When this variable contains a function, and `pos-visible-in-window-p' is
|
||||
called with a non-nil GROUP parameter, the function is called instead of
|
||||
`pos-visible-in-window-p''s normal action. `pos-visible-in-window-p'
|
||||
passes the function its three parameters POS, WINDOW, and PARTIALLY. The
|
||||
function may call `pos-visible-in-window-p' recursively. */);
|
||||
Vpos_visible_in_window_p_group_function = Qnil;
|
||||
Fmake_variable_buffer_local (Qpos_visible_in_window_p_group_function);
|
||||
Fput (Qpos_visible_in_window_p_group_function, Qpermanent_local, Qt);
|
||||
|
||||
DEFVAR_LISP ("move-to-window-line-group-function",
|
||||
Vmove_to_window_line_group_function,
|
||||
doc: /* Function for `move-to-window-line' when its GROUP parameter is non-nil.
|
||||
When this variable contains a function, and `move-to-window-line' is
|
||||
called with a non-nil GROUP parameter, the function is called instead of
|
||||
`move-to-window-line''s normal action. `move-to-window-line' passes the
|
||||
function its parameter ARG. The function may call `move-to-window-line'
|
||||
recursively. */);
|
||||
Vmove_to_window_line_group_function = Qnil;
|
||||
Fmake_variable_buffer_local (Qmove_to_window_line_group_function);
|
||||
Fput (Qmove_to_window_line_group_function, Qpermanent_local, Qt);
|
||||
|
||||
defsubr (&Sselected_window);
|
||||
defsubr (&Sminibuffer_window);
|
||||
defsubr (&Swindow_minibuffer_p);
|
||||
|
Loading…
Reference in New Issue
Block a user