I wrote recently about fill-paragraph-semlf and how I moved to it entirely with M-q. It quickly turned out that it wasn’t the best idea. Sometimes I want to be able to fill the paragraph in the old way, too. I figured that the best way to do it is to make M-q do that when pressed for the second time.
Now, there is the unfill package maintained by Steve Purcell, which introduces the unfill-toggle function. Binding it to M-q makes it alternate between filling and “unfilling” the paragraph (that is, turning it to one long line) when pressed more than one time. What I want is something even better – to have three options, semantic filling, unfilling and filling “normally”.
I think the simplest way to to achieve that is to introduce a global variable to keep the last operation performed by M-q in, much like what C-l (recenter-top-bottom) does.
(require 'cl-lib)
(defvar fill-paragraph-state nil
"The way the paragraph was filled the last time.")
;; From https://github.com/purcell/unfill/blob/master/unfill.el#L39
(defun unfill-paragraph ()
"Replace newline chars in current paragraph by single spaces.
This command does the inverse of `fill-paragraph'."
(interactive)
(let ((fill-column most-positive-fixnum))
(call-interactively 'fill-paragraph)))
(defun fill-paragraph-rotate ()
"Fill the current paragraph in one of three ways.
First, it fills the paragraph semantically, then, unfills it, and
finally, fills it in the traditional way."
(interactive)
(unless (eq last-command this-command)
(setq fill-paragraph-state nil))
(let (deactivate-mark)
(cl-case fill-paragraph-state
('fill-paragraph-semlf
(call-interactively 'unfill-paragraph)
(setq fill-paragraph-state 'unfill-paragraph))
('unfill-paragraph
(call-interactively 'fill-paragraph)
(setq fill-paragraph-state 'fill-paragraph))
(t
(call-interactively 'fill-paragraph-semlf)
(setq fill-paragraph-state 'fill-paragraph-semlf)))))
As you can see, the code is pretty simple. If the last command is not fill-paragraph-rotate, the state of the three-way toggle is reset, and then we perform the fill depending on how it was performed the last time.
One minor problem with this function is that in some modes, semantic filling just doesn’t work. For example, as I mentioned before, AUCTeX sets fill-paragraph-function to LaTeX-fill-paragraph, which apparently overrides fill-region-as-paragraph-function. This means that “traditional” and “semantic” filling does exactly the same thing in AUCTeX buffers. I could utilize fill-paragraph-function instead of fill-region-as-paragraph-function, but I don’t see the point. I don’t write in (La)TeX that often nowadays, and I can live without semantic filling in (La)TeX buffers. On the other hand, if I were still doing a lot of (La)TeX, I would probably do something about it. Semantic filling is especially valuable in LaTeX, where many people may collaborate on a plain text document written (mostly) in a natural language. Thing is, LaTeX-fill-paragraph seems extremely complex, and I don’t really want to invest a lot of time in a feature I would hardly ever need. Instead, I decided to suggest such a feature to AUCTeX developers.
Anyway, that’s it for today. Happy writing in Emacs!