" Default settings and functions used in every snippet file. XPTemplate priority=all " containers let s:f = g:XPTfuncs() XPTvar $author $author is not set, you need to set g:xptemplate_vars="$author=your_name" in .vimrc XPTvar $email $email is not set, you need to set g:xptemplate_vars="$email=your_email@com" in .vimrc XPTvar $VOID " if () ** { " else ** { XPTvar $BRif ' ' " } ** else { XPTvar $BRel \n " for () ** { " while () ** { " do ** { XPTvar $BRloop ' ' " struct name ** { XPTvar $BRstc ' ' " int fun() ** { " class name ** { XPTvar $BRfun ' ' " int fun ** ( " class name ** ( XPTvar $SPfun '' " int fun( ** arg ** ) " if ( ** condition ** ) " for ( ** statement ** ) " [ ** a, b ** ] " { ** 'k' : 'v' ** } XPTvar $SParg ' ' " if ** ( " while ** ( " for ** ( XPTvar $SPcmd ' ' " a ** = ** b " a = a ** + ** 1 " (a, ** b, ** ) XPTvar $SPop ' ' XPTvar $DATE_FMT '%Y %b %d' XPTvar $TIME_FMT '"%H:%M:%S"' XPTvar $DATETIME_FMT '%c' XPTvar $TRUE 1 XPTvar $FALSE 0 XPTvar $NULL 0 XPTvar $UNDEFINED 0 XPTvar $VOID_LINE XPTvar $CURSOR_PH CURSOR XPTinclude \ _common/personal \ _common/inlineComplete \ _common/common.* let s:f_prototype = xpt#snipfunction#funcs call extend( s:f, s:f_prototype, 'error' ) fun! s:f._xSnipName() return self._ctx.renderContext.snipObject.name endfunction fun! s:f.GetWrappedText() let wrap = self._ctx.renderContext.wrap let [ l, r ] = self.ItemEdges() if !has_key( wrap, 'text' ) return 0 endif if l == '' && r == '' return { 'nIndent' : wrap.indent, \ 'action' : 'text', \ 'parseIndent' : 0, \ 'text' : wrap.text } else let wrap.curline = wrap.lines[ 0 ] let wrap.lines = wrap.lines[ 1 : ] return wrap.curline endif endfunction fun! s:f.WrapAlignAfter( min ) let wrap = self._ctx.renderContext.wrap let n = max( [ a:min, wrap.max ] ) - len( wrap.curline ) return repeat( ' ', n ) endfunction fun! s:f.WrapAlignBefore( min ) let wrap = self._ctx.renderContext.wrap let n = max( [ a:min, wrap.max ] ) - len( wrap.lines[ 0 ] ) return repeat( ' ', n ) endfunction fun! s:f.Item() return get( self._ctx.renderContext, 'item', {} ) endfunction " current name fun! s:f.ItemName() "{{{ return get( self.Item(), 'name', '' ) endfunction "}}} let s:f.N = s:f.ItemName " name with edge fun! s:f.ItemFullname() "{{{ return get( self.Item(), 'fullname', '') endfunction "}}} let s:f.NN = s:f.ItemFullname " current value user typed fun! s:f.ItemValue() dict "{{{ return self.GetVar( '$UserInput' ) endfunction "}}} let s:f.V = s:f.ItemValue fun! s:f.PrevItem( n ) let hist = get( self._ctx.renderContext, 'history', [] ) return get( hist, a:n, {} ) endfunction fun! s:f.ItemInitValue() return get( self.Item(), 'initValue', '' ) endfunction let s:f.IV = s:f.ItemInitValue fun! s:f.ItemValueStripped( ... ) let ptn = a:0 == 0 || a:1 =~ 'lr' \ ? '\V\^\s\*\|\s\*\$' \ : ( a:1 == 'l' \ ? '\V\^\s\*' \ : '\V\s\*\$' ) return substitute( self.ItemValue(), ptn, '', 'g' ) endfunction let s:f.VS = s:f.ItemValueStripped fun! s:f.ItemPos() return XPMposStartEnd( self._ctx.renderContext.leadingPlaceHolder.mark ) endfunction fun! s:f.ItemInitValueWithEdge() let [ l, r ] = self.ItemEdges() return l . self.IV() . r endfunction let s:f.IVE = s:f.ItemInitValueWithEdge " if value match one of the regexps fun! s:f.Vmatch( ... ) let v = self.V() for reg in a:000 if match(v, reg) != -1 return 1 endif endfor return 0 endfunction " value matchstr fun! s:f.VMS( reg ) return matchstr(self.V(), a:reg) endfunction " edge stripped value fun! s:f.ItemStrippedValue() let v = self.V() let [edgeLeft, edgeRight] = self.ItemEdges() let v = substitute( v, '\V\^' . edgeLeft, '', '' ) let v = substitute( v, '\V' . edgeRight . '\$', '', '' ) return v endfunction let s:f.V0 = s:f.ItemStrippedValue fun! s:f.Phase() dict return get( self._ctx.renderContext, 'phase', '' ) endfunction " TODO this is not needed at all except as a shortcut. " equals to expand() fun! s:f.E(s) "{{{ return expand(a:s) endfunction "}}} " return the context fun! s:f.Context() "{{{ return self._ctx.renderContext endfunction "}}} let s:f.C = s:f.Context " TODO this is not needed at all except as a shortcut. " post filter substitute fun! s:f.S(str, ptn, rep, ...) "{{{ let flg = a:0 >= 1 ? a:1 : 'g' return substitute(a:str, a:ptn, a:rep, flg) endfunction "}}} " equals to S(C().value, ...) fun! s:f.SubstituteWithValue(ptn, rep, ...) "{{{ let flg = a:0 >= 1 ? a:1 : 'g' return substitute(self.V(), a:ptn, a:rep, flg) endfunction "}}} let s:f.SV = s:f.SubstituteWithValue fun! s:f.HasStep( name ) let namedStep = get( self._ctx.renderContext, 'namedStep', {} ) return has_key( namedStep, a:name ) endfunction " reference to another finished item value fun! s:f.Reference(name) "{{{ let namedStep = get( self._ctx.renderContext, 'namedStep', {} ) return get( namedStep, a:name, '' ) endfunction "}}} let s:f.R = s:f.Reference fun! s:f.Snippet( name ) return get( self._ctx.renderContext.ftScope.allTemplates, a:name, { 'tmpl' : '' } )[ 'tmpl' ] endfunction " black hole fun! s:f.Void(...) "{{{ return "" endfunction "}}} let s:f.VOID = s:f.Void " Echo several expression and concat them. " That's the way to use normal vim script expression instead of mixed string fun! s:f.Echo( ... ) let text = '' if a:0 > 0 let text = a:1 endif return { 'action': 'text', 'text': text } endfunction fun! s:f.EchoIf( isTrue, ... ) if a:isTrue return join( a:000, '' ) else return self.V() endif endfunction fun! s:f.EchoIfEq( expected, ... ) if self.V() ==# a:expected return join( a:000, '' ) else return self.V() endif endfunction fun! s:f.EchoIfNoChange( ... ) if self.V0() ==# self.ItemName() return join( a:000, '' ) else return self.V() endif endfunction fun! s:f.Commentize( text ) if has_key( self, '$CL' ) return self[ '$CL' ] . ' ' . a:text . ' ' . self[ '$CR' ] elseif has_key( self, '$CS' ) return self[ '$CS' ] . ' ' . a:text endif return a:text endfunction fun! s:f.VoidLine() return self.Commentize( 'void' ) endfunction " Same with Echo* except echoed text is to be build to generate dynamic place " holders fun! s:f.Build( ... ) return { 'action' : 'build', 'text' : join( a:000, '' ) } endfunction let s:f.Embed = s:f.Build fun! s:f.BuildSnippet( snipname ) return { 'action' : 'build', 'snippet' : a:snipname } endfunction fun! s:f.BuildIfChanged( ... ) let v = substitute( self.V(), "\\V\n\\|\\s", '', 'g') " let fn = substitute( self.ItemFullname(), "\\V\n\\|\\s", '', 'g') let fn = substitute( self.ItemInitValueWithEdge(), "\\V\n\\|\\s", '', 'g') if v ==# fn || v == '' return '' else return { 'action' : 'build', 'text' : join( a:000, '' ) } endif endfunction fun! s:f.BuildIfNoChange( ... ) let v = substitute( self.V(), "\\V\n\\|\\s", '', 'g') " let fn = substitute( self.ItemFullname(), "\\V\n\\|\\s", '', 'g') let fn = substitute( self.ItemInitValueWithEdge(), "\\V\n\\|\\s", '', 'g') if v ==# fn return { 'action' : 'build', 'text' : join( a:000, '' ) } else return 0 endif endfunction " trigger nested template fun! s:f.Trigger( name ) "{{{ return {'action' : 'expandTmpl', 'tmplName' : a:name} endfunction "}}} fun! s:f.Finish(...) let opt = {} if a:0 > 0 let opt.text = a:1 endif return self.Fin(opt) endfunction fun! s:f.FinishOuter( ... ) let opt = {"marks" : "mark"} if a:0 > 0 let opt.text = a:1 endif return self.Fin(opt) endfunction fun! s:f.FinishInner( ... ) let opt = {"marks" : "innerMarks"} if a:0 > 0 let opt.text = a:1 endif return self.Fin(opt) endfunction fun! s:f.Fin(opt) " there is still items left if ! empty( self._ctx.renderContext.itemList ) return get(a:opt, 'text', 0) endif let r = {'action' : 'finishTemplate'} if has_key(a:opt, 'text') let r.text = a:opt.text endif if has_key(a:opt, 'marks') let r.marks = a:opt.marks endif return r endfunction fun! s:f.Next( ... ) if a:0 == 0 return { 'nav' : 'next' } else return { 'nav' : 'next', 'text' : join( a:000, '' ) } endif endfunction fun! s:f.Remove() return { 'action' : 'text', 'nav' : 'next', 'text' : '' } endfunction " This function is intended to be used for popup selection : " XSET bidule=Choose([' ','dabadi','dabada']) fun! s:f.Choose( lst, ... ) "{{{ let val = { 'action' : 'pum', 'pum' : a:lst } if a:0 == 1 let val.acceptEmpty = a:1 != 0 endif return val endfunction "}}} fun! s:f.ChooseStr(...) "{{{ return copy( a:000 ) endfunction "}}} " XXX " Fill in postType, and finish template rendering at once. " This make nested template rendering go back to upper level, top-level " template rendering quit. fun! s:f.xptFinishTemplateWith(postType) dict endfunction " XXX " Fill in postType, jump to next item. For creating item being able to be " automatically filled in fun! s:f.xptFinishItemWith(postType) dict endfunction " TODO test me fun! s:f.UnescapeMarks(string) dict let patterns = self._ctx.renderContext.snipObject.ptn let charToEscape = '\(\[' . patterns.l . patterns.r . ']\)' let r = substitute( a:string, '\v(\\*)\1\\?\V' . charToEscape, '\1\2', 'g') return r endfunction let s:f.UE = s:f.UnescapeMarks fun! s:f.headerSymbol(...) "{{{ let h = expand('%:t') let h = substitute(h, '\.', '_', 'g') " replace . with _ let h = substitute(h, '.', '\U\0', 'g') " make all characters upper case return '__'.h.'__' endfunction "}}} fun! s:f.date(...) "{{{ return strftime( self.GetVar( '$DATE_FMT' ) ) endfunction "}}} fun! s:f.datetime(...) "{{{ return strftime( self.GetVar( '$DATETIME_FMT' ) ) endfunction "}}} fun! s:f.time(...) "{{{ return strftime( self.GetVar( '$TIME_FMT' ) ) endfunction "}}} fun! s:f.file(...) "{{{ return expand("%:t") endfunction "}}} fun! s:f.fileRoot(...) "{{{ return expand("%:t:r") endfunction "}}} fun! s:f.fileExt(...) "{{{ return expand("%:t:e") endfunction "}}} fun! s:f.path(...) "{{{ return expand("%:p") endfunction "}}} fun! s:f.UpperCase( v ) return substitute(a:v, '.', '\u&', 'g') endfunction fun! s:f.LowerCase( v ) return substitute(a:v, '.', '\l&', 'g') endfunction " Return Item Edges fun! s:f.ItemEdges() "{{{ let leader = get( self._ctx.renderContext, 'leadingPlaceHolder', {} ) if has_key( leader, 'leftEdge' ) return [ leader.leftEdge, leader.rightEdge ] else return [ '', '' ] endif endfunction "}}} let s:f.Edges = s:f.ItemEdges fun! s:f.ItemCreate( name, edges, filters ) let [ ml, mr ] = XPTmark() let item = ml . a:name if has_key( a:edges, 'left' ) let item = ml . a:edges.left . item endif if has_key( a:edges, 'right' ) let item .= ml . a:edges.right endif let item .= mr if has_key( a:filters, 'post' ) let item .= a:filters.post . mr . mr endif return item endfunction " {{{ Quick Repetition " If something typed, ing to next generate another item other than the " typed. " " If nothing typed but only to next, clear it. " " Normal clear typed, also clear it " TODO escape mark character in a:sep or a:item " }}} fun! s:f.ExpandIfNotEmpty( sep, item, ... ) "{{{ let v = self.V() let [ ml, mr ] = XPTmark() if a:0 != 0 let r = a:1 else let r = '' endif " let t = ( v == '' || v == a:item || v == ( a:sep . a:item . r ) ) let t = ( v == '' || v =~ '\V' . a:item ) \ ? '' \ : self.Build( v \ . ml . a:sep . ml . a:item . ml . r . mr \ . 'ExpandIfNotEmpty(' . string( a:sep ) . ', ' . string( a:item ) . ')' . mr . mr ) return t endfunction "}}} fun! s:f.ExpandInsideEdge( newLeftEdge, newRightEdge ) let v = self.V() let fullname = self.ItemFullname() let [ el, er ] = self.ItemEdges() if v ==# fullname || v == '' return '' endif return substitute( v, '\V' . er . '\$' , '' , '' ) \. self.ItemCreate( self.ItemName(), { 'left' : a:newLeftEdge, 'right' : a:newRightEdge }, {} ) \. er endfunction fun! s:f.NIndent() return &shiftwidth endfunction fun! s:f.ResetIndent( nIndent, text ) return { 'action' : 'resetIndent', 'resetIndent' : 1, 'nIndent' : a:nIndent, 'text' : a:text } endfunction fun! s:f.CmplQuoter_pre() dict if !g:xptemplate_brace_complete return '' endif let v = substitute( self.ItemStrippedValue(), '\V\^\s\*', '', '' ) let first = matchstr( v, '\V\^\[''"]' ) if first == '' return '' endif let v = substitute( v, '\V\[^' . first . ']', '', 'g' ) if v == first " only 1 quoter return first else return '' endif endfunction fun! s:f.AutoCmpl( keepInPost, list, ... ) if !a:keepInPost && self.Phase() == 'post' return '' endif if type( a:list ) == type( [] ) let list = a:list else let list = [ a:list ] + a:000 endif let v = self.V0() if v == '' return '' endif for word in list if word =~ '\V\^' . v return word[ len( v ) : ] endif endfor return '' endfunction " Short names are normally not good. Some alias to those short name functions are " made, with meaningful names. " " They all start with prefix 'xpt'. " " ================================= Snippets =================================== " Shortcuts call XPTdefineSnippet('Author', {}, '`$author^') call XPTdefineSnippet('Email', {}, '`$email^') call XPTdefineSnippet("Date", {}, "`date()^") call XPTdefineSnippet("File", {}, "`file()^") call XPTdefineSnippet("Path", {}, "`path()^") call XPTdefineSnippet('"_', {'hint' : '" .. "', 'wraponly' : 'w' }, '"`w^"') call XPTdefineSnippet("'_", {'hint' : "' .. '", 'wraponly' : 'w' }, "'`w^'") call XPTdefineSnippet("<_", {'hint' : '< .. >', 'wraponly' : 'w' }, '<`w^>') call XPTdefineSnippet("(_", {'hint' : '( .. )', 'wraponly' : 'w' }, '(`w^)') call XPTdefineSnippet("[_", {'hint' : '[ .. ]', 'wraponly' : 'w' }, '[`w^]') call XPTdefineSnippet("{_", {'hint' : '{ .. }', 'wraponly' : 'w' }, '{`w^}') call XPTdefineSnippet("`_", {'hint' : '` .. `', 'wraponly' : 'w' }, '\``w^\`')