From 80ac875d93508e858fb357e4decb038ba61c6207 Mon Sep 17 00:00:00 2001 From: wsdjeg Date: Tue, 14 Mar 2017 00:57:16 +0800 Subject: [PATCH] Add mapping guide --- autoload/SpaceVim.vim | 74 ++++ autoload/SpaceVim/layers/core.vim | 1 - autoload/SpaceVim/mapping/guide.vim | 487 +++++++++++++++++++++++++++ autoload/SpaceVim/mapping/leader.vim | 1 - config/plugins/vim-airline.vim | 12 + config/plugins/vim-leader-guide.vim | 8 + syntax/leaderGuide.vim | 15 + 7 files changed, 596 insertions(+), 2 deletions(-) create mode 100644 autoload/SpaceVim/mapping/guide.vim create mode 100644 config/plugins/vim-leader-guide.vim create mode 100644 syntax/leaderGuide.vim diff --git a/autoload/SpaceVim.vim b/autoload/SpaceVim.vim index 238a5a41f..f2e99438f 100644 --- a/autoload/SpaceVim.vim +++ b/autoload/SpaceVim.vim @@ -257,6 +257,80 @@ let g:spacevim_wildignore \ = '*/tmp/*,*.so,*.swp,*.zip,*.class,tags,*.jpg, \*.ttf,*.TTF,*.png,*/target/*, \.git,.svn,.hg,.DS_Store,*.svg' +" privite options +let g:_spacevim_mappings = {} +"==== + +if exists('loaded_leaderGuide_vim') || &cp + finish +endif +let loaded_leaderGuide_vim = 1 + +let s:save_cpo = &cpo +set cpo&vim + +if !exists('g:leaderGuide_vertical') + let g:leaderGuide_vertical = 0 +endif + +if !exists('g:leaderGuide_sort_horizontal') + let g:leaderGuide_sort_horizontal = 0 +endif + +if !exists('g:leaderGuide_position') + let g:leaderGuide_position = 'botright' +endif + +if !exists('g:leaderGuide_run_map_on_popup') + let g:leaderGuide_run_map_on_popup = 1 +endif + +if !exists("g:leaderGuide_hspace") + let g:leaderGuide_hspace = 5 +endif + +if !exists("g:leaderGuide_flatten") + let g:leaderGuide_flatten = 1 +endif + +if !exists("g:leaderGuide_default_group_name") + let g:leaderGuide_default_group_name = "" +endif + +if !exists("g:leaderGuide_max_size") + let g:leaderGuide_max_size = 0 +endif + +if !exists("g:leaderGuide_submode_mappings") + let g:leaderGuide_submode_mappings = {'': "win_close"} +endif + +if !exists("g:leaderGuide_displayfunc") + function! s:leaderGuide_display() + let g:leaderGuide#displayname = substitute(g:leaderGuide#displayname, '\c$', '', '') + endfunction + let g:leaderGuide_displayfunc = [function("s:leaderGuide_display")] +endif + +if !SpaceVim#mapping#guide#has_configuration() + let g:leaderGuide_map = {} + call SpaceVim#mapping#guide#register_prefix_descriptions('', 'g:leaderGuide_map') +endif + +command -nargs=1 LeaderGuideD call SpaceVim#mapping#guide#start('0', ) +command -range -nargs=1 LeaderGuideVisualD call SpaceVim#mapping#guide#start('1', ) + +command -nargs=1 LeaderGuide call SpaceVim#mapping#guide#start_by_prefix('0', ) +command -range -nargs=1 LeaderGuideVisual call SpaceVim#mapping#guide#start_by_prefix('1', ) + +nnoremap leaderguide-buffer :call leaderGuide#start_by_prefix('0', '') +vnoremap leaderguide-buffer :call leaderGuide#start_by_prefix('1', '') +nnoremap leaderguide-global :call leaderGuide#start_by_prefix('0', ' ') +vnoremap leaderguide-global :call leaderGuide#start_by_prefix('1', ' ') + +let &cpo = s:save_cpo +unlet s:save_cpo +"==== function! SpaceVim#loadCustomConfig() abort let custom_confs_old = SpaceVim#util#globpath(getcwd(), '.local.vim') diff --git a/autoload/SpaceVim/layers/core.vim b/autoload/SpaceVim/layers/core.vim index b52f6805e..1835d85e8 100644 --- a/autoload/SpaceVim/layers/core.vim +++ b/autoload/SpaceVim/layers/core.vim @@ -1,7 +1,6 @@ function! SpaceVim#layers#core#plugins() abort return [ \ ['Shougo/vimproc.vim', {'build' : 'make'}], - \ ['hecal3/vim-leader-guide', {'loadconf': 1, 'loadconf_before' : 1, 'merged' : 0}], \ ['benizi/vim-automkdir'], \ ['airblade/vim-rooter'], \ ] diff --git a/autoload/SpaceVim/mapping/guide.vim b/autoload/SpaceVim/mapping/guide.vim new file mode 100644 index 000000000..0078fa5d1 --- /dev/null +++ b/autoload/SpaceVim/mapping/guide.vim @@ -0,0 +1,487 @@ +"============================================================================= +" guide.vim --- mappings guide helper for SpaceVim +" Copyright (c) 2016-2017 Shidong Wang & Contributors +" Author: Shidong Wang < wsdjeg at 163.com > +" URL: https://spacevim.org +" License: MIT license +"============================================================================= + +let s:save_cpo = &cpo +set cpo&vim + +function! SpaceVim#mapping#guide#has_configuration() "{{{ + return exists('s:desc_lookup') +endfunction "}}} + +function! SpaceVim#mapping#guide#register_prefix_descriptions(key, dictname) " {{{ + let key = a:key ==? '' ? ' ' : a:key + if !exists('s:desc_lookup') + call s:create_cache() + endif + if strlen(key) == 0 + let s:desc_lookup['top'] = a:dictname + return + endif + if !has_key(s:desc_lookup, key) + let s:desc_lookup[key] = a:dictname + endif +endfunction "}}} +function! s:create_cache() " {{{ + let s:desc_lookup = {} + let s:cached_dicts = {} +endfunction " }}} +function! s:create_target_dict(key) " {{{ + if has_key(s:desc_lookup, 'top') + 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) " {{{ + 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 " }}} + +function! SpaceVim#mapping#guide#populate_dictionary(key, dictname) " {{{ + call s:start_parser(a:key, s:cached_dicts[a:key]) +endfunction " }}} +function! SpaceVim#mapping#guide#parse_mappings() " {{{ + for [k, v] in items(s:cached_dicts) + call s:start_parser(k, v) + endfor +endfunction " }}} + + +function! s:start_parser(key, dict) " {{{ + let key = a:key ==? ' ' ? "" : a:key + let readmap = "" + redir => readmap + silent execute 'map '.key + redir END + 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 =~ '.*' || mapd.lhs =~ '.*' + continue + endif + let mapd.display = s:format_displaystring(mapd.rhs) + let mapd.lhs = substitute(mapd.lhs, key, "", "") + let mapd.lhs = substitute(mapd.lhs, "", " ", "g") + let mapd.lhs = substitute(mapd.lhs, "", "", "g") + let mapd.rhs = substitute(mapd.rhs, "", "".mapd['sid']."_", "g") + if mapd.lhs != '' && mapd.display !~# 'LeaderGuide.*' + if (visual && match(mapd.mode, "[vx ]") >= 0) || + \ (!visual && match(mapd.mode, "[vx]") == -1) + let mapd.lhs = s:string_to_keys(mapd.lhs) + call s:add_map_to_dict(mapd, 0, a:dict) + endif + endif + endfor +endfunction " }}} + +function! s:add_map_to_dict(map, level, dict) " {{{ + 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 " }}} +function! s:format_displaystring(map) " {{{ + 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 " }}} +function! s:flattenmap(dict, str) " {{{ + 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({}) + let strcall = a:str.kv + call extend(ret, s:flattenmap(a:dict[kv], a:str.kv)) + endif + endfor + return ret +endfunction " }}} + + +function! s:escape_mappings(mapping) " {{{ + let feedkeyargs = a:mapping.noremap ? "nt" : "mt" + let rstring = substitute(a:mapping.rhs, '\', '\\\\', 'g') + let rstring = substitute(rstring, '<\([^<>]*\)>', '\\<\1>', 'g') + let rstring = substitute(rstring, '"', '\\"', 'g') + let rstring = 'call feedkeys("'.rstring.'", "'.feedkeyargs.'")' + return rstring +endfunction " }}} +function! s:string_to_keys(input) " {{{ + " Avoid special case: <> + if match(a:input, '<.\+>') != -1 + let retlist = [] + let si = 0 + let go = 1 + while si < len(a:input) + if go + call add(retlist, a:input[si]) + else + let retlist[-1] .= a:input[si] + endif + if a:input[si] ==? '<' + let go = 0 + elseif a:input[si] ==? '>' + let go = 1 + end + let si += 1 + endw + return retlist + else + return split(a:input, '\zs') + endif +endfunction " }}} +function! s:escape_keys(inp) " {{{ + let ret = substitute(a:inp, "<", "", "") + return substitute(ret, "|", "", "") +endfunction " }}} +function! s:show_displayname(inp) " {{{ + if has_key(s:displaynames, toupper(a:inp)) + return s:displaynames[toupper(a:inp)] + else + return a:inp + end +endfunction " }}} +" displaynames {{{1 " +let s:displaynames = {'': '', + \ '': ''} +" 1}}} " + + +function! s:calc_layout() " {{{ + let ret = {} + let smap = filter(copy(s:lmap), 'v:key !=# "name"') + let ret.n_items = len(smap) + let length = values(map(smap, + \ 'strdisplaywidth("[".v:key."]".'. + \ '(type(v:val) == type({}) ? v:val["name"] : v:val[1]))')) + let maxlength = max(length) + g:leaderGuide_hspace + 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(0) / maxlength + let ret.col_width = winwidth(0) / 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 + "echom string(ret) + endif + return ret +endfunction " }}} +function! s:create_string(layout) " {{{ + 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"'),'1') + for k in smap + let desc = type(s:lmap[k]) == type({}) ? s:lmap[k].name : s:lmap[k][1] + let displaystring = "[".s:show_displayname(k)."] ".desc + 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 + silent execute "cnoremap ".substitute(k, "|", "", ""). " " . s:escape_keys(k) ."" + 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 + call insert(r, '') + let output = join(r, "\n ") + cnoremap + cnoremap submode + return output +endfunction " }}} + + +function! s:start_buffer() " {{{ + let s:winv = winsaveview() + let s:winnr = winnr() + let s:winres = winrestcmd() + call 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 + + setlocal modifiable + if g:leaderGuide_vertical + noautocmd execute 'vert res '.layout.win_dim + else + noautocmd execute 'res '.layout.win_dim + endif + silent 1put!=string + normal! ggdd + setlocal nomodifiable + call s:wait_for_input() +endfunction " }}} +function! s:handle_input(input) " {{{ + call s:winclose() + if type(a:input) ==? type({}) + let s:lmap = a:input + call s:start_buffer() + else + call feedkeys(s:vis.s:reg.s:count, 'ti') + redraw + try + unsilent execute a:input[0] + catch + unsilent echom v:exception + endtry + endif +endfunction " }}} +function! s:wait_for_input() " {{{ + redraw + let inp = input("") + if inp ==? '' + call s:winclose() + elseif match(inp, "^submode") == 0 + call s:submode_mappings() + else + let fsel = get(s:lmap, inp) + call s:handle_input(fsel) + endif +endfunction " }}} +function! s:winopen() " {{{ + if !exists('s:bufnr') + let s:bufnr = -1 + endif + let pos = g:leaderGuide_position ==? 'topleft' ? 'topleft' : 'botright' + 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 + if qfbuf + noautocmd execute bnum.'bwipeout!' + endif + else + let splitcmd = g:leaderGuide_vertical ? ' 1vnew' : ' 1new' + noautocmd execute pos.splitcmd + let s:bufnr = bufnr('%') + autocmd WinLeave call s:winclose() + endif + let s:gwin = winnr() + setlocal filetype=leaderGuide + setlocal nonumber norelativenumber nolist nomodeline nowrap + setlocal nobuflisted buftype=nofile bufhidden=unload noswapfile + setlocal nocursorline nocursorcolumn colorcolumn= + setlocal winfixwidth winfixheight + setlocal statusline=\ Leader\ Guide +endfunction " }}} +function! s:winclose() " {{{ + noautocmd execute s:gwin.'wincmd w' + if s:gwin == winnr() + close + exe s:winres + let s:gwin = -1 + noautocmd execute s:winnr.'wincmd w' + call winrestview(s:winv) + endif + redraw +endfunction " }}} +function! s:page_down() " {{{ + call feedkeys("\", "n") + call feedkeys("\", "x") + call s:wait_for_input() +endfunction " }}} +function! s:page_up() " {{{ + call feedkeys("\", "n") + call feedkeys("\", "x") + call s:wait_for_input() +endfunction " }}} + +function! s:handle_submode_mapping(cmd) " {{{ + if a:cmd ==? 'page_down' + call s:page_down() + elseif a:cmd ==? 'page_up' + call s:page_up() + elseif a:cmd ==? 'win_close' + call s:winclose() + endif +endfunction " }}} +function! s:submode_mappings() " {{{ + let submodestring = "" + let maplist = [] + for key in items(g:leaderGuide_submode_mappings) + let map = maparg(key[0], "c", 0, 1) + if !empty(map) + call add(maplist, map) + endif + execute 'cnoremap '.key[0].' '.key[1].'' + let submodestring = submodestring.' '.key[0].': '.key[1].',' + endfor + let inp = input(strpart(submodestring, 0, strlen(submodestring)-1)) + for map in maplist + call s:mapmaparg(map) + endfor + silent call s:handle_submode_mapping(inp) +endfunction " }}} +function! s:mapmaparg(maparg) " {{{ + let noremap = a:maparg.noremap ? 'noremap' : 'map' + let buffer = a:maparg.buffer ? ' ' : '' + let silent = a:maparg.silent ? ' ' : '' + let nowait = a:maparg.nowait ? ' ' : '' + let st = a:maparg.mode.''.noremap.' '.nowait.silent.buffer.''.a:maparg.lhs.' '.a:maparg.rhs + execute st +endfunction " }}} + +function! s:get_register() "{{{ + 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) " {{{ + let s:vis = a:vis ? 'gv' : '' + let s:count = v:count != 0 ? v:count : '' + let s:toplevel = a:key ==? ' ' + + 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:start_buffer() +endfunction " }}} +function! SpaceVim#mapping#guide#start(vis, dict) " {{{ + let s:vis = a:vis ? 'gv' : 0 + let s:lmap = a:dict + call s:start_buffer() +endfunction " }}} + +let &cpo = s:save_cpo +unlet s:save_cpo + +" vim:set et sw=2 cc=80: diff --git a/autoload/SpaceVim/mapping/leader.vim b/autoload/SpaceVim/mapping/leader.vim index f98b2f333..b4c4bf306 100644 --- a/autoload/SpaceVim/mapping/leader.vim +++ b/autoload/SpaceVim/mapping/leader.vim @@ -1,6 +1,5 @@ function! SpaceVim#mapping#leader#defindglobalMappings() abort inoremap =MyLeaderTabfunc() - nnoremap @=((foldclosed(line('.')) < 0) ? 'zc' : 'zo') "for buftabs noremap bp :bprev diff --git a/config/plugins/vim-airline.vim b/config/plugins/vim-airline.vim index 977d98724..bfa69659c 100644 --- a/config/plugins/vim-airline.vim +++ b/config/plugins/vim-airline.vim @@ -49,6 +49,18 @@ nmap 8 AirlineSelectTab8 nmap 9 AirlineSelectTab9 nmap - AirlineSelectPrevTab nmap + AirlineSelectNextTab +let g:_spacevim_mappings.1 = ['', 'window 1'] +let g:_spacevim_mappings.2 = ['', 'window 2'] +let g:_spacevim_mappings.3 = ['', 'window 3'] +let g:_spacevim_mappings.4 = ['', 'window 4'] +let g:_spacevim_mappings.5 = ['', 'window 5'] +let g:_spacevim_mappings.6 = ['', 'window 6'] +let g:_spacevim_mappings.7 = ['', 'window 7'] +let g:_spacevim_mappings.8 = ['', 'window 8'] +let g:_spacevim_mappings.9 = ['', 'window 9'] +let g:_spacevim_mappings.1 = ['', 'window 1'] +let g:_spacevim_mappings['-'] = ['', 'previous window'] +let g:_spacevim_mappings['+'] = ['', 'next window'] if !exists('g:airline_symbols') let g:airline_symbols = {} endif diff --git a/config/plugins/vim-leader-guide.vim b/config/plugins/vim-leader-guide.vim new file mode 100644 index 000000000..ae99a21b5 --- /dev/null +++ b/config/plugins/vim-leader-guide.vim @@ -0,0 +1,8 @@ +let g:leaderGuide_max_size = 15 +let g:leaderGuide_submode_mappings = + \ { '': 'win_close', '': 'page_down', '': 'page_up'} +let g:_spacevim_mappings.g = {'name' : 'git function', + \ 'd' : ['Gita diff', 'git diff'], + \ } +call leaderGuide#register_prefix_descriptions("\\", 'g:_spacevim_mappings') +call leaderGuide#register_prefix_descriptions("[unite]", 'g:_spacevim_unite_mappings') diff --git a/syntax/leaderGuide.vim b/syntax/leaderGuide.vim new file mode 100644 index 000000000..0653f522c --- /dev/null +++ b/syntax/leaderGuide.vim @@ -0,0 +1,15 @@ +if exists("b:current_syntax") + finish +endif +let b:current_syntax = "leaderguide" + +syn region LeaderGuideKeys start="\["hs=e+1 end="\]\s"he=s-1 + \ contained +syn region LeaderGuideBrackets start="\(^\|\s\+\)\[" end="\]\s\+" + \ contains=LeaderGuideKeys keepend +syn region LeaderGuideDesc start="^" end="$" + \ contains=LeaderGuideBrackets + +hi def link LeaderGuideDesc Identifier +hi def link LeaderGuideKeys Type +hi def link LeaderGuideBrackets Delimiter