Emacs Lisp: by Example
"Aaron S. Hawley" <[email protected]>
| Newsgroups | gmane.org.ballistichelmet.lambda |
|---|---|
| Organization | University of Vermont |
| Message-ID | <[email protected]> |
;;;; Emacs Lisp: by Example
;;; Text Processing and Interaction Facilities
;; February 13 2004
;; Aaron Hawley
;;
;; Emacs Lisp has much of the regular expression power of Perl with
;; the invaluable addition of interactive capabilities. Below are
;; some examples. The ability to modify text files is but a taste of
;; the functionality of Emacs and her lisp extension language. The
;; following functions present some common uses (regular expressions,
;; interaction, highlighting, user prompts) and mistakes (watch for
;; case sensitivity) of writing Emacs Lisp. The last function proves
;; the point that a search-and-replace (no matter how strong a regular
;; expression) cannot always successfully complete a task that demands
;; human intervention. These functions were developed in GNU Emacs 21.
(defun mytext-next-all-caps-heading ()
"Finds a text heading because it is in all caps."
(interactive)
(message "Finding text headings ...")
(push-mark) ;; start from current cursor position
(let ((case-fold-search nil)) ;; set to case-sensitive.
(if (re-search-forward
"^[^a-z\n]+$"
nil ;; not bound
t) ;; quell errors
(message "Found text heading.")
(message "End of buffer"))))
(defun mytext-unjustify-buffer ()
"Finds a text heading because it is in all caps."
(interactive)
(message "Finding text headings ...")
(push-mark) ;; start from current cursor position
(let ((case-fold-search nil)) ;; set to case-sensitive.
;; remove any spaces between single consecutive "word
;; constituents" (which really just means a single letter).
(perform-replace
" \\(\\w\\) +\\(\\w\\)\\b"
"\\1\\2"
nil ;; don't query
t ;; is regexp
nil)) ;; don't enforce word delimiting
(message "Line unjustified"))
(defun mytext-indented-lines-to-paragraphs ()
"Converts single space lines with indentation at beginning of
paragraphs to paragraphs with a blank line between each paragraph."
(interactive)
(message "Converting indented lines to paragraphs ...")
(push-mark) ;; start from current cursor position
;; any line starting with blank characters should be changed
;; to a double line.
(perform-replace
"\n[[:blank:]]+\\b"
"\n\n"
nil ;; don't query
t ;; is regexp
nil) ;; don't enforce word delimiting
(message "Indentation converted to paragraphs"))
(defun mytext-previous-word ()
"Return the word previous to location ``point'' is on--return as a
string."
(save-excursion (backward-word 1) (current-word)))
;; When using optical character recognition (OCR) scanning technology
;; or simply copying and pasting from print-oriented electronic
;; documents, hyphenation will be present at the end of lines. To
;; correct this situation with a regular expression is a simple task.
;; Not all hyphens should be removed, however. Because of the dual
;; meaning of a hyphen, it could very well be necessary for the word's
;; spelling. So at each hyphenated line, the user is prompted ("yes"
;; or "no") whether to keep or remove the hyphen.
(defun mytext-remove-hyphenated-lines ()
"Dehyphenates all lines in the buffer, and will wrap the word to the
next line.
Upon the arriving at a hyphenated line, the user will be queried as to
whether the word should maintain the hyphen or be concatenated without
the hyphen."
(interactive)
(setq hyphenated-lines 0) ;; counter
(message "Removing end of line hyphens ...")
(push-mark) ;; start from current cursor position.
;; search repeatedly for a hyphen at the end of a line.
(while (re-search-forward "-[[:blank:]]*\n\\b"
(point-max) ;; go to end of buffer.
t) ;; quell errors.
;; increment counter.
(setq hyphenated-lines (1+ hyphenated-lines))
;; save-excursion is handy: it allows you to move the cursor
;; around, retrieve and return a value but return the cursor back
;; to where it started.
(let* ((hyphenated-word-start (save-excursion
(backward-word 1)
(point)))
(hyphenated-word-end (save-excursion
;; go to end of word.
(forward-word 1)
(point)))
(hyphenated-word (concat
(mytext-previous-word)
(current-word)))
;; Create an overlay over the span of the hyphenated word.
(highlight-overlay (make-overlay hyphenated-word-start
hyphenated-word-end)))
;; Set font face of the overlay of the high to highlight
;; (usually a inverse-video appearance).
(overlay-put highlight-overlay 'face 'highlight)
;; Ask the user if the hyphen is truly part of the word or not.
;; FIXME: This could be accomplished much of the time by using
;; Emacs's spell-checking facilities.
(if (y-or-n-p (concat "Remove hyphenation in \""
hyphenated-word
"\" ?"))
;; If yes, remove hyphen from word.
(replace-match "")
;; Else keep the hyphen in the word.
(replace-match "-"))
(delete-overlay highlight-overlay) ;; Remove highlighting.
(backward-word 1) ;; Go to the beginning of the word.
(open-line 1) ;; Make end-line, putting (wrapping) word to next
;; line.
(delete-trailing-whitespace)
(undo-boundary) ;; have the each iterative modification be a
;; single undo, rather than a single undo of
;; all the work done by this function.
(forward-line))) ;; Done with this line, continue on next.
;; END: report how many lines were fixed.
(message (concat "Fixed "
(number-to-string hyphenated-lines)
" hyphenated lines")))