@@ -20,6 +20,21 @@ let s:TRUE = !0
2020let s: FALSE = 0
2121let 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 = {
251266function ! 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
260271endfunction
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+
262285function ! 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
334362endfunction
335363
336364function ! 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
475502endfunction
476503
@@ -520,11 +547,12 @@ endfunction
520547function ! 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
567595endfunction
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()
570618function ! 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
706754endfunction
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)
714757function ! s: deepextend (expr1, expr2) abort
715758 let expr2 = copy (a: expr2 )
0 commit comments