829 lines
23 KiB
VimL
829 lines
23 KiB
VimL
"======================================================================
|
|
"
|
|
" menu.vim - main menu bar
|
|
"
|
|
" Created by skywind on 2019/12/24
|
|
" Last Modified: 2019/12/30 01:14
|
|
"
|
|
"======================================================================
|
|
|
|
" vim: set noet fenc=utf-8 ff=unix sts=4 sw=4 ts=4 :
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" namespace of configuration
|
|
"----------------------------------------------------------------------
|
|
let s:namespace = { 'system':{'config':{}, 'weight':100, 'index':0} }
|
|
let s:name = 'system'
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" switch config namespace
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#switch(name)
|
|
if !has_key(s:namespace, a:name)
|
|
let s:namespace[a:name] = {}
|
|
let s:namespace[a:name].config = {}
|
|
let s:namespace[a:name].index = 0
|
|
let s:namespace[a:name].weight = 100
|
|
endif
|
|
let s:name = a:name
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" clear all entries in current namespace
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#reset()
|
|
let current = s:namespace[s:name].config
|
|
let s:namespace[s:name].weight = 100
|
|
let s:namespace[s:name].index = 0
|
|
for key in keys(current)
|
|
call remove(current, key)
|
|
endfor
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" register entry: (section='File', entry='&Save', command='w')
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#register(section, entry, command, help)
|
|
let current = s:namespace[s:name].config
|
|
if !has_key(current, a:section)
|
|
let index = 0
|
|
let maximum = 0
|
|
for name in keys(current)
|
|
let w = current[name].weight
|
|
let maximum = (index == 0)? w : ((maximum < w)? w : maximum)
|
|
let index += 1
|
|
endfor
|
|
let current[a:section] = {'name':a:section, 'weight':0, 'items':[]}
|
|
let current[a:section].ft = ''
|
|
let current[a:section].weight = s:namespace[s:name].weight
|
|
let s:namespace[s:name].weight += 10
|
|
endif
|
|
let menu = current[a:section]
|
|
let item = {'name':a:entry, 'cmd':a:command, 'help':a:help}
|
|
let menu.items += [item]
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" remove entry:
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#remove(section, index)
|
|
let current = s:namespace[s:name].config
|
|
if !has_key(current, a:section)
|
|
return -1
|
|
endif
|
|
let menu = current[a:section]
|
|
if type(a:index) == v:t_number
|
|
let index = (a:index < 0)? (len(menu.items) + a:index) : a:index
|
|
if index < 0 || index >= len(menu.items)
|
|
return -1
|
|
endif
|
|
call remove(menu.items, index)
|
|
elseif type(a:index) == v:t_string
|
|
if a:index ==# '*'
|
|
menu.items = []
|
|
else
|
|
let index = -1
|
|
for ii in range(len(menu.items))
|
|
if menu.items[ii].name ==# a:index
|
|
let index = ii
|
|
break
|
|
endif
|
|
endfor
|
|
if index < 0
|
|
return -1
|
|
endif
|
|
call remove(menu.items, index)
|
|
endif
|
|
endif
|
|
return 0
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" return items key
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#section(section)
|
|
let current = s:namespace[s:name].config
|
|
return get(current, a:section, v:null)
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" install a how section
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#install(section, content, ...)
|
|
let current = s:namespace[s:name].config
|
|
if a:0 > 2 && (a:3 != 0)
|
|
while 1
|
|
if quickui#menu#remove(a:section, 0) != 0
|
|
break
|
|
endif
|
|
endwhile
|
|
endif
|
|
if type(a:content) == v:t_list
|
|
for item in a:content
|
|
if type(item) == v:t_dict
|
|
call quickui#menu#register(a:section, item.name, item.command)
|
|
elseif type(item) == v:t_list
|
|
let size = len(item)
|
|
let name = (size >= 1)? item[0] : ''
|
|
let cmd = (size >= 2)? item[1] : ''
|
|
let help = (size >= 3)? item[2] : ''
|
|
call quickui#menu#register(a:section, name, cmd, help)
|
|
elseif type(item) == v:t_string
|
|
call quickui#menu#register(a:section, item, '', '')
|
|
endif
|
|
endfor
|
|
elseif type(a:content) == v:t_dict
|
|
for name in keys(a:content)
|
|
let cmd = a:content[name]
|
|
call quickui#menu#register(a:section, name, cmd, '')
|
|
endfor
|
|
endif
|
|
if a:0 > 0 && has_key(current, a:section)
|
|
if type(a:1) == v:t_number
|
|
let current[a:section].weight = a:1
|
|
endif
|
|
endif
|
|
if a:0 > 1 && has_key(current, a:section)
|
|
let current[a:section].ft = a:2
|
|
endif
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" clear all entries in current namespace
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#clear(section)
|
|
let current = s:namespace[s:name].config
|
|
if has_key(current, a:section)
|
|
call remove(current, a:section)
|
|
endif
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" change weight
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#change_weight(section, weight)
|
|
let current = s:namespace[s:name].config
|
|
if has_key(current, a:section)
|
|
let current[a:section].weight = a:weight
|
|
endif
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" change file types
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#change_ft(section, ft)
|
|
let current = s:namespace[s:name].config
|
|
if has_key(current, a:section)
|
|
let current[a:section].ft = a:ft
|
|
endif
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" preset menu
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#preset(section, context, ...)
|
|
let current = s:namespace[s:name].config
|
|
let save_items = []
|
|
if has_key(current, a:section)
|
|
let save_items = current[a:section].items
|
|
let current[a:section].items = []
|
|
endif
|
|
if a:0 == 0
|
|
call quickui#menu#install(a:section, a:context)
|
|
else
|
|
call quickui#menu#install(a:section, a:context, a:1)
|
|
endif
|
|
if len(save_items) > 0
|
|
if len(a:context) > 0
|
|
call quickui#menu#register(a:section, '--', '', '')
|
|
endif
|
|
for ni in save_items
|
|
call quickui#menu#register(a:section, ni.name, ni.cmd, ni.help)
|
|
endfor
|
|
endif
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" compare section
|
|
"----------------------------------------------------------------------
|
|
function! s:section_compare(s1, s2)
|
|
if a:s1[0] == a:s2[0]
|
|
return 0
|
|
else
|
|
return (a:s1[0] > a:s2[0])? 1 : -1
|
|
endif
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" get section
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#available(name)
|
|
let current = s:namespace[a:name].config
|
|
let menus = []
|
|
let callback = get(g:, 'quickui_menu_filter', '')
|
|
let F = (callback != '')? function(callback) : ''
|
|
for name in keys(current)
|
|
let menu = current[name]
|
|
if menu.ft != ''
|
|
let fts = split(menu.ft, ',')
|
|
if index(fts, &ft) < 0
|
|
continue
|
|
endif
|
|
endif
|
|
if callback != ''
|
|
if F(menu.name) == 0
|
|
continue
|
|
endif
|
|
endif
|
|
if len(menu.items) > 0
|
|
let menus += [[menu.weight, menu.name]]
|
|
endif
|
|
endfor
|
|
call sort(menus, 's:section_compare')
|
|
let result = []
|
|
for obj in menus
|
|
let result += [obj[1]]
|
|
endfor
|
|
return result
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" parse
|
|
"----------------------------------------------------------------------
|
|
function! s:parse_menu(name, padding)
|
|
let current = s:namespace[a:name].config
|
|
let inst = {'items':[], 'text':'', 'width':0, 'hotkey':{}}
|
|
let start = 0
|
|
let split = repeat(' ', a:padding)
|
|
let names = quickui#menu#available(a:name)
|
|
let index = 0
|
|
let size = len(names)
|
|
for section in names
|
|
let menu = current[section]
|
|
let item = {'name':menu.name, 'text':''}
|
|
let obj = quickui#core#escape(menu.name)
|
|
let item.text = ' ' . obj[0] . ' '
|
|
let item.key_char = obj[1]
|
|
let item.key_pos = (obj[4] < 0)? -1 : (obj[4] + 1)
|
|
let item.x = start
|
|
let item.w = strwidth(item.text)
|
|
let start += item.w + strwidth(split)
|
|
let inst.items += [item]
|
|
let inst.text .= item.text . ((index + 1 < size)? split : '')
|
|
if item.key_pos >= 0
|
|
let key = tolower(item.key_char)
|
|
let inst.hotkey[key] = index
|
|
endif
|
|
let index += 1
|
|
endfor
|
|
let inst.width = strwidth(inst.text)
|
|
return inst
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" internal
|
|
"----------------------------------------------------------------------
|
|
let s:cmenu = {'state':0, 'index':0, 'size':0, 'winid':-1, 'drop':-1}
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" create popup ui
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#create(opts)
|
|
if s:cmenu.state != 0
|
|
return -1
|
|
endif
|
|
let name = get(a:opts, 'name', s:name)
|
|
if !has_key(s:namespace, name)
|
|
return -1
|
|
endif
|
|
let current = s:namespace[name].config
|
|
let s:cmenu.inst = s:parse_menu(name, 2)
|
|
if s:cmenu.inst.width + 5 >= &columns
|
|
let s:cmenu.inst = s:parse_menu(name, 1)
|
|
if s:cmenu.inst.width + 5 >= &columns
|
|
let s:cmenu.inst = s:parse_menu(name, 0)
|
|
endif
|
|
endif
|
|
let s:cmenu.name = name
|
|
let s:cmenu.index = s:namespace[name].index
|
|
let s:cmenu.width = &columns
|
|
let s:cmenu.size = len(s:cmenu.inst.items)
|
|
let s:cmenu.current = current
|
|
let winid = popup_create([s:cmenu.inst.text], {'hidden':1, 'wrap':0})
|
|
let bufnr = winbufnr(winid)
|
|
let s:cmenu.winid = winid
|
|
let s:cmenu.bufnr = bufnr
|
|
let s:cmenu.cfg = deepcopy(a:opts)
|
|
let w = s:cmenu.width
|
|
let opts = {"minwidth":w, "maxwidth":w, "minheight":1, "maxheight":1}
|
|
let opts.line = 1
|
|
let opts.col = 1
|
|
call popup_move(winid, opts)
|
|
call setwinvar(winid, '&wincolor', get(a:opts, 'color', 'QuickBG'))
|
|
let opts = {'mapping':0, 'cursorline':0, 'drag':0, 'zindex':31000}
|
|
let opts.border = [0,0,0,0,0,0,0,0,0]
|
|
let opts.padding = [0,0,0,0]
|
|
let opts.filter = 'quickui#menu#filter'
|
|
let opts.callback = 'quickui#menu#callback'
|
|
if 1
|
|
let keymap = quickui#utils#keymap()
|
|
let s:cmenu.keymap = keymap
|
|
endif
|
|
let s:cmenu.hotkey = s:cmenu.inst.hotkey
|
|
" echo "hotkey: ". string(s:cmenu.hotkey)
|
|
let s:cmenu.drop = -1
|
|
let s:cmenu.state = 1
|
|
let s:cmenu.context = -1
|
|
call popup_setoptions(winid, opts)
|
|
call quickui#menu#update()
|
|
call popup_show(winid)
|
|
return 0
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" render menu
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#update()
|
|
let winid = s:cmenu.winid
|
|
if s:cmenu.state == 0
|
|
return -1
|
|
endif
|
|
let inst = s:cmenu.inst
|
|
let cmdlist = ['syn clear']
|
|
let index = 0
|
|
for item in inst.items
|
|
if item.key_pos >= 0
|
|
let x = item.key_pos + item.x + 1
|
|
let cmd = quickui#core#high_region('QuickKey', 1, x, 1, x + 1, 1)
|
|
let cmdlist += [cmd]
|
|
endif
|
|
let index += 1
|
|
endfor
|
|
let index = s:cmenu.index
|
|
if index >= 0 && index < s:cmenu.size
|
|
let x = inst.items[index].x + 1
|
|
let e = x + inst.items[index].w
|
|
let cmd = quickui#core#high_region('QuickSel', 1, x, 1, e, 1)
|
|
let cmdlist += [cmd]
|
|
endif
|
|
call quickui#core#win_execute(winid, cmdlist)
|
|
return 0
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" close menu
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#close()
|
|
if s:cmenu.state != 0
|
|
call popup_close(s:cmenu.winid)
|
|
let s:cmenu.winid = -1
|
|
let s:cmenu.state = 0
|
|
endif
|
|
endfunc
|
|
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" exit callback
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#callback(winid, code)
|
|
" echom "quickui#menu#callback"
|
|
let s:cmenu.state = 0
|
|
let s:cmenu.winid = -1
|
|
let s:namespace[s:cmenu.name].index = s:cmenu.index
|
|
if s:cmenu.context >= 0
|
|
call popup_close(s:cmenu.context, -3)
|
|
let s:cmenu.context = -1
|
|
endif
|
|
redraw
|
|
echo ""
|
|
redraw
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" event handler
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#filter(winid, key)
|
|
let keymap = s:cmenu.keymap
|
|
if a:key == "\<ESC>" || a:key == "\<c-c>"
|
|
call popup_close(a:winid, -1)
|
|
return 1
|
|
elseif a:key == "\<LeftMouse>"
|
|
return s:mouse_click()
|
|
elseif has_key(s:cmenu.hotkey, a:key)
|
|
let index = s:cmenu.hotkey[a:key]
|
|
let index = (index < 0)? (s:cmenu.size - 1) : index
|
|
let index = (index >= s:cmenu.size)? 0 : index
|
|
let s:cmenu.index = (s:cmenu.size == 0)? 0 : index
|
|
call quickui#menu#update()
|
|
call s:context_dropdown()
|
|
redraw
|
|
elseif has_key(keymap, a:key)
|
|
let key = keymap[a:key]
|
|
call s:movement(key)
|
|
redraw
|
|
return 1
|
|
endif
|
|
return 1
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" moving
|
|
"----------------------------------------------------------------------
|
|
function! s:movement(key)
|
|
if a:key == 'ESC'
|
|
if g:quickui#core#has_nvim == 0
|
|
call popup_close(s:cmenu.winid, -1)
|
|
endif
|
|
return 1
|
|
elseif a:key == 'LEFT' || a:key == 'RIGHT'
|
|
let index = s:cmenu.index
|
|
if index < 0
|
|
let index = 0
|
|
elseif a:key == 'LEFT'
|
|
let index -= 1
|
|
elseif a:key == 'RIGHT'
|
|
let index += 1
|
|
endif
|
|
let index = (index < 0)? (s:cmenu.size - 1) : index
|
|
let index = (index >= s:cmenu.size)? 0 : index
|
|
let s:cmenu.index = (s:cmenu.size == 0)? 0 : index
|
|
call quickui#menu#update()
|
|
" echo "MOVE: " . index
|
|
elseif a:key == 'PAGEUP' || a:key == 'PAGEDOWN'
|
|
let index = (a:key == 'PAGEUP')? 0 : (s:cmenu.size - 1)
|
|
let s:cmenu.index = (s:cmenu.size == 0)? 0 : index
|
|
call quickui#menu#update()
|
|
elseif a:key == 'ENTER' || a:key == 'DOWN'
|
|
if g:quickui#core#has_nvim == 0
|
|
call s:context_dropdown()
|
|
else
|
|
return s:neovim_dropdown()
|
|
endif
|
|
endif
|
|
return 0
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" mouse click
|
|
"----------------------------------------------------------------------
|
|
function! s:mouse_click()
|
|
let pos = getmousepos()
|
|
if pos.winid != s:cmenu.winid || pos.line != 1
|
|
call popup_close(s:cmenu.winid, -1)
|
|
return 0
|
|
endif
|
|
let x = pos.wincol - 1
|
|
let index = 0
|
|
let select = -1
|
|
for item in s:cmenu.inst.items
|
|
if x >= item.x && x < item.x + item.w
|
|
let select = index
|
|
endif
|
|
let index += 1
|
|
endfor
|
|
if select >= 0
|
|
let s:cmenu.index = select
|
|
if s:cmenu.context >= 0
|
|
call popup_close(s:cmenu.index, -1)
|
|
let s:cmenu.context = -1
|
|
endif
|
|
call quickui#menu#update()
|
|
call s:context_dropdown()
|
|
redraw
|
|
endif
|
|
return 1
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" drop down context
|
|
"----------------------------------------------------------------------
|
|
function! s:context_dropdown()
|
|
let cursor = s:cmenu.index
|
|
if cursor < 0 || cursor >= s:cmenu.size || s:cmenu.state == 0
|
|
return 0
|
|
endif
|
|
if s:cmenu.state == 2
|
|
call popup_close(s:cmenu.context, -3)
|
|
let s:cmenu.state = 1
|
|
let s:cmenu.context = -1
|
|
endif
|
|
let item = s:cmenu.inst.items[s:cmenu.index]
|
|
let opts = {'col': item.x + 1, 'line': 2, 'horizon':1, 'zindex':31100}
|
|
let opts.callback = 'quickui#menu#context_exit'
|
|
let opts.reserve = 1
|
|
let opts.lazyredraw = 1
|
|
let cfg = s:cmenu.current[item.name]
|
|
let s:cmenu.dropdown = []
|
|
for item in cfg.items
|
|
let s:cmenu.dropdown += [[item.name, item.cmd, item.help]]
|
|
endfor
|
|
let index = get(cfg, 'index', 0)
|
|
let opts.index = (index < 0 || index >= len(cfg.items))? 0 : index
|
|
let cfg.index = opts.index
|
|
let hwnd = quickui#context#open(s:cmenu.dropdown, opts)
|
|
let s:cmenu.context = hwnd.winid
|
|
let s:cmenu.state = 1
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" context menu callback
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#context_exit(code)
|
|
" echom "quickui#menu#context_exit"
|
|
let s:cmenu.context = -1
|
|
let hwnd = g:quickui#context#current
|
|
if has_key(hwnd, 'index') && hwnd.index >= 0
|
|
let item = s:cmenu.inst.items[s:cmenu.index]
|
|
let cfg = s:cmenu.current[item.name]
|
|
let cfg.index = hwnd.index
|
|
" echo "save index: ".hwnd.index
|
|
endif
|
|
if a:code >= 0 || a:code == -3
|
|
if s:cmenu.state > 0 && s:cmenu.winid >= 0
|
|
call popup_close(s:cmenu.winid, 0)
|
|
endif
|
|
return 0
|
|
elseif a:code == -1 " close context menu by ESC
|
|
if s:cmenu.state > 0 && s:cmenu.winid >= 0
|
|
call popup_close(s:cmenu.winid, 0)
|
|
endif
|
|
elseif a:code == -2 " close context menu by mouse
|
|
if s:cmenu.state > 0 && s:cmenu.winid >= 0
|
|
let pos = getmousepos()
|
|
if pos.winid != s:cmenu.winid
|
|
call popup_close(s:cmenu.winid, 0)
|
|
endif
|
|
endif
|
|
elseif a:code == -1000 || a:code == -2000
|
|
call s:movement((a:code == -1000)? 'LEFT' : 'RIGHT')
|
|
call s:movement('DOWN')
|
|
elseif a:code == -1001 || a:code == -2001
|
|
call s:movement((a:code == -1001)? 'PAGEUP' : 'PAGEDOWN')
|
|
call s:movement('DOWN')
|
|
endif
|
|
return 0
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" open menu
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#open(...)
|
|
let opts = {}
|
|
if a:0 > 0
|
|
let opts.name = a:1
|
|
endif
|
|
if g:quickui#core#has_nvim == 0
|
|
call quickui#menu#create(opts)
|
|
else
|
|
call quickui#menu#nvim_open_menu(opts)
|
|
endif
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" neovim dropdown context: returns non-zero for exit
|
|
"----------------------------------------------------------------------
|
|
function! s:neovim_dropdown()
|
|
let cursor = s:cmenu.index
|
|
if cursor < 0 || cursor >= s:cmenu.size || s:cmenu.state == 0
|
|
return 0
|
|
endif
|
|
if s:cmenu.state == 2
|
|
let s:cmenu.state = 1
|
|
let s:cmenu.context = -1
|
|
return 1
|
|
endif
|
|
let item = s:cmenu.inst.items[s:cmenu.index]
|
|
let opts = {'col': item.x + 1, 'line': 2, 'horizon':1, 'zindex':31100}
|
|
let opts.reserve = 1
|
|
let opts.lazyredraw = 1
|
|
let cfg = s:cmenu.current[item.name]
|
|
let s:cmenu.dropdown = []
|
|
for item in cfg.items
|
|
let s:cmenu.dropdown += [[item.name, '', item.help]]
|
|
endfor
|
|
let index = get(cfg, 'index', 0)
|
|
let opts.index = (index < 0 || index >= len(cfg.items))? 0 : index
|
|
let cfg.index = opts.index
|
|
let hr = quickui#context#open(s:cmenu.dropdown, opts)
|
|
let cfg.index = g:quickui#context#current.index
|
|
let s:cmenu.next = 0
|
|
if hr >= 0
|
|
if hr < len(cfg.items)
|
|
let s:cmenu.script = cfg.items[hr].cmd
|
|
endif
|
|
return 1
|
|
elseif hr == -1000
|
|
call s:movement('LEFT')
|
|
let s:cmenu.next = 1
|
|
elseif hr == -2000
|
|
call s:movement('RIGHT')
|
|
let s:cmenu.next = 1
|
|
elseif hr == -1001
|
|
call s:movement('PAGEUP')
|
|
let s:cmenu.next = 1
|
|
elseif hr == -2001
|
|
call s:movement('PAGEDOWN')
|
|
let s:cmenu.next = 1
|
|
elseif hr == -2
|
|
call s:neovim_click()
|
|
endif
|
|
return (s:cmenu.next == 0)? 1 : 0
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" returns non-zero to quit
|
|
"----------------------------------------------------------------------
|
|
function! s:neovim_click()
|
|
if v:mouse_winid != s:cmenu.winid || v:mouse_lnum != 1
|
|
return 1
|
|
endif
|
|
let x = v:mouse_col - 1
|
|
let index = 0
|
|
let select = -1
|
|
for item in s:cmenu.inst.items
|
|
if x >= item.x && x < item.x + item.w
|
|
let select = index
|
|
endif
|
|
let index += 1
|
|
endfor
|
|
if select >= 0
|
|
let s:cmenu.index = select
|
|
let s:cmenu.next = 1
|
|
endif
|
|
return 0
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" neovim open menu
|
|
"----------------------------------------------------------------------
|
|
function! quickui#menu#nvim_open_menu(opts)
|
|
if s:cmenu.state != 0
|
|
" return -1
|
|
endif
|
|
let name = get(a:opts, 'name', s:name)
|
|
if !has_key(s:namespace, name)
|
|
return -1
|
|
endif
|
|
let current = s:namespace[name].config
|
|
let s:cmenu.inst = s:parse_menu(name, 2)
|
|
if s:cmenu.inst.width + 5 >= &columns
|
|
let s:cmenu.inst = s:parse_menu(name, 1)
|
|
if s:cmenu.inst.width + 5 >= &columns
|
|
let s:cmenu.inst = s:parse_menu(name, 0)
|
|
endif
|
|
endif
|
|
let s:cmenu.name = name
|
|
let s:cmenu.index = s:namespace[name].index
|
|
let s:cmenu.width = &columns
|
|
let s:cmenu.size = len(s:cmenu.inst.items)
|
|
let s:cmenu.current = current
|
|
let bid = quickui#core#scratch_buffer('menu', [s:cmenu.inst.text])
|
|
let w = s:cmenu.width
|
|
let opts = {'width':w, 'height':1, 'focusable':1, 'style':'minimal'}
|
|
let opts.col = 0
|
|
let opts.row = 0
|
|
let opts.relative = 'editor'
|
|
let s:cmenu.bufnr = bid
|
|
if has('nvim-0.6.0')
|
|
let opts.noautocmd = 1
|
|
endif
|
|
let winid = nvim_open_win(bid, 0, opts)
|
|
let s:cmenu.winid = winid
|
|
let s:cmenu.cfg = deepcopy(a:opts)
|
|
let w = s:cmenu.width
|
|
let color = get(a:opts, 'color', 'QuickBG')
|
|
call nvim_win_set_option(winid, 'winhl', 'Normal:'. color)
|
|
let s:cmenu.hotkey = s:cmenu.inst.hotkey
|
|
let s:cmenu.state = 1
|
|
let s:cmenu.context = -1
|
|
let s:cmenu.next = 0
|
|
let keymap = quickui#utils#keymap()
|
|
let s:cmenu.keymap = keymap
|
|
let s:cmenu.script = ''
|
|
call quickui#menu#update()
|
|
while 1
|
|
noautocmd call quickui#menu#update()
|
|
if s:cmenu.next == 0
|
|
noautocmd redraw
|
|
elseif s:cmenu.next == 1
|
|
let s:cmenu.next = 0
|
|
call quickui#menu#update()
|
|
if s:neovim_dropdown() != 0
|
|
break
|
|
else
|
|
continue
|
|
endif
|
|
elseif s:cmenu.next == 2
|
|
let s:cmenu.next = 0
|
|
continue
|
|
endif
|
|
let s:cmenu.next = 0
|
|
try
|
|
let code = getchar()
|
|
catch /^Vim:Interrupt$/
|
|
let code = "\<C-C>"
|
|
endtry
|
|
let ch = (type(code) == v:t_number)? nr2char(code) : code
|
|
if ch == "\<ESC>" || ch == "\<c-c>"
|
|
break
|
|
elseif ch == "\<LeftMouse>"
|
|
if s:neovim_click() != 0
|
|
break
|
|
endif
|
|
elseif has_key(s:cmenu.hotkey, ch)
|
|
let index = s:cmenu.hotkey[ch]
|
|
let index = (index < 0)? (s:cmenu.size - 1) : index
|
|
let index = (index >= s:cmenu.size)? 0 : index
|
|
let s:cmenu.index = (s:cmenu.size == 0)? 0 : index
|
|
call quickui#menu#update()
|
|
if s:neovim_dropdown() != 0
|
|
break
|
|
endif
|
|
elseif has_key(keymap, ch)
|
|
let key = keymap[ch]
|
|
if s:movement(key) != 0
|
|
break
|
|
endif
|
|
endif
|
|
endwhile
|
|
call nvim_win_close(winid, 0)
|
|
redraw
|
|
echo ""
|
|
redraw
|
|
let s:namespace[name].index = s:cmenu.index
|
|
if s:cmenu.script != ''
|
|
let script = s:cmenu.script
|
|
exec script
|
|
endif
|
|
endfunc
|
|
|
|
|
|
"----------------------------------------------------------------------
|
|
" testing suit
|
|
"----------------------------------------------------------------------
|
|
if 0
|
|
call quickui#menu#switch('test')
|
|
call quickui#menu#reset()
|
|
call quickui#menu#install('H&elp', [
|
|
\ [ '&Content', 'echo 4' ],
|
|
\ [ '&About', 'echo 5' ],
|
|
\ ])
|
|
call quickui#menu#install('&File', [
|
|
\ [ "&New File\tCtrl+n", '' ],
|
|
\ [ "&Open File\t(F3)", 'echo 1' ],
|
|
\ [ "&Close", 'echo 3' ],
|
|
\ [ "--", '' ],
|
|
\ [ "&Save\tCtrl+s", ''],
|
|
\ [ "Save &As", '' ],
|
|
\ [ "Save All", '' ],
|
|
\ [ "--", '' ],
|
|
\ [ "E&xit\tAlt+x", '' ],
|
|
\ ])
|
|
call quickui#menu#install('&Edit', [
|
|
\ [ '&Copy', 'echo 1', 'help1' ],
|
|
\ [ '&Paste', 'echo 2', 'help2' ],
|
|
\ [ '&Find', 'echo 3', 'help3' ],
|
|
\ ])
|
|
call quickui#menu#install('&Tools', [
|
|
\ [ '&Copy', 'echo 1', 'help1' ],
|
|
\ [ '&Paste', 'echo 2', 'help2' ],
|
|
\ [ '&Find', 'echo 3', 'help3' ],
|
|
\ ])
|
|
|
|
call quickui#menu#install('&Window', [])
|
|
call quickui#menu#change_weight('H&elp', 1000)
|
|
call quickui#menu#switch('system')
|
|
call quickui#menu#open('test')
|
|
endif
|
|
|
|
|
|
|