Files
vim-sandwich-mirror/doc/operator-sandwich.jax
machakann ffe2bae2fc Add a simple way to set timeout option both for operators and textobjects
Use g:sandwich#timeout and g:sandwich#timeoutlen.

Reported at #123
2021-11-28 16:30:11 +09:00

1855 lines
71 KiB
Plaintext

*operator-sandwich.jax* 『挟まれた』テキストを編集する。
Last change:28-Nov-2021.
書いた人 : machakann <mckn{at}outlook.jp>
ライセンス : NYSL license
日本語 <http://www.kmonos.net/nysl/>
English (Unofficial) <http://www.kmonos.net/nysl/index.en.html>
必須要件: Vim 7.4 かそれ以降のバージョン
|+reltime| 機能 (任意)
|+float| 機能 (任意)
visualrepeat.vim (vimscript #3848) プラグイン (任意)
==============================================================================
CONTENTS *operator-sandwich-contents*
TL;DR
INTRODUCTION |operator-sandwich-introduction|
KEYMAPPINGS |operator-sandwich-keymappings|
CONFIGURATION |operator-sandwich-configuration|
REQUISITE
buns
external
FILTERS
filetype
kind
motionwise
mode
action
expr_filter
LOCAL OPTIONS
cursor
highlight
hi_duration
skip_space
noremap
linewise
command
query_once
expr
autoindent
indentkeys
indentkeys+
indentkeys-
regex
skip_char
GLOBAL OPTIONS
timeout |g:operator#sandwich#timeout|
timeoutlen |g:operator#sandwich#timeoutlen|
highlight_duration |g:operator#sandwich#highlight_duration|
HIGHLIGHT GROUP |operator-sandwich-highlight-group|
AUTOCOMMANDS |operator-sandwich-autocommands|
API |operator-sandwich-api|
MISCELLANEOUS |operator-sandwich-miscellaneous|
囲みを外すオペレータのハイライトはいらない
ハイライトは全部いらない
matchit.vim のハイライトがかぶって邪魔
文字列を囲むオペレータの文字指向の場合だけ空白をスキップしないのはなぜ?
なぜ囲みを外す/置換するオペレータのキーマッピングはデフォルトで提供されない?
ドットコマンドでもカーソル位置を保存・復元したい
Query1st 系列のキーマッピングは何のためにある?
置換オペレータにおけるレシピに指定されたオプションの扱いについて
visualrepeat.vim プラグイン対応について
==============================================================================
TL;DR
こちらをご覧ください。 |sandwich-quick-start|.
==============================================================================
INTRODUCTION *operator-sandwich-introduction*
*operator-sandwich* は (foo) や "bar" などの「挟まれた」テキストを編集するため
のオペレータプラグインです。
|<Plug>(operator-sandwich-add)|, |<Plug>(operator-sandwich-delete)|,
|<Plug>(operator-sandwich-replace)| の三つの独立したオペレータからなります。
|<Plug>(operator-sandwich-add)| 文字列を括弧などで囲むオペレータです。デフォル
トでは sa にマップされています。例えば、 foo という文字列上にカーソルがあると
します。
>
foo
<
saiw" とキーを押下すると次のようになります。
>
"foo"
<
あるいは saiw( と押すと次のようになります。
>
(foo)
<
( と ) のペアに関してはそれが一つのセットとして事前に登録されており、そのため
に正しく囲むことができます。登録されていないものについては、 " と同じように同
じ文字が前後に挿入されます。登録されたセットをレシピ "recipe" と呼びます。詳し
くは |operator-sandwich-configuration| をご覧ください。
|<Plug>(operator-sandwich-delete)| は囲みを外すオペレータです。デフォルトでは
ノーマルモードに単独のマッピングが準備されませんので、試したい場合には適当なキ
ーに割り当ててください。このオペレータは指定された領域の両端が同じ文字か、登録
されたペアにマッチする場合にこれらを削除します。例えば、オペレータが sd にマッ
プされているとして、 (foo) にカーソルがあっている場合を考えます。
>
(foo)
<
sda( とキー入力をすると両端の括弧が外されます。なぜならテキストオブジェクト
|a(| は括弧を両端に含む領域を指定するためです。
>
foo
<
"foo" というテキストについてはキー入力 sd2i" (|iquote|) が同じように働くでしょ
う。実際には先に述べたように |<Plug>(operator-sandwich-delete)| は sd にマップ
されていません。なぜなら |textobj-sandwich| と組み合わせて使うのがほぼ常に便利
であるからです。このため、 sd はあらかじめ |textobj-sandwich| との複合マッピン
グとして用意されています。詳しくは |sandwich-keymappings| をご覧ください。
|<Plug>(operator-sandwich-replace)| は囲みを置き換えるオペレータです。デフォル
トではノーマルモードに単独のマッピングが準備されませんので、試したい場合には適
当なキーに割り当ててください。このオペレータは指定された領域の両端が同じ文字
か、登録されたペアにマッチする場合にこれらを置換します。例えばオペレータが sr
にマップされているとして、 (foo) にカーソルがあっている場合を考えます。
>
(foo)
<
sra(" とキー入力をすると両端の括弧がダブルクオーテーションに置換されます。
>
"foo"
<
入力の順番は削除されるもの、ここでは ( が先で、そのあとに挿入されるもの、" を
入力します。削除されるもの、挿入されるものはそれぞれ
|<Plug>(operator-sandwich-delete)| 及び |<Plug>(operator-sandwich-add)| と同じ
ように選ばれます。実際には sd と同じ理由で sr には複合マッピングがマップされて
います。詳しくは |sandwich-keymappings| をご覧ください。
------------------------------------------------------------------------------
これらすべてのオペレータは [count] を受け付けますが、その解釈方法は少し変って
います。通常のオペレータとテキストオブジェクトであれば、ありうるキー入力は次の
ようなものでしょう。
[count]{operator}[count]{textobject}
例えば 3|d|iw| というキー入力は二単語と間のスペースを削除します。カウントを入
力するタイミングは二回ありますが、これらが区別されることはありません。つまり
3diw と d3iw は原則的に同じです。もし両方のタイミングでカウントを与えれば、そ
の積がカウントとなります。つまり、 3d2iw あるいは 2d3iw は 6diw および d6iw と
全て同一のコマンドです。
これに対して |operator-sandwich| の提供するオペレータはそのタイミングによって
与えられるカウントを区別します。これらのオペレータは最初のタイミングで与えられ
るカウントのみをオペレータで使用し、後のタイミングで与えられるカウントのみをテ
キストオブジェクトに渡します。例えば、 2sa3iw(( というキー入力は二単語と間のス
ペースを二回括弧で囲みます。
>
foo bar ---> ((foo bar))
<
|.| コマンドで動作を繰り返した場合は最後に使ったカウントが使用されます。もしカ
ウントが |.| コマンドに渡された場合にはテキストオブジェクトに渡されたカウント
のみが更新されます。
------------------------------------------------------------------------------
これらのオペレータは矩形ビジュアルモード |blockwise-visual| でも動作します。例
えば次の三行三桁の領域を選択しているとします。
>
foo
bar
baz
<
sa( と入力します
>
(foo)
(bar)
(baz)
<
次の四行四桁の短い行が含まれている場合を考えます。
>
a
bb
ccc
dddd
<
sa( と入力します。
>
(a)
(bb)
(ccc)
(dddd)
<
この場合、すべての行に対し行末までを範囲として処理します。選択最終行が最も長い
行でない場合は |$| コマンドで全ての行末まで選択を拡張した状態にするとよいでし
ょう。
>
aaaa
bbb
cc
d
<
最初の行にカーソルを置き、 <C-v>3j$sa( とキー入力します。
>
(aaaa)
(bbb)
(cc)
(d)
<
==============================================================================
KEYMAPPINGS *operator-sandwich-keymappings*
このプラグインは下記のキーマッピングを提供します。
|<Plug>(operator-sandwich-add)|, |<Plug>(operator-sandwich-delete)| 及び
|<Plug>(operator-sandwich-replace)| は基本的にノーマルモード、ヴィジュアルモー
ド、オペレータ待機モードで動作します。 |<Plug>(operator-sandwich-add)| はノー
マルモードとビジュアルモードの両方で sa にマップされています。一方、
|<Plug>(operator-sandwich-delete)| と |<Plug>(operator-sandwich-replace)| はビ
ジュアルモードでのみ sd および sr に単独のマッピングとして定義されます。ノーマ
ルモードでは便利のため |textobj-sandwich| との複合マッピングとして定義されます
。詳しくは |sandwich-keymappings| をご覧ください。
機能 キーマッピング デフォルト
--------------------------------------------------------------------------
囲む <Plug>(operator-sandwich-add) sa
囲みを外す <Plug>(operator-sandwich-delete) sd (ビジュアルモード)
囲みを置換 <Plug>(operator-sandwich-replace) sr (ビジュアルモード)
--------------------------------------------------------------------------
もし上記のデフォルト設定が必要なければ、あなたの vimrc で
g:operator_sandwich_no_default_key_mappings を定義してください。
>
let g:operator_sandwich_no_default_key_mappings = 1
<
これでデフォルト設定は適用されません。お好みのキーに設定しなおしてください。
>
map ys <Plug>(operator-sandwich-add)
<
NOTE: 誤操作を防ぐため以下の設定を vimrc に追加することを強く推奨します。
>
nmap s <Nop>
xmap s <Nop>
<
|s| コマンドは |c|l| コマンドによって代替できます。
------------------------------------------------------------------------------
キーマッピング~
<Plug>(operator-sandwich-add) *<Plug>(operator-sandwich-add)*
テキストを括弧などで囲むためのオペレータコマンドです。[count] が与えら
れた場合、その数だけ囲みを追加します。
<Plug>(operator-sandwich-delete) *<Plug>(operator-sandwich-delete)*
テキストの囲みを外すためのオペレータコマンドです。 [count] が与えられ
た場合、その数だけ連続する囲みを外します。
<Plug>(operator-sandwich-replace) *<Plug>(operator-sandwich-replace)*
テキストの囲みを置き換えるためのオペレータコマンドです。 [count] が与
えられた場合、その数だけ連続する囲みを置換します。
query-1st 系列キーマッピング~
*<Plug>(operator-sandwich-add-query1st)*
テキストを括弧などで囲むためのオペレータコマンドです。[count] が与えら
れた場合、その数だけ囲みを追加します。|<Plug>(operator-sandwich-add)|
とは違い、 {motion/textobject} の入力の前に挿入する文字の決定を行いま
す。
>
nmap sa <Plug>(operator-sandwich-add-query1st)
" Press sa(iw
" foo -> (foo)
<
NOTE: ノーマルモードへのマップでのみ意味を持ちます。|:xmap| でビジュア
ルモードにもマップできますが、ビジュアルモードでは入力順序が通常
の |<Plug>(operator-sandwich-add)| と同じです。また、別の理由か
ら使用が推奨されません。 |operator-sandwich-miscellaneous| を
ご覧ください。
*<Plug>(operator-sandwich-replace-query1st)*
テキストの囲みを置き換えるためのオペレータコマンドです。 [count] が与
えられた場合、その数だけ連続する囲みを置換します。
|<Plug>(operator-sandwich-replace)|とは違い、 {motion/textobject} の入
力の前に挿入する文字の決定を行います。
>
nmap sa <Plug>(operator-sandwich-replace-query1st)
" Press sr(a[
" [foo] -> (foo)
<
NOTE: ノーマルモードへのマップでのみ意味を持ちます。|:xmap| でビジュア
ルモードにもマップできますが、ビジュアルモードでは入力順序が通常
の |<Plug>(operator-sandwich-replace)| と同じです。また、別の
理由から使用が推奨されません。 |operator-sandwich-miscellaneous|
をご覧ください。
補助キーマッピング~
カウントの取り扱いに関して、補助的な働きをするキーマッピングが三つ用意されてい
ます。短縮キーマッピングなどを独自に定義する際に役に立つでしょう。オペレータの
独特なカウントの扱いについては |operator-sandwich-introduction| をご覧ください
。実用例は |sandwich-keymappings| をご覧ください。
*<Plug>(operator-sandwich-synchro-count)*
<Plug>(operator-sandwich-synchro-count)
オペレータに与えられた [count] と同じカウントを続く
{motion}/{textobject} に与えるためのキーマッピングです。
>
nmap sd(
\ <Plug>(operator-sandwich-delete)<Plug>(operator-sandwich-synchro-count)a(
<
このキーマッピングでは 2sd( は 2<Plug>(operator-sandwich-delete)2a( に
等しくなります。
*<Plug>(operator-sandwich-release-count)*
<Plug>(operator-sandwich-release-count)
与えられたカウントをオペレータで使わずに続く {motion}/{textobject} に
与えるためのキーマッピングです。
>
nmap sd(
\ <Plug>(operator-sandwich-delete)<Plug>(operator-sandwich-release-count)a(
<
このキーマッピングでは 2sd( は <Plug>(operator-sandwich-delete)2a( に
等しくなります。
*<Plug>(operator-sandwich-squash-count)*
<Plug>(operator-sandwich-squash-count)
与えられたカウントをすべて無視するためのキーマッピングです。
>
nmap sd(
\ <Plug>(operator-sandwich-delete)<Plug>(operator-sandwich-squash-count)a(
<
このキーマッピングでは 2sd( は <Plug>(operator-sandwich-delete)a( に
等しくなります。
ドットコマンドを便利にする補助的なキーマッピングが二種あります。これらは local
option の "cursor" に関係しており、このオプションの選択肢 "keep" を |.| コマン
ドリピート時にも有効にするために使われます。カーソル位置を編集後にも保つための
このオプションはデフォルトでは |.| コマンドリピート時には有効にならないのです
が、以下のどちらかのキーマッピングを使用することで有効にすることができます。他
のプラグインとキーマッピングが衝突する恐れがあるので、環境によって適切なほうを
使用してください。 |operator-sandwich-configuration| の local option 中 cursor
オプションの項もご覧ください。
vim-event-DotCommandPre <https://github.com/machakann/vim-event-DotCommandPre>
を使用している場合は、以下のキーマッピングを使用する必要はありません。
*<Plug>(operator-sandwich-predot)*
<Plug>(operator-sandwich-predot)
このキーマッピングは local option "cursor" の "keep" を |.| コマンドで
も有効にするために使われます。このキーマッピング自体は |.| キーを送ら
ないので、 |.| キーシークエンスを送るマッピングに先駆けるようにマップ
してください。 |.| キーにマップするような他のプラグイン、例えば
`<Plug>(ExampleDot)` というマッピングを |.| キーに定義するプラグインを
ご使用の場合は次のように使います。
>
nmap . <Plug>(operator-sandwich-predot)<Plug>(ExampleDot)
<
repeat.vim (vimscript #2136) をご使用の場合は `<Plug>(RepeatDot)` の
定義が遅延されているので、そのキーマッピングの存在を保証するために次の
行を vimrc へ追加します。
>
runtime autoload/repeat.vim
nmap . <Plug>(operator-sandwich-predot)<Plug>(RepeatDot)
<
*<Plug>(operator-sandwich-dot)*
<Plug>(operator-sandwich-dot)
このキーマッピングは local option "cursor" の "keep" を |.| コマンドで
も有効にするために使われます。このキーマッピング自体が |.| キーを送る
ので、 |.| キーにマップするようなプラグインをお使いでなければこちらを
使用してください。次の行を vimrc に追加します。
>
nmap . <Plug>(operator-sandwich-dot)
<
キーマッピング関数~
ユーザーは新しいキーマッピングを定義するのに以下の関数を使うこともできます。
*operator#sandwich#keymap()*
operator#sandwich#keymap(kind, mode[, options[, recipes]])
この関数はオペレータのキーマッピングを定義するのにつかわれます。
>
nnoremap <silent> sa :<C-u>call operator#sandwich#keymap('add', 'n')<CR>
xnoremap <silent> sa <Esc>:call operator#sandwich#keymap('add', 'x')<CR>
<
省略可能な第三引数に空でない辞書変数が与えられた場合、辞書に含まれる
local option はそのキーマッピングで使われるオプションのデフォルト値
を上書きします。ただし、 motionwise に依って設定することはここではでき
ません。
>
" example 1
nnoremap <silent> sa
\ <Esc>:call operator#sandwich#keymap(
\ 'add',
\ 'n',
\ {'highlight': 0}
\ )<CR>
" example 2
let g:sandwich_alt_options = {'highlight': 0}
nnoremap <silent> sa
\ <Esc>:call operator#sandwich#keymap(
\ 'add',
\ 'n',
\ g:sandwich_alt_options
\ )<CR>
<
省略可能な第四引数にリストが与えられた場合、そのキーマッピングは
|g:sandwich#recipes| (|g:sandwich#default_recipes|) や
|g:operator#sandwich#recipes| (|g:operator#sandwich#default_recipes|)
のかわりに引数に与えられたリストを参照します。
>
" example 1
nnoremap <silent> sa
\ <Esc>:call operator#sandwich#keymap(
\ 'add',
\ 'n',
\ {},
\ [{'buns': ['(', ')']}]
\ )<CR>
" example 2
let g:sandwich_alt_recipes = [{'buns': ['(', ')']}]
nnoremap <silent> sa
\ <Esc>:call operator#sandwich#keymap(
\ 'add',
\ 'n',
\ {},
\ g:sandwich_alt_recipes
\ )<CR>
<
*operator#sandwich#query1st()*
operator#sandwich#query1st(kind, mode[, options[, recipes]])
この関数は |operator#sandwich#keymap()| と同様の関数ですが、
|<Plug>(operator-sandwich-add-query1st)| や
|<Plug>(operator-sandwich-replace-query1st)| などの query1st 系列の
キーマッピングを定義するのに使われます。
==============================================================================
CONFIGURATION *operator-sandwich-configuration*
囲み文字のセットと付加情報をまとめたものをレシピ "recipe" と呼びます。一つ一つ
のレシピは |Dictionary| であり、これを集めた |list| がオペレータの動作を決めま
す。 |g:sandwich#default_recipes| はそのリストのうちの一つで、
|operator-sandwich| と |textobj-sandwich| の両方から参照されます。これは多くの
場合、共有された方が便利であるためです。もしユーザーが |g:sandwich#recipes| を
定義した場合はかわりにそちらが使用されます。デフォルトの
|g:sandwich#default_recipes| は |:echo| コマンドで確認できます。
>
:echo g:sandwich#default_recipes
<
この変数はロックされていますが、 |g:sandwich#recipes| をユーザーが宣言する際に
必要ならコピーすることができます。
>
:let g:sandwich#recipes = deepcopy(g:sandwich#default_recipes)
<
デフォルトでは (), [], {}, <> のセットが登録されています。より詳しくは
|g:sandwich#default_recipes| をご覧ください。
|g:operator#sandwich#default_recipes| はまた別のリストで、こちらは
|operator-sandwich| のみからしか参照されません。ユーザーが
|g:operator#sandwich#recipes| を定義した際にはそちらがかわりに使用されます。
|g:operator#sandwich#default_recipes| は |g:sandwich#default_recipes| と同様に
ロックされています。
g:operator#sandwich#recipes *g:operator#sandwich#recipes*
オペレータのみから参照されるレシピのリストです。このリストが存在しない
場合は |g:operator#sandwich#default_recipes| が使用されます。
*b:operator_sandwich_recipes*
|b:operator_sandwich_recipes| が存在する場合は、
|g:operator#sandwich#recipes| のかわりにそちらが使われます。これはバッ
ファについてローカルな値なので、ファイルタイプ固有な設定が増えすぎた時
に使うと便利かもしれません。
g:operator#sandwich#default_recipes *g:operator#sandwich#default_recipes*
デフォルトで用意されるレシピのリストの一つです。オペレータのみから参照
されます。ユーザーが |g:operator#sandwich#recipes| を定義した場合には
そちらがかわりにつかわれます。その際必要ならコピーすることができます。
>
:let g:operator#sandwich#recipes
\ = deepcopy(g:operator#sandwich#default_recipes)
<
NOTE: もしレシピが競合する場合は |g:operator#sandwich#default_recipes| か
|g:operator#sandwich#recipes| が |g:sandwich#default_recipes| か
|g:sandwich#recipes| よりも優先されます。また同じリスト内であれば、リス
ト後方のレシピほど優先されます。
------------------------------------------------------------------------------
一つ一つのレシピは |Dictionary| 変数であり、 requisite, input, filter, local
optionの四種の情報を持ちえます。 requisite はすべてのレシピに必須の情報で囲み
文字を特定するためのものです。input はレシピを指定するためのユーザー入力を決め
ます。 filter は使用する状況によってレシピを選別するためにあります。 local
option はレシピによってオペレータの働きを細かく制御するために使われます。さら
にこれら以外にオペレータの基本的な動作を制御するための global option もいくつ
か存在します。
設定を変更する場合はまず必要なリストを宣言しましょう。
>
let g:sandwich#recipes = []
<
あるいはデフォルト設定を引き継ぐためにコピーしてもよいでしょう。
>
let g:sandwich#recipes = deepcopy(g:sandwich#default_recipes)
<
Requisite~
requisite には buns と external の二種類あり、すべてのレシピはどちらかを持たな
ければなりません。
buns
テキストを囲む文字列のセットを定義するためのキーです。値に文字列を二つ
要素に持つ |list| を持ちます。囲むまたは置換するオペレータにおける挿入
される文字列、囲みを外すまたは置換するオペレータにおける削除される文字
列の両方に使われます。もし "regex" オプションが真なら正規表現として扱
われます。またレシピが "input" キーを持たない場合、レシピを指定するた
めのキー入力にも使われます。
>
let g:sandwich#recipes += [
\ {'buns': ['(', ')']}
\ ]
" Press saiw( or saiw)
" foo ---> (foo)
let g:sandwich#recipes += [
\ {'buns': ['ab', 'cd']}
\ ]
" Press saiwab or saiwcd
" foo ---> abfoocd
let g:sandwich#recipes += [
\ {'buns': ['ab', 'cd'], 'input': ['a']}
\ ]
" Press saiwa
" foo ---> abfoocd
<
external
こちらは補助的に使われる requisite です。文字列二要素の |list| でそれ
ぞれの要素は外部のテキストオブジェクトになります。囲みを外すまたは置換
するオペレータにおける削除される文字列を検索する場合にのみ使われ、挿入
文字列としては使われません。つまり、言い換えれば囲むオペレータでは使わ
れません。削除文字列は二つのテキストオブジェクトの選択する範囲の差によ
って決められ、リストの前方の要素が狭い範囲を選択するテキストオブジェク
ト、後方の要素が広い範囲を選択するテキストオブジェクトとみなされます。
"buns" とは違い、多くの local option が無効になります。
>
let g:sandwich#recipes += [
\ {'external': ['it', 'at']}
\ ]
" "it" selects the text inside tags, "at" selects including tags.
" Therefore, the deletions are the both tags.
" <---it--->
" <title>title here</title>
" <----------at----------->
" Press <Plug>(operator-sandwich-delete)at
" <title>title here</title> ---> title here
<
"noremap" オプションは有効です。内部的にはビジュアルモード選択を利用し
て範囲を確かめているのでビジュアルモードへのマッピング (xmap,
xnoremap, vmap, vnoremap)が展開の対象になります。
>
let g:sandwich#recipes += [
\ {'external': ['i[', 'a['], 'noremap': 0}
\ ]
" Press <Plug>(operator-sandwich-delete)a[
" [foo] ---> foo
xnoremap i[ i{
xnoremap a[ a{
" Press <Plug>(operator-sandwich-delete)a{
" {foo} ---> foo
<
"noremap" オプションと組み合わせることでユーザー定義テキストオブジェク
トも同様にレシピ化できます。
>
" "noremap" option should be false.
let g:sandwich#recipes += [
\ {
\ 'external': ["\<Plug>(textobj-sandwich-auto-i)",
\ "\<Plug>(textobj-sandwich-auto-a)"],
\ 'noremap': 0,
\ }
\ ]
<
NOTE: 使用するテキストオブジェクトはビジュアルモードで正しく動作するこ
とを期待されます。
NOTE: すべてのテキストオブジェクトが動作するとは限りません。
Input~
input
文字列を囲むまたは置換する際、オペレータは囲みを決定するためにユーザー
に入力を促します。この時の入力に使われるのがこのキーの値になります。値
はリストで複数の文字列を含むことができます。このキーを持たないレシピで
は "buns" がかわりにつかわれます。以下の例では、 "input" キーを持たな
いので "buns" がそのまま使われます。
>
let g:sandwich#recipes += [
\ {'buns': ['"""', '"""']}
\ ]
" Press saiw"""
" foo ---> """foo"""
<
"input" キーがあればそちらがかわりにつかわれます。
>
let g:sandwich#recipes += [
\ {'buns': ['"""', '"""'], 'input': ['"']}
\ ]
" Press saiw"
" foo ---> """foo"""
<
Filter~
filetype
ファイルタイプによってレシピを選別するフィルターです。値はリストでファ
イルタイプ名の文字列が要素になります。レシピが "filetype" キーを持たな
いか、要素として "all" を持つ場合はすべてのファイルタイプで有効になり
ます。
>
" The following recipes are valid on any filetype.
let g:sandwich#recipes += [
\ {'buns': ['(', ')']}
\ {'buns': ['[', ']'], 'filetype': ['all']}
\ ]
" The textobj "it" and "at" is not versatile and might be heavy on
" large files, thus it would be better to activate only on specific
" filetypes.
let g:sandwich#recipes += [
\ {'external': ['it', 'at'], 'filetype': ['html']}
\ ]
<
kind
オペレータの種類によってレシピを選別するフィルターです。値はリストで要
素にオペレータの種類を文字列として持ちます。使用可能な種類は "add",
"delete", "replace", "operator", "all" です。 "operator" は "add",
"delete", "replace" のすべてを指定した場合と同じです。 "operator" と
"all" の違いは、 "all" は |textobj-sandwich| の種類も含むことがある点
にあります。あわせて |textobj-sandwich-configuration| もご覧ください。
レシピが "kind" キーを持たなければすべての種類で有効です。
>
" The following recipe is valid only with the add operator.
let g:sandwich#recipes += [
\ {'buns': ['"""', '"""'], 'kind': ['add']}
\ ]
<
motionwise
指定された範囲の性質によってレシピを選別するフィルターです。値はリスト
で使用可能な要素は "char", "line", "block", "all" です。範囲の種類につ
いては|characterwise|, |linewise|, |characterwise-visual|,
|linewise-visual|, |blockwise-visual| の項をご覧ください。レシピが
"motionwise" キーを持たなければすべての範囲指定に関して有効です。
>
" The following recipe is valid only in linewise motion or linewise
" visual.
let g:sandwich#recipes += [
\ {'buns': ['```', '```'], 'motionwise': ['line']}
\ ]
<
mode
使用されたモードによってレシピを選別するフィルターです。値はモードを表
す文字のリストです。使用可能な文字は "n" と "x" のみです。"n" はノーマ
ルモードを、 "x" はビジュアルモードを表します。レシピが "mode" キーを
持たなければすべてのモードで有効です。
>
" These recipes are switch behaviors on modes with the same input.
let g:sandwich#recipes += [
\ {'buns': ['"', '"'], 'mode': ['n']}
\ {'buns': ['"""', '"""'], 'mode': ['x'], 'input': ['"']}
\ ]
<
action
編集方法の種類によってレシピを選別するフィルターです。すべてのオペレー
タの動作は、追加 "add" と削除 "delete" の二つの編集方法に分けることが
できます。文字列を囲むオペレータは "add" のみ、囲みを外すオペレータは
"delete" のみ、置換するオペレータは "delete" のち "add" をすることによ
り置換しています。このフィルターはそれぞれの編集において使われる機会を
制限します。使用可能な名前は "add", "delete", "all" です。レシピが
"action" キーを持たなければすべての編集操作において有効になります。
"add" のみが指定されている場合、そのレシピは |textobj-sandwich| で無効
になりますが、"delete" 及び "all" が含まれていれば有効になります。これ
は通常、削除においてそれらのテキストオブジェクトが内部的に使われるため
です。
つまり、"add" は追加と置換のオペレータで有効、"delete" は削除と置換の
オペレータに加え、テキストオブジェクトで有効となります。
>
" The recipe is valid only for add actions
let g:sandwich#recipes += [
\ {'buns': ['"""', '"""'], 'action': ['add'], 'input': ['"']}
\ ]
" The recipe is valid for delete actions and textobjects
let g:sandwich#recipes += [
\ {'buns': ['"""', '"""'], 'action': ['delete'], 'input': ['"']}
\ ]
<
expr_filter
ユーザーがフィルターを自作して使うことができます。リストの要素は式
|expression| として評価され、評価値が真 (1) の場合にはそのレシピは有効
となり、評価値が偽 (0) の場合にはレシピは無効となります。
>
" A filter should be defined in somewhere, for example in your vimrc.
function! FilterValid()
return 1
endfunction
function! FilterInvalid()
return 0
endfunction
" This recipe is valid
let g:sandwich#recipes += [
\ {'buns': ['(', ')'], 'expr_filter': ['FilterValid()']}
\ ]
" This recipe is invalid
let g:sandwich#recipes += [
\ {'buns': ['(', ')'], 'expr_filter': ['FilterInvalid()']}
\ ]
<
Local option~
local option はレシピごとに細かく挙動を調整するために設定されます。もし指定の
ない場合はデフォルトで設定されている値が使われます。この値はオペレータの種類と
範囲指定の性質に依って違う値をもち、 |g:operator#sandwich#options| に格納され
ています。
例えば、文字列を囲むオペレータの文字単位範囲に対するハイライトをOn/Offするオプ
ション "highlight" のデフォルト値を変更したい場合は次のようにします。
>
let g:operator#sandwich#options.add.char.highlight = 0
<
あるいは関数インターフェースも用意されています。 |operator#sandwich#set()|
>
call operator#sandwich#set('add', 'char', 'highlight', 0)
<
g:operator#sandwich#options *g:operator#sandwich#options*
local option のデフォルト値を格納した |Dictionary| 変数です。
>
let operator#sandwich#options[kind][motionwise][option] = {value}
" For example
let g:operator#sandwich#options['add']['char']['highlight'] = 0
" or
let g:operator#sandwich#options.add.char.highlight = 0
<
*b:operator_sandwich_options*
|b:operator_sandwich_options| が存在する場合はそちらが優先されます。
バッファについてローカルなオプション設定を使うのに便利でしょう。
使用可能なキー名を下に列挙します。
* kind
- add
- delete
- replace
* motionwise
- char
- line
- block
* option
- cursor (for all kinds)
- highlight (for all kinds)
- skip_space (for all kinds)
- noremap (for all kinds)
- linewise (for all kinds)
- command (for all kinds)
- query_once (for add and replace)
- expr (for add and replace)
- listexpr (for add and replace)
- autoindent (for add and replace)
- indentkeys (for add and replace)
- indentkeys- (for add and replace)
- indentkeys+ (for add and replace)
- regex (for delete and replace)
- skip_char (for delete and replace)
*operator#sandwich#set()*
operator#sandwich#set(kind, motionwise, option, value)
local option のデフォルト値を安全かつ簡単に変更するための関数です。引
数の組み合わせが不正な場合、関数はメッセージを表示します。使用可能な引
数は |g:operator#sandwich#options| の項に列挙されています。また、これ
に加えて、この関数では "all" を kind 及び motionwise に指定することが
できます。
*operator#sandwich#setlocal()*
operator#sandwich#setlocal(kind, motionwise, option, value)
local option のバッファについてローカルなデフォルト値を安全かつ簡単に
変更するための関数です。引数の組み合わせが不正な場合、関数はメッセージ
を表示します。使用可能な引数は |g:operator#sandwich#options| の項に列
挙されています。また、これに加えて、この関数では "all" を kind 及び
motionwise に指定することができます。
operator#sandwich#set_default() *operator#sandwich#set_default()*
local option のデフォルト値を初期化します。
cursor
オペレータが編集後のカーソル位置を指定するオプションです。
"innner_head", "keep", "inner_tail", "head", "tail" が使用可能です。
inner_head: 囲みの内側の文字列の先頭
keep : 処理開始時のカーソル位置をできる限り復元する
inner_tail: 囲みの内側の文字列の末尾
head : 前方の囲みの先頭
tail : 後方の囲みの末尾
headend : 前方の囲みの末尾
tailstart : 後方の囲みの先頭
default : inner_head とほぼ同じですがカーソルが行頭に来るときは最
初の非空白文字まで送ります
>
# : cursor
foo ---> (foo)
# : inner_head
(foo)
# : inner_tail
# : keep
(foo)
# : head
(foo)
# : tail
<
NOTE: 残念ながら "keep" オプションは |.| コマンドでの繰り返しの際に
デフォルトではカーソル位置を復元できません。自動的に
"inner_head" へフォールバックします。必要であれば補助キーマッピ
ング |<Plug>(operator-sandwich-predot)| か
|<Plug>(operator-sandwich-dot)| を |.| キーにマッピングすること
でこの機能を有効にすることができます。
デフォルト値
* add
- char : "default"
- line : "default"
- block: "default"
* delete
- char : "default"
- line : "default"
- block: "default"
* replace
- char : "default"
- line : "default"
- block: "default"
highlight
処理対象のハイライト機能のオン/オフを切り替えます。値が真なら編集位置
をハイライトします。値が 1 の場合は簡素な、値が 2 の場合は多色を用いた
リッチなハイライトを行います。さらに、値が 3 の場合は編集後も追加文字
列を一定時間ハイライトします。 0 を設定するとハイライトを停止します。
囲みを外すオペレータのハイライトやリッチなハイライトを使っている場合は
、編集後も |g:operator#sandwich#highlight_duration| に指定された時間の
間ハイライトが残りますが、この間もユーザーの操作はブロックされていませ
ん。何らかの入力があった場合直ちにハイライトを中止されます。
ハイライトに使われる色はユーザーの好きなように変更できます。
|operator-sandwich-highlight-group| の項をご覧ください。
NOTE: このオプションはレシピで指定しても効果がありません。
変更する場合は |operator#sandwich#set()| 関数を使ってください。
>
call operator#sandwich#set('all', 'all', 'highlight', 1)
<
デフォルト値
* add
- char : 3
- line : 3
- block: 3
* delete
- char : 3
- line : 3
- block: 3
* replace
- char : 3
- line : 3
- block: 3
hi_duration
オペレータにおける編集後にハイライトが持続する時間をミリ秒単位で指定し
ます。デフォルト値は 200 です。
NOTE: このオプションはレシピで指定しても効果がありません。
変更する場合は |operator#sandwich#set()| 関数を使ってください。
>
call operator#sandwich#set('all', 'all', 'hi_duration', 1)
<
デフォルト値
* add
- char : 200
- line : 200
- block: 200
* delete
- char : 200
- line : 200
- block: 200
* replace
- char : 200
- line : 200
- block: 200
skip_space
値が 1 なら、指定された文字列の両端のスペースをスキップします。
>
let g:sandwich#recipes += [
\ {'buns': ['(', ')'], 'skip_space': 0}
\ ]
" Press sa5l( when the cursor is on the first space.
" ?foo? ---> ( foo ) : ? is space
let g:sandwich#recipes = []
let g:sandwich#recipes += [
\ {'buns': ['(', ')'], 'skip_space': 1}
\ ]
" ?foo? ---> ?(foo)? : ? is space
<
ただし、囲みを外す/置換するオペレータについては両端が同じ文字である場
合は動作条件を満たすのでこれはただちに削除/置換されます。よってこのオ
プションは指定範囲の片側のみが空白であった場合に動作します。
>
let g:sandwich#recipes += [
\ {'buns': ['"', '"'], 'skip_space': 1}
\ ]
" Press sda"
" ?"foo" ---> ?foo : ? is space
<
両端が空白の場合にもこれをスキップするためには値を 2 にします。
デフォルト値
* add
- char : 0
- line : 1
- block: 1
* delete
- char : 1
- line : 2
- block: 1
* replace
- char : 1
- line : 2
- block: 1
noremap
このオプションは囲みを挿入する際にキーマッピングを展開するかどうかを切
り替えます。値が真なら展開しません。
>
inoremap ( [
inoremap ) ]
let g:sandwich#recipes += [
\ {'buns': ['(', ')'], 'noremap': 1}
\ ]
" Press saiw(
" foo ---> (foo)
let g:sandwich#recipes = []
let g:sandwich#recipes += [
\ {'buns': ['(', ')'], 'noremap': 0}
\ ]
" Press saiw(
" foo ---> [foo]
<
このオプションは requisite の "external" にも適用されます。
デフォルト値
* add
- char : 1
- line : 1
- block: 1
* delete
- char : 1
- line : 1
- block: 1
* replace
- char : 1
- line : 1
- block: 1
linewise
このオプションは文字列の挿入/削除の方法を切り替えます。通常の動作は文
字単位指向です。
>
call operator#sandwich#set('add', 'char', 'linewise', 0)
" Press saiw(
" foo ---> (foo)
<
このオプションが1であれば、行指向になります。
>
call operator#sandwich#set('add', 'char', 'linewise', 1)
" Press saiw(
" foo ---> (
foo
)
<
文字列を削除する場合は、文字列削除後にその行に空白文字以外に残っていな
ければ行ごと削除します。
>
call operator#sandwich#set('delete', 'char', 'linewise', 0)
" Press <Plug>(operator-sandwich-delete)a(
" ( : this line was remained
" foo ---> foo : this line was remained
" ) : this line was remained
call operator#sandwich#set('delete', 'char', 'linewise', 1)
" Press <Plug>(operator-sandwich-delete)a(
" ( ---> foo
" foo
" )
<
空白文字以外が残るようであれば行を保存します。
>
call operator#sandwich#set('delete', 'char', 'linewise', 1)
" Press <Plug>(operator-sandwich-delete)a(
" (foo foo
" bar ---> bar
" baz) baz
<
値が2の場合は空白以外が残っても気にせず行を削除します。
>
call operator#sandwich#set('delete', 'char', 'linewise', 2)
" Press <Plug>(operator-sandwich-delete)a(
" (foo ---> bar
" bar
" baz)
<
囲みを置換するオペレータの場合はこれらの組み合わせの動作になります。
NOTE: コマンドラインウィンドウ |cmdline-window| 内では無視され、0が指
定されているかのように振舞います。
デフォルト値
* add
- char : 0
- line : 1
- block: 0
* delete
- char : 0
- line : 1
- block: 0
* replace
- char : 0
- line : 0
- block: 0
command
オペレータ処理後に実行されるコマンドのリストです。 |'[| と |']| の二つ
のマークが編集した位置の先頭と末尾へ設定されるので、これを使うと便利で
しょう。
>
let g:sandwich#recipes += [
\ {
\ 'buns' : ['{', '}'],
\ 'linewise': 1,
\ 'command' : ["'[+1,']-1normal! >>"]
\ },
\ ]
" Press saiw{
" foo ---> {
foo
}
<
デフォルト値
* add
- char : []
- line : []
- block: []
* delete
- char : []
- line : []
- block: []
* replace
- char : []
- line : []
- block: []
query_once
このオプションは [count] が与えられた場合の挙動を変更します。もしこの
値が偽なら、文字列を囲むオペレータと囲みを置換するオペレータは与えられ
たカウントの回数だけ挿入文字列をユーザーに尋ねます。一方、このオプショ
ンの値が真の場合、一回だけ尋ねて、以降は同じものを挿入します。
デフォルト値
* add
- char : 0
- line : 0
- block: 0
* replace
- char : 0
- line : 0
- block: 0
expr
このオプションの値が 1 か 2 なら "buns" は式として評価されてから挿入さ
れます。値が 1 の場合は一度だけ評価され、|.| コマンドでは同じものが使
用されます。値が 2 の場合は |.| コマンドで繰り返される毎に評価されます
。例えば以下のレシピはその時々の無名レジスタ |quotequote| の内容を挿入
します。 (参考: |:let-@|)
>
let g:sandwich#recipes += [
\ {'buns': ['@@', '@@'], 'expr': 1, 'input': ['@']}
\ ]
<
NOTE: このオプションが真の時、 "buns" はレシピを呼ぶためのキー入力とは
みなされませんので、 "input" の指定が必要になります。
NOTE: もし式が |getchar()| や |input()| でユーザーに入力を求める場合、
|operator-sandwich| の囲みを外すオペレータや |textobj-sandwich|
の |<Plug>(textobj-sandwich-auto-i)| や
|<Plug>(textobj-sandwich-auto-a)| で不都合が出ることがあります。
この問題を避けるために、 "kind" フィルター及び "action" フィルタ
ーを併用することが推奨されます。例えば次のレシピは html スタイル
のタグで囲むことを目的として、タグ名の入力をユーザーに求めます。
NOTE: |textobj-sandwich| と違い |operator-sandwich| は "buns" に空文字
列を許容します。もし中止したい場合は例外
'OperatorSandwichCancel' を |:throw| してください。
>
let g:operator#sandwich#recipes += [
\ {
\ 'buns' : ['TagInput(1)', 'TagInput(0)'],
\ 'expr' : 1,
\ 'filetype': ['html'],
\ 'action' : ['add'],
\ 'input' : ['t'],
\ },
\ ]
function! TagInput(is_head) abort
if a:is_head
let s:TagLast = input('Tag: ')
if s:TagLast !=# ''
let tag = printf('<%s>', s:TagLast)
else
throw 'OperatorSandwichCancel'
endif
else
let tag = printf('</%s>',
\ matchstr(s:TagLast, '^\a[^[:blank:]>/]*'))
endif
return tag
endfunction
<
デフォルト値
* add
- char : 0
- line : 0
- block: 0
* replace
- char : 0
- line : 0
- block: 0
listexpr
このオプションは上の "expr" オプションに似ていますが、一つの文字列を
buns として渡します。この文字列の評価値が文字列二つを含むリストを返す
ことが必要です。これは html タグのように前後の囲みが文字列を共有する場
合を "expr" の場合よりも自然に記述できます。
>
let g:operator#sandwich#recipes += [
\ {
\ 'buns' : 'HTMLTagInput()',
\ 'listexpr': 1,
\ 'filetype': ['html'],
\ 'action' : ['add'],
\ 'input' : ['t'],
\ },
\ ]
function! HTMLTagInput() abort
let tagstring = input('Tag: ')
if tagstring ==# ''
throw 'OperatorSandwichCancel'
endif
let former = printf('<%s>', tagstring)
let latter = printf('</%s>',
\ matchstr(tagstring, '^\a[^[:blank:]>/]*'))
return [former, latter]
endfunction
<
デフォルト値
* add
- char : 0
- line : 0
- block: 0
* replace
- char : 0
- line : 0
- block: 0
autoindent
このオプションはオペレーターによる編集中の自動インデント機能を指定する
のにつかわれます。値には整数を指定します。1~3の整数にそれぞれ vim の
オプション 'autoindent', 'smartindent', 'cindent' が対応しています。値
が 0 の場合はすべての自動インデント機能を停止します。値が負数の場合は
設定を変更せず、現行の設定をそのまま使います。もし vim の 'indentexpr'
オプションを使用したい場合には負数を指定するとよいでしょう。
* -n : 設定を変更しない ( 'indentexpr' が空でなければそれが使われる)
* 0 : 'noautoindent', 'nosmartindent', 'nocindent', 'indentexpr'=''
* 1 : 'autoindent'
* 2 : 'smartindent'
* 3 : 'cindent'
* 4 : 常にインデントを保持する
>
let g:sandwich#recipes += [
\ {'buns': ['{', '}'], 'motionwise': ['line'], 'autoindent': 3},
\ ]
<
Default values
* add
- char : -1
- line : -1
- block: -1
* replace
- char : -1
- line : -1
- block: -1
indentkeys
indentkeys+
indentkeys-
これらのオプションはオペレーター編集中に vim のオプション 'indentkeys'
あるいは 'cinkeys' オプションの値を指定するためのオプションです。書式
は 'cinkeys' オプションと同様です。"indentkeys" オプションの値は
|:set| indentkeys={value}
の {value} のように設定されます。同じように "indentkeys+",
"indentkeys-" オプションの値はそれぞれ、
|:set| indentkeys+={value}
|:set| indentkeys-={value}
{value} のように設定されます。ただし一点だけ違いがあり、
|:set| indentkeys-={value} の場合は、次のようにその順番に処理が依存し
ます。
>
:set indentkeys? " -> 0{,0},:,0#,!^F,o,O,e
:set indentkeys-=0},0{
:set indentkeys? " -> 0{,0},:,0#,!^F,o,O,e
" '0{' and '0}' は取り除かれていない、
" なぜなら '0},0{' という文字列は 'indentkeys' の中にないからである。
:set indentkeys-=0}
:set indentkeys? " -> 0{,:,0#,!^F,o,O,e
:set indentkeys-=0{
:set indentkeys? " -> :,0#,!^F,o,O,e
<
これに対し "indentkeys-" オプションの場合は順番を気にする必要はありま
せん。単純にコンマ区切りで列挙してください。
>
let g:sandwich#recipes += [
\ {'buns': ['[', ']'], 'filetype': ['tex'], 'indentkeys-': '[,]'}
\ ]
" This is same as the above
"let g:sandwich#recipes += [
" \ {'buns': ['[', ']'], 'filetype': ['tex'], 'indentkeys-': '],['}
" \ ]
<
もし、 'indentexpr' オプションが空で 'cindent' が有効なら自動的に
'cinkeys' へ処理が切り替わります。
処理される順番は "indentkeys" -> "indentkeys+" -> "indentkeys-" のよう
になっています。値が文字列以外の場合は 'indentkeys' 及び 'cinkeys' の
値を変更しません。
Default values
* add
- char : 0
- line : 0
- block: 0
* replace
- char : 0
- line : 0
- block: 0
regex
もしこのオプションの値が真なら "buns" は正規表現だとみなされます。また
このオプションが真の場合は文字列を囲む/囲みを置換するオペレータでの挿
入文字列には使用されなくなります。削除する文字列の検索にのみ使われます
>
let g:sandwich#recipes += [
\ {'buns': ['\d\+', '\d\+'], 'regex': 1}
\ ]
" Press <Plug>(operator-sandwich-delete)iw
" 123foo456 ---> foo
<
デフォルト値
* delete
- char : 0
- line : 0
- block: 0
* replace
- char : 0
- line : 0
- block: 0
skip_char
もしこのオプションの値が真なら登録された囲みを見つけるまで指定範囲の両
端を縮小します。
>
let g:sandwich#recipes += [
\ {'buns': ['(', ')'], 'skip_char': 1}
\ ]
" Press V<Plug>(operator-sandwich-delete)
" foo(bar)baz ---> foobarbaz
<
デフォルト値
* delete
- char : 0
- line : 0
- block: 0
* replace
- char : 0
- line : 0
- block: 0
Global option~
いくつか基本的な動作を制御するためのオプションが存在します。
g:operator#sandwich#timeout *g:operator#sandwich#timeout*
このオプションに偽値が設定されている場合、オペレータは一つのレシピを指
定する完全な入力がなされるまで待ちます。例えば、下記のレシピを用意しま
>
let g:sandwich#recipes = [
\ {'buns': ['for {', '}'], 'nesting': 1, 'input': ['bf']}
\ {'buns': ['if {', '}'], 'nesting': 1, 'input': ['bi']}
\ {'buns': ['else {', '}'], 'nesting': 1, 'input': ['be']}
\ ]
<
このオプションが真の場合は `saiwb` とタイプして少し待つと、オペレータ
はタイムアウトのため単語を `b` で囲みます。しかし、偽の場合は一つのレ
シピを指定する入力が完成するまで待ちます。この変数が定義されていなけれ
ば |g:sandwich#timeout| が代わりに参照されます。特別な理由がなければ
|g:sandwich#timeout| を使ってください。
関連:|g:operator#sandwich#timeoutlen|
g:operator#sandwich#timeoutlen *g:operator#sandwich#timeoutlen*
入力に前方一致で重複するレシピが存在する場合に次のキーシーケンスを待つ
時間をミリ秒単位で指定します。
>
let g:sandwich#recipes = [
\ {'buns': ['(', ')']}
\ {'buns': ['((', '))']}
\ ]
<
saiw( とキー入力するとオペレータは次に ( が入力されるかこの時間だけ待
ちます。この間にもう一度 ( を押下すると '((' と '))' のレシピが使われ
るでしょう。キーの押下なしでこの時間が過ぎると '(' と ')' のレシピが使
われるでしょう。この変数が存在しなければ |g:sandwich#timeoutlen| が代
わりに参照されます。特別な理由がなければ |g:sandwich#timeoutlen| を
使ってください。
タイムアウト機能(|g:operator#sandwich#timeout|, |g:sandwich#timeout|,
'timeout')がオフの場合はこのオプションは無視されます。
*g:operator#sandwich#highlight_duration*
g:operator#sandwich#highlight_duration
オペレータにおける編集後にハイライトが持続する時間をミリ秒単位で指定し
ます。デフォルト値は 200 です。
NOTE: このオプションは近々廃止される予定です。代わりに local option の
"hi_duration" をご使用ください。
*g:operator#sandwich#persistent_highlight*
g:operator#sandwich#persistent_highlight
囲みを追加/置換するオペレータの編集後のハイライトの方法を指定します。
どちらの場合も一定時間 (|g:operator#sandwich#highlight_duration| に指
定された時間) の間ハイライトが持続します。このオプションに "blink" が
指定されれば、ハイライトはユーザーの入力によりただちに中止されるでしょ
う。 "glow" が指定されれば、ユーザーがテキストを編集するまで中止されま
せん。デフォルト値は "glow" です。
NOTE: 囲みを外すオペレータは "blink" の挙動で固定されています。
NOTE: |g:operator#sandwich#highlight_duration| が小さい場合は二つの選
択肢にほとんど違いは見られないでしょう。
==============================================================================
HIGHLIGHT GROUP *operator-sandwich-highlight-group*
三つのオペレータすべてが何らかのハイライト機能を持っています。そのオンオフの切
り替えは local option の highlight によって切り替えられますが、その色について
は独自のハイライトグループによって管理されます。
OperatorSandwichBuns *hl-OperatorSandwichBuns*
このハイライトグループによってオペレータのハイライト色を宣言します。
このグループは "highlight" オプションが 1 のときに使われます。
デフォルトでは IncSearch |hl-IncSearch| グループにリンクしています。
OperatorSandwichChange *hl-OperatorSandwichChange*
このハイライトグループによってオペレータのハイライト色を宣言します。
このグループは "highlight" オプションが 2 以上のときに、囲みを追加する
オペレーターで囲まれる文字列に使われます。
デフォルトでは DiffChange |hl-DiffChange| グループにリンクしています。
OperatorSandwichDelete *hl-OperatorSandwichDelete*
このハイライトグループによってオペレータのハイライト色を宣言します。
このグループは "highlight" オプションが 2 以上のときに、囲みを
削除/置換するオペレーターで削除される囲み文字列に使われます。
デフォルトでは DiffDelete |hl-DiffDelete| グループにリンクしています。
OperatorSandwichAdd *hl-OperatorSandwichAdd*
このハイライトグループによってオペレータのハイライト色を宣言します。
このグループは "highlight" オプションが 3 以上のときに、囲みを
追加/置換するオペレーターで追加される囲み文字列に使われます。
デフォルトでは DiffAdd |hl-DiffAdd| グループにリンクしています。
ユーザーはこれらを自由に変更できます。
>
" Example 1
highlight link OperatorSandwichBuns Visual
" Example 2
highlight OperatorSandwichBuns ctermfg=White ctermbg=Red
\ guifg=White guibg=Red
<
==============================================================================
AUTOCOMMAND *operator-sandwich-autocommands*
ユーザーは |:autocmd| によってオペレータの動作前と後に処理をフックできます。そ
れぞれのオペレータは独自の |User| オートコマンドイベントを持っているのでこれを
使いオートコマンドを設定するとよいでしょう。
文字列を囲むオペレータ~
OperatorSandwichAddPre *OperatorSandwichAddPre*
文字列を囲むオペレータの処理前に実行されます。
OperatorSandwichAddPost *OperatorSandwichAddPost*
文字列を囲むオペレータの処理後に実行されます。
囲みを外すオペレータ~
OperatorSandwichDeletePre *OperatorSandwichDeletePre*
囲みを外すオペレータの処理前に実行されます。
OperatorSandwichDeletePost *OperatorSandwichDeletePost*
囲みを外すオペレータの処理後に実行されます。
囲みを置換するオペレータ~
OperatorSandwichReplacePre *OperatorSandwichReplacePre*
囲みを置換するオペレータの処理前に実行されます。
OperatorSandwichReplacePost *OperatorSandwichReplacePost*
囲みを置換するオペレータの処理後に実行されます。
実用例~
下記の例は Vim のデフォルトプラグイン matchit.vim のハイライトをオペレータ処理
中のみ抑制します。
>
autocmd User OperatorSandwichAddPre,OperatorSandwichReplacePre NoMatchParen
autocmd User OperatorSandwichAddPost,OperatorSandwichReplacePost DoMatchParen
<
==============================================================================
API *operator-sandwich-api*
|operator-sandwich| はいくつかの関数を API として提供します。これらの関数は
"expr" オプション付きの設定を便利にするのに役立つことでしょう。
operator#sandwich#get_info({info}) *operator#sandwich#get_info()*
現在のオペレーターの情報を返します。有効な {info} は次です。
`state`: |.| リピート時には 0 です。それ以外は 1 です。
`kind` : オペレーターの種類です。
"add", "delete", "replace" のどれかが返ります。
`count`: オペレーターに与えられた [count] です。
`mode` : オペレーターの使用されたモードを表す一文字です。ノーマル
モードなら "n" が、ビジュアルモードなら "x" です。
`motionwise`:
編集する領域の種類。 "char", "line", "block" または空文字
列 "" が返りうる。
operator#sandwich#kind() *operator#sandwich#kind()*
オペレーター待機モード |operator-pending-mode| において使用された場合
に、使用される予定の |operator-sandwich| オペレーターの名前を返しま
す。つまり "add", "delete", "replace" が返ります。それ以外の場合には空
文字が返ります。他のオペレーターを使用した場合にも空文字を返します。
|textobj-sandwich| との連携に便利かもしれません。
*operator#sandwich#show()*
operator#sandwich#show([{place}[, {group}[, {forcibly}]]])
この関数はテキストをハイライトするのに使います。ハイライトするテキスト
は {place} によって指定され、次の値が指定可能です。
`target`: 置換オペレーターにより置換の対象となるテキスト
`stuff` : 囲みを追加するオペレーターにより囲まれるテキスト
`added` : 囲みを追加/置換するオペレーターにより追加されたテキスト
{place} が省略された場合、 囲みを追加するオペレーターには `stuff` を、
削除/置換するオペレータには `target` を使います。
{group} が与えられた場合、テキストはこのハイライトグループ
|highlight-groups| によりハイライトされます。テキストが既にハイライト
されている場合は {group} が現在の値と違う場合のみ更新しますが、そうで
なければ何もせず終了します。ハイライトの追加あるいは更新に成功した
場合、関数は 0 を返します。それ以外の場合は 1 を返します。
もし、 {forcibly} が与えられ真の場合、この関数は "highlight"
オプションに関わらずテキストのハイライトを実行します。
*operator#sandwich#quench()*
operator#sandwich#quench([{place}])
|operator#sandwich#show()| 関数によるハイライトを削除します。 {place}
には |operator#sandwich#show()| に与えたものと同じ値を指定してくだ
さい。 {place} が省略された場合、 囲みを追加するオペレーターには
`stuff` を、削除/置換するオペレータには `target` を使います。
削除に成功すれば 0 、それ以外の場合は 1 を返します。
例えば、 query1st 系列のキーマッピング
|<Plug>(operator-sandwich-add-query1st)| は、その囲むテキストをハイライトしま
せん。しかし、ユーザーに入力を促すような "expr" 設定を使った場合、ハイライトが
行われると見栄えがよくなる場合があります。下記の例はユーザーに関数名を問い合わ
せ、その関数で囲むような新しいキーマッピングを定義しています。
>
nmap sf <Plug>(operator-sandwich-add-query1st)<C-f>
xmap sf <Plug>(operator-sandwich-add)<C-f>
let g:operator#sandwich#recipes += [
\ {
\ 'buns': ['FuncName()', '")"'],
\ 'kind': ['add'],
\ 'action': ['add'],
\ 'expr': 1,
\ 'cursor': 'inner_tail',
\ 'input': ["\<C-f>"]
\ },
\ ]
function! FuncName() abort
call operator#sandwich#show('stuff')
let funcname = input('funcname: ')
call operator#sandwich#quench('stuff')
if funcname ==# ''
throw 'OperatorSandwichCancel'
endif
return funcname . '('
endfunction
<
この新しいオペレータキーマッピング `sf` は `sfiwfunc<CR>` という入力により
"foo" を "func(foo)" にします。
==============================================================================
MISCELLANEOUS *operator-sandwich-miscellaneous*
囲みを外すオペレータのハイライトはいらない~
そうですね。次の行を vimrc へ追記しましょう。
>
call operator#sandwich#set('delete', 'all', 'highlight', 0)
<
ハイライトは全部いらない~
かもしれませんね。次の行を vimrc へ追記しましょう。
>
call operator#sandwich#set('all', 'all', 'highlight', 0)
<
matchit.vim のハイライトがかぶって邪魔~
|:autocmd| を使って一時的に抑制しましょう。
|operator-sandwich-autocommands| をご参照ください。
>
autocmd User OperatorSandwichAddPre,OperatorSandwichReplacePre NoMatchParen
autocmd User OperatorSandwichAddPost,OperatorSandwichReplacePost DoMatchParen
<
あるいは単にはっきりと違う色を使うのもいいですね。
|operator-sandwich-highlight-group| の項をご覧ください。
>
highlight OperatorSandwichBuns ctermfg=White ctermbg=Red
\ guifg=White guibg=Red
<
文字列を囲むオペレータの文字指向の場合だけ空白をスキップしないのはなぜ?~
私がたまに不便に思ったからです。端的に言うとビジュアルモードなどでスペ
ース含みで囲みたい場合があったからです。お気に召さなければ次の行を
vimrc へ追加してください。
>
call operator#sandwich#set('add', 'char', 'skip_space', 1)
<
なぜ囲みを外す/置換するオペレータのキーマッピングはデフォルトで提供されない?~
これらのオペレータの動作条件を鑑みるに、ほぼ常に |textobj-sandwich| と
組み合わせるのが便利だからです。このため単体ではなくテキストオブジェク
トとの複合マッピングがかわりに用意されます。詳しくは
|sandwich-keymappings| の項をご覧ください。また、ビジュアルモードでは
単体でマッピングされていますよ。もちろんノーマルモードでも動作条件を満
たす限り、あらゆるモーションあるいはテキストオブジェクトと組み合わせる
ことができますので興味があれば試してみてください。
|<Plug>(operator-sandwich-delete)|
|<Plug>(operator-sandwich-replace)|
ドットコマンドでもカーソル位置を保存・復元したい~
local option "cursor" の "keep" はデフォルトでは |.| コマンドリピート
では有効ではありません。しかし必要であれば、
|<Plug>(operator-sandwich-predot)| か |<Plug>(operator-sandwich-dot)|
を |.| キーにマッピングすることでこの機能を有効にすることができます。
もし他に |.| コマンドにマップするようなプラグインをご使用の場合は
|<Plug>(operator-sandwich-predot)| を使います。例えば
`<Plug>(ExampleDot)` というマッピングを |.| キーに定義するプラグインを
ご使用の場合は次のように使います。
>
nmap . <Plug>(operator-sandwich-predot)<Plug>(ExampleDot)
<
repeat.vim (vimscript #2136) をご使用の場合は `<Plug>(RepeatDot)` の
定義が遅延されているので、そのキーマッピングの存在を保証するために次の
行を vimrc へ追加します。
>
runtime autoload/repeat.vim
nmap . <Plug>(operator-sandwich-predot)<Plug>(RepeatDot)
<
上記のようなプラグインを使ってない場合は
|<Plug>(operator-sandwich-dot)| を使います。
>
nmap . <Plug>(operator-sandwich-dot)
<
|<Plug>(operator-sandwich-predot)| 及び
|<Plug>(operator-sandwich-dot)| それぞれの詳しい説明もご覧ください。
Query1st 系列のキーマッピングは何のためにある?~
Query1st 系列のキーマッピングは二つあります。
|<Plug>(operator-sandwich-add-query1st)| 及び
|<Plug>(operator-sandwich-replace-query1st)| です。これらは通常の
|<Plug>(operator-sandwich-add)| 及び
|<Plug>(operator-sandwich-replace)| とはノーマルモードでの使用時のキー
入力の順序が違います。通常のキーマッピングは
>
{operator}{motion/textobject}{addition}
<
のように {addition} の指定を最後に入力します。つまり、単語を () で囲み
たい場合 `saiw(` のように入力します。この場合、 `sa` が {operator},
`iw` が {textobject}, `(` が {addition}の指定になります。
これに対し、query1st 系列のキーマッピングは{addition} の指定が
{textobj} の前にきます。
>
{operator}{addition}{motion/textobj}
<
つまり、先の例と同等の入力は `sa(iw` になります。これは例えばより
限定的なマッピングを作るのに便利です。
>
nmap s( <Plug>(operator-sandwich-add-query1st)(
nmap s[ <Plug>(operator-sandwich-add-query1st)[
nmap s{ <Plug>(operator-sandwich-add-query1st){
" Press s(iw
" foo -> (foo)
<
Query1st 系列のキーマッピングは、範囲を指定する {motion} あるいは
{textobject} よりも前に {addition} を決定するため、いくつか制限があり
ます。
1. motionwise フィルタは実際の範囲指定にかかわらず、すべての種類
(char, line, block) について有効なレシピのみを残します。
2. highlight オプションは無視され、ハイライトは行われません。
3. 主に上記のような使用を想定しているため query_once オプションは 1 に
設定されます。これは |operator#sandwich#query1st()| 関数を使って
キーマッピングを設定しなおすことで上書きできます。
>
nmap <silent> <Plug>(operator-sandwich-add-query1st)
\ :<C-u>call operator#sandwich#query1st('add', 'n', {'query_once': 0})<CR>
nmap ssa <Plug>(operator-sandwich-add-query1st)
<
ビジュアルモードでは入力順序が変わらないので query1st 系列のキーマッピ
ングを使う必要はありません。上記の制限もあるため通常のキーマッピングを
使うことが望ましいでしょう。
>
xmap s( <Plug>(operator-sandwich-add)(
xmap s[ <Plug>(operator-sandwich-add)[
xmap s{ <Plug>(operator-sandwich-add){
<
置換オペレータにおけるレシピに指定されたオプションの扱いについて~
置換オペレータの編集には一度に二つのレシピが関係しますが、オプションの
種類によってどちらの値が使用されるかが変わります。
`cursor`
どちらのレシピでも指定できますが、挿入文字列を指定したレシピが優先され
ます。
`query_once`
挿入文字列を指定したレシピが使われます。
`regex`
置換対象文字列を指定したレシピが使われます。
`expr`
挿入文字列を指定したレシピが使われます。
`noremap`
置換対象範囲の決定には置換対象文字列を指定したレシピが、文字列の挿入に
は挿入文字列を指定したレシピが使われます。
`skip_space`
置換対象文字列を指定したレシピが使われます。
`skip_char`
置換対象文字列を指定したレシピが使われます。
`command`
両方のレシピに指定された値が有効です。挿入文字列を指定したレシピの値が
後に実行されます。
`linewise`
両方のレシピに指定された値のうち大きいほうが使われます。
`autoindent`
挿入文字列を指定したレシピが使われます。
`indentkeys`
挿入文字列を指定したレシピが使われます。
`indentkeys+`
挿入文字列を指定したレシピが使われます。
`indentkeys-`
挿入文字列を指定したレシピが使われます。
visualrepeat.vim プラグイン対応について
このプラグインは visualrepeat.vim プラグイン (vimscript #3848) に対応
しています。このプラグインを利用するうえでユーザーが特別な設定をする
必要はありません。上記のプラグインが正しくインストールされていれば、
ビジュアルモードにおいても |.| コマンドが機能するようになります。
==============================================================================
vim:tw=78:ts=8:ft=help:norl:noet: