Not logged in - Log In / Register

Revision 4 as of 2009-09-25 21:14:26

Clear message

Tips, snippets and smug satisfaction for Launchpad's Emacs and XEmacs users.

Sorting the TAGS tables

make TAGS creates a tags table with the canonical package sorted first.

Find things

Add bzr-tools.el to your load-path and then use bzr-tools-grep to search all of the versioned files. This can help you catch code in txt or zcml files that an rgrep might not find.

Never have lint again!

This snippet, pinched from http://www.plope.com/Members/chrism/flymake-mode/view, runs pyflakes through flymake. That means unused imports and unrecognized names get highlighted, without you having to explicitly run anything.

Tested with GNU Emacs

;; Run pyflakes with flymake.
(when (load "flymake" t)
  (defun flymake-pyflakes-init ()
    (let* ((temp-file (flymake-init-create-temp-buffer-copy
           (local-file (file-relative-name
                        (file-name-directory buffer-file-name))))
      (list "pyflakes" (list local-file))))

  (add-to-list 'flymake-allowed-file-name-masks
               '("\\.py\\'" flymake-pyflakes-init)))

(add-hook 'find-file-hook 'flymake-find-file-hook)

;; Work around bug in flymake that causes Emacs to hang when you open a
;; docstring.
(delete '(" *\\(\\[javac\\]\\)? *\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)\:\\([0-9]+\\)\:[ \t\n]*\\(.+\\)" 2 4 nil 5)

;; And the same for the emacs-snapshot in Hardy ... spot the difference.
(delete '(" *\\(\\[javac\\] *\\)?\\(\\([a-zA-Z]:\\)?[^:(        \n]+\\):\\([0-9]+\\):[  \n]*\\(.+\\)" 2 4 nil 5)

(delete '(" *\\(\\[javac\\] *\\)?\\(\\([a-zA-Z]:\\)?[^:(        \n]+\\):\\([0-9]+\\):[  \n]*\\(.+\\)" 2 4 nil 5)

Sorting import statements

Chuck this in your .emacs, restart (or eval-region it), put the cursor between the ()s of a big nasty import statement and M-x sort-imports should straighten everything out (MichaelHudson).

BarryWarsaw 22-Oct-2007 -- made this portable between XEmacs and FSFmacs and renamed the command sort-imports

BradCrittenden 22-Oct-2007 -- sort-imports does not work with emacs21. Upgrade to emacs22 and it works just fine.

(defun join-words-wrapping (words separator line-prefix line-length)
  (let ((lines ())
        (current-line line-prefix))
    (while words
      (let* ((word (car words))
             (maybe-line (concat current-line word separator)))
        (if (> (length maybe-line) line-length)
            (setq lines (cons (substring current-line 0 -1) lines)
                  current-line (concat line-prefix word separator " "))
          (setq current-line (concat maybe-line " "))))
      (setq words (cdr words)))
    (setq lines (cons (substring
                       current-line 0 (- 0 (length separator) 1)) lines))
    (mapconcat 'identity (nreverse lines) "\n")))

(defun sort-imports ()
    (let ((open-paren (save-excursion (progn (up-list -1) (point))))
          (close-paren (save-excursion (progn (up-list 1) (point))))
      (goto-char (1+ open-paren))
      (skip-chars-forward " \n\t")
      (setq sorted-imports
              (split-string (buffer-substring
                             (save-excursion (goto-char (1- close-paren))
                                             (skip-chars-backward " \n\t")
                            ", *\\(\n *\\)?"))
             ;; XXX Should this sort case insensitively?
      ;; Remove empty strings.
      (delete-region open-paren close-paren)
      (goto-char open-paren)
      (insert "(\n")
      (insert (join-words-wrapping (remove "" sorted-imports) "," "    " 78))
      (insert ")")

Quoting diffs for reviews

Emacs users: here's a little defun that makes the quoting part of the above workflow a little easier. Just mark the region of text you want to quote and do M-x baw-quote-region (or bind to a key of course). (BarryWarsaw)

(defun baw-quote-region (start end)
  (interactive "_r")
  (let ((fill-prefix "> "))
    (indent-region start end nil)))

Note that this snippet only works with XEmacs. Testing in emacs-snapshot on gutsy gave this error: execute-extended-command: Invalid control letter '_' (137) in interactive calling string.

And here's a version that works with GNU Emacs:

(defun equote-region ()
      (replace-regexp "^" "> " nil (region-beginning) (region-end))))

Spotting style issues while you edit

You can set up Emacs to highlight some common style issues - long lines, trailing whitespace, annoying silent TABs and such.

I used whitespace-mode.el from the GNU Emacs tree. The mode customization is difficult, so I just copied my custom variables here. This gives you long line highlighting, trailing whitespace, extra newlines at the end of the file, and bright red evil TABs:


  '(global-whitespace-mode t)
  '(whitespace-style (quote (tabs trailing lines empty tab-mark)))

  '(whitespace-tab ((((class color) (background dark)) (:background "red1" :foreground "yellow"))))

For something lighter, you may want to set the show-trailing-whitespace variable - it will show trailing whitespace as bright red.

Get Emacs to clean up your whitespace

(defun baw-whitespace-normalization ()
  "Like untabify, but also cleans up lines with trailing whitespace."
      (untabify (point-min) (point-max))
      (goto-char (point-min))
      (while (re-search-forward "[ \t]+$" nil t)
        (let ((bol (save-excursion (beginning-of-line) (point)))
              (eol (save-excursion (end-of-line) (point))))
          (goto-char (match-beginning 0))
          (if (and (bolp)
                   (eq (char-after) ?\))
              (forward-char 1))
          (skip-chars-backward " \t" bol)
          (delete-region (point) eol)
      ;; Now clean up any trailing blank lines
      (goto-char (point-max))
      (skip-chars-backward " \t\n")
      (if (not (bolp))
          (forward-char 1))
      (delete-region (point) (point-max))
      ;; But make sure the files ends in a newline
      (if (not (bolp))

Bugify and mail standup notes

Joey has asked that standup notes include the bug number and description. Kiko has contributed a script (lp-bug-ifier.py) to fetch the bug description for all bugs found in STDIN and spit it out on STDOUT.

The following script will copy the current buffer into a compose-mail buffer and bugify it. The launchpad list address is filled in as is most of the subject. It'll need to be customized for other teams than Foundations.

(defun bugify ()
  (kill-ring-save (region-beginning) (region-end))
  (set-mark-command nil)
  (shell-command-on-region (region-beginning) (region-end) "lp-bug-ifier.py" t)
  (insert "launchpad@lists.canonical.com")
  (insert "Foundations standup: 2008-")