notes from /dev/null

by Charles Choi 최민수


Fixing Emacs Page Navigation

12 Aug 2025  Charles Choi

In conventional word processors, it is common to use the page up and down keys on a keyboard to navigate pages in a document. Typically this entails moving the cursor position in the document so that it is at the start of the page, scrolled so that the cursor is at the top of the screen/window. Also with such programs a typographic presumption is made on what constitutes a “page.”

As Emacs is designed to work with plain text files that can have arbitrary structure, determining what a “page” is more abstract, as a variable called page-delimiter is used to determine the start of a page. Its default value is set to the control character ^L. The key sequence C-q C-l will enter ^L into the text file.

A file with embedded ^L characters can be navigated with the forward-page and backward-page commands. However these commands break convention with word processor behavior described above by only moving the point to where ^L is and not scrolling the document accordingly so that the point is at the top of the window.

To emulate the desired scroll behavior, we can couple our page navigation commands with the command recenter-top-bottom as shown below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
(defun cc/backward-page-at-top (&optional count)
  "Move backward page, moving point to top of window."
  (interactive)
  (backward-page count)
  (recenter-top-bottom 0))

(defun cc/forward-page-at-top (&optional count)
  "Move forward page, moving point to top of window."
  (interactive)
  (forward-page count)
  (recenter-top-bottom 0))

Bind these commands globally to the page up (cc/backward-page-at-top, <prior>) and down (cc/forward-page-at-top, <next>) keys and life is good, no? Actually these bindings should be made only for those major modes which use ^L to demarcate different sections. Such is the case with Emacs Lisp (Elisp). A binding example for it is as follows:

1
2
(keymap-set emacs-lisp-mode-map "<prior>" #'cc/backward-page-at-top)
(keymap-set emacs-lisp-mode-map "<next>" #'cc/forward-page-at-top)

Closing Thoughts

The convention of using ^L as a page delimiter goes way back to its actual ASCII definition as a printer form-feed character. It was co-opted by Emacs and vi to support page navigation, and if you find yourself in situation where you can use it, by all means do so. Any support for structural navigation is a win in my book.

If this is the first you’ve heard of ^L, now you know.

emacs

 

AboutMastodonBlueskyGitHub

Feeds & Tags
Get Scrim for macOSGet Captee for macOS

Powered by Pelican