http://rubikitch.com/に移転しました このページをアンテナに追加 RSSフィード

2011-02-21

[]続・Emacsで連番を挿入する方法

久々のEmacsネタ

歴史は繰り返すものです。 今はブラウザでなんでもできてしまう時代、かつてのEmacsを彷彿とさせます。 だが、ブラウザEmacsに決定的に劣っているのは、『速さが足りない』ことだと思ってます。

フレーム、フラッシュなどマウス前提のIFなので、素早い動作が難しいです。 対して、Emacsテキスト入力のスペシャリストテキスト入力が関わる場面があれば、そこに必ずEmacs活躍があります。 dabbrevyasnippetなど、入力に不可欠なツールが無数に存在するからです。

さてさて…

2年前に書いた記事 では、外部コマンドloopを使ってEmacsで連番を入力する方法を紹介しました。 しかし、めんどいですね。 なので、Emacs Lispで書きました。

M-x duplicate-this-line-forward 直前の行をコピーする

直前の行と同じ行を作成することはよくあります。 C-a C-k C-k C-y C-y ...と操作すると思いますが、キルリングが置き換わってしまう問題があります。 そこで、このコード

(defun duplicate-this-line-forward (n)
  "Duplicates the line point is on.  The point is next line.
 With prefix arg, duplicate current line this many times."
  (interactive "p")
  (when (eq (point-at-eol)(point-max))
    (save-excursion (end-of-line) (insert "\n")))
  (save-excursion
    (beginning-of-line)
    (dotimes (i n)
      (insert-buffer-substring (current-buffer) (point-at-bol)(1+ (point-at-eol))))))

僕は F5 に割り当てています。 連打することでたくさんコピーできます。 数引数を指定すると、その回数だけコピーします。

M-x seq 数字のみが違う同じ行を作成する

「第1回」から「第10回」までの行を作成したいとします。 そのとき、「第1回」という行をM-x duplicate-this-line-forwardでコピーして数字だけを書き換えるのは面倒です。 そこで、このコード

(defun count-string-matches (regexp string)
  (with-temp-buffer
    (insert string)
    (count-matches regexp (point-min) (point-max))))
(defun seq (format-string from to)
  "Insert sequences with FORMAT-STRING.
FORMAT-STRING is like `format', but it can have multiple %-sequences."
  (interactive
   (list (read-string "Input sequence Format: ")
         (read-number "From: " 1)
         (read-number "To: ")))
  (save-excursion
    (loop for i from from to to do
          (insert (apply 'format format-string
                         (make-list (count-string-matches "%[^%]" format-string) i))
                  "\n")))
  (end-of-line))

M-x seqでは、数字部分をformat関数の書式指定にしておくことでそこが数字に置き換わります。 このコマンドは、書式指定→開始番号→終了番号の順で聞いてきます。 この例では、「M-x seq RET 第%d回 RET RET 10 RET」と操作します。

%dは複数個持つことができます。 「M-x seq RET [%02d]第%d回 RET RET 3 RET」で以下の行が挿入されます。

[01]第1回
[02]第2回
[03]第3回

M-x number-rectangle 連番の長方形を作成する

最後に、連番の長方形を作成するコマンド作りました

(eval-when-compile (require 'cl))
(defun number-rectangle (start end format-string from)
  "Delete (don't save) text in the region-rectangle, then number it."
  (interactive
   (list (region-beginning) (region-end)
         (read-string "Number rectangle: " (if (looking-back "^ *") "%d. " "%d"))
         (read-number "From: " 1)))
  (save-excursion
    (goto-char start)
    (setq start (point-marker))
    (goto-char end)
    (setq end (point-marker))
    (delete-rectangle start end)
    (goto-char start)
    (loop with column = (current-column)
          while (<= (point) end)
          for i from from   do
          (insert (format format-string i))
          (forward-line 1)
          (move-to-column column)))
  (goto-char start))

(global-set-key "\C-xrN" 'number-rectangle)

C-x r t (string-rectangle)は、同じ文字列を複数行に書く(行頭の「*」や引用符「> 」など)のに便利です。 その連番バージョンです。

使い方は連番を入れたい行の行頭をリージョンとして指定し、C-x r Nと操作します。 すると、連番の書式、開始番号を聞いてきます。 書式は「%d. 」ならば「1. 」、「2. 」〜という感じです。

あるいは、「第1回」の行をM-x duplicate-this-line-forwardでコピーして、数字部分を長方形リージョンに指定する使い方もあります。 そのときは書式は「%d」と指定します。

なお、このコマンドと同じような働きをするコマンドM-x rectangle-number-linesが開発版Emacs存在し、C-x r Nに割り当ててあります。

両者の違いは、M-x number-rectangleの方が賢くて使いやすいことです。

  • カーソル位置によってデフォルトの書式が異なる
    • 行頭(インデントがあってもよい)のときは「%d. 」
    • 行頭以外では「%d」
  • M-x number-rectangleはC-uをつけないと細かな指定ができない

ただのリサーチ不足ではありますが、この程度のコマンドはすぐ書けるので。 結果的には好みのコマンドが出来上がりました。

まとめ

今回はM-x seq、M-x number-rectangleの2種類の連番コマンド定義しました。 それに付随してM-x duplicate-this-line-forwardも定義しました。

では、よりよいEmacsライフを! お役に立てれば幸いだ。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/rubikitch/20110221/seq
Connection: close