Skip to content

Commit f5ecb99

Browse files
committed
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
1 parent f80929a commit f5ecb99

File tree

1 file changed

+62
-19
lines changed

1 file changed

+62
-19
lines changed

autoload/vital/_easymotion/HitAHint/Motion.vim

Lines changed: 62 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,21 @@ let s:TRUE = !0
2020
let s:FALSE = 0
2121
let s:DIRECTION = {'forward': 0, 'backward': 1}
2222

23+
" Check Vim version
24+
function! s:has_patch(major, minor, patch) abort
25+
let l:version = (a:major * 100 + a:minor)
26+
return has('patch-' . a:major . '.' . a:minor . '.' . a:patch) ||
27+
\ (v:version > l:version) ||
28+
\ (v:version == l:version && 'patch' . a:patch)
29+
endfunction
30+
31+
" matchadd('Conceal', {pattern}, {priority}, -1, {'conceal': {char}}}) can
32+
" highlight pattern and conceal target correctly even if the target is keyword
33+
" characters.
34+
" - http://ftp.vim.org/vim/patches/7.4/7.4.792
35+
" - https://groups.google.com/forum/#!searchin/vim_dev/matchadd$20conceal/vim_dev/8bKa98GhHdk/VOzIBhd1m8YJ
36+
let s:can_preserve_syntax = s:has_patch(7, 4, 792)
37+
2338
" s:move() moves cursor over/accross window with Hit-A-Hint feature like
2439
" vim-easymotion
2540
" @param {dict} config
@@ -251,14 +266,22 @@ let s:Hinter = {
251266
function! s:Hinter.new(hint_dict, config) abort
252267
let s = deepcopy(self)
253268
let s.config = a:config
254-
let win2pos2hint = s:create_win2pos2hint(a:hint_dict)
255-
let s.winnrs = sort(map(keys(win2pos2hint), 'str2nr(v:val)'))
256-
let s.win2pos2hint = win2pos2hint
257-
let s.w2l2c2h = s:win2pos2hint_to_w2l2c2h(win2pos2hint)
258-
call s._save_lines()
269+
call s.init(a:hint_dict)
259270
return s
260271
endfunction
261272

273+
function! s:Hinter.init(hint_dict) abort
274+
let win2pos2hint = s:create_win2pos2hint(a:hint_dict)
275+
let self.winnrs = sort(map(keys(win2pos2hint), 'str2nr(v:val)'))
276+
let self.win2pos2hint = win2pos2hint
277+
let self.w2l2c2h = s:win2pos2hint_to_w2l2c2h(win2pos2hint)
278+
let self.hl_target_ids = {}
279+
for winnr in self.winnrs
280+
let self.hl_target_ids[winnr] = []
281+
endfor
282+
call self._save_lines()
283+
endfunction
284+
262285
function! s:Hinter.before() abort
263286
let self.highlight_id_cursor = matchadd('Cursor', '\%#', 101)
264287
call self.save_options()
@@ -322,28 +345,32 @@ function! s:Hinter.modify_env_for_win(winnr) abort
322345
setlocal modifiable
323346
setlocal noreadonly
324347

325-
ownsyntax overwin
348+
if !s:can_preserve_syntax
349+
ownsyntax overwin
350+
endif
351+
326352
setlocal conceallevel=2
327353
setlocal concealcursor=ncv
328354

329355
let self.highlight_ids[a:winnr] = get(self.highlight_ids, a:winnr, [])
330356
if self.config.do_shade
331-
syntax clear
357+
if !s:can_preserve_syntax
358+
syntax clear
359+
endif
332360
let self.highlight_ids[a:winnr] += [matchadd(self.config.highlight.shade, '\_.*', 100)]
333361
endif
334362
endfunction
335363

336364
function! s:Hinter.restore_env() abort
337-
syntax clear HitAHintTarget
338365
call s:PHighlight.set('Conceal', self.save_conceal)
339366
let nr = winnr()
340367
try
341368
for winnr in self.winnrs
342369
call s:move_to_win(winnr)
343370
call self.restore_lines_for_win(winnr)
344-
" Clear syntax defined by Hit-A-Hint motion before restoring syntax.
345-
syntax clear HitAHintTarget
346-
if self.config.do_shade
371+
call self.remove_hints(winnr)
372+
373+
if !s:can_preserve_syntax && self.config.do_shade
347374
let &syntax = self.save_syntax[winnr]
348375
endif
349376

@@ -470,7 +497,7 @@ function! s:Hinter._show_hint_for_win(winnr) abort
470497
endif
471498
execute 'highlight! link Conceal' self.config.highlight.target
472499
for [lnum, cnum, char] in hints
473-
call s:show_hint_pos(lnum, cnum, char)
500+
call self.show_hint_pos(lnum, cnum, char, a:winnr)
474501
endfor
475502
endfunction
476503

@@ -520,11 +547,12 @@ endfunction
520547
function! s:Hinter._replace_line_for_hint(lnum, col_num, line, hint) abort
521548
let line = a:line
522549
let col_num = a:col_num
550+
let do_replace_target = !(self.config.do_shade || s:can_preserve_syntax)
523551
let target = matchstr(line, '\%' . col_num .'c.')
524552
" Append one space for empty line or match at end of line
525553
if target is# ''
526554
let hintwidth = strdisplaywidth(join(a:hint[:1], ''))
527-
let char = self.config.do_shade ? ' ' : '.'
555+
let char = do_replace_target ? ' ' : '.'
528556
let line .= repeat(char, hintwidth)
529557
return [line, hintwidth, 0]
530558
endif
@@ -536,7 +564,7 @@ function! s:Hinter._replace_line_for_hint(lnum, col_num, line, hint) abort
536564
let line = self._replace_text_to_space(line, a:lnum, col_num, strdisplaywidth(target))
537565
let offset = strdisplaywidth(target) - len(target)
538566
else
539-
if !self.config.do_shade
567+
if do_replace_target
540568
" The priority of :syn-cchar is always under the priority of keywords.
541569
" So, Hit-A-Hint replaces targets character with '.'.
542570
let space = '.'
@@ -566,6 +594,26 @@ function! s:Hinter._replace_text_to_space(line, lnum, col_num, len) abort
566594
return line
567595
endfunction
568596

597+
function! s:Hinter.show_hint_pos(lnum, cnum, char, winnr) abort
598+
let p = '\%'. a:lnum . 'l\%'. a:cnum . 'c.'
599+
if s:can_preserve_syntax
600+
let self.hl_target_ids[a:winnr] += [matchadd('Conceal', p, 101, -1, {'conceal': a:char})]
601+
else
602+
exec "syntax match HitAHintTarget '". p . "' contains=NONE containedin=.* conceal cchar=". a:char
603+
endif
604+
endfunction
605+
606+
function! s:Hinter.remove_hints(winnr) abort
607+
if s:can_preserve_syntax
608+
for id in self.hl_target_ids[a:winnr]
609+
call matchdelete(id)
610+
endfor
611+
else
612+
" Clear syntax defined by Hit-A-Hint motion before restoring syntax.
613+
syntax clear HitAHintTarget
614+
endif
615+
endfunction
616+
569617
" @param {number} col_num col_num is 1 origin like col()
570618
function! s:tab2spacelen(line, col_num) abort
571619
let before_line = a:col_num > 2 ? a:line[: a:col_num - 2]
@@ -705,11 +753,6 @@ function! s:wincall(func, arglist, ...) abort
705753
return r
706754
endfunction
707755

708-
function! s:show_hint_pos(lnum, cnum, char) abort
709-
let p = '\%'. a:lnum . 'l\%'. a:cnum . 'c.'
710-
exec "syntax match HitAHintTarget '". p . "' contains=NONE containedin=.* conceal cchar=". a:char
711-
endfunction
712-
713756
" deepextend (nest: 1)
714757
function! s:deepextend(expr1, expr2) abort
715758
let expr2 = copy(a:expr2)

0 commit comments

Comments
 (0)