638 lines
18 KiB
VimL
638 lines
18 KiB
VimL
|
|
if exists( "g:__XPOPUP_VIM__" ) && g:__XPOPUP_VIM__ >= XPT#ver
|
||
|
|
finish
|
||
|
|
endif
|
||
|
|
let g:__XPOPUP_VIM__ = XPT#ver
|
||
|
|
let s:oldcpo = &cpo
|
||
|
|
set cpo-=< cpo+=B
|
||
|
|
runtime plugin/debug.vim
|
||
|
|
exe XPT#let_sid
|
||
|
|
let s:log = CreateLogger( 'warn' )
|
||
|
|
let s:log = CreateLogger( 'debug' )
|
||
|
|
fun! s:SetIfNotExist(k,v)
|
||
|
|
if !exists(a:k)
|
||
|
|
exe "let ".a:k."=".string(a:v)
|
||
|
|
endif
|
||
|
|
endfunction
|
||
|
|
let s:opt = { 'doCallback':'doCallback', 'enlarge':'enlarge', 'acceptEmpty':'acceptEmpty', 'tabNav':'tabNav', }
|
||
|
|
let s:CHECK_PUM = 1
|
||
|
|
let s:errorTolerance = 3
|
||
|
|
let s:sessionPrototype = { 'callback':{}, 'list':[], 'key':'', 'prefixIndex':{}, 'popupCount':0, 'sessCount':0, 'errorInputCount':0, 'line':0, 'col':0, 'prefix':'', 'ignoreCase':0, 'acceptEmpty':0, 'matchWholeName':0, 'matchPrefix':0, 'strictInput':0, 'tabNav':0, 'last':'', 'currentText':'', 'longest':'', 'matched':'', 'matchedCallback':'', 'currentList':[], }
|
||
|
|
fun! XPPopupNew(callback,data,...)
|
||
|
|
let sess = deepcopy(s:sessionPrototype)
|
||
|
|
let sess.callback = a:callback
|
||
|
|
let sess.data = a:data
|
||
|
|
call sess.createPrefixIndex([])
|
||
|
|
if a:0 > 0
|
||
|
|
let items = a:1
|
||
|
|
if type( items ) == type( '' )
|
||
|
|
call sess.SetTriggerKey(items)
|
||
|
|
elseif type(items) == type([])
|
||
|
|
call sess.addList(items)
|
||
|
|
else
|
||
|
|
call s:log.Error( 'unsupported items type as pum items:' . str( items ) )
|
||
|
|
endif
|
||
|
|
endif
|
||
|
|
return sess
|
||
|
|
endfunction
|
||
|
|
fun! s:popup(start_col,opt) dict
|
||
|
|
let doCallback = get(a:opt,s:opt.doCallback,1)
|
||
|
|
let ifEnlarge = get(a:opt,s:opt.enlarge,1)
|
||
|
|
let self.popupCount += 1
|
||
|
|
let cursorIndex = col(".") - 1 - 1
|
||
|
|
let self.line = line(".")
|
||
|
|
let self.col = a:start_col
|
||
|
|
let self.prefix = s:GetTextBeforeCursor(self)
|
||
|
|
let self.ignoreCase = self.prefix !~# '\u'
|
||
|
|
if self.key != ''
|
||
|
|
let self.longest = self.prefix
|
||
|
|
let actions = self.KeyPopup(doCallback,ifEnlarge)
|
||
|
|
else
|
||
|
|
let self.currentList = s:filterCompleteList(self)
|
||
|
|
if ifEnlarge
|
||
|
|
let self.longest = s:LongestPrefix(self)
|
||
|
|
else
|
||
|
|
let self.longest = self.prefix
|
||
|
|
endif
|
||
|
|
let actions = self.ListPopup(doCallback,ifEnlarge)
|
||
|
|
endif
|
||
|
|
let actions = s:CreateSession(self) . actions
|
||
|
|
call s:ApplyMapAndSetting()
|
||
|
|
return actions
|
||
|
|
endfunction
|
||
|
|
fun PUMclear()
|
||
|
|
return "\<C-v>\<C-v>\<BS>"
|
||
|
|
endfunction
|
||
|
|
fun! s:CreateSession(sess)
|
||
|
|
if !exists( 'b:__xpp_sess_count' )
|
||
|
|
let b:__xpp_sess_count = 0
|
||
|
|
endif
|
||
|
|
let action = ''
|
||
|
|
let b:__xpp_sess_count += 1
|
||
|
|
let a:sess.sessCount = b:__xpp_sess_count
|
||
|
|
if exists( 'b:__xpp_current_session' )
|
||
|
|
call s:End()
|
||
|
|
if pumvisible()
|
||
|
|
let action .= PUMclear()
|
||
|
|
endif
|
||
|
|
endif
|
||
|
|
let b:__xpp_current_session = a:sess
|
||
|
|
return action
|
||
|
|
endfunction
|
||
|
|
fun! s:SetAcceptEmpty(acc) dict
|
||
|
|
let self.acceptEmpty = !!a:acc
|
||
|
|
return self
|
||
|
|
endfunction
|
||
|
|
fun! s:SetMatchWholeName(mwn) dict
|
||
|
|
let self.matchWholeName = !!a:mwn
|
||
|
|
return self
|
||
|
|
endfunction
|
||
|
|
fun! s:SetOption(opt) dict
|
||
|
|
if type(a:opt) == type([])
|
||
|
|
for optname in a:opt
|
||
|
|
let self[optname] = 1
|
||
|
|
endfor
|
||
|
|
elseif type(a:opt) == type({})
|
||
|
|
for [key,value] in items(a:opt)
|
||
|
|
let self[key] = value
|
||
|
|
endfor
|
||
|
|
endif
|
||
|
|
endfunction
|
||
|
|
fun! s:KeyPopup(doCallback,ifEnlarge) dict
|
||
|
|
let actionList = []
|
||
|
|
if a:ifEnlarge
|
||
|
|
let actionList = [ 'clearPum', 'clearPrefix', 'typeLongest', 'triggerKey', 'setLongest' ]
|
||
|
|
if a:doCallback
|
||
|
|
let actionList += [ 'checkAndCallback' ]
|
||
|
|
endif
|
||
|
|
else
|
||
|
|
let actionList = [ 'clearPum', 'clearPrefix', 'typeLongest', 'triggerKey', 'removeTrailing', 'forcePumShow' ]
|
||
|
|
endif
|
||
|
|
return "\<C-r>=XPPprocess(" . string( actionList ) . ")\<CR>"
|
||
|
|
endfunction
|
||
|
|
fun! s:ListPopup(doCallback,ifEnlarge) dict
|
||
|
|
let actionClosePum = ''
|
||
|
|
let actionList = []
|
||
|
|
if self.longest !=# self.prefix
|
||
|
|
let actionList += ['clearPum', 'clearPrefix', 'clearPum', 'typeLongest' ]
|
||
|
|
endif
|
||
|
|
if 0
|
||
|
|
else
|
||
|
|
if self.popupCount > 1 && a:ifEnlarge && self.acceptEmpty && self.prefix == ''
|
||
|
|
let self.matched = ''
|
||
|
|
let self.matchedCallback = 'onOneMatch'
|
||
|
|
let actionList = []
|
||
|
|
let actionList += [ 'clearPum', 'clearPrefix', 'clearPum', 'callback' ]
|
||
|
|
elseif len(self.currentList) == 0
|
||
|
|
let self.matched = ''
|
||
|
|
let self.matchedCallback = 'onEmpty'
|
||
|
|
let actionList += ['callback']
|
||
|
|
elseif len(self.currentList) == 1 && a:doCallback
|
||
|
|
if self.matchPrefix
|
||
|
|
let self.matched = type(self.currentList[0]) == type({}) ? self.currentList[0].word : self.currentList[0]
|
||
|
|
let self.matchedCallback = 'onOneMatch'
|
||
|
|
let actionList += ['clearPum', 'clearPrefix', 'clearPum', 'typeMatched', 'callback']
|
||
|
|
else
|
||
|
|
let actionClosePum = PUMclear()
|
||
|
|
let actionList += [ 'popup', 'fixPopup' ]
|
||
|
|
endif
|
||
|
|
elseif self.prefix != "" && self.longest ==? self.prefix
|
||
|
|
if self.matchPrefix && a:doCallback
|
||
|
|
let self.matched = ''
|
||
|
|
for item in self.currentList
|
||
|
|
let key = type(item) == type({}) ? item.word : item
|
||
|
|
if key ==? self.prefix
|
||
|
|
let self.matched = key
|
||
|
|
let self.matchedCallback = 'onOneMatch'
|
||
|
|
let actionList += ['clearPum', 'clearPrefix', 'clearPum', 'typeLongest', 'callback']
|
||
|
|
break
|
||
|
|
endif
|
||
|
|
endfor
|
||
|
|
if self.matched == ''
|
||
|
|
let actionClosePum = PUMclear()
|
||
|
|
let actionList += [ 'popup', 'fixPopup' ]
|
||
|
|
endif
|
||
|
|
else
|
||
|
|
let actionClosePum = PUMclear()
|
||
|
|
let actionList += [ 'popup', 'fixPopup' ]
|
||
|
|
endif
|
||
|
|
else
|
||
|
|
let actionClosePum = PUMclear()
|
||
|
|
let actionList += [ 'popup', 'fixPopup' ]
|
||
|
|
endif
|
||
|
|
endif
|
||
|
|
let self.matchPrefix = 1
|
||
|
|
return actionClosePum . "\<C-r>=XPPprocess(" . string( actionList ) . ")\<CR>"
|
||
|
|
endfunction
|
||
|
|
fun! s:SetTriggerKey(key) dict
|
||
|
|
let self.key = a:key
|
||
|
|
endfunction
|
||
|
|
fun! s:sessionPrototype.addList(list)
|
||
|
|
let list = a:list
|
||
|
|
if list == []
|
||
|
|
return
|
||
|
|
endif
|
||
|
|
if type( list[0] ) == type( '' )
|
||
|
|
call map( list, '{"word" : v:val, "icase" : 1 }' )
|
||
|
|
else
|
||
|
|
call map( list, '{"word" : v:val["word"],' . '"info": get(v:val, "info", ""),' . '"menu": get(v:val, "menu", ""),' . '"icase": 1 }' )
|
||
|
|
endif
|
||
|
|
let self.list += list
|
||
|
|
call self.updatePrefixIndex(list)
|
||
|
|
endfunction
|
||
|
|
fun! s:sessionPrototype.createPrefixIndex(list)
|
||
|
|
let self.prefixIndex = { 'keys' : {}, 'lowerkeys' : {}, 'ori' : {}, 'lower' : {} }
|
||
|
|
call self.updatePrefixIndex(a:list)
|
||
|
|
endfunction
|
||
|
|
fun! s:sessionPrototype.updatePrefixIndex(list)
|
||
|
|
if g:xptemplate_pum_quick_back == 0
|
||
|
|
return
|
||
|
|
endif
|
||
|
|
for item in a:list
|
||
|
|
let key = (type(item) == type({})) ?item.word : item
|
||
|
|
if !has_key(self.prefixIndex.keys,key)
|
||
|
|
let self.prefixIndex.keys[key] = 1
|
||
|
|
call s:UpdateIndex(self.prefixIndex.ori,key)
|
||
|
|
endif
|
||
|
|
let lowerKey = substitute(key, '.', '\l&', 'g')
|
||
|
|
if !has_key(self.prefixIndex.lowerkeys,lowerKey)
|
||
|
|
let self.prefixIndex.lowerkeys[lowerKey] = 1
|
||
|
|
call s:UpdateIndex(self.prefixIndex.lower,lowerKey)
|
||
|
|
endif
|
||
|
|
endfor
|
||
|
|
endfunction
|
||
|
|
fun! s:_InitBuffer()
|
||
|
|
if exists( 'b:__xpp_buffer_init' )
|
||
|
|
return
|
||
|
|
endif
|
||
|
|
let b:_xpp_map_saver = xpt#msvr#New(1)
|
||
|
|
call xpt#msvr#AddList(b:_xpp_map_saver, 'i_<UP>', 'i_<DOWN>', 'i_<BS>', 'i_<TAB>', 'i_<S-TAB>', 'i_<CR>', 'i_<C-e>', 'i_<C-y>', )
|
||
|
|
let b:_xpp_setting_switch = xpt#settingswitch#New()
|
||
|
|
let co = {"menu":1, "menuone":1, "longest":1}
|
||
|
|
for k in split(&completeopt, ',')
|
||
|
|
let co[k] = 1
|
||
|
|
endfor
|
||
|
|
let new_completeopt = join( keys(co), ',' )
|
||
|
|
call xpt#settingswitch#AddList(b:_xpp_setting_switch, [ '&l:cinkeys', '' ], [ '&l:indentkeys', '' ], [ '&completeopt', new_completeopt ], )
|
||
|
|
let b:__xpp_buffer_init = 1
|
||
|
|
endfunction
|
||
|
|
fun! XPPprocess(list)
|
||
|
|
if !exists("b:__xpp_current_session")
|
||
|
|
call s:log.Error("session does not exist!")
|
||
|
|
return ""
|
||
|
|
endif
|
||
|
|
let sess = b:__xpp_current_session
|
||
|
|
if len(a:list) == 0
|
||
|
|
return "\<C-n>\<C-p>"
|
||
|
|
endif
|
||
|
|
let actionName = a:list[0]
|
||
|
|
let nextList = a:list[1 :]
|
||
|
|
let postAction = ""
|
||
|
|
if actionName == 'clearPrefix'
|
||
|
|
let n = col(".") - sess.col
|
||
|
|
let postAction = repeat( "\<bs>", n )
|
||
|
|
elseif actionName == 'clearPum'
|
||
|
|
if pumvisible()
|
||
|
|
let postAction = "\<C-e>"
|
||
|
|
endif
|
||
|
|
elseif actionName == 'triggerKey'
|
||
|
|
let postAction = sess.key
|
||
|
|
elseif actionName == 'setLongest'
|
||
|
|
let current = s:GetTextBeforeCursor(sess)
|
||
|
|
if len(current) > len(sess.longest)
|
||
|
|
let postAction = repeat( "\<BS>", len( current ) - len( sess.longest ) ) . current[len(sess.longest) :]
|
||
|
|
let sess.longest = s:GetTextBeforeCursor(sess)
|
||
|
|
if pumvisible()
|
||
|
|
let nextList = [ 'clearPum', 'clearPrefix', 'typeLongest', 'triggerKey' ] + nextList
|
||
|
|
else
|
||
|
|
let nextList = [ 'clearPrefix', 'clearPum', 'typeLongest' ] + nextList
|
||
|
|
endif
|
||
|
|
endif
|
||
|
|
elseif actionName == 'removeTrailing'
|
||
|
|
let current = s:GetTextBeforeCursor(sess)
|
||
|
|
if len(current) > len(sess.longest)
|
||
|
|
let postAction = repeat( "\<BS>", len( current ) - len( sess.longest ) )
|
||
|
|
endif
|
||
|
|
elseif actionName == 'forcePumShow'
|
||
|
|
let postAction = "\<C-n>\<C-p>"
|
||
|
|
elseif actionName == 'checkAndCallback'
|
||
|
|
if pumvisible()
|
||
|
|
return "\<C-n>\<C-p>"
|
||
|
|
else
|
||
|
|
let current = s:GetTextBeforeCursor(sess)
|
||
|
|
let sess.matched = current
|
||
|
|
let sess.matchedCallback = 'onOneMatch'
|
||
|
|
call s:End()
|
||
|
|
let postAction = ""
|
||
|
|
if has_key(sess.callback,sess.matchedCallback)
|
||
|
|
let postAction = sess.callback[sess.matchedCallback](sess)
|
||
|
|
return postAction
|
||
|
|
else
|
||
|
|
return ''
|
||
|
|
endif
|
||
|
|
endif
|
||
|
|
elseif actionName == 'keymodeEnlarge'
|
||
|
|
let current = s:GetTextBeforeCursor(sess)
|
||
|
|
if sess.acceptEmpty && current == ''
|
||
|
|
let sess.longest = ''
|
||
|
|
let sess.matched = ''
|
||
|
|
let sess.matchedCallback = 'onOneMatch'
|
||
|
|
let nextList = [ 'callback' ]
|
||
|
|
elseif current !=# sess.currentText
|
||
|
|
let sess.longest = sess.currentText
|
||
|
|
let sess.matched = sess.currentText
|
||
|
|
let sess.matchedCallback = 'onOneMatch'
|
||
|
|
let nextList = [ 'clearPrefix', 'typeLongest', 'callback' ]
|
||
|
|
else
|
||
|
|
return sess.popup(sess.col, { 'doCallback' : 1, 'enlarge':1 } )
|
||
|
|
endif
|
||
|
|
elseif actionName == 'enlarge'
|
||
|
|
let current = s:GetTextBeforeCursor(sess)
|
||
|
|
if current !=# sess.currentText
|
||
|
|
let sess.longest = sess.currentText
|
||
|
|
let sess.matched = sess.currentText
|
||
|
|
let sess.matchedCallback = 'onOneMatch'
|
||
|
|
let nextList = [ 'clearPrefix', 'typeLongest', 'callback' ]
|
||
|
|
else
|
||
|
|
return sess.popup(sess.col, { 'doCallback' : 1, 'enlarge':1 } )
|
||
|
|
endif
|
||
|
|
elseif actionName == 'typeMatched'
|
||
|
|
let postAction = sess.matched
|
||
|
|
elseif actionName == 'typeLongest'
|
||
|
|
let postAction = sess.longest
|
||
|
|
elseif actionName == 'type'
|
||
|
|
let postAction = remove(nextList,0)
|
||
|
|
elseif actionName == 'popup'
|
||
|
|
call complete(sess.col,sess.currentList)
|
||
|
|
elseif actionName == 'fixPopup'
|
||
|
|
let current = s:GetTextBeforeCursor(sess)
|
||
|
|
let i = 0
|
||
|
|
let j = -1
|
||
|
|
for v in sess.currentList
|
||
|
|
let key = type(v) == type({}) ? v.word : v
|
||
|
|
if key ==# current
|
||
|
|
let j = i
|
||
|
|
break
|
||
|
|
endif
|
||
|
|
let i += 1
|
||
|
|
endfor
|
||
|
|
if j != -1
|
||
|
|
let postAction .= repeat( "\<C-p>", j + 1 )
|
||
|
|
endif
|
||
|
|
elseif actionName == 'callback'
|
||
|
|
call s:End()
|
||
|
|
let postAction = ""
|
||
|
|
if has_key(sess.callback,sess.matchedCallback)
|
||
|
|
let postAction = sess.callback[sess.matchedCallback](sess)
|
||
|
|
return postAction
|
||
|
|
endif
|
||
|
|
elseif actionName == 'end'
|
||
|
|
call s:End()
|
||
|
|
let postAction = ''
|
||
|
|
else
|
||
|
|
endif
|
||
|
|
if !empty(nextList)
|
||
|
|
let postAction .= "\<C-r>=XPPprocess(" . string( nextList ) . ")\<CR>"
|
||
|
|
else
|
||
|
|
let postAction .= g:xpt_post_action
|
||
|
|
endif
|
||
|
|
return postAction
|
||
|
|
endfunction
|
||
|
|
fun! s:GetTextBeforeCursor(sess)
|
||
|
|
let c = col( "." )
|
||
|
|
if c == 1
|
||
|
|
return ''
|
||
|
|
endif
|
||
|
|
return getline(".")[ a:sess.col - 1 : c - 2 ]
|
||
|
|
endfunction
|
||
|
|
fun! XPPcomplete(col,list)
|
||
|
|
let oldcfu = &completefunc
|
||
|
|
set completefunc=XPPcompleteFunc
|
||
|
|
return "\<C-x>\<C-u>"
|
||
|
|
endfunction
|
||
|
|
fun! XPPcr()
|
||
|
|
if !s:PopupCheck(s:CHECK_PUM)
|
||
|
|
call feedkeys("\<CR>", 'mt')
|
||
|
|
return ""
|
||
|
|
endif
|
||
|
|
return "\<C-r>=XPPaccept()\<CR>"
|
||
|
|
endfunction
|
||
|
|
fun! XPPup(key)
|
||
|
|
if !s:PopupCheck(s:CHECK_PUM)
|
||
|
|
call feedkeys( a:key, 'mt' )
|
||
|
|
return ""
|
||
|
|
endif
|
||
|
|
return "\<C-p>"
|
||
|
|
endfunction
|
||
|
|
fun! XPPdown(key)
|
||
|
|
if !s:PopupCheck(s:CHECK_PUM)
|
||
|
|
call feedkeys( a:key, 'mt' )
|
||
|
|
return ""
|
||
|
|
endif
|
||
|
|
return "\<C-n>"
|
||
|
|
endfunction
|
||
|
|
fun! XPPcallback()
|
||
|
|
if !exists("b:__xpp_current_session")
|
||
|
|
return ""
|
||
|
|
endif
|
||
|
|
let sess = b:__xpp_current_session
|
||
|
|
call s:End()
|
||
|
|
if has_key(sess.callback,sess.matchedCallback)
|
||
|
|
let post = sess.callback[sess.matchedCallback](sess)
|
||
|
|
else
|
||
|
|
let post = ""
|
||
|
|
endif
|
||
|
|
return post
|
||
|
|
endfunction
|
||
|
|
fun! XPPshorten()
|
||
|
|
if !s:PopupCheck(! s:CHECK_PUM)
|
||
|
|
let s:pos = getpos(".")[ 1 : 2 ]
|
||
|
|
return "\<C-e>\<C-r>=XPPcorrectPos()\<cr>\<bs>"
|
||
|
|
endif
|
||
|
|
if !pumvisible()
|
||
|
|
return "\<BS>"
|
||
|
|
endif
|
||
|
|
let sess = b:__xpp_current_session
|
||
|
|
let current = s:GetTextBeforeCursor(sess)
|
||
|
|
if sess.key != ''
|
||
|
|
return "\<BS>"
|
||
|
|
endif
|
||
|
|
if current == ''
|
||
|
|
call s:End()
|
||
|
|
return "\<bs>"
|
||
|
|
endif
|
||
|
|
let actions = "\<C-y>"
|
||
|
|
let actions = ""
|
||
|
|
if g:xptemplate_pum_quick_back == 1
|
||
|
|
let prefixMap = (sess.ignoreCase) ? sess.prefixIndex.lower : sess.prefixIndex.ori
|
||
|
|
let shorterKey = s:FindShorter(prefixMap, ( sess.ignoreCase ? substitute(current, '.', '\l&', 'g') : current ))
|
||
|
|
else
|
||
|
|
let shorterKey = current[0 : -2]
|
||
|
|
endif
|
||
|
|
let action = actions . repeat( "\<bs>", len(current) - len(shorterKey) ) . "\<C-r>=XPPrepopup(0, 'noenlarge')\<cr>"
|
||
|
|
return action
|
||
|
|
endfunction
|
||
|
|
fun! XPPenlarge(key)
|
||
|
|
if !s:PopupCheck(s:CHECK_PUM)
|
||
|
|
call feedkeys( a:key, 'm' )
|
||
|
|
return ""
|
||
|
|
endif
|
||
|
|
return "\<C-r>=XPPrepopup(1, 'enlarge')\<cr>"
|
||
|
|
endfunction
|
||
|
|
fun! XPPcancel(key)
|
||
|
|
if !s:PopupCheck()
|
||
|
|
call feedkeys( a:key, 'mt' )
|
||
|
|
return ""
|
||
|
|
endif
|
||
|
|
return "\<C-r>=XPPprocess(" . string( [ 'clearPum', 'clearPrefix', 'typeLongest', 'end' ] ) . ")\<cr>"
|
||
|
|
endfunction
|
||
|
|
fun! XPPaccept()
|
||
|
|
if !s:PopupCheck()
|
||
|
|
call feedkeys("\<C-y>", 'mt')
|
||
|
|
return ""
|
||
|
|
endif
|
||
|
|
let sess = b:__xpp_current_session
|
||
|
|
let beforeCursor = col( "." ) - 2
|
||
|
|
let beforeCursor = beforeCursor == -1 ? 0 : beforeCursor
|
||
|
|
let toType = getline(sess.line)[sess.col - 1 : beforeCursor]
|
||
|
|
return "\<C-r>=XPPprocess(" . string( [ 'clearPum', 'clearPrefix', 'type', toType, 'end' ] ) . ")\<cr>"
|
||
|
|
endfunction
|
||
|
|
fun! XPPrepopup(doCallback,ifEnlarge)
|
||
|
|
if !exists("b:__xpp_current_session")
|
||
|
|
return ""
|
||
|
|
endif
|
||
|
|
let sess = b:__xpp_current_session
|
||
|
|
if sess.key != ''
|
||
|
|
let sess.currentText = s:GetTextBeforeCursor(sess)
|
||
|
|
let action = "\<C-e>" . "\<C-r>=XPPprocess(" . string( [ 'keymodeEnlarge' ] ) . ")\<CR>"
|
||
|
|
return action
|
||
|
|
else
|
||
|
|
let action = sess.popup(sess.col, { 'doCallback' : a:doCallback, 'enlarge':a:ifEnlarge == 'enlarge' } )
|
||
|
|
return action
|
||
|
|
endif
|
||
|
|
endfunction
|
||
|
|
fun! XPPcorrectPos()
|
||
|
|
let p = getpos(".")[1:2]
|
||
|
|
if p != s:pos
|
||
|
|
unlet s:pos
|
||
|
|
return "\<bs>"
|
||
|
|
else
|
||
|
|
unlet s:pos
|
||
|
|
return ""
|
||
|
|
endif
|
||
|
|
endfunction
|
||
|
|
fun! s:ApplyMapAndSetting()
|
||
|
|
call s:_InitBuffer()
|
||
|
|
if exists( 'b:__xpp_pushed' )
|
||
|
|
return
|
||
|
|
endif
|
||
|
|
let b:__xpp_pushed = 1
|
||
|
|
call xpt#msvr#Save(b:_xpp_map_saver)
|
||
|
|
let sess = b:__xpp_current_session
|
||
|
|
exe 'inoremap <silent> <buffer> <UP>' '<C-r>=XPPup("\<lt>UP>")<CR>'
|
||
|
|
exe 'inoremap <silent> <buffer> <DOWN>' '<C-r>=XPPdown("\<lt>DOWN>")<CR>'
|
||
|
|
exe 'inoremap <silent> <buffer> <bs>' '<C-r>=XPPshorten()<cr>'
|
||
|
|
exe 'inoremap <silent> <buffer> <C-e>' '<C-r>=XPPcancel("\<lt>C-e>")<cr>'
|
||
|
|
if sess.tabNav
|
||
|
|
exe 'inoremap <silent> <buffer> <S-tab>' '<C-r>=XPPup("\<lt>S-Tab>")<cr>'
|
||
|
|
exe 'inoremap <silent> <buffer> <tab>' '<C-r>=XPPdown("\<lt>TAB>")<cr>'
|
||
|
|
exe 'inoremap <silent> <buffer> <cr>' '<C-r>=XPPenlarge("\<lt>CR>")<cr>'
|
||
|
|
exe 'inoremap <silent> <buffer> <C-y>' '<C-r>=XPPenlarge("\<lt>C-y>")<cr>'
|
||
|
|
else
|
||
|
|
exe 'inoremap <silent> <buffer> <tab>' '<C-r>=XPPenlarge("\<lt>TAB>")<cr>'
|
||
|
|
exe 'inoremap <silent> <buffer> <cr>' '<C-r>=XPPenlarge("\<lt>CR>")<cr>'
|
||
|
|
exe 'inoremap <silent> <buffer> <C-y>' '<C-r>=XPPenlarge("\<lt>C-y>")<cr>'
|
||
|
|
endif
|
||
|
|
augroup XPpopup
|
||
|
|
au!
|
||
|
|
au CursorMovedI * call s:CheckAndFinish()
|
||
|
|
au InsertEnter * call XPPend()
|
||
|
|
augroup END
|
||
|
|
call xpt#settingswitch#Switch(b:_xpp_setting_switch)
|
||
|
|
if exists( ':AcpLock' )
|
||
|
|
AcpLock
|
||
|
|
endif
|
||
|
|
endfunction
|
||
|
|
fun! s:ClearMapAndSetting()
|
||
|
|
call s:_InitBuffer()
|
||
|
|
if !exists( 'b:__xpp_pushed' )
|
||
|
|
return
|
||
|
|
endif
|
||
|
|
unlet b:__xpp_pushed
|
||
|
|
augroup XPpopup
|
||
|
|
au!
|
||
|
|
augroup END
|
||
|
|
call xpt#msvr#Restore(b:_xpp_map_saver)
|
||
|
|
call xpt#settingswitch#Restore(b:_xpp_setting_switch)
|
||
|
|
if exists( ':AcpUnlock' )
|
||
|
|
try
|
||
|
|
AcpUnlock
|
||
|
|
catch /.*/
|
||
|
|
endtry
|
||
|
|
endif
|
||
|
|
endfunction
|
||
|
|
fun! s:CheckAndFinish()
|
||
|
|
if !exists( 'b:__xpp_current_session' )
|
||
|
|
call s:End()
|
||
|
|
return ''
|
||
|
|
endif
|
||
|
|
let sess = b:__xpp_current_session
|
||
|
|
if !pumvisible()
|
||
|
|
if line( "." ) == sess.line
|
||
|
|
if sess.strictInput
|
||
|
|
if col(".") > sess.col
|
||
|
|
call feedkeys( "\<BS>", 'n' )
|
||
|
|
endif
|
||
|
|
else
|
||
|
|
return s:MistakeTypeEnd()
|
||
|
|
endif
|
||
|
|
else
|
||
|
|
return s:MistakeTypeEnd()
|
||
|
|
endif
|
||
|
|
endif
|
||
|
|
return ''
|
||
|
|
endfunction
|
||
|
|
fun! s:MistakeTypeEnd()
|
||
|
|
call s:End()
|
||
|
|
return PUMclear()
|
||
|
|
endfunction
|
||
|
|
fun! XPPhasSession()
|
||
|
|
return exists("b:__xpp_current_session")
|
||
|
|
endfunction
|
||
|
|
fun! XPPend()
|
||
|
|
call s:End()
|
||
|
|
if pumvisible()
|
||
|
|
return PUMclear()
|
||
|
|
endif
|
||
|
|
return ''
|
||
|
|
endfunction
|
||
|
|
fun! s:End()
|
||
|
|
call s:ClearMapAndSetting()
|
||
|
|
if exists("b:__xpp_current_session")
|
||
|
|
unlet b:__xpp_current_session
|
||
|
|
endif
|
||
|
|
endfunction
|
||
|
|
fun! s:PopupCheck(...)
|
||
|
|
let checkPum = (a:0 == 0 || a:1)
|
||
|
|
if !exists("b:__xpp_current_session")
|
||
|
|
call s:End()
|
||
|
|
return 0
|
||
|
|
endif
|
||
|
|
let sess = b:__xpp_current_session
|
||
|
|
if sess.line != line(".") || col(".") < sess.col || (checkPum && !pumvisible())
|
||
|
|
call s:End()
|
||
|
|
return 0
|
||
|
|
endif
|
||
|
|
return 1
|
||
|
|
endfunction
|
||
|
|
fun! s:UpdateIndex(map,key)
|
||
|
|
let [i,len] = [0,len(a:key)]
|
||
|
|
while i < len
|
||
|
|
let prefix = a:key[0 : i - 1]
|
||
|
|
if !has_key(a:map,prefix)
|
||
|
|
let a:map[prefix] = 1
|
||
|
|
else
|
||
|
|
let a:map[prefix] += 1
|
||
|
|
endif
|
||
|
|
let i += 1
|
||
|
|
endwhile
|
||
|
|
endfunction
|
||
|
|
fun! s:LongestPrefix(sess)
|
||
|
|
let longest = ".*"
|
||
|
|
for e in a:sess.currentList
|
||
|
|
let key = (type(e) == type({})) ? e.word : e
|
||
|
|
if longest == ".*"
|
||
|
|
let longest = a:sess.ignoreCase ? substitute(key, '.', '\l&', 'g') : key
|
||
|
|
else
|
||
|
|
while key !~ '^\V' . ( a:sess.ignoreCase ? '\c' : '\C' ) . escape(longest, '\') && len(longest) > 0
|
||
|
|
let longest = longest[ : -2 ] " remove one char
|
||
|
|
endwhile
|
||
|
|
endif
|
||
|
|
endfor
|
||
|
|
let longest = ( longest == '.*' ) ? '' : longest
|
||
|
|
if a:sess.prefix !=# longest[: len(a:sess.prefix) - 1]
|
||
|
|
let longest = a:sess.prefix . longest[len(a:sess.prefix) :]
|
||
|
|
endif
|
||
|
|
return longest
|
||
|
|
endfunction
|
||
|
|
fun! s:filterCompleteList(sess)
|
||
|
|
let list = []
|
||
|
|
let caseOption = a:sess.ignoreCase ? '\c' : '\C'
|
||
|
|
if a:sess.matchWholeName
|
||
|
|
let pattern = '\V\^' . caseOption . a:sess.prefix . '\$'
|
||
|
|
else
|
||
|
|
let pattern = '\V\^' . caseOption . a:sess.prefix
|
||
|
|
endif
|
||
|
|
for item in a:sess.list
|
||
|
|
let key = (type(item) == type({})) ? item.word : item
|
||
|
|
if key =~ pattern
|
||
|
|
let list += [item]
|
||
|
|
endif
|
||
|
|
endfor
|
||
|
|
return list
|
||
|
|
endfunction
|
||
|
|
fun! s:FindShorter(map,key)
|
||
|
|
let key = a:key
|
||
|
|
if len(key) == 1
|
||
|
|
return ''
|
||
|
|
endif
|
||
|
|
let nmatch = has_key(a:map,key) ? a:map[key] : 1
|
||
|
|
if !has_key(a:map,key[: -2])
|
||
|
|
return key[: -2]
|
||
|
|
endif
|
||
|
|
let key = key[: -2]
|
||
|
|
while key != '' && a:map[key] == nmatch
|
||
|
|
let key = key[: -2]
|
||
|
|
endwhile
|
||
|
|
return key
|
||
|
|
endfunction
|
||
|
|
fun! s:ClassPrototype(...)
|
||
|
|
let p = {}
|
||
|
|
for name in a:000
|
||
|
|
let p[ name ] = function( '<SNR>' . s:sid . name )
|
||
|
|
endfor
|
||
|
|
return p
|
||
|
|
endfunction
|
||
|
|
let s:sessionPrototype2 = s:ClassPrototype( 'popup', 'SetAcceptEmpty', 'SetMatchWholeName', 'SetTriggerKey', 'SetOption', 'KeyPopup', 'ListPopup', )
|
||
|
|
call extend( s:sessionPrototype, s:sessionPrototype2, 'force' )
|
||
|
|
let &cpo = s:oldcpo
|