Commits

Takeshi NISHIDA committed 69618b0

Added g:acp_behaviorUserDefinedFunction option and g:acp_behaviorUserDefinedPattern option

Comments (0)

Files changed (4)

+"=============================================================================
+" Copyright (c) 2007-2009 Takeshi NISHIDA
+"
+"=============================================================================
+" LOAD GUARD {{{1
+
+if exists('g:loaded_autoload_acp') || v:version < 702
+  finish
+endif
+let g:loaded_autoload_acp = 1
+
+" }}}1
+"=============================================================================
+" GLOBAL FUNCTIONS: {{{1
+
+"
+function acp#enable()
+  call acp#disable()
+
+  augroup AcpGlobalAutoCommand
+    autocmd!
+    autocmd InsertEnter * unlet! s:posLast
+    autocmd InsertLeave * call s:finishPopup()
+  augroup END
+
+  if g:acp_mappingDriven
+    call s:mapForMappingDriven()
+  else
+    autocmd AcpGlobalAutoCommand CursorMovedI * call s:feedPopup()
+  endif
+
+  nnoremap <silent> i i<C-r>=<SID>feedPopup()<CR>
+  nnoremap <silent> a a<C-r>=<SID>feedPopup()<CR>
+  nnoremap <silent> R R<C-r>=<SID>feedPopup()<CR>
+endfunction
+
+"
+function acp#disable()
+  call s:unmapForMappingDriven()
+  augroup AcpGlobalAutoCommand
+    autocmd!
+  augroup END
+  nnoremap i <Nop> | nunmap i
+  nnoremap a <Nop> | nunmap a
+  nnoremap R <Nop> | nunmap R
+endfunction
+
+"
+function acp#lock()
+  let s:lockCount += 1
+endfunction
+
+"
+function acp#unlock()
+  let s:lockCount -= 1
+  if s:lockCount < 0
+    let s:lockCount = 0
+    throw "AutoComplPop: not locked"
+  endif
+endfunction
+
+"
+function acp#onPopupPost()
+  if pumvisible()
+    " a command to restore to original text and select the first match
+    return (s:behavsCurrent[0].command =~# "\<C-p>" ? "\<C-n>\<Up>"
+          \                                         : "\<C-p>\<Down>")
+  elseif exists('s:behavsCurrent[1]')
+    call remove(s:behavsCurrent, 0)
+    call s:setCompletefunc()
+    return printf("\<C-e>%s\<C-r>=acp#onPopupPost()\<CR>",
+          \       s:behavsCurrent[0].command)
+  else
+    call s:finishPopup()
+    return "\<C-e>"
+  endif
+endfunction
+
+" }}}1
+"=============================================================================
+" LOCAL FUNCTIONS: {{{1
+
+"
+function s:mapForMappingDriven()
+  call s:unmapForMappingDriven()
+  let s:keysMappingDriven = [
+        \ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+        \ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+        \ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+        \ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+        \ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+        \ '-', '_', '~', '^', '.', ',', ':', '!', '#', '=', '%', '$', '@', '<', '>', '/', '\',
+        \ '<Space>', '<C-h>', '<BS>', ]
+  for key in s:keysMappingDriven
+    execute printf('inoremap <silent> %s %s<C-r>=<SID>feedPopup()<CR>',
+          \        key, key)
+  endfor
+endfunction
+
+"
+function s:unmapForMappingDriven()
+  if !exists('s:keysMappingDriven')
+    return
+  endif
+  for key in s:keysMappingDriven
+    execute 'iunmap ' . key
+  endfor
+  let s:keysMappingDriven = []
+endfunction
+
+"
+function s:setTempOption(name, value)
+  call extend(s:tempOptionSet, { a:name : eval('&' . a:name) }, 'keep')
+  execute printf('let &%s = a:value', a:name)
+endfunction
+
+"
+function s:restoreTempOptionAll()
+  for [name, value] in items(s:tempOptionSet)
+    execute printf('let &%s = value', name)
+  endfor
+  let s:tempOptionSet = {}
+endfunction
+
+"
+function s:matchesBehavior(text, behav)
+  return a:text =~ a:behav.pattern &&
+        \ (!exists('a:behav.exclude') || a:text !~ a:behav.exclude)
+endfunction
+
+"
+function s:isCursorMovedSinceLastCall()
+  if exists('s:posLast')
+    let posPrev = s:posLast
+  endif
+  let s:posLast = getpos('.')
+  if !exists('posPrev')
+    return 1
+  elseif has('multi_byte_ime')
+    return (posPrev[1] != s:posLast[1] || posPrev[2] + 1 == s:posLast[2] ||
+          \ posPrev[2] > s:posLast[2])
+  else
+    return (posPrev != s:posLast)
+  endif
+endfunction
+
+"
+function s:feedPopup()
+  " NOTE: CursorMovedI is not triggered while the popup menu is visible. And
+  "       it will be triggered when popup menu is disappeared.
+  if s:lockCount > 0 || pumvisible() || &paste
+    return ''
+  endif
+  let cursorMoved = s:isCursorMovedSinceLastCall()
+  if exists('s:behavsCurrent[0].repeat') && s:behavsCurrent[0].repeat
+    let s:behavsCurrent = [ s:behavsCurrent[0] ]
+  elseif cursorMoved
+    let s:behavsCurrent = copy(exists('g:acp_behavior[&filetype]')
+          \                    ? g:acp_behavior[&filetype]
+          \                    : g:acp_behavior['*'])
+  else
+    let s:behavsCurrent = []
+  endif
+  let text = strpart(getline('.'), 0, col('.') - 1)
+  call filter(s:behavsCurrent, 's:matchesBehavior(text, v:val)')
+  if empty(s:behavsCurrent)
+    call s:finishPopup()
+    return ''
+  endif
+  " In case of dividing words by symbols (e.g. "for(int", "ab==cd") while a
+  " popup menu is visible, another popup is not available unless input <C-e>
+  " or try popup once. So first completion is duplicated.
+  call insert(s:behavsCurrent, s:behavsCurrent[0])
+  call s:setTempOption('spell', 0)
+  call s:setTempOption('completeopt', 'menuone' . (g:acp_completeoptPreview ? ',preview' : ''))
+  call s:setTempOption('complete', g:acp_completeOption)
+  call s:setTempOption('ignorecase', g:acp_ignorecaseOption)
+  " NOTE: With CursorMovedI driven, Set 'lazyredraw' to avoid flickering.
+  "       With Mapping driven, set 'nolazyredraw' to make a popup menu visible.
+  call s:setTempOption('lazyredraw', !g:acp_mappingDriven)
+  call s:setCompletefunc()
+  call feedkeys(s:behavsCurrent[0].command, 'n') " use <Plug> for silence instead of <C-r>=
+  call feedkeys("\<Plug>AcpOnPopupPost", 'm')
+  return '' " for <C-r>=
+endfunction
+
+"
+function s:finishPopup()
+  let s:behavsCurrent = []
+  call s:restoreTempOptionAll()
+endfunction
+
+"
+function s:setCompletefunc()
+  if exists('s:behavsCurrent[0].completefunc')
+    call s:setTempOption('completefunc', s:behavsCurrent[0].completefunc)
+  endif
+endfunction
+
+" }}}1
+"=============================================================================
+" INITIALIZATION {{{1
+
+let s:lockCount = 0
+let s:behavsCurrent = []
+let s:tempOptionSet = {}
+
+inoremap <silent> <expr> <Plug>AcpOnPopupPost acp#onPopupPost()
+
+
+" }}}1
+"=============================================================================
+" vim: set fdm=marker:
 <
         真なら自動ポップアップ時に、 'completeopt' へ "preview" を追加します。
 
+                                             *g:acp_behaviorUserDefinedFunction*  >
+  let g:acp_behaviorUserDefinedFunction = ''
+<
+        ユーザー定義補完の関数。空ならこの補完は行いません。
+
+                                             *g:acp_behaviorUserDefinedPattern*  >
+  let g:acp_behaviorUserDefinedPattern = '\k$'
+<
+        ユーザー定義補完の自動ポップアップを行うのに必要なカーソルの直前のパタ
+        ーン。
+
                                              *g:acp_behaviorKeywordCommand*  >
   let g:acp_behaviorKeywordCommand = "\<C-p>"
 <
           'completefunc' に設定する関数。 "command" が "<C-x><C-u>" のときだけ
           意味があります。。
 
-        "pattern", "excluded":
-          カーソル直前テキストが "pattern" にマッチし、"excluded" にマッチしな
+        "pattern", "exclude":
+          カーソル直前テキストが "pattern" にマッチし、"exclude" にマッチしな
           かった場合、補完メニューをポップアップします。
 
         "repeat":
 <
         If non-zero, "preview" is added to 'completeopt' when auto-popup.
 
+                                             *g:acp_behaviorUserDefinedFunction*  >
+  let g:acp_behaviorUserDefinedFunction = ''
+<
+        Function for user-defined completion. If empty, this completion will
+        be never attempted.
+
+        See also:|complete-functions|
+
+                                             *g:acp_behaviorUserDefinedPattern*  >
+  let g:acp_behaviorUserDefinedPattern = '\k$'
+<
+        Pattern before a cursor, which are needed to attempt user-defined
+        completion.
+
                                              *g:acp_behaviorKeywordCommand*  >
   let g:acp_behaviorKeywordCommand = "\<C-p>"
 <
                                               *g:acp_behaviorKeywordLength*  >
   let g:acp_behaviorKeywordLength = 2
 <
-        Length of keyword characters before the cursor, which are needed to
-        attempt the keyword completion. If negative value, it will never
-        attempt this completion.
+        Length of keyword characters before a cursor, which are needed to
+        attempt keyword completion. If negative value, this completion will be
+        never attempted.
 
                                                  *g:acp_behaviorFileLength*  >
   let g:acp_behaviorFileLength = 0
 <
-        Length of filename characters before the cursor, which are needed to
-        attempt the filename completion. If negative value, it will never
-        attempt this completion.
+        Length of filename characters before a cursor, which are needed to
+        attempt filename completion. If negative value, this completion will
+        be never attempted.
 
                                        *g:acp_behaviorRubyOmniMethodLength*  >
   let g:acp_behaviorRubyOmniMethodLength = 0
 <
-        Length of keyword characters before the cursor, which are needed to
-        attempt the ruby omni-completion for methods. If negative value, it
-        will never attempt this completion.
+        Length of keyword characters before a cursor, which are needed to
+        attempt ruby omni-completion for methods. If negative value, this
+        completion will be never attempted.
 
                                        *g:acp_behaviorRubyOmniSymbolLength*  >
   let g:acp_behaviorRubyOmniSymbolLength = 1
 <
-        Length of keyword characters before the cursor, which are needed to
-        attempt the ruby omni-completion for symbols. If negative value, it
-        will never attempt this completion.
+        Length of keyword characters before a cursor, which are needed to
+        attempt ruby omni-completion for symbols. If negative value, this
+        completion will be never attempted.
 
                                            *g:acp_behaviorPythonOmniLength*  >
   let g:acp_behaviorPythonOmniLength = 0
 <
-        Length of keyword characters before the cursor, which are needed to
-        attempt the python omni-completion. If negative value, it will never
-        attempt this completion.
+        Length of keyword characters before a cursor, which are needed to
+        attempt python omni-completion. If negative value, this completion
+        will be never attempted.
 
                                              *g:acp_behaviorHtmlOmniLength*  >
   let g:acp_behaviorHtmlOmniLength = 0
 <
-        Length of keyword characters before the cursor, which are needed to
-        attempt the HTML omni-completion. If negative value, it will never
-        attempt this completion.
+        Length of keyword characters before a cursor, which are needed to
+        attempt HTML omni-completion. If negative value, this completion will
+        be never attempted.
 
                                       *g:acp_behaviorCssOmniPropertyLength*  >
   let g:acp_behaviorCssOmniPropertyLength = 1
 <
-        Length of keyword characters before the cursor, which are needed to
-        attempt the CSS omni-completion for properties. If negative value, it
-        will never attempt this completion.
+        Length of keyword characters before a cursor, which are needed to
+        attempt CSS omni-completion for properties. If negative value, this
+        completion will be never attempted.
 
                                          *g:acp_behaviorCssOmniValueLength*  >
   let g:acp_behaviorCssOmniValueLength = 0
 <
-        Length of keyword characters before the cursor, which are needed to
-        attempt the CSS omni-completion for values. If negative value, it will
-        never attempt this completion.
+        Length of keyword characters before a cursor, which are needed to
+        attempt CSS omni-completion for values. If negative value, this
+        completion will be never attempted.
 
                                                            *g:acp_behavior*  >
   let g:acp_behavior = {}
           'completefunc' will be set to this user-provided function during the
           completion. Only makes sense when "command" is "<C-x><C-u>".
 
-        "pattern", "excluded":
-          If a text before the cursor matches "pattern" and not "excluded",
-          popup menu is opened.
+        "pattern", "exclude":
+          If a text before a cursor matches "pattern" and not "exclude", popup
+          menu is opened.
 
         "repeat":
           If non-zero, the last completion is automatically repeated.
 ==============================================================================
 CHANGELOG                                                      *acp-changelog*
 
-2.7.1 (or 2.8)
+2.8
+  - Added g:acp_behaviorUserDefinedFunction option and
+    g:acp_behaviorUserDefinedPattern option for users who want to make custom
+    completion auto-popup.
   - Fixed a bug that setting 'spell' on a new buffer made typing go crazy.
 
 2.7
         \   'css'    : [],
         \ }
   "---------------------------------------------------------------------------
+  if !empty(g:acp_behaviorUserDefinedFunction)
+    for key in keys(behavs)
+      call add(behavs[key], {
+            \   'command'      : "\<C-x>\<C-u>",
+            \   'completefunc' : g:acp_behaviorUserDefinedFunction,
+            \   'pattern'      : g:acp_behaviorUserDefinedPattern,
+            \   'repeat'       : 0,
+            \ })
+    endfor
+  endif
+  "---------------------------------------------------------------------------
   if g:acp_behaviorKeywordLength >= 0
     for key in keys(behavs)
       call add(behavs[key], {
-            \   'command'  : g:acp_behaviorKeywordCommand,
-            \   'pattern'  : printf('\k\{%d,}$', g:acp_behaviorKeywordLength),
-            \   'repeat'   : 0,
+            \   'command' : g:acp_behaviorKeywordCommand,
+            \   'pattern' : printf('\k\{%d,}$', g:acp_behaviorKeywordLength),
+            \   'repeat'  : 0,
             \ })
     endfor
   endif
   if g:acp_behaviorFileLength >= 0
     for key in keys(behavs)
       call add(behavs[key], {
-            \   'command'  : "\<C-x>\<C-f>",
-            \   'pattern'  : printf('\f[%s]\f\{%d,}$', (has('win32') || has('win64') ? '/\\' : '/'),
-            \                       g:acp_behaviorFileLength),
-            \   'excluded' : '[*/\\][/\\]\f*$\|[^[:print:]]\f*$',
-            \   'repeat'   : 1,
+            \   'command' : "\<C-x>\<C-f>",
+            \   'pattern' : printf('\f[%s]\f\{%d,}$', (has('win32') || has('win64') ? '/\\' : '/'),
+            \                      g:acp_behaviorFileLength),
+            \   'exclude' : '[*/\\][/\\]\f*$\|[^[:print:]]\f*$',
+            \   'repeat'  : 1,
             \ })
     endfor
   endif
   "---------------------------------------------------------------------------
   if has('ruby') && g:acp_behaviorRubyOmniMethodLength >= 0
     call add(behavs.ruby, {
-          \   'command'  : "\<C-x>\<C-o>",
-          \   'pattern'  : printf('[^. \t]\(\.\|::\)\k\{%d,}$', g:acp_behaviorRubyOmniMethodLength),
-          \   'repeat'   : 0,
+          \   'command' : "\<C-x>\<C-o>",
+          \   'pattern' : printf('[^. \t]\(\.\|::\)\k\{%d,}$',
+          \                      g:acp_behaviorRubyOmniMethodLength),
+          \   'repeat'  : 0,
           \ })
   endif
   "---------------------------------------------------------------------------
   if has('ruby') && g:acp_behaviorRubyOmniSymbolLength >= 0
     call add(behavs.ruby, {
-          \   'command'  : "\<C-x>\<C-o>",
-          \   'pattern'  : printf('\(^\|[^:]\):\k\{%d,}$', g:acp_behaviorRubyOmniSymbolLength),
-          \   'repeat'   : 0,
+          \   'command' : "\<C-x>\<C-o>",
+          \   'pattern' : printf('\(^\|[^:]\):\k\{%d,}$',
+          \                      g:acp_behaviorRubyOmniSymbolLength),
+          \   'repeat'  : 0,
           \ })
   endif
   "---------------------------------------------------------------------------
   if has('python') && g:acp_behaviorPythonOmniLength >= 0
     call add(behavs.python, {
-          \   'command'  : "\<C-x>\<C-o>",
-          \   'pattern'  : printf('\k\.\k\{%d,}$', g:acp_behaviorPythonOmniLength),
-          \   'repeat'   : 0,
+          \   'command' : "\<C-x>\<C-o>",
+          \   'pattern' : printf('\k\.\k\{%d,}$',
+          \                      g:acp_behaviorPythonOmniLength),
+          \   'repeat'  : 0,
           \ })
   endif
   "---------------------------------------------------------------------------
   if g:acp_behaviorHtmlOmniLength >= 0
-    let behav_html = {
-          \   'command'  : "\<C-x>\<C-o>",
-          \   'pattern'  : printf('\(<\|<\/\|<[^>]\+ \|<[^>]\+=\"\)\k\{%d,}$', g:acp_behaviorHtmlOmniLength),
-          \   'repeat'   : 1,
+    let behavHtml = {
+          \   'command' : "\<C-x>\<C-o>",
+          \   'pattern' : printf('\(<\|<\/\|<[^>]\+ \|<[^>]\+=\"\)\k\{%d,}$',
+          \                      g:acp_behaviorHtmlOmniLength),
+          \   'repeat'  : 1,
           \ }
-    call add(behavs.html , behav_html)
-    call add(behavs.xhtml, behav_html)
+    call add(behavs.html , behavHtml)
+    call add(behavs.xhtml, behavHtml)
   endif
   "---------------------------------------------------------------------------
   if g:acp_behaviorCssOmniPropertyLength >= 0
     call add(behavs.css, {
-          \   'command'  : "\<C-x>\<C-o>",
-          \   'pattern'  : printf('\(^\s\|[;{]\)\s*\k\{%d,}$', g:acp_behaviorCssOmniPropertyLength),
-          \   'repeat'   : 0,
+          \   'command' : "\<C-x>\<C-o>",
+          \   'pattern' : printf('\(^\s\|[;{]\)\s*\k\{%d,}$',
+          \                      g:acp_behaviorCssOmniPropertyLength),
+          \   'repeat'  : 0,
           \ })
   endif
   "---------------------------------------------------------------------------
   if g:acp_behaviorCssOmniValueLength >= 0
     call add(behavs.css, {
-          \   'command'  : "\<C-x>\<C-o>",
-          \   'pattern'  : printf('[:@!]\s*\k\{%d,}$', g:acp_behaviorCssOmniValueLength),
-          \   'repeat'   : 0,
+          \   'command' : "\<C-x>\<C-o>",
+          \   'pattern' : printf('[:@!]\s*\k\{%d,}$',
+          \                      g:acp_behaviorCssOmniValueLength),
+          \   'repeat'  : 0,
           \ })
   endif
   "---------------------------------------------------------------------------
   return behavs
 endfunction
 
-"
-function s:enable()
-  call s:disable()
-
-  augroup AcpGlobalAutoCommand
-    autocmd!
-    autocmd InsertEnter * unlet! s:posLast
-    autocmd InsertLeave * call s:finishPopup()
-  augroup END
-
-  if g:acp_mappingDriven
-    call s:mapForMappingDriven()
-  else
-    autocmd AcpGlobalAutoCommand CursorMovedI * call s:feedPopup()
-  endif
-
-  nnoremap <silent> i i<C-r>=<SID>feedPopup()<CR>
-  nnoremap <silent> a a<C-r>=<SID>feedPopup()<CR>
-  nnoremap <silent> R R<C-r>=<SID>feedPopup()<CR>
-endfunction
-
-"
-function s:disable()
-  call s:unmapForMappingDriven()
-  augroup AcpGlobalAutoCommand
-    autocmd!
-  augroup END
-  nnoremap i <Nop> | nunmap i
-  nnoremap a <Nop> | nunmap a
-  nnoremap R <Nop> | nunmap R
-endfunction
-
-"
-let s:lockCount = 0
-
-"
-function s:lock()
-  let s:lockCount += 1
-endfunction
-
-"
-function s:unlock()
-  let s:lockCount -= 1
-  if s:lockCount < 0
-    let s:lockCount = 0
-    throw "autocomplpop.vim: not locked"
-  endif
-endfunction
-
-"
-function s:mapForMappingDriven()
-  call s:unmapForMappingDriven()
-  let s:keysMappingDriven = [
-        \ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
-        \ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
-        \ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
-        \ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
-        \ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
-        \ '-', '_', '~', '^', '.', ',', ':', '!', '#', '=', '%', '$', '@', '<', '>', '/', '\',
-        \ '<Space>', '<C-h>', '<BS>', ]
-  for key in s:keysMappingDriven
-    execute printf('inoremap <silent> %s %s<C-r>=<SID>feedPopup()<CR>',
-          \        key, key)
-  endfor
-endfunction
-
-"
-function s:unmapForMappingDriven()
-  if !exists('s:keysMappingDriven')
-    return
-  endif
-  for key in s:keysMappingDriven
-    execute 'iunmap ' . key
-  endfor
-  let s:keysMappingDriven = []
-endfunction
-
-"
-let s:tempOptionSet = { }
-
-"
-function s:setTempOption(name, value)
-  call extend(s:tempOptionSet, { a:name : eval('&' . a:name) }, 'keep')
-  execute printf('let &%s = a:value', a:name)
-endfunction
-
-"
-function s:restoreTempOptionAll()
-  for [name, value] in items(s:tempOptionSet)
-    execute printf('let &%s = value', name)
-  endfor
-  let s:tempOptionSet = {}
-endfunction
-
-"
-function s:matchesBehavior(text, behav)
-  return a:text =~ a:behav.pattern &&
-        \ (!exists('a:behav.excluded') || a:text !~ a:behav.excluded)
-endfunction
-
-"
-function s:isCursorMovedSinceLastCall()
-  if exists('s:posLast')
-    let posPrev = s:posLast
-  endif
-  let s:posLast = getpos('.')
-  if !exists('posPrev')
-    return 1
-  elseif has('multi_byte_ime')
-    return (posPrev[1] != s:posLast[1] || posPrev[2] + 1 == s:posLast[2] ||
-          \ posPrev[2] > s:posLast[2])
-  else
-    return (posPrev != s:posLast)
-  endif
-endfunction
-
-"
-let s:behavsCurrent = []
-
-"
-function s:feedPopup()
-  " NOTE: CursorMovedI is not triggered while the popup menu is visible. And
-  "       it will be triggered when popup menu is disappeared.
-  if s:lockCount > 0 || pumvisible() || &paste
-    return ''
-  endif
-  let cursorMoved = s:isCursorMovedSinceLastCall()
-  if exists('s:behavsCurrent[0].repeat') && s:behavsCurrent[0].repeat
-    let s:behavsCurrent = [ s:behavsCurrent[0] ]
-  elseif cursorMoved
-    let s:behavsCurrent = copy(exists('g:acp_behavior[&filetype]')
-          \                    ? g:acp_behavior[&filetype]
-          \                    : g:acp_behavior['*'])
-  else
-    let s:behavsCurrent = []
-  endif
-  let text = strpart(getline('.'), 0, col('.') - 1)
-  call filter(s:behavsCurrent, 's:matchesBehavior(text, v:val)')
-  if empty(s:behavsCurrent)
-    call s:finishPopup()
-    return ''
-  endif
-  " In case of dividing words by symbols (e.g. "for(int", "ab==cd") while a
-  " popup menu is visible, another popup is not available unless input <C-e>
-  " or try popup once. So first completion is duplicated.
-  call insert(s:behavsCurrent, s:behavsCurrent[0])
-  call s:setTempOption('spell', 0)
-  call s:setTempOption('completeopt', 'menuone' . (g:acp_completeoptPreview ? ',preview' : ''))
-  call s:setTempOption('complete', g:acp_completeOption)
-  call s:setTempOption('ignorecase', g:acp_ignorecaseOption)
-  " NOTE: With CursorMovedI driven, Set 'lazyredraw' to avoid flickering.
-  "       With Mapping driven, set 'nolazyredraw' to make a popup menu visible.
-  call s:setTempOption('lazyredraw', !g:acp_mappingDriven)
-  call s:setCompletefunc()
-  call feedkeys(s:behavsCurrent[0].command, 'n') " use <Plug> for silence instead of <C-r>=
-  call feedkeys("\<Plug>AcpOnPopupPost", 'm')
-  return '' " for <C-r>=
-endfunction
-
-"
-function s:finishPopup()
-  let s:behavsCurrent = []
-  call s:restoreTempOptionAll()
-endfunction
-
-"
-function s:setCompletefunc()
-  if exists('s:behavsCurrent[0].completefunc')
-    call s:setTempOption('completefunc', s:behavsCurrent[0].completefunc)
-  endif
-endfunction
-
-"
-function s:onPopupPost()
-  if pumvisible()
-    " a command to restore to original text and select the first match
-    return (s:behavsCurrent[0].command =~# "\<C-p>" ? "\<C-n>\<Up>"
-          \                                         : "\<C-p>\<Down>")
-  elseif exists('s:behavsCurrent[1]')
-    call remove(s:behavsCurrent, 0)
-    call s:setCompletefunc()
-    return printf("\<C-e>%s\<C-r>=%sonPopupPost()\<CR>",
-          \       s:behavsCurrent[0].command, s:PREFIX_SID)
-  else
-    call s:finishPopup()
-    return "\<C-e>"
-  endif
-endfunction
-
 " }}}1
 "=============================================================================
 " INITIALIZATION {{{1
 
 "-----------------------------------------------------------------------------
-function s:getSidPrefix()
-  return matchstr(expand('<sfile>'), '<SNR>\d\+_')
-endfunction
-let s:PREFIX_SID = s:getSidPrefix()
-delfunction s:getSidPrefix
-"-----------------------------------------------------------------------------
 call s:defineOption('g:acp_enableAtStartup', 1)
 call s:defineOption('g:acp_mappingDriven', 0)
 call s:defineOption('g:acp_ignorecaseOption', 1)
 call s:defineOption('g:acp_completeOption', '.,w,b,k')
 call s:defineOption('g:acp_completeoptPreview', 0)
+call s:defineOption('g:acp_behaviorUserDefinedFunction', '')
+call s:defineOption('g:acp_behaviorUserDefinedPattern' , '\k$')
 call s:defineOption('g:acp_behaviorKeywordCommand', "\<C-p>")
 call s:defineOption('g:acp_behaviorKeywordLength', 2)
 call s:defineOption('g:acp_behaviorFileLength', 0)
 "-----------------------------------------------------------------------------
 call extend(g:acp_behavior, s:makeDefaultBehavior(), 'keep')
 "-----------------------------------------------------------------------------
-command! -bar -narg=0 AcpEnable  call s:enable()
-command! -bar -narg=0 AcpDisable call s:disable()
-command! -bar -narg=0 AcpLock    call s:lock()
-command! -bar -narg=0 AcpUnlock  call s:unlock()
+command! -bar -narg=0 AcpEnable  call acp#enable()
+command! -bar -narg=0 AcpDisable call acp#disable()
+command! -bar -narg=0 AcpLock    call acp#lock()
+command! -bar -narg=0 AcpUnlock  call acp#unlock()
 "-----------------------------------------------------------------------------
 " legacy commands
 command! -bar -narg=0 AutoComplPopEnable  AcpEnable
 command! -bar -narg=0 AutoComplPopLock    AcpLock
 command! -bar -narg=0 AutoComplPopUnlock  AcpUnlock
 "-----------------------------------------------------------------------------
-inoremap <silent> <expr> <Plug>AcpOnPopupPost <SID>onPopupPost()
-"-----------------------------------------------------------------------------
 if g:acp_enableAtStartup
   AcpEnable
 endif