Snippets and vim updates and such, oh my
git-svn-id: http://photonzero.com/dotfiles/trunk@33 23f722f6-122a-0410-8cef-c75bd312dd78
This commit is contained in:
parent
a0995d6be5
commit
9d2548e8a9
56 changed files with 13433 additions and 129 deletions
1954
.vim/autoload/genutils.vim
Executable file
1954
.vim/autoload/genutils.vim
Executable file
File diff suppressed because it is too large
Load diff
472
.vim/autoload/lookupfile.vim
Executable file
472
.vim/autoload/lookupfile.vim
Executable file
|
|
@ -0,0 +1,472 @@
|
|||
" lookupfile.vim: See plugin/lookupfile.vim
|
||||
|
||||
" Make sure line-continuations won't cause any problem. This will be restored
|
||||
" at the end
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
" Some onetime initialization of variables
|
||||
if !exists('s:myBufNum')
|
||||
let s:windowName = '[Lookup File]'
|
||||
let s:myBufNum = -1
|
||||
let s:popupIsHidden = 0
|
||||
endif
|
||||
let g:lookupfile#lastPattern = ""
|
||||
let g:lookupfile#lastResults = []
|
||||
let g:lookupfile#lastStatsMsg = []
|
||||
let g:lookupfile#recentFiles = []
|
||||
|
||||
function! lookupfile#OpenWindow(bang, initPat)
|
||||
let origWinnr = winnr()
|
||||
let _isf = &isfname
|
||||
let _splitbelow = &splitbelow
|
||||
set nosplitbelow
|
||||
try
|
||||
if s:myBufNum == -1
|
||||
" Temporarily modify isfname to avoid treating the name as a pattern.
|
||||
set isfname-=\
|
||||
set isfname-=[
|
||||
if exists('+shellslash')
|
||||
call genutils#OpenWinNoEa("1sp \\\\". escape(s:windowName, ' '))
|
||||
else
|
||||
call genutils#OpenWinNoEa("1sp \\". escape(s:windowName, ' '))
|
||||
endif
|
||||
let s:myBufNum = bufnr('%')
|
||||
else
|
||||
let winnr = bufwinnr(s:myBufNum)
|
||||
if winnr == -1
|
||||
call genutils#OpenWinNoEa('1sb '. s:myBufNum)
|
||||
else
|
||||
let wasVisible = 1
|
||||
exec winnr 'wincmd w'
|
||||
endif
|
||||
endif
|
||||
finally
|
||||
let &isfname = _isf
|
||||
let &splitbelow = _splitbelow
|
||||
endtry
|
||||
|
||||
call s:SetupBuf()
|
||||
let initPat = ''
|
||||
if a:bang != ''
|
||||
let initPat = ''
|
||||
elseif a:initPat != ''
|
||||
let initPat = a:initPat
|
||||
elseif g:lookupfile#lastPattern != '' && g:LookupFile_PreserveLastPattern
|
||||
let initPat = g:lookupfile#lastPattern
|
||||
endif
|
||||
$
|
||||
if getline('.') !=# initPat
|
||||
silent! put=''
|
||||
call setline('.', initPat)
|
||||
endif
|
||||
startinsert!
|
||||
if !g:LookupFile_OnCursorMovedI
|
||||
" This is a hack to bring up the popup immediately, while reopening the
|
||||
" window, just for a better response.
|
||||
aug LookupFileCursorHoldImm
|
||||
au!
|
||||
au CursorMovedI <buffer> nested exec 'doautocmd LookupFile CursorHoldI' |
|
||||
\ au! LookupFileCursorHoldImm
|
||||
aug END
|
||||
endif
|
||||
call s:LookupFileSet()
|
||||
aug LookupFileReset
|
||||
au!
|
||||
au CursorMovedI <buffer> call <SID>LookupFileSet()
|
||||
au CursorMoved <buffer> call <SID>LookupFileSet()
|
||||
au WinEnter <buffer> call <SID>LookupFileSet()
|
||||
au TabEnter <buffer> call <SID>LookupFileSet()
|
||||
au WinEnter * call <SID>LookupFileReset(0)
|
||||
au TabEnter * call <SID>LookupFileReset(0)
|
||||
au CursorMoved * call <SID>LookupFileReset(0)
|
||||
" Better be safe than sorry.
|
||||
au BufHidden <buffer> call <SID>LookupFileReset(1)
|
||||
aug END
|
||||
endfunction
|
||||
|
||||
function! lookupfile#CloseWindow()
|
||||
if bufnr('%') != s:myBufNum
|
||||
return
|
||||
endif
|
||||
|
||||
call s:LookupFileReset(1)
|
||||
close
|
||||
endfunction
|
||||
|
||||
function! lookupfile#ClearCache()
|
||||
let g:lookupfile#lastPattern = ""
|
||||
let g:lookupfile#lastResults = []
|
||||
endfunction
|
||||
|
||||
function! s:LookupFileSet()
|
||||
if bufnr('%') != s:myBufNum || exists('s:_backspace')
|
||||
return
|
||||
endif
|
||||
let s:_backspace = &backspace
|
||||
set backspace=start
|
||||
let s:_completeopt = &completeopt
|
||||
set completeopt+=menuone
|
||||
let s:_updatetime = &updatetime
|
||||
let &updatetime = g:LookupFile_UpdateTime
|
||||
endfunction
|
||||
|
||||
function! s:LookupFileReset(force)
|
||||
if a:force
|
||||
aug LookupFileReset
|
||||
au!
|
||||
aug END
|
||||
endif
|
||||
" Ignore the event while in the same buffer.
|
||||
if exists('s:_backspace') && (a:force || (bufnr('%') != s:myBufNum))
|
||||
let &backspace = s:_backspace
|
||||
let &completeopt = s:_completeopt
|
||||
let &updatetime = s:_updatetime
|
||||
unlet s:_backspace s:_completeopt s:_updatetime
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:HidePopup()
|
||||
let s:popupIsHidden = 1
|
||||
return "\<C-E>"
|
||||
endfunction
|
||||
|
||||
function! lookupfile#IsPopupHidden()
|
||||
return s:popupIsHidden
|
||||
endfunction
|
||||
|
||||
function! s:SetupBuf()
|
||||
call genutils#SetupScratchBuffer()
|
||||
resize 1
|
||||
setlocal wrap
|
||||
setlocal bufhidden=hide
|
||||
setlocal winfixheight
|
||||
setlocal wrapmargin=0
|
||||
setlocal textwidth=0
|
||||
setlocal completefunc=lookupfile#Complete
|
||||
syn clear
|
||||
set ft=lookupfile
|
||||
" Setup maps to open the file.
|
||||
inoremap <silent> <buffer> <expr> <C-E> <SID>HidePopup()
|
||||
inoremap <silent> <buffer> <expr> <CR> <SID>AcceptFile(0, "\<CR>")
|
||||
inoremap <silent> <buffer> <expr> <C-O> <SID>AcceptFile(1, "\<C-O>")
|
||||
" This prevents the "Whole line completion" from getting triggered with <BS>,
|
||||
" however this might make the dropdown kind of flash.
|
||||
inoremap <buffer> <expr> <BS> pumvisible()?"\<C-E>\<BS>":"\<BS>"
|
||||
inoremap <buffer> <expr> <S-BS> pumvisible()?"\<C-E>\<BS>":"\<BS>"
|
||||
" Make <C-Y> behave just like <CR>
|
||||
imap <buffer> <C-Y> <CR>
|
||||
if g:LookupFile_EscCancelsPopup
|
||||
inoremap <buffer> <expr> <Esc> pumvisible()?"\<C-E>\<C-C>":"\<Esc>"
|
||||
endif
|
||||
inoremap <buffer> <expr> <silent> <Down> <SID>GetCommand(1, 1, "\<C-N>",
|
||||
\ "\"\\<Lt>C-N>\"")
|
||||
inoremap <buffer> <expr> <silent> <Up> <SID>GetCommand(1, 1, "\<C-P>",
|
||||
\ "\"\\<Lt>C-P>\"")
|
||||
inoremap <buffer> <expr> <silent> <PageDown> <SID>GetCommand(1, 0,
|
||||
\ "\<PageDown>", '')
|
||||
inoremap <buffer> <expr> <silent> <PageUp> <SID>GetCommand(1, 0,
|
||||
\ "\<PageUp>", '')
|
||||
nnoremap <silent> <buffer> o :OpenFile<CR>
|
||||
nnoremap <silent> <buffer> O :OpenFile!<CR>
|
||||
command! -buffer -nargs=0 -bang OpenFile
|
||||
\ :call <SID>OpenCurFile('<bang>' != '')
|
||||
command! -buffer -nargs=0 -bang AddPattern :call <SID>AddPattern()
|
||||
nnoremap <buffer> <silent> <Plug>LookupFile :call lookupfile#CloseWindow()<CR>
|
||||
inoremap <buffer> <silent> <Plug>LookupFile <C-E><C-C>:call lookupfile#CloseWindow()<CR>
|
||||
|
||||
aug LookupFile
|
||||
au!
|
||||
if g:LookupFile_ShowFiller
|
||||
exec 'au' (g:LookupFile_OnCursorMovedI ? 'CursorMovedI' : 'CursorHoldI')
|
||||
\ '<buffer> call <SID>ShowFiller()'
|
||||
endif
|
||||
exec 'au' (g:LookupFile_OnCursorMovedI ? 'CursorMovedI' : 'CursorHoldI')
|
||||
\ '<buffer> call lookupfile#LookupFile(0)'
|
||||
aug END
|
||||
endfunction
|
||||
|
||||
function! s:GetCommand(withPopupTrigger, withSkipPat, actCmd, innerCmd)
|
||||
let cmd = ''
|
||||
if a:withPopupTrigger && !pumvisible()
|
||||
let cmd .= "\<C-X>\<C-U>"
|
||||
endif
|
||||
let cmd .= a:actCmd. "\<C-R>=(getline('.') == lookupfile#lastPattern) ? ".
|
||||
\ a:innerCmd." : ''\<CR>"
|
||||
return cmd
|
||||
endfunction
|
||||
|
||||
function! s:AddPattern()
|
||||
if g:LookupFile_PreservePatternHistory
|
||||
silent! put! =g:lookupfile#lastPattern
|
||||
$
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:AcceptFile(splitWin, key)
|
||||
if s:popupIsHidden
|
||||
return a:key
|
||||
endif
|
||||
if !pumvisible()
|
||||
call lookupfile#LookupFile(0, 1)
|
||||
endif
|
||||
let acceptCmd = ''
|
||||
if type(g:LookupFile_LookupAcceptFunc) == 2 ||
|
||||
\ (type(g:LookupFile_LookupAcceptFunc) == 1 &&
|
||||
\ substitute(g:LookupFile_LookupAcceptFunc, '\s', '', 'g') != '')
|
||||
let acceptCmd = call(g:LookupFile_LookupAcceptFunc, [a:splitWin, a:key])
|
||||
else
|
||||
let acceptCmd = lookupfile#AcceptFile(a:splitWin, a:key)
|
||||
endif
|
||||
|
||||
return (!pumvisible() ? "\<C-X>\<C-U>" : '').acceptCmd
|
||||
endfunction
|
||||
|
||||
function! s:IsValid(fileName)
|
||||
if bufnr('%') != s:myBufNum || a:fileName == ''
|
||||
return 0
|
||||
endif
|
||||
if !filereadable(a:fileName) && !isdirectory(a:fileName)
|
||||
if g:LookupFile_AllowNewFiles
|
||||
" Check if the parent directory exists, then we can create a new buffer
|
||||
" (Ido feature)
|
||||
let parent = fnamemodify(a:fileName, ':h')
|
||||
if parent == '' || (parent != '' && !isdirectory(parent))
|
||||
return 1
|
||||
endif
|
||||
endif
|
||||
return 0
|
||||
endif
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! lookupfile#AcceptFile(splitWin, key)
|
||||
if len(g:lookupfile#lastResults) == 0 && !s:IsValid(getline('.'))
|
||||
return "\<C-O>:echohl ErrorMsg | echo 'No such file or directory' | echohl NONE\<CR>"
|
||||
endif
|
||||
|
||||
" Skip the first match, which is essentially the same as pattern.
|
||||
let nextCmd = "\<C-N>\<C-R>=(getline('.') == lookupfile#lastPattern)?\"\\<C-N>\":''\<CR>"
|
||||
let acceptCmd = "\<C-Y>\<Esc>:AddPattern\<CR>:OpenFile".(a:splitWin?'!':'').
|
||||
\ "\<CR>"
|
||||
if getline('.') ==# g:lookupfile#lastPattern
|
||||
if len(g:lookupfile#lastResults) == 0
|
||||
" FIXME: shouldn't this be an error?
|
||||
let acceptCmd = acceptCmd
|
||||
elseif len(g:lookupfile#lastResults) == 1 || g:LookupFile_AlwaysAcceptFirst
|
||||
" If there is only one file, we will also select it (if not already
|
||||
" selected)
|
||||
let acceptCmd = nextCmd.acceptCmd
|
||||
else
|
||||
let acceptCmd = nextCmd
|
||||
endif
|
||||
endif
|
||||
|
||||
return acceptCmd
|
||||
endfunction
|
||||
|
||||
function! s:OpenCurFile(splitWin)
|
||||
let fileName = getline('.')
|
||||
if fileName =~ '^\s*$'
|
||||
return
|
||||
endif
|
||||
if !s:IsValid(fileName)
|
||||
echohl ErrorMsg | echo 'No such file or directory' | echohl NONE
|
||||
endif
|
||||
|
||||
if type(g:LookupFile_LookupNotifyFunc) == 2 ||
|
||||
\ (type(g:LookupFile_LookupNotifyFunc) == 1 &&
|
||||
\ substitute(g:LookupFile_LookupNotifyFunc, '\s', '', 'g') != '')
|
||||
call call(g:LookupFile_LookupNotifyFunc, [])
|
||||
endif
|
||||
call lookupfile#CloseWindow()
|
||||
|
||||
" Update the recent files list.
|
||||
if g:LookupFile_RecentFileListSize > 0
|
||||
let curPos = index(g:lookupfile#recentFiles, fileName)
|
||||
call add(g:lookupfile#recentFiles, fileName)
|
||||
if curPos != -1
|
||||
call remove(g:lookupfile#recentFiles, curPos)
|
||||
elseif len(g:lookupfile#recentFiles) > g:LookupFile_RecentFileListSize
|
||||
let g:lookupfile#recentFiles = g:lookupfile#recentFiles[
|
||||
\ -g:LookupFile_RecentFileListSize :]
|
||||
endif
|
||||
endif
|
||||
|
||||
let bufnr = genutils#FindBufferForName(fileName)
|
||||
let winnr = bufwinnr(bufnr)
|
||||
if winnr == -1 && g:LookupFile_SearchForBufsInTabs
|
||||
for i in range(tabpagenr('$'))
|
||||
if index(tabpagebuflist(i+1), bufnr) != -1
|
||||
" Switch to the tab and set winnr.
|
||||
exec 'tabnext' (i+1)
|
||||
let winnr = bufwinnr(bufnr)
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
if winnr != -1
|
||||
exec winnr.'wincmd w'
|
||||
else
|
||||
let splitOpen = 0
|
||||
if &switchbuf ==# 'split' || a:splitWin
|
||||
let splitOpen = 1
|
||||
endif
|
||||
" First try opening as a buffer, if it fails, we will open as a file.
|
||||
try
|
||||
if bufnr == -1
|
||||
throw ''
|
||||
endif
|
||||
exec (splitOpen?'s':'').'buffer' bufnr
|
||||
catch /^Vim\%((\a\+)\)\=:E325/
|
||||
" Ignore, this anyway means the file was found.
|
||||
catch
|
||||
try
|
||||
exec (splitOpen?'split':'edit') fileName
|
||||
catch /^Vim\%((\a\+)\)\=:E325/
|
||||
" Ignore, this anyway means the file was found.
|
||||
endtry
|
||||
endtry
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:ShowFiller()
|
||||
return lookupfile#LookupFile(1)
|
||||
endfunction
|
||||
|
||||
function! lookupfile#Complete(findstart, base)
|
||||
if a:findstart
|
||||
return 0
|
||||
else
|
||||
call lookupfile#LookupFile(0, 1, a:base)
|
||||
return g:lookupfile#lastStatsMsg+g:lookupfile#lastResults
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lookupfile#LookupFile(showingFiller, ...)
|
||||
let generateMode = (a:0 == 0 ? 0 : a:1)
|
||||
if generateMode
|
||||
let pattern = (a:0 > 1) ? a:2 : getline('.')
|
||||
else
|
||||
let pattern = getline('.')
|
||||
" The normal completion behavior is to stop completion when cursor is moved.
|
||||
if col('.') == 1 || (col('.') != col('$'))
|
||||
return ''
|
||||
endif
|
||||
endif
|
||||
if pattern == '' || (pattern ==# g:lookupfile#lastPattern && pumvisible())
|
||||
return ''
|
||||
endif
|
||||
|
||||
if s:popupIsHidden && g:lookupfile#lastPattern ==# pattern
|
||||
return ''
|
||||
endif
|
||||
let s:popupIsHidden = 0
|
||||
|
||||
let statusMsg = ''
|
||||
if pattern == ' '
|
||||
if len(g:lookupfile#recentFiles) == 0
|
||||
let statusMsg = '<<< No recent files >>>'
|
||||
let files = []
|
||||
else
|
||||
let statusMsg = '<<< Showing '.len(g:lookupfile#recentFiles).' recent files >>>'
|
||||
let files = reverse(copy(g:lookupfile#recentFiles))
|
||||
endif
|
||||
elseif strlen(pattern) < g:LookupFile_MinPatLength
|
||||
let statusMsg = '<<< Type at least '.g:LookupFile_MinPatLength.
|
||||
\ ' characters >>>'
|
||||
let files = []
|
||||
" We ignore filler when we have the result in hand.
|
||||
elseif g:lookupfile#lastPattern ==# pattern
|
||||
" This helps at every startup as we start with the previous pattern.
|
||||
let files = g:lookupfile#lastResults
|
||||
elseif a:showingFiller
|
||||
" Just show a filler and return. We could return this as the only match, but
|
||||
" unless 'completeopt' has "menuone", menu doesn't get shown.
|
||||
let statusMsg = '<<< Looking up files... hit ^C to break >>>'
|
||||
let files = []
|
||||
else
|
||||
if type(g:LookupFile_LookupFunc) == 2 ||
|
||||
\ (type(g:LookupFile_LookupFunc) == 1 &&
|
||||
\ substitute(g:LookupFile_LookupFunc, '\s', '', 'g') != '')
|
||||
let files = call(g:LookupFile_LookupFunc, [pattern])
|
||||
else
|
||||
let _tags = &tags
|
||||
try
|
||||
let &tags = eval(g:LookupFile_TagExpr)
|
||||
let taglist = taglist(g:LookupFile_TagsExpandCamelCase ?
|
||||
\ lookupfile#ExpandCamelCase(pattern) : pattern)
|
||||
catch
|
||||
echohl ErrorMsg | echo "Exception: " . v:exception | echohl NONE
|
||||
return ''
|
||||
finally
|
||||
let &tags = _tags
|
||||
endtry
|
||||
|
||||
" Show the matches for what is typed so far.
|
||||
if g:LookupFile_UsingSpecializedTags
|
||||
let files = map(taglist, '{'.
|
||||
\ '"word": fnamemodify(v:val["filename"], ":p"), '.
|
||||
\ '"abbr": v:val["name"], '.
|
||||
\ '"menu": fnamemodify(v:val["filename"], ":h"), '.
|
||||
\ '"dup": 1, '.
|
||||
\ '}')
|
||||
else
|
||||
let files = map(taglist, 'fnamemodify(v:val["filename"], ":p")')
|
||||
endif
|
||||
endif
|
||||
|
||||
let pat = g:LookupFile_FileFilter
|
||||
if pat != ''
|
||||
call filter(files, '(type(v:val) == 4) ? v:val["word"] !~ pat : v:val !~ pat')
|
||||
endif
|
||||
|
||||
if g:LookupFile_SortMethod ==# 'alpha'
|
||||
" When UsingSpecializedTags, sort by the actual name (Timothy, Guo
|
||||
" (firemeteor dot guo at gmail dot com)).
|
||||
if type(get(files, 0)) == 4
|
||||
call sort(files, "s:CmpByName")
|
||||
else
|
||||
call sort(files)
|
||||
endif
|
||||
endif
|
||||
let g:lookupfile#lastPattern = pattern
|
||||
let g:lookupfile#lastResults = files
|
||||
endif
|
||||
if statusMsg == ''
|
||||
if len(files) > 0
|
||||
let statusMsg = '<<< '.len(files).' Matching >>>'
|
||||
else
|
||||
let statusMsg = '<<< None Matching >>>'
|
||||
endif
|
||||
endif
|
||||
let msgLine = [{'word': pattern, 'abbr': statusMsg, 'menu': pattern}]
|
||||
let g:lookupfile#lastStatsMsg = msgLine
|
||||
if !generateMode
|
||||
call complete(1, msgLine+files)
|
||||
endif
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! lookupfile#ExpandCamelCase(str)
|
||||
let pat = a:str
|
||||
" Check if there are at least two consecutive uppercase letters to turn on
|
||||
" the CamelCase expansion.
|
||||
if match(a:str, '\u\u') != -1
|
||||
let pat = '\C'.substitute(a:str, '\u\+',
|
||||
\ '\=substitute(submatch(0), ".", '."'".'&\\U*'."'".', "g")', 'g')
|
||||
let @*=pat
|
||||
endif
|
||||
return pat
|
||||
endfunction
|
||||
|
||||
function! s:CmpByName(i1, i2)
|
||||
let ileft = a:i1["abbr"]
|
||||
let iright = a:i2["abbr"]
|
||||
return ileft == iright ? 0 : ileft > iright ? 1 : -1
|
||||
endfunc
|
||||
|
||||
" Restore cpo.
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
|
||||
" vim6:fdm=marker et sw=2
|
||||
215
.vim/autoload/objc/cocoacomplete.vim
Normal file
215
.vim/autoload/objc/cocoacomplete.vim
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
" File: cocoacomplete.vim (part of the cocoa.vim plugin)
|
||||
" Author: Michael Sanders (msanders42 [at] gmail [dot] com)
|
||||
" Last Updated: June 30, 2009
|
||||
" Description: An omni-completion plugin for Cocoa/Objective-C.
|
||||
|
||||
let s:lib_dir = fnameescape($HOME.'/.vim/lib/')
|
||||
let s:cocoa_indexes = s:lib_dir.'cocoa_indexes/'
|
||||
|
||||
if !isdirectory(s:cocoa_indexes)
|
||||
echom 'Error in cocoacomplete.vim: could not find ~/.vim/lib/cocoa_indexes directory'
|
||||
endif
|
||||
|
||||
fun! objc#cocoacomplete#Complete(findstart, base)
|
||||
if a:findstart
|
||||
" Column where completion starts:
|
||||
return match(getline('.'), '\k\+\%'.col('.').'c')
|
||||
else
|
||||
let matches = []
|
||||
let complete_type = s:GetCompleteType(line('.'), col('.') - 1)
|
||||
|
||||
if complete_type == 'methods'
|
||||
call s:Complete(a:base, ['alloc', 'init', 'retain', 'release',
|
||||
\ 'autorelease', 'retainCount',
|
||||
\ 'description', 'class', 'superclass',
|
||||
\ 'self', 'zone', 'isProxy', 'hash'])
|
||||
let obj_pos = s:GetObjPos(line('.'), col('.'))
|
||||
call extend(matches, s:CompleteMethod(line('.'), obj_pos, a:base))
|
||||
elseif complete_type == 'types' || complete_type == 'returntypes'
|
||||
let opt_types = complete_type == 'returntypes' ? ['IBAction'] : []
|
||||
call s:Complete(a:base, opt_types + ['void', 'id', 'BOOL', 'int',
|
||||
\ 'double', 'float', 'char'])
|
||||
call extend(matches, s:CompleteCocoa(a:base, 'classes', 'types',
|
||||
\ 'notifications'))
|
||||
elseif complete_type != ''
|
||||
if complete_type =~ 'function_params$'
|
||||
let complete_type = substitute(complete_type, 'function_params$', '', '')
|
||||
let functions = s:CompleteFunction(a:base)
|
||||
endif
|
||||
|
||||
" Mimic vim's dot syntax for other complete types (see :h ft).
|
||||
let word = a:base == '' ? 'NS' : a:base
|
||||
let args = [word] + split(complete_type, '\.')
|
||||
call extend(matches, call('s:CompleteCocoa', args))
|
||||
|
||||
" List functions after the other items in the menu.
|
||||
if exists('functions') | call extend(matches, functions) | endif
|
||||
endif
|
||||
return matches
|
||||
endif
|
||||
endf
|
||||
|
||||
fun s:GetCompleteType(lnum, col)
|
||||
let scopelist = map(synstack(a:lnum, a:col), 'synIDattr(v:val, "name")')
|
||||
if empty(scopelist) | return 'types' | endif
|
||||
|
||||
let current_scope = scopelist[-1]
|
||||
let beforeCursor = strpart(getline(a:lnum), 0, a:col)
|
||||
|
||||
" Completing a function name:
|
||||
if getline(a:lnum) =~ '\%'.(a:col + 1).'c\s*('
|
||||
return 'functions'
|
||||
elseif current_scope == 'objcSuperclass'
|
||||
return 'classes'
|
||||
" Inside brackets "[ ... ]":
|
||||
elseif index(scopelist, 'objcMessage') != -1
|
||||
return beforeCursor =~ '\[\k*$' ? 'classes' : 'methods'
|
||||
" Inside parentheses "( ... )":
|
||||
elseif current_scope == 'cParen'
|
||||
" Inside parentheses for method definition:
|
||||
if beforeCursor =~ '^\s*[-+]\s*([^{;]*'
|
||||
return beforeCursor =~ '^\s*[-+]\s*([^)]*$' ? 'returntypes' : 'types'
|
||||
" Inside function, loop, or conditional:
|
||||
else
|
||||
return 'classes.types.constants.function_params'
|
||||
endif
|
||||
" Inside braces "{ ... }" or after equals "=":
|
||||
elseif current_scope == 'cBlock' || current_scope == 'objcAssign' || current_scope == ''
|
||||
let type = current_scope == 'cBlock' ? 'types.constants.' : ''
|
||||
let type = 'classes.'.type.'function_params'
|
||||
|
||||
if beforeCursor =~ 'IBOutlet' | return 'classes' | endif
|
||||
return beforeCursor =~ '\v(^|[{};=\])]|return)\s*\k*$'? type : 'methods'
|
||||
" Directly inside "@implementation ... @end" or "@interface ... @end"
|
||||
elseif current_scope == 'objcImp' || current_scope == 'objcHeader'
|
||||
" TODO: Complete delegate/subclass methods
|
||||
endif
|
||||
return ''
|
||||
endf
|
||||
|
||||
" Adds item to the completion menu if they match the base.
|
||||
fun s:Complete(base, items)
|
||||
for item in a:items
|
||||
if item =~ '^'.a:base | call complete_add(item) | endif
|
||||
endfor
|
||||
endf
|
||||
|
||||
" Returns position of "foo" in "[foo bar]" or "[baz bar: [foo bar]]".
|
||||
fun s:GetObjPos(lnum, col)
|
||||
let beforeCursor = strpart(getline(a:lnum), 0, a:col)
|
||||
return match(beforeCursor, '\v.*(^|[\[=;])\s*\[*\zs[A-Za-z0-9_@]+') + 1
|
||||
endf
|
||||
|
||||
" Completes a method given the position of the object and the method
|
||||
" being completed.
|
||||
fun s:CompleteMethod(lnum, col, method)
|
||||
let class = s:GetCocoaClass(a:lnum, a:col)
|
||||
if class == ''
|
||||
let object = matchstr(getline(a:lnum), '\%'.a:col.'c\k\+')
|
||||
let class = s:GetDeclWord(object)
|
||||
if class == '' | return [] | endif
|
||||
endif
|
||||
let method = s:GetMethodName(a:lnum, a:col, a:method)
|
||||
let matches = split(system(s:lib_dir.'get_methods.sh '.class.
|
||||
\ '|grep "^'.method.'"'), "\n")
|
||||
if exists('g:loaded_snips') " Use snipMate if it's installed
|
||||
call objc#pum_snippet#Map()
|
||||
else " Otherwise, only complete the method name.
|
||||
call map(matches, 'substitute(v:val, ''\v:\zs.{-}\ze(\w+:|$)'', " ", "g")')
|
||||
endif
|
||||
|
||||
" If dealing with a partial method name, only complete past it. E.g., in
|
||||
" "[NSString stringWithCharacters:baz l|]" (where | is the cursor),
|
||||
" only return "length", not "stringWithCharacters:length:".
|
||||
if stridx(method, ':') != -1
|
||||
let method = substitute(method, a:method.'$', '\\\\zs&', '')
|
||||
call map(matches, 'matchstr(v:val, "'.method.'.*")')
|
||||
endif
|
||||
return matches
|
||||
endf
|
||||
|
||||
" Returns the Cocoa class at a given position if it exists, or
|
||||
" an empty string "" if it doesn't.
|
||||
fun s:GetCocoaClass(lnum, col)
|
||||
let class = matchstr(getline(a:lnum), '\%'.a:col.'c[A-Za-z0-9_"@]\+')
|
||||
if class =~ '^@"' | return 'NSString' | endif " Treat @"..." as an NSString
|
||||
let v:errmsg = ''
|
||||
sil! hi cocoaClass
|
||||
if v:errmsg == '' && synIDattr(synID(a:lnum, a:col, 0), 'name') == 'cocoaClass'
|
||||
return class " If cocoaClass is defined, try using that.
|
||||
endif
|
||||
return system('grep ^'.class.' '.s:cocoa_indexes.'classes.txt') != ''
|
||||
\ ? class : '' " Use grep as a fallback.
|
||||
endf
|
||||
|
||||
" Returns the word before a variable declaration.
|
||||
fun s:GetDeclWord(var)
|
||||
let startpos = [line('.'), col('.')]
|
||||
let line_found = searchdecl(a:var) != 0 ? 0 : line('.')
|
||||
call cursor(startpos)
|
||||
let matchstr = '\v(IBOutlet\s+)=\zs\k+\s*\ze\**\s*'
|
||||
|
||||
" If the declaration was not found in the implementation file, check
|
||||
" the header.
|
||||
if !line_found && expand('%:e') == 'm'
|
||||
let header_path = expand('%:p:r').'.h'
|
||||
if filereadable(header_path)
|
||||
for line in readfile(header_path)
|
||||
if line =~ '^\s*\(IBOutlet\)\=\s*\k*\s*\ze\**\s*'.a:var.'\s*'
|
||||
return matchstr(line, matchstr)
|
||||
endif
|
||||
endfor
|
||||
return ''
|
||||
endif
|
||||
endif
|
||||
|
||||
return matchstr(getline(line_found), matchstr.a:var)
|
||||
endf
|
||||
|
||||
fun s:SearchList(list, regex)
|
||||
for line in a:list
|
||||
if line =~ a:regex
|
||||
return line
|
||||
endif
|
||||
endfor
|
||||
return ''
|
||||
endf
|
||||
|
||||
" Returns the method name, ready to be searched by grep.
|
||||
" The "base" word needs to be passed in separately, because
|
||||
" Vim apparently removes it from the line during completions.
|
||||
fun s:GetMethodName(lnum, col, base)
|
||||
let line = getline(a:lnum)
|
||||
let col = matchend(line, '\%'.a:col.'c\S\+\s\+') + 1 " Skip past class name.
|
||||
if line =~ '\%'.col.'c\k\+:'
|
||||
let base = a:base == '' ? '' : ' '.a:base
|
||||
let method = matchstr(line, '\%'.col.'c.\{-}\ze]').base
|
||||
return substitute(method, '\v\k+:\zs.{-}\ze(\s*\k+:|'.base.'$)', '[^:]*', 'g')
|
||||
else
|
||||
return a:base
|
||||
endif
|
||||
endf
|
||||
|
||||
" Completes Cocoa functions, using snippets for the parameters if possible.
|
||||
fun s:CompleteFunction(word)
|
||||
let files = s:cocoa_indexes.'functions.txt' " TODO: Add C functions.
|
||||
let matches = split(system('zgrep -h "^'.a:word.'" '.files), "\n")
|
||||
if exists('g:loaded_snips') " Use snipMate if it's installed
|
||||
call objc#pum_snippet#Map()
|
||||
else " Otherwise, just complete the function name
|
||||
call map(matches, "{'word':matchstr(v:val, '^\\k\\+'), 'abbr':v:val}")
|
||||
endif
|
||||
return matches
|
||||
endf
|
||||
|
||||
" Completes word for Cocoa "classes", "types", "notifications", or "constants".
|
||||
" (supplied as the optional parameters).
|
||||
fun s:CompleteCocoa(word, file, ...)
|
||||
let files = ''
|
||||
for file in [a:file] + a:000
|
||||
let files .= ' '.s:cocoa_indexes.file.'.txt'
|
||||
endfor
|
||||
|
||||
return split(system('grep -ho "^'.a:word.'[A-Za-z0-9_]*" '.files), "\n")
|
||||
endf
|
||||
" vim:noet:sw=4:ts=4:ft=vim
|
||||
160
.vim/autoload/objc/man.vim
Normal file
160
.vim/autoload/objc/man.vim
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
" File: objc#man.vim (part of the cocoa.vim plugin)
|
||||
" Author: Michael Sanders (msanders42 [at] gmail [dot] com)
|
||||
" Description: Allows you to look up Cocoa API docs in Vim.
|
||||
" Last Updated: June 30, 2009
|
||||
" NOTE: See http://mymacinations.com/2008/02/06/changing-the-systems-default-settings-for-html-files-safe/
|
||||
" for removing the annoying security alert in Leopard.
|
||||
|
||||
" Return all matches in for ":CocoaDoc <tab>" sorted by length.
|
||||
fun objc#man#Completion(ArgLead, CmdLine, CursorPos)
|
||||
return system('grep -ho "^'.a:ArgLead.'\w*" ~/.vim/lib/cocoa_indexes/*.txt'.
|
||||
\ "| perl -e 'print sort {length $a <=> length $b} <>'")
|
||||
endf
|
||||
|
||||
let s:docsets = []
|
||||
for path in ['/Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset',
|
||||
\ '/Developer/Platforms/iPhoneOS.platform/Developer/Documentation/DocSets/com.apple.adc.documentation.AppleiPhone3_0.iPhoneLibrary.docset']
|
||||
if isdirectory(path)
|
||||
call add(s:docsets, path)
|
||||
endif
|
||||
endfor
|
||||
|
||||
let s:docset_cmd = '/Developer/usr/bin/docsetutil search -skip-text -query '
|
||||
|
||||
fun s:OpenFile(file)
|
||||
if a:file =~ '/.*/man/'
|
||||
exe ':!'.substitute(&kp, '^man -s', 'man', '').' '.a:file
|
||||
else
|
||||
" /usr/bin/open strips the #fragments in file:// URLs, which we need,
|
||||
" so I'm using applescript instead.
|
||||
call system('osascript -e ''open location "file://'.a:file.'"'' &')
|
||||
endif
|
||||
endf
|
||||
|
||||
fun objc#man#ShowDoc(...)
|
||||
let word = a:0 ? a:1 : matchstr(getline('.'), '\<\w*\%'.col('.').'c\w\+:\=')
|
||||
|
||||
" Look up the whole method if it takes multiple arguments.
|
||||
if !a:0 && word[len(word) - 1] == ':'
|
||||
let word = s:GetMethodName()
|
||||
endif
|
||||
|
||||
if word == ''
|
||||
if !a:0 " Mimic K if using it as such
|
||||
echoh ErrorMsg
|
||||
echo 'E349: No identifier under cursor'
|
||||
echoh None
|
||||
endif
|
||||
return
|
||||
endif
|
||||
|
||||
let references = {}
|
||||
|
||||
" First check Cocoa docs for word using docsetutil
|
||||
for docset in s:docsets
|
||||
let response = split(system(s:docset_cmd.word.' '.docset), "\n")
|
||||
let docset .= '/Contents/Resources/Documents/' " Actual path of files
|
||||
for line in response
|
||||
" Format string is: " Language/type/class/word path"
|
||||
let path = matchstr(line, '\S*$')
|
||||
if path[0] != '/' | let path = docset.path | endif
|
||||
if has_key(references, path) | continue | endif " Ignore duplicate entries
|
||||
|
||||
let [lang, type, class] = split(matchstr(line, '^ \zs*\S*'), '/')[:2]
|
||||
" If no class if given use type instead
|
||||
if class == '-' | let class = type | endif
|
||||
let references[path] = {'lang': lang, 'class': class}
|
||||
endfor
|
||||
endfor
|
||||
|
||||
" Then try man
|
||||
let man = system('man -S2:3 -aW '.word)
|
||||
if man !~ '^No manual entry'
|
||||
for path in split(man, "\n")
|
||||
if !has_key(references, path)
|
||||
let references[path] = {'lang': 'C', 'class': 'man'}
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
if len(references) == 1
|
||||
return s:OpenFile(keys(references)[0])
|
||||
elseif !empty(references)
|
||||
echoh ModeMsg | echo word | echoh None
|
||||
return s:ChooseFrom(references)
|
||||
else
|
||||
echoh WarningMsg
|
||||
echo "Can't find documentation for ".word
|
||||
echoh None
|
||||
endif
|
||||
endf
|
||||
|
||||
fun s:ChooseFrom(references)
|
||||
let type_abbr = {'cl' : 'Class', 'intf' : 'Protocol', 'cat' : 'Category',
|
||||
\ 'intfm' : 'Method', 'instm' : 'Method', 'econst' : 'Enum',
|
||||
\ 'tdef' : 'Typedef', 'macro' : 'Macro', 'data' : 'Data',
|
||||
\ 'func' : 'Function'}
|
||||
let inputlist = []
|
||||
" Don't display "Objective-C" if all items are objc
|
||||
let show_lang = !AllKeysEqual(values(a:references), 'lang', 'Objective-C')
|
||||
let i = 1
|
||||
for ref in values(a:references)
|
||||
let class = ref.class
|
||||
if has_key(type_abbr, class) | let class = type_abbr[class] | endif
|
||||
call add(inputlist, i.'. '.(show_lang ? ref['lang'].' ' : '').class)
|
||||
let i += 1
|
||||
endfor
|
||||
let num = inputlist(inputlist)
|
||||
return num ? s:OpenFile(keys(a:references)[num - 1]) : -1
|
||||
endf
|
||||
|
||||
fun AllKeysEqual(list, key, item)
|
||||
for item in a:list
|
||||
if item[a:key] != a:item
|
||||
return 0
|
||||
endif
|
||||
endfor
|
||||
return 1
|
||||
endf
|
||||
|
||||
fun s:GetMethodName()
|
||||
let pos = [line('.'), col('.')]
|
||||
let startpos = searchpos('\v^\s*-.{-}\w+:|\[\s*\w+\s+\w+:|\]\s*\w+:', 'cbW')
|
||||
|
||||
" Method declaration (- (foo) bar:)
|
||||
if getline(startpos[0]) =~ '^\s*-.\{-}\w\+:'
|
||||
let endpos = searchpos('{', 'W')
|
||||
" Message inside brackets ([foo bar: baz])
|
||||
else
|
||||
let endpos = searchpairpos('\[', '', '\]', 'W')
|
||||
endif
|
||||
call cursor(pos)
|
||||
|
||||
if startpos[0] == 0 || endpos[0] == 0 | return '' | endif
|
||||
let lines = getline(startpos[0], endpos[0])
|
||||
|
||||
let lines[0] = strpart(lines[0], startpos[1] - 1)
|
||||
let lines[-1] = strpart(lines[-1], 0, endpos[1])
|
||||
|
||||
" Ignore outer brackets
|
||||
let message = substitute(join(lines), '^\[\|\]$', '', '')
|
||||
" Ignore nested messages [...]
|
||||
let message = substitute(message, '\[.\{-}\]', '', 'g')
|
||||
" Ignore strings (could contain colons)
|
||||
let message = substitute(message, '".\{-}"', '', 'g')
|
||||
" Ignore @selector(...)
|
||||
let message = substitute(message, '@selector(.\{-})', '', 'g')
|
||||
|
||||
return s:MatchAll(message, '\w\+:')
|
||||
endf
|
||||
|
||||
fun s:MatchAll(haystack, needle)
|
||||
let matches = matchstr(a:haystack, a:needle)
|
||||
let index = matchend(a:haystack, a:needle)
|
||||
while index != -1
|
||||
let matches .= matchstr(a:haystack, a:needle, index + 1)
|
||||
let index = matchend(a:haystack, a:needle, index + 1)
|
||||
endw
|
||||
return matches
|
||||
endf
|
||||
" vim:noet:sw=4:ts=4:ft=vim
|
||||
124
.vim/autoload/objc/method_builder.vim
Normal file
124
.vim/autoload/objc/method_builder.vim
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
" File: objc#method_builder.vim (part of the cocoa.vim plugin)
|
||||
" Author: Michael Sanders (msanders42 [at] gmail [dot] com)
|
||||
" Description: Builds an empty implementation (*.m) file given a header (*.h)
|
||||
" file. When called with no arguments (simply ":BuildMethods"),
|
||||
" it looks for the corresponding header file of the current *.m
|
||||
" file (e.g. "foo.m" -> "foo.h").
|
||||
" Last Updated: June 03, 2009
|
||||
" - make sure you're not in a comment
|
||||
|
||||
" TODO: Relative pathnames
|
||||
fun objc#method_builder#Completion(ArgLead, CmdLine, CursorPos)
|
||||
let dir = stridx(a:ArgLead, '/') == -1 ? getcwd() : fnamemodify(a:ArgLead, ':h')
|
||||
let search = fnamemodify(a:ArgLead, ':t')
|
||||
let files = split(glob(dir.'/'.search.'*.h')
|
||||
\ ."\n".glob(dir.'/'.search.'*/'), "\n")
|
||||
call map(files, 'fnameescape(fnamemodify(v:val, ":."))')
|
||||
return files
|
||||
endf
|
||||
|
||||
fun s:Error(msg)
|
||||
echoh ErrorMsg | echo a:msg | echoh None
|
||||
return -1
|
||||
endf
|
||||
|
||||
fun s:GetDeclarations(file)
|
||||
let header = readfile(a:file)
|
||||
let template = []
|
||||
let in_comment = 0
|
||||
let in_header = 0
|
||||
let looking_for_semi = 0
|
||||
|
||||
for line in header
|
||||
if in_comment
|
||||
if stridx(line, '*/') != -1 | let in_comment = 0 | endif
|
||||
continue " Ignore declarations inside multi-line comments
|
||||
elseif stridx(line, '/*') != -1
|
||||
let in_comment = 1 | continue
|
||||
endif
|
||||
|
||||
if stridx(line, '@interface') != -1
|
||||
let in_header = 1
|
||||
let template += ['@implementation'.matchstr(line, '@interface\zs\s\+\w\+'), '']
|
||||
continue
|
||||
elseif in_header && stridx(line, '@end') != -1
|
||||
let in_header = 0
|
||||
call add(template, '@end')
|
||||
break " Only process one @interface at a time, for now.
|
||||
endif
|
||||
if !in_header | continue | endif
|
||||
|
||||
let first_char = strpart(line, 0, 1)
|
||||
if first_char == '-' || first_char == '+' || looking_for_semi
|
||||
let semi_pos = stridx(line, ';')
|
||||
let looking_for_semi = semi_pos == -1
|
||||
if looking_for_semi
|
||||
call add(template, line)
|
||||
else
|
||||
call add(template, strpart(line, 0, semi_pos))
|
||||
let template += ['{', "\t", '}', '']
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
return template
|
||||
endf
|
||||
|
||||
fun objc#method_builder#Build(header)
|
||||
let headerfile = a:header == '' ? expand('%:p:r').'.h' : a:header
|
||||
if expand('%:e') != 'm'
|
||||
return s:Error('Not in an implementation file.')
|
||||
elseif !filereadable(headerfile)
|
||||
return s:Error('Could not read header file.')
|
||||
endif
|
||||
|
||||
let declarations = s:GetDeclarations(headerfile)
|
||||
|
||||
if empty(declarations)
|
||||
return s:Error('Header file has no method declarations!')
|
||||
endif
|
||||
|
||||
let len = len(declarations)
|
||||
let last_change = line('.')
|
||||
|
||||
if search('\V'.substitute(declarations[0], '\s\+', '\\s\\+', ''))
|
||||
if !searchpair('@implementation', '', '@end', 'W')
|
||||
return s:Error('Missing @end declaration.')
|
||||
endif
|
||||
let i = 2 " Skip past the @implementation line & blank line
|
||||
let len -= 1 " Skip past @end declaration
|
||||
let lnum = line('.') - 1
|
||||
else
|
||||
let i = 0
|
||||
let lnum = line('.')
|
||||
endif
|
||||
let start_line = lnum
|
||||
|
||||
while i < len
|
||||
let is_method = declarations[i][0] =~ '@\|+\|-'
|
||||
if !is_method || !search('\V'.substitute(escape(declarations[i], '\'),
|
||||
\ 'void\|IBAction', '\\(void\\|IBAction\\)', 'g'), 'n')
|
||||
call append(lnum, declarations[i])
|
||||
let lnum += 1
|
||||
if is_method | let last_change = lnum | endif
|
||||
else " Skip method declaration if it is already declared.
|
||||
if declarations[i][0] == '@'
|
||||
let i += 1
|
||||
else
|
||||
while declarations[i] != '}' && i < len
|
||||
let i += 1
|
||||
endw
|
||||
let i += 1
|
||||
endif
|
||||
endif
|
||||
let i += 1
|
||||
endw
|
||||
call cursor(last_change, 1)
|
||||
|
||||
if lnum == start_line
|
||||
echoh WarningMsg
|
||||
let class = matchstr(declarations[0], '@implementation\s\+\zs.*')
|
||||
echo 'The methods for the "'.class.'" class have already been declared.'
|
||||
echoh None
|
||||
endif
|
||||
endf
|
||||
" vim:noet:sw=4:ts=4:ft=vim
|
||||
115
.vim/autoload/objc/method_list.vim
Normal file
115
.vim/autoload/objc/method_list.vim
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
" File: objc#method_list.vim (part of the cocoa.vim plugin)
|
||||
" Author: Michael Sanders (msanders42 [at] gmail [dot] com)
|
||||
" Description: Opens a split window containing the methods of the current file.
|
||||
" Last Updated: July 13, 2009
|
||||
|
||||
au WinLeave Method\ List call<SID>LeaveMethodList()
|
||||
au WinEnter Method\ List call objc#method_list#Activate(0)
|
||||
|
||||
fun objc#method_list#Activate(update)
|
||||
let s:opt = {'is':&is, 'hls': &hls} " Save current options.
|
||||
let s:last_search = @/
|
||||
set is nohls
|
||||
" If methodlist has already been opened, reactivate it.
|
||||
if exists('s:mlist_buffer') && bufexists(s:mlist_buffer)
|
||||
let mlist_win = bufwinnr(s:mlist_buffer)
|
||||
if mlist_win == -1
|
||||
sil exe 'belowright sbuf '.s:mlist_buffer
|
||||
if a:update | call s:UpdateMethodList() | endif
|
||||
elseif winbufnr(2) == -1
|
||||
quit " If no other windows are open, close the method list automatically.
|
||||
else " If method list is out of focus, bring it back into focus.
|
||||
exe mlist_win.'winc w'
|
||||
endif
|
||||
else " Otherwise, create the method list.
|
||||
call s:CreateMethodList()
|
||||
call s:UpdateMethodList()
|
||||
endif
|
||||
endf
|
||||
|
||||
fun s:CreateMethodList()
|
||||
botright new
|
||||
|
||||
let s:sortPref = 0
|
||||
let s:mlist_buffer = bufnr('%')
|
||||
|
||||
sil file Method\ List
|
||||
setl bt=nofile bh=wipe noswf nobl nonu nowrap syn=objc
|
||||
syn match objcPragmark '^[^-+@].*$'
|
||||
hi objcPragmark gui=italic term=underline
|
||||
|
||||
nn <silent> <buffer> <cr> :cal<SID>SelectMethod()<cr>
|
||||
nn <buffer> q <c-w>q
|
||||
nn <buffer> p <c-w>p
|
||||
nm <buffer> l p
|
||||
nm <buffer> <2-leftmouse> <cr>
|
||||
endf
|
||||
|
||||
" Returns the lines of all the matches in a dictionary
|
||||
fun s:GetAllMatches(needle)
|
||||
let startpos = [line('.'), col('.')]
|
||||
call cursor(1, 1)
|
||||
|
||||
let results = {}
|
||||
let line = search(a:needle, 'Wc')
|
||||
let key = matchstr(getline(line), a:needle)
|
||||
if !s:InComment(line, 1) && key != ''
|
||||
let results[key] = line
|
||||
endif
|
||||
|
||||
while 1
|
||||
let line = search(a:needle, 'W')
|
||||
if !line | break | endif
|
||||
let key = matchstr(getline(line), a:needle)
|
||||
if !s:InComment(line, 1) && key != ''
|
||||
let results[key] = line
|
||||
endif
|
||||
endw
|
||||
|
||||
call cursor(startpos)
|
||||
return results
|
||||
endf
|
||||
|
||||
fun s:InComment(line, col)
|
||||
return stridx(synIDattr(synID(a:line, a:col, 0), 'name'), 'omment') != -1
|
||||
endf
|
||||
|
||||
fun s:UpdateMethodList()
|
||||
winc p " Go to source file window
|
||||
let s:methods = s:GetAllMatches('^\v(\@(implementation|interface) \w+|'.
|
||||
\ '\s*(\+|-).*|#pragma\s+mark\s+\zs.+)')
|
||||
winc p " Go to method window
|
||||
|
||||
if empty(s:methods)
|
||||
winc q
|
||||
echoh WarningMsg
|
||||
echo 'There are no methods in this file!'
|
||||
echoh None
|
||||
return
|
||||
endif
|
||||
|
||||
call setline(1, sort(keys(s:methods), 's:SortByLineNum'))
|
||||
exe "norm! \<c-w>".line('$').'_'
|
||||
endf
|
||||
|
||||
fun s:SortByLineNum(i1, i2)
|
||||
let line1 = s:methods[a:i1]
|
||||
let line2 = s:methods[a:i2]
|
||||
return line1 == line2 ? 0 : line1 > line2 ? 1 : -1
|
||||
endf
|
||||
|
||||
fun s:SelectMethod()
|
||||
let number = s:methods[getline('.')]
|
||||
winc q
|
||||
winc p
|
||||
call cursor(number, 1)
|
||||
endf
|
||||
|
||||
fun s:LeaveMethodList()
|
||||
for [option, value] in items(s:opt)
|
||||
exe 'let &'.option.'='.value
|
||||
endfor
|
||||
let @/ = s:last_search == '' ? '' : s:last_search
|
||||
unl s:opt s:last_search
|
||||
endf
|
||||
" vim:noet:sw=4:ts=4:ft=vim
|
||||
87
.vim/autoload/objc/pum_snippet.vim
Normal file
87
.vim/autoload/objc/pum_snippet.vim
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
" File: pum_snippet.vim
|
||||
" Author: Michael Sanders (msanders42 [at] gmail [dot] com)
|
||||
" Last Updated: June 12, 2009
|
||||
" Description: Uses snipMate to jump through function or method objc
|
||||
" parameters when autocompleting. Used in cocoacomplete.vim.
|
||||
|
||||
" This function is invoked whenever pum_snippet is to be used; the keys are
|
||||
" only mapped when used as the trigger, and then immediately unmapped to avoid
|
||||
" breaking abbreviations, as well as other things.
|
||||
fun! objc#pum_snippet#Map()
|
||||
ino <silent> <buffer> <space> <c-r>=objc#pum_snippet#Trigger(' ')<cr>
|
||||
if !exists('g:SuperTabMappingForward') " Only map tab if not using supertab.
|
||||
\ || (g:SuperTabMappingForward != '<tab>' && g:SuperTabMappingForward != '<tab>')
|
||||
ino <silent> <buffer> <tab> <c-r>=objc#pum_snippet#Trigger("\t")<cr>
|
||||
endif
|
||||
ino <silent> <buffer> <return> <c-r>=objc#pum_snippet#Trigger("\n")<cr>
|
||||
let s:start = col('.')
|
||||
" Completion menu can only be detected when the popup menu is visible, so
|
||||
" 'menuone' needs to be temporarily set:
|
||||
let s:cot = &cot
|
||||
set cot+=menuone
|
||||
endf
|
||||
|
||||
fun! objc#pum_snippet#Unmap()
|
||||
call s:UnmapKey('<space>')
|
||||
call s:UnmapKey('<tab>')
|
||||
call s:UnmapKey('<return>')
|
||||
endf
|
||||
|
||||
fun s:UnmapKey(key)
|
||||
if maparg(a:key, 'i') =~? '^<C-R>=objc#pum_snippet#Trigger('
|
||||
sil exe 'iunmap <buffer> '.a:key
|
||||
endif
|
||||
endf
|
||||
|
||||
fun! objc#pum_snippet#Trigger(key)
|
||||
call objc#pum_snippet#Unmap()
|
||||
if pumvisible()
|
||||
let line = getline('.')
|
||||
let col = col('.')
|
||||
let word = matchstr(line, '\%'.s:start.'c\k\+(.\{-})\%'.col.'c')
|
||||
if word != ''
|
||||
let ConvertWord = function('s:ConvertFunction')
|
||||
elseif match(line, '\%'.s:start.'c\k\+[^()]*:[^()]*\%'.col.'c') != -1
|
||||
let word = matchstr(line, '\%'.s:start.'c\k\+[^()]*\%'.col.'c')
|
||||
let ConvertWord = function('s:ConvertMethod')
|
||||
endif
|
||||
if word != ''
|
||||
call s:ResetOptions()
|
||||
let col -= len(word)
|
||||
sil exe 's/\V'.escape(word, '\/').'\%#//'
|
||||
return snipMate#expandSnip(ConvertWord(word), col)
|
||||
endif
|
||||
endif
|
||||
call s:ResetOptions()
|
||||
return a:key
|
||||
endf
|
||||
|
||||
fun s:ResetOptions()
|
||||
let &cot = s:cot
|
||||
unl s:start s:cot
|
||||
endf
|
||||
|
||||
fun s:ConvertFunction(function)
|
||||
let name = matchstr(a:function, '^\k\+')
|
||||
let params = matchstr(a:function, '^\k\+(\zs.*')
|
||||
let snippet = name.'('.substitute(params, '\v(.{-1})(, |\))', '${0:\1}\2', 'g').'${0}'
|
||||
return s:OrderSnippet(snippet)
|
||||
endf
|
||||
|
||||
fun s:ConvertMethod(method)
|
||||
if stridx(a:method, ':') == -1 | return a:method | endif
|
||||
let snippet = substitute(a:method, '\v\k+:\zs.{-}\ze(\s*\k+:|$)', '${0:&}', 'g')
|
||||
return s:OrderSnippet(snippet)
|
||||
endf
|
||||
|
||||
" Converts "${0} foo ${0} bar ..." to "${1} foo ${2} bar", etc.
|
||||
fun s:OrderSnippet(snippet)
|
||||
let snippet = a:snippet
|
||||
let i = 1
|
||||
while stridx(snippet, '${0') != -1
|
||||
let snippet = substitute(snippet, '${0', '${'.i, '')
|
||||
let i += 1
|
||||
endw
|
||||
return snippet
|
||||
endf
|
||||
" vim:noet:sw=4:ts=4:ft=vim
|
||||
433
.vim/autoload/snipMate.vim
Normal file
433
.vim/autoload/snipMate.vim
Normal file
|
|
@ -0,0 +1,433 @@
|
|||
fun! Filename(...)
|
||||
let filename = expand('%:t:r')
|
||||
if filename == '' | return a:0 == 2 ? a:2 : '' | endif
|
||||
return !a:0 || a:1 == '' ? filename : substitute(a:1, '$1', filename, 'g')
|
||||
endf
|
||||
|
||||
fun s:RemoveSnippet()
|
||||
unl! g:snipPos s:curPos s:snipLen s:endCol s:endLine s:prevLen
|
||||
\ s:lastBuf s:oldWord
|
||||
if exists('s:update')
|
||||
unl s:startCol s:origWordLen s:update
|
||||
if exists('s:oldVars') | unl s:oldVars s:oldEndCol | endif
|
||||
endif
|
||||
aug! snipMateAutocmds
|
||||
endf
|
||||
|
||||
fun snipMate#expandSnip(snip, col)
|
||||
let lnum = line('.') | let col = a:col
|
||||
|
||||
let snippet = s:ProcessSnippet(a:snip)
|
||||
" Avoid error if eval evaluates to nothing
|
||||
if snippet == '' | return '' | endif
|
||||
|
||||
" Expand snippet onto current position with the tab stops removed
|
||||
let snipLines = split(substitute(snippet, '$\d\+\|${\d\+.\{-}}', '', 'g'), "\n", 1)
|
||||
|
||||
let line = getline(lnum)
|
||||
let afterCursor = strpart(line, col - 1)
|
||||
" Keep text after the cursor
|
||||
if afterCursor != "\t" && afterCursor != ' '
|
||||
let line = strpart(line, 0, col - 1)
|
||||
let snipLines[-1] .= afterCursor
|
||||
else
|
||||
let afterCursor = ''
|
||||
" For some reason the cursor needs to move one right after this
|
||||
if line != '' && col == 1 && &ve != 'all' && &ve != 'onemore'
|
||||
let col += 1
|
||||
endif
|
||||
endif
|
||||
|
||||
call setline(lnum, line.snipLines[0])
|
||||
|
||||
" Autoindent snippet according to previous indentation
|
||||
let indent = matchend(line, '^.\{-}\ze\(\S\|$\)') + 1
|
||||
call append(lnum, map(snipLines[1:], "'".strpart(line, 0, indent - 1)."'.v:val"))
|
||||
|
||||
" Open any folds snippet expands into
|
||||
if &fen | sil! exe lnum.','.(lnum + len(snipLines) - 1).'foldopen' | endif
|
||||
|
||||
let [g:snipPos, s:snipLen] = s:BuildTabStops(snippet, lnum, col - indent, indent)
|
||||
|
||||
if s:snipLen
|
||||
aug snipMateAutocmds
|
||||
au CursorMovedI * call s:UpdateChangedSnip(0)
|
||||
au InsertEnter * call s:UpdateChangedSnip(1)
|
||||
aug END
|
||||
let s:lastBuf = bufnr(0) " Only expand snippet while in current buffer
|
||||
let s:curPos = 0
|
||||
let s:endCol = g:snipPos[s:curPos][1]
|
||||
let s:endLine = g:snipPos[s:curPos][0]
|
||||
|
||||
call cursor(g:snipPos[s:curPos][0], g:snipPos[s:curPos][1])
|
||||
let s:prevLen = [line('$'), col('$')]
|
||||
if g:snipPos[s:curPos][2] != -1 | return s:SelectWord() | endif
|
||||
else
|
||||
unl g:snipPos s:snipLen
|
||||
" Place cursor at end of snippet if no tab stop is given
|
||||
let newlines = len(snipLines) - 1
|
||||
call cursor(lnum + newlines, indent + len(snipLines[-1]) - len(afterCursor)
|
||||
\ + (newlines ? 0: col - 1))
|
||||
endif
|
||||
return ''
|
||||
endf
|
||||
|
||||
" Prepare snippet to be processed by s:BuildTabStops
|
||||
fun s:ProcessSnippet(snip)
|
||||
let snippet = a:snip
|
||||
" Evaluate eval (`...`) expressions.
|
||||
" Using a loop here instead of a regex fixes a bug with nested "\=".
|
||||
if stridx(snippet, '`') != -1
|
||||
while match(snippet, '`.\{-}`') != -1
|
||||
let snippet = substitute(snippet, '`.\{-}`',
|
||||
\ substitute(eval(matchstr(snippet, '`\zs.\{-}\ze`')),
|
||||
\ "\n\\%$", '', ''), '')
|
||||
endw
|
||||
let snippet = substitute(snippet, "\r", "\n", 'g')
|
||||
endif
|
||||
|
||||
" Place all text after a colon in a tab stop after the tab stop
|
||||
" (e.g. "${#:foo}" becomes "${:foo}foo").
|
||||
" This helps tell the position of the tab stops later.
|
||||
let snippet = substitute(snippet, '${\d\+:\(.\{-}\)}', '&\1', 'g')
|
||||
|
||||
" Update the a:snip so that all the $# become the text after
|
||||
" the colon in their associated ${#}.
|
||||
" (e.g. "${1:foo}" turns all "$1"'s into "foo")
|
||||
let i = 1
|
||||
while stridx(snippet, '${'.i) != -1
|
||||
let s = matchstr(snippet, '${'.i.':\zs.\{-}\ze}')
|
||||
if s != ''
|
||||
let snippet = substitute(snippet, '$'.i, s.'&', 'g')
|
||||
endif
|
||||
let i += 1
|
||||
endw
|
||||
|
||||
if &et " Expand tabs to spaces if 'expandtab' is set.
|
||||
return substitute(snippet, '\t', repeat(' ', &sts ? &sts : &sw), 'g')
|
||||
endif
|
||||
return snippet
|
||||
endf
|
||||
|
||||
" Counts occurences of haystack in needle
|
||||
fun s:Count(haystack, needle)
|
||||
let counter = 0
|
||||
let index = stridx(a:haystack, a:needle)
|
||||
while index != -1
|
||||
let index = stridx(a:haystack, a:needle, index+1)
|
||||
let counter += 1
|
||||
endw
|
||||
return counter
|
||||
endf
|
||||
|
||||
" Builds a list of a list of each tab stop in the snippet containing:
|
||||
" 1.) The tab stop's line number.
|
||||
" 2.) The tab stop's column number
|
||||
" (by getting the length of the string between the last "\n" and the
|
||||
" tab stop).
|
||||
" 3.) The length of the text after the colon for the current tab stop
|
||||
" (e.g. "${1:foo}" would return 3). If there is no text, -1 is returned.
|
||||
" 4.) If the "${#:}" construct is given, another list containing all
|
||||
" the matches of "$#", to be replaced with the placeholder. This list is
|
||||
" composed the same way as the parent; the first item is the line number,
|
||||
" and the second is the column.
|
||||
fun s:BuildTabStops(snip, lnum, col, indent)
|
||||
let snipPos = []
|
||||
let i = 1
|
||||
let withoutVars = substitute(a:snip, '$\d\+', '', 'g')
|
||||
while stridx(a:snip, '${'.i) != -1
|
||||
let beforeTabStop = matchstr(withoutVars, '^.*\ze${'.i.'\D')
|
||||
let withoutOthers = substitute(withoutVars, '${\('.i.'\D\)\@!\d\+.\{-}}', '', 'g')
|
||||
|
||||
let j = i - 1
|
||||
call add(snipPos, [0, 0, -1])
|
||||
let snipPos[j][0] = a:lnum + s:Count(beforeTabStop, "\n")
|
||||
let snipPos[j][1] = a:indent + len(matchstr(withoutOthers, '.*\(\n\|^\)\zs.*\ze${'.i.'\D'))
|
||||
if snipPos[j][0] == a:lnum | let snipPos[j][1] += a:col | endif
|
||||
|
||||
" Get all $# matches in another list, if ${#:name} is given
|
||||
if stridx(withoutVars, '${'.i.':') != -1
|
||||
let snipPos[j][2] = len(matchstr(withoutVars, '${'.i.':\zs.\{-}\ze}'))
|
||||
let dots = repeat('.', snipPos[j][2])
|
||||
call add(snipPos[j], [])
|
||||
let withoutOthers = substitute(a:snip, '${\d\+.\{-}}\|$'.i.'\@!\d\+', '', 'g')
|
||||
while match(withoutOthers, '$'.i.'\(\D\|$\)') != -1
|
||||
let beforeMark = matchstr(withoutOthers, '^.\{-}\ze'.dots.'$'.i.'\(\D\|$\)')
|
||||
call add(snipPos[j][3], [0, 0])
|
||||
let snipPos[j][3][-1][0] = a:lnum + s:Count(beforeMark, "\n")
|
||||
let snipPos[j][3][-1][1] = a:indent + (snipPos[j][3][-1][0] > a:lnum
|
||||
\ ? len(matchstr(beforeMark, '.*\n\zs.*'))
|
||||
\ : a:col + len(beforeMark))
|
||||
let withoutOthers = substitute(withoutOthers, '$'.i.'\ze\(\D\|$\)', '', '')
|
||||
endw
|
||||
endif
|
||||
let i += 1
|
||||
endw
|
||||
return [snipPos, i - 1]
|
||||
endf
|
||||
|
||||
fun snipMate#jumpTabStop(backwards)
|
||||
let leftPlaceholder = exists('s:origWordLen')
|
||||
\ && s:origWordLen != g:snipPos[s:curPos][2]
|
||||
if leftPlaceholder && exists('s:oldEndCol')
|
||||
let startPlaceholder = s:oldEndCol + 1
|
||||
endif
|
||||
|
||||
if exists('s:update')
|
||||
call s:UpdatePlaceholderTabStops()
|
||||
else
|
||||
call s:UpdateTabStops()
|
||||
endif
|
||||
|
||||
" Don't reselect placeholder if it has been modified
|
||||
if leftPlaceholder && g:snipPos[s:curPos][2] != -1
|
||||
if exists('startPlaceholder')
|
||||
let g:snipPos[s:curPos][1] = startPlaceholder
|
||||
else
|
||||
let g:snipPos[s:curPos][1] = col('.')
|
||||
let g:snipPos[s:curPos][2] = 0
|
||||
endif
|
||||
endif
|
||||
|
||||
let s:curPos += a:backwards ? -1 : 1
|
||||
" Loop over the snippet when going backwards from the beginning
|
||||
if s:curPos < 0 | let s:curPos = s:snipLen - 1 | endif
|
||||
|
||||
if s:curPos == s:snipLen
|
||||
let sMode = s:endCol == g:snipPos[s:curPos-1][1]+g:snipPos[s:curPos-1][2]
|
||||
call s:RemoveSnippet()
|
||||
return sMode ? "\<tab>" : TriggerSnippet()
|
||||
endif
|
||||
|
||||
call cursor(g:snipPos[s:curPos][0], g:snipPos[s:curPos][1])
|
||||
|
||||
let s:endLine = g:snipPos[s:curPos][0]
|
||||
let s:endCol = g:snipPos[s:curPos][1]
|
||||
let s:prevLen = [line('$'), col('$')]
|
||||
|
||||
return g:snipPos[s:curPos][2] == -1 ? '' : s:SelectWord()
|
||||
endf
|
||||
|
||||
fun s:UpdatePlaceholderTabStops()
|
||||
let changeLen = s:origWordLen - g:snipPos[s:curPos][2]
|
||||
unl s:startCol s:origWordLen s:update
|
||||
if !exists('s:oldVars') | return | endif
|
||||
" Update tab stops in snippet if text has been added via "$#"
|
||||
" (e.g., in "${1:foo}bar$1${2}").
|
||||
if changeLen != 0
|
||||
let curLine = line('.')
|
||||
|
||||
for pos in g:snipPos
|
||||
if pos == g:snipPos[s:curPos] | continue | endif
|
||||
let changed = pos[0] == curLine && pos[1] > s:oldEndCol
|
||||
let changedVars = 0
|
||||
let endPlaceholder = pos[2] - 1 + pos[1]
|
||||
" Subtract changeLen from each tab stop that was after any of
|
||||
" the current tab stop's placeholders.
|
||||
for [lnum, col] in s:oldVars
|
||||
if lnum > pos[0] | break | endif
|
||||
if pos[0] == lnum
|
||||
if pos[1] > col || (pos[2] == -1 && pos[1] == col)
|
||||
let changed += 1
|
||||
elseif col < endPlaceholder
|
||||
let changedVars += 1
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
let pos[1] -= changeLen * changed
|
||||
let pos[2] -= changeLen * changedVars " Parse variables within placeholders
|
||||
" e.g., "${1:foo} ${2:$1bar}"
|
||||
|
||||
if pos[2] == -1 | continue | endif
|
||||
" Do the same to any placeholders in the other tab stops.
|
||||
for nPos in pos[3]
|
||||
let changed = nPos[0] == curLine && nPos[1] > s:oldEndCol
|
||||
for [lnum, col] in s:oldVars
|
||||
if lnum > nPos[0] | break | endif
|
||||
if nPos[0] == lnum && nPos[1] > col
|
||||
let changed += 1
|
||||
endif
|
||||
endfor
|
||||
let nPos[1] -= changeLen * changed
|
||||
endfor
|
||||
endfor
|
||||
endif
|
||||
unl s:endCol s:oldVars s:oldEndCol
|
||||
endf
|
||||
|
||||
fun s:UpdateTabStops()
|
||||
let changeLine = s:endLine - g:snipPos[s:curPos][0]
|
||||
let changeCol = s:endCol - g:snipPos[s:curPos][1]
|
||||
if exists('s:origWordLen')
|
||||
let changeCol -= s:origWordLen
|
||||
unl s:origWordLen
|
||||
endif
|
||||
let lnum = g:snipPos[s:curPos][0]
|
||||
let col = g:snipPos[s:curPos][1]
|
||||
" Update the line number of all proceeding tab stops if <cr> has
|
||||
" been inserted.
|
||||
if changeLine != 0
|
||||
let changeLine -= 1
|
||||
for pos in g:snipPos
|
||||
if pos[0] >= lnum
|
||||
if pos[0] == lnum | let pos[1] += changeCol | endif
|
||||
let pos[0] += changeLine
|
||||
endif
|
||||
if pos[2] == -1 | continue | endif
|
||||
for nPos in pos[3]
|
||||
if nPos[0] >= lnum
|
||||
if nPos[0] == lnum | let nPos[1] += changeCol | endif
|
||||
let nPos[0] += changeLine
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
elseif changeCol != 0
|
||||
" Update the column of all proceeding tab stops if text has
|
||||
" been inserted/deleted in the current line.
|
||||
for pos in g:snipPos
|
||||
if pos[1] >= col && pos[0] == lnum
|
||||
let pos[1] += changeCol
|
||||
endif
|
||||
if pos[2] == -1 | continue | endif
|
||||
for nPos in pos[3]
|
||||
if nPos[0] > lnum | break | endif
|
||||
if nPos[0] == lnum && nPos[1] >= col
|
||||
let nPos[1] += changeCol
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
endif
|
||||
endf
|
||||
|
||||
fun s:SelectWord()
|
||||
let s:origWordLen = g:snipPos[s:curPos][2]
|
||||
let s:oldWord = strpart(getline('.'), g:snipPos[s:curPos][1] - 1,
|
||||
\ s:origWordLen)
|
||||
let s:prevLen[1] -= s:origWordLen
|
||||
if !empty(g:snipPos[s:curPos][3])
|
||||
let s:update = 1
|
||||
let s:endCol = -1
|
||||
let s:startCol = g:snipPos[s:curPos][1] - 1
|
||||
endif
|
||||
if !s:origWordLen | return '' | endif
|
||||
let l = col('.') != 1 ? 'l' : ''
|
||||
if &sel == 'exclusive'
|
||||
return "\<esc>".l.'v'.s:origWordLen."l\<c-g>"
|
||||
endif
|
||||
return s:origWordLen == 1 ? "\<esc>".l.'gh'
|
||||
\ : "\<esc>".l.'v'.(s:origWordLen - 1)."l\<c-g>"
|
||||
endf
|
||||
|
||||
" This updates the snippet as you type when text needs to be inserted
|
||||
" into multiple places (e.g. in "${1:default text}foo$1bar$1",
|
||||
" "default text" would be highlighted, and if the user types something,
|
||||
" UpdateChangedSnip() would be called so that the text after "foo" & "bar"
|
||||
" are updated accordingly)
|
||||
"
|
||||
" It also automatically quits the snippet if the cursor is moved out of it
|
||||
" while in insert mode.
|
||||
fun s:UpdateChangedSnip(entering)
|
||||
if exists('g:snipPos') && bufnr(0) != s:lastBuf
|
||||
call s:RemoveSnippet()
|
||||
elseif exists('s:update') " If modifying a placeholder
|
||||
if !exists('s:oldVars') && s:curPos + 1 < s:snipLen
|
||||
" Save the old snippet & word length before it's updated
|
||||
" s:startCol must be saved too, in case text is added
|
||||
" before the snippet (e.g. in "foo$1${2}bar${1:foo}").
|
||||
let s:oldEndCol = s:startCol
|
||||
let s:oldVars = deepcopy(g:snipPos[s:curPos][3])
|
||||
endif
|
||||
let col = col('.') - 1
|
||||
|
||||
if s:endCol != -1
|
||||
let changeLen = col('$') - s:prevLen[1]
|
||||
let s:endCol += changeLen
|
||||
else " When being updated the first time, after leaving select mode
|
||||
if a:entering | return | endif
|
||||
let s:endCol = col - 1
|
||||
endif
|
||||
|
||||
" If the cursor moves outside the snippet, quit it
|
||||
if line('.') != g:snipPos[s:curPos][0] || col < s:startCol ||
|
||||
\ col - 1 > s:endCol
|
||||
unl! s:startCol s:origWordLen s:oldVars s:update
|
||||
return s:RemoveSnippet()
|
||||
endif
|
||||
|
||||
call s:UpdateVars()
|
||||
let s:prevLen[1] = col('$')
|
||||
elseif exists('g:snipPos')
|
||||
if !a:entering && g:snipPos[s:curPos][2] != -1
|
||||
let g:snipPos[s:curPos][2] = -2
|
||||
endif
|
||||
|
||||
let col = col('.')
|
||||
let lnum = line('.')
|
||||
let changeLine = line('$') - s:prevLen[0]
|
||||
|
||||
if lnum == s:endLine
|
||||
let s:endCol += col('$') - s:prevLen[1]
|
||||
let s:prevLen = [line('$'), col('$')]
|
||||
endif
|
||||
if changeLine != 0
|
||||
let s:endLine += changeLine
|
||||
let s:endCol = col
|
||||
endif
|
||||
|
||||
" Delete snippet if cursor moves out of it in insert mode
|
||||
if (lnum == s:endLine && (col > s:endCol || col < g:snipPos[s:curPos][1]))
|
||||
\ || lnum > s:endLine || lnum < g:snipPos[s:curPos][0]
|
||||
call s:RemoveSnippet()
|
||||
endif
|
||||
endif
|
||||
endf
|
||||
|
||||
" This updates the variables in a snippet when a placeholder has been edited.
|
||||
" (e.g., each "$1" in "${1:foo} $1bar $1bar")
|
||||
fun s:UpdateVars()
|
||||
let newWordLen = s:endCol - s:startCol + 1
|
||||
let newWord = strpart(getline('.'), s:startCol, newWordLen)
|
||||
if newWord == s:oldWord || empty(g:snipPos[s:curPos][3])
|
||||
return
|
||||
endif
|
||||
|
||||
let changeLen = g:snipPos[s:curPos][2] - newWordLen
|
||||
let curLine = line('.')
|
||||
let startCol = col('.')
|
||||
let oldStartSnip = s:startCol
|
||||
let updateTabStops = changeLen != 0
|
||||
let i = 0
|
||||
|
||||
for [lnum, col] in g:snipPos[s:curPos][3]
|
||||
if updateTabStops
|
||||
let start = s:startCol
|
||||
if lnum == curLine && col <= start
|
||||
let s:startCol -= changeLen
|
||||
let s:endCol -= changeLen
|
||||
endif
|
||||
for nPos in g:snipPos[s:curPos][3][(i):]
|
||||
" This list is in ascending order, so quit if we've gone too far.
|
||||
if nPos[0] > lnum | break | endif
|
||||
if nPos[0] == lnum && nPos[1] > col
|
||||
let nPos[1] -= changeLen
|
||||
endif
|
||||
endfor
|
||||
if lnum == curLine && col > start
|
||||
let col -= changeLen
|
||||
let g:snipPos[s:curPos][3][i][1] = col
|
||||
endif
|
||||
let i += 1
|
||||
endif
|
||||
|
||||
" "Very nomagic" is used here to allow special characters.
|
||||
call setline(lnum, substitute(getline(lnum), '\%'.col.'c\V'.
|
||||
\ escape(s:oldWord, '\'), escape(newWord, '\&'), ''))
|
||||
endfor
|
||||
if oldStartSnip != s:startCol
|
||||
call cursor(0, startCol + s:startCol - oldStartSnip)
|
||||
endif
|
||||
|
||||
let s:oldWord = newWord
|
||||
let g:snipPos[s:curPos][2] = newWordLen
|
||||
endf
|
||||
" vim:noet:sw=4:ts=4:ft=vim
|
||||
Loading…
Add table
Add a link
Reference in a new issue