aboutsummaryrefslogtreecommitdiff
path: root/autoload/hints.vim
blob: ac0a3e5f9db777ede48df9d3c9fafd4428923b75 (plain) (blame)
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
" Display qutebrowser-like hints.

" Max number of tags is 105, which is LCM(21, 5)
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 line = line('w0')
  let endline = line('w$')

  let hints = {}
  for i in marklist
    let hints[i.mark] = i.pos[1]
  endfor

  while line <= endline
    if plugin.TagLine(line, getline(line))
      let tag=printf("%s%s",
            \ s:cons[line % len(s:cons)], s:vowel[line % len(s:vowel)])
      let hints[tag] = line
    endif

    let line += 1
  endwhile

  return hints
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 has_key(a:hint_dict, a:str)
    return a:hint_dict[a:str]
  endif

  if len(a:str) == 1 || a:str[0] == a:str[1]
    return s:get(a:hint_dict, "'" . 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, nr2char(c1)) >= 0 || nr2char(c1) == "'"
    let c2 = getchar()
  else
    let c2 = ""
  endif

  call s:cleanup_hints()

  let line = s:get(hints, nr2char(c1) . nr2char(c2))

  if line >= 0
    if a:visual == 'o'
      norm! V
    endif
    norm m'
    call cursor(line, 1)
    norm ^
  endif
endfunction