Skip to content

Instantly share code, notes, and snippets.

@hail2u
Created January 5, 2012 17:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hail2u/1566304 to your computer and use it in GitHub Desktop.
Save hail2u/1566304 to your computer and use it in GitHub Desktop.
Vim script language handler for google code prettify
/**
* @preserve Copyright (C) 2012 Kyo Nagashima
*
* LICENSE: http://hail2u.mit-license.org/2012
*/
/**
* @fileoverview
* Registers a language handler for Vim script.
*
*
* To use, include prettify.js and this file in your HTML page.
* Then put your code in an HTML tag like
* <pre class="prettyprint lang-vim"></pre>
*
*
* @author kyo@haiil2u.net
*/
PR['registerLangHandler'](
PR['createSimpleLexer'](
[
// Whitespace
[PR['PR_PLAIN'], /^[\t\n\r \xA0\u2028\u2029]+/, null, '\t\n\r \xA0\u2028\u2029']
],
[
// Double quoted string
[PR['PR_STRING'], /^\"[^\"\r\n]*?\"/],
// Single quoted string
[PR['PR_STRING'], /^\'[^\'\r\n]*?\'/],
// Line comment
[PR['PR_COMMENT'], /^[\"\u2018\u2019][^\r\n\u2028\u2029]*/],
// Keywords
[PR['PR_KEYWORD'], /^(?:function|endfunction|delfunction|return|call|let|unlet|lockvar|unlockvar|if|endif|else|elseif|while|endwhile|for|in|endfor|continue|break|try|endtry|catch|finally|throw|echo|ehon|echohl|echomsg|echoerr|execute|set|autocmd|augroup|[nvxsoilc]?(?:nore)?map|command)\b/i],
// Literal number
[PR['PR_LITERAL'], /^(?:\d+)/i],
// Identifier
[PR['PR_PLAIN'], /^(?:(?:[a-z]|_\w)[\w\:]*)/i],
// Punctuation
[PR['PR_PUNCTUATION'], /^[^\s\w\'\"]+/]
]
),
['vim']
);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test page for lang-vim.js</title>
<link rel="stylesheet" href="http://hail2u.github.com/natural.css">
<link rel="stylesheet" href="http://google-code-prettify.googlecode.com/svn/trunk/styles/desert.css">
<script src="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js"></script>
<script src="lang-vim.js"></script>
</head>
<body onload="prettyPrint()">
<header>
<h1>Test page for lang-vim.js</h1>
</header>
<p>Download: <a href="https://gist.github.com/1566304">lang-vim.js</a></p>
<pre class="prettyprint lang-vim">" jptemplate.vim:
"
" A simple yet powerful interactive templating system for VIM.
"
" Version 1.5 (released 2008-07-08).
"
" Copyright (c) 2008 Jannis Pohlmann &lt;jannis@xfce.org&gt;.
"
" This program is free software; you can redistribute it and/or modify
" it under the terms of the GNU General Public License as published by
" the Free Software Foundation; either version 2 of the License, or (at
" your option) any later version.
"
" This program is distributed in the hope that it will be useful, but
" WITHOUT ANY WARRANTY; without even the implied warranty of
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
" General Public License for more details.
"
" You should have received a copy of the GNU General Public License
" along with this program; if not, write to the Free Software
" Foundation, Inc., 59 Temple Place, Suite 330, Boston,
" MA 02111-1307 USA
" Reserved variable names
let s:reservedVariables = ['date','shell','interactive_shell']
" Variable value history
let s:rememberedValues = {}
" Characters to be escaped before the substitute() call
let s:escapeCharacters = '&amp;~\'
function! jp:Initialize()
" List for default configuration
let defaults = []
" Default configuration values
call add(defaults, ['g:jpTemplateDir', $HOME . '/.vim/jptemplate'])
call add(defaults, ['g:jpTemplateKey', '&lt;C-Tab&gt;'])
call add(defaults, ['g:jpTemplateDateFormat', '%Y-%m-%d'])
call add(defaults, ['g:jpTemplateDefaults', {}])
call add(defaults, ['g:jpTemplateVerbose', 0])
" Set default configuration for non-existent variables
for var in filter(defaults, '!exists(v:val[0])')
exec 'let ' . var[0] . ' = ' . string(var[1])
endfor
endfunction
function! jp:GetTemplateInfo()
" Prepare info dictionary
let info = {}
" Get part of the line before the cursor
let part = getline('.')[0 : getpos('.')[2]-1]
" Get start and end position of the template name
let info['start'] = match(part, '\(\w*\)$')
let info['end'] = matchend(part, '\(\w*\)$')
" Get template name
let info['name'] = part[info['start'] : info['end']]
" Throw exception if no template name could be found
if empty(info['name'])
throw 'No template name found at cursor'
endif
" Determine directory to load the template from (skip empty directories;
" each directory may override the ones before)
for dir in filter([ 'general', &amp;ft ], '!empty(v:val)')
let filename = g:jpTemplateDir .'/'. dir .'/'. info['name']
if filereadable(filename)
let info['filename'] = filename
endif
endfor
" Throw exception if the template file does not exist in any of these
" directories (or is not readable)
if !has_key(info, 'filename')
throw 'Template file not found'
endif
" Determine indentation
let info['indent'] = matchstr(part, '^\s\+')
" Return template name information
return info
endfunction
function! jp:ReadTemplate(name, filename)
" Try to read the template file and throw exception if that fails
try
return readfile(a:filename)
catch
throw 'Template "' . a:name . '" could not be found.'
endtry
endfunction
function! jp:UpdateCursorPosition(lines, endColumn)
" Define cursorPosition as the column to which the cursor is moved
let cursorPosition = -1
for cnt in range(0, a:lines)
" Search for ${cursor} in the current line
let str = getline(line('.') + cnt)
let start = match(str, '${cursor}')
let end = matchend(str, '${cursor}')
let before = strpart(str, 0, start)
let after = strpart(str, end)
if start &gt;= 0
" Remove ${cursor} and move the cursor to the desired position
call setline(line('.') + cnt, before . after)
call cursor(line('.') + cnt, start+1)
let cursorPosition = start
" We're done
break
endif
endfor
" Update cursor position in case no ${cursor} was found in the template
" and the resulting template was not empty
if cursorPosition == -1 &amp;&amp; a:lines &gt;= 0
if a:lines == 0
call cursor(line('.'), a:endColumn + 1)
else
call cursor(line('.') + a:lines, a:endColumn + 1)
endif
endif
" Return to insert mode (distinguish between 'in the middle of the line' and
" 'at the end of the line')
if col('.') == len(getline('.'))
startinsert!
else
startinsert
endif
endfunction
function! jp:ParseExpression(expr)
" Determine position of the separator between name and value
let valuepos = match(a:expr, ':')
" Extract name and value strings
let name = valuepos &gt;= 0 ? strpart(a:expr, 0, valuepos) : a:expr
let value = valuepos &gt;= 0 ? strpart(a:expr, valuepos + 1) : ''
" Return list with both strings
return [name, value]
endfunction
function! jp:EvaluateReservedVariable(name, value, variables)
let result = ''
if a:name == 'date'
let result = strftime(empty(a:value) ? g:jpTemplateDateFormat : a:value)
elseif a:name == 'shell'
if !empty(a:value)
let result = system(a:value)
endif
elseif a:name == 'interactive_shell'
let command = input('interactive_shell: ', a:value)
if !empty(command)
let result = system(command)
endif
endif
return result
endfunction
function! jp:ExpandTemplate(info, template)
" Backup content before and after the template name
let before = strpart(getline('.'), 0, a:info['start'])
let after = strpart(getline('.'), a:info['end'])
" Merge lines of the template and then split them up again.
" This makes multi-line variable values possible
let mergedTemplate = split(join(a:template, "\n"), "\n")
" Define cnt as the number of inserted lines
let cnt = 0
" Remove template string if the resulting template is empty
if empty(mergedTemplate)
call setline(line('.'), before . after)
call cursor(line('.'), len(before) + 1)
let cnt = -1
else
" Insert template between before and after
for cnt in range(0, len(mergedTemplate) - 1)
if cnt == 0
call setline(line('.'), before . mergedTemplate[cnt])
else
call append(line('.') + cnt - 1, a:info['indent'] . mergedTemplate[cnt])
endif
if cnt == len(mergedTemplate) - 1
call setline(line('.') + cnt, getline(line('.') + cnt) . after)
endif
endfor
endif
" Define start and end columns of the template
let startColumn = len(before)
if empty(mergedTemplate)
let endColumn = startColumn
else
if cnt == 0
let endColumn = startColumn + len(mergedTemplate[0])
else
let endColumn = len(a:info['indent'] . mergedTemplate[len(mergedTemplate) - 1])
endif
endif
" Return number of inserted lines, start and end columns
return [cnt, startColumn, endColumn]
endfunction
function! jp:ProcessTemplate(info, template)
let matchpos = 0
let expressions = []
let variables = {}
let reserved = {}
" Make a string out of the template lines
let s:str = join(a:template, ' ')
" Detect all variable names of the template
while 1
" Find next variable start and end position
let start = match(s:str, '${[^{}]\+}', matchpos)
let end = matchend(s:str, '${[^{}]\+}', matchpos)
if start &lt; 0
" Stop search if there is no variable left
break
else
" Extract variable expression (remove '${' and '}')
let expr = s:str[start+2 : end-2]
" Extract variable name and default value */
let [name, value] = jp:ParseExpression(expr)
if name == 'cursor'
" Skip the ${cursor} variable
elseif count(s:reservedVariables, name) &gt; 0
let reserved[expr] = ''
else
" Only insert variables on their first appearance
if !has_key(variables, name)
" Add expression to the expression list
call add(expressions, expr)
" Set variable value to ''
let variables[name] = ''
endif
" Check whether local default value is defined or not
if empty(value)
" If not, check if variable value is empty
if empty(variables[name])
" If so, either set it to the last remembered value or the global
" default if it exists
if has_key(s:rememberedValues, name)
let variables[name] = s:rememberedValues[name]
elseif has_key(g:jpTemplateDefaults, name)
let variables[name] = g:jpTemplateDefaults[name]
endif
endif
else
" Use local default(first occurence in the template only)
let variables[name] = value
endif
endif
" Start next search at the end position of this expression
let matchpos = end
endif
endwhile
" Ask the user to enter values for all variables
for expr in expressions
let [name, value] = jp:ParseExpression(expr)
let variables[name] = input(name . ': ', variables[name])
let s:rememberedValues[name] = variables[name]
endfor
" Evaluate reserved variables
for expr in keys(reserved)
let [name, value] = jp:ParseExpression(expr)
let replacement = jp:EvaluateReservedVariable(name, value, variables)
let reserved[expr] = replacement
endfor
" Expand all variables (custom and reserved)
for index in range(len(a:template))
for expr in expressions
let [name, value] = jp:ParseExpression(expr)
let expr = '${' . name . '\(:[^{}]\+\)\?}'
let value = escape(variables[name], s:escapeCharacters)
let a:template[index] = substitute(a:template[index], expr, value, 'g')
endfor
for [expr, value] in items(reserved)
let expr = '${' . expr . '}'
let value = escape(value, s:escapeCharacters)
let a:template[index] = substitute(a:template[index], expr, value, 'g')
endfor
endfor
" Insert template into the code line by line
let [insertedLines, startColumn, endColumn] = jp:ExpandTemplate(a:info, a:template)
" Update the cursor position and return to insert mode
call jp:UpdateCursorPosition(insertedLines, endColumn)
endfunction
function! jp:InsertTemplate()
try
" Detect bounds of the template name as well as the name itself
let info = jp:GetTemplateInfo()
" Load the template file
let template = jp:ReadTemplate(info['name'], info['filename'])
" Do the hard work: Process the template
call jp:ProcessTemplate(info, template)
catch
" Inform the user about errors
echo g:jpTemplateVerbose ? v:exception . " (in " . v:throwpoint . ")" : v:exception
endtry
endfunction
" Initialize jptemplate configuration
call jp:Initialize()
" Map keyboard shortcut to the template system
exec 'imap ' . g:jpTemplateKey . ' &lt;Esc&gt;:call jp:InsertTemplate()&lt;CR&gt;'
</pre>
<p>This test Vim script code is <a href="https://github.com/Jannis/jptemplate">jptemplate</a>.</p>
</body>
</html>
@dciccale
Copy link

dciccale commented Oct 7, 2013

cool thx!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment