Improving Your Copy

February 16, 2009 by John Jenkins · 1 Comment
Filed under: Emacs 

Copy - Material, such as a manuscript, that is to be set in type.

The next feature I want for article mode is for it to be able to help you to write good copy. Sounds impossible? Well, copyblogger has an article with some rules you can follow.

To get started, just delete the word very. While you’re at it, get rid of cowardly qualifiers like "it seems" or "just might be" or "could be considered." Wimpiness is for first drafts. If it helps you to visualize Hans and Franz at this point, feel free.

I’d like something that highlights these cowardly qualifiers and perhaps also sentences that are too long (like this one) along with commands to move between the sections of problematic copy.

(defvar am-max-sentence-len 25)

(defvar am-copy-positions nil)
(defvar am-current-pos -1)

(defvar am-copy-qualifiers
  (concat "very\\|"
          "it seems\\|"
          "just might be\\|"
          "could be considered\\|"
          "that\\|"
          "really\\|"
          "just"))

am-copy-positions will store the locations as a vector that we can move forwards and backwards along and am-current-pos will index into that vector.

(defun am-add-copy-issue (start end)
  (let ((marker-start (make-marker))
        (marker-end (make-marker)))
    (set-marker marker-start start)
    (set-marker marker-end end)
    (push (cons marker-start marker-end) am-copy-positions))
  (am-add-overlay start end 'am-copy-face))

When a problem is found there are two jobs to do - store the location and add the overlay. In the interests of DRY there is a single function, am-add-copy-issue that does both. (am-add-copy-issue ...) stores the start and end of the suspect copy as markers1. I don’t really need the end position at the moment but I am considering of adding a command to easily delete the issue too.

(defun am-highlight-long-sentences ()
  (interactive)
  (save-excursion
    (let (start end matches)
      (goto-char (point-min))
      (setq start (point))
      (while (< start (point-max))
        (forward-sentence)
        (setq end (point))
        (when (> (count-matches *am-re-word* start end) am-max-sentence-len)
          (am-add-copy-issue start end))
        (setq start end)))))

(defun am-highlight-qualifiers ()
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward am-copy-qualifiers nil t)
      (am-add-copy-issue (match-beginning 0) (match-end 0)))))

am-change-copy-highlight is a helper function for moving between the sections of bad copy. It checks if the bad copy check is active and if we are at the first / last section before amending the index. am-next-copy-highlight and am-previous-copy-highlight then call this with a -1 or a +1 offset respectively.

(defun am-change-copy-highlight (offset)
  (let (newpos)
    (when (numberp am-current-pos) (setq newpos (+ am-current-pos offset)))
    (cond ((not am-copy-positions)
           (message "Error: copywriting check not active"))
          ((or (< newpos 0)
               (> (1+ newpos) (length am-copy-positions)))
           (message (format (concat "Error: am-current-pos not "
                                    "a valid index (%s %s)")
                            newpos offset)))
          (t (progn
               (setq am-current-pos newpos)
               (goto-char (car (elt am-copy-positions newpos))))))))

(defun am-next-copy-highlight ()
  (interactive)
  (am-change-copy-highlight -1))

(defun am-previous-copy-highlight ()
  (interactive)
  (am-change-copy-highlight 1))

(defun am-reset-copy-highlight ()
  (interactive)
  (setq am-current-pos (length am-copy-positions))
  (am-change-copy-highlight -1))

am-check-copy-start resets the positions and highlights the long sentences and suspect qualifiers. vconcat can be used for converting lists into vectors. am-check-copy-stop resets the variables and deletes the overlays.

(vconcat &rest SEQUENCES)

Concatenate all the arguments and make the result a vector.
The result is a vector whose elements are the elements of all the arguments.

(defun am-check-copy-start ()
  (interactive)
  (setq am-copy-positions nil)
  (am-highlight-long-sentences)
  (am-highlight-qualifiers)
  (setq am-copy-positions (vconcat am-copy-positions)
        am-current-pos (length am-copy-positions))
  (am-reset-copy-highlight))

(defun am-check-copy-stop ()
  (interactive)
  (setq am-copy-positions nil
        am-current-pos nil)
  (am-delete-overlays))

And which keys should I use for each of the features? Perhaps these ones?

(define-key article-mode-keymap (kbd "C-x C-l") 'am-check-copy-start)
(define-key article-mode-keymap (kbd "C-x C-n") 'am-next-copy-highlight)
(define-key article-mode-keymap (kbd "C-x C-p") 'am-previous-copy-highlight)
(define-key article-mode-keymap (kbd "C-x C-r") 'am-reset-copy-highlight)))

1. Markers are updated so that they keep pointing to the same thing when the text before them changes. They are necessary in this case as I imagine that the bad copy will often need to be changed.

Comments

One Response to “Improving Your Copy”
  1. JamesD says:

    Thanks for the useful info. It’s so interesting

Speak Your Mind

Tell us what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!