はじめに
複数箇所を同時に編集するツールがEmacsに揃ってきた. 本稿ではその中の一つである,ieditについて紹介する.
参考記事
先人の書いた記事は参考になるだろう.
インストール
MELPAに登録されているので,M-x list-packages
からieditを選択し,インストールする.
ソースコード
https://github.com/victorhge/iedit
設定
(require 'iedit)
使用方法
以下,使用方法について述べる.
M-x iedit-mode (基本)
M-x iedit-mode
,もしくはC-;
でカーソル下のシンボルをカレントバッファ全体に渡ってハイライトする.
マッチ箇所を1箇所編集するだけでその編集が全体に反映されるので,
リファクタリングに大変重宝するというわけである.
終了するときは再度M-x iedit-mode
(or C-;
)とすればよい.
ただし,シンボルは部分マッチしないので,
部分マッチさせたいときはリージョンで明示的に囲ってからiedit-mode
を発動する.
たとえば,
foo foo-bar foo-bar-baz
という3行が記述されたバッファにおいて,カーソルが1行目の行末にある状況を考える.
このときiedit-mode
を発動すると1行目のfooのみがハイライトされ,2行目と3行目のfooにはマッチしない.
2行目,3行目にあるfooにもマッチするようにしたいならば,
事前にfooをリージョンで囲ってからiedit-mode
を発動せよ,ということである.
なお上記の挙動はあくまで「デフォルト」である. 後述するカスタマイズ変数の設定により,挙動を多少変更できる.
バリエーション
C-u 0 M-x iedit-mode
orC-u 0 C-;
現在の関数内にマッチ箇所を限定させることが可能.
C-u M-x iedit-mode
orC-u C-;
カレントバッファ内で直前のiedit-modeを実行.要はresume機能である.
C-u C-u M-x iedit-mode
orC-u C-u C-;
バッファグローバルレベルで直前のiedit-mode
を実行.
あるバッファで発動したiedit-mode
のマッチ内容を別のバッファでも発動したいときに用いる.
- activeなリージョンが存在する時の振る舞い
一度iedit-mode
を発動してマッチさせた後,
それらマッチ箇所を含む形である大きさのリージョンを作り(activeなリージョンで囲む),
再度iedit-mode
を発動させるとマッチ箇所がそのリージョン内に限定され,リージョン外のマッチ箇所は解除される.
C-u M-x iedit-mode
とすると逆にリージョン内のマッチを解除し,リージョン外のマッチ箇所はそのまま残る.
リージョンがactivateでなくなればこの振る舞いは終了する.
- isearch中に発動
isearch中にC-;
を押すことでiedit-mode
に移行できる.
キーバインド
以下はiedit-mode
発動中に有効なキーバインドである.
キーバインド | 説明 |
---|---|
C-; | iedit-mode終了 |
C-' | マッチ箇所を含む行のみを抽出して表示 |
C-? | ミニバッファにヘルプを表示 |
TAB | 次のマッチ箇所に移動 |
Shift-TAB | 前のマッチ箇所に移動 |
M-< | カレントバッファ内の最初のマッチ箇所に移動 |
M-> | カレントバッファ内の最後のマッチ箇所に移動 |
M-I (M-Shift-i) | マッチ箇所を現在行に限定 |
M-H (M-Shift-h) | マッチ箇所を関数内に限定 |
M-{ | マッチ範囲を上に1行増やす |
M-} | マッチ範囲を下に1行増やす |
M-G (M-Shift-g) | 直前のiedit-mode を適用(探索範囲はバッファグローバル) |
M-C (M-Shift-c) | 大文字・小文字の区別をトグル |
M-D (M-Shift-d) | マッチ箇所を一斉に削除 |
M-U (M-Shift-u) | マッチ箇所を大文字に |
M-L (M-Shift-l) | マッチ箇所を小文字に |
M-N (M-Shift-n) | マッチ箇所を数字を順番に挿入 |
M-SPC | マッチ箇所を一斉にスペースに置換 |
M-; | カーソル位置にあるマッチ箇所をトグル |
M-B | iedit-buffering発動 |
上記キーバインドはひと通り試してみて,ぜひ使用感を掴んでほしい.
使用例
- TAB, Shift-TAB, M-<, M->
マッチ箇所がウィンドウの表示範囲外になるときに,TABやShift-TABを押していくことでどんどんジャンプしていけるのでチラ見に便利.
- C-'
iedit-mode
発動後,どれくらいハイライトがヒットしたかを視覚的に確認できる.
C-u N(数字)C-'
とすれば周辺N行を含めて抽出可能.デフォルトは周辺1行.
- M-H
とりあえずiedit-mode
を発動してみて,思ったより範囲が広かったらM-H
で範囲を関数内に狭める.
ナローイング(例えばnarrow-to-defun
)を発動する手間が省けて便利.
はじめから関数内に限定したいならC-u 0 C-;
.
- M-B
カーソル下のマッチ箇所のみを対象に編集可能になる(ieditのバッファリング).
編集が完了したら再度M-B
or C-;
で編集を全体に反映させる.
状況によっては便利.
M-x iedit-rectangle-mode(発展)
rectangle領域を対象にしてiedit-mode
を発動する.
するとrectangle領域の全てが編集対象になり,ある行の編集内容がすべての行に反映される.
複数行編集の拡張の一つと捉えるべき.
なおキーバインドはC-x r RET
である.
カスタマイズ
iedit-current-symbol-default
カーソル下にあるシンボルをieditのデフォルト入力にするかどうか.初期値はt
(デフォルト入力にする).
nil
のときはリージョンで明示的に囲ってから発動させる必要がある.
iedit-only-at-symbol-boundaries
シンボルの部分マッチを許容するかどうか.初期値はt
(許容しない).
nil
ならば部分マッチを許容する.
またnil
にするとマッチングが過剰になる傾向になることには注意.
iedit-toggle-key-default
iedit-mode
を発動するキー.デフォルトではC-;
に設定されている.
iedit-occurrence
ハイライト時のフェイス.デフォルトはhighlight
を継承している.
iedit-read-only-occurrence
よく分かっていない.
iedit-case-sensitive-default
iedit-mode
の編集時に大文字と小文字を区別するかどうか.初期値はt
(区別しない).
iedit-unmatched-lines-invisible-default
マッチしない行を自動的に隠すかどうか.初期値はnil
(隠さない).
iedit-transient-mark-sensitive
transient-mark-mode
のON/OFFを気にするかどうか.初期値はt
(ON/OFFを気にする).
すなわち,t
の場合,transient-mark-mode
がOFFならば,
たとえリージョンがactiveであってもieditは何もしない.
iedit-overlay-priority
The priority of the overlay used to indicate matches. 初期値は200. まだよく分かっていない.
yasnippetを用いている人は以下の設定もしておくと,TAB移動時に意図しないスニペットの展開が抑制できて幸せになれる.
(add-hook 'iedit-mode-hook #'(lambda () (yas-minor-mode -1))) (add-hook 'iedit-mode-end-hook #'(lambda () (yas-minor-mode 1)))
欠点
デフォルトでC-;
をキーバインドとして奪ってしまうので,
それらのキーを用いる設定をしている方々は注意が必要である.
また,C-;
やC-'
はterminal emulatorでは「基本的に」用いることができないので,
個人で押しやすいキーに設定したりなどカスタマイズの必要性が発生するだろう.
おわりに
本稿ではieditを紹介した. 同時編集系ではmultiple-cursorsなどもあるが,ieditでも十分実用に供するレベルという感想である.