spacevim/autoload/SpaceVim/mapping/guide.vim
JIe 2bb7059579
Some checks failed
Detach Plugins / check (FlyGrep.vim) (push) Has been cancelled
Detach Plugins / check (GitHub.vim) (push) Has been cancelled
Detach Plugins / check (JavaUnit.vim) (push) Has been cancelled
Detach Plugins / check (SourceCounter.vim) (push) Has been cancelled
Detach Plugins / check (cpicker.nvim) (push) Has been cancelled
Detach Plugins / check (dein-ui.vim) (push) Has been cancelled
Detach Plugins / check (git.vim) (push) Has been cancelled
Detach Plugins / check (iedit.vim) (push) Has been cancelled
Detach Plugins / check (scrollbar.vim) (push) Has been cancelled
Detach Plugins / check (vim-chat) (push) Has been cancelled
Detach Plugins / check (vim-cheat) (push) Has been cancelled
Detach Plugins / check (vim-todo) (push) Has been cancelled
Detach Plugins / check (xmake.vim) (push) Has been cancelled
test / Linux (nvim, nightly) (push) Has been cancelled
test / Linux (nvim, v0.3.8) (push) Has been cancelled
test / Linux (nvim, v0.4.0) (push) Has been cancelled
test / Linux (nvim, v0.4.2) (push) Has been cancelled
test / Linux (nvim, v0.4.3) (push) Has been cancelled
test / Linux (nvim, v0.4.4) (push) Has been cancelled
test / Linux (nvim, v0.5.0) (push) Has been cancelled
test / Linux (nvim, v0.5.1) (push) Has been cancelled
test / Linux (nvim, v0.6.0) (push) Has been cancelled
test / Linux (nvim, v0.6.1) (push) Has been cancelled
test / Linux (nvim, v0.7.0) (push) Has been cancelled
test / Linux (nvim, v0.7.2) (push) Has been cancelled
test / Linux (nvim, v0.8.0) (push) Has been cancelled
test / Linux (nvim, v0.8.1) (push) Has been cancelled
test / Linux (nvim, v0.8.2) (push) Has been cancelled
test / Linux (nvim, v0.8.3) (push) Has been cancelled
test / Linux (nvim, v0.9.0) (push) Has been cancelled
test / Linux (nvim, v0.9.1) (push) Has been cancelled
test / Linux (true, vim, v7.4.052) (push) Has been cancelled
test / Linux (true, vim, v7.4.1689) (push) Has been cancelled
test / Linux (true, vim, v7.4.629) (push) Has been cancelled
test / Linux (true, vim, v8.0.0027) (push) Has been cancelled
test / Linux (true, vim, v8.0.0183) (push) Has been cancelled
test / Linux (vim, nightly) (push) Has been cancelled
test / Linux (vim, v8.0.0184) (push) Has been cancelled
test / Linux (vim, v8.0.1453) (push) Has been cancelled
test / Linux (vim, v8.1.2269) (push) Has been cancelled
test / Linux (vim, v8.2.2434) (push) Has been cancelled
test / Linux (vim, v8.2.3995) (push) Has been cancelled
test / Windows (nvim, nightly) (push) Has been cancelled
test / Windows (nvim, v0.3.8) (push) Has been cancelled
test / Windows (nvim, v0.4.2) (push) Has been cancelled
test / Windows (nvim, v0.4.3) (push) Has been cancelled
test / Windows (nvim, v0.4.4) (push) Has been cancelled
test / Windows (nvim, v0.5.0) (push) Has been cancelled
test / Windows (nvim, v0.5.1) (push) Has been cancelled
test / Windows (nvim, v0.6.0) (push) Has been cancelled
test / Windows (nvim, v0.6.1) (push) Has been cancelled
test / Windows (nvim, v0.7.0) (push) Has been cancelled
test / Windows (nvim, v0.7.2) (push) Has been cancelled
test / Windows (nvim, v0.8.0) (push) Has been cancelled
test / Windows (nvim, v0.8.1) (push) Has been cancelled
test / Windows (nvim, v0.8.2) (push) Has been cancelled
test / Windows (nvim, v0.8.3) (push) Has been cancelled
test / Windows (nvim, v0.9.0) (push) Has been cancelled
test / Windows (nvim, v0.9.1) (push) Has been cancelled
test / Windows (vim, nightly) (push) Has been cancelled
test / Windows (vim, v7.4.1185) (push) Has been cancelled
test / Windows (vim, v7.4.1689) (push) Has been cancelled
test / Windows (vim, v8.0.0027) (push) Has been cancelled
test / Windows (vim, v8.0.1453) (push) Has been cancelled
test / Windows (vim, v8.1.2269) (push) Has been cancelled
test / Windows (vim, v8.2.2434) (push) Has been cancelled
test / Windows (vim, v8.2.3995) (push) Has been cancelled
docker / docker (push) Has been cancelled
mirror / check (coding) (push) Has been cancelled
mirror / check (gitee) (push) Has been cancelled
mirror / check (gitlab) (push) Has been cancelled
init
2024-08-21 14:17:26 +08:00

954 lines
31 KiB
VimL

"=============================================================================
" guide.vim --- key binding guide for SpaceVim
" Copyright (c) 2016-2023 Wang Shidong & Contributors
" Author: Wang Shidong < wsdjeg@outlook.com >
" URL: https://spacevim.org
" License: GPLv3
"=============================================================================
scriptencoding utf-8
if exists('s:save_cpo')
finish
endif
let s:save_cpo = &cpo
set cpo&vim
""
" @section Mapping Guide, plugins-mapping-guide
" @parentsection plugins
" The mapping guide windows will be opened each time the prefix key is pressed
" in normal/visual mode. It will list all available key bindings and the short
" descriptions. The prefix can be `[SPC]`, `[WIN]` or `<Leader>`.
"
" The prefixes are mapped to the following key bindings by default:
" >
" Prefix | Custom options and default values | Descriptions
" ---------------------------------------------------------------------
" [SPC]` | NONE / `<Space>` | default mapping prefix
" [WIN]` | `windows_leader` / `s` | window mapping prefix
" <Leader>` | default vim leader | default leader prefix
" <
"
" The default value of `<Leader>` is `\`, if you want to change this key,
" you need to use the bootstrap function. For example, to use `,`
" as the `<Leader>` key:
" >
" function! myspacevim#before() abort
" let g:mapleader = ','
" endfunction
" <
"
" NOTE: When modifying the variable `g:mapleader` in a function.
" you can not omit the variable's scope. Because the default scope
" of a variable in function is `l:`. It is different from what you
" see in vim help |mapleader|.
"
" By default the guide buffer will be displayed 1000ms after the keys being pressed.
" You can change the delay by adding vim option `'timeoutlen'` to your bootstrap function.
"
" For example, after pressing `<Space>` in normal mode, you will see all the
" key bindings start with `SPC` in mapping guide windows.
" you can type `b` for all the buffer mappings, `p` for project mappings, etc.
"
" After pressing `Ctrl-h` in guide buffer, you will get paging and help info in the statusline.
" >
" | Keys | Descriptions |
" | ---- | ----------------------------- |
" | `u` | undo pressing |
" | `n` | next page of guide buffer |
" | `p` | previous page of guide buffer |
" <
" Use `SpaceVim#custom#SPC()` to define custom SPC mappings. For example:
" >
" call SpaceVim#custom#SPC('nnoremap',
" \ ['f', 't'],
" \ 'echom "hello world"', 'test custom SPC', 1)
" <
"
" The first parameter sets the type of shortcut key,
" which can be `nnoremap` or `nmap`, the second parameter is a list of keys,
" and the third parameter is an ex command or key binding,
" depending on whether the last parameter is true.
" The fourth parameter is a short description of this custom key binding.
"
" @subsection Fuzzy find key bindings
"
" It is possible to search for specific key bindings by pressing `?`
" in the root of the guide buffer.
"
" To narrow the list down, just insert the mapping keys or descriptions of
" what mappings you want, the fuzzy finder will get the mappings.
"
" Then use `<Tab>` or `<Up>` and `<Down>` to select the mapping,
" press `<Enter>` to execute that command.
"
" @subsection Mapping guide theme
"
" The default mapping guide theme is `leaderguide`,
" which is same as vim-leaderguide(https://github.com/hecal3/vim-leader-guide),
" there is another available theme called `whichkey`.
" To set the mapping guide theme, use following snippet:
" >
" [options]
" # the value can be `leaderguide` or `whichkey`
" leader_guide_theme = 'whichkey'
" <
if has('nvim-0.8.0')
function! SpaceVim#mapping#guide#parse_mappings() abort " {{{
lua require("spacevim.plugin.guide").parse_mappings()
endfunction "}}}
function! SpaceVim#mapping#guide#start(vis, dict) abort " {{{
lua require("spacevim.plugin.guide").start(
\ require("spacevim").eval("a:vis"),
\ require("spacevim").eval("a:dict")
\ )
endfunction "}}}
function! SpaceVim#mapping#guide#has_configuration() abort "{{{
return luaeval('require("spacevim.plugin.guide").has_configuration()')
endfunction "}}}
function! SpaceVim#mapping#guide#start_by_prefix(vis, key) abort " {{{
lua require("spacevim.plugin.guide").start_by_prefix(
\ require("spacevim").eval("a:vis"),
\ require("spacevim").eval("a:key")
\ )
endfunction "}}}
function! SpaceVim#mapping#guide#register_displayname(lhs, name) abort
lua require("spacevim.plugin.guide").register_displayname(
\ require("spacevim").eval("a:lhs"),
\ require("spacevim").eval("a:name")
\ )
endfunction "}}}
function! SpaceVim#mapping#guide#populate_dictionary(key, dictname) abort " {{{
lua require("spacevim.plugin.guide").populate_dictionary(
\ require("spacevim").eval("a:key"),
\ require("spacevim").eval("a:dictname")
\ )
endfunction "}}}
function! SpaceVim#mapping#guide#register_prefix_descriptions(key, dictname) abort " {{{
lua require("spacevim.plugin.guide").register_prefix_descriptions(
\ require("spacevim").eval("a:key"),
\ require("spacevim").eval("a:dictname")
\ )
endfunction "}}}
function! SpaceVim#mapping#guide#displayfunc() abort
lua require("spacevim.plugin.guide").displayfunc()
endfunction
else
" Load SpaceVim API
let s:CMP = SpaceVim#api#import('vim#compatible')
let s:STR = SpaceVim#api#import('data#string')
let s:KEY = SpaceVim#api#import('vim#key')
let s:VIM = SpaceVim#api#import('vim')
let s:BUFFER = SpaceVim#api#import('vim#buffer')
if has('nvim')
let s:FLOATING = SpaceVim#api#import('neovim#floating')
else
let s:FLOATING = SpaceVim#api#import('vim#floating')
endif
let s:SL = SpaceVim#api#import('vim#statusline')
let s:LOG =SpaceVim#logger#derive('guide')
" guide specific var
let s:winid = -1
let s:bufnr = -1
let s:prefix_key_inp = []
let s:lmap = {}
" this should be the history of s:lmap and s:guide_group
let s:undo_history = []
let s:registered_name = {}
function! SpaceVim#mapping#guide#has_configuration() abort "{{{
return exists('s:desc_lookup')
endfunction "}}}
function! SpaceVim#mapping#guide#register_prefix_descriptions(key, dictname) abort " {{{
let key = a:key ==? '<Space>' ? ' ' : a:key
if !exists('s:desc_lookup')
call s:create_cache()
endif
if strlen(key) == 0
let s:desc_lookup['top'] = a:dictname
elseif !has_key(s:desc_lookup, key)
let s:desc_lookup[key] = a:dictname
endif
call s:LOG.debug('desc_lookup is:' . string(s:desc_lookup))
endfunction "}}}
function! s:create_cache() abort " {{{
let s:desc_lookup = {}
let s:cached_dicts = {}
endfunction " }}}
function! s:create_target_dict(key) abort " {{{
if has_key(s:desc_lookup, 'top')
" use {expr} to eval viml value
let toplevel = deepcopy({s:desc_lookup['top']})
let tardict = s:toplevel ? toplevel : get(toplevel, a:key, {})
let mapdict = s:cached_dicts[a:key]
call s:merge(tardict, mapdict)
elseif has_key(s:desc_lookup, a:key)
let tardict = deepcopy({s:desc_lookup[a:key]})
let mapdict = s:cached_dicts[a:key]
call s:merge(tardict, mapdict)
else
let tardict = s:cached_dicts[a:key]
endif
return tardict
endfunction " }}}
function! s:merge(dict_t, dict_o) abort " {{{
let target = a:dict_t
let other = a:dict_o
for k in keys(target)
if type(target[k]) == type({}) && has_key(other, k)
if type(other[k]) == type({})
if has_key(target[k], 'name')
let other[k].name = target[k].name
endif
call s:merge(target[k], other[k])
elseif type(other[k]) == type([])
if g:leaderGuide_flatten == 0 || type(target[k]) == type({})
let target[k.'m'] = target[k]
endif
let target[k] = other[k]
if has_key(other, k.'m') && type(other[k.'m']) == type({})
call s:merge(target[k.'m'], other[k.'m'])
endif
endif
endif
endfor
call extend(target, other, 'keep')
endfunction " }}}
" @vimlint(EVL103, 1, a:dictname)
function! SpaceVim#mapping#guide#populate_dictionary(key, dictname) abort " {{{
call s:start_parser(a:key, s:cached_dicts[a:key])
endfunction " }}}
" @vimlint(EVL103, 0, a:dictname)
function! SpaceVim#mapping#guide#parse_mappings() abort " {{{
for [k, v] in items(s:cached_dicts)
call s:start_parser(k, v)
endfor
endfunction " }}}
function! s:start_parser(key, dict) abort " {{{
if a:key ==# '[KEYs]'
return
endif
let key = a:key ==? ' ' ? '<Space>' : a:key
0verbose let readmap = s:CMP.execute('map ' . key, 'silent')
let lines = split(readmap, "\n")
let visual = s:vis ==# 'gv' ? 1 : 0
for line in lines
let mapd = maparg(split(line[3:])[0], line[0], 0, 1)
if mapd.lhs ==# '\\'
let mapd.feedkeyargs = ''
elseif mapd.noremap == 1
let mapd.feedkeyargs = 'nt'
else
let mapd.feedkeyargs = 'mt'
endif
if mapd.lhs =~# '<Plug>.*' || mapd.lhs =~# '<SNR>.*'
continue
endif
let mapd.display = s:format_displaystring(mapd.rhs)
let mapd.lhs = substitute(mapd.lhs, key, '', '')
let mapd.lhs = substitute(mapd.lhs, '<Space>', ' ', 'g')
let mapd.lhs = substitute(mapd.lhs, '<Tab>', '<C-I>', 'g')
let mapd.rhs = substitute(mapd.rhs, '<SID>', '<SNR>'.mapd['sid'].'_', 'g')
if mapd.lhs !=# '' && mapd.display !~# 'LeaderGuide.*'
let mapd.lhs = s:string_to_keys(mapd.lhs)
if (visual && match(mapd.mode, '[vx ]') >= 0) ||
\ (!visual && match(mapd.mode, '[vx]') == -1)
call s:add_map_to_dict(mapd, 0, a:dict)
endif
endif
endfor
endfunction " }}}
function! s:add_map_to_dict(map, level, dict) abort " {{{
if len(a:map.lhs) > a:level+1
let curkey = a:map.lhs[a:level]
let nlevel = a:level+1
if !has_key(a:dict, curkey)
let a:dict[curkey] = { 'name' : g:leaderGuide_default_group_name }
" mapping defined already, flatten this map
elseif type(a:dict[curkey]) == type([]) && g:leaderGuide_flatten
let cmd = s:escape_mappings(a:map)
let curkey = join(a:map.lhs[a:level+0:], '')
let nlevel = a:level
if !has_key(a:dict, curkey)
let a:dict[curkey] = [cmd, a:map.display]
endif
elseif type(a:dict[curkey]) == type([]) && g:leaderGuide_flatten == 0
let cmd = s:escape_mappings(a:map)
let curkey = curkey.'m'
if !has_key(a:dict, curkey)
let a:dict[curkey] = { 'name' : g:leaderGuide_default_group_name }
endif
endif
" next level
if type(a:dict[curkey]) == type({})
call s:add_map_to_dict(a:map, nlevel, a:dict[curkey])
endif
else
let cmd = s:escape_mappings(a:map)
if !has_key(a:dict, a:map.lhs[a:level])
let a:dict[a:map.lhs[a:level]] = [cmd, a:map.display]
" spot is taken already, flatten existing submaps
elseif type(a:dict[a:map.lhs[a:level]]) == type({}) && g:leaderGuide_flatten
let childmap = s:flattenmap(a:dict[a:map.lhs[a:level]], a:map.lhs[a:level])
for it in keys(childmap)
let a:dict[it] = childmap[it]
endfor
let a:dict[a:map.lhs[a:level]] = [cmd, a:map.display]
endif
endif
endfunction " }}}
" @vimlint(EVL111, 1, Fun)
function! s:format_displaystring(map) abort " {{{
let g:leaderGuide#displayname = a:map
for Fun in g:leaderGuide_displayfunc
call Fun()
endfor
let display = g:leaderGuide#displayname
unlet g:leaderGuide#displayname
return display
endfunction " }}}
" @vimlint(EVL111, 0, Fun)
function! s:flattenmap(dict, str) abort " {{{
let ret = {}
for kv in keys(a:dict)
if type(a:dict[kv]) == type([])
let toret = {}
let toret[a:str.kv] = a:dict[kv]
return toret
elseif type(a:dict[kv]) == type({})
call extend(ret, s:flattenmap(a:dict[kv], a:str.kv))
endif
endfor
return ret
endfunction " }}}
function! s:escape_mappings(mapping) abort " {{{
let rstring = substitute(a:mapping.rhs, '\', '\\\\', 'g')
let rstring = substitute(rstring, '<\([^<>]*\)>', '\\<\1>', 'g')
let rstring = substitute(rstring, '"', '\\"', 'g')
let rstring = 'call feedkeys("'.rstring.'", "'.a:mapping.feedkeyargs.'")'
return rstring
endfunction " }}}
function! s:string_to_keys(input) abort
" Avoid special case: <>
let retlist = []
if match(a:input, '<.\+>') != -1
let si = 0
let go = 1
while si < len(a:input)
if go
if a:input[si] ==# ' '
call add(retlist, '[SPC]')
else
call add(retlist, a:input[si])
endif
else
let retlist[-1] .= a:input[si]
endif
if a:input[si] ==? '<'
let go = 0
elseif a:input[si] ==? '>'
let go = 1
endif
let si += 1
endwhile
else
for it in split(a:input, '\zs')
if it ==# ' '
call add(retlist, '[SPC]')
else
call add(retlist, it)
endif
endfor
endif
return retlist
endfunction
function! s:escape_keys(inp) abort " {{{
let ret = substitute(a:inp, '<', '<lt>', '')
return substitute(ret, '|', '<Bar>', '')
endfunction " }}}
function! s:calc_layout() abort " {{{
let ret = {}
let smap = filter(copy(s:lmap), 'v:key !=# "name"')
let ret.n_items = len(smap)
let length = values(map(smap,
\ 'strdisplaywidth(repeat(" ", 8 - strlen(v:key)) . "[".v:key."]".'.
\ '(type(v:val) == type({}) ? v:val["name"] : v:val[1]))'))
let maxlength = max(length) + g:leaderGuide_hspace
call s:LOG.debug('maxlength is:' . maxlength)
if g:leaderGuide_vertical
let ret.n_rows = winheight(0) - 2
let ret.n_cols = ret.n_items / ret.n_rows + (ret.n_items != ret.n_rows)
let ret.col_width = maxlength
let ret.win_dim = ret.n_cols * ret.col_width
else
let ret.n_cols = winwidth(s:winid) >= maxlength ? winwidth(s:winid) / maxlength : 1
let ret.col_width = winwidth(s:winid) / ret.n_cols
let ret.n_rows = ret.n_items / ret.n_cols + (fmod(ret.n_items,ret.n_cols) > 0 ? 1 : 0)
let ret.win_dim = ret.n_rows
endif
call s:LOG.debug('layout is:' . string(ret))
return ret
endfunction " }}}
" icon -> number -> A-Za-z
" 65-90 97-122
function! s:get_key_number(key) abort
return char2nr(a:key ==# '[SPC]' ? ' ' : a:key ==? '<Tab>' ? "\t" : a:key)
endfunction
function! s:compare_key(i1, i2) abort
let a = s:get_key_number(a:i1)
let b = s:get_key_number(a:i2)
if a - b == 32 && a >= 97 && a <= 122
return -1
elseif b - a == 32 && b >= 97 && b <= 122
return 1
elseif a >= 97 && a <= 122 && b >= 97 && b <= 122
return a == b ? 0 : a > b ? 1 : -1
elseif a >= 65 && a <= 90 && b >= 65 && b <= 90
return a == b ? 0 : a > b ? 1 : -1
elseif a >= 97 && a <= 122 && b >= 65 && b <= 90
return s:compare_key(nr2char(a), nr2char(b + 32))
elseif a >= 65 && a <= 90 && b >= 97 && b <= 122
return s:compare_key(nr2char(a), nr2char(b - 32))
endif
return a == b ? 0 : a > b ? 1 : -1
endfunction
function! s:create_string(layout) abort " {{{
let l = a:layout
let l.capacity = l.n_rows * l.n_cols
let overcap = l.capacity - l.n_items
let overh = l.n_cols - overcap
let n_rows = l.n_rows - 1
let rows = []
let row = 0
let col = 0
let smap = sort(filter(keys(s:lmap), 'v:val !=# "name"'), function('s:compare_key'))
for k in smap
let offset = repeat(' ', 8 - strlen(k))
let desc = type(s:lmap[k]) == type({}) ? s:lmap[k].name : s:lmap[k][1]
if g:spacevim_leader_guide_theme == 'whichkey'
let displaystring = offset . k .' -> '.desc
else
let displaystring = offset . '['. k .'] '.desc
endif
let crow = get(rows, row, [])
if empty(crow)
call add(rows, crow)
endif
call add(crow, displaystring)
call add(crow, repeat(' ', l.col_width - strdisplaywidth(displaystring)))
if !g:leaderGuide_sort_horizontal
if row >= n_rows - 1
if overh > 0 && row < n_rows
let overh -= 1
let row += 1
else
let row = 0
let col += 1
endif
else
let row += 1
endif
else
if col == l.n_cols - 1
let row +=1
let col = 0
else
let col += 1
endif
endif
endfor
let r = []
let mlen = 0
for ro in rows
let line = join(ro, '')
call add(r, line)
if strdisplaywidth(line) > mlen
let mlen = strdisplaywidth(line)
endif
endfor
let output = join(r, "\n")
return output
endfunction " }}}
let s:VIMH = SpaceVim#api#import('vim#highlight')
function! s:highlight_cursor() abort
let info = {
\ 'name' : 'SpaceVimGuideCursor',
\ 'guibg' : synIDattr(synIDtrans(synID(line('.'), col('.'), 1)), 'guifg'),
\ 'guifg' : synIDattr(synIDtrans(synID(line('.'), col('.'), 1)), 'guibg'),
\ 'ctermbg' : synIDattr(synIDtrans(synID(line('.'), col('.'), 1)), 'ctermfg'),
\ 'ctermfg' : synIDattr(synIDtrans(synID(line('.'), col('.'), 1)), 'ctermbg'),
\ }
hi! def link SpaceVimGuideCursor Cursor
call s:VIMH.hi(info)
if s:vis ==# 'gv'
" [bufnum, lnum, col, off]
let begin = getpos("'<")
let end = getpos("'>")
if begin[1] == end[1]
let s:cursor_hi = s:CMP.matchaddpos('SpaceVimGuideCursor', [[begin[1], min([begin[2], end[2]]), abs(begin[2] - end[2]) + 1]])
else
let pos = [[begin[1], begin[2], len(getline(begin[1])) - begin[2] + 1],
\ [end[1], 1, end[2]],
\ ]
for lnum in range(begin[1] + 1, end[1] - 1)
call add(pos, [lnum, 1, len(getline(lnum))])
endfor
let s:cursor_hi = s:CMP.matchaddpos('SpaceVimGuideCursor', pos)
endif
else
let s:cursor_hi = s:CMP.matchaddpos('SpaceVimGuideCursor', [[line('.'), col('.'), 1]])
endif
endfunction
function! s:remove_cursor_highlight() abort
try
call matchdelete(s:cursor_hi)
catch
endtry
endfunction
" @vimlint(EVL102, 1, l:string)
function! s:start_buffer() abort " {{{
let s:winv = winsaveview()
let s:winnr = winnr()
let s:winres = winrestcmd()
let [s:winid, s:bufnr] = s:winopen()
let layout = s:calc_layout()
let string = s:create_string(layout)
if g:leaderGuide_max_size
let layout.win_dim = min([g:leaderGuide_max_size, layout.win_dim])
endif
call setbufvar(s:bufnr, '&modifiable', 1)
if s:FLOATING.exists()
let rst = s:FLOATING.win_config(s:winid,
\ {
\ 'relative': 'editor',
\ 'width' : &columns,
\ 'height' : layout.win_dim + 2,
\ 'row' : &lines - layout.win_dim - 4,
\ 'col' : 0
\ })
else
if g:leaderGuide_vertical
noautocmd execute 'vert res '.layout.win_dim
else
noautocmd execute 'res '.layout.win_dim
endif
endif
if s:FLOATING.exists()
" when using floating windows, and the flaating windows do not support
" statusline, add extra black line at top and button of the content.
call s:BUFFER.buf_set_lines(s:bufnr, 0, -1, 0, [''] + split(string, "\n") + [''])
else
call s:BUFFER.buf_set_lines(s:bufnr, 0, -1, 0, split(string, "\n"))
endif
call setbufvar(s:bufnr, '&modifiable', 0)
redraw!
call s:wait_for_input()
endfunction " }}}
" @vimlint(EVL102, 0, l:string)
function! s:handle_input(input) abort " {{{
call s:winclose()
if type(a:input) ==? type({})
let s:lmap = a:input
call s:start_buffer()
else
let s:prefix_key_inp = []
call feedkeys(s:vis.s:reg.s:count, 'ti')
redraw!
try
unsilent execute a:input[0]
catch
unsilent echom v:exception
endtry
endif
endfunction " }}}
" wait for in input sub function should be not block vim
function! s:wait_for_input() abort " {{{
redraw!
let inp = s:VIM.getchar()
if inp ==# "\<Esc>"
let s:prefix_key_inp = []
let s:undo_history = []
let s:guide_help_mode = 0
call s:winclose()
doautocmd WinEnter
elseif s:guide_help_mode ==# 1
call s:submode_mappings(inp)
let s:guide_help_mode = 0
elseif inp ==# "\<C-h>"
let s:guide_help_mode = 1
call s:updateStatusline()
redraw!
call s:wait_for_input()
else
if inp ==# ' '
let inp = '[SPC]'
else
let inp = s:KEY.char2name(inp)
endif
let fsel = get(s:lmap, inp)
if !empty(fsel)
call add(s:prefix_key_inp, inp)
call add(s:undo_history, s:lmap)
call s:handle_input(fsel)
else
call s:winclose()
doautocmd WinEnter
let keys = get(s:, 'prefix_key_inp', [])
let name = SpaceVim#mapping#leader#getName(s:prefix_key)
let _keys = join(keys, '-')
if empty(_keys)
call s:build_mpt(['key bindings is not defined: ', name . '-' . inp])
else
call s:build_mpt(['key bindings is not defined: ', name . '-' . _keys . '-' . inp])
endif
let s:prefix_key_inp = []
let s:guide_help_mode = 0
endif
endif
endfunction " }}}
function! s:build_mpt(mpt) abort
normal! :
echohl Comment
if type(a:mpt) == 1
echon a:mpt
elseif type(a:mpt) == 3
echon join(a:mpt)
endif
echohl NONE
endfunction
" change this func, do not focus to the new windows, and return winid.
function! s:winopen() abort " {{{
call s:highlight_cursor()
let pos = g:leaderGuide_position ==? 'topleft' ? 'topleft' : 'botright'
if s:FLOATING.exists()
if !bufexists(s:bufnr)
let s:bufnr = s:BUFFER.create_buf(v:false, v:true)
endif
let s:winid = s:FLOATING.open_win(s:bufnr, v:true,
\ {
\ 'relative': 'editor',
\ 'width' : &columns,
\ 'height' : 12,
\ 'row' : &lines - 14,
\ 'col' : 0
\ })
else
if bufexists(s:bufnr)
let qfbuf = &buftype ==# 'quickfix'
let splitcmd = g:leaderGuide_vertical ? ' 1vs' : ' 1sp'
noautocmd execute pos . splitcmd
let bnum = bufnr('%')
noautocmd execute 'buffer '.s:bufnr
cmapclear <buffer>
if qfbuf
noautocmd execute bnum.'bwipeout!'
endif
else
let splitcmd = g:leaderGuide_vertical ? ' 1vnew' : ' 1new'
noautocmd execute pos.splitcmd
let s:bufnr = bufnr('%')
augroup guide_autocmd
autocmd!
autocmd WinLeave <buffer> call s:winclose()
augroup END
endif
let s:winid = winnr()
endif
let s:guide_help_mode = 0
if exists('&winhighlight')
call s:VIM.setbufvar(s:bufnr, {
\ '&winhighlight' : 'Normal:Pmenu,Search:',
\ })
endif
call s:VIM.setbufvar(s:bufnr, {
\ '&filetype' : 'leaderGuide',
\ '&number' : 0,
\ '&relativenumber' : 0,
\ '&list' : 0,
\ '&modeline' : 0,
\ '&wrap' : 0,
\ '&buflisted' : 0,
\ '&buftype' : 'nofile',
\ '&bufhidden' : 'unload',
\ '&swapfile' : 0,
\ '&cursorline' : 0,
\ '&cursorcolumn' : 0,
\ '&colorcolumn' : '',
\ '&winfixwidth' : 1,
\ '&winfixheight' : 1,
\ })
" @fixme not sure if the listchars should be changed!
" setlocal listchars=
call s:updateStatusline()
call s:toggle_hide_cursor()
return [s:winid, s:bufnr]
endfunction " }}}
if s:SL.support_float()
function! s:updateStatusline() abort
call SpaceVim#mapping#guide#theme#hi()
let gname = get(s:guide_group, 'name', '')
if !empty(gname)
let gname = ' - ' . gname[1:]
" let gname = substitute(gname,' ', '\\ ', 'g')
endif
let keys = get(s:, 'prefix_key_inp', [])
" let keys = substitute(keys, '\', '\\\', 'g')
noautocmd let winid = s:SL.open_float([
\ ['Guide: ', 'LeaderGuiderPrompt'],
\ [' ', 'LeaderGuiderSep1'],
\ [SpaceVim#mapping#leader#getName(s:prefix_key)
\ . join(keys, '') . gname, 'LeaderGuiderName'],
\ [' ', 'LeaderGuiderSep2'],
\ [s:guide_help_msg(0), 'LeaderGuiderFill'],
\ [repeat(' ', 999), 'LeaderGuiderFill'],
\ ])
call SpaceVim#logger#debug('key binding guide float statusline winid:' . winid)
endfunction
function! s:close_float_statusline() abort
call SpaceVim#logger#debug('close float statusline winid:' . s:SL.__winid)
call s:SL.close_float()
endfunction
else
function! s:updateStatusline() abort
call SpaceVim#mapping#guide#theme#hi()
let gname = get(s:guide_group, 'name', '')
if !empty(gname)
let gname = ' - ' . gname[1:]
endif
let keys = get(s:, 'prefix_key_inp', [])
call setbufvar(s:bufnr, '&statusline', '%#LeaderGuiderPrompt# Guide: ' .
\ '%#LeaderGuiderSep1#' . s:lsep .
\ '%#LeaderGuiderName# ' .
\ SpaceVim#mapping#leader#getName(s:prefix_key)
\ . join(keys, '') . gname
\ . ' %#LeaderGuiderSep2#' . s:lsep . '%#LeaderGuiderFill#'
\ . s:guide_help_msg(0))
endfunction
endif
function! Test_st() abort
call s:updateStatusline()
endfunction
function! s:guide_help_msg(escape) abort
if s:guide_help_mode == 1
let msg = ' n -> next-page, p -> previous-page, u -> undo-key'
else
let msg = ' [C-h paging/help]'
endif
return a:escape ? substitute(msg,' ', '\\ ', 'g') : msg
endfunction
let s:t_ve = ''
function! s:toggle_hide_cursor() abort
let t_ve = &t_ve
let &t_ve = s:t_ve
let s:t_ve = t_ve
endfunction
function! s:winclose() abort " {{{
call s:toggle_hide_cursor()
if s:FLOATING.exists()
call s:FLOATING.win_close(s:winid, 1)
if s:SL.support_float()
call s:close_float_statusline()
endif
else
noautocmd execute s:winid.'wincmd w'
if s:winid == winnr()
noautocmd close
redraw!
exe s:winres
let s:winid = -1
noautocmd execute s:winnr.'wincmd w'
call winrestview(s:winv)
if exists('*nvim_open_win')
doautocmd WinEnter
endif
endif
endif
call s:remove_cursor_highlight()
endfunction " }}}
function! s:page_down() abort " {{{
call feedkeys("\<c-c>", 'n')
call feedkeys("\<c-d>", 'x')
redraw!
call s:wait_for_input()
endfunction " }}}
function! s:page_undo() abort " {{{
call s:winclose()
if len(s:prefix_key_inp) > 0
call remove(s:prefix_key_inp, -1)
endif
if len(s:undo_history) > 0
let s:lmap = remove(s:undo_history, -1)
endif
call s:start_buffer()
endfunction " }}}
function! s:page_up() abort " {{{
call feedkeys("\<c-c>", 'n')
call feedkeys("\<c-u>", 'x')
redraw!
call s:wait_for_input()
endfunction " }}}
function! s:handle_submode_mapping(cmd) abort " {{{
let s:guide_help_mode = 0
call s:updateStatusline()
if a:cmd ==# 'n'
call s:page_down()
elseif a:cmd ==# 'p'
call s:page_up()
elseif a:cmd ==# 'u'
call s:page_undo()
else
call s:winclose()
endif
endfunction " }}}
function! s:submode_mappings(key) abort " {{{
silent call s:handle_submode_mapping(a:key)
endfunction " }}}
function! s:mapmaparg(maparg) abort " {{{
let noremap = a:maparg.noremap ? 'noremap' : 'map'
let buffer = a:maparg.buffer ? '<buffer> ' : ''
let silent = a:maparg.silent ? '<silent> ' : ''
let nowait = a:maparg.nowait ? '<nowait> ' : ''
let st = a:maparg.mode . '' . noremap . ' ' . nowait . silent . buffer
\ . '' .a:maparg.lhs . ' ' . a:maparg.rhs
execute st
endfunction " }}}
function! s:get_register() abort "{{{
if match(&clipboard, 'unnamedplus') >= 0
let clip = '+'
elseif match(&clipboard, 'unnamed') >= 0
let clip = '*'
else
let clip = '"'
endif
return clip
endfunction "}}}
function! SpaceVim#mapping#guide#start_by_prefix(vis, key) abort " {{{
if a:key ==# ' ' && exists('b:spacevim_lang_specified_mappings')
let g:_spacevim_mappings_space.l = b:spacevim_lang_specified_mappings
endif
let s:guide_help_mode = 0
let s:vis = a:vis ? 'gv' : ''
let s:count = v:count != 0 ? v:count : ''
let s:toplevel = a:key ==? ' '
let s:prefix_key = a:key
let s:guide_group = {}
if has('nvim') && !exists('s:reg')
let s:reg = ''
else
let s:reg = v:register != s:get_register() ? '"'.v:register : ''
endif
if !has_key(s:cached_dicts, a:key) || g:leaderGuide_run_map_on_popup
"first run
let s:cached_dicts[a:key] = {}
call s:start_parser(a:key, s:cached_dicts[a:key])
endif
if has_key(s:desc_lookup, a:key) || has_key(s:desc_lookup , 'top')
let rundict = s:create_target_dict(a:key)
else
let rundict = s:cached_dicts[a:key]
endif
let s:lmap = rundict
call s:LOG.debug('lmap is:' . string(s:lmap))
call s:start_buffer()
endfunction " }}}
function! SpaceVim#mapping#guide#start(vis, dict) abort " {{{
let s:vis = a:vis ? 'gv' : 0
let s:lmap = a:dict
call s:start_buffer()
endfunction " }}}
function! SpaceVim#mapping#guide#register_displayname(lhs, name) abort
call extend(s:registered_name, {a:lhs : a:name})
endfunction
function! SpaceVim#mapping#guide#displayfunc() abort
if has_key(s:registered_name, g:leaderGuide#displayname)
return s:registered_name[g:leaderGuide#displayname]
endif
let g:leaderGuide#displayname = substitute(g:leaderGuide#displayname, '\c<cr>$', '', '')
endfunction
endif
if !exists('g:leaderGuide_displayfunc')
let g:leaderGuide_displayfunc = [function('SpaceVim#mapping#guide#displayfunc')]
endif
if get(g:, 'mapleader', '\') ==# ' '
call SpaceVim#mapping#guide#register_prefix_descriptions(' ',
\ 'g:_spacevim_mappings')
else
call SpaceVim#mapping#guide#register_prefix_descriptions(get(g:, 'mapleader', '\'),
\ 'g:_spacevim_mappings')
call SpaceVim#plugins#help#regist_root({'<Leader>' : g:_spacevim_mappings})
call SpaceVim#mapping#guide#register_prefix_descriptions(' ',
\ 'g:_spacevim_mappings_space')
call SpaceVim#plugins#help#regist_root({'SPC' : g:_spacevim_mappings_space})
endif
if !g:spacevim_vimcompatible && !empty(g:spacevim_windows_leader)
call SpaceVim#mapping#guide#register_prefix_descriptions(
\ g:spacevim_windows_leader,
\ 'g:_spacevim_mappings_windows')
call SpaceVim#plugins#help#regist_root({'[WIN]' : g:_spacevim_mappings_windows})
endif
call SpaceVim#mapping#guide#register_prefix_descriptions(
\ '[KEYs]',
\ 'g:_spacevim_mappings_prefixs')
call SpaceVim#mapping#guide#register_prefix_descriptions(
\ 'g',
\ 'g:_spacevim_mappings_g')
call SpaceVim#plugins#help#regist_root({'[g]' : g:_spacevim_mappings_g})
call SpaceVim#mapping#guide#register_prefix_descriptions(
\ 'z',
\ 'g:_spacevim_mappings_z')
call SpaceVim#plugins#help#regist_root({'[z]' : g:_spacevim_mappings_z})
let [s:lsep, s:rsep] = SpaceVim#layers#core#statusline#rsep()
let &cpo = s:save_cpo
unlet s:save_cpo
" vim:set et sw=2 cc=80: