1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
" Display qutebrowser-like hints.
" Max number of tags is 105, which is LCM(21, 5) because 21 and 5 are coprime
let s:cons = "tnshrdlcumwfgypkbvjxqz" " 21
let s:vowel = "aeiou" " 5
let s:signs_to_unplace = []
let s:signs_to_undefine = []
let s:sign_index = 5555
if !exists('g:hints_ns')
let g:hints_ns = nvim_create_namespace("")
endif
" Generate hints on the current file. This may use specific plugins for each
" filetype.
function! s:generate_hints() abort
let marklist = getmarklist(bufnr())
let plugin = hints#plugins#getPluginForFiletype(&ft)
call plugin.Before(expand("%"))
let cur_line = line('.')
let line = 1
let hints = {}
let tag_hints = {}
for i in marklist
let tag_hints[i.mark] = i.pos[1]
endfor
let hints_left = len(s:vowel) * len(s:cons)
let last_line = line('$')
let cnt = 0
while line <= last_line
if plugin.TagLine(line, getline(line))
let tag=printf("%s%s",
\ s:cons[cnt % len(s:cons)], s:vowel[cnt % len(s:vowel)])
let cnt += 1
" We want to keep the hints closest to the cursor line.
if !has_key(hints, tag) || abs(cur_line - hints[tag]) > abs(cur_line - line)
let hints[tag] = line
endif
endif
let line += 1
endwhile
return extend(tag_hints, hints, 'force')
endfunction
function! s:display_hints(hints) abort
let s = s:sign_index
for [tag, line] in items(a:hints)
call add(s:signs_to_undefine, "tag_" . tag)
call add(s:signs_to_unplace, s)
"call nvim_buf_set_virtual_text(
" \ 0, g:hints_ns, line - 1, [[tag, "Number"]], {})
exec printf("sign define tag_%s text=%s texthl=Number", tag, tag)
exec printf("sign place %d line=%d name=tag_%s file=%s", s, line, tag, expand('%:p'))
let s += 1
endfor
endfunction
function! s:cleanup_hints() abort
call nvim_buf_clear_namespace(0, g:hints_ns, 0, -1)
for s in s:signs_to_unplace
try
exec printf("sign unplace %d", s)
catch
endtry
endfor
for s in s:signs_to_undefine
try
exec printf("sign undefine %s", s)
catch
endtry
endfor
endfunction
function! s:get(hint_dict, str) abort
if a:str =~ '^[A-Z]\+$'
let [a, _] = s:get(a:hint_dict, tolower(a:str))
return [a, "^"]
endif
if has_key(a:hint_dict, a:str)
return [a:hint_dict[a:str], col('.') . '|']
endif
if len(a:str) == 1 || a:str[0] == a:str[1]
let [a, _] = s:get(a:hint_dict, "'" . a:str[0])
return [a, "`" . a:str[0]]
endif
return [-1, '']
endfunction
function! hints#runHints(visual) abort
let hints = s:generate_hints()
call s:display_hints(hints)
redraw
let c1 = getchar()
if c1 == 0x1b " Escape
call s:cleanup_hints()
return
endif
if stridx(s:cons, tolower(nr2char(c1))) >= 0 || nr2char(c1) == "'"
let c2 = getchar()
else
let c2 = ""
endif
call s:cleanup_hints()
let [line, act] = s:get(hints, nr2char(c1) . nr2char(c2))
if line >= 0
if a:visual == 'o'
norm! V
endif
norm m'
call cursor(line, 1)
if len(act) > 0
exec "norm! " . act
endif
endif
endfunction
|