The variable ‘scroll-preserve-screen-position’ may be useful to some. When you scroll down, and up again, point should end up at the same position you started out with. The value can be toggled by the built in mode
Besides using the scrollbar, there are other ways for scrolling with the mouse. For GnuEmacs this can be found in mouse-drag.el (which should be installed by default) and for XEmacs you might use the simple replacement TrackScroll.
I like to align my window exactly to the relevant pieces of code. Being able to move the view while point stays at its place makes this easier.
(defun gcm-scroll-down () (interactive) (scroll-up 1))
(defun gcm-scroll-up () (interactive) (scroll-down 1))
(global-set-key [(control down)] 'gcm-scroll-down) (global-set-key [(control up)] 'gcm-scroll-up)
You can achieve the same effect and avoid writing those two defuns separately using the holy lambda() function. Here are my two bindings for scrolling the windows without moving the point.
(global-set-key "\M-n" (lambda () (interactive) (scroll-up 4)) ) (global-set-key "\M-p" (lambda () (interactive) (scroll-down 4)) )
But it’s usually better to use a named function: You can give it documentation, bind it to multiple keys, share it, advise it, etc. – SeanO
Point moves for me… 😟 What am I missing? (GNU Emacs 24.3.3) --mgalgs
I would like to bind my page up and page down keys to move the point a window-height number of lines rather than scrolling the window (of course scrolling would automatically happen since the point would move off the top or bottom of the window). If the point was close to the top, it would move it to the beginning of the buffer. If it was close to the bottom, it would move it to the end of the buffer. I’ve tried “
scroll-(down|up)-nomark” (from Pc selection mode) and “
scroll-(down|up)” (the Emacs default). None of them quite have the behavior I’m looking for (they scroll the window rather than move the point).
I searched help for “
pager-page-(down|up)” (using “
C-h a pager-page-up” and “
C-h f pager-page-up”). Doesn’t quite do what I want – it moves the point to keep it at the same position in the window when the window scrolls. It seems to provide the same functionality as setting
‘scroll-preserve-screen-position’ to non-nil (I’m using an Emacs 22 snapshot – 22.214.171.124 – in case that matters).
Further, suppose the window is 40 lines tall. I want
<PgDn> to behave as if I pressed the down arrow 40 times (except near the end of the document). Likewise, I want
<PgUp> to behave as if I pressed the up arrow 40 times (except near the beginning of the document). Is this possible?
I partially figured it out (adapted from some code on SmoothScrolling):
(defun sfp-page-down () (interactive) (next-line (- (window-text-height) next-screen-context-lines))) (defun sfp-page-up () (interactive) (previous-line (- (window-text-height) next-screen-context-lines))) (global-set-key [next] 'sfp-page-down) (global-set-key [prior] 'sfp-page-up)
The only problem is that it forgets which column I’m on: If I start at column 40, then page up/down and land on a line with only 10 characters, then page up/down to a line with more than 40 characters, the point will be at column 10, not column 40. This is odd considering the up/down arrow keys don’t have this problem and they’re bound to
This works, instead:
(defun sfp-page-down () (interactive) (setq this-command 'next-line) (next-line (- (window-text-height) next-screen-context-lines))) (defun sfp-page-up () (interactive) (setq this-command 'previous-line) (previous-line (- (window-text-height) next-screen-context-lines))) (global-set-key [next] 'sfp-page-down) (global-set-key [prior] 'sfp-page-up)
‘previous-line’ use a previously-remembered column number only if the previous command was either
‘previous-line’. Otherwise, they save the current column number to be used in future calls. Since the previous command was always either
‘sfp-page-up’, whatever column the point landed on would be used for the next destination column. So, I set
‘this-command’ to trick them. --sfp
To make the two functions more cooperative with the ShiftSelectMode of Emacs 23, you may add an (unused) argument and specify `^’ in interactive’s argument:
(&optional arg) (interactive "^P"). And for shift selection of CuaMode to work, you need to set the
‘CUA’ property. So, as a result of a discussion on Stackoverflow, these functions take the following form:
(defun sfp-page-down (&optional arg) (interactive "^P") (setq this-command 'next-line) (next-line (- (window-text-height) next-screen-context-lines))) (put 'sfp-page-down 'isearch-scroll t) (put 'sfp-page-down 'CUA 'move) (defun sfp-page-up (&optional arg) (interactive "^P") (setq this-command 'previous-line) (previous-line (- (window-text-height) next-screen-context-lines))) (put 'sfp-page-up 'isearch-scroll t) (put 'sfp-page-up 'CUA 'move)
The following shows how to use
‘condition-case’ as an alternative approach to extending the behavior for
When navigating the buffer with
‘scroll-down’ – from the traditional key bindings or otherwise – reaching the end of the buffer isn’t possible. In many applications, scrolling with Pgup or Pgdn would eventually get you to the top or the bottom. Emacs on the other hand will stop scrolling when the end of the buffer is reached. The philosophy (read: religion) is that scrolling commands are wholly separate from the point motion commands: Ideological purity that is imposed on the user because by the implementation. Fortunately, it doesn’t take much to customize Emacs to a more familiar behavior.
(global-set-key [next] (lambda () (interactive) (condition-case nil (scroll-up) (end-of-buffer (goto-char (point-max)))))) (global-set-key [prior] (lambda () (interactive) (condition-case nil (scroll-down) (beginning-of-buffer (goto-char (point-min))))))
Another way is to just enable cua-mode, which gives you this more modern behaviour by default.
But be advised that
‘cua-mode’ will change more behaviors than just that.
Emacs 24 has
(setq scroll-error-top-bottom t) to approximate this behavior.
Wouldn’t it be nice if when pressing C- and scrolling, your cursor moved around as if you were pressing on the arrows but in a far more sensitive way ? The only code you need is :
(define-key key-translation-map (kbd "<C-mouse-4>") (kbd "<up>")) (define-key key-translation-map (kbd "<C-mouse-5>") (kbd "<down>")) (global-set-key (kbd "<C-mouse-6>") 'left-char) (global-set-key (kbd "<C-mouse-7>") 'right-char)
With this config, you can even use it in term (terminal emulation) and enjoy new ways of navigating within commands like less, man or visidata.