comparison lisp/packages/scroll-in-place.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children b82b59fe008d
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1
2 ;;;; -*-Emacs-Lisp-*- Improved Vertical Scrolling Commands
3 ;;;; Written by Eric Eide, last modified on 1994/11/18 21:23:01.
4 ;;;; (C) Copyright 1993, 1994, Eric Eide and the University of Utah
5 ;;;;
6 ;;;; COPYRIGHT NOTICE
7 ;;;;
8 ;;;; This program is free software; you can redistribute it and/or modify it
9 ;;;; under the terms of the GNU General Public License as published by the Free
10 ;;;; Software Foundation; either version 2 of the License, or (at your option)
11 ;;;; any later version.
12 ;;;;
13 ;;;; This program is distributed in the hope that it will be useful, but
14 ;;;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 ;;;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 ;;;; for more details.
17 ;;;;
18 ;;;; You should have received a copy of the GNU General Public License along
19 ;;;; with GNU Emacs. If you did not, write to the Free Software Foundation,
20 ;;;; Inc., 675 Mass Ave., Cambridge, MA 02139, USA.
21
22 ;;; Synched up with: Not in FSF.
23
24 ;;;; AUTHORS
25 ;;;;
26 ;;;; This package was written by Eric Eide (eeide@cs.utah.edu) and was based on
27 ;;;; a very similar package ("scroll-fix") by Joe Wells. Almost all of the
28 ;;;; code in this file is original, but I owe a great debt to Mr. Wells for his
29 ;;;; ideas and his original implementation.
30 ;;;;
31 ;;;; Eric Eide (eeide@cs.utah.edu)
32 ;;;; University of Utah
33 ;;;; 3190 Merrill Engineering Building
34 ;;;; Salt Lake City, Utah 84112
35 ;;;;
36 ;;;; Joe Wells (jbw@cs.bu.edu)
37 ;;;;
38 ;;;; Joe Wells' "scroll-fix" package is Copyright (C) 1988, 1989, and 1991 by
39 ;;;; the Free Software Foundation. It is distributed under the terms of the
40 ;;;; GNU General Public License.
41
42 ;;;; LISP CODE DIRECTORY INFORMATION
43 ;;;;
44 ;;;; LCD Archive Entry:
45 ;;;; scroll-in-place|Eric Eide|eeide@cs.utah.edu|
46 ;;;; Improved vertical scrolling commands|
47 ;;;; 1994/11/18 21:23:01|1.3|~/misc/scroll-in-place.el.Z|
48
49 ;;;; SUMMARY
50 ;;;;
51 ;;;; This package provides improved vertical scrolling commands for GNU Emacs.
52 ;;;; These new commands offer the following features:
53 ;;;;
54 ;;;; + When a scrolling command is executed, GNU Emacs tries to keep point as
55 ;;;; close as possible to its original window position (window line and
56 ;;;; column). This is what "scroll in place" means: point stays "in place"
57 ;;;; within the window. (There are times when point must be moved from its
58 ;;;; original window position in order to execute the scroll; see below.)
59 ;;;;
60 ;;;; The variable `scroll-in-place', which is true by default, determines
61 ;;;; whether or not the standard GNU Emacs scrolling commands (`scroll-down',
62 ;;;; `scroll-up', `scroll-other-window-down', and `scroll-other-window') use
63 ;;;; the "in place" features listed here. When `scroll-in-place' is `nil'
64 ;;;; the standard GNU Emacs scrolling commands essentially just call the
65 ;;;; original versions of themselves. (Note that even when `scroll-in-place'
66 ;;;; is `nil' the new versions of `scroll-down' and `scroll-up' have slightly
67 ;;;; different behavior when a minibuffer window is the selected window. See
68 ;;;; below.)
69 ;;;;
70 ;;;; It is possible to turn off (or turn on) "in place" scrolling for certain
71 ;;;; buffers by making buffer-local bindings of the variable `scroll-in-
72 ;;;; place' for those buffers. The variable `scroll-in-place' is not usually
73 ;;;; buffer-local, but you can make it so if you desire.
74 ;;;;
75 ;;;; + Because the improved scrolling commands keep point at its original
76 ;;;; window position, these scrolling commands are "reversible." The
77 ;;;; `scroll-up' command undoes the effect of the immediately previous
78 ;;;; `scroll-down' command (if any) and vice versa. In other words, if you
79 ;;;; scroll up and then immediately scroll back down, the window config-
80 ;;;; uration is restored to its exact original state. This allows you to
81 ;;;; browse through a buffer more easily, as you can always get back to the
82 ;;;; original configuration.
83 ;;;;
84 ;;;; Note, however, that the improved scrolling commands are guaranteed to be
85 ;;;; reversible only if there are no intervening non-scrolling commands.
86 ;;;; Also, if you give a prefix argument to a scrolling command (in order to
87 ;;;; specify the number of lines to scroll by), previous scrolling commands
88 ;;;; may no longer be reversible. More specifically, if the new prefix
89 ;;;; argument has a different magnitude than the previous scrolling distance,
90 ;;;; then any previous scrolling commands are not reversible. The new prefix
91 ;;;; argument takes precedence.
92 ;;;;
93 ;;;; You might find it useful to think of the scrolling commands as forming
94 ;;;; "chains." A scrolling command either starts or continues a chain. By
95 ;;;; issuing a non-scrolling command or by changing the number of lines to be
96 ;;;; scrolled, you break the chain. (Note that simply changing the scrolling
97 ;;;; direction won't break the chain; changing the absolute number of lines
98 ;;;; to be scrolled is what breaks the chain.) Scrolling commands are
99 ;;;; guaranteed to be reversible only within the current chain. Hopefully
100 ;;;; that's clear enough.
101 ;;;;
102 ;;;; + When a scrolling command is given a prefix argument (which specifies the
103 ;;;; number of lines to scroll by), then that argument becomes the default
104 ;;;; scrolling distance for all immediately subsequent scrolling commands.
105 ;;;; This means that you can easily set the scrolling distance for a chain
106 ;;;; of scrolling commands. Note that a new prefix argument or any non-
107 ;;;; scrolling command breaks the chain (as described above), and any further
108 ;;;; scrolling commands will use the usual defaults (or the prefix argument
109 ;;;; you specify at that time, of course).
110 ;;;;
111 ;;;; However, there are cases in which one doesn't want the current scrolling
112 ;;;; command to use the default scrolling distance that was set by the
113 ;;;; previous scrolling command. For example, suppose that you had special
114 ;;;; commands that scrolled one line up and one line down. When you invoke
115 ;;;; one of these commands, the "in place" scrolling routines set the default
116 ;;;; scrolling distance to be just one line. Now suppose that you use one of
117 ;;;; your special commands and then immediately invoke `scroll-up' (`C-v'),
118 ;;;; expecting it to scroll by a near windowful of text. You would be
119 ;;;; disappointed --- because the previous command set the default scrolling
120 ;;;; distance to be just one line, `scroll-up' just scrolls by one line.
121 ;;;;
122 ;;;; To solve this problem, "scroll-in-place" allows you to divide scrolling
123 ;;;; commands into separate "groups." Commands in a group can only form
124 ;;;; chains with (and therefore, inherit defaults from) commands in the same
125 ;;;; group. (Note that no command can be in more than one group.) If you
126 ;;;; invoke a scrolling command that is not in the same group as that of the
127 ;;;; immediately previous scrolling command, then the previous chain is
128 ;;;; broken and you start a new chain --- with a new set of defaults.
129 ;;;;
130 ;;;; So to solve the problem described above, you could put your one-line
131 ;;;; scrolling commands in their own group. Once that is done, the standard
132 ;;;; scrolling commands will not form chains with your one-line scrolling
133 ;;;; commands, and therefore will not use the default scrolling distance set
134 ;;;; by those commands. Problem solved!
135 ;;;;
136 ;;;; By default, all "in place" scrolling commands are in a single group. If
137 ;;;; you want to partition some commands into separate groups, you must do
138 ;;;; that yourself *before* any "in place" commands are invoked. For more
139 ;;;; information about grouping commands, see the documentation for the
140 ;;;; variables `scroll-command-groups' and `scroll-default-command-group'.
141 ;;;;
142 ;;;; + The improved scrolling commands will avoid displaying empty lines past
143 ;;;; the end of the buffer when possible. In other words, just as you can't
144 ;;;; see "dead space" before the beginning of the buffer text, the new
145 ;;;; scrolling commands try to avoid displaying "dead space" past the end of
146 ;;;; the buffer text. This behavior is somewhat configurable; see the
147 ;;;; documentation for the variable `scroll-allow-blank-lines-past-eob'.
148 ;;;;
149 ;;;; Dead space will be displayed if it is necessary in order to make a
150 ;;;; previous scrolling action reversible, however.
151 ;;;;
152 ;;;; + If the scrolling commands cannot keep point at its initial window
153 ;;;; position (because a buffer boundary is on screen and the window can't be
154 ;;;; scrolled as far as necessary to keep point at the right place), point is
155 ;;;; allowed to temporarily stray from its initial window position. That is,
156 ;;;; point moves the correct number of window lines, even if it means that it
157 ;;;; has to stray from its desired window position. This straying is undone
158 ;;;; when (and if) the scrolling action is reversed.
159 ;;;;
160 ;;;; + If a scrolling command tries to move point past a buffer boundary, point
161 ;;;; is instead moved to the boundary (the beginning or the end of the buffer
162 ;;;; as appropriate) and an appropriate message is displayed. This motion is
163 ;;;; reversible, of course.
164 ;;;;
165 ;;;; However, if point was already at the buffer boundary when the scrolling
166 ;;;; command was invoked, the command signals an appropriate error instead.
167 ;;;;
168 ;;;; + When a minibuffer window is the selected window, the new versions of
169 ;;;; `scroll-up' and `scroll-down' either scroll the window in the variable
170 ;;;; `minibuffer-scroll-window' (which is usually the window of completions)
171 ;;;; or the `next-window' if there is no `minibuffer-scroll-window'. This is
172 ;;;; usually much more useful than scrolling the minibuffer itself. (Note
173 ;;;; that this feature is available even when the variable `scroll-in-place'
174 ;;;; is `nil'.)
175 ;;;;
176 ;;;; + When a scrolling command is scrolling a window other than the selected
177 ;;;; window, it will signal an appropriate buffer boundary error if the
178 ;;;; window cannot be scrolled (because the appropriate buffer boundary is
179 ;;;; already visible). This means that an error is signalled even in cases
180 ;;;; that would be allowed (by "straying" point or by moving it to the buffer
181 ;;;; boundary) if the window were selected.
182 ;;;;
183 ;;;; (If an error were not signalled in these cases, then there would be many
184 ;;;; cases in which the last scroll in a particular direction would appear to
185 ;;;; do nothing because only the point position would change --- the
186 ;;;; displayed text would stay the same! To avoid these cases the scrolling
187 ;;;; commands signal boundary errors "prematurely" when the window to be
188 ;;;; scrolled is not selected.)
189 ;;;;
190 ;;;; So how is this package different than Joe Wells' "scroll-fix" package?
191 ;;;;
192 ;;;; + This package provides "in place" behavior for the standard GNU Emacs
193 ;;;; commands by default; "scroll-fix" does not.
194 ;;;;
195 ;;;; + "scroll-fix" behaves differently when the window is near a buffer
196 ;;;; boundary. Instead of allowing point to stray, "scroll-fix" first does
197 ;;;; an incomplete scroll (i.e., moves point less than the full distance in
198 ;;;; order to keep point at the desired window position) and then pops point
199 ;;;; to the buffer boundary. I think that the behavior of this package is
200 ;;;; somewhat move intuitive, especially for small scrolling distances.
201 ;;;;
202 ;;;; + The scrolling commands in this package will appropriately signal buffer
203 ;;;; boundary errors; the commands in "scroll-fix" never signal boundary
204 ;;;; errors. This makes it difficult to allow "scroll-fix" to replace the
205 ;;;; standard `scroll-down' and `scroll-up' commands because some other
206 ;;;; packages (e.g., VM and GNUS) expect the scrolling commands to signal
207 ;;;; these errors as necessary.
208 ;;;;
209 ;;;; + This package handles long lines correctly. (But see PROBLEMS, below.)
210 ;;;;
211 ;;;; + "scroll-fix" handles prefix arguments differently. In "scroll-fix", a
212 ;;;; number-containing prefix argument always breaks any running chain of
213 ;;;; scrolling commands. The prefix argument `-' (the symbol minus,
214 ;;;; generated by `C-u -') causes a temporary change in direction --- a
215 ;;;; change for only the current command. In this package, however, a
216 ;;;; number-containing prefix argument only breaks a running chain if it has
217 ;;;; a different magnitude than the default scrolling distance, and the
218 ;;;; prefix argument `-' causes a permanent change in the sign of the default
219 ;;;; scrolling distance --- a change visible to immediately subsequent
220 ;;;; scrolling commands.
221 ;;;;
222 ;;;; + This package keeps track of the set of "in place" scrolling commands
223 ;;;; dynamically, in order to detect "chains" of scrolling commands.
224 ;;;; "scroll-fix" has a fixed list of scrolling commands, so "scroll-fix"
225 ;;;; cannot keep track of some chains. (Again, "scroll-fix" interacts badly
226 ;;;; with VM and GNUS.) And because "scroll-fix" keeps a static list of
227 ;;;; scrolling commands, it is a bad idea to call its "in place" commands
228 ;;;; from a program. This package, because it maintains the information
229 ;;;; dynamically, has no such problems.
230 ;;;;
231 ;;;; + This package allows one to divide the "in place" scrolling commands into
232 ;;;; groups; a command in a group only forms chains with the members of its
233 ;;;; group. "scroll-fix" has no notion of command groups.
234 ;;;;
235 ;;;; + This package provides "in place" versions of the standard GNU Emacs
236 ;;;; commands `scroll-other-window-down' and `scroll-other-window'.
237 ;;;;
238 ;;;; + This package will refuse to scroll non-selected windows (by signalling
239 ;;;; an error) when the displayed text would not change, as described in the
240 ;;;; feature list above.
241 ;;;;
242 ;;;; + When a minibuffer window is selected, this package always scrolls a
243 ;;;; window other than the minibuffer. "scroll-fix" will scroll another
244 ;;;; window only if the entire minibuffer contents are visible.
245 ;;;;
246 ;;;; + "scroll-fix" provides a command to toggle the "in place" behavior of the
247 ;;;; standard GNU Emacs commands. This package doesn't; you'll have to set
248 ;;;; the option manually with the command `set-variable'.
249 ;;;;
250 ;;;; + This package has gratuitous variable renaming (insert smile here!):
251 ;;;;
252 ;;;; "scroll-fix" user variable Equivalent in this package
253 ;;;; -----------------------------------------------------------------------
254 ;;;; scroll-in-place (none)
255 ;;;; scroll-in-place-replace-original scroll-in-place
256 ;;;; scroll-in-place-eob-blank-allowed scroll-allow-blank-lines-past-eob
257 ;;;;
258 ;;;; + This package allows programmers to specify the default scrolling
259 ;;;; distance (i.e., the default distance used when starting a new chain of
260 ;;;; scrolling commands) for custom scrolling commands.
261
262 ;;;; COMMANDS AND FUNCTIONS
263 ;;;;
264 ;;;; This package provides the following "in place" versions of GNU Emacs'
265 ;;;; standard vertical scrolling commands:
266 ;;;;
267 ;;;; scroll-down-in-place
268 ;;;; scroll-up-in-place
269 ;;;; scroll-other-window-down-in-place
270 ;;;; scroll-other-window-in-place
271 ;;;;
272 ;;;; The variable `scroll-in-place', which is true by default, determines
273 ;;;; whether or not the new versions of the standard GNU Emacs scrolling
274 ;;;; commands (`scroll-down', `scroll-up', `scroll-other-window-down', and
275 ;;;; `scroll-other-window') use the "in place" features listed above. When
276 ;;;; `scroll-in-place' is `nil' the standard GNU Emacs scrolling commands
277 ;;;; essentially just call the original versions of themselves. (Note that
278 ;;;; even when `scroll-in-place' is `nil' the new versions of `scroll-down' and
279 ;;;; `scroll-up' have slightly different behavior when a minibuffer window is
280 ;;;; the selected window. See the feature list above.)
281 ;;;;
282 ;;;; NOTE that this package redefines the standard GNU Emacs commands `scroll-
283 ;;;; down', `scroll-up', `scroll-other-window-down', and `scroll-other-window'
284 ;;;; (in order to check the variable `scroll-in-place', as described above).
285 ;;;; The command `scroll-other-window-down' first appeared as a standard
286 ;;;; command in the FSF's GNU Emacs 19.26.
287 ;;;;
288 ;;;; This package also provides the following functions and variables which are
289 ;;;; of use to programmers:
290 ;;;;
291 ;;;; scroll-window
292 ;;;; scroll-window-in-place
293 ;;;; scroll-window-in-place-continue-sequence
294 ;;;; scroll-default-lines (variable)
295 ;;;; scroll-command-groups (variable)
296 ;;;;
297 ;;;; The `scroll-window-in-place' function is the heart of the "in place"
298 ;;;; scrolling commands. `scroll-window' is a function that checks the
299 ;;;; variable `scroll-in-place' and calls the appropriate scrolling function
300 ;;;; (either `scroll-window-in-place' or one of the original versions of
301 ;;;; `scroll-down' and `scroll-up'). The function `scroll-window-in-place-
302 ;;;; continue-sequence' is provided in order to preserve running "chains" of
303 ;;;; scrolling commands as described above.
304 ;;;;
305 ;;;; The variable `scroll-default-lines' determines the default scrolling
306 ;;;; distance when a new chain of "in place" scrolling commands begins. If
307 ;;;; this variable is not a number, then the default distance is the height of
308 ;;;; the window to be scrolled minus `next-screen-context-lines'. The variable
309 ;;;; `scroll-command-groups' contains the explicit groups of "in place"
310 ;;;; scrolling commands; for more information read the variable documentation.
311
312 ;;;; YOUR .EMACS FILE
313 ;;;;
314 ;;;; To use this package, you simply need to load it from within your ".emacs"
315 ;;;; file:
316 ;;;;
317 ;;;; (require 'scroll-in-place)
318 ;;;;
319 ;;;; By default, this package provides for the standard GNU Emacs vertical
320 ;;;; scrolling commands (`scroll-down', `scroll-up', `scroll-other-window-
321 ;;;; down', and `scroll-other-window') to use the "in place" features. If you
322 ;;;; would rather not have this, set the variable `scroll-in-place' to `nil':
323 ;;;;
324 ;;;; (setq scroll-in-place nil)
325 ;;;;
326 ;;;; When `scroll-in-place' is `nil' you will have to bind keys in order to
327 ;;;; call the "in place" scrolling commands. For example, you might want to do
328 ;;;; the following:
329 ;;;;
330 ;;;; (global-set-key "\M-v" 'scroll-down-in-place)
331 ;;;; (global-set-key "\C-v" 'scroll-up-in-place)
332 ;;;;
333 ;;;; Sun users should also read the PROBLEMS section, below.
334 ;;;;
335 ;;;; ADVANCED CUSTOMIZATION
336 ;;;;
337 ;;;; If you want to partition certain "in place" scrolling commands into
338 ;;;; separate groups, you should do something like the following:
339 ;;;;
340 ;;;; ;; Make one group containing the commands `scroll-down-one-line' and
341 ;;;; ;; `scroll-up-one-line'. (These are not standard GNU Emacs commands.)
342 ;;;; (setq scroll-command-groups
343 ;;;; (list '(scroll-down-one-line scroll-up-one-line)))
344 ;;;;
345 ;;;; You could write the `scroll-down-one-line' command like this:
346 ;;;;
347 ;;;; (defun scroll-down-one-line (arg)
348 ;;;; "Scroll down one line, or number of lines specified by prefix arg."
349 ;;;; (interactive "P")
350 ;;;; (let ((scroll-default-lines 1))
351 ;;;; (scroll-down-in-place arg)))
352 ;;;;
353 ;;;; If you want to disable "in place" scrolling for windows that display a
354 ;;;; particular buffer (while leaving it available in other windows), you can
355 ;;;; make `scroll-in-place' a buffer-local variable for that buffer and then
356 ;;;; bind that local copy of `scroll-in-place' to `nil'. This is the kind of
357 ;;;; thing that one generally does in a major mode hook. For example, you can
358 ;;;; disable "in place" scrolling of GNUS article windows with the following
359 ;;;; code:
360 ;;;;
361 ;;;; (setq gnus-article-mode-hook
362 ;;;; (function (lambda ()
363 ;;;; (make-local-variable 'scroll-in-place)
364 ;;;; (setq scroll-in-place nil))))
365 ;;;; ;; Set the variable `gnus-Article-mode-hook' instead if you are using
366 ;;;; ;; an old version of GNUS, say version 3.13 or 3.14.
367 ;;;;
368 ;;;; The variable `scroll-allow-blank-lines-past-eob' can also be made local to
369 ;;;; particular buffers, if you desire. (But why would you want to do that?)
370
371 ;;;; PROBLEMS
372 ;;;;
373 ;;;; + It is sometimes difficult for one's eyes to follow an incomplete scroll
374 ;;;; (i.e., a scroll in which the text doesn't move as far as one expected),
375 ;;;; especially when the scrolled window is not selected (and therefore that
376 ;;;; window's point is not highlighted). One can lose one's place in the
377 ;;;; text.
378 ;;;;
379 ;;;; + The names `scroll-down-in-place' and `scroll-up-in-place' conflict with
380 ;;;; two commands in the GNU Emacs terminal-specific file "term/sun.el".
381 ;;;; This means that in order to load this package correctly, Sunterm users
382 ;;;; will have to use the hook `term-setup-hook'. For example, you might put
383 ;;;; the following form in your ".emacs" file:
384 ;;;;
385 ;;;; (setq term-setup-hook (function (lambda () (require 'scroll-in-place))))
386 ;;;;
387 ;;;; If this is confusing, get help from your local GNU Emacs guru.
388 ;;;;
389 ;;;; + `scroll-determine-goal-column' tries to honor the variable `track-eol'
390 ;;;; if it is set. But when lines are being wrapped we can't move point past
391 ;;;; the wrap --- or else it is possible that scrolling won't work correctly.
392 ;;;; In short, this package honors `track-eol' as best it can.
393 ;;;;
394 ;;;; + `scroll-window-in-place' can become confused when something changes the
395 ;;;; window "out from under it." By "confused" I mean that it is possible
396 ;;;; for `scroll-window-in-place' to think that it should continue the
397 ;;;; running sequence of "in place" scrolls when it should really probably
398 ;;;; start a new sequence. For example, if a process filter inserts text
399 ;;;; into the buffer and moves point, `scroll-window-in-place' loses track of
400 ;;;; where point should be and where the window should start. Commands that
401 ;;;; call a "scroll in place" function and then subsequently move point can
402 ;;;; also confuse `scroll-window-in-place'.
403 ;;;;
404 ;;;; To correct some of this confusion, `scroll-window-in-place' could keep
405 ;;;; track of the final positions of `window-start' and `window-point',
406 ;;;; possibly with both markers and character positions. In my experience
407 ;;;; the "in place" scrolling commands are almost never confused (except by
408 ;;;; fancy packages that do their own fancy kinds of scrolling, as described
409 ;;;; below), so the extra sanity checking isn't worth the effort. If your
410 ;;;; mileage varies let me know.
411 ;;;;
412 ;;;; + The "in place" scrolling commands can interact poorly with packages that
413 ;;;; provide their own special scrolling commands. For example, there are
414 ;;;; varying degrees of conflict with Rmail, VM, and GNUS.
415 ;;;;
416 ;;;; RMAIL
417 ;;;;
418 ;;;; In the version of Rmail that is part of the FSF's GNU Emacs 19 (19.25
419 ;;;; through 19.28 at least), the command `rmail-summary-scroll-msg-down' in
420 ;;;; the file "rmailsum.el" fails to work properly when "in place" scrolling
421 ;;;; is enabled for the Rmail message buffer. (The source of the conflict:
422 ;;;; the "in place" scrolling commands and Emacs' standard scrolling commands
423 ;;;; interpret the argument '- in different ways.) Fortunately it is easy to
424 ;;;; patch Rmail. Send me mail if you would like to receive a copy of these
425 ;;;; patches.
426 ;;;;
427 ;;;; I know of no conflicts between the "in place" scrolling commands and
428 ;;;; older versions of Rmail (i.e., versions that came with GNU Emacs 18).
429 ;;;;
430 ;;;; VM
431 ;;;;
432 ;;;; `scroll-window-in-place' is *very* confused by VM 5's message scrolling
433 ;;;; commands, especially because VM 5 rebuilds Emacs' window configuration
434 ;;;; from scratch so often. I have written an experimental set of patches
435 ;;;; for VM 5.70 that allows VM 5 to use the "scroll-in-place" features; send
436 ;;;; me mail if you would like to receive a copy of these patches. I hope
437 ;;;; that someday my patches will be incorporated into VM.
438 ;;;;
439 ;;;; `scroll-window-in-place' is not confused by VM 4.41's message scrolling
440 ;;;; commands, however.
441 ;;;;
442 ;;;; GNUS
443 ;;;;
444 ;;;; `scroll-window-in-place' can be *slightly* confused by GNUS' article
445 ;;;; scrolling commands because they move point to the last line of the
446 ;;;; article window and then scroll the text. (This is the case for at least
447 ;;;; GNUS versions 3.13 through 4.1, inclusive.) The potential conflict is
448 ;;;; so minor, however, that you'll probably never notice it. I never do.
449 ;;;;
450 ;;;; A severe conflict, however, exists between the "in place" scrolling
451 ;;;; commands and the add-on "gnus-hide" package. "gnus-hide" can elide
452 ;;;; signatures at the ends of articles but it does so in a way that causes
453 ;;;; `scroll-window-in-place', as invoked by the GNUS scrolling commands, not
454 ;;;; to signal end-of-buffer conditions at the right times. Someday I may
455 ;;;; write new article scrolling commands for GNUS.
456 ;;;;
457 ;;;; + Process filters that call scrolling functions can cause confusion. They
458 ;;;; may break running chains of "in place" scrolling commands and they may
459 ;;;; set up inappropriate defaults for future scrolling commands. Maybe this
460 ;;;; is a moot problem, as I am currently unaware of any process filters that
461 ;;;; invoke scrolling commands (although many filters move point around,
462 ;;;; which will also confuse `scroll-window-in-place').
463
464 ;; (provide 'scroll-in-place) at the end of this file.
465
466
467 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
468 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
469 ;;;;
470 ;;;; Here are the variable declarations, both user options and internal
471 ;;;; variables.
472 ;;;;
473 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
474 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
475
476 (defvar scroll-in-place t
477 "*When this variable is true (i.e., non-`nil'), the standard GNU Emacs
478 vertical scrolling commands `scroll-down', `scroll-up', `scroll-other-window-
479 down', and `scroll-other-window' will attempt to keep point at its current
480 position in the window (window line and column). In other words, point stays
481 \"in place\" within the window.
482
483 When this variable is `nil' the standard GNU Emacs vertical scrolling commands
484 behave as usual. The \"in place\" equivalents, however, are still available as
485 separate commands.
486
487 This variable may be made buffer-local in order to disable (or enable) \"in
488 place\" scrolling in particular buffers."
489 ;; I have thought about dividing `scroll-in-place' into three variables: a
490 ;; list of commands that always scroll in place, a list of commands that
491 ;; never scroll in place, and a flag that determines the default behavior of
492 ;; other scrolling commands. This could make it easier to make "in place"
493 ;; scrolling the default because one could single out certain ill-behaved
494 ;; commands. But as of now I'm sure that the added complexity would really
495 ;; be worth it.
496 )
497
498 (defvar scroll-allow-blank-lines-past-eob nil
499 "*When this variable is `nil' the \"in place\" scrolling commands will avoid
500 displaying empty lines past the end of the buffer text. In other words, just
501 as you can't see \"dead space\" before the beginning of the buffer text, the
502 \"in place\" scrolling commands try to avoid displaying \"dead space\" past the
503 end of the buffer text. This helps make the most of window real estate.
504
505 Note that sometimes it is necessary to display \"dead space\" in order to make
506 a previous scrolling action reversible.
507
508 When this variable is non-`nil' the \"in place\" scrolling commands will always
509 allow blank lines to be shown past the end of the buffer.")
510
511 ;;;;
512 ;;;; The following variables are not user options, but are intended to be set
513 ;;;; by code outside this package.
514 ;;;;
515
516 (defvar scroll-default-lines nil
517 "The default number of lines to be scrolled by when a new sequence of \"in
518 place\" scrolling commands begins. Of course, when an explicit number of lines
519 is specified, that explicit number takes precedence. See the documentation for
520 the function `scroll-window-in-place' for more information.
521
522 If this variable is not bound to a number, then the default number of lines is
523 the height of the window to be scrolled minus `next-screen-context-lines'.
524
525 This variable should not be set globally! Commands that want to specify a
526 default scrolling distance should just bind the variable `scroll-default-lines'
527 temporarily.")
528
529 (defvar scroll-command-groups nil
530 "The explicitly specified \"groups\" of \"in place\" scrolling commands.
531 This variable should be set before or immediately after the \"in place\"
532 scrolling package is loaded, and then not changed after that.
533
534 Usually, \"in place\" scrolling commands share state (e.g., the number of lines
535 to scroll by) with any and all immediately previous \"in place\" scrolling
536 commands. Sometimes, however, this is undesirable. In these cases the \"in
537 place\" scrolling commands can be divided into groups. A command in a group
538 only shares state with members of its group.
539
540 Each element of `scroll-command-groups' is a list that contains all of the
541 members of a unique command group. For example, if there were only one
542 explicit group and that group contained the commands `scroll-down-one-line' and
543 `scroll-up-one-line', then `scroll-command-groups' would be set to:
544
545 ((scroll-down-one-line scroll-up-one-line))
546
547 Commands that are not in any explicitly specified group are added to a default
548 group. That group is stored in the variable `scroll-default-command-group'.
549
550 The \"in place\" scrolling functions assume that all of the scrolling command
551 groups are nonintersecting (i.e., no command is in more than one group) and
552 only contain \"in place\" scrolling commands.")
553
554 ;;;;
555 ;;;; The variables below this point are internal to this package.
556 ;;;;
557
558 (defvar scroll-default-command-group nil
559 "The set of \"in place\" scrolling commands that are not members of any
560 explicitly defined group of commands. This set of commands is an implicitly
561 defined group, constructed as \"in place\" commands are invoked, and members of
562 this group share state among themselves. See the documentation for the
563 variable `scroll-command-groups' for more information.")
564
565 (defvar scroll-initially-displayed-lines 0
566 "The number of window lines that contained buffer text when the current
567 sequence of \"in place\" scrolling commands started. Unless the variable
568 `scroll-in-place-allow-blank-lines-past-eob' is true, the \"in place\"
569 scrolling commands ensure that at least this many text lines are visible at all
570 times.")
571
572 (defvar scroll-previous-window nil
573 "The window that was most recently scrolled by an \"in place\" scrolling
574 command.")
575
576 (defvar scroll-previous-lines 0
577 "The number of window lines that the previous \"in place\" scrolling command
578 attempted to scroll.")
579
580 (defvar scroll-goal-column 0
581 "The desired horizontal window position for point, used by the \"in place\"
582 scrolling commands.")
583
584 (defvar scroll-boundary-previous-point nil
585 "The value of point before point was moved to a buffer boundary.")
586
587 (defvar scroll-boundary-previous-lines 0
588 "The number of lines that point moved when it moved to a buffer boundary.")
589
590 (defvar scroll-boundary-error-command nil
591 "The value of `this-command' when an \"in place\" scrolling command signalled
592 a buffer boundary error. This is used to decide how subsequent scrolling
593 commands should recover from the error.")
594
595 (defvar scroll-boundary-error-point nil
596 "The value of point when an \"in place\" scrolling command signalled a buffer
597 boundary error. This is used to decide how subsequent scrolling commands
598 should recover from the error."
599 ;; This variable is used as a flag, indicating whether or not the previous
600 ;; "in place" scrolling command signalled an error.
601 )
602
603 (defvar scroll-window-debt 0
604 "The difference between the number of lines an \"in place\" scrolling command
605 tried to scroll a window and the number of lines that the window actually
606 scrolled. This difference is the \"debt\" in the window's starting position.
607 Subsequent \"in place\" scrolling commands try to make up this debt.")
608
609 (defconst scroll-pos-visible-bug-p
610 ;; On September 14, 1993, David Hughes <djh@Harston.CV.COM> told me that
611 ;; Lucid GNU Emacs 19.8 had inherited the bug from Epoch... sigh.
612 (let ((old-match-data (match-data)))
613 (unwind-protect
614 (or (and (boundp 'epoch::version)
615 (if (string-match "\\`4\\." emacs-version) t nil)
616 )
617 (and (string-match "Lucid" emacs-version)
618 (if (string-match "\\`19\\.8\\." emacs-version) t nil)
619 )
620 )
621 (store-match-data old-match-data)))
622 "A flag, set when this version of GNU Emacs has a buggy version of the
623 function `pos-visible-in-window-p' that returns `nil' when given `(point-max)'
624 and `(point-max)' is on the last line of the window. Currently, this flag is
625 set for all versions of Epoch 4 and for Lucid GNU Emacs 19.8.")
626
627
628 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
629 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
630 ;;;;
631 ;;;; Here are the window-choosing auxiliary functions used by the new scrolling
632 ;;;; commands.
633 ;;;;
634 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
635 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
636
637 (defun scroll-choose-window ()
638 "Choose the window to be scrolled by the commands `scroll-down', `scroll-up',
639 `scroll-down-in-place', and `scroll-up-in-place'.
640
641 The rules are simple. If the selected window is not a minibuffer window, then
642 just choose the selected window.
643
644 However, when a minibuffer window is selected, look first for the `minibuffer-
645 scroll-window'. The `minibuffer-scroll-window' is usually the window that
646 displays completions. If it exists, choose it; otherwise choose the next
647 window after the selected window in the canonical ordering of windows. The
648 next window is generally the one below the selected window, or the one at the
649 top of the screen if the selected window is at the bottom of the screen."
650 (let ((selected-window (selected-window)))
651 (if (window-minibuffer-p selected-window)
652 ;; A minibuffer window is selected --- scroll some other window.
653 (if (window-live-p minibuffer-scroll-window)
654 minibuffer-scroll-window
655 ;; We know that the (selected) minibuffer is active, so `next-window'
656 ;; will examine all of the frames that share this minibuffer.
657 ;; Should we consider `other-window-scroll-buffer' here? I don't
658 ;; believe so.
659 (next-window selected-window))
660 selected-window)))
661
662 ;;;
663 ;;;
664 ;;;
665
666 (defun scroll-choose-other-window ()
667 "Choose the window to be scrolled by the commands `scroll-other-window-down',
668 `scroll-other-window', `scroll-other-window-down-in-place', and `scroll-other-
669 window-in-place'.
670
671 The rules are these. If the selected window is not a minibuffer window, then
672 choose either:
673
674 + a window that displays the `other-window-scroll-buffer', if that buffer
675 exists. Note, this function will display that buffer if necessary.
676
677 + the next window after the selected window in the canonical ordering of
678 windows. The next window is generally the one below the selected window,
679 or the one at the top of the screen if the selected window is at the bottom
680 of the screen.
681
682 However, when a minibuffer window is selected, look first for the `minibuffer-
683 scroll-window'. The `minibuffer-scroll-window' is usually the window that
684 displays completions. If it exists, choose it; otherwise choose the window to
685 be scrolled as described above (`other-window-scroll-buffer' or next window).
686
687 This function is essentially a Lisp version of the function `other-window-for-
688 scrolling' which first appeared in the FSF's GNU Emacs 19.26."
689 (let* ((no-error nil)
690 (selected-window (selected-window))
691 (other-window nil))
692 (setq other-window
693 (cond ((and (window-minibuffer-p selected-window)
694 (window-live-p minibuffer-scroll-window))
695 ;; Don't signal an error when `minibuffer-scroll-window' is
696 ;; the minibuffer itself --- which would be really weird, but
697 ;; isn't necessarily erroneous.
698 (setq no-error t)
699 minibuffer-scroll-window)
700
701 ((and ;; `other-window-scroll-buffer' is an Emacs 19 invention.
702 (boundp 'other-window-scroll-buffer)
703 (bufferp other-window-scroll-buffer)
704 ;; `buffer-name' is `nil' if the buffer has been killed.
705 (buffer-name other-window-scroll-buffer))
706 ;; This is what FSF GNU Emacs 19.26 does, but it occurred to
707 ;; me: what if one of these forms returns the selected window?
708 ;; Signalling an error would be bad news, so I added a flag.
709 (setq no-error t)
710 (or (get-buffer-window other-window-scroll-buffer)
711 (display-buffer other-window-scroll-buffer t)))
712
713 ((let ((next-window (next-window selected-window)))
714 (if (eq next-window selected-window)
715 nil
716 next-window)))
717
718 (t
719 ;; In Emacs 19 (FSF, Lucid, and XEmacs), look for a window on
720 ;; another visible frame. This could be written for
721 ;; Epoch, too, I suppose...
722 (condition-case nil
723 (let ((this-window (next-window selected-window nil t)))
724 (while (not (or (eq this-window selected-window)
725 (scroll-choose-window-frame-visible-p
726 this-window)))
727 (setq this-window (next-window this-window nil t)))
728 this-window)
729 ;; In older versions of Emacs, `next-window' didn't accept
730 ;; three arguments. Catch this error and then return the
731 ;; selected window --- which will cause another error to be
732 ;; signalled later on.
733 (wrong-number-of-arguments selected-window))
734 )
735 ))
736
737 (if (and (not no-error)
738 (eq selected-window other-window))
739 (error "There is no other window."))
740 other-window))
741
742 ;;;
743 ;;;
744 ;;;
745
746 (defun scroll-choose-window-frame-visible-p (window)
747 "Return a true value if the frame of the given WINDOW is visible."
748 (cond ((fboundp 'window-frame)
749 (eq t (frame-visible-p (window-frame window))))
750 (t t)))
751
752
753 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
754 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
755 ;;;;
756 ;;;; Here are the "in place" scrolling commands (interactive functions) and the
757 ;;;; replacements for the standard GNU Emacs vertical scrolling commands.
758 ;;;;
759 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
760 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
761
762 ;;;;
763 ;;;; Here are the new scroll "in place" commands.
764 ;;;;
765
766 (defun scroll-down-in-place (&optional lines)
767 "Scroll the text of the current window downward by LINES lines, leaving point
768 as close as possible to its current window position (window line and column).
769 In other words, point is left \"in place\" within the window. As a special
770 case, when the current window is a minibuffer window, this command scrolls the
771 `minibuffer-scroll-window' (which is usually the list of completions) if it
772 exists, or otherwise the next window in the canonical ordering of windows.
773
774 If the optional argument LINES is `nil', scroll the window by the same amount
775 it was moved by the immediately previous \"in place\" scrolling command, or by
776 the value of the variable `scroll-default-lines' (usually almost a windowful)
777 if the previous command was not an \"in place\" scrolling command (or when that
778 previous command scrolled some other window, or when other circumstances
779 prevent the previous scrolling distance from being used). If LINES is the
780 symbol `-', then the scrolling distance is determined as if LINES had been
781 `nil' and then that distance is multiplied by -1.
782
783 If the window cannot be scrolled by the full distance, point is allowed to
784 stray from its initial position so that it can move the full number of lines.
785 If point cannot move the full number of lines, point is moved to the buffer
786 boundary. Any immediately subsequent \"in place\" scrolling commands will try
787 to restore point to its initial window position."
788 (interactive "P")
789 (scroll-window-in-place (scroll-choose-window) lines -1))
790
791 ;;;
792 ;;;
793 ;;;
794
795 (defun scroll-up-in-place (&optional lines)
796 "Scroll the text of the current window upward by LINES lines, leaving point
797 as close as possible to its current window position (window line and column).
798 In other words, point is left \"in place\" within the window. As a special
799 case, when the current window is a minibuffer window, this command scrolls the
800 `minibuffer-scroll-window' (which is usually the list of completions) if it
801 exists, or otherwise the next window in the canonical ordering of windows.
802
803 If the optional argument LINES is `nil', scroll the window by the same amount
804 it was moved by the immediately previous \"in place\" scrolling command, or by
805 the value of the variable `scroll-default-lines' (usually almost a windowful)
806 if the previous command was not an \"in place\" scrolling command (or when that
807 previous command scrolled some other window, or when other circumstances
808 prevent the previous scrolling distance from being used). If LINES is the
809 symbol `-', then the scrolling distance is determined as if LINES had been
810 `nil' and then that distance is multiplied by -1.
811
812 If the window cannot be scrolled by the full distance, point is allowed to
813 stray from its initial position so that it can move the full number of lines.
814 If point cannot move the full number of lines, point is moved to the buffer
815 boundary. Any immediately subsequent \"in place\" scrolling commands will try
816 to restore point to its initial window position."
817 (interactive "P")
818 (scroll-window-in-place (scroll-choose-window) lines 1))
819
820 ;;;
821 ;;; The command `scroll-other-window-down' first appeared in FSF GNU Emacs
822 ;;; 19.26.
823 ;;;
824
825 (defun scroll-other-window-down-in-place (&optional lines)
826 "Scroll the text of the next window downward by LINES lines, leaving point in
827 that window as close as possible to its current window position (window line
828 and column). In other words, point is left \"in place\" within the window.
829 The next window is generally the one below the current one, or the one at the
830 top of the screen if the current window is at the bottom of the screen. In
831 special circumstances this command will scroll a window other than the next
832 window. Read the documentation for the function `scroll-choose-other-window'
833 for details.
834
835 If the optional argument LINES is `nil', scroll the window by the same amount
836 it was moved by the immediately previous \"in place\" scrolling command, or by
837 the value of the variable `scroll-default-lines' (usually almost a windowful)
838 if the previous command was not an \"in place\" scrolling command (or when that
839 previous command scrolled some other window, or when other circumstances
840 prevent the previous scrolling distance from being used). If LINES is the
841 symbol `-', then the scrolling distance is determined as if LINES had been
842 `nil' and then that distance is multiplied by -1.
843
844 If the window cannot be scrolled by the full distance, point is allowed to
845 stray from its initial position so that it can move the full number of lines.
846 If point cannot move the full number of lines, point is moved to the buffer
847 boundary. Any immediately subsequent \"in place\" scrolling commands will try
848 to restore point to its initial window position.
849
850 If it is impossible to scroll the text of the window at all (because a buffer
851 boundary is already visible), this command signals a buffer boundary error.
852 The error is signalled even if point could otherwise move the full number of
853 lines."
854 (interactive "P")
855 (scroll-window-in-place (scroll-choose-other-window) lines -1))
856
857 ;;;
858 ;;;
859 ;;;
860
861 (defun scroll-other-window-in-place (&optional lines)
862 "Scroll the text of the next window upward by LINES lines, leaving point in
863 that window as close as possible to its current window position (window line
864 and column). In other words, point is left \"in place\" within the window.
865 The next window is generally the one below the current one, or the one at the
866 top of the screen if the current window is at the bottom of the screen. In
867 special circumstances this command will scroll a window other than the next
868 window. Read the documentation for the function `scroll-choose-other-window'
869 for details.
870
871 If the optional argument LINES is `nil', scroll the window by the same amount
872 it was moved by the immediately previous \"in place\" scrolling command, or by
873 the value of the variable `scroll-default-lines' (usually almost a windowful)
874 if the previous command was not an \"in place\" scrolling command (or when that
875 previous command scrolled some other window, or when other circumstances
876 prevent the previous scrolling distance from being used). If LINES is the
877 symbol `-', then the scrolling distance is determined as if LINES had been
878 `nil' and then that distance is multiplied by -1.
879
880 If the window cannot be scrolled by the full distance, point is allowed to
881 stray from its initial position so that it can move the full number of lines.
882 If point cannot move the full number of lines, point is moved to the buffer
883 boundary. Any immediately subsequent \"in place\" scrolling commands will try
884 to restore point to its initial window position.
885
886 If it is impossible to scroll the text of the window at all (because a buffer
887 boundary is already visible), this command signals a buffer boundary error.
888 The error is signalled even if point could otherwise move the full number of
889 lines."
890 (interactive "P")
891 (scroll-window-in-place (scroll-choose-other-window) lines 1))
892
893 ;;;;
894 ;;;; Here are the replacements for GNU Emacs' standard vertical scrolling
895 ;;;; commands.
896 ;;;;
897
898 (or (fboundp 'original-scroll-down)
899 (fset 'original-scroll-down (symbol-function 'scroll-down)))
900 (or (fboundp 'original-scroll-up)
901 (fset 'original-scroll-up (symbol-function 'scroll-up)))
902 (or (fboundp 'original-scroll-other-window-down)
903 ;; `scroll-other-window-down' first appeared in FSF GNU Emacs 19.26.
904 (if (fboundp 'scroll-other-window-down)
905 (fset 'original-scroll-other-window-down
906 (symbol-function 'scroll-other-window-down))
907 ))
908 (or (fboundp 'original-scroll-other-window)
909 (fset 'original-scroll-other-window (symbol-function 'scroll-other-window))
910 )
911
912 ;;;
913 ;;;
914 ;;;
915
916 (defun scroll-down (&optional lines)
917 "Scroll the text of the current window downward by LINES lines. As a special
918 case, when the current window is a minibuffer window, this command scrolls the
919 `minibuffer-scroll-window' (which is usually the list of completions) if it
920 exists, or otherwise the next window in the canonical ordering of windows.
921
922 The argument LINES is optional. Its meaning depends on the current value of
923 the variable `scroll-in-place'.
924
925 When the variable `scroll-in-place' is true, this command works just like the
926 command `scroll-down-in-place', scrolling the current window and leaving point
927 \"in place\" within the window. See the documentation for the command
928 `scroll-down-in-place' for more information.
929
930 When the variable `scroll-in-place' is `nil' this command invokes the standard
931 GNU Emacs version of `scroll-down'. In that case, when LINES is `nil' the
932 current window is scrolled by nearly a complete windowful of text.
933
934 Note that this command correctly handles cases in which `scroll-in-place' has a
935 buffer-local value in the window to be scrolled. That value is honored."
936 (interactive "P")
937 (scroll-window (scroll-choose-window) lines -1))
938
939 ;;;
940 ;;;
941 ;;;
942
943 (defun scroll-up (&optional lines)
944 "Scroll the text of the current window upward by LINES lines. As a special
945 case, when the current window is a minibuffer window, this command scrolls the
946 `minibuffer-scroll-window' (which is usually the list of completions) if it
947 exists, or otherwise the next window in the canonical ordering of windows.
948
949 The argument LINES is optional. Its meaning depends on the current value of
950 the variable `scroll-in-place'.
951
952 When the variable `scroll-in-place' is true, this command works just like the
953 command `scroll-up-in-place', scrolling the current window and leaving point
954 \"in place\" within the window. See the documentation for the command
955 `scroll-up-in-place' for more information.
956
957 When the variable `scroll-in-place' is `nil' this command invokes the standard
958 GNU Emacs version of `scroll-up'. In that case, when LINES is `nil' the
959 current window is scrolled by nearly a complete windowful of text.
960
961 Note that this command correctly handles cases in which `scroll-in-place' has a
962 buffer-local value in the window to be scrolled. That value is honored."
963 (interactive "P")
964 (scroll-window (scroll-choose-window) lines 1))
965
966 ;;;
967 ;;; NOTE that in the FSF GNU Emacs 19.26 version of `scroll-other-window-down',
968 ;;; the `lines' argument is required. I've left it optional in order to be
969 ;;; like `scroll-other-window'.
970 ;;;
971
972 (defun scroll-other-window-down (&optional lines)
973 "Scroll the text of the next window downward by LINES lines. The next window
974 is generally the one below the current one, or the one at the top of the screen
975 if the current window is at the bottom of the screen. In special circumstances
976 this command will scroll a window other than the next window. Read the
977 documentation for the function `scroll-choose-other-window' for details.
978
979 The argument LINES is optional. Its meaning depends on the current value of
980 the variable `scroll-in-place'.
981
982 When the variable `scroll-in-place' is true, this command works just like the
983 command `scroll-other-window-down-in-place', scrolling the next window and
984 leaving point \"in place\" within that window. See the documentation for the
985 command `scroll-other-window-down-in-place' for more information.
986
987 When the variable `scroll-in-place' is `nil' this command invokes the standard
988 GNU Emacs version of `scroll-other-window-down'. In that case, when LINES is
989 `nil' the next window is scrolled by nearly a complete windowful of text.
990 \(Note that `scroll-other-window-down' first appeared as a standard command in
991 the FSF's GNU Emacs 19.26. If the builtin version of that command is not
992 available in the current Emacs system, an equivalent action is invoked
993 instead.)
994
995 Note that this command correctly handles cases in which `scroll-in-place' has a
996 buffer-local value in the window to be scrolled. That value is honored."
997 (interactive "P")
998 ;; This code is similar to the body of `scroll-window', below.
999 (let* ((other-window (scroll-choose-other-window))
1000 (other-window-buffer (window-buffer other-window)))
1001 (if ;; Allow `scroll-in-place' to be a buffer-local variable.
1002 (save-excursion (set-buffer other-window-buffer) scroll-in-place)
1003 (scroll-window-in-place other-window lines -1)
1004
1005 ;; Paranoid, we forcibly break any running sequence of "in place"
1006 ;; scrolling commands.
1007 (setq scroll-previous-window nil)
1008 ;; For XEmacs and Lucid GNU Emacs, preserve the region's state.
1009 (if (boundp 'zmacs-region-stays)
1010 (setq zmacs-region-stays t))
1011 (if (fboundp 'original-scroll-other-window-down)
1012 (original-scroll-other-window-down lines)
1013 ;; `scroll-other-window-down' first appeared as a builtin in FSF GNU
1014 ;; Emacs 19.26, so it may not be available in the current Emacs system.
1015 ;; Do the equivalent thing.
1016 (original-scroll-other-window (cond
1017 ((null lines) '-)
1018 ((eq lines '-) nil)
1019 (t (- (prefix-numeric-value lines)))
1020 ))
1021 ))
1022 ))
1023
1024 ;;;
1025 ;;;
1026 ;;;
1027
1028 (defun scroll-other-window (&optional lines)
1029 "Scroll the text of the next window upward by LINES lines. The next window
1030 is generally the one below the current one, or the one at the top of the screen
1031 if the current window is at the bottom of the screen. In special circumstances
1032 this command will scroll a window other than the next window. Read the
1033 documentation for the function `scroll-choose-other-window' for details.
1034
1035 The argument LINES is optional. Its meaning depends on the current value of
1036 the variable `scroll-in-place'.
1037
1038 When the variable `scroll-in-place' is true, this command works just like the
1039 command `scroll-other-window-in-place', scrolling the next window and leaving
1040 point \"in place\" within that window. See the documentation for the command
1041 `scroll-other-window-in-place' for more information.
1042
1043 When the variable `scroll-in-place' is `nil' this command invokes the standard
1044 GNU Emacs version of `scroll-other-window'. In that case, when LINES is `nil'
1045 the next window is scrolled by nearly a complete windowful of text.
1046
1047 Note that this command correctly handles cases in which `scroll-in-place' has a
1048 buffer-local value in the window to be scrolled. That value is honored."
1049 (interactive "P")
1050 ;; This code is similar to the body of `scroll-window', below.
1051 (let* ((other-window (scroll-choose-other-window))
1052 (other-window-buffer (window-buffer other-window)))
1053 (if ;; Allow `scroll-in-place' to be a buffer-local variable.
1054 (save-excursion (set-buffer other-window-buffer) scroll-in-place)
1055 (scroll-window-in-place other-window lines 1)
1056
1057 ;; Paranoid, we forcibly break any running sequence of "in place"
1058 ;; scrolling commands.
1059 (setq scroll-previous-window nil)
1060 ;; For XEmacs and Lucid GNU Emacs, preserve the region's state.
1061 (if (boundp 'zmacs-region-stays)
1062 (setq zmacs-region-stays t))
1063 (original-scroll-other-window lines))
1064 ))
1065
1066
1067 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1068 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1069 ;;;;
1070 ;;;; Here are the new functions `scroll-window-in-place', `scroll-window', and
1071 ;;;; `scroll-window-in-place-continue-sequence'. These functions are intended
1072 ;;;; to be available to programs outside this package.
1073 ;;;;
1074 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1075 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1076
1077 (defun scroll-window-in-place (window lines direction)
1078 "Scroll WINDOW vertically by the given number of window LINES in the given
1079 DIRECTION, leaving the window's point as close as possible to its original
1080 window position (window line and column). In other words, the window's point
1081 is left \"in place\" within the window.
1082
1083 Note that the window to be scrolled does not have to be the selected window,
1084 and that this function does not change which window is selected.
1085
1086 LINES specifies the number of window lines to scroll and is interpreted as if
1087 it were a raw prefix argument. If LINES is `nil', the window is scrolled by
1088 the amount it was moved by the immediately previous \"in place\" scrolling
1089 command, or by the value of the variable `scroll-default-lines' (by default,
1090 almost a windowful) if the previous command was not an \"in place\" scrolling
1091 command (or when WINDOW is not the previously scrolled window, or when the
1092 value of `this-command' is not in the same group as the previous scrolling
1093 command (see the documentation for the variable `scroll-command-groups'), or
1094 when other circumstances prevent the previous scrolling distance from being
1095 used). If LINES is the symbol `-', then the scrolling distance is determined
1096 as if LINES had been `nil' and then that distance is multiplied by -1.
1097
1098 DIRECTION determines the direction of the scrolling motion. The values -1 and
1099 `down' indicate downward motion; the values 1 and `up' indicate upward motion.
1100 Any other value causes an error.
1101
1102 If the window cannot be scrolled by the full distance (because the window hits
1103 the boundary of its buffer), the window's point is allowed to stray from its
1104 initial position so that it can move the full number of lines. If point cannot
1105 move the full number of lines, point is moved to the buffer boundary (unless it
1106 was already there, in which case a buffer boundary error is signalled instead).
1107 Any immediately subsequent \"in place\" scrolling commands will try to restore
1108 point to its initial window position.
1109
1110 Unless the variable `scroll-allow-blank-lines-past-eob' is true, this function
1111 avoids displaying blank lines past the end of the buffer except as necessary to
1112 make a previous \"in place\" scrolling action reversible. Effectively, this
1113 means that this function will not display any more past-end-of-buffer blank
1114 lines than were visible when the current sequence of \"in place\" scrolling
1115 commands started. When the variable `scroll-allow-blank-lines-past-eob' is
1116 true, this function will display as many blank lines as is necessary to keep
1117 point \"in place\" in the window.
1118
1119 Note that if WINDOW is not the selected window and it is impossible to scroll
1120 the text of WINDOW at all (because a buffer boundary is already visible), then
1121 this function signals a buffer boundary error. The error is signalled even if
1122 point could otherwise move the full number of lines."
1123 (let* (;; Make sure that the user doesn't quit in the middle and leave us
1124 ;; with our variables out of sync.
1125 (inhibit-quit t)
1126 (original-window (selected-window))
1127 (original-buffer (current-buffer))
1128 (window-height (- (window-height window)
1129 (if (window-minibuffer-p window)
1130 0 1)))
1131 (this-command-group (scroll-get-command-group this-command))
1132 (continue-scroll-p
1133 (and ;; We're scrolling the previously scrolled window...
1134 (windowp scroll-previous-window)
1135 (eq window scroll-previous-window)
1136 ;; ...and the last command was an "in place" scrolling command
1137 ;; that can be continued by this command.
1138 (if (eq last-command t)
1139 ;; If the previous command signalled an error, the value of
1140 ;; `last-command' is `t'. Try to see if we signalled the
1141 ;; error and if point is where we left it. (NOTE that FSF
1142 ;; GNU Emacs 19.23+ no longer sets `last-command' to `t'
1143 ;; when a command signals an error. This is OK because the
1144 ;; else part of this `if' does the appropriate thing.)
1145 (and scroll-boundary-error-point
1146 (eq (window-point window) scroll-boundary-error-point)
1147 (memq scroll-boundary-error-command this-command-group)
1148 )
1149 ;; Otherwise...
1150 (memq last-command this-command-group))
1151 ))
1152 (lines-value (prefix-numeric-value lines))
1153 )
1154
1155 ;; For XEmacs and Lucid GNU Emacs, preserve the region's state. Note that
1156 ;; these Emacsen will forcibly deactivate the region if we signal an error
1157 ;; later on. Is this bad?
1158 (if (boundp 'zmacs-region-stays)
1159 (setq zmacs-region-stays t))
1160 ;; Parse the direction into a unit distance (1 or -1).
1161 (setq direction (scroll-parse-direction direction))
1162
1163 (setq scroll-previous-window window
1164 ;; `(setq scroll-boundary-error-command nil)' is not necessary.
1165 scroll-boundary-error-point nil)
1166 (unwind-protect
1167 (progn
1168 ;; `select-window' does an implicit `set-buffer'.
1169 (select-window window)
1170
1171 (if (or ;; The current command is not a continuation of a running
1172 ;; sequence of "in place" scrolling commands...
1173 (not continue-scroll-p)
1174 ;; ...or we were given an explicit number of lines to scroll,
1175 ;; and that number has a different magnitude than the last
1176 ;; number of lines we scrolled...
1177 (and (or (numberp lines) (consp lines))
1178 (/= scroll-previous-lines lines-value)
1179 (/= scroll-previous-lines (- lines-value)))
1180 ;; ...or the last successful scrolling command moved to a
1181 ;; buffer boundary, but the buffer is no longer in the state
1182 ;; we left it. (This can occur if, for example, we signal an
1183 ;; end-of-buffer error and something catches it and moves
1184 ;; point or renarrows. VM, for example, does this.)
1185 (and scroll-boundary-previous-point
1186 (or (not (or (bobp) (eobp)))
1187 (< scroll-boundary-previous-point (point-min))
1188 (> scroll-boundary-previous-point (point-max))
1189 (eq scroll-boundary-previous-point (point)))))
1190
1191 ;; We're starting a new sequence of scrolling commands.
1192 (setq lines (if (or (numberp lines) (consp lines))
1193 lines-value
1194 ;; The default number of lines...
1195 (* (if (eq lines '-) -1 1)
1196 (if (numberp scroll-default-lines)
1197 scroll-default-lines
1198 (max (- window-height
1199 next-screen-context-lines)
1200 1))))
1201 scroll-previous-lines lines
1202 scroll-goal-column (scroll-determine-goal-column window)
1203 scroll-boundary-previous-point nil
1204 ;; `(setq scroll-boundary-previous-lines 0)' is not
1205 ;; necessary.
1206 scroll-window-debt 0
1207 scroll-initially-displayed-lines
1208 (if scroll-allow-blank-lines-past-eob
1209 0
1210 (save-excursion
1211 (goto-char (window-start window))
1212 (vertical-motion (1- window-height)))))
1213
1214 ;; Otherwise we want to scroll by the same number of lines (but
1215 ;; possibly in a different direction) that we scrolled in previous
1216 ;; invocations of this function.
1217 (cond ((null lines)
1218 (setq lines scroll-previous-lines))
1219 ((eq lines '-)
1220 (setq lines (- scroll-previous-lines)
1221 scroll-previous-lines lines))
1222 (t
1223 (setq lines lines-value
1224 scroll-previous-lines lines)))
1225 )
1226
1227 (setq lines (* direction lines))
1228
1229 ;; If point is not in the window, center window around point. We try
1230 ;; to account for a bug in `pos-visible-in-window-p' in some versions
1231 ;; of Emacs (see `scroll-pos-visible-bug-p', above).
1232 (save-excursion
1233 (if (pos-visible-in-window-p (let ((point (point)))
1234 (if (and scroll-pos-visible-bug-p
1235 (= point (point-max)))
1236 (max (1- point) (point-min))
1237 point))
1238 window)
1239 nil
1240 (vertical-motion (/ (- window-height) 2))
1241 (set-window-start window (point))))
1242
1243 (cond ((and scroll-boundary-previous-point
1244 ;; `lines' is the same sign as the direction from point
1245 ;; to the `scroll-boundary-previous-point'.
1246 (cond ((> lines 0)
1247 (> (- scroll-boundary-previous-point (point)) 0))
1248 ((< lines 0)
1249 (< (- scroll-boundary-previous-point (point)) 0))
1250 (t nil)))
1251 ;; We're moving away from the buffer boundary.
1252 (goto-char scroll-boundary-previous-point)
1253 ;; Always move here (i.e., don't reject cases in which the
1254 ;; window doesn't move).
1255 (scroll-set-window-start window
1256 (- scroll-boundary-previous-lines))
1257 ;; (message "Back, window debt is %s." scroll-window-debt)
1258 (setq scroll-boundary-previous-point nil))
1259
1260 ((= lines 0)
1261 ;; We're going nowhere, so save ourselves some work.
1262 ;; (message "Scrolled zero lines.")
1263 )
1264
1265 (t
1266 ;; Perform the scrolling motion.
1267 (let ((initial-point (point))
1268 (moved nil))
1269 ;; First move point and see how far it goes.
1270 (setq moved (vertical-motion lines))
1271 (if (= moved lines)
1272 (progn
1273 ;; Point moved the full distance. Move to the desired
1274 ;; column and then try to move the window the full
1275 ;; distance, too.
1276 (move-to-column (+ (current-column)
1277 scroll-goal-column))
1278 (or (scroll-set-window-start window moved
1279 original-window)
1280 (scroll-signal-boundary-error initial-point
1281 lines))
1282 ;; (message "Normal, window debt is %s."
1283 ;; scroll-window-debt)
1284 )
1285 ;; Point couldn't move all the way. Move to the buffer
1286 ;; boundary if we're not already there, or signal a buffer
1287 ;; boundary error otherwise.
1288 (let ((boundary-point (if (< lines 0)
1289 (point-min)
1290 (point-max)))
1291 (boundary-symbol (if (< lines 0)
1292 'beginning-of-buffer
1293 'end-of-buffer)))
1294 (if (= initial-point boundary-point)
1295 (scroll-signal-boundary-error initial-point lines)
1296 ;; Scroll the window by as many lines as point could
1297 ;; move.
1298 (or (scroll-set-window-start window moved
1299 original-window)
1300 (scroll-signal-boundary-error initial-point
1301 lines))
1302 (message "%s" (get boundary-symbol 'error-message))
1303 ;; (message "Boundary, window debt is %s."
1304 ;; scroll-window-debt)
1305 (setq scroll-boundary-previous-lines moved)
1306 (setq scroll-boundary-previous-point initial-point)
1307 (goto-char boundary-point))
1308 )))
1309 )))
1310
1311 ;; The unwind forms of the `unwind-protect', above. Restore the
1312 ;; originally selected window and current buffer.
1313 (select-window original-window)
1314 (set-buffer original-buffer)))
1315
1316 ;; The standard GNU Emacs scrolling commands return `nil' so we do, too.
1317 nil)
1318
1319 ;;;
1320 ;;;
1321 ;;;
1322
1323 (defun scroll-window (window lines direction)
1324 "Scroll WINDOW vertically by the given number of window LINES in the given
1325 DIRECTION. Note that the window to be scrolled does not have to be the
1326 selected window, and that this function does not change which window is
1327 selected.
1328
1329 When the variable `scroll-in-place' is true, this function simply invokes the
1330 function `scroll-window-in-place' to scroll the window and leave point \"in
1331 place\" within that window. See the documentation for `scroll-window-in-place'
1332 for more information.
1333
1334 When the variable `scroll-in-place' is `nil' this function invokes the original
1335 version of the standard GNU Emacs command `scroll-down' or `scroll-up', as
1336 determined by DIRECTION, to scroll the window. If DIRECTION is -1 or `down',
1337 the original `scroll-down' is called; if DIRECTION is 1 or `up', the original
1338 `scroll-up' is called. Any other DIRECTION is an error. LINES is interpreted
1339 as if it were a raw prefix argument. If LINES is `nil', the window is scrolled
1340 by almost a complete windowful. If LINES is the symbol `-', the window is
1341 scrolled by almost a complete windowful in the opposite direction.
1342
1343 Note that this function correctly handles cases in which `scroll-in-place' has
1344 a buffer-local value in the WINDOW's buffer. That value is honored."
1345 (let ((current-buffer (current-buffer))
1346 (selected-window (selected-window))
1347 (window-buffer (window-buffer window)))
1348 (if ;; Allow `scroll-in-place' to be a buffer-local variable.
1349 (if (eq current-buffer window-buffer)
1350 scroll-in-place
1351 (save-excursion (set-buffer window-buffer) scroll-in-place))
1352 (scroll-window-in-place window lines direction)
1353
1354 (unwind-protect
1355 (progn
1356 ;; Paranoid, we forcibly break any running sequence of "in place"
1357 ;; scrolling commands.
1358 (setq scroll-previous-window nil)
1359 ;; For XEmacs and Lucid GNU Emacs, preserve the region's state.
1360 (if (boundp 'zmacs-region-stays)
1361 (setq zmacs-region-stays t))
1362 (select-window window)
1363 (if (= (scroll-parse-direction direction) 1)
1364 (original-scroll-up lines)
1365 (original-scroll-down lines)))
1366 (select-window selected-window)
1367 (set-buffer current-buffer))
1368 )))
1369
1370 ;;;
1371 ;;; The following function is sometimes useful. For example, I call it from
1372 ;;; functions that are invoked by certain mouse button down events in order to
1373 ;;; preserve any running chain of "in place" scrolling commands. This lets me
1374 ;;; continue the sequence from my mouse button up functions.
1375 ;;;
1376 ;;; I haven't yet needed a function to purposely break a running sequence of
1377 ;;; "in place" scrolling commands. Such a function would be easy to write,
1378 ;;; however; just set the variable `scroll-previous-window' to `nil'.
1379 ;;;
1380
1381 (defun scroll-window-in-place-continue-sequence ()
1382 "If the previous command was a \"scroll in place\" command, set the variable
1383 `this-command' to the name of that previous command. This ensures that any
1384 running sequence of \"in place\" scrolling commands will not be broken by the
1385 current command. See the documentation for the commands `scroll-down-in-place'
1386 and `scroll-up-in-place' for more information about \"in place\" scrolling.
1387
1388 NOTE that you don't need to call this function if the current command scrolls
1389 in place! You only need to call this function when the current command is not
1390 a \"scroll in place\" command but you still want to preserve any running
1391 sequence of \"in place\" commands. Such situations are rare.
1392
1393 NOTE that this function sets `this-command' in order to trick the \"in place\"
1394 scrolling commands. If something else subsequently sets `this-command', any
1395 running sequence of scrolling commands will probably be broken anyway."
1396 (if (if (eq last-command t)
1397 ;; If `last-command' is `t', then the previous command signalled an
1398 ;; error. See if the last invocation of `scroll-window-in-place'
1399 ;; signalled an error. (NOTE that FSF GNU Emacs 19.23+ no longer
1400 ;; sets `last-command' to `t' when a command signals an error. This
1401 ;; is OK because the else part of this `if' does the appropriate
1402 ;; thing.)
1403 scroll-boundary-error-point
1404 ;; Otherwise, the value of `last-command' must belong to some group of
1405 ;; "in place" scrolling commands.
1406 (or (memq last-command scroll-default-command-group)
1407 (let ((groups scroll-command-groups)
1408 (found nil))
1409 (while (and groups (not found))
1410 (if (memq last-command (car groups))
1411 (setq found t)
1412 (setq groups (cdr groups)))
1413 )
1414 found)))
1415 (setq this-command last-command)))
1416
1417
1418 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1419 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1420 ;;;;
1421 ;;;; Here are the various auxiliary functions called by the function `scroll-
1422 ;;;; window-in-place'. None of the functions are intended to be called from
1423 ;;;; outside this package.
1424 ;;;;
1425 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1426 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1427
1428 (defun scroll-get-command-group (command)
1429 "Return the group of \"in place\" scrolling commands that contains the given
1430 COMMAND. This is the list of commands with which the given command may share
1431 state and form \"chains.\"
1432
1433 This function is an auxiliary for the function `scroll-window-in-place'. Don't
1434 call this function from other code."
1435 ;; This function assumes that the given command is an "in place" scrolling
1436 ;; command.
1437 (let ((groups scroll-command-groups)
1438 (found nil))
1439 (while (and groups (not found))
1440 (if (memq command (car groups))
1441 (setq found t)
1442 (setq groups (cdr groups)))
1443 )
1444 (if groups
1445 (car groups)
1446 ;; Otherwise return the default command group. If necessary, add the
1447 ;; given command to the default command group.
1448 (or (memq command scroll-default-command-group)
1449 (setq scroll-default-command-group
1450 (cons command scroll-default-command-group)))
1451 scroll-default-command-group)
1452 ))
1453
1454 ;;;
1455 ;;;
1456 ;;;
1457
1458 (defun scroll-parse-direction (direction)
1459 "Return the signed unit distance for the given DIRECTION. If DIRECTION is
1460 unacceptable, signal an error."
1461 (cond ((or (eq direction 1) (eq direction -1)) direction)
1462 ((eq direction 'up) 1)
1463 ((eq direction 'down) -1)
1464 (t (signal 'args-out-of-range (list 'direction direction)))
1465 ))
1466
1467 ;;;
1468 ;;;
1469 ;;;
1470
1471 (defun scroll-determine-goal-column (window)
1472 "Return the goal column for the \"in place\" vertical scrolling commands.
1473 This is the horizontal window position at which these commands try to keep
1474 point.
1475
1476 This function is an auxiliary for the function `scroll-window-in-place'. Don't
1477 call this function from other code."
1478 ;; NOTE that `window' must be the selected window! `scroll-window-in-place'
1479 ;; ensures that this is so.
1480 (cond ((or truncate-lines
1481 (and truncate-partial-width-windows
1482 (< (window-width window) (screen-width)))
1483 (> (window-hscroll window) 0))
1484 ;; Lines in this window are being truncated.
1485 (if (and track-eol (eolp))
1486 9999
1487 (current-column)))
1488 ((and track-eol (eolp))
1489 ;; In some ways this isn't quite right, as point doesn't track the
1490 ;; ends of wrapped lines. But if it did so, point would be on the
1491 ;; wrong window line. This is the best we can do.
1492 (1- (window-width window)))
1493 (t (% (current-column) (1- (window-width window))))
1494 ))
1495
1496 ;;;
1497 ;;;
1498 ;;;
1499
1500 (defun scroll-set-window-start (window lines &optional original-window)
1501 "Move the `window-start' of the given window, which must be the selected
1502 window. If the window was successfully scrolled, update the variable
1503 `scroll-window-debt' and return `t'. Otherwise return `nil'.
1504
1505 This function is an auxiliary for the function `scroll-window-in-place'. Don't
1506 call this function from other code."
1507 (save-excursion
1508 (goto-char (window-start window))
1509 ;; Try to move the window start by the specified number of lines. In
1510 ;; addition, try to make up any existing debt in the window start's
1511 ;; position and make sure that we don't move too close to the end of the
1512 ;; buffer.
1513 (let ((moved (+ (vertical-motion (+ lines
1514 scroll-window-debt
1515 scroll-initially-displayed-lines))
1516 (vertical-motion (- scroll-initially-displayed-lines)))))
1517 ;; If we're not scrolling the `original-window' (i.e., the originally
1518 ;; selected window), punt if we didn't move the window start at all.
1519 (if (and original-window
1520 (not (eq window original-window))
1521 (= moved 0))
1522 nil
1523 ;; Otherwise update the window start and keep track of the debt in our
1524 ;; position. Return `t' to indicate success.
1525 (set-window-start window (point))
1526 (setq scroll-window-debt (- (+ lines scroll-window-debt) moved))
1527 t))
1528 ))
1529
1530 ;;;
1531 ;;;
1532 ;;;
1533
1534 (defun scroll-signal-boundary-error (initial-point lines)
1535 "Move point to its initial location and signal an appropriate buffer boundary
1536 error.
1537
1538 This function is an auxiliary for the function `scroll-window-in-place'. Don't
1539 call this function from other code."
1540 (goto-char initial-point)
1541 ;; Remember what we were doing and where point was when we signalled the
1542 ;; error so that subsequent "in place" scrolling commands can decide how to
1543 ;; recover.
1544 (setq scroll-boundary-error-command this-command
1545 scroll-boundary-error-point initial-point)
1546 (signal (if (< lines 0) 'beginning-of-buffer 'end-of-buffer)
1547 nil))
1548
1549
1550 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1551 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1552 ;;;;
1553 ;;;; Finally, here is the `provide' statement.
1554 ;;;;
1555 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1556 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1557
1558 (provide 'scroll-in-place)
1559
1560 ;; End of file.
1561