Created
January 5, 2012 17:41
-
-
Save hail2u/1566304 to your computer and use it in GitHub Desktop.
Vim script language handler for google code prettify
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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'] | |
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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 <jannis@xfce.org>. | |
" | |
" 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 = '&~\' | |
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', '<C-Tab>']) | |
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', &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 >= 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 && a:lines >= 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 >= 0 ? strpart(a:expr, 0, valuepos) : a:expr | |
let value = valuepos >= 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 < 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) > 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 . ' <Esc>:call jp:InsertTemplate()<CR>' | |
</pre> | |
<p>This test Vim script code is <a href="https://github.com/Jannis/jptemplate">jptemplate</a>.</p> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
cool thx!