diff options
author | Josh Rahm <rahm@google.com> | 2022-08-09 00:33:40 -0600 |
---|---|---|
committer | Josh Rahm <rahm@google.com> | 2022-08-09 00:33:40 -0600 |
commit | 54ce931f0bcede9affde3a6934656fa6d4ad9961 (patch) | |
tree | 29d6c48b81f6ee5a5206fe5f97a52c5530fae537 | |
parent | 3340b11176d467961ae8426091d53c6ad1a01d2c (diff) | |
download | fieldmarshal.vim-54ce931f0bcede9affde3a6934656fa6d4ad9961.tar.gz fieldmarshal.vim-54ce931f0bcede9affde3a6934656fa6d4ad9961.tar.bz2 fieldmarshal.vim-54ce931f0bcede9affde3a6934656fa6d4ad9961.zip |
Add hints.vim
Hints work like qutebrowser. <C-f> will enter hint mode, which will
prompt the user to type a two-letter sequence to jump the cursor to a
specific line.
-rw-r--r-- | autoload/hints.vim | 107 | ||||
-rw-r--r-- | autoload/hints/plugins.vim | 59 | ||||
-rw-r--r-- | plugin/hints.vim | 3 |
3 files changed, 169 insertions, 0 deletions
diff --git a/autoload/hints.vim b/autoload/hints.vim new file mode 100644 index 0000000..e7b9a1b --- /dev/null +++ b/autoload/hints.vim @@ -0,0 +1,107 @@ +" Display qutebrowser-like hints. + +" Max number of tags is 105, which is LCM(21, 5) +let s:cons = "bcdfghjklmnpqrstvwxyz" " 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 plugin = hints#plugins#getPluginForFiletype(&ft) + call plugin.Before(expand("%")) + + let ci = 0 + let vi = 0 + + let line = line('w0') + let endline = line('w$') + + let hints = {} + + while line <= endline + if plugin.TagLine(line, getline(line)) + let tag=printf("%s%s", + \ s:cons[ci % len(s:cons)], s:vowel[vi % len(s:vowel)]) + let hints[tag] = line + + " Advance _both_ the consonants and vowels. We want the tags to generally + " have as little in common as possible. + let ci += 1 + let vi += 1 + 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=LineNr", 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! 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 + + let c2 = getchar() + + call s:cleanup_hints() + + let line = get(hints, nr2char(c1) . nr2char(c2), -1) + + if line >= 0 + norm m' + if len(a:visual) + exec "norm " . a:visual + endif + call cursor(line, 1) + norm ^ + endif +endfunction diff --git a/autoload/hints/plugins.vim b/autoload/hints/plugins.vim new file mode 100644 index 0000000..de8cc6c --- /dev/null +++ b/autoload/hints/plugins.vim @@ -0,0 +1,59 @@ +let s:ftplugins = {} +let s:default_plugin = {} + +let s:vim_plugin = {} +function! s:vim_plugin.Before(file) +endfunction +function! s:vim_plugin.TagLine(linenr, line) + return a:line =~ '\<\(if\|function\|return\|end\w*\|while\|for\|let\|else\|try\)\>' +endfunction + +let s:java_plugin = {} + +function! s:java_plugin.Before(file) dict + let self.last_line = '' +endfunction + +let s:WHITESPACE_OR_COMMENT='\(^\s*$\)\|\(^\s*//\)\|\(^\s*\*/\)' +function! s:java_plugin.TagLine(linenr, line) dict + if self.last_line =~ s:WHITESPACE_OR_COMMENT + \ && !(a:line =~ s:WHITESPACE_OR_COMMENT) + let self.last_line = a:line + return v:true + endif + let self.last_line = a:line + + return + \ a:line =~ '^\s*}$' || + \ a:line =~ '\<\(public\|private\|protected\|class\|static\|try\|while\|for\|if\|else\|catch\)\>' +endfunction + +call hints#plugins#registerFt("vim", s:vim_plugin) +call hints#plugins#registerFt("java", s:java_plugin) + +function! hints#plugins#registerFt(filetype, plugin) abort + let s:ftplugins[a:filetype] = a:plugin +endfunction + +function! hints#plugins#getPluginForFiletype(filetype) abort + return get(s:ftplugins, a:filetype, s:default_plugin) +endfunction + +function! hints#plugins#getDefaultPlugin() abort + return s:default_plugin +endfunction + +function! s:default_plugin.Before(file) + let self.last_line = '' +endfunction + +let s:ISSPACE= '^\s*$' +function! s:default_plugin.TagLine(linenr, line) + if self.last_line =~ s:ISSPACE && !(a:line =~ s:ISSPACE) + let self.last_line = a:line + return v:true + endif + + let self.last_line = a:line + return v:false +endfunction diff --git a/plugin/hints.vim b/plugin/hints.vim new file mode 100644 index 0000000..47282ad --- /dev/null +++ b/plugin/hints.vim @@ -0,0 +1,3 @@ +noremap <silent> <C-f> :<C-u>call hints#runHints("")<cr> +onoremap <silent> <C-f> :<C-u> call hints#runHints("V")<cr> +vnoremap <silent> <C-f> :<C-u> call hints#runHints("V")<cr> |