Underling plain text in Emacs
EDIT 2015-06-15: Boruch Baum improved upon my original code. The revised version included below has several additional desirable properties:
- Aligns underlines properly under characters when line starts with whitespace.
- Does not underline trailing whitespace.
- Works if you already typed
after typing line you want underlined. - Optionally does not underline any whitespace (with C-u C-u prefix).
- Does not allow underlining with control characters or whitespace.
- When underlining commented lines, inserts leading comment char.
Often when I’m writing emails, text documents, or code I like to create section headings (not unlike markdown headings) to provide visual segmentation to document structure. To quickly facilitate “underlining” text this way, I wrote the following convenience function in Emacs Lisp:
defun underline-text (arg)
("Inserts a line under the current line, filled with a default
underline character `='. If point had been at the end of the
line, moves point to the beginning of the line directly following
the underlining. It does not underline the line's leading
whitespace, trailing whitespace, or comment symbols. With prefix `C-u'
prompts user for a custom underline character. With prefix `C-u
C-u', does not underline whitespace embedded in the line."
; Copyright 2015 Boruch Baum <boruch_baum@gmx.com>, GPL3+ license
"p")
(interactive let* ((original-point (point))
(
(underline-char"[[:cntrl:][:space:]]" "="
(replace-regexp-in-string if (= arg 1)
("="
(char-to-stringread-char "What character to underline with?")))))
(
(original-point-is-eolwhen (looking-at "$") t))
(
(original-point-is-eob= original-point (point-max))))
(
(beginning-of-line)unless
(when (looking-at "[[:space:]]*$")
(0)
(beginning-of-line when (looking-at "[[:space:]]*$")
(
(goto-char original-point)"nothing to do")))
(message
(insert
(buffer-substring (line-beginning-position) (line-end-position))"\n")
(save-restriction
(narrow-to-regionprogn
(1- (re-search-forward "[^[:space:]]" nil t)))
(goto-char (cond
(";+") (match-end 0))
((looking-at "#+") (match-end 0))
((looking-at "//+") (match-end 0))
((looking-at "/\\*+") (match-end 0))
((looking-at t (point))))
(1+ (progn
(
(goto-char (line-end-position))"[^[:space:]]" nil t))))
(re-search-backward
(untabify (point-min) (point-max))
(goto-char (point-min))if (= arg 16)
("[^[:space:]]" nil t)
(while (re-search-forward nil))
(replace-match underline-char "[^[:space:]]" nil t)
(re-search-forward 1- (point)))
(goto-char ("." nil t)
(while (re-search-forward nil)))
(replace-match underline-char
(widen))if original-point-is-eob
(
(goto-char (point-max))if original-point-is-eol
("^"))
(goto-char (re-search-forward
(goto-char original-point)))))) }
Once the above code is evaluated, entering C-c u will turn
My section heading
into
My section heading
==================
By preceding with the universal argument, you will be prompted for the underlining character. So entering C-u C-c u + will produce
My section heading
++++++++++++++++++
A double prefix followed by a underlining character will skip whitespace. For example, C-u C-u C-c u = produces
My section heading
== ======= =======
If the line to be underlined is a code comment, the necessary comment character is prepended to the underline
# My code comment
# ===============
The above also works for right-aligned text.