2013年12月17日火曜日

[Emacs]リージョンを任意の文字列で囲むコマンドを作成した

Emacsで文章を作成していると、

hogehoge
fugafuga

--------------------
hogehoge
fugafuga
--------------------

と----で囲ったり、
Redmineのコメントで、

hogehoge
fugafuga

<pre>
hogehoge
fugafuga
</pre>

と書くことが結構多い。
指定したリージョンの前後に、任意の文字列を挿入できるコマンドがあると便利そうなので作ってみた。

使い方

リージョンを選択して、
M-x enclose-string
ミニバッファで
String(s/t/num):
と聞いてくるので、以下のいずれかを入力する。

(1)任意の文字列で囲む場合
最初の文字にsを指定する。
例: shoge
hogeで囲む。

(2)タグで囲む場合
最初の文字にtを指定する。
例: tpre
<pre>と</pre>で囲む。

(3)指定した回数を繰り返す文字列で囲む場合
例: 30-
------------------------------(「-」30個)で囲む。

ソース

(defun multi-string (n str)
  (loop repeat n concat str))

(defun pre-post-text-string (str)
 (list str str))

(defun pre-post-tag-string (str)
 (list (concat "<" str ">") (concat "</" str ">")))

(defun pre-post-multi-string (n str)
 (let ((n-str (multi-string (string-to-int n) str)))
    (list n-str n-str)))

(defun pre-post-string (str)
 "書式文字列に応じた前後の文字列を取得する。\n
前の文字列と後ろの文字列のリストを返す。\n
最初の文字が s の場合、それ以降の文字列を前後の文字列とする。\n
例: s--- → (\"---\" \"---\")\n
最初の文字が t の場合、それ以降の文字列をタグ名として扱う。\n
例: tpre → (\"<pre>\" \"</pre>\")\n
最初の文字列が数値の場合、数値の後ろの文字列を数値分繰替えした文字列を、前後の文字列とする。
例: 10* → (\"**********\" \"**********\")\n"
 (cond
  ((string-match "^s\\(.*\\)" str)
    (pre-post-text-string (match-string 1 str)))
  ((string-match "^t\\(.*\\)" str)
    (pre-post-tag-string (match-string 1 str)))
  ((string-match "^\\([0-9]+\\)\\(.*\\)" str)
    (pre-post-multi-string (match-string 1 str) (match-string 2 str)))))

(defun enclose-region (start end str)
  "リージョンの前後に文字列を挿入する。"
  (interactive "r\nsString(s/t/num):")
  (destructuring-bind (pre-str post-str) (pre-post-string str)
    (message (concat pre-str ":" post-str))
    (save-excursion
      (save-restriction
    (narrow-to-region start end)
    (goto-char (point-min))
    (insert pre-str "\n")
    (goto-char (point-max))
    (unless (bolp)
      (insert "\n"))
    (insert-before-markers post-str "\n")))))


Emacsは、手軽に機能を拡張できるので、便利だ。