332 lines
9.1 KiB
VimL
332 lines
9.1 KiB
VimL
" =============== ============================================================
|
|
" Name : rule.vim
|
|
" Synopsis : vim script library: rule
|
|
" Author : Zhao Cai <caizhaoff@gmail.com>
|
|
" HomePage : https://github.com/zhaocai/zl.vim
|
|
" Date Created : Sat 03 Sep 2011 03:54:00 PM EDT
|
|
" Last Modified : Sat 29 Sep 2012 01:03:24 AM EDT
|
|
" Tag : [ vim, rule ]
|
|
" Copyright : © 2012 by Zhao Cai,
|
|
" Released under current GPL license.
|
|
" =============== ============================================================
|
|
|
|
|
|
|
|
" ============================================================================
|
|
" Rule: [[[1
|
|
" ============================================================================
|
|
|
|
" [TODO]( list for at type ) @zhaocai @start(2012-09-27 08:05)
|
|
|
|
let s:rule_types = [
|
|
\ 'filetype', 'buftype', 'mode' , 'cword',
|
|
\ 'bufname' , 'at' , 'syntax', 'expr' ,
|
|
\ ]
|
|
let s:nrule = {
|
|
\ 'eval_order' : copy(s:rule_types),
|
|
\ 'eval_negate' : [] ,
|
|
\ 'logic' : 'or' ,
|
|
\ 'rule' : {} ,
|
|
\ }
|
|
|
|
function! GoldenView#zl#rule#norm(urule, ...)
|
|
"--------- ------------------------------------------------
|
|
" Desc : normalize rules
|
|
"
|
|
" Rule :
|
|
" - "urule" : "Unnormalized RULE", rules written by users.
|
|
" - "nrule" : "Nnormalized RULE", rules completed with
|
|
" optional items and internal items.
|
|
"
|
|
" Args :
|
|
" - urule: un-normalized rule
|
|
" - opts :
|
|
" - eval_order : order in s:rule_types,
|
|
" - eval_negate : reverse eval result
|
|
" - logic :
|
|
" - {or} : 'v:filetype || v:bufname || ...'
|
|
" - {and} : 'v:filetype && v:bufname && ...'
|
|
" - {string} : similar to v:val for filter()
|
|
"
|
|
" Return : normalized rules
|
|
" Raise :
|
|
"
|
|
" Example : >
|
|
"
|
|
" Refer :
|
|
"--------- ------------------------------------------------
|
|
let nrule = deepcopy(s:nrule)
|
|
|
|
if a:0 >= 1 && GoldenView#zl#var#is_dict(a:1)
|
|
call extend(nrule, a:1)
|
|
endif
|
|
|
|
let type_expr = {
|
|
\ 'buftype' : '&buftype' ,
|
|
\ 'filetype' : '&ft' ,
|
|
\ 'bufname' : "bufname('%')" ,
|
|
\ 'cword' : "expand('<cword>')" ,
|
|
\ }
|
|
|
|
let type_pat = {}
|
|
for type in ['filetype', 'buftype', 'syntax']
|
|
if has_key(a:urule, type)
|
|
let type_pat[type] = '^\%(' . join(a:urule[type], '\|') . '\)$'
|
|
endif
|
|
endfor
|
|
for type in ['bufname', 'cword']
|
|
if has_key(a:urule, type)
|
|
let type_pat[type] = '^\%('
|
|
\ . join(map(a:urule[type], 'GoldenView#zl#regex#escape(v:val)'), '\|')
|
|
\ . '\)$'
|
|
endif
|
|
endfor
|
|
|
|
|
|
" normalize each type of rules
|
|
for type in ['mode']
|
|
if has_key(a:urule, type)
|
|
let nrule.rule[type] = a:urule[type]
|
|
endif
|
|
endfor
|
|
|
|
for type in ['filetype', 'buftype', 'bufname', 'cword']
|
|
if has_key(a:urule, type)
|
|
let nrule.rule[type] =
|
|
\ {
|
|
\ 'eval_expr' : 1 ,
|
|
\ 'expr' : type_expr[type] ,
|
|
\ 'pat' : type_pat[type] ,
|
|
\ }
|
|
endif
|
|
endfor
|
|
|
|
|
|
for type in ['syntax']
|
|
if has_key(a:urule, type)
|
|
let nrule.rule[type] = type_pat[type]
|
|
endif
|
|
endfor
|
|
|
|
for type in ['mode', 'at']
|
|
if has_key(a:urule, type)
|
|
let nrule.rule[type] = a:urule[type]
|
|
endif
|
|
endfor
|
|
|
|
for type in ['expr']
|
|
if has_key(a:urule, type)
|
|
try | let nrule.rule[type] =
|
|
\ join(
|
|
\ map(
|
|
\ map(
|
|
\ copy(a:urule[type])
|
|
\ ,"join(v:val,' || ')"
|
|
\ )
|
|
\ , "'('.v:val.')'"
|
|
\ )
|
|
\ ,' && '
|
|
\ )
|
|
catch /^Vim\%((\a\+)\)\=:E714/ " E714: List required
|
|
throw 'zl(rule): expr rule should be written as list of lists.'
|
|
endtry
|
|
endif
|
|
endfor
|
|
|
|
call filter(
|
|
\ nrule['eval_order']
|
|
\ , 'has_key(nrule.rule, v:val) && !empty(nrule.rule[v:val])'
|
|
\ )
|
|
|
|
return nrule
|
|
endfunction
|
|
|
|
|
|
function! GoldenView#zl#rule#is_true(nrule, ...)
|
|
try
|
|
return call('GoldenView#zl#rule#logic_'.a:nrule['logic'], [a:nrule] + a:000)
|
|
catch /^Vim\%((\a\+)\)\=:E129/
|
|
throw 'zl(rule): undefined logic funcref'
|
|
endtry
|
|
endfunction
|
|
|
|
|
|
function! GoldenView#zl#rule#is_false(nrule, ...)
|
|
return !call('GoldenView#zl#rule#is_true', [a:nrule] + a:000)
|
|
endfunction
|
|
|
|
|
|
" rule logic
|
|
function! s:_return(nrule, type, ret)
|
|
return
|
|
\ index(a:nrule.eval_negate, a:type) >= 0
|
|
\ ? !a:ret
|
|
\ : a:ret
|
|
endfunction
|
|
|
|
function! GoldenView#zl#rule#logic_or(nrule, ...)
|
|
let opts = {}
|
|
if a:0 >= 1 && GoldenView#zl#var#is_dict(a:1)
|
|
call extend(opts, a:1)
|
|
endif
|
|
|
|
for type in a:nrule['eval_order']
|
|
if s:_return(a:nrule, type, s:eval_{type}(a:nrule['rule'], opts))
|
|
return 1
|
|
endif
|
|
endfor
|
|
return 0
|
|
endfunction
|
|
|
|
function! GoldenView#zl#rule#logic_and(nrule, ...)
|
|
let opts = {}
|
|
if a:0 >= 1 && GoldenView#zl#var#is_dict(a:1)
|
|
call extend(opts, a:1)
|
|
endif
|
|
|
|
for type in a:nrule['eval_order']
|
|
if !s:_return(a:nrule, type, s:eval_{type}(a:nrule['rule'], opts))
|
|
return 0
|
|
endif
|
|
endfor
|
|
return 1
|
|
endfunction
|
|
|
|
function! GoldenView#zl#rule#logic_expr(nrule, ...)
|
|
let opts = {}
|
|
if a:0 >= 1 && GoldenView#zl#var#is_dict(a:1)
|
|
call extend(opts, a:1)
|
|
endif
|
|
|
|
let str = a:nrule['expr']
|
|
for type in a:nrule['eval_order']
|
|
let str = substitute(str
|
|
\ , 'v:'.type
|
|
\ , string(
|
|
\ s:_return(a:nrule, type,
|
|
\ s:eval_{type}(a:nrule['rule'], opts)
|
|
\ )
|
|
\ )
|
|
\ , 'ge'
|
|
\ )
|
|
endfor
|
|
|
|
try
|
|
return eval(str)
|
|
catch /^Vim\%((\a\+)\)\=:E/
|
|
throw printf('zl(rule): eval(%s) raises %s', str, v:exception)
|
|
endtry
|
|
endfunction
|
|
|
|
|
|
|
|
" nrule eval
|
|
function! s:eval_filetype(nrule, ...)
|
|
return call('s:_eval_match', ['filetype', a:nrule] + a:000)
|
|
endfunction
|
|
|
|
function! s:eval_cword(nrule, ...)
|
|
return call('s:_eval_match', ['cword', a:nrule] + a:000)
|
|
endfunction
|
|
|
|
function! s:eval_buftype(nrule, ...)
|
|
return call('s:_eval_match', ['buftype', a:nrule] + a:000)
|
|
endfunction
|
|
|
|
function! s:eval_bufname(nrule, ...)
|
|
return call('s:_eval_match', ['bufname', a:nrule] + a:000)
|
|
endfunction
|
|
|
|
|
|
function! s:eval_at(nrule, ...)
|
|
return search(get(a:nrule, 'at', '\%#'), 'bcnW')
|
|
endfunction
|
|
|
|
function! s:eval_mode(nrule, ...)
|
|
let mode_pat = get(a:nrule, 'mode', [])
|
|
let mode_expr =
|
|
\ a:0 >= 1 && GoldenView#zl#var#is_dict(a:1)
|
|
\ ? get(a:1, 'mode', mode())
|
|
\ : mode()
|
|
|
|
return
|
|
\ !empty(
|
|
\ filter(
|
|
\ mode_pat
|
|
\ , 'stridx(mode_expr, v:val) == -1'
|
|
\ )
|
|
\ )
|
|
endfunction
|
|
|
|
function! s:eval_syntax(nrule, ...)
|
|
let pat = get(a:nrule, 'syntax', '')
|
|
|
|
let opts = {}
|
|
if a:0 >= 1 && GoldenView#zl#var#is_dict(a:1)
|
|
call extend(opts, a:1)
|
|
endif
|
|
let syn_names = GoldenView#zl#syntax#synstack_names(opts)
|
|
|
|
return !empty(filter(syn_names, 'match(v:val, pat) != -1'))
|
|
endfunction
|
|
|
|
function! s:eval_expr(nrule, ...)
|
|
try
|
|
return eval(get(a:nrule, 'expr', 1))
|
|
catch /^Vim\%((\a\+)\)\=:E/
|
|
return 0
|
|
endtry
|
|
endfunction
|
|
|
|
function! s:_eval_match(type, nrule, ...)
|
|
"--------- ------------------------------------------------
|
|
" Desc : internal match evluation
|
|
" Rule :
|
|
" { 'type' :
|
|
" {
|
|
" 'eval_expr' : (1|0) ,
|
|
" 'expr' : {expr} ,
|
|
" 'pat' : {pat} ,
|
|
" }
|
|
" }
|
|
"
|
|
" Args : [{type}, {nrule}[, {opts}]]
|
|
" Return :
|
|
" - 0 : false
|
|
" - 1 : true
|
|
" Raise : zl(rule)
|
|
"
|
|
" Refer : vimhelp:match()
|
|
"--------- ------------------------------------------------
|
|
|
|
let rule = copy(get(a:nrule, a:type, {}))
|
|
if empty(rule)
|
|
throw 'zl(rule): ' . v:exception
|
|
endif
|
|
|
|
" opt for {expr} from runtime opts
|
|
if a:0 >= 1 && GoldenView#zl#var#is_dict(a:1) && has_key(a:1, a:type)
|
|
let rt_rule = a:1[a:type]
|
|
if GoldenView#zl#var#is_dict(rt_rule)
|
|
call extend(rule, rt_rule)
|
|
elseif GoldenView#zl#var#is_string(rt_rule)
|
|
let rule['expr'] = rt_rule
|
|
let rule['eval_expr'] = 0
|
|
endif
|
|
endif
|
|
if rule['eval_expr']
|
|
let rule['expr'] = eval(rule['expr'])
|
|
endif
|
|
try
|
|
return call('match', [rule['expr'], rule['pat']]) != -1
|
|
catch /^Vim\%((\a\+)\)\=:E/
|
|
throw 'zl(rule): ' . v:exception
|
|
endtry
|
|
endfunction
|
|
|
|
|
|
" ============================================================================
|
|
" Modeline: [[[1
|
|
" ============================================================================
|
|
" vim: set ft=vim ts=4 sw=4 tw=78 fdm=marker fmr=[[[,]]] fdl=1 :
|