UltiSnips/plugin/UltiSnips.vim

305 lines
10 KiB
VimL
Raw Normal View History

" File: UltiSnips.vim
" Author: Holger Rapp <SirVer@gmx.de>
" Description: The Ultimate Snippets solution for Vim
"
" Testing Info: {{{
" See directions at the top of the test.py script located one
A "clearsnippets" feature ========================= It's difficult for the user to control which of the default bundled snippets are active in his environment. The 'runtimepath' variable must be set to the root of the ultisnips installation, which brings in all of the bundled snippets. Though the user may individually override the definition of the bundled snippets using the "!" flag, the method has a couple of problems: - There's no way to remove a snippet, only to override it (and each snippet must be overridden individually). - The "!" flag currently doesn't remove the overridden snippets from the "list snippets" command. It might be considered a feature that "!" doesn't actually remove the snippets from the "list snippets" command, though perhaps that's an unintended effect. In any case, it would be more convenient to allow the user to selectively remove the bundled snippets from his environment. A patch is provided in the following branch to address these problems: http://code.launchpad.net/~drmikehenry/ultisnips/clearsnippets The branch's primary purpose is the addition of a "clearsnippets" command that may be placed in a user's ~/.vim/UltiSnips/ft.snippets file. The user may clear all lower-priority snippet for that file type with the line: clearsnippets Alternatively, he may clear individual snippets by listing their triggers: clearsnippets trigger1 trigger2 A few changes were made to the testing system as part of the incorporation of this new feature. These changes include: - The "extends" directive is now supported on multiple lines throughout file. - A completely empty .snippets file is now possible. - The test.py scripts now handles most of the vim setup, simplifying the running of the tests. The invocation of Vim now reduces to: vim -u NONE Instructions for running the tests are included at top of test.py, where they should be more visible to interested users; UltiSnips.vim now just points to test.py's instructions. - A new function vim_quote() encodes an arbitrary string into a singly-quoted Vim string, with embedded quotes escaped. - SnippetsFileParser() now allows file_data to be passed directly for unit testing, avoiding the need to create files in the filesystem for test purposes. - A new _error() function reports errors to the user. At runtime, this function uses :echo_err in general, but also can append error text to current buffer to check for expected errors during unit tests. - Added error checks to snippets file parsing, along with unit tests for the parsing. - Increased retries from 2 to 4 (on my system, occasionally the timing still causes tests to fail).
2009-09-08 20:15:10 -04:00
" directory above this file.
" }}}
if exists('did_UltiSnips_vim') || &cp || version < 700
A "clearsnippets" feature ========================= It's difficult for the user to control which of the default bundled snippets are active in his environment. The 'runtimepath' variable must be set to the root of the ultisnips installation, which brings in all of the bundled snippets. Though the user may individually override the definition of the bundled snippets using the "!" flag, the method has a couple of problems: - There's no way to remove a snippet, only to override it (and each snippet must be overridden individually). - The "!" flag currently doesn't remove the overridden snippets from the "list snippets" command. It might be considered a feature that "!" doesn't actually remove the snippets from the "list snippets" command, though perhaps that's an unintended effect. In any case, it would be more convenient to allow the user to selectively remove the bundled snippets from his environment. A patch is provided in the following branch to address these problems: http://code.launchpad.net/~drmikehenry/ultisnips/clearsnippets The branch's primary purpose is the addition of a "clearsnippets" command that may be placed in a user's ~/.vim/UltiSnips/ft.snippets file. The user may clear all lower-priority snippet for that file type with the line: clearsnippets Alternatively, he may clear individual snippets by listing their triggers: clearsnippets trigger1 trigger2 A few changes were made to the testing system as part of the incorporation of this new feature. These changes include: - The "extends" directive is now supported on multiple lines throughout file. - A completely empty .snippets file is now possible. - The test.py scripts now handles most of the vim setup, simplifying the running of the tests. The invocation of Vim now reduces to: vim -u NONE Instructions for running the tests are included at top of test.py, where they should be more visible to interested users; UltiSnips.vim now just points to test.py's instructions. - A new function vim_quote() encodes an arbitrary string into a singly-quoted Vim string, with embedded quotes escaped. - SnippetsFileParser() now allows file_data to be passed directly for unit testing, avoiding the need to create files in the filesystem for test purposes. - A new _error() function reports errors to the user. At runtime, this function uses :echo_err in general, but also can append error text to current buffer to check for expected errors during unit tests. - Added error checks to snippets file parsing, along with unit tests for the parsing. - Increased retries from 2 to 4 (on my system, occasionally the timing still causes tests to fail).
2009-09-08 20:15:10 -04:00
finish
endif
" Define dummy version of function called by autocommand setup in
" ftdetect/UltiSnips.vim. If the function isn't defined (probably due to
" using a copy of vim without python support) it will cause an error anytime a
" new file is opened.
function! UltiSnips_FileTypeChanged()
endfunction
2012-02-08 10:28:39 -05:00
if !exists("g:UltiSnipsUsePythonVersion")
let g:_uspy=":py3 "
if !has("python3")
if !has("python")
if !exists("g:UltiSnipsNoPythonWarning")
echo "UltiSnips requires py >= 2.6 or any py3"
endif
2012-02-08 10:28:39 -05:00
finish
endif
let g:_uspy=":py "
endif
let g:UltiSnipsUsePythonVersion = "<tab>"
else
if g:UltiSnipsUsePythonVersion == 2
let g:_uspy=":py "
else
let g:_uspy=":py3 "
endif
endif
" Global Variables {{{
" The trigger used to expand a snippet.
" NOTE: expansion and forward jumping can, but needn't be the same trigger
if !exists("g:UltiSnipsExpandTrigger")
2011-04-27 11:37:07 -04:00
let g:UltiSnipsExpandTrigger = "<tab>"
endif
" The trigger used to display all triggers that could possible
" match in the current position.
if !exists("g:UltiSnipsListSnippets")
2011-04-27 11:37:07 -04:00
let g:UltiSnipsListSnippets = "<c-tab>"
endif
" The trigger used to jump forward to the next placeholder.
" NOTE: expansion and forward jumping can, but needn't be the same trigger
if !exists("g:UltiSnipsJumpForwardTrigger")
2011-04-27 11:37:07 -04:00
let g:UltiSnipsJumpForwardTrigger = "<c-j>"
endif
" The trigger to jump backward inside a snippet
if !exists("g:UltiSnipsJumpBackwardTrigger")
2011-04-27 11:37:07 -04:00
let g:UltiSnipsJumpBackwardTrigger = "<c-k>"
endif
" Should UltiSnips unmap select mode mappings automagically?
if !exists("g:UltiSnipsRemoveSelectModeMappings")
2011-04-27 11:37:07 -04:00
let g:UltiSnipsRemoveSelectModeMappings = 1
end
" If UltiSnips should remove Mappings, which should be ignored
if !exists("g:UltiSnipsMappingsToIgnore")
2011-04-27 11:37:07 -04:00
let g:UltiSnipsMappingsToIgnore = []
endif
" UltiSnipsEdit will use this variable to decide if a new window
" is opened when editing. default is "normal", allowed are also
" "vertical", "horizontal"
if !exists("g:UltiSnipsEditSplit")
2011-04-27 11:37:07 -04:00
let g:UltiSnipsEditSplit = 'normal'
endif
" A list of directory names that are searched for snippets.
if !exists("g:UltiSnipsSnippetDirectories")
2011-04-27 11:37:07 -04:00
let g:UltiSnipsSnippetDirectories = [ "UltiSnips" ]
endif
" Should UltiSnips map JumpForwardTrigger and JumpBackwardTrigger only during
" snippet expansion?
if !exists("g:UltiSnipsClearJumpTrigger")
let g:UltiSnipsClearJumpTrigger = 1
endif
" }}}
" Global Commands {{{
function! UltiSnipsEdit(...)
2011-04-27 11:37:07 -04:00
if a:0 == 1 && a:1 != ''
let type = a:1
else
exec g:_uspy "vim.command(\"let type = '%s'\" % UltiSnips_Manager.primary_filetype)"
endif
exec g:_uspy "vim.command(\"let file = '%s'\" % UltiSnips_Manager.file_to_edit(vim.eval(\"type\")))"
let mode = 'e'
if exists('g:UltiSnipsEditSplit')
if g:UltiSnipsEditSplit == 'vertical'
let mode = 'vs'
elseif g:UltiSnipsEditSplit == 'horizontal'
let mode = 'sp'
2011-04-27 11:37:07 -04:00
endif
endif
exe ':'.mode.' '.file
endfunction
" edit snippets, default of current file type or the specified type
command! -nargs=? -complete=customlist,UltiSnipsFiletypeComplete UltiSnipsEdit
\ :call UltiSnipsEdit(<q-args>)
" Global Commands {{{
function! UltiSnipsAddFiletypes(filetypes)
exec g:_uspy "UltiSnips_Manager.add_buffer_filetypes('" . a:filetypes . ".all')"
return ""
endfunction
command! -nargs=1 UltiSnipsAddFiletypes :call UltiSnipsAddFiletypes(<q-args>)
"" }}}
" FUNCTIONS {{{
2010-07-12 08:52:12 -04:00
function! CompensateForPUM()
2011-04-27 11:37:07 -04:00
""" The CursorMovedI event is not triggered while the popup-menu is visible,
""" and it's by this event that UltiSnips updates its vim-state. The fix is
""" to explicitly check for the presence of the popup menu, and update
""" the vim-state accordingly.
if pumvisible()
exec g:_uspy "UltiSnips_Manager.cursor_moved()"
2011-04-27 11:37:07 -04:00
endif
2010-07-12 08:52:12 -04:00
endfunction
function! UltiSnips_ExpandSnippet()
exec g:_uspy "UltiSnips_Manager.expand()"
2011-04-27 11:37:07 -04:00
return ""
endfunction
function! UltiSnips_ExpandSnippetOrJump()
2011-04-27 11:37:07 -04:00
call CompensateForPUM()
exec g:_uspy "UltiSnips_Manager.expand_or_jump()"
2011-04-27 11:37:07 -04:00
return ""
2009-07-04 06:15:12 -04:00
endfunction
function! UltiSnips_ListSnippets()
exec g:_uspy "UltiSnips_Manager.list_snippets()"
2011-04-27 11:37:07 -04:00
return ""
endfunction
function! UltiSnips_SnippetsInCurrentScope()
let g:current_ulti_dict = {}
exec g:_uspy "UltiSnips_Manager.list_snippets_dict()"
return g:current_ulti_dict
endfunction
function! UltiSnips_SaveLastVisualSelection()
exec g:_uspy "UltiSnips_Manager.save_last_visual_selection()"
return ""
endfunction
2009-07-10 06:47:54 -04:00
function! UltiSnips_JumpBackwards()
2011-04-27 11:37:07 -04:00
call CompensateForPUM()
exec g:_uspy "UltiSnips_Manager.jump_backwards()"
2011-04-27 11:37:07 -04:00
return ""
endfunction
2009-07-10 06:47:54 -04:00
function! UltiSnips_JumpForwards()
2011-04-27 11:37:07 -04:00
call CompensateForPUM()
exec g:_uspy "UltiSnips_Manager.jump_forwards()"
2011-04-27 11:37:07 -04:00
return ""
2009-07-04 06:15:12 -04:00
endfunction
function! UltiSnips_FileTypeChanged()
exec g:_uspy "UltiSnips_Manager.reset_buffer_filetypes()"
exec g:_uspy "UltiSnips_Manager.add_buffer_filetypes('" . &ft . "')"
return ""
endfunction
function! UltiSnips_AddSnippet(trigger, value, descr, options, ...)
2011-04-27 11:37:07 -04:00
" Takes the same arguments as SnippetManager.add_snippet:
" (trigger, value, descr, options, ft = "all", globals = None)
exec g:_uspy "args = vim.eval(\"a:000\")"
exec g:_uspy "trigger = vim.eval(\"a:trigger\")"
exec g:_uspy "value = vim.eval(\"a:value\")"
exec g:_uspy "descr = vim.eval(\"a:descr\")"
exec g:_uspy "options = vim.eval(\"a:options\")"
exec g:_uspy "UltiSnips_Manager.add_snippet(trigger, value, descr, options, *args)"
2011-04-27 11:37:07 -04:00
return ""
endfunction
function! UltiSnips_Anon(value, ...)
2011-04-27 11:37:07 -04:00
" Takes the same arguments as SnippetManager.expand_anon:
" (value, trigger="", descr="", options="", globals = None)
exec g:_uspy "args = vim.eval(\"a:000\")"
exec g:_uspy "value = vim.eval(\"a:value\")"
exec g:_uspy "UltiSnips_Manager.expand_anon(value, *args)"
2011-04-27 11:37:07 -04:00
return ""
endfunction
2009-07-04 06:15:12 -04:00
function! UltiSnips_MapKeys()
2011-04-27 11:37:07 -04:00
" Map the keys correctly
if g:UltiSnipsExpandTrigger == g:UltiSnipsJumpForwardTrigger
2011-04-27 11:37:07 -04:00
exec "inoremap <silent> " . g:UltiSnipsExpandTrigger . " <C-R>=UltiSnips_ExpandSnippetOrJump()<cr>"
exec "snoremap <silent> " . g:UltiSnipsExpandTrigger . " <Esc>:call UltiSnips_ExpandSnippetOrJump()<cr>"
else
exec "inoremap <silent> " . g:UltiSnipsExpandTrigger . " <C-R>=UltiSnips_ExpandSnippet()<cr>"
exec "snoremap <silent> " . g:UltiSnipsExpandTrigger . " <Esc>:call UltiSnips_ExpandSnippet()<cr>"
if g:UltiSnipsClearJumpTrigger == 0
exec "inoremap <silent> " . g:UltiSnipsJumpForwardTrigger . " <C-R>=UltiSnips_JumpForwards()<cr>"
exec "snoremap <silent> " . g:UltiSnipsJumpForwardTrigger . " <Esc>:call UltiSnips_JumpForwards()<cr>"
endif
2011-04-27 11:37:07 -04:00
endif
exec 'xnoremap ' . g:UltiSnipsExpandTrigger. ' :call UltiSnips_SaveLastVisualSelection()<cr>gvs'
if g:UltiSnipsClearJumpTrigger == 0
exec "inoremap <silent> " . g:UltiSnipsJumpBackwardTrigger . " <C-R>=UltiSnips_JumpBackwards()<cr>"
exec "snoremap <silent> " . g:UltiSnipsJumpBackwardTrigger . " <Esc>:call UltiSnips_JumpBackwards()<cr>"
endif
2011-04-27 11:37:07 -04:00
exec "inoremap <silent> " . g:UltiSnipsListSnippets . " <C-R>=UltiSnips_ListSnippets()<cr>"
exec "snoremap <silent> " . g:UltiSnipsListSnippets . " <Esc>:call UltiSnips_ListSnippets()<cr>"
2012-01-17 03:30:19 -05:00
snoremap <silent> <BS> <c-g>c
snoremap <silent> <DEL> <c-g>c
snoremap <silent> <c-h> <c-g>c
endf
function! UltiSnips_MapInnerKeys()
if g:UltiSnipsExpandTrigger != g:UltiSnipsJumpForwardTrigger
exec "inoremap <buffer> <silent> " . g:UltiSnipsJumpForwardTrigger . " <C-R>=UltiSnips_JumpForwards()<cr>"
exec "snoremap <buffer> <silent> " . g:UltiSnipsJumpForwardTrigger . " <Esc>:call UltiSnips_JumpForwards()<cr>"
endif
exec "inoremap <buffer> <silent> " . g:UltiSnipsJumpBackwardTrigger . " <C-R>=UltiSnips_JumpBackwards()<cr>"
exec "snoremap <buffer> <silent> " . g:UltiSnipsJumpBackwardTrigger . " <Esc>:call UltiSnips_JumpBackwards()<cr>"
endf
function! UltiSnips_RestoreInnerKeys()
if g:UltiSnipsExpandTrigger != g:UltiSnipsJumpForwardTrigger
exec "iunmap <buffer> " . g:UltiSnipsJumpForwardTrigger
exec "sunmap <buffer> " . g:UltiSnipsJumpForwardTrigger
endif
exec "iunmap <buffer> " . g:UltiSnipsJumpBackwardTrigger
exec "sunmap <buffer> " . g:UltiSnipsJumpBackwardTrigger
endf
function! UltiSnips_CursorMoved()
exec g:_uspy "UltiSnips_Manager.cursor_moved()"
endf
function! UltiSnips_EnteredInsertMode()
exec g:_uspy "UltiSnips_Manager.entered_insert_mode()"
endf
function! UltiSnips_LeavingBuffer()
exec g:_uspy "UltiSnips_Manager.leaving_buffer()"
endf
function! UltiSnips_LeavingInsertMode()
exec g:_uspy "UltiSnips_Manager.restore_unnamed_register()"
endfunction
" }}}
" COMPLETE FUNCTIONS {{{
function! UltiSnipsFiletypeComplete(arglead, cmdline, cursorpos)
let ret = {}
let items = map(
\ split(globpath(&runtimepath, 'syntax/*.vim'), '\n'),
\ 'fnamemodify(v:val, ":t:r")'
\ )
call insert(items, 'all')
for item in items
if !has_key(ret, item) && item =~ '^'.a:arglead
let ret[item] = 1
endif
endfor
return sort(keys(ret))
endfunction
" }}}
2009-07-04 06:15:12 -04:00
"" STARTUP CODE {{{
2009-07-04 06:15:12 -04:00
" Expand our path
exec g:_uspy "import vim, os, sys"
exec g:_uspy "new_path = vim.eval('expand(\"<sfile>:h\")')"
exec g:_uspy "vim.command(\"let g:UltiSnipsPythonPath = '%s'\" % new_path)"
exec g:_uspy "sys.path.append(new_path)"
exec g:_uspy "from UltiSnips import UltiSnips_Manager"
exec g:_uspy "UltiSnips_Manager.expand_trigger = vim.eval('g:UltiSnipsExpandTrigger')"
exec g:_uspy "UltiSnips_Manager.forward_trigger = vim.eval('g:UltiSnipsJumpForwardTrigger')"
exec g:_uspy "UltiSnips_Manager.backward_trigger = vim.eval('g:UltiSnipsJumpBackwardTrigger')"
2009-07-04 06:15:12 -04:00
au CursorMovedI * call UltiSnips_CursorMoved()
au CursorMoved * call UltiSnips_CursorMoved()
au BufLeave * call UltiSnips_LeavingBuffer()
au InsertLeave * call UltiSnips_LeavingInsertMode()
call UltiSnips_MapKeys()
2011-04-27 11:37:07 -04:00
let did_UltiSnips_vim=1
" }}}
2011-04-27 11:37:07 -04:00
" vim: ts=8 sts=4 sw=4