Xah Lee, 2008-12-10, 2009-08-19
Emacs has a command “fill-paragraph” (Alt+q) that does hard wrap of current paragraph. (it inserts a newline char for every of ~70 chars.) This command is especially useful when writing email or plain text based report. Emacs also has fill-region, which acts on a text selection. Emacs also has fill-buffer, that does to a whole file's text. However, there are some usability problems with these commands. This page discuss the problems and some suggestions.
One frequently asked question is how to “unfill”. Namely, to do reverse of fill-paragraph. Technically, this means replacing newline chars by a space. Emacs does not have a built-in function for this or a keyboard shortcut. The typical answer to this question, is to set fill-column to a big value, then call fill-paragraph, then set fill-column back to previous value. This is inconvenient.
When user needs to break lines for several paragraphs of text, she need to call “fill-region”. There is no keyboard shortcut for it. It would be nice, if there is a hard-wrap command will automatically do fill-region when there is a text selection.
In the following, we suggest a command that “fill” or “unfill” the current paragraph. If the block of text the cursor is on is already “filled”, then the command will do “unfill”, and vice versa. In short, it's a toggle. Also, if there is a text selection, then the command automatically works on the region. This way, there is one single command with one single shortcut to remember.
Here is a implementation:
(defun compact-uncompact-block () "Remove or add line endings on the current block of text. This is similar to a toggle for fill-paragraph and unfill-paragraph When there is a text selection, act on the region. When in text mode, a paragraph is considered a block. When in programing language mode, the block defined by between empty lines. Todo: The programing language behavior is currently not done. Right now, the code uses fill* functions, so does not work or work well in programing lang modes. A proper implementation to compact is replacing newline chars by space when the newline char is not inside string. " (interactive) ;; This command symbol has a property “'stateIsCompact-p”, the ;; possible values are t and nil. This property is used to easily ;; determine whether to compact or uncompact, when this command is ;; called again (let (bds currentLineCharCount currentStateIsCompact (bigFillColumnVal 4333999) (deactivate-mark nil)) (save-excursion ;; currentLineCharCount is used to determine whether current state ;; is compact or not, when the command is run for the first time (setq currentLineCharCount (progn (setq bds (bounds-of-thing-at-point 'line)) (length (buffer-substring-no-properties (car bds) (cdr bds))) ;; Note: 'line includes newline char if it is not buffer's last line ) ) ;; Determine whether the text is currently compact. when the last ;; command is this, then symbol property easily tells, but when ;; this command is used fresh, right now we use num of chars of ;; the cursor line as a way to define current compatness state (setq currentStateIsCompact (if (eq last-command this-command) (get this-command 'stateIsCompact-p) (if (> currentLineCharCount fill-column) t nil) ) ) (if (and transient-mark-mode mark-active) (if currentStateIsCompact (fill-region (region-beginning) (region-end)) (let ((fill-column bigFillColumnVal)) (fill-region (region-beginning) (region-end))) ) (if currentStateIsCompact (fill-paragraph nil) (let ((fill-column bigFillColumnVal)) (fill-paragraph nil)) ) ) (put this-command 'stateIsCompact-p (if currentStateIsCompact nil t)) ) ) )
Note that the above inline doc, it mentions the behavior in computer language mode. In computer language mode, fill/unfill should behave by automatically formatting the current block of code. A “block” can easily be defined as the text between blank lines. How exactly a block of code is cut into lines can be determined by the language's syntax. For C-like syntax langs such as Java, Perl, JavaScript, etc, it is usually the semicolon “;”. For lisp, a unit is mostly syntactically delimited by matching parens. (note that emacs already has hundreds of bundled functions that handle code formatting for most languages.) Although, machine created formatting may not be as nice as human's manual formatting, but i think it can make this command a very useful supplement.
The command as it is above does not currently handle computer language code. However, it shouldn't be too difficult to implement. A simple heuristics based algorithm to determine where line ends (such as searching for “;” outside of strings), should be practically sufficient. Once line endings are found, just insert line breaks at those points, then use emacs's builtin functions to indent the line. To implement “unfill”, one can replace newline chars with space (making sure that the newline char is not inside strings or comments). This should make this command sufficiently useful in language modes too.
Note that emacs also has a auto-fill-mode minor mode. With that on, lines will automatically be cut as user types. This feature is nice and is independent of the above suggestion.
Note: the compact-uncompact-block command is currently included in the Ergoemacs: A Ergonomic Keyboard Shortcut Layout For Emacs.
Some Wikipedia references: