Roads? Where we're going we don't need roads.
Back to the Future
Evilの真髄はその拡張性です. 本稿では主にチュートリアルを通して, Evilを拡張する方法を解説します.
Evilの拡張
Evilはもともと拡張性を考慮して設計されています. 最小限のコア部分がEvilの本体だとすると, ステート, コマンド, オペレータ, モーション, テキストオブジェクトなどEvilの具体的な機能はすべて拡張機能として実装されているとも言えます.
これら拡張機能を定義するための機構はあらかじめコアに備わっていて, evil-define-functionality
といった名前のマクロが用意されています. たとえば, evil-define-state
, evil-define-command
, evil-define-operator
, evil-define-motion
, evil-define-text-object
といった具合です.
あとは, 必要に応じたEmacs Lispの知識と, Evilの内部的な動作のための補助関数についての知識さえあれば, 簡単にEvilのプラグインを作成できます. このようにして作られた拡張機能の例としてもっとも優れているのは, Evilそのものの機能のソースコードです. 最初のうちは, evil-commands.elなどを参考にするのがよいでしょう.
このあとの節では, Evilの拡張機能を定義する方法をチュートリアル形式で解説していきます.
例1: コメントアウトオペレータ
オペレータを自作する例として, コメントアウト/アンコメントするためのオレータを定義してみましょう. オペレータは範囲選択なしに用いられた場合は, 直後にモーションを伴って, 最初のカーソル位置からモーション終了後の位置までの範囲に, 何らかの操作を施すものです. 選択範囲が与えられた場合は, 文字・行・矩形の選択種別に応じて操作を施します.
Evilでは, (evil-define-operator name (beg end ...) ...)
の形でオペレータを定義できます. beg
, end
には選択範囲の開始位置と終了位置が渡されます. 後続のモーションの扱いはとくに明示的にやる必要はなく, モーション終了後に決定された選択範囲が渡されます.
単純な選択範囲のコメントアウト
Emacsでは, comment-or-uncomment-region
という関数で, 特定の範囲をコメントアウト/アンコメントできます. 選択種別について気にしなければ, これをevil-define-operator
の中で呼び出すだけで, オペレータの定義が完成します.
(evil-define-operator evil-comment-or-uncomment-region (beg end) "Comment out text from BEG to END." (interactive "<r>") (comment-or-uncomment-region beg end))
名前はevil-comment-or-uncomment-region
としました. interactive
に渡している<r>
は, このオペレータの引数として選択範囲を受け取ることを表していて, 範囲が選択されていないときにはinteractive
の行を解釈する途中でモーションの入力を自動的に待ちます.
矩形選択範囲のコメントアウト
上の定義でも, 文字選択(v
)や行選択(V
)の場合はうまくいきますが, 矩形選択(C-v
)された範囲をうまくコメントアウトすることができません. 矩形選択の場合は, 選択範囲に含まれる部分を行ごとに分割して操作を適用する必要があります. たとえば, 以下の文章の|
の間が選択範囲だとします.
Assume that the range between | in this text is seleced. If the selection is blockwise, then each line of the selected text is restricted to the columns between |.
矩形選択では色つきで示した部分が選択範囲ですが, 実際にはbeg
とend
には|
の位置が渡ってくるだけなので, 矩形選択の場合は行ごとに列の範囲を限定しながら操作を適用する必要があります. 矩形選択範囲を行ごとの範囲に変換して操作を適用できるように, evil-apply-on-block
という内部関数が用意されています.
選択種別を受け取れるようにinteractive
に<R>
を渡すようにして, 矩形選択のときにはevil-apply-on-block
を使うようにすると以下のようになります.
(evil-define-operator evil-comment-or-uncomment-region (beg end type) "Comment out text from BEG to END with TYPE." (interactive "<R>") (if (eq type 'block) (evil-apply-on-block #'comment-or-uncomment-region beg end nil) (comment-or-uncomment-region beg end)))
実はこのままではうまくいきません. comment-or-uncomment-region
は, コメント開始記号を挿入/削除するので, 行ごとの操作を適用する途中で, 列の範囲がずれてしまうのです. Emacsには, 文字列の挿入/削除が起きても位置を正しく保存するために, マーカという仕組みがあります. まずは行ごとに限定すべき範囲に対してマーカを設定して, そのマーカで示された範囲にコメントアウト操作を適用するようにしましょう.
(defun evil-mark-on-lines (beg end lines) (let ((beg-marker (save-excursion (goto-char beg) (point-marker))) (end-marker (save-excursion (goto-char end) (point-marker)))) (set-marker-insertion-type end-marker t) (setcdr lines (cons (cons beg-marker end-marker) (cdr lines))))) (defun evil-apply-on-block-markers (func beg end &rest args) "Like `evil-apply-on-block' but first mark all lines and then call the function on the marked ranges." (let ((lines (list nil))) (evil-apply-on-block #'evil-mark-on-lines beg end nil lines) (dolist (range (nreverse (cdr lines))) (let ((beg (car range)) (end (cdr range))) (apply func beg end args) (set-marker beg nil) (set-marker end nil))))) (evil-define-operator evil-comment-or-uncomment-region (beg end type) "Comment out text from BEG to END with TYPE." (interactive "<R>") (if (eq type 'block) (evil-apply-on-block-markers #'comment-or-uncomment-region beg end) (comment-or-uncomment-region beg end)))
キーマップ
プラグインが定義するキーは, 適宜オン/オフできるとよいでしょう. そのためには, プラグイン専用のマイナーモードを定義し, そのマイナーモードが有効な場合だけキーを割り当てるのがよいでしょう.
マイナーモードは以下のように定義します. これにより, マイナーモード用のキーマップevil-operator-comment-mode-map
が自動的に作られます.
(defgroup evil-operator-comment nil "Comment/uncomment operator for Evil" :prefix "evil-operator-comment-" :group 'evil) (define-minor-mode evil-operator-comment-mode "Buffer local minor mode of comment/uncomment operator for Evil." :lighter "" :keymap (make-sparse-keymap) :group 'evil-operator-comment (evil-normalize-keymaps))
evil-define-key
を使うと, このマイナーモードが有効で, かつ特定のステートのときだけ使えるキーを定義できます. ここでは, ノーマルステートとビジュアルステートのC
キーに割り当てることにします.
(evil-define-key 'normal evil-operator-comment-mode-map "C" 'evil-comment-or-uncomment-region) (evil-define-key 'visual evil-operator-comment-mode-map "C" 'evil-comment-or-uncomment-region)
このマイナーモードを常に有効にしておきたい場合のために, グローバルマイナーモードも定義しておくとよいでしょう.
(defun evil-operator-comment-mode-install () (evil-operator-comment-mode 1)) (define-globalized-minor-mode global-evil-operator-comment-mode evil-operator-comment-mode evil-operator-comment-mode-install "Global minor mode of comment/uncomment operator for Evil.")
これで, 使う側では
(global-evil-operator-comment-mode 1)
とするだけで済むようになります.
例2: 次のシンボルへ移動するモーション
モーションを自作する例として, 次のシンボルへ移動するモーションを定義してみましょう.
モーションの定義
Emacsにはもともとforward-symbol
(thingatpointパッケージ)というコマンドがあり, Evilを使っていてもこのコマンドはふつうに動作します. しかし, w
(evil-forward-word-begin
)で単語移動するときなどは単語の先頭で止まりますが, forward-symbol
はシンボルの終端(シンボルの最後の文字の次の位置)で止まってしまいます. これはちょうど, Emacsの単語移動コマンドforward-word
が単語の終端で止まるのと同じで, EmacsとVimの移動コマンドの流儀の違いに由来します.
この流儀の違いを吸収するために, Evilにはevil-move-beginning
という内部関数が用意されています. この関数には, 移動する回数と, Emacs流の移動関数を渡します. ただし, 移動関数は指定された回数の移動ができなかった場合(途中でバッファの先頭や末尾に到達してしまった場合)は, 残りの移動回数を返す必要があります. 残り移動回数を返すようにしたシンボル移動のコマンドを仮にevil-forward-symbol
とすると, w
のようにVimの流儀でシンボル移動するコマンドevil-forward-symbol-begin
は以下のように定義できます.
(evil-define-motion evil-forward-symbol-begin (count) "Move the cursor to the beginning of the COUNT-th next symbol." :type exclusive (evil-move-beginning count #'evil-forward-symbol))
モーションの定義にはevil-define-motion
マクロを使います. :type
には, オペレータを施したときに, 移動後のカーソル位置をオペレータの適用範囲に含めるかどうかを指定します. evil-forward-symbol
は次のシンボルの先頭に移動するコマンドなので, 移動後のカーソル位置をオペレータの適用範囲には含めません(exclusive
を指定します).
次にevil-forward-symbol
を定義しましょう. evil-forward-word
の定義を参考に, foward-symbol
がバッファの端点に到達してしまったときだけnil
を返すと仮定して, 以下のように定義してみました.
(defun evil-forward-symbol (&optional count) (setq count (or count 1)) (let* ((dir (if (>= count 0) +1 -1)) (count (abs count))) (while (and (> count 0) (forward-symbol dir)) (setq count (1- count))) count))
実はこれはうまくいきません. なぜなら, forward-symbol
はforward-word
と違って, 端点に到達してもnil
を返さない場合があるからです. そこで, forward-symbol
の定義を少し修正したevil-forward-smbol1
を定義して, そちらを使うようにしましょう.
(defun evil-forward-symbol1 (dir) (if (natnump dir) (re-search-forward "\\(\\sw\\|\\s_\\)+" nil 'move count) (prog1 (re-search-backward "\\(\\sw\\|\\s_\\)+" nil 'move) (skip-syntax-backward "w_")))) (defun evil-forward-symbol (&optional count) (setq count (or count 1)) (let* ((dir (if (>= count 0) +1 -1)) (count (abs count))) (while (and (> count 0) (evil-forward-symbol1 dir)) (setq count (1- count))) count))
これでおおよそうまくいきますが, このままではw
と違って, 空行を飛ばしてしまいます. Evilにはevil-move-empty-lines
という, 次の空行まで移動するコマンドがあるので, このコマンドと, いま定義したevil-forward-symbol
と, 移動距離の短い方を使えばうまくいきます. Evilには「移動距離の短い方を使う」ためのマクロevil-define-union-move
も用意されているので, これを使いましょう.
(evil-define-union-move evil-move-symbol (count) "Move by symbols." (evil-forward-symbol count) (evil-move-empty-lines count))
いま定義したevil-move-symbol
を, evil-forward-symbol
の代わりにevil-move-beginning
に渡すように, evil-forward-symbol-begin
を修正します.
(evil-define-motion evil-forward-symbol-begin (count) "Move the cursor to the beginning of the COUNT-th next symbol." :type exclusive (evil-move-beginning count #'evil-move-symbol))
同じようにして, 前のシンボルに移動するコマンドも定義できます.
(evil-define-motion evil-backward-symbol-begin (count) "Move the cursor to the beginning of the COUNT-th previous symbol." :type exclusive (evil-move-beginning (- (or count 1)) #'evil-move-symbol))
内部で用いるコマンドはcount
が負数でもいいように定義してあったので, evil-move-beginning
に渡すcount
の符号を反転させるだけで, 何も新しいものは要りません.
さらに, evil-move-beginning
の代わりにevil-move-end
を使うと, 単語移動におけるe
(evil-forward-word-end
)のように, シンボルの末尾で止まるコマンドも定義できます.
(evil-define-motion evil-forward-symbol-end (count) "Move the cursor to the end of the COUNT-th next symbol." :type inclusive (evil-move-end count #'evil-move-symbol nil t)) (evil-define-motion evil-backward-symbol-end (count) "Move the cursor to the end of the COUNT-th previous symbol." :type inclusive (evil-move-end (- (or count 1)) #'evil-move-symbol nil t))
シンボルの末尾はオペレータの適用範囲に含めて欲しいので, evil-define-motion
に渡す:type
はinclusive
です. また, evil-move-end
の呼出しでは, inclusive
な場合には第4引数で指定する必要があります.
以上で, シンボル単位の移動コマンドが定義できました. 実際には, たとえば行末のシンボルにカーソルがあるときに, 次の行の空白をオペレータの適用範囲に含めないようにしたりといった細かな調整をすべきかもしれませんが, おおまかなところとしてはこれで完成です.
テキストオブジェクト
evil-move-symbol
のように, 一定の条件を満たすように作られた関数は, Evilの内部関数evil-an-object-range
とevil-inner-object-range
を使って, そのままテキストオブジェクトに変換できます.
(evil-define-text-object evil-a-symbol (count &optional beg end type) "Select a symbol." (evil-an-object-range count beg end type #'evil-move-symbol)) (evil-define-text-object evil-inner-symbol (count &optional beg end type) "Select inner symbol." (evil-inner-object-range count beg end type #'evil-move-symbol))
ただし, evil-an-object-range
とevil-inner-object-range
を使ってテキストオブジェクトを作る場合は, 渡す関数が次の条件を満たす必要があります.
- 引数として
count
のみをとる count
が正のときは, オブジェクトの末尾がcount
個過ぎた後の, 最初のオブジェクトの先頭に移動する(ただし, 最初からカーソルがオブジェクトの末尾にあるときは, そのオブジェクトも数える)count
が負のときは,count
個前のオブジェクトの先頭に移動する(ただし, 最初からカーソルがオブジェクトの先頭にあるときはそのオブジェクトは数えない)- 返り値は,
count
で指定された回数と実際に移動できた回数の差(つまり成功時は0になる)
evil-move-symbol
はこの条件を満たすように作っていたわけです.
キーマップ
定義されたコマンドを簡単なキーで使えるようにする場合, たとえば,w
等に割り当てるなら次のようにします.
(define-key evil-motion-state-map (kbd ",") (make-sparse-keymap)) (define-key evil-motion-state-map (kbd ",w") #'evil-forward-symbol-begin) (define-key evil-motion-state-map (kbd ",b") #'evil-backward-symbol-begin) (define-key evil-motion-state-map (kbd ",e") #'evil-forward-symbol-end) (define-key evil-motion-state-map (kbd ",ge") #'evil-backward-symbol-end) (define-key evil-outer-text-objects-map (kbd ",w") #'evil-a-symbol) (define-key evil-inner-text-objects-map (kbd ",w") #'evil-inner-symbol)
例3: 同じ文字の間を表すオブジェクト
evil-an-object-range
やevil-inner-object-range
は用いずに, いちからテキストオブジェクトを自作する例として, 同じ文字の間を表すオブジェクトを定義してみましょう. vifc
で文字c
に囲まれた範囲を選択できるようにするのが目標です. vafc
のときはc
そのものも選択されるように, vifc
した後にもう一度ifc
した場合は選択範囲を拡大することにしましょう.
テキストオブジェクトを定義するにはevil-define-text-object
を使います. 定義されるテキストオブジェクトは引数count
と, オプショナル引数beg
, end
, type
を取ります. オプショナル引数は, 既に選択範囲がある場合に渡されます. 実際の処理はevil-between-range
という関数に任せることにしましょう.
(evil-define-text-object evil-a-between (count &optional beg end type) "Select range between a character by which the command is followed." (evil-between-range count beg end type t)) (evil-define-text-object evil-inner-between (count &optional beg end type) "Select inner range between a character by which the command is followed." (evil-between-range count beg end type))
evil-between-range
の第5引数で, 入力された文字c
そのものも選択範囲に含めるかどうかを指定することにしました.
単純な実装
evil-between-range
がやるべきことは, count
個前と後の文字c
を見つけて, 見つけた位置を表す範囲オブジェクトを返すことです. 文字の入力を受け取るにはevil-read-key
, 回数指定で文字を探すにはevil-find-char
, 範囲オブジェクトをつくるにはevil-range
を使います.
(defun evil-between-range (count beg end type &optional inclusive) (ignore-errors (let ((count (abs (or count 1))) (ch (evil-read-key)) beg-inc end-inc) (save-excursion (evil-find-char (- count) ch) (setq beg-inc (point))) (save-excursion (backward-char) (evil-find-char count ch) (setq end-inc (1+ (point)))) (if inclusive (evil-range beg-inc end-inc) (evil-range (1+ beg-inc) (1- end-inc))))))
文字が見つからなかった場合はエラーになるので, 全体をignore-errors
で囲っておきます. 文字を探す間のカーソル移動が後に影響しないようにsave-excursion
で囲うようにもします. 負の回数には意味がないので絶対値を取ります. 後方に文字を探すときは, カーソルがその文字の上にあるときを考慮して1文字戻ってから探します. 第5引数がt
のときは, 見つかった文字の位置も含めた範囲を, それ以外のときは1文字ずつ縮小した範囲を返します.
選択範囲の拡大
この定義のままだと, 常にカーソル位置から始めて文字を探しますが, beg
とend
が指定されたとき(既に範囲が選択されているとき)は, 既存の選択範囲の開始位置から前に, 終了位置から後ろに探して, 結果的に選択範囲が拡大されるようにしなければなりません. また, 選択範囲がちょうど指定の文字の間の範囲を表している場合は, すぐ外側の文字が見つかって, 選択範囲が拡大されなくなってしまうので, 特別な取り扱いが必要です. このような点を考慮して修正したのが以下のコードです.
(defun evil-between-range (count beg end type &optional inclusive) (ignore-errors (let ((count (abs (or count 1))) (beg (and beg end (min beg end))) (end (and beg end (max beg end))) (ch (evil-read-key)) beg-inc end-inc) (save-excursion (when beg (goto-char beg)) (evil-find-char (- count) ch) (setq beg-inc (point))) (save-excursion (when end (goto-char end)) (backward-char) (evil-find-char count ch) (setq end-inc (1+ (point)))) (if inclusive (evil-range beg-inc end-inc) (if (and beg end (= (1+ beg-inc) beg) (= (1- end-inc) end)) (evil-range beg-inc end-inc) (evil-range (1+ beg-inc) (1- end-inc)))))))
キーマップ
できあがったテキストオブジェクトを使うためのキーを割り当てるには, evil-outer-text-objects-map
とevil-inner-text-objects-map
を使います.
(define-key evil-outer-text-objects-map "f" 'evil-a-between) (define-key evil-inner-text-objects-map "f" 'evil-inner-between)
例4: かなステート
ステートを自作する例として, ひらがな/カタカナを簡単に入力できるステートを定義してみましょう. Vimにはもともとダイグラフの機能があり, Evilもこれをサポートしているので, 入力されたキーのかな変換にはこれを使うことにしましょう.
ステートの定義
新しいステートを定義するにはevil-define-state
マクロを使います. これを使うだけで, ステート・キーマップ・フックといったものが自動的に作成されます.
(evil-define-state kana "Kana input state." :tag " <かな> " :cursor (bar . 2) :message "-- かな --" :enable (insert) (cond ((evil-kana-state-p) ;; かなステートに入ったときにすることはここに書く ) (t ;; かなステートを抜けるときにすることはここに書く )))
かなステートに入ったときは, 挿入ステートのキーマップも使えるようにしました(:enable
キーワード) これによってESC
でノーマルステートに戻るなどの操作は自動的に有効になります. 他にどんなキーワードがあるかは, M-x describe-function RET evil-define-state RET
やhttps://bitbucket.org/lyro/evil/src/master/evil-states.el:evil-states.elを参照して下さい. 今回は使いませんが, evil-define-state
の本体では, ステートの有効化/無効化時に実行するコードを書くことができます.
かな変換コマンド
ダイグラフそのものを表すキーが入力されたときに, ダイグラフが表す文字を挿入するコマンドevil-insert-kana
を作りましょう. たとえば,
(define-key some-map (kbd "ka") #'evil-insert-kana)
と割り当てることで, ka
の入力に対して「か」が挿入されるようにします.
this-command-keys
関数を使うと, 現在のコマンドを実行するために入力したキーを取得できるので, これをダイグラフとみなして文字を挿入するようにします.
(evil-define-command evil-insert-kana () "Insert Kanas." (interactive) (let ((str (this-command-keys))) (if (= 2 (length str)) (let ((ch (evil-digraph (list (aref str 0) (aref str 1))))) (if (characterp ch) (insert-char ch) (error "Invalid digraph \"%s\"" str))) (error "Invalid keys \"%s\"" str))))
入力されたキーが2文字でない場合, 有効なダイグラフでない場合はエラーにしています.
キーマップ
まず, 日本語のダイグラフの範囲に, evil-insert-kana
を割り当てます. 割り当てるキーマップはevil-kana-state-map
です.
(defun evil-kana-make-digraph-patterns (c1 c2) (let (result) (dolist (first (list (string c1) (upcase (string c1)))) (dolist (second (list (string c2) (upcase (string c2)))) (push (concat first second) result))) result)) (let* ((vowels '(?a ?i ?u ?e ?o)) (consonants '(?k ?s ?t ?n ?h ?m ?y ?r ?w ?g ?z ?d ?b ?v)) (singles '(?n))) (dolist (v vowels) (define-key evil-kana-state-map (format "%c5" v) #'evil-insert-kana) (define-key evil-kana-state-map (format "%c6" v) #'evil-insert-kana) (define-key evil-kana-state-map (upcase (format "%c5" v)) #'evil-insert-kana) (define-key evil-kana-state-map (upcase (format "%c6" v)) #'evil-insert-kana) (dolist (c consonants) (dolist (str (evil-kana-make-digraph-patterns c v)) (define-key evil-kana-state-map (read-kbd-macro str) #'evil-insert-kana)))) (dolist (s singles) (define-key evil-kana-state-map (format "%c5" s) #'evil-insert-kana) (define-key evil-kana-state-map (format "%c6" s) #'evil-insert-kana)))
ノーマルステートからC-k
でかなステートに移れるようにします.
(define-key evil-normal-state-map (kbd "C-k") #'evil-kana-state)
リファレンス
ステート
(evil-define-state name doc keywords... body...)
- ステートを定義します. ステート切り替えコマンド
evil-name-state
, ステート判別コマンドevil-name-state-p
, キーマップevil-name-state-map
などが自動的に定義されます.keywords
にキーワードを指定することで, モードラインに表示するステートのタグ, カーソル形状, フックなども設定できます. 詳しくはM-x describe-function RET evil-define-state RET
を参照して下さい.
コマンド
(evil-define-command name (args...) doc keywords... body)
- コマンドを定義します. キーワードには
:repeat
,:keep-visual
など, コマンドをEvil化するための設定を書きます. コマンドが引数をとる場合は,body
の先頭に(interactive "code")
と書きます.code
に指定する内容は引数の種類によってに決まり,evil-define-interactive-code
で定義されているものか, Emacs標準のものを指定します.evil-define-interactive-code
で定義されているものにどんなものがあるかは, evil-types.elを参照して下さい. (evil-define-interactive-code "code" (prompt) doc keywords... body)
- コマンド引数のコードを定義します.
(prompt)
は省略可能で, ユーザからの入力を待つ場合に指定します.prompt
は,interactive
で指定されたプロンプト文字列を受け取るための変数名です. キーワードはExコマンドの引数のコードを定義する場合に使います.body
には, 実際に引数を計算するための式を書きます.
オペレータ
(evil-define-operator name (beg end &optional type args...) doc keywords... body)
- オペレータを定義します. 最初の2つの引数は選択範囲の開始位置と終了位置を受け取ります. 3つ目の引数を受け取る場合は, 選択種別が渡されます. これ以外の方法で引数を受け取る場合は
body
の先頭に(interactive "code")
と書きます.code
の意味はevil-define-command
と同じです. キーワードには:repeat
,:motion
,:move-point
,:jump
などを指定します.:keep-visual t
と:suppress-operator t
は自動的に設定されます.body
にはオペレータの操作を書きます.
モーション
(evil-define-motion name (count args...) doc keywords... body)
- モーションを定義します. 最初の引数は繰り返し回数を受け取ります. これ以外の方法で引数を受け取る場合は
body
の先頭に(interactive "code")
と書きます.code
の意味はevil-define-command
と同じです. キーワードには:type
,:jump
などを指定します.:keep-visual t
は自動的に設定されます.body
には実際の移動操作を書きます. (evil-define-union-move name (count) moves...)
- 複数の移動操作のうち, 移動距離が最小のものを採用する移動操作を定義します.
moves
には移動操作を書きます. それぞれの移動操作は, 指定回数の移動に成功したときは0を返さなければなりません. 0以外の値を返した場合, その移動操作は採用されません.
テキストオブジェクト
(evil-define-text-object name (count &optional beg end type args...) doc keywords... body)
- テキストオブジェクトを定義します. 最初の引数は繰り返し回数, 2番目以降は選択範囲を受け取ります. これ以外の方法で引数を受け取る場合は
body
の先頭に(interactive "code")
と書きます.code
の意味はevil-define-command
と同じです. キーワードには:type
,:extend-selection
などを指定します. デフォルトでは:extend-selection t
に設定されます.body
には新しい選択範囲を表すオブジェクトを返す式を書きます. 選択範囲は, 選択開始位置, 終了位置で始まるリストで, 3つ目の要素がある場合は選択種別です. このリストは通常evil-range
関数で作ります.
補助関数
(evil-apply-on-block func beg end pass-columns args...)
- 関数
func
を,beg
からend
までの矩形範囲に適用します.func
は2引数以上の関数でなければなりません.pass-columns
がnil
のときはfunc
の最初の2引数にはバッファ内の位置が渡され, それ以外の場合は列位置が渡されます.args...
はfunc
への3つ目以降の引数です. (evil-move-beginning count forward &optional backward)
- 次の
count
番目のオブジェクトの先頭まで移動します.forward
とbackward
にはオブジェクト間を移動する関数を渡します. どちらの関数も回数を引数に取ります. もしどちらかの関数が指定されなかった場合は, 指定された方の関数に符号が逆の回数を指定したものがもう片方の関数として使われます. 関数は指定された回数の移動が成功すれば0を, そうでなければ残り回数を返す必要があります. (evil-move-end count forward &optional backward inclusive)
- 次の
count
番目のオブジェクトの末尾まで移動します.forward
とbackward
にはオブジェクト間を移動する関数を渡します. どちらの関数も回数を引数に取ります. もしどちらかの関数が指定されなかった場合は, 指定された方の関数に符号が逆の回数を指定したものがもう片方の関数として使われます. 関数は指定された回数の移動が成功すれば0を, そうでなければ残り回数を返す必要があります. カーソルをオブジェクトの末尾に移動する場合はinclusive
にt
を指定します.それ以外の場合はカーソルはオブジェクトの末尾の次の位置に移動します. (evil-an-object-range count beg end type forward &optional backward range-type newlines)
- 移動関数からオブジェクトの範囲を作ります.
beg
,end
,type
には現在の選択範囲を指定します.forward
,backward
には移動関数を指定します. 移動関数は回数を引数に取り, 指定された回数の移動が成功すれば0を, そうでなければ残り回数を返す必要があります. (evil-inner-object-range count beg end type forward &optional backward range-type )
- 移動関数からオブジェクトの範囲を作ります.
beg
,end
,type
には現在の選択範囲を指定します.forward
,backward
には移動関数を指定します. 移動関数は回数を引数に取り, 指定された回数の移動が成功すれば0を, そうでなければ残り回数を返す必要があります. (evil-range beg end &optional type properties...)
- 範囲オブジェクトを作ります.
(evil-read-key &optional prompt)
- ユーザからのキー入力を読み取ります.
prompt
を指定すると入力待ちの間プロンプトを表示します. Emacs標準のread-key
関数と違い,evil-read-key-map
が有効になります. (evil-with-single-undo body)
body
内でのバッファの変更を, 1回で元に戻せるようにします.