Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Divide parentheses into kinds so as to match languages with complex parentheses syntax #175

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ let g:rainbow_conf = {
- 'ctermfgs': a list of `ctermfg` (`:h highlight-ctermfg`)
- 'cterms': a list of `cterm` (`:h highlight-cterm`)
- 'operators': describe the operators you want to highlight (note: be careful about special characters which needs escaping, you can find more examples [here](https://github.com/luochen1990/rainbow/issues/3), and you can also read the [vim help about syn-pattern](http://vimdoc.sourceforge.net/htmldoc/syntax.html#:syn-pattern)). note that this option will be overwritten by the `step` part of `parentheses`.
- 'parentheses': a list of parentheses definitions, a parentheses definition contains parts like `start=/(/`, `step=/,/`, `stop=/)/`, `fold`, `contained`, `containedin=someSynNames`, `contains=@Spell`, see `:h syntax` for more details. notice that the `step` part is defined by this plugin so it is not described by the official vim doc.
- 'parentheses': a list of parentheses definitions, a parentheses definition contains parts like `start=/(/`, `step=/,/`, `stop=/)/`, `fold`, `contained`, `containedin=someSynNames`, `contains=@Spell`, `kind=someNames`, `upkind=someKindNames,`, see `:h syntax` for more details. notice that the `step`, `kind` and `upkind` part is defined by this plugin so it is not described by the official vim doc; where `step` represents the operators need to be highlighted alone with the parentheses; `kind` works like `cluster` in vim `syntax` system, but it's specified separately by each parenthesis definition, with a list of kind names separated by `,`, the default kind is `''`(empty string), and can be specified explicitly by prepending or appending a single comma to the kind list; `upkind` has similar syntax as `kind`, and works like `containedin`, the kind of the parenthesis would always be included.
- 'parentheses_options': parentheses options shared between different parentheses, things like `containedin=xxxFuncBody`, `contains=@Spell` (or 'contains=@NoSpell') often appears here. this option is often used to solve [3rd-party-plugin-compatibility]() problems.
- 'separately': configure for specific filetypes (decided by &ft), key `*` for filetypes without separate configuration, value `0` means disable rainbow only for this type of files, value `"default"` means keep the default shim for this filetype (notice: the default shim config will change between plugin version).
- 'syn_name_prefix': add a prefix to name of the syntax definition, this option is often used to solve [3rd-party-plugin-compatibility]() problems.
Expand Down Expand Up @@ -184,6 +184,6 @@ nnoremap <f4> :exec 'syn list '.synIDattr(synID(line('.'), col('.'), 0), 'name')
Move your cursor to a parentheses and press the keys to use them.

------------------------------------------------------------------
**Rate this script if you like it, and I'll appreciate it and improve this plugin for you because of your support!
**Rate this script if you like it, and I'll appreciate it and improve this plugin for you because of your support!**

Just go to [this page](http://www.vim.org/scripts/script.php?script_id=4176) and choose `Life Changing` and click `rate`**
**Just go to [this page](http://www.vim.org/scripts/script.php?script_id=4176) and choose `Life Changing` and click `rate`**
4 changes: 2 additions & 2 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ let g:rainbow_active = 1 "0 if you want to enable it later via :RainbowToggle
- 'guis': 一个`gui`的列表 (`:h highlight-gui`), 将按顺序循环使用
- 'ctermfgs': 一个`ctermfg`的列表 (`:h highlight-ctermfg`), 即终端下的括号颜色
- 'cterms': 一个`cterm`的列表 (`:h highlight-cterm`)
- 'operators': 描述你希望哪些运算符跟着与它同级的括号一起高亮(注意:留意需要转义的特殊字符,更多样例见[这里](https://github.com/luochen1990/rainbow/issues/3), 你也可以读[vim帮助 :syn-pattern](http://vimdoc.sourceforge.net/htmldoc/syntax.html#:syn-pattern))
- 'parentheses': 一个关于括号定义的列表, 每一个括号的定义包含形如以下的部分: `start=/(/`, `step=/,/`, `stop=/)/`, `fold`, `contained`, `containedin=someSynNames`, `contains=@Spell`. 各个部分具体含义可参考 `:h syntax`, 其中 `step` 为本插件的扩展定义, 表示括号中间需要高亮的运算符.
- 'operators': 描述你希望哪些运算符跟着与它同级的括号一起高亮.(注意:留意需要转义的特殊字符,更多样例见[这里](https://github.com/luochen1990/rainbow/issues/3), 你也可以读[vim帮助 :syn-pattern](http://vimdoc.sourceforge.net/htmldoc/syntax.html#:syn-pattern)) 另外, `parentheses`设置下的`step`部分会覆盖这项设置
- 'parentheses': 一个关于括号定义的列表, 每一个括号的定义包含形如以下的部分: `start=/(/`, `step=/,/`, `stop=/)/`, `fold`, `contained`, `containedin=someSynNames`, `contains=@Spell`, `kind=someNames`, `upkind=someKindNames`. 各个部分具体含义可参考 `:h syntax`, 其中 `step`, `kind` 和 `upkind` 为本插件的扩展定义; `step`表示括号中间需要高亮的运算符; `kind`类似于vim的`cluster`, 但由每种括号定义分别指定, 不同的种类之间以`,`分开, 如果没有指定种类, 默认的会是`''`(空), 也可以在种类列表之前或之后加上逗号来显式指定这种括号的种类; `upkind`的语法和`kind`相似, 作用类似vim的`containedin`, 不过括号自己的种类永远会被包含在`upkind`里.
- 'separately': 针对文件类型(由&ft决定)作不同的配置,未被单独设置的文件类型使用`*`下的配置,值为`0`表示仅对该类型禁用插件,值为`"default"`表示使用针对该类型的默认兼容配置 (注意, 默认兼容配置可能随着该插件版本的更新而改变, 如果你不希望它改变, 那么你应该将它拷贝一份放到你的vimrc文件里).
- 省略某个字段以使用默认设置

Expand Down
47 changes: 31 additions & 16 deletions autoload/rainbow.vim
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fun s:concat(strs)
endfun

fun s:resolve_parenthesis_with(init_state, p)
let [paren, contained, containedin, contains_prefix, contains, op] = a:init_state
let [paren, contained, containedin, contains_prefix, contains, op, kind, upkind] = a:init_state
let p = (type(a:p) == type([])) ? ((len(a:p) == 3) ? printf('start=#%s# step=%s end=#%s#', a:p[0], op, a:p[-1]) : printf('start=#%s# end=#%s#', a:p[0], a:p[-1])) : a:p "NOTE: preprocess the old style parentheses config

let ls = split(p, '\v%(%(start|step|end)\=(.)%(\1@!.)*\1[^ ]*|\w+%(\=[^ ]*)?) ?\zs', 0)
Expand All @@ -27,25 +27,29 @@ fun s:resolve_parenthesis_with(init_state, p)
let containedin = s:concat([containedin, s:trim(v)])
elseif k == 'contained'
let contained = 1
elseif k == 'kind'
let kind = s:trim(v)
elseif k == 'upkind'
let upkind = s:trim(v)
else
let paren .= s
endif
endfor
let rst = [paren, contained, containedin, contains_prefix, contains, op]
let rst = [paren, contained, containedin, contains_prefix, contains, op, kind, upkind]
"echom json_encode(rst)
return rst
endfun

fun s:resolve_parenthesis_from_config(config)
return s:resolve_parenthesis_with(['', 0, '', a:config.contains_prefix, '', a:config.operators], a:config.parentheses_options)
return s:resolve_parenthesis_with(['', 0, '', a:config.contains_prefix, '', a:config.operators, '', ''], a:config.parentheses_options)
endfun

fun s:synID(prefix, group, lv, id)
return a:prefix.'_lv'.a:lv.'_'.a:group.a:id
endfun

fun s:synGroupID(prefix, group, lv)
return a:prefix.a:group.'_lv'.a:lv
fun s:synGroupID(prefix, group, lv, kind)
return a:prefix.a:group.'_lv'.a:lv.'_'.a:kind
endfun

fun rainbow#syn(config)
Expand All @@ -55,30 +59,41 @@ fun rainbow#syn(config)

let glob_paran_opts = s:resolve_parenthesis_from_config(conf)
let b:rainbow_loaded = cycle
let kindlist = {}
for id in range(len(conf.parentheses))
let [paren, contained, containedin, contains_prefix, contains, op] = s:resolve_parenthesis_with(glob_paran_opts, conf.parentheses[id])
let [paren, contained, containedin, contains_prefix, contains, op, kind, upkind] = s:resolve_parenthesis_with(glob_paran_opts, conf.parentheses[id])
let kind = kind == '' ? [''] : split(kind, ',', 1)->uniq()
let upkind = (upkind == '' ? [] : split(upkind, ',', 1))->extend(kind)->uniq()
for k in kind
if !has_key(kindlist, k)
let kindlist[k] = []
endif
call add(kindlist[k], id)
endfor
for lv in range(cycle)
let lv2 = ((lv + cycle - 1) % cycle)
let [rid, pid, gid2] = [s:synID(prefix, 'r', lv, id), s:synID(prefix, 'p', lv, id), s:synGroupID(prefix, 'Regions', lv2)]
let uplv = ((lv + cycle - 1) % cycle)
let [rid, pid, upid] = [s:synID(prefix, 'r', lv, id), s:synID(prefix, 'p', lv, id), upkind->mapnew('"@".s:synGroupID(prefix, "Regions", uplv, v:val)')->join(',')]

if len(op) > 2
exe 'syn match '.s:synID(prefix, 'o', lv, id).' '.op.' containedin='.s:synID(prefix, 'r', lv, id).' contained'
endif

let real_contained = (lv == 0)? (contained? 'contained ' : '') : 'contained '
let real_containedin = (lv == 0)? s:concat([containedin, '@'.gid2]) : '@'.gid2
let real_containedin = (lv == 0)? s:concat([containedin, upid]) : upid
let real_contains = s:concat([contains_prefix, contains])
exe 'syn region '.rid.' matchgroup='.pid.' '.real_contained.'containedin='.real_containedin.' contains='.real_contains.' '.paren
endfor
endfor
for lv in range(cycle)
exe 'syn cluster '.s:synGroupID(prefix, 'Regions', lv).' contains='.join(map(range(len(conf.parentheses)), 's:synID(prefix, "r", lv, v:val)'), ',')
exe 'syn cluster '.s:synGroupID(prefix, 'Parentheses', lv).' contains='.join(map(range(len(conf.parentheses)), 's:synID(prefix, "p", lv, v:val)'), ',')
exe 'syn cluster '.s:synGroupID(prefix, 'Operators', lv).' contains='.join(map(range(len(conf.parentheses)), 's:synID(prefix, "o", lv, v:val)'), ',')
for [kind, ids] in items(kindlist)
for lv in range(cycle)
exe 'syn cluster '.s:synGroupID(prefix, 'Regions', lv, kind).' contains='.join(mapnew(ids, 's:synID(prefix, "r", lv, v:val)'), ',')
exe 'syn cluster '.s:synGroupID(prefix, 'Parentheses', lv, kind).' contains='.join(mapnew(ids, 's:synID(prefix, "p", lv, v:val)'), ',')
exe 'syn cluster '.s:synGroupID(prefix, 'Operators', lv, kind).' contains='.join(mapnew(ids, 's:synID(prefix, "o", lv, v:val)'), ',')
endfor
exe 'syn cluster '.prefix.'Regions_'.kind.' contains='.join(map(range(cycle), '"@".s:synGroupID(prefix, "Regions", v:val, kind)'), ',')
exe 'syn cluster '.prefix.'Parentheses_'.kind.' contains='.join(map(range(cycle), '"@".s:synGroupID(prefix, "Parentheses", v:val, kind)'), ',')
exe 'syn cluster '.prefix.'Operators_'.kind.' contains='.join(map(range(cycle), '"@".s:synGroupID(prefix, "Operators", v:val, kind)'), ',')
endfor
exe 'syn cluster '.prefix.'Regions contains='.join(map(range(cycle), '"@".s:synGroupID(prefix, "Regions", v:val)'), ',')
exe 'syn cluster '.prefix.'Parentheses contains='.join(map(range(cycle), '"@".s:synGroupID(prefix, "Parentheses", v:val)'), ',')
exe 'syn cluster '.prefix.'Operators contains='.join(map(range(cycle), '"@".s:synGroupID(prefix, "Operators", v:val)'), ',')
if has_key(conf, 'after') | for cmd in conf.after | exe cmd | endfor | endif
endfun

Expand Down
11 changes: 10 additions & 1 deletion autoload/rainbow_main.vim
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,16 @@ let s:rainbow_conf = {
\ 'parentheses': ['start=/\v\<((script|style|area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)[ >])@!\z([-_:a-zA-Z0-9]+)(\s+[-_:a-zA-Z0-9]+(\=("[^"]*"|'."'".'[^'."'".']*'."'".'|[^ '."'".'"><=`]*))?)*\>/ end=#</\z1># fold'],
\ },
\ 'lua': {
\ 'parentheses': ["start=/(/ end=/)/", "start=/{/ end=/}/", "start=/\\v\\[\\ze($|[^[])/ end=/\\]/"],
\ 'parentheses': ['start=/(/ end=/)/', 'start=/{/ end=/}/', 'start=/\v\[\ze($|!(\=*\[))/ end=/\]/'],
\ },
\ 'zsh': {
\ 'parentheses': [
\ 'start=/\v\(\ze($|[^(])/ end=/)/',
\ 'start=/((/ end=/))/ kind=arithQuote upkind=,',
\ 'start=/\$((/ end=/))/ kind=arithQuote upkind=,arithInner',
\ 'start=/(/ end=/)/ contained kind=arithInner upkind=arithQuote',
\ 'start=/\V[[/ end=/]]/', 'start=/\v\[\ze($|[^[])/ end=/]/',
\ 'start=/{/ end=/}/'],
\ },
\ 'perl': {
\ 'syn_name_prefix': 'perlBlockFoldRainbow',
Expand Down
7 changes: 4 additions & 3 deletions tests/test.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[==[ Long bracket string 1... ]==]

(function(args)
lst = { a=function(arg) print("hello") end,
b=(1+2)*3/4,
Expand All @@ -7,6 +9,5 @@
(function() return 0 end)()] = 1
end)("blah")

[[
Special lua string...
]]
[[ Long bracket string 2 ]]

6 changes: 6 additions & 0 deletions tests/test.zsh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
(((($(((1+(2+3))))+4*5)*6)))
[[ $((1 + 2)) == $([ ] || echo 3) ]]

function f() {
}