Last Modified:

use Module行をキレイにソートするEmacsPerl

Perlコード中のuse Module;をASCII順にソートする場合、Emacsのsort-linesを使うと

use Digest::MD5;
use Digest;

みたいになってちょっと気持ち悪い。:が0x3aで;が0x3bだから当たり前なんだけど、やっぱり階層順

use Digest;
use Digest::MD5;

になって欲しい。

それからプラグマ(e.g. strict)とかプラグマっぽい小文字なモジュール(e.g. Digest::base)が先に来るように、つまり

use Digest::MD5;
use Digest::base;
use autodie;

ではなく

use autodie;
use Digest::base;
use Digest::MD5;

になって欲しい。

というわけで、そうなるようなソート関数を書いた。

(defun cperl-sort-lines-helper (region)
  (let ((words (split-string (buffer-substring-no-properties (car region) (cdr region)) "[ ;]+" t))
        (diff (- ?a ?A)))
    (concat (mapcar #'(lambda (c)
                        (cond
                         ((and (<= ?A c) (<= c ?Z)) (+ c diff))
                         ((and (<= ?a c) (<= c ?z)) (- c diff))
                         (t c)))
                    (vconcat (nth 0 words) (nth 1 words))))))

(defun cperl-sort-lines (reverse beg end)
  "モジュールの並べ替えのためにモジュール名以降を無視してソートする。"
  (interactive "P\nr")
  (save-excursion
    (save-restriction
      (narrow-to-region beg end)
      (goto-char (point-min))
      (let ;; To make `end-of-line' and etc. to ignore fields.
          ((inhibit-field-text-motion t))
        (sort-subr reverse 'forward-line 'end-of-line nil nil
                   #'(lambda (a b) (string< (cperl-sort-lines-helper a) (cperl-sort-lines-helper b))))))))