From patch 7.4.792, we can conceal item with matchadd()

It solves problem of :syn-cchar which cannot conceal some keyword items.

Patch 7.4.792 is nice!
Thanks @chrisbra
This commit is contained in:
haya14busa 2016-01-21 15:47:58 +09:00
parent f80929acbe
commit f5ecb99abe

View File

@ -20,6 +20,21 @@ let s:TRUE = !0
let s:FALSE = 0 let s:FALSE = 0
let s:DIRECTION = {'forward': 0, 'backward': 1} let s:DIRECTION = {'forward': 0, 'backward': 1}
" Check Vim version
function! s:has_patch(major, minor, patch) abort
let l:version = (a:major * 100 + a:minor)
return has('patch-' . a:major . '.' . a:minor . '.' . a:patch) ||
\ (v:version > l:version) ||
\ (v:version == l:version && 'patch' . a:patch)
endfunction
" matchadd('Conceal', {pattern}, {priority}, -1, {'conceal': {char}}}) can
" highlight pattern and conceal target correctly even if the target is keyword
" characters.
" - http://ftp.vim.org/vim/patches/7.4/7.4.792
" - https://groups.google.com/forum/#!searchin/vim_dev/matchadd$20conceal/vim_dev/8bKa98GhHdk/VOzIBhd1m8YJ
let s:can_preserve_syntax = s:has_patch(7, 4, 792)
" s:move() moves cursor over/accross window with Hit-A-Hint feature like " s:move() moves cursor over/accross window with Hit-A-Hint feature like
" vim-easymotion " vim-easymotion
" @param {dict} config " @param {dict} config
@ -251,14 +266,22 @@ let s:Hinter = {
function! s:Hinter.new(hint_dict, config) abort function! s:Hinter.new(hint_dict, config) abort
let s = deepcopy(self) let s = deepcopy(self)
let s.config = a:config let s.config = a:config
let win2pos2hint = s:create_win2pos2hint(a:hint_dict) call s.init(a:hint_dict)
let s.winnrs = sort(map(keys(win2pos2hint), 'str2nr(v:val)'))
let s.win2pos2hint = win2pos2hint
let s.w2l2c2h = s:win2pos2hint_to_w2l2c2h(win2pos2hint)
call s._save_lines()
return s return s
endfunction endfunction
function! s:Hinter.init(hint_dict) abort
let win2pos2hint = s:create_win2pos2hint(a:hint_dict)
let self.winnrs = sort(map(keys(win2pos2hint), 'str2nr(v:val)'))
let self.win2pos2hint = win2pos2hint
let self.w2l2c2h = s:win2pos2hint_to_w2l2c2h(win2pos2hint)
let self.hl_target_ids = {}
for winnr in self.winnrs
let self.hl_target_ids[winnr] = []
endfor
call self._save_lines()
endfunction
function! s:Hinter.before() abort function! s:Hinter.before() abort
let self.highlight_id_cursor = matchadd('Cursor', '\%#', 101) let self.highlight_id_cursor = matchadd('Cursor', '\%#', 101)
call self.save_options() call self.save_options()
@ -322,28 +345,32 @@ function! s:Hinter.modify_env_for_win(winnr) abort
setlocal modifiable setlocal modifiable
setlocal noreadonly setlocal noreadonly
if !s:can_preserve_syntax
ownsyntax overwin ownsyntax overwin
endif
setlocal conceallevel=2 setlocal conceallevel=2
setlocal concealcursor=ncv setlocal concealcursor=ncv
let self.highlight_ids[a:winnr] = get(self.highlight_ids, a:winnr, []) let self.highlight_ids[a:winnr] = get(self.highlight_ids, a:winnr, [])
if self.config.do_shade if self.config.do_shade
if !s:can_preserve_syntax
syntax clear syntax clear
endif
let self.highlight_ids[a:winnr] += [matchadd(self.config.highlight.shade, '\_.*', 100)] let self.highlight_ids[a:winnr] += [matchadd(self.config.highlight.shade, '\_.*', 100)]
endif endif
endfunction endfunction
function! s:Hinter.restore_env() abort function! s:Hinter.restore_env() abort
syntax clear HitAHintTarget
call s:PHighlight.set('Conceal', self.save_conceal) call s:PHighlight.set('Conceal', self.save_conceal)
let nr = winnr() let nr = winnr()
try try
for winnr in self.winnrs for winnr in self.winnrs
call s:move_to_win(winnr) call s:move_to_win(winnr)
call self.restore_lines_for_win(winnr) call self.restore_lines_for_win(winnr)
" Clear syntax defined by Hit-A-Hint motion before restoring syntax. call self.remove_hints(winnr)
syntax clear HitAHintTarget
if self.config.do_shade if !s:can_preserve_syntax && self.config.do_shade
let &syntax = self.save_syntax[winnr] let &syntax = self.save_syntax[winnr]
endif endif
@ -470,7 +497,7 @@ function! s:Hinter._show_hint_for_win(winnr) abort
endif endif
execute 'highlight! link Conceal' self.config.highlight.target execute 'highlight! link Conceal' self.config.highlight.target
for [lnum, cnum, char] in hints for [lnum, cnum, char] in hints
call s:show_hint_pos(lnum, cnum, char) call self.show_hint_pos(lnum, cnum, char, a:winnr)
endfor endfor
endfunction endfunction
@ -520,11 +547,12 @@ endfunction
function! s:Hinter._replace_line_for_hint(lnum, col_num, line, hint) abort function! s:Hinter._replace_line_for_hint(lnum, col_num, line, hint) abort
let line = a:line let line = a:line
let col_num = a:col_num let col_num = a:col_num
let do_replace_target = !(self.config.do_shade || s:can_preserve_syntax)
let target = matchstr(line, '\%' . col_num .'c.') let target = matchstr(line, '\%' . col_num .'c.')
" Append one space for empty line or match at end of line " Append one space for empty line or match at end of line
if target is# '' if target is# ''
let hintwidth = strdisplaywidth(join(a:hint[:1], '')) let hintwidth = strdisplaywidth(join(a:hint[:1], ''))
let char = self.config.do_shade ? ' ' : '.' let char = do_replace_target ? ' ' : '.'
let line .= repeat(char, hintwidth) let line .= repeat(char, hintwidth)
return [line, hintwidth, 0] return [line, hintwidth, 0]
endif endif
@ -536,7 +564,7 @@ function! s:Hinter._replace_line_for_hint(lnum, col_num, line, hint) abort
let line = self._replace_text_to_space(line, a:lnum, col_num, strdisplaywidth(target)) let line = self._replace_text_to_space(line, a:lnum, col_num, strdisplaywidth(target))
let offset = strdisplaywidth(target) - len(target) let offset = strdisplaywidth(target) - len(target)
else else
if !self.config.do_shade if do_replace_target
" The priority of :syn-cchar is always under the priority of keywords. " The priority of :syn-cchar is always under the priority of keywords.
" So, Hit-A-Hint replaces targets character with '.'. " So, Hit-A-Hint replaces targets character with '.'.
let space = '.' let space = '.'
@ -566,6 +594,26 @@ function! s:Hinter._replace_text_to_space(line, lnum, col_num, len) abort
return line return line
endfunction endfunction
function! s:Hinter.show_hint_pos(lnum, cnum, char, winnr) abort
let p = '\%'. a:lnum . 'l\%'. a:cnum . 'c.'
if s:can_preserve_syntax
let self.hl_target_ids[a:winnr] += [matchadd('Conceal', p, 101, -1, {'conceal': a:char})]
else
exec "syntax match HitAHintTarget '". p . "' contains=NONE containedin=.* conceal cchar=". a:char
endif
endfunction
function! s:Hinter.remove_hints(winnr) abort
if s:can_preserve_syntax
for id in self.hl_target_ids[a:winnr]
call matchdelete(id)
endfor
else
" Clear syntax defined by Hit-A-Hint motion before restoring syntax.
syntax clear HitAHintTarget
endif
endfunction
" @param {number} col_num col_num is 1 origin like col() " @param {number} col_num col_num is 1 origin like col()
function! s:tab2spacelen(line, col_num) abort function! s:tab2spacelen(line, col_num) abort
let before_line = a:col_num > 2 ? a:line[: a:col_num - 2] let before_line = a:col_num > 2 ? a:line[: a:col_num - 2]
@ -705,11 +753,6 @@ function! s:wincall(func, arglist, ...) abort
return r return r
endfunction endfunction
function! s:show_hint_pos(lnum, cnum, char) abort
let p = '\%'. a:lnum . 'l\%'. a:cnum . 'c.'
exec "syntax match HitAHintTarget '". p . "' contains=NONE containedin=.* conceal cchar=". a:char
endfunction
" deepextend (nest: 1) " deepextend (nest: 1)
function! s:deepextend(expr1, expr2) abort function! s:deepextend(expr1, expr2) abort
let expr2 = copy(a:expr2) let expr2 = copy(a:expr2)