" config which can be overridden (shared lines) if !exists('g:snipMate') let g:snipMate = {} endif let s:c = g:snipMate try call tlib#input#List('mi', '', []) catch /.*/ echoe "you're missing tlib. See install instructions at ".expand(':h:h').'/README.rst' endtry " disable write cache in files " some people get errors about writing the cache files. Probably there is no " pay off having slow disks anyway. So disabling the cache by default let s:c.cache_parsed_snippets_on_disk = get(s:c, 'cache_parsed_snippets_on_disk', 0) let s:c.read_snippets_cached = get(s:c, 'read_snippets_cached', {'func' : function('snipMate#ReadSnippetsFile'), 'version': 3, 'use_file_cache': s:c.cache_parsed_snippets_on_disk}) " if filetype is objc, cpp, cs or cu also append snippets from scope 'c' " you can add multiple by separating scopes by ',', see s:AddScopeAliases " TODO add documentation to doc/* let s:c.scope_aliases = get(s:c, 'scope_aliases', {}) let s:c.scope_aliases.objc = get(s:c.scope_aliases, 'objc', 'c') let s:c.scope_aliases.cpp = get(s:c.scope_aliases, 'cpp', 'c') let s:c.scope_aliases.cu = get(s:c.scope_aliases, 'cu', 'c') let s:c.scope_aliases.cs = get(s:c.scope_aliases, 'cs','c') let s:c.scope_aliases.xhtml = get(s:c.scope_aliases, 'xhtml', 'html') let s:c.scope_aliases.html = get(s:c.scope_aliases, 'html', 'javascript') let s:c.scope_aliases.php = get(s:c.scope_aliases, 'php', 'php,html,javascript') let s:c.scope_aliases.ur = get(s:c.scope_aliases, 'ur', 'html,javascript') let s:c.scope_aliases.mxml = get(s:c.scope_aliases, 'mxml', 'actionscript') let s:c.scope_aliases.eruby = get(s:c.scope_aliases, 'eruby', 'eruby-rails,html') " set this to "\" to make snipmate not swallow tab (make sure to not have " expandtab set). Remember that you can always enter tabs by then " you don't need this let s:c['no_match_completion_feedkeys_chars'] = get(s:c, 'no_match_completion_feedkeys_chars', "\t") 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 if exists('g:snipmate_content_visual') let visual = g:snipmate_content_visual | unlet g:snipmate_content_visual else let visual = '' endif let snippet = substitute(snippet,'{VISUAL}', escape(visual,'%\'), 'g') " Evaluate eval (`...`) expressions. " Backquotes prefixed with a backslash "\" are ignored. " And backslash can be escaped by doubling it. " Using a loop here instead of a regex fixes a bug with nested "\=". if stridx(snippet, '`') != -1 let new = [] let snip = split(snippet, '\%(\\\@ 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 ? "\" : snipMate#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 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 "\".l.'v'.s:origWordLen."l\" endif return s:origWordLen == 1 ? "\".l.'gh' \ : "\".l.'v'.(s:origWordLen - 1)."l\" 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 " should be moved to utils or such? fun! snipMate#SetByPath(dict, path, value) let d = a:dict for p in a:path[:-2] if !has_key(d,p) | let d[p] = {} | endif let d = d[p] endfor let d[a:path[-1]] = a:value endf " reads a .snippets file " returns list of " ['triggername', 'name', 'contents'] " if triggername is not set 'default' is assumed fun! snipMate#ReadSnippetsFile(file) let result = [] if !filereadable(a:file) | return result | endif let r_guard = 'guard\s\+\zs.*' let inSnip = 0 let guard = 1 for line in readfile(a:file) + ["\n"] if inSnip == 2 && line =~ r_guard let guard = matchstr(line, r_guard) elseif inSnip && (line[0] == "\t" || line == '') let content .= strpart(line, 1)."\n" continue elseif inSnip call add(result, [trigger, name == '' ? 'default' : name, content[:-2], guard]) let inSnip = 0 let guard = "1" endif if inSnip == 2 let inSnip = 1 endif if line[:6] == 'snippet' " 2 signals first line let inSnip = 2 let trigger = strpart(line, 8) let name = '' let space = stridx(trigger, ' ') + 1 if space " Process multi snip let name = strpart(trigger, space) let trigger = strpart(trigger, 0, space - 1) endif let content = '' endif endfor return result endf " adds scope aliases to list. " returns new list " the aliases of aliases are added recursively fun! s:AddScopeAliases(list) let did = {} let scope_aliases = get(s:c,'scope_aliases', {}) let new = a:list let new2 = [] while !empty(new) for i in new if !has_key(did, i) let did[i] = 1 call extend(new2, split(get(scope_aliases,i,''),',')) endif endfor let new = new2 let new2 = [] endwhile return keys(did) endf " don't ask me wy searching for trigger { is soo slow. fun! s:Glob(dir, file) let f = a:dir.a:file if a:dir =~ '\*' || isdirectory(a:dir) return split(glob(escape(f,"{}")),"\n") else return filereadable(f) ? [f] : [] endif endf " returns dict of " { path: { 'type': one of 'snippet' 'snippets', " 'exists': 1 or 0 " " for single snippet files: " 'name': name of snippet " 'trigger': trigger of snippet " } " } " use trigger = '*' to match all snippet files " use mustExist = 1 to return existing files only " " mustExist = 0 is used by OpenSnippetFiles fun! snipMate#GetSnippetFiles(mustExist, scopes, trigger) let paths = funcref#Call(s:c.snippet_dirs) let result = {} let scopes = s:AddScopeAliases(a:scopes) " collect existing files for scope in scopes for r in paths let rtp_last = fnamemodify(r,':t') " .snippets files (many snippets per file). let glob_p = r.'/snippets/'.scope.'.snippets' for snippetsF in split(glob(glob_p),"\n") let scope = fnamemodify(snippetsF,':t:r') let result[snippetsF] = {'exists': 1, 'type': 'snippets', 'name_prefix': rtp_last.' '.scope } endfor if !a:mustExist && !has_key(result, glob_p) " name_prefix not used let result[glob_p] = {'exists': 0, 'type': 'snippets'} endif let glob_p = r.'/snippets/'.scope.'/*.snippets' for snippetsF in split(glob(glob_p),"\n") let result[snippetsF] = {'exists': 1, 'type': 'snippets', 'name_prefix' : rtp_last.' '.fnamemodify(snippetsF,':t:r')} endfor " == one file per snippet: == " without name snippets//.snippet for f in s:Glob(r.'/snippets/'.scope,'/'.a:trigger.'.snippet') let trigger = fnamemodify(f,':t:r') let result[f] = {'exists': 1, 'type': 'snippet', 'name': 'default', 'trigger': trigger, 'name_prefix' : rtp_last.' '.scope} endfor " add /snippets/trigger/*.snippet files (TODO) " with name (multi-snip) snippets///.snippet for f in s:Glob(r.'/snippets/'.scope.'/'.a:trigger,'/*.snippet') let name = fnamemodify(f,':t:r') let trigger = fnamemodify(f,':h:t') let result[f] = {'exists': 1, 'type': 'snippet', 'name': name, 'trigger': trigger, 'name_prefix' : rtp_last.' '.scope} endfor endfor endfor return result endf fun! snipMate#EvalGuard(guard) " left: everything left of expansion " word: the expanded word " are guaranteed to be in scpe if a:guard == '1' | return 1 | endif let word = s:c.word " eval is evil, but backticks are allowed anyway. let left = getline('.')[:col('.')-3 - len(word)] exec 'return '.a:guard endf " default triggers based on paths fun! snipMate#DefaultPool(scopes, trigger, result) let triggerR = substitute(a:trigger,'*','.*','g') for [f,opts] in items(snipMate#GetSnippetFiles(1, a:scopes, a:trigger)) if opts.type == 'snippets' for [trigger, name, contents, guard] in cached_file_contents#CachedFileContents(f, s:c.read_snippets_cached, 0) if trigger !~ triggerR | continue | endif if snipMate#EvalGuard(guard) call snipMate#SetByPath(a:result, [trigger, opts.name_prefix.' '.name], contents) endif endfor elseif opts.type == 'snippet' call snipMate#SetByPath(a:result, [opts.trigger, opts.name_prefix.' '.opts.name], funcref#Function('return readfile('.string(f).')')) else throw "unexpected" endif endfor endf " return a dict of snippets found in runtimepath matching trigger " scopes: list of scopes. usually this is the filetype. eg ['c','cpp'] " trigger may contain glob patterns. Thus use '*' to get all triggers " fun! snipMate#GetSnippets(scopes, trigger) let result = {} let triggerR = escape(substitute(a:trigger,'*','.*','g'), '~') " escape '~' for use as regexp " let scopes = s:AddScopeAliases(a:scopes) for F in values(g:snipMateSources) call funcref#Call(F, [a:scopes, a:trigger, result]) endfor return result endf " adds leading tab " and replaces leading spaces by tabs " see ftplugin/snippet.vim fun! snipMate#RetabSnip() range let leadingTab = expand('%:e') == 'snippets' let lines = getline(a:firstline, a:lastline) " remove leading "\t" let allIndented = 1 for l in lines if l[0] != '\t' | let allIndented = 0 | endif endfor " retab if allIndented call map(lines, 'v:val[1:]') endif let leadingSp = filter(map(copy(lines),'matchstr(v:val,"^\\s*") '),'v:val !=""') if !empty(leadingSp) " lines containing leading spaces found let smallestInd = len(sort(leadingSp)[-1]) let ind = input('retab, spaces per tab: ', smallestInd) for i in range(0, len(lines)-1) let ml = matchlist(lines[i], '^\(\s*\)\(.*\)') let lines[i] = repeat("\t", len(ml[1]) / ind) \ . repeat( " ", len(ml[1]) % ind) \ . ml[2] endfor endif " readd tab let tab = leadingTab ? "\t" : "" for i in range(0,len(lines)-1) call setline(a:firstline + i, tab.lines[i]) endfor endf fun! snipMate#OpenSnippetFiles() let dict = snipMate#GetSnippetFiles(0, snipMate#ScopesByFile(), '*') " sort by files wether they exist - put existing files first let exists = [] let notExists = [] for [file, v] in items(dict) let v['file'] = file if v['exists'] call add(exists, v) else call add(notExists, v) endif endfor let all = exists + notExists let show = map(copy(all),'(v:val["exists"] ? "exists:" : "does not exist yet:")." ".v:val["file"]') let select = tlib#input#List('mi', 'select files to be opened in splits', show) for idx in select exec 'sp '.all[idx - 1]['file'] endfor endf fun! snipMate#ScopesByFile() " duplicates are removed in AddScopeAliases return filter(funcref#Call(s:c.get_scopes), "v:val != ''") endf " used by both: completion and insert snippet fun! snipMate#GetSnippetsForWordBelowCursor(word, suffix, break_on_first_match) " Setup lookups: '1.2.3' becomes [1.2.3] + [3, 2.3] let parts = split(a:word, '\W\zs') if len(parts) > 2 let parts = parts[-2:] " max 2 additional items, this might become a setting endif let lookups = [a:word.a:suffix] let lookup = '' for w in reverse(parts) let lookup = w . lookup if index(lookups, lookup) == -1 call add(lookups, lookup.a:suffix) endif endfor " allow matching '.' if a:word =~ '\.$' call add(lookups, '.'.a:suffix) endif call filter(lookups, 'v:val != ""') " echo lookups let matching_snippets = [] let snippet = '' " prefer longest word for word in lookups let s:c.word = word " echomsg string(lookups).' current: '.word for [k,snippetD] in items(funcref#Call(s:c['get_snippets'], [snipMate#ScopesByFile(), word])) if a:suffix == '' " hack: require exact match if k !=# word | continue | endif endif call add(matching_snippets, [k, snippetD]) if a:break_on_first_match | break| endif endfor endfor return matching_snippets endf " snippets: dict containing snippets by name " usually this is just {'default' : snippet_contents } fun! s:ChooseSnippet(snippets) let snippet = [] let keys = keys(a:snippets) let i = 1 for snip in keys let snippet += [i.'. '.snip] let i += 1 endfor if len(snippet) == 1 " there's only a single snippet, choose it let idx = 0 else let idx = tlib#input#List('si','select snippet by name',snippet) -1 if idx == -1 return '' endif endif " if a:snippets[..] is a String Call returns it " If it's a function or a function string the result is returned return funcref#Call(a:snippets[keys(a:snippets)[idx]]) endf fun! snipMate#ShowAvailableSnips() let line = getline('.') let col = col('.') let word = matchstr(line, '\S\+\%'.col.'c') let matchlen = 0 let matches = [] let snippet_triggers = map(snipMate#GetSnippetsForWordBelowCursor(word, '*', 0),'v:val[0]') for trigger in snippet_triggers if word == '' let matches += [trigger] " Show all matches if word is empty elseif trigger =~ '^'.word let matches += [trigger] let len = len(word) if len > matchlen | let matchlen = len | endif endif endfor " Pretty hacky, but really can't have the tab swallowed! if len(matches) == 0 call feedkeys(s:c['no_match_completion_feedkeys_chars'], 'n') return "" endif " This is to avoid a bug with Vim when using complete(col - matchlen, matches) " (Issue#46 on the Google Code snipMate issue tracker). call setline(line('.'), substitute(line, repeat('.', matchlen).'\%'.col.'c', '', '')) call complete(col, sort(matches)) return '' endf " user interface implementation {{{1 fun! snipMate#TriggerSnippet() if exists('g:SuperTabMappingForward') if g:SuperTabMappingForward == "" let SuperTabPlug = maparg('SuperTabForward', 'i') if SuperTabPlug == "" let SuperTabKey = "\" else exec "let SuperTabKey = \"" . escape(SuperTabPlug, '<') . "\"" endif elseif g:SuperTabMappingBackward == "" let SuperTabPlug = maparg('SuperTabBackward', 'i') if SuperTabPlug == "" let SuperTabKey = "\" else exec "let SuperTabKey = \"" . escape(SuperTabPlug, '<') . "\"" endif endif endif if pumvisible() " Update snippet if completion is used, or deal with supertab if exists('SuperTabKey') call feedkeys(SuperTabKey) | return '' endif call feedkeys("\a", 'n') " Close completion menu call feedkeys("\") | return '' endif if exists('g:snipPos') | return snipMate#jumpTabStop(0) | endif let word = matchstr(getline('.'), '\S\+\%'.col('.').'c') let list = snipMate#GetSnippetsForWordBelowCursor(word, '', 1) if empty(list) let snippet = '' else let [trigger, snippetD] = list[0] let s = s:ChooseSnippet(snippetD) if type(s) == type([]) let snippet = join(s, "\n") else let snippet = s end let &undolevels = &undolevels " create new undo point let col = col('.') - len(trigger) sil exe 's/\V'.escape(trigger, '/\.').'\%#//' return snipMate#expandSnip(snippet, col) endif " should allow other plugins to register hooks instead (duplicate code) if exists('SuperTabKey') call feedkeys(SuperTabKey) return '' endif return word == '' \ ? "\" \ : "\=snipMate#ShowAvailableSnips()\" endf fun! snipMate#BackwardsSnippet() if exists('g:snipPos') | return snipMate#jumpTabStop(1) | endif if exists('g:SuperTabMappingForward') if g:SuperTabMappingForward == "" let SuperTabPlug = maparg('SuperTabForward', 'i') if SuperTabPlug == "" let SuperTabKey = "\" else exec "let SuperTabKey = \"" . escape(SuperTabPlug, '<') . "\"" endif elseif g:SuperTabMappingBackward == "" let SuperTabPlug = maparg('SuperTabBackward', 'i') if SuperTabPlug == "" let SuperTabKey = "\" else exec "let SuperTabKey = \"" . escape(SuperTabPlug, '<') . "\"" endif endif endif " should allow other plugins to register hooks instead (duplicate code) if exists('SuperTabKey') call feedkeys(SuperTabKey) return '' endif return "\" endf " vim:noet:sw=4:ts=4:ft=vim