1
Files
flake-nixinator/config/neovim/store/lazy-plugins/vim-sandwich/doc/textobj-sandwich.txt

1257 lines
38 KiB
Plaintext

*textobj-sandwich.txt* The textobject plugin to select sandwiched texts.
Last change:28-Nov-2021.
Author : machakann <mckn{at}outlook.jp>
License : NYSL license
Japanese <http://www.kmonos.net/nysl/>
English (Unofficial) <http://www.kmonos.net/nysl/index.en.html>
Requirement: Vim 7.4 or higher
|+reltime| feature (optional)
|+float| feature (optional)
==============================================================================
CONTENTS *textobj-sandwich-contents*
TL;DR
INTRODUCTION |textobj-sandwich-introduction|
KEYMAPPINGS |textobj-sandwich-keymappings|
CONFIGURATION |textobj-sandwich-configuration|
REQUISITE
buns
external
FILTERS
filetype
kind
mode
operator
LOCAL OPTIONS
nesting
expand_range
regex
skip_regex
skip_regex_head
skip_regex_tail
quoteescape
expr
noremap
syntax
inner_syntax
match_syntax
skip_breaking
skip_expr
GLOBAL OPTIONS
timeout |g:textobj#sandwich#timeout|
timeoutlen |g:textobj#sandwich#timeoutlen|
stimeoutlen |g:textobj#sandwich#stimeoutlen|
latest_jump |g:textobj#sandwich#latest_jump|
MISCELLANEOUS |textobj-sandwich-miscellaneous|
It is not what I expect with key sequence dib.
Timed out so frequently!
My cursor moved a lot because of unintended selection!
==============================================================================
TL;DR
See |sandwich-quick-start|.
==============================================================================
INTRODUCTION *textobj-sandwich-introduction*
*textobj-sandwich* is an textobject plugin to search and select sandwiched
text, like (foo) or "bar". It consists of four independent textobject
keymappings,
|<Plug>(textobj-sandwich-auto-i)|, |<Plug>(textobj-sandwich-auto-a)|,
|<Plug>(textobj-sandwich-query-i)| and |<Plug>(textobj-sandwich-query-a)|.
|<Plug>(textobj-sandwich-auto-i)| and |<Plug>(textobj-sandwich-auto-a)|
searches a sandwiched text automatically. The sets of surroundings called
"recipe"s are listed in advance. It is described in detail in
|textobj-sandwich-configuration|. |<Plug>(textobj-sandwich-auto-i)| selects
a surrounded region without surroundings. |<Plug>(textobj-sandwich-auto-a)|
selects a surrounded region including surroundings. These are mapped to
key sequences `ib` and `ab` in default.
|<Plug>(textobj-sandwich-query-i)| and |<Plug>(textobj-sandwich-query-a)|
searches a sandwiched text based on a user input. If the user input is matched
with a recipe registered, then it selects the text determined by the matched
recipe. Otherwise it selects the region surrounded by a same character input.
|<Plug>(textobj-sandwich-query-i)| selects a surrounded region without
surroundings. |<Plug>(textobj-sandwich-query-a)| selects a surrounded region
including surroundings. These are mapped to key sequences `is` and `as` in
default.
------------------------------------------------------------------------------
In visual mode, these textobjects expands the selection area by successive key
sequence as similar to |v|iw|iw|iw|....
Assume that the following text and the cursor is on foo.
>
{baz[bar(foo)bar]baz}
<
Press `vib`
>
<-> : selected region
{baz[bar(foo)bar]baz}
<
Press `ib` again
>
<---------> : selected region
{baz[bar(foo)bar]baz}
<
Press `ib` again
>
<-----------------> : selected region
{baz[bar(foo)bar]baz}
<
------------------------------------------------------------------------------
In block-wise visual mode, a target text is searched within the cursor line
and the other end follows. For example, assume the 5 by 5 text.
>
(foo)
(bar)
(baz)
<
When the cursor is on the first line, press `<C-v>2jibd`
>
()
()
()
<
Next assume that the lines like this:
>
foooo
baaar
(baz)
<
When the cursor is on the first line, press `<C-v>2jibd`
>
fo
br
()
<
==============================================================================
KEYMAPPINGS *textobj-sandwich-keymappings*
This plugin defines following keymappings. They are valid in operator-pending
mode and visual mode.
keymappings default keymappings
-----------------------------------------------------------
<Plug>(textobj-sandwich-auto-i) ib
<Plug>(textobj-sandwich-auto-a) ab
<Plug>(textobj-sandwich-query-i) is
<Plug>(textobj-sandwich-query-a) as
-----------------------------------------------------------
If you do not need default keymappings, define a variable named
g:textobj_sandwich_no_default_key_mappings in your vimrc.
>
let g:textobj_sandwich_no_default_key_mappings = 1
<
Then default mappings are never applied. And map them again as you like.
>
omap ia <Plug>(textobj-sandwich-auto-i)
xmap ia <Plug>(textobj-sandwich-auto-i)
omap aa <Plug>(textobj-sandwich-auto-a)
xmap aa <Plug>(textobj-sandwich-auto-a)
<
------------------------------------------------------------------------------
keymappings~
<Plug>(textobj-sandwich-auto-i) *<Plug>(textobj-sandwich-auto-i)*
The textobject mapping to search and select a sandwiched text
automatically. This keymapping selects inside surroundings. The
surroundings are not included. This keymapping is mapped to `ib` of
operator-pending mode and visual mode in default. This keymapping
could be mapped to operator-pending mode |:omap|, to visual mode
|:xmap|, and also to normal mode |:nmap|.
<Plug>(textobj-sandwich-auto-a) *<Plug>(textobj-sandwich-auto-a)*
The textobject mapping to search and select a sandwiched text
automatically. This keymapping selects sandwiched text including
surroundings. This keymapping is mapped to `ab` of operator-pending
mode and visual mode in default. This keymapping could be mapped to
operator-pending mode |:omap|, to visual mode |:xmap|, and also to
normal mode |:nmap|.
<Plug>(textobj-sandwich-query-i) *<Plug>(textobj-sandwich-query-i)*
The textobject mapping to search and select a sandwiched text
depending on a user input. This keymapping selects inside
surroundings. The surroundings are not included. This keymapping is
mapped to `is` of operator-pending mode and visual mode in default.
This keymapping could be mapped to operator-pending mode |:omap|, to
visual mode |:xmap|, and also to normal mode |:nmap|.
<Plug>(textobj-sandwich-query-a) *<Plug>(textobj-sandwich-query-a)*
The textobject mapping to search and select a sandwiched text
depending on a user input. This keymapping selects sandwiched text
including surroundings. This keymapping is mapped to `as` of
operator-pending mode and visual mode in default. This keymapping
could be mapped to operator-pending mode |:omap|, to visual mode
|:xmap|, and also to normal mode |:nmap|.
*<Plug>(textobj-sandwich-literal-query-i)*
<Plug>(textobj-sandwich-literal-query-i)
This textobject mapping is similar as
|<Plug>(textobj-sandwich-query-i)| but it always ignores user
settings, |g:sandwich#recipes| and |g:textobj#sandwich#recipes|. The
user input is interpreted as-is, thus the mapping selects a text
surrounded by the same characters. This keymapping could be mapped to
operator-pending mode |:omap|, to visual mode |:xmap|, and also to
normal mode |:nmap|. >
omap if <Plug>(textobj-sandwich-literal-query-i)
xmap if <Plug>(textobj-sandwich-literal-query-i)
" press difa to delete a text surrounded by 'a'.
" abcba -> aa
<
*<Plug>(textobj-sandwich-literal-query-a)*
<Plug>(textobj-sandwich-literal-query-a)
This textobject mapping is similar as
|<Plug>(textobj-sandwich-query-a)| but it always ignores user
settings, |g:sandwich#recipes| and |g:textobj#sandwich#recipes|. The
user input is interpreted as-is, thus the mapping selects a text
surrounded by the same characters. This keymapping could be mapped to
operator-pending mode |:omap|, to visual mode |:xmap|, and also to
normal mode |:nmap|. >
omap if <Plug>(textobj-sandwich-literal-query-a)
xmap if <Plug>(textobj-sandwich-literal-query-a)
" press dafb to delete a text surrounded by 'b' including 'b'.
" abcba -> aa
<
KEY MAPPING FUNCTIONS~
User can make new mappings by using function interfaces natively.
*textobj#sandwich#auto()*
textobj#sandwich#auto(mode, a_or_i[, options[, recipes]])
This function is used to make a operator key-mapping as following.
>
onoremap <silent><expr> ib textobj#sandwich#auto('o', 'i')
xnoremap <silent><expr> ib textobj#sandwich#auto('x', 'i')
onoremap <silent><expr> ab textobj#sandwich#auto('o', 'a')
xnoremap <silent><expr> ab textobj#sandwich#auto('x', 'a')
<
If a not-empty dictionary is given to the optional third argument of
this function, the local options inside the dictionary override
default option values.
>
" example 1
onoremap <silent><expr> ib
\ textobj#sandwich#auto('o', 'i', {'expand_range': 0})
" example 2
let g:sandwich_alt_options = {'expand_range': 0}
onoremap <silent><expr> ib
\ textobj#sandwich#auto('o', 'i', g:sandwich_alt_options)
<
If a list of recipes is given to the optional fourth argument of this
function, the key mapping use the list instead of
|g:sandwich#recipes| (|g:sandwich#default_recipes|) and
|g:textobj#sandwich#recipes| (|g:textobj#sandwich#default_recipes|).
>
" example 1
onoremap <silent><expr> ib
\ textobj#sandwich#auto('o', 'i', {}, [{'buns': ['(', ')']}])
" example 2
let g:sandwich_alt_recipes = [{'buns': ['(', ')']}]
onoremap <silent><expr> ib
\ textobj#sandwich#auto('o', 'i', {}, g:sandwich_alt_recipes)
<
*textobj#sandwich#query()*
textobj#sandwich#query(mode, a_or_i[, options[, recipes]])
This function is similar as |textobj#sandwich#auto()|, but it is
used for declaring new query series textobjects.
>
onoremap <silent><expr> is textobj#sandwich#query('o', 'i')
xnoremap <silent><expr> is textobj#sandwich#query('x', 'i')
onoremap <silent><expr> as textobj#sandwich#query('o', 'a')
xnoremap <silent><expr> as textobj#sandwich#query('x', 'a')
<
==============================================================================
CONFIGURATION *textobj-sandwich-configuration*
A set of surroundings and options for it is called "recipe". Each recipe is a
dictionary and the |list|s of recipes determines the textobject's behavior.
|g:sandwich#default_recipes| is one of the |list|s of recipes. This is shared
to be used with |operator-sandwich| since it is convenient in many cases. If
|g:sandwich#recipes| is defined by user, it is employed alternatively. The
default recipes |g:sandwich#default_recipes| can be checked by |:echo|
command.
>
:echo g:sandwich#default_recipes
<
This variable is locked usually, but it can be copied when you declare
|g:sandwich#recipes| if you need.
>
:let g:sandwich#recipes = deepcopy(g:sandwich#default_recipes)
<
The set of "(" and ")", "[" and "]", "{" and "}", "<" and ">" are registered
in default. The detailed description is in |g:sandwich#default_recipes|.
|g:textobj#sandwich#default_recipes| is another list of recipes. This is used
only by |textobj-sandwich|. If |g:textobj#sandwich#recipes| is defined, it is
employed alternatively. |g:textobj#sandwich#default_recipes| is locked as same
as |g:sandwich#default_recipes|.
g:textobj#sandwich#recipes *g:textobj#sandwich#recipes*
This is one of the lists of recipes which is referred only from
|textobj-sandwich|. If this list does not exist,
|g:textobj#sandwich#default_recipes| is used.
*b:textobj_sandwich_recipes*
If |b:textobj_sandwich_recipes| exists, it would be used instead of
|g:textobj#sandwich#recipes|. This is buffer local, thus it might be
convenient to manage too many filetype-specific recipes.
g:textobj#sandwich#default_recipes *g:textobj#sandwich#default_recipes*
This is one of the lists of recipes which is prepared in default. If
|g:textobj#sandwich#recipes| exists, it will be used alternatively.
This variable is locked usually, but it can be copied when you declare
|g:textobj#sandwich#recipes| if you need.
>
:let g:textobj#sandwich#recipes
\ = deepcopy(g:textobj#sandwich#default_recipes)
<
NOTE: If recipes are conflicted in some reason,
|g:textobj#sandwich#default_recipes| and |g:textobj#sandwich#recipes| is prior
to |g:sandwich#default_recipes| and |g:sandwich#recipes|. In a same list, a
latter item is prior to a former item.
------------------------------------------------------------------------------
A recipe is a |Dictionary| variable and it can have four kinds of
information. Requisite, input, filters and local options. The requisite is
essential for all recipe, it defines a set of surroundings. The input is a
option to assign a recipe for an action. The filters is the option to filter
recipes depending on the situation in use. The local option is utilized to
tune the behavior for each recipe. In addition to them, several global options
are employed to control fundamental behavior of the textobjects.
As a first step, define your list of recipes.
>
let g:sandwich#recipes = []
<
Or just copy the default one if you need.
>
let g:sandwich#recipes = deepcopy(g:sandwich#default_recipes)
<
Requisite~
There are two kinds of requisite, buns and external. All recipes should have
any one of the two.
buns
This is the key to assign the surroundings. Its value is a list
including two strings which will be the surroundings searched in
text. If "regex" option is true, it is regarded as regular expression.
If a recipe do not have "input" option, this is used as the assignment
input for |<Plug>(textobj-sandwich-query-i)| and
|<Plug>(textobj-sandwich-query-a)|.
>
let g:sandwich#recipes += [
\ {'buns': ['(', ')']}
\ ]
" Press dis( or dis)
" (foo) ---> ()
let g:sandwich#recipes += [
\ {'buns': ['ab', 'cd']}
\ ]
" Press disab or discd
" abfoocd ---> abcd
let g:sandwich#recipes += [
\ {'buns': ['ab', 'cd'], 'input': ['a']}
\ ]
" Press disa
" abfoocd ---> abcd
<
external
This is supplementary requisite. This is a list including two
textobjects as strings. A narrower textobject is the first item and
wider textobject is the second item. This is used when a user want to
use external textobjects as a recipe. Many local options are not
valid.
>
let g:sandwich#recipes += [
\ {'external': ['it', 'at']}
\ ]
" "it" selects the text inside tags, "at" selects including tags.
" <---it--->
" <title>title here</title>
" <----------at----------->
" Press dib
" <title>title here</title> ---> <title></title>
" Press dab
" <title>title here</title> --->
<
"noremap" option is applied for this. Since visual selection is
employed to check its region intrinsically, only the mappings in
visual mode are related to the option.
>
let g:sandwich#recipes += [
\ {'external': ['i[', 'a['], 'noremap': 0}
\ ]
" Press dib
" [foo] ---> []
xnoremap i[ i{
xnoremap a[ a{
" Press dib
" {foo} ---> {}
<
Combined with "noremap" option, user defined textobjects can be used
in the same way.
>
" "noremap" option should be false.
let g:sandwich#recipes += [
\ {
\ 'external': ["\<Plug>(textobj-sandwich-auto-i)",
\ "\<Plug>(textobj-sandwich-auto-a)"],
\ 'noremap': 0,
\ 'kind': ['query'],
\ 'input': ['b']
\ }
\ ]
<
NOTE: Registered textobjects should work correctly in visual mode.
NOTE: Not all the user defined textobjects are not guaranteed to work.
Input~
input
This is the key to assign a recipe for an searching.
|<Plug>(textobj-sandwich-query-i)| and
|<Plug>(textobj-sandwich-query-a)| ask
user to determine surroundings in an searching. At that moment, users
are asked an input to assign a recipe. This option makes the input. If
a recipe does not have the key, items in "buns" are used for the
assignment.
>
let g:sandwich#recipes += [
\ {'buns': ['"""', '"""']}
\ ]
" Press dis"""
" """foo""" ---> """"""
<
If the recipe has input key, it will be used alternatively.
>
let g:sandwich#recipes += [
\ {'buns': ['"""', '"""'], 'input': ['"']}
\ ]
" Press dis"
" """foo""" ---> """"""
<
This value should be a |list|, and multiple assignment is valid.
Filter~
filetype
This filter filters recipes by filetypes in use. It is a list of
filetypes as strings. If a recipe does not have filetype key or has a
value "all", the recipe is valid on any filetype.
>
" 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
This filter filters recipes by kinds of operator actions. It is a list
of names of kinds. "auto", "query", "textobj" and "all" can be used.
"textobj" is same as both "auto" and "query". The difference between
"textobj" and "all" is that "all" might include operator kinds in
|g:sandwich#recipes|. See |operator-sandwich-configuration|. If a
recipe does not have kind key, the recipe is valid on any kind.
>
" The following recipe is valid only with
" <Plug>(textobj-sandwich-auto-i) and <Plug>(textobj-sandwich-auto-a)
let g:sandwich#recipes += [
\ {'buns': ['"""', '"""'], 'kind': ['auto']}
\ ]
<
mode
This filter filters recipes by modes. It is a list of characters
representing modes. "o" or "x" can be used. "o" represents a use in
operator-pending mode, and "x" represents a use in visual mode. If a
recipe does not have mode key, the recipe is valid on any mode.
>
" These recipes are switch behaviors on modes with the same input.
let g:sandwich#recipes += [
\ {'buns': ['"', '"'], 'mode': ['o']}
\ {'buns': ['"""', '"""'], 'mode': ['x'], 'input': ['"']}
\ ]
<
action
This key is used to filter the recipes by the kinds of action. "add"
and "delete" is reserved for |operator-sandwich|, "all" includes the
those two kinds of action. "add" prohibits to take effect for
|textobj-sandwich| and "delete" and "all" allows it, because usually a
delete action uses those textobjects.
>
" This recipe does not take effect for textobjects
let g:sandwich#recipes += [
\ {'buns': ['"""', '"""'], 'action': ['add'], 'input': ['"']}
\ ]
" This recipe is valid for delete actions and textobjects
let g:sandwich#recipes += [
\ {'buns': ['"""', '"""'], 'action': ['delete'], 'input': ['"']}
\ ]
<
expr_filter
A user can define filters by oneself. The items of the list are
evaluated as |expression|, and if the value is true (1) then the
recipe is valid, if the value is false (0) then the recipe is invalid.
>
" 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()']}
\ ]
<
For example, the following filter makes recipes possible to be valid
only with a specific operator.
>
function! FilterOperator(operator)
return a:operator ==# v:operator ? 1 : 0
endfunction
" This recipe is valid only with d operator.
let g:sandwich#recipes += [
\ {'buns': ['(', ')'], 'expr_filter': ['FilterOperator("d")']}
\ ]
<
Local option~
Local options are used to optimize the behavior for each recipe. If any
option is set, the default value depending on kinds is used. These default
values are changed by |g:textobj#sandwich#options|.
If you want to change the default value of skip_break option of
|<Plug>(textobj-sandwich-query-i)| and |<Plug>(textobj-sandwich-query-a)|
>
let g:textobj#sandwich#options.query.skip_break = 1
<
Or use the function |textobj#sandwich#set()|.
>
call textobj#sandwich#set('query', 'skip_break', 1)
<
g:textobj#sandwich#options *g:textobj#sandwich#options*
The dictionary includes default local option values.
>
" let textobj#sandwich#options[kind][option] = {value}
" For example
let g:textobj#sandwich#options['query']['skip_break'] = 1
" or
let g:textobj#sandwich#options.query.skip_break = 1
<
*b:textobj_sandwich_options*
If |b:textobj_sandwich_options| exists, it will be used instead of
|g:textobj#sandwich#options|. It would be useful when a user wants to
use buffer-local option settings.
Available keys are listed below.
* kind
- query
- auto
* option
- nesting
- expand_range
- regex
- skip_regex
- skip_regex_head
- skip_regex_tail
- quoteescape
- expr
- noremap
- syntax
- inner_syntax
- match_syntax
- skip_break
- skip_expr
*textobj#sandwich#set()*
textobj#sandwich#set(kind, option, value)
The function to change default values of local options easily and
safely. If the combination of arguments is not appropriate, this
function shows error messages. The available arguments are listed in
|g:textobj#sandwich#options|. In addition to that, "all" is available
for kind.
*textobj#sandwich#setlocal()*
textobj#sandwich#setlocal(kind, option, value)
The function to change buffer-local default values of local options
easily and safely. If the combination of arguments is not appropriate,
this function shows error messages. The available arguments are listed
in |g:textobj#sandwich#options|. In addition to that, "all" is
available for kind.
textobj#sandwich#set_default() *textobj#sandwich#set_default()*
The function initializes all default values of local options.
nesting
This option switches the searching algorithm. If a set of "buns" makes
nested structure, this option should be 1. Otherwise it should be 0.
For example, ( and ) makes nest but " is not generally. Assume that
the cursor is on foo of the text, expected results are different
depending on whether it makes nest or not.
Yank a part of text by a key sequence `yib`.
>
# : cursor
case1: (foo(bar)baz) : foo(bar)baz is the expected result
case2: "foo"bar"baz" : foo is the expected result
<
This option is desirable to set on every recipes.
Default values
* query: 0
* auto : 0
expand_range
If this option is 0, surroundings are searched within the cursor line.
If this option is a positive integer, the searched range is expanded
by the number of lines. If this option is a negative integer, whole
buffer is taken as the searched range.
NOTE: Intrinsically, it is not searched a wide range at a time.
The searching lines are expanded step-by-step with monitoring
the elapsed time and a certain time
|g:textobj#sandwich#stimeoutlen| is elapsed without finding
[count] number of candidate, the searching process would time
out.
In many cases, 0 or a negative number would be a good choice.
Default values
* query: -1
* auto : -1
regex
If this option is true, requisite "buns" is regarded as regular
expressions.
>
let g:sandwich#recipes += [
\ {'buns': ['\d\+', '\d\+'], 'regex': 1}
\ ]
" Press dib
" 123foo456 ---> 123456
<
NOTE: If this option is true, the recipe requires "input" to use with
query-textobjects. "buns" never be regarded as key inputs to
trigger.
Default values
* query: 0
* auto : 0
skip_regex
skip_regex_head
skip_regex_tail
These are lists of regular expressions to skip candidate positions in
searching. When the textobjects searches a target text, even though a
text matched with "buns", if the text also matched with an item in
these lists then it will be skipped. The regular expression have to
matched with the head of a skipped text.
>
let g:sandwich#recipes += [
\ {'buns': ['b', 'a'], 'skip_regex': ['a\zea']}
\ ]
" Press dib
" baaaaaaaar ---> bar
<
Items in "skip_regex" are checked both in searching head and tail
buns. Usually this is enough helpful, but if head, tail and escape
character are all same, it might be a problem. For instance,
successive two quotes, '', inside a quote wrapped string literal is
regarded as a quote in Vim script.
>
:echo '''foo bar''' " -> 'foo bar'
<
To skip the successive quotes, searching head and tail are required to
be distinguished. Use "skip_regex_head", "skip_regex_tail".
>
let g:sandwich#recipes += [
\ {
\ 'buns': ["'", "'"],
\ 'filetype': ['vim'],
\ 'expand_range': 0,
\ 'skip_regex_head':
\ ['\%(\%#\zs''\|''\%#\zs\)''\%(''''\)*[^'']'],
\ 'skip_regex_tail':
\ ['[^'']\%(''''\)*\%(\%#\zs''\|''\%#\zs\)'''],
\ 'nesting': 0
\ 'match_syntax': 2,
\ }
\ ]
<
NOTE: This is still not perfect. If cursor is on ended successive
single quotes, it does not work as expected.
>
### ### : Cursor should not be on
'''foo '' bar''' : the positions pointed by #.
<
Cursor is moving in searching positions, thus user can use the pattern
\%# |/\%#|.
Default values
* query: []
* auto : []
quoteescape
If this option is true, skip candidate positions escaped by characters
included in 'quoteescape' option. Practically this option is specific
for ', " and `.
>
let g:sandwich#recipes += [
\ {'buns': ['"', '"'], 'quoteescape': 1}
\ ]
" Press dib
" "foo\"bar" ---> foo\"bar
<
Default values
* query: 0
* auto : 0
expr
If this option is 1 or 2, requisite "buns" is evaluated as expression.
If this option is 1, "buns" are evaluated once and repeat it by |.|
command. If this option is 2, "buns" are evaluated every times in |.|
repeating. For example, the following recipe searches the text in the
unnamed register. (ref. |:let-@|, |quotequote|)
>
let g:sandwich#recipes += [
\ {'buns': ['@@', '@@'], 'expr': 1, 'input': ['@']}
\ ]
<
NOTE: If this option is true, the recipe requires "input" to use with
query-textobjects. "buns" never be regarded as key inputs to
trigger.
NOTE: If "buns" include empty string resulting of the evaluation,
|textobj-sandwich| cancels the selection.
NOTE: If the expressions query user something by |getchar()| or
|input()|, the recipe may cause problem on the
|operator-sandwich| delete operator and |textobj-sandwich|
textobjects, |<Plug>(textobj-sandwich-auto-i)| and
|<Plug>(textobj-sandwich-auto-a)|. To avoid this problem, it is
recommended to use "kind" filter. For example, the following
recipe asks two characters to select a text between the two
characters.
>
let g:textobj#sandwich#recipes += [
\ {
\ 'buns': ['GetChar()', 'GetChar()'],
\ 'kind': ['query'],
\ 'expr': 1,
\ 'input': ['f']
\ },
\ ]
function! GetChar() abort
let c = getchar()
let c = type(c) == type(0) ? nr2char(c) : c
return c ==# "\<Esc>" || c ==# "\<C-c>" ? '' : c
endfunction
<
Default values
* query: 0
* auto : 0
noremap
This option is referred only with "external" textobjects. In case that
a "external" textobject has been remapped, if this option is true it
would not be remapped. If this option is false, the nest mapping would
be expanded. Also see the description about "external" in requisite.
NOTE: Since visual selection is employed to check its region
intrinsically, only the mappings in visual mode are related.
Default values
* query: 1
* auto : 1
syntax
This is a list of syntax groups expected to be applied to the
surroundings. If this list is not empty, the textobjects check the
syntax to skip candidates. If syntax highlighting is not active, this
option is simply ignored.
>
" check the position pointed by #
" # #
" "foo"
<
For example, " is expected to be highlighted by several limited
highlight groups.
>
let g:sandwich#recipes += [
\ {
\ 'buns': ['"', '"'],
\ 'quoteescape': 1,
\ 'expand_range': 0,
\ 'nesting': 0,
\ 'match_syntax': 1,
\ 'syntax':
\ ['Constant', 'Statement', 'Special', 'String', 'Comment'],
\ 'inner_syntax':
\ ['Constant', 'PreProc', 'Special', 'String', 'Comment'],
\ }
\ ]
<
However the recipe is not useful for some filetype, for example
markdown, while it really goes well with some filetypes to recognize
strings surrounded by "" even in the following situation.
>
key press vas" selects as following. # means cursor positions.
<-#->
list = ["foo", "bar"]
<-----#------>
<
Therefore, if possible, it would be better to prepare recipes for each
filetypes.
>
let g:sandwich#recipes += [
\ {
\ 'buns': ['"', '"'],
\ 'filetype': ['ruby'],
\ 'quoteescape': 1,
\ 'expand_range': 0,
\ 'nesting': 0,
\ 'match_syntax': 1,
\ 'syntax':
\ ['Constant', 'Special', 'String', 'Comment'],
\ 'inner_syntax':
\ ['Constant', 'Special', 'String', 'Comment'],
\ }
\ ]
let g:sandwich#recipes += [
\ {
\ 'buns': ['"', '"'],
\ 'filetype': ['sh'],
\ 'quoteescape': 1,
\ 'expand_range': 0,
\ 'nesting': 0,
\ 'match_syntax': 1,
\ 'syntax':
\ ['Constant', 'Statement', 'String', 'Comment'],
\ 'inner_syntax':
\ ['Constant', 'Special', 'PreProc', 'String', 'Comment'],
\ }
\ ]
<
In many colorscheme, frequently used highlight group name is shared.
See |group-name|.
NOTE: If an item in the list exists in the syntax stack at the
candidate, it is regarded as the matched. The syntax stack can
be checked by using following keymapping on a text.
>
nnoremap <Leader>s :echo map(synstack(line('.'), col('.')),
\ 'synIDattr(synIDtrans(v:val), "name")')<CR>
<
Default values
* query: []
* auto : []
inner_syntax
This is a list of syntax groups expected to be applied to the
both edges of a surrounded text. If this list is not empty, the
textobjects check the syntax to skip candidates. If syntax
highlighting is not active, this option is simply ignored.
In addition, also when "match_syntax" option is 2, this option is
ignored.
>
let g:sandwich#recipes += [
\ {
\ 'buns': ['"', '"'],
\ 'quoteescape': 1,
\ 'inner_syntax': ['Constant', 'String']
\ }
\ ]
" check the position pointed by #
" # #
" "foo"
<
There are practical examples in the above, local option "syntax",
section. Please see also them.
In many colorscheme, frequently used highlight group name is shared.
See |group-name|.
NOTE: If an item in the list exists in the syntax stack at the
candidate, it is regarded as the matched. The syntax stack can
be checked by using following keymapping on a text.
>
nnoremap <Leader>s :echo map(synstack(line('.'), col('.')),
\ 'synIDattr(synIDtrans(v:val), "name")')<CR>
<
Default values
* query: []
* auto : []
match_syntax
If this option is 1, the textobjects check the both surroundings
whether their syntaxes are matched or not. If not, the candidate is
skipped. In addition to that, if this option is 2, the textobjects
also check the both edge of the surrounded text whether their
colorings are same as those of surroundings. If this option is 3,
almost same as that is 3 but textobjects check the inside text
independently. That is to say, both surroundings should be same
colorings and both edge of surrounded text should be same colorings,
but it is not required to be same the colorings of surroundings and
that of the surrounded text.
>
AB CD
(foo)
match_syntax is 1: A == D is required.
match_syntax is 2: A == D == B == C is required.
match_syntax is 3: A == D and B == C is required.
<
If a surrounding is not a character, textobjects check its head only.
In many cases, both sides of surroundings have same syntaxes. For
example, '' is frequently used for the string literal, "" itself would
be applied Constant or String syntax and the inside text also applied
the same.
>
let g:sandwich#recipes += [
\ {
\ 'buns': ["'", "'"],
\ 'quoteescape' : 1,
\ 'syntax' : ['Constant', 'String'],
\ 'match_syntax': 2
\ }
\ ]
<
There are also other examples in the section of local option "syntax".
NOTE: The applied (displayed) syntax can be checked by using the
following keymapping on a text.
>
nnoremap <Leader>S
\ :echo synIDattr(synIDtrans(synID(line('.'), col('.'), 1)), 'name')<CR>
<
The displayed syntaxes of both surroundings should be matched to
be valid. However, as for the case of insides the surroundings
the matched condition is somehow relaxed, only have to be
included in syntax stacks. Because, for instance, output
conversion specifiers in string literal like "%s" is highlighted
with different color. Even though the fact, "String" is expect
to included in its syntax stack, if it is true it works same as
other string literals. A syntax stack can be checked by using
the following key mapping on a text.
>
nnoremap <Leader>s :echo map(synstack(line('.'), col('.')),
\ 'synIDattr(synIDtrans(v:val), "name")')<CR>
<
Default values
* query: 0
* auto : 0
skip_break
Assume that the following text.
>
{
foo
}
<
The strings surrounded by { and } is "\n foo\n", thus key sequence
dib should simply give:
>
{}
<
However sometimes it is more useful to make like this.
>
{
}
<
If this option is true, the textobjects skip the breakings at the both
ends to make the latter situation. In addition, skip following spaces
together to keep indentation. That is to say, skipped string would be
a string matched with the pattern "\n\\s*".
This option is valid only for |<Plug>(textobj-sandwich-query-i)| and
|<Plug>(textobj-sandwich-auto-i)|.
Default values
* query: 0
* auto : 0
skip_expr
The value is a list of |expression|s. Searching the selection area,
every time when a text matched with buns is found the expressions are
evalueated. If the expression returns true (not 0), then the candidate
is skipped and textobject searches next.
>
" skip 'a's other than head and tail of a line.
let g:sandwich#recipes += [
\ {
\ 'buns': ['a', 'a'],
\ 'skip_expr': [
\ 'getpos(".")[2] != 1 && getpos(".")[2] != col([getpos(".")[1], "$"])-1'
\ ]
\ }
\ ]
" Press dib
" aaaaa ---> aa
<
Note that if the item is |Funcref|, it should be possible to accept
two arguments.
>
:function {func}(is_head, pos)
<
If a:is_head is 1, the textobject is searching a head surrounding
matched with buns. Otherwise the textobject is searching a tail
surrounding matched with buns. a:pos is a list pointing the head of
matched position. It has four items which is same format with the
argument of |getpos()|. Not necessarily to use them, use if needed.
In future, the arguments are possible to append. Thus it might be
better to assign variable-length argument.
>
" skip 'a's other than head and tail of a line.
function! SkipIntermediates(is_head, pos, ...)
if a:is_head
return a:pos[2] != 1
else
return a:pos[2] != col([a:pos[1], '$'])-1
endif
endfunction
let g:sandwich#recipes += [
\ {
\ 'buns': ['a', 'a'],
\ 'skip_expr': [function('SkipIntermediates')]
\ }
\ ]
" Press dib
" aaaaa ---> aa
<
Default values
* query: []
* auto : []
Global option~
There are several options to control fundamental behavior of the operators.
g:textobj#sandwich#timeout *g:textobj#sandwich#timeout*
If this option is a falsy value, the query-textobject will wait for
subsequent inputs until the complete key sequence has been received to
specify a recipe. For example, with the following recipes,
>
let g:sandwich#recipes = [
\ {'buns': ['for {', '}'], 'nesting': 1, 'input': ['bf']}
\ {'buns': ['if {', '}'], 'nesting': 1, 'input': ['bi']}
\ {'buns': ['else {', '}'], 'nesting': 1, 'input': ['be']}
\ ]
<
type `visb` and a while later the textobject eagerly select a text
wrapped in `b` if this option is true. The textobject wait next input
until a recipe is specified if this option is false. If this has not
been defined, |g:sandwich#timeout| is used instead. Unless there is
any particular reason, use |g:sandwich#timeout|.
See |g:textobj#sandwich#timeoutlen| also.
g:textobj#sandwich#timeoutlen *g:textobj#sandwich#timeoutlen*
The time in milli seconds that waits for a key code or mapped key
sequence to complete. If there are recipes overlapped, this option is
used. Assume that the following recipes are prepared:
>
let g:sandwich#recipes = [
\ {'buns': ['(', ')']}
\ {'buns': ['((', '))']}
\ ]
<
after pressing vis(, the textobject waits in the time. If you press
one more ( in the time, then a recipe for '((' and '))' is decided to
use. No keypress has come through the time a recipe for '(' and ')' is
settled. If this has not been defined, |g:sandwich#timeoutlen| is used
instead. Unless there is any particular reason, use
|g:sandwich#timeoutlen|.
When 'timeout' is off or |g:textobj#sandwich#timeout| is false, this
option is ignored.
g:textobj#sandwich#stimeoutlen *g:textobj#sandwich#stimeoutlen*
This is the time in milli second to give up searching candidates.
After passing over the time without finding enough number of
candidates, then the textobjects give up searching and selection. The
default value is 500.
g:textobj#sandwich#latest_jump *g:textobj#sandwich#latest_jump*
If the value is true, the textobjects record the original cursor
position to the latest jump marker |``|. If the cursor moved
unexpectedly, |``| command will restore the cursor position quickly.
The default value is 1.
==============================================================================
MISCELLANEOUS *textobj-sandwich-miscellaneous*
It is not what I expect with key sequence dib.~
The key sequence `dib` will make this:
>
(
foo
)
<
to this:
>
()
<
Because the surrouded text is not ' foo' but '\n foo\n'. If you
want a result like this:
>
(
)
<
then you can control by local option "skip_break".
>
call textobj#sandwich#set('all', 'skip_break', 1)
<
Timed out so frequently!~
Set the |g:textobj#sandwich#stimeoutlen| larger. The default value is
500.
My cursor moved a lot because of unintended selection!~
Don't panic. You can use undo |u| command, and you can go back to the
original position by |``| command. See
|g:textobj#sandwich#latest_jump|.
==============================================================================
vim:tw=78:ts=8:ft=help:norl:noet: