Skip to content
Open
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
18 changes: 13 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Rainbow Parentheses Improved
Rainbow Parentheses Improved
===
> help you read complex code by showing diff level of parentheses in diff color !!

Expand Down 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, see [syntax-for-parentheses-definition]().
- '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 All @@ -116,10 +116,18 @@ let g:rainbow_conf = {

To get more advanced config examples, try to search throught this [tag](https://github.com/luochen1990/rainbow/issues?utf8=%E2%9C%93&q=label%3A%22config+reference%22+).

#### Syntax for `parentheses` definition

A parentheses definition defines a kind of parentheses and contains parts like `start=/(/`, `step=/,/`, `stop=/)/`, `fold`, `contained`, `containedin=someSynNames`, `contains=@Spell`, and `cluster=someNames`, see `:h syntax` for more details for parts except `step` and `cluster`. The content of `step` is a regex matching the operators within the parentheses that should be highlighted; `cluster` is a comma-separated list (just like `containein`) specifying the parenthesis clusters the kind of parentheses, whose default value is `default`, and `default` can also be explicitly specified in the `cluster` list.

Parenthesis clusters can be referred to in `contains` and `containedin` with the form `#name`, thus the nesting parentheses would be highlighted strictly according to their nesting levels. If you want to use top-level highlight for some parentheses, specify the syntax cluster names rainbow generated for the parentheses clusters instead.

User Command
------------

- **:RainbowToggle** --you can use it to toggle this plugin.
- **:RainbowToggle** -- you can use it to toggle this plugin on and off.
- **:RainbowToggleOn** -- turn this plugin on.
- **:RainbowToggleOff** -- turn this plugin off

3rd Party Plugin Compatibility
------------------------------
Expand Down Expand Up @@ -184,6 +192,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`**
12 changes: 9 additions & 3 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

- 更快速和流畅的体验。
- 简短,高质量,并且易读的源代码。
- 现在的版本将不再限制括号的嵌套层数。
- 现在的版本将不再限制括号的嵌套层数。
- 现在你可以分别自定义图形界面下和终端上所使用的各种括号颜色。
- 现在你可以自定义括号的形式,不过在这之前你最好了解vim脚本的正则表达式。
- 现在你甚至可以为不同类型的文件设定不同的配置。
Expand All @@ -26,7 +26,7 @@
- 现在采用json风格的配置文件,更加可读,更易于进行高级配置。
- 最后但并非不重要的一点是,如你所见,现在增加了中文说明。

### 以下是本插件所参考的旧版本:
### 以下是本插件所参考的旧版本:
- http://www.vim.org/scripts/script.php?script_id=1561 (Martin Krischik)
- http://www.vim.org/scripts/script.php?script_id=3772 (kien)

Expand Down Expand Up @@ -94,10 +94,16 @@ let g:rainbow_active = 1 "0 if you want to enable it later via :RainbowToggle
- '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` 为本插件的扩展定义, 表示括号中间需要高亮的运算符.
- 'parentheses': 一个关于括号定义的列表, 其中的每个项目描述了一种括号, 具体的语法见[parentheses的语法]()
- 'separately': 针对文件类型(由&ft决定)作不同的配置,未被单独设置的文件类型使用`*`下的配置,值为`0`表示仅对该类型禁用插件,值为`"default"`表示使用针对该类型的默认兼容配置 (注意, 默认兼容配置可能随着该插件版本的更新而改变, 如果你不希望它改变, 那么你应该将它拷贝一份放到你的vimrc文件里).
- 省略某个字段以使用默认设置

#### `parentheses`的语法

每一种括号的定义包含形如以下的部分: `start=/(/`, `step=/,/`, `stop=/)/`, `fold`, `contained`, `containedin=someSynNames`, `contains=@Spell`, `cluster=someNames`. 其中, `start`, `stop`, `fold`, `contained`, `containedin` 和 `contains` 的具体含义可参考 `:h syntax`; `step` 和 `cluster` 为本插件的扩展定义. `step` 是一个正则, 匹配括号中间需要高亮的运算符. `cluster` 是一个用逗号分隔的列表 (和 `containedin` 类似), 指定了这种括号所属的括号组, 默认的括号组名称为 `default`, 也可以将它显式放在括号组名称的列表中.

在 `contains` 和 `containein` 中可以用 `#name` 的形式引用一个括号组, 这样相互嵌套的括号就会严格按照嵌套层次来高亮. 如果想要在某种或者某组括号里使用顶层的高亮, 可以使用为括号组生成的语法元素的名字.

-------------------------------------------------------------------
**最后,如果你喜欢这个插件,给它一个评价,我会心存感激,并且因为你的肯定继续改进这个插件!(从[该页面](http://www.vim.org/scripts/script.php?script_id=4176)下方,选择`Life Changing`选项,然后点击`rate`)**

78 changes: 53 additions & 25 deletions autoload/rainbow.vim
Original file line number Diff line number Diff line change
Expand Up @@ -11,41 +11,47 @@ 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 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 [paren, contained, containedin, contains_prefix, contains, op, cluster] = 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)
for s in ls
let [k, v] = [matchstr(s, '^[^=]\+\ze\(=\|$\)'), matchstr(s, '^[^=]\+=\zs.*')]
let [k, v] = [s:trim(matchstr(s, '^[^=]\+\ze\(=\|$\)')), s:trim(matchstr(s, '^[^=]\+=\zs.*'))]
if k == 'step'
let op = s:trim(v)
let op = v
elseif k == 'contains_prefix'
let contains_prefix = s:trim(v)
let contains_prefix = v
elseif k == 'contains'
let contains = s:concat([contains, s:trim(v)])
let contains = s:concat([contains, v])
elseif k == 'containedin'
let containedin = s:concat([containedin, s:trim(v)])
let containedin = s:concat([containedin, v])
elseif k == 'contained'
let contained = 1
elseif k == 'cluster'
let cluster = s:concat([cluster, 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, cluster]
"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, cluster)
return a:prefix.a:group.'_lv'.a:lv.'_'.a:cluster
endfun

fun rainbow#syn(config)
Expand All @@ -55,31 +61,53 @@ fun rainbow#syn(config)

let glob_paran_opts = s:resolve_parenthesis_from_config(conf)
let b:rainbow_loaded = cycle
let cluster_list = {}
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, cluster] = s:resolve_parenthesis_with(glob_paran_opts, conf.parentheses[id])

let cluster = split(cluster, ',') ?? ['default']
for k in cluster
let cluster_list[k] = get(cluster_list, k, [])->add(id)
endfor
let containedin_items = split(containedin, ',')
let upcluster = filter(copy(containedin_items), 'v:val =~ "#.*"')->map('v:val[1:]') ?? cluster
let containedin = filter(containedin_items, 'v:val !~ "#.*"')->join(',')
let contains_items = (contains_prefix != '' ? [contains_prefix] : []) + split(contains, ',')

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),
\ mapnew(upcluster, '"@".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_contains = s:concat([contains_prefix, contains])
exe 'syn region '.rid.' matchgroup='.pid.' '.real_contained.'containedin='.real_containedin.' contains='.real_contains.' '.paren
let real_containedin = (lv == 0)? s:concat([containedin, upid]) : upid
let real_contains = mapnew(contains_items,
\ 'v:val =~ "#.*" ? "@".s:synGroupID(prefix, "Regions", uplv, v:val[1:]) : v:val')
\ ->flatten()->join(',')
let real_contains = real_contains != '' ? ' contains='.real_contains : ''
exe 'syn region '.rid.' matchgroup='.pid.' '.real_contained.'containedin='.real_containedin.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, abbr] in [['Regions', 'r'], ['Parentheses', 'p'], ['Operators', 'o']]
for [cluster, ids] in items(cluster_list)
for lv in range(cycle)
exe 'syn cluster '.s:synGroupID(prefix, kind, lv, cluster).' contains='.
\ mapnew(ids, 's:synID(prefix, abbr, lv, v:val)')->join(',')
endfor
exe 'syn cluster '.prefix.kind.'_'.cluster.' contains='.
\ map(range(cycle), '"@".s:synGroupID(prefix, kind, v:val, cluster)')->join(',')
endfor
exe 'syn cluster '.prefix.kind.' contains='.map(keys(cluster_list), 'prefix.kind."_".v:val')->join(',')
endfor

for cmd in conf->get('after', [])
exe cmd
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

fun rainbow#syn_clear(config)
Expand Down
2 changes: 2 additions & 0 deletions doc/rainbow.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Rainbow Parentheses Improved *rainbow*
==========================================================================

Detailed document is in the README.

Commands: *rainbow-commands*
--------------------------------------------------------------------------

Expand Down