Emacs: Form Feed and Source Code Section Paging Commands

Advertise Here

, ,

This page discusses some issues about the Form Feed character (^L) used in emacs, and commands to page thru source code sections.

Problem of “forward-paragraph” and “backward-paragraph”

Emacs has commands forward-paragraphCtrl+】 and backward-paragraphCtrl+】. The problem with these is that the definition of “paragraph” in emacs is not well defined; it depends on what mode you are in. For example, in text-mode, a paragraph is basically a text block separated by newline characters. But in html-mode, it moves by some weird way. (try view source of this page, open in emacs, and move.) Technically, this is because the notion of “paragraph” in emacs is dependent on emacs's syntax table. (emacs's syntax table is a elementary system that cagetorize character to a list of semantic categories. From my experience in the past few years, is not a good system, and i think emacs could do without.)

(info "(elisp) Syntax Tables")

“forward-block” and “backward-block”

I much prefer a key that always page by text block, as defined by newline sequences. So i wrote the following code:

(defun forward-block ()
  "Move cursor forward to next occurrence of double newline char.
In most major modes, this is the same as `forward-paragraph', however,
this function behaves the same in any mode.
“forward-paragraph” is mode dependent, because it depends on
syntax table that has different meaning for “paragraph”."
  (interactive)
  (skip-chars-forward "\n")
  (when (not (search-forward-regexp "\n[[:blank:]]*\n" nil t))
    (goto-char (point-max)) ) )

(defun backward-block ()
  "Move cursor backward to previous occurrence of double newline char.
See: `forward-block'"
  (interactive)
  (skip-chars-backward "\n")
  (when (not (search-backward-regexp "\n[[:blank:]]*\n" nil t))
    (goto-char (point-min))
    )
  )

You can assign a key like this:

(global-set-key (kbd "<C-up>") 'backward-block) ; Ctrl+↑
(global-set-key (kbd "<C-down>") 'forward-block) ; Ctrl+↓

This way, when you press a key to move by “paragraph”, the cursor movement is predictable.

Problems of Emacs's “forward-page” and “backward-page”

In Emacs Lisp convention, the Form Feed character (ASCII 12) is a indicator of a code section in a source code. There's a built-in command backward-pageCtrl+x [】 and forward-pageCtrl+x ]】 to page thru sections. In many emacs lisp source code files, you'll see lots of these chars, displayed as “^L”.

This convention has several problems:

So, in the end, using the form feed as section indicator has 2 problems. One is technical.

Alternative To Form Feed as Section Break Marker

So, overall, i think i'm going to move away from using form feed char in my elisp source code.

Unfortunately, there's no good or standard replacement. Usually, people just add a bunch of hyphen like this “-----” or equal sing “=====” or underscore “_____” or just a sequence of comment char, whatever it is in the language. These are hacks. The problem with these approach is you cannot have a key to do paging because the page marker varies.

So, a workaround i came up is to use the Unicode section sign “§” together with a bunch of dashes “-----”. The section sign is meant as a proper marker to indicate a code section. The line graph is meant to be a visual display for lack of better alternative at the moment. (better would be to have the editor automatically display the section char with a line after it.) For drawing lines, a more proper Unicode char than dash is the Unicode glyph the BOX DRAWINGS LIGHT HORIZONTAL (U+2500) like this “─────”. The problem is that it's harder to input.

So, my section break in elisp looks like this:

; § ────────────────────

“forward-section” and “backward-section”

So i wrote forward-section and backward-section to page by the “§” markup.

(defun forward-section ()
  "Move cursor forward to next occurrence of the SECTION SIGN § char (unicode 167)."
  (interactive)
  (when (not (search-forward-regexp "§" nil t))
    (goto-char (point-max)) ) )

(defun backward-section ()
  "Move cursor forward to previous occurrence of the SECTION SIGN § char (unicode 167)."
  (interactive)
  (when (not (search-backward-regexp "§" nil t))
    (goto-char (point-min)) ) )

Here's the keys i assigned for it:

(global-set-key (kbd "<s-prior>") 'backward-section) ; Win+PageUp
(global-set-key (kbd "<s-next>") 'forward-section) ; Win+PageDown

(global-set-key (kbd "<C-M-prior>") 'backward-page) ; Ctrl+Alt+PageUp
(global-set-key (kbd "<C-M-next>") 'forward-page) ; Ctrl+Alt+PageDown

For inputting the § char, press 【Ctrl+x 8 S】 (➲ Emacs and Unicode Tips). Or, you can define:

(define-key key-translation-map (kbd "H-s") (kbd "§")) ; SECTION SIGN. Hyper+s

Or, you can buy my Emacs Unicode Math Symbols Input Mode (xmsi-mode).

See also: Emacs: How to define Super & Hyper Keys.

(thanks to Miura Masahiro for the tip on inputting §.)

blog comments powered by Disqus