One sentence per line
When using version control and collaborating with others it is useful1 to structure the file so that each sentence is in its own line. This way it is often easier to see what changes others have made in the diffs.
In Emacs one often uses M-q
, which is the fill-paragaph
function. This
refills (or reflows2) the paragraph so that it is no more than fill-column
characters wide. The problem with using it though is that if one changes even a
small thing in one sentence, the whole paragraph will typically need to be
refilled and each line will be changed. As a consequence, the diff in the
version control commit will look as if the whole paragraph was potentially
changed. This is terrible, horrible, abominable behavior3.
The way to fix it is to redefine M-q
to fill the paragraph in such a way that
each sentence is on its own line. Immediately a question and a problem appears.
What is a sentence? We are in luck. Emacs developers have seen it prudent to
think long and hard about just this problem and have blessed us with functions
forward-sentence
and backward-sentence
which are just what we need.
The plan is as follows. We will bind the shortcut M-q
to the function
ales/fill-paragraph
defined below. This function will first put the whole
paragraph that we are currently in into a single line. Then it will use
forward-sentence
to jump through the sentences and split the paragraph into
lines consisting of sentences. What could be easier?
(defun ales/fill-paragraph (&optional P)
"When called with prefix argument call `fill-paragraph'.
Otherwise split the current paragraph into one sentence per line."
(interactive "P")
(if (not P)
(save-excursion
(let ((fill-column 12345678)) ;; relies on dynamic binding
(fill-paragraph) ;; this will not work correctly if the paragraph is
;; longer than 12345678 characters (in which case the
;; file must be at least 12MB long. This is unlikely.)
(let ((end (save-excursion
(forward-paragraph 1)
(backward-sentence)
(point-marker)))) ;; remember where to stop
(beginning-of-line)
(while (progn (forward-sentence)
(<= (point) (marker-position end)))
(just-one-space) ;; leaves only one space, point is after it
(delete-char -1) ;; delete the space
(newline) ;; and insert a newline
(LaTeX-indent-line) ;; I only use this in combination with late, so this makes sense
))))
;; otherwise do ordinary fill paragraph
(fill-paragraph P)))
Then I just bind this function to M-q
in latex-mode
by doing
(define-key LaTeX-mode-map (kbd "M-q") 'ales/fill-paragraph)
And we are done. Easy peasy. This almost always™ works correctly, but sometimes Emacs gets confused as to what a sentence is.
Here it is in action.
-
It is a choice, as everything. At least the diffs look prettier this way. ↩
-
It would be a miracle if Emacs used standard terminology. As I said before, one must be prepared to suffer to use Emacs. It is not unlike certain religions. But then again, there is no happiness without suffering. ↩
-
And is something I have done until recently. Now I don’t anymore so I can preach and pretend that what I do now is much better and only scrubs do what I have done previously. ↩