" Vimball Archiver by Charles E. Campbell, Jr., Ph.D. UseVimball finish doc/templator.txt [[[1 254 *templator.txt* Multi-file project templates using skeleton/snippets engines Author: Tom Link, micathom at gmail com The templator plugin allows the creation of filesets based on multi-file templates. Templates could be written in any code template/skeleton/snippets style. At the time of writing, templates can be written in: - template vim (see |templator-tvim|) ("tvim" extension) - tskeleton (vimscript #1160) ("tskel" extension) It shoudln't be too difficult to add support for additional template engines. The |:Templator| command can be used to create multi-file projects. Example 1: Create files for the "test" template-set in the current root directory, which usually is the current working directory unless |b:templator_root_dir| is set: > :Templator test Example 2: Create files for the "test" template-set in some directory (the directory is created if it doesn't already exist): > :Templator ~/src/foo/bar/test Templates are kept in "templator" subdirectories in your 'runtimepath' (e.g. ~/.vim/templator). A subdirectory's name consists of "TEMPLATE_NAME.TEMPLATE_TYPE". TEMPLATE_NAME is the name that is used for the |:Templator| command. TEMPLATE_TYPE is the name of the template engine used to expand file templates. Templates consist of a bunch of files and an optional vim script (see |templator-scripts|) that is run after creating the files. ----------------------------------------------------------------------- Tutorial~ Following the second example above, (using tskeleton for file templates) the root directory of the template set would be: > ~/.vim/templator/test.tskel/ The template set could, e.g., consist of the following files: > ~/.vim/templator/test.tskel/README.TXT ~/.vim/templator/test.tskel/docs/index.html ~/.vim/templator/test.tskel/src/main.c and an optional vim script (see |templator-scripts|) in: ~/.vim/templator/test.vim This vim script is run with ~/src/foo/bar/ set as current working directory. The above command call > :Templator ~/src/foo/bar/test would the result in the creation of the following files: > ~/src/foo/bar/README.TXT ~/src/foo/bar/docs/index.html ~/src/foo/bar/docs/main.c ----------------------------------------------------------------------- *templator-scripts* Template scripts~ Every template set may be accompanied by a vim script in the parent directory. E.g. the script file for the template set "~/.vim/templator/test.tskel/" is "~/.vim/templator/test.vim". The template script for template NAME can set the following |dictionary-function|s (self is set to g:templator#drivers[NAME]): g:templator#drivers.{NAME}.Before(args) dict Called before processing the template set. g:templator#drivers.{NAME}.Buffer(args) dict Called on each newly created file. g:templator#drivers.{NAME}.After(args) dict Called after processing the template set. ----------------------------------------------------------------------- *templator-placeholders* Placeholders in filenames~ The basename of template files may contain place holders. The values for these placeholders can be set when calling the |:Templator| command. The argument may contain named or numbered arguments. E.g. :Templator test foo class=Test bar Will create files based on the template set called "test" with the following argument list: 1 ....... foo 2 ....... bar class ... Test Placeholders in filenames can be defined as follows: ${1} .............. 1 can be any numeric value that references the nth (unnamed) value of the argument list ${NAME} ........... Replace with the argument NAME ${NAME=DEFAULT} ... Replace with the argument NAME but use the DEFAULT value if it isn't set Example: With the above argument list the template filename "docs/${class}.txt" will be expanded to the filename "~/src/foo/bar/docs/Test.txt". ----------------------------------------------------------------------- Install~ In order to install the vba, open the vba file in VIM and type: > :so % See :help vimball for details. Also available via git: http://github.com/tomtom/templator_vim/ Optional: In order to use tskeleton-style template sets, tskeleton (vimscript #1160) must be installed: http://www.vim.org/scripts/script.php?script_id=1160 ======================================================================== Contents~ :Templator .............................. |:Templator| g:templator#verbose ..................... |g:templator#verbose| g:templator#edit ........................ |g:templator#edit| g:templator#sep ......................... |g:templator#sep| templator#Setup ......................... |templator#Setup()| g:templator#expander#tvim#enable ........ |g:templator#expander#tvim#enable| templator#expander#tvim#Init ............ |templator#expander#tvim#Init()| templator#expander#tvim#Expand .......... |templator#expander#tvim#Expand()| templator#expander#tskel#Init ........... |templator#expander#tskel#Init()| templator#expander#tskel#Expand ......... |templator#expander#tskel#Expand()| ======================================================================== plugin/templator.vim~ *:Templator* :Templator [DIRNAME/]NAME [ARG1 ARG2 ...] NAME is the basename (with the extension removed) of a multi-files project template. The list of optional arguments is used to expand place holders in filenames (see |templator-placeholders|). See |templator#Setup()| for details. ======================================================================== autoload/templator.vim~ *g:templator#verbose* g:templator#verbose (default: 1) If true, show some warnings (e.g. when opening an already existing file that wasn't created by templator). *g:templator#edit* g:templator#edit (default: 'hide edit') The command used for opening files. *g:templator#sep* g:templator#sep (default: exists('+shellslash') && !&shellslash ? '\' : '/') *templator#Setup()* templator#Setup(name, ...) The name argument may contain directory information. E.g. "foo/bar/test" will create file from the template set "test" in the directory "foo/bar", which will be created if necessary. *b:templator_root_dir* If the name argument begins with "*", the filename is relative to the project's root directory. Templator uses the following methods to find the project's root directory: 1. If the variable b:templator_root_dir exists, use its value. 2. If tlib (vimscript #1863) is available, check if the current buffer is under the control of a supported VCS and use that directory. Example: If b:templator_root_dir is /home/foo/bar and the current buffer is /home/foo/bar/src/lib/test.c, then *boo/far will create files from the "far" template set in /home/foo/bar/boo. Additional arguments can be passed as a mix of numbered and named arguments. E.g. "foo name=bar boo" will be parsed as: 1 = foo name = bar 2 = boo Those arguments can be used from placeholders (see |templator-placeholders|). ======================================================================== autoload/templator/expander/tvim.vim~ *templator-tvim* Template vim~ tvim is a minimal php-style template engine. The following place-holders are supported: ... Replace the placeholder with the output (see |:echo|) of the enclosed vim code. .. Set the cursor at this position after expanding any placeholder. *g:templator#expander#tvim#enable* g:templator#expander#tvim#enable (default: 1) It true, enable templates in template-vim. Code embedded in templates is executed via |:@|. It is not run in the sandbox. *templator#expander#tvim#Init()* templator#expander#tvim#Init() *templator#expander#tvim#Expand()* templator#expander#tvim#Expand() ======================================================================== autoload/templator/expander/tskel.vim~ *templator#expander#tskel#Init()* templator#expander#tskel#Init() *templator#expander#tskel#Expand()* templator#expander#tskel#Expand() vim:tw=78:fo=tcq2:isk=!-~,^*,^|,^":ts=8:ft=help:norl: plugin/templator.vim [[[1 31 " @Author: Tom Link (micathom AT gmail com?subject=[vim]) " @Website: http://www.vim.org/account/profile.php?user_id=4037 " @GIT: http://github.com/tomtom/ " @License: GPL (see http://www.gnu.org/licenses/gpl.txt) " @Last Change: 2010-09-26. " @Revision: 17 " GetLatestVimScripts: 0 0 :AutoInstall: templator.vim " Project templates using skeleton/snippets engines if &cp || exists("loaded_templator") finish endif let loaded_templator = 1 let s:save_cpo = &cpo set cpo&vim " :display: :Templator [DIRNAME/]NAME [ARG1 ARG2 ...] " NAME is the basename (with the extension removed) of a multi-files " project template. " " The list of optional arguments is used to expand place holders in " filenames (see |templator-placeholders|). " " See |templator#Setup()| for details. command! -complete=customlist,templator#Complete -nargs=+ Templator call templator#Setup() let &cpo = s:save_cpo unlet s:save_cpo autoload/templator.vim [[[1 334 " @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim]) " @License: GPL (see http://www.gnu.org/licenses/gpl.txt) " @Last Change: 2012-12-05. " @Revision: 285 if !exists('g:templator#verbose') " If true, show some warnings (e.g. when opening an already existing " file that wasn't created by templator). let g:templator#verbose = 1 "{{{2 endif if !exists('g:templator#drivers') " :nodoc: let g:templator#drivers = {} "{{{2 endif if !exists('g:templator#edit') " The command used for opening files. let g:templator#edit = 'hide edit' "{{{2 endif if !exists('g:templator#sep') let g:templator#sep = exists('+shellslash') && !&shellslash ? '\' : '/' "{{{2 endif let s:expanders_init = {} " :nodoc: function! templator#Complete(ArgLead, CmdLine, CursorPos) "{{{3 let templators = keys(s:GetAllTemplators()) " TLogVAR templators let dir = fnamemodify(a:ArgLead, ':h') let base = fnamemodify(a:ArgLead, ':t') let templators = filter(templators, 'strpart(v:val, 0, len(a:ArgLead)) ==# base') if empty(templators) let completions = split(glob(a:ArgLead .'*'), '\n') else let completions = map(templators, 's:JoinFilename(dir, v:val)') endif " TLogVAR completions return completions endf " Create files based on the template set referred to by the basename of " the name argument. " The name argument may contain directory information. E.g. " "foo/bar/test" will create file from the template set "test" in the " directory "foo/bar", which will be created if necessary. " " *b:templator_root_dir* " If the name argument begins with "*", the filename is relative to the " project's root directory. Templator uses the following methods to find " the project's root directory: " " 1. If the variable b:templator_root_dir exists, use its value. " 2. If tlib (vimscript #1863) is available, check if the current " buffer is under the control of a supported VCS and use that " directory. " " Example: " If b:templator_root_dir is /home/foo/bar and the current buffer is " /home/foo/bar/src/lib/test.c, then *boo/far will create files from the " "far" template set in /home/foo/bar/boo. " " Additional arguments can be passed as a mix of numbered and named " arguments. E.g. "foo name=bar boo" will be parsed as: " " 1 = foo " name = bar " 2 = boo " " Those arguments can be used from placeholders (see " |templator-placeholders|). function! templator#Setup(name, ...) "{{{3 let args = s:ParseArgs(a:000) let [tname, dirname] = s:GetDirname(a:name) " TLogVAR dirname let templator = s:GetTemplator(tname) let ttype = templator.type let cwd = getcwd() " TLogVAR cwd try " TLogVAR templator.dir let templator_dir_len = len(templator.dir) + 1 if templator.dir =~ '[\/]$' let templator_dir_len += 1 endif call s:RunHook(dirname, tname, 'Before', args) for filename in templator.files call s:SetDir(dirname) " TLogVAR filename let outfile = s:GetOutfile(dirname, filename, args, templator_dir_len) if filereadable(outfile) if g:templator#verbose echohl WarningMsg echom "Templator: File already exists: " outfile echohl NONE endif exec g:templator#edit fnameescape(outfile) else let lines = readfile(filename) if writefile(lines, outfile) != -1 let fargs = copy(args) let fargs.filename = outfile if !s:RunHook('', tname, 'Edit', args) exec g:templator#edit fnameescape(outfile) endif let b:templator_args = args call templator#expander#{ttype}#Expand() call s:RunHook(&acd ? '' : expand('%:p:h'), tname, 'Buffer', args) unlet! b:templator_args update endif endif endfor call s:RunHook(dirname, tname, 'After', args) finally exec 'cd' fnameescape(cwd) endtry endf function! s:GetAllTemplators() "{{{3 if !exists('s:templators') let files = globpath(&rtp, 'templator/*.*') let s:templators = {} for dirname in split(files, '\n') if isdirectory(dirname) let tname = fnamemodify(dirname, ':t:r') let ttype = fnamemodify(dirname, ':e') " TLogVAR ttype, tname if !has_key(s:expanders_init, ttype) try let s:expanders_init[ttype] = templator#expander#{ttype}#Init() catch /^Vim\%((\a\+)\)\=:E117/ let s:expanders_init[ttype] = 0 endtry endif " echom "DBG get(s:expanders_init, ttype, 0)" get(s:expanders_init, ttype, 0) if get(s:expanders_init, ttype, 0) if has_key(s:templators, tname) if g:templator#verbose echohl WarningMsg echom "Templator: duplicate entry:" tname filename echohl NONE endif else let dirname_len = len(dirname) let filenames = split(glob(dirname .'/**/*'), '\n') let filenames = filter(filenames, '!isdirectory(v:val)') let s:templators[tname] = { \ 'type': ttype, \ 'dir': dirname, \ 'files': filenames \ } endif endif endif endfor endif return s:templators endf function! s:GetDirname(name) "{{{3 " TLogVAR a:name if a:name =~ '^\*' let use_root = 1 let name = strpart(a:name, 1) else let use_root = 0 let name = a:name endif let dirname = fnamemodify(name, ':h') let tname = fnamemodify(name, ':t') " TLogVAR use_root, name, dirname, tname if use_root if exists('b:templator_root_dir') let dirname = s:JoinFilename(b:templator_root_dir, dirname) elseif exists('g:loaded_tlib') && g:loaded_tlib >= 100 let [vcs_type, vcs_dir] = tlib#vcs#FindVCS(expand('%')) " TLogVAR vcs_type, vcs_dir if !empty(vcs_dir) let dirname = s:JoinFilename(fnamemodify(vcs_dir, ':p:h:h'), dirname) endif else echohl WarningMsg echom "Templator: No method left to find the project's root directory:" a:name echohl NONE endif endif " TLogVAR dirname let dirname = fnamemodify(dirname, ':p') if !isdirectory(dirname) call mkdir(dirname, 'p') endif " TLogVAR tname, dirname return [tname, dirname] endf function! s:GetTemplator(tname) "{{{3 let templators = s:GetAllTemplators() if !has_key(templators, a:tname) throw "Templator: Unknown template name: ". a:tname endif let templator = templators[a:tname] let ttype = templator.type if !get(s:expanders_init, ttype, 0) throw printf("Templator: Unsupported template type %s for %s", ttype, a:name) endif if !has_key(g:templator#drivers, ttype) let g:templator#drivers[a:tname] = {} let driver_file = fnamemodify(templator.dir, ':p:h:r') .'.vim' " TLogVAR driver_file, filereadable(driver_file) if filereadable(driver_file) exec 'source' fnameescape(driver_file) endif endif return templator endf function! s:GetOutfile(dirname, filename, args, templator_dir_len) "{{{3 " TLogVAR a:dirname, a:filename, a:args, a:templator_dir_len let subdir = strpart(fnamemodify(a:filename, ':h'), a:templator_dir_len) " TLogVAR subdir let subfilename = s:ExpandFilename(fnamemodify(a:filename, ':t'), a:args) " TLogVAR subfilename let outdir = a:dirname if !empty(subdir) if outdir == '.' let outdir = subdir else let outdir = s:JoinFilename(outdir, subdir) endif endif " TLogVAR outdir if outdir == '.' let outfile = subfilename else if !isdirectory(outdir) call mkdir(outdir, 'p') endif let outfile = s:JoinFilename(outdir, subfilename) endif " TLogVAR outfile return outfile endf function! s:RunHook(dirname, tname, name, args, ...) "{{{3 " TLogVAR a:dirname, a:tname, a:name, a:args let tdef = g:templator#drivers[a:tname] " TLogVAR tdef if has_key(tdef, a:name) if !empty(a:dirname) let cwd = getcwd() endif try call s:SetDir(a:dirname) " TLogVAR tdef[a:name] call tdef[a:name](a:args) return 1 finally if !empty(a:dirname) exec 'cd' fnameescape(cwd) endif endtry endif return 0 endf function! s:SetDir(dirname) "{{{3 let dirname = s:StripSep(a:dirname) " TLogVAR dirname, getcwd() if !empty(dirname) && getcwd() != dirname exec 'cd' fnameescape(dirname) endif endf function! s:ExpandFilename(filename, args) "{{{3 let filename = substitute(a:filename, '\$\(\$\|{\(\w\+\)\%(=\(.\{-}\)\)\?}\)', '\=s:PlaceHolder(a:args, submatch(1), submatch(2), submatch(3))', 'g') return filename endf function! s:PlaceHolder(args, pct, name, default) "{{{3 if a:pct == '$' return '$' else return get(a:args, a:name, a:default) endif endf function! s:ParseArgs(arglist) "{{{3 let args = {} let idx = 1 for arg in a:arglist if arg =~ '^\w\+=' let key = matchstr(arg, '^\w\{-}\ze=') let val = matchstr(arg, '^\w\{-}=\zs.*$') else let key = idx let val = arg let idx += 1 endif let args[key] = val endfor return args endf function! s:JoinFilename(...) "{{{3 let parts = map(copy(a:000), 's:StripSep(v:val)') return join(parts, g:templator#sep) endf function! s:StripSep(filename) "{{{3 return substitute(a:filename, '[\/]$', '', 'g') endf autoload/templator/expander/tvim.vim [[[1 68 " @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim]) " @License: GPL (see http://www.gnu.org/licenses/gpl.txt) " @Last Change: 2012-12-06. " @Revision: 54 " :doc: " *templator-tvim* " Template vim~ " " tvim is a minimal php-style template engine. The following " place-holders are supported: " " ... Replace the placeholder with the output (see " |:echo|) of the enclosed vim code. " .. Set the cursor at this position after expanding any " placeholder. if !exists('g:templator#expander#tvim#enable') " It true, enable templates in template-vim. " " Code embedded in templates is executed via |:@|. It is not run in " the sandbox. let g:templator#expander#tvim#enable = 1 "{{{2 endif function! templator#expander#tvim#Init() "{{{3 return g:templator#expander#tvim#enable endf function! templator#expander#tvim#Expand() "{{{3 let text = join(getline(1, '$'), "\n") let text = substitute(text, '', '\=s:Replace(submatch(1))', 'g') " TLogVAR text let lines = split(text, ' \|\n') 1,$delete call append(1, lines) 1delete if search('', 'cw') let line = substitute(getline('.'), '', '', '') call setline('.', line) endif endf function! s:Replace(code) "{{{3 " TLogVAR a:code let lines = split(a:code, '\n') let lines = map(lines, '":". v:val') let t = @t try let @t = join(lines, "\n") ."\n" " TLogVAR @t redir => output silent @t redir END finally let @t = t endtry let output = substitute(output, '^\n\|\n$', '', '') " let output = substitute(output, '\n', "\", 'g') " TLogVAR output return output endf autoload/templator/expander/tskel.vim [[[1 15 " @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim]) " @License: GPL (see http://www.gnu.org/licenses/gpl.txt) " @Last Change: 2012-12-05. " @Revision: 7 function! templator#expander#tskel#Init() "{{{3 return exists(":TSkeletonSetup") endf function! templator#expander#tskel#Expand() "{{{3 call tskeleton#FillIn("", &filetype) endf templator/r.vim [[[1 13 " @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim]) " @License: GPL (see http://www.gnu.org/licenses/gpl.txt) " @Last Change: 2012-12-03. " @Revision: 12 function! g:templator#drivers.r.After(args) dict "{{{3 let filename = get(a:args, '1', 'main') .'.R' " TLogVAR filename exec 'buffer' filename endf templator/r.tskel/${1=main}.R [[[1 4 source("_init.R") <+CURSOR+> templator/r.tskel/_init.R [[[1 7 # project.dir <- normalizePath(dirname(parent.frame(2)$ofile)) project.dir <- normalizePath(dirname((function() {attr(body(sys.function()), "srcfile")})()$filename)) source(paste(project.dir, "lib/variables.R", sep = "/")) source(paste(project.dir, "lib/functions.R", sep = "/")) source(paste(project.dir, "lib/db.R", sep = "/")) templator/r.tskel/lib/functions.R [[[1 2 templator/r.tskel/lib/db.R [[[1 2 templator/r.tskel/lib/variables.R [[[1 2