428 lines
13 KiB
VimL
Executable file
428 lines
13 KiB
VimL
Executable file
" Vim indent file
|
|
" Language: Mako
|
|
" Author: Scott Torborg <storborg@mit.edu>
|
|
" Version: 0.4
|
|
" License: Do What The Fuck You Want To Public License (WTFPL)
|
|
"
|
|
" ---------------------------------------------------------------------------
|
|
"
|
|
" DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
" Version 2, December 2004
|
|
"
|
|
" Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
|
"
|
|
" Everyone is permitted to copy and distribute verbatim or modified
|
|
" copies of this license document, and changing it is allowed as long
|
|
" as the name is changed.
|
|
"
|
|
" DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
" TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
"
|
|
" 0. You just DO WHAT THE FUCK YOU WANT TO.
|
|
"
|
|
" ---------------------------------------------------------------------------
|
|
"
|
|
" This script does more useful indenting for Mako HTML templates. It indents
|
|
" inside of control blocks, defs, etc. Note that this indenting style will
|
|
" sacrifice readability of the output text for the sake of readability of the
|
|
" template.
|
|
"
|
|
" We'll use HTML indenting globally, python inside <% %> blocks. Inspired by
|
|
" the excellent PHP + HTML indentation files such as php.vim by Pim Snel.
|
|
"
|
|
" Changelog:
|
|
" 0.4 - 5 March 2010
|
|
" - Added license information
|
|
" 0.3 - 15 September 2009
|
|
" - Added explicit indenting for ## comments, fixed unindenting count,
|
|
" thanks to Mike Lewis (@MikeRLewis) for this
|
|
" 0.2 - 15 June 2009
|
|
" - Fixed issue where opening and closing mako tags on the same line
|
|
" would cause incorrect indenting
|
|
" 0.1 - 06 June 2009
|
|
" - Initial public release of mako indent file
|
|
|
|
if exists("b:did_indent")
|
|
finish
|
|
endif
|
|
let b:did_indent = 1
|
|
|
|
setlocal nosmartindent
|
|
setlocal noautoindent
|
|
setlocal nocindent
|
|
setlocal nolisp
|
|
setlocal expandtab
|
|
setlocal softtabstop=2
|
|
setlocal shiftwidth=2
|
|
|
|
setlocal indentexpr=GetMakoIndent()
|
|
setlocal indentkeys+=*<Return>,<>>,<bs>,end,:
|
|
|
|
" Only define the function once.
|
|
if exists("*GetMakoIndent")
|
|
finish
|
|
endif
|
|
|
|
if exists('g:html_indent_tags')
|
|
unlet g:html_indent_tags
|
|
endif
|
|
|
|
function IsInsidePythonBlock(startline)
|
|
" Loop until we get a line that's either <% or %>
|
|
let lnum = a:startline
|
|
while getline(lnum) !~ '\(%>\|<%\)$' && lnum > 0
|
|
let lnum = lnum - 1
|
|
endwhile
|
|
|
|
" lnum points to the last control. If it's a <% then we're inside an
|
|
" embedded python block, otherwise we're not.
|
|
return getline(lnum) =~ '<%$'
|
|
endfunction
|
|
|
|
function GetMakoIndent()
|
|
" Find a non-empty line above the current line
|
|
let lnum = prevnonblank(v:lnum - 1)
|
|
|
|
" Hit the start of the file, use zero indent.
|
|
if lnum == 0
|
|
return 0
|
|
endif
|
|
|
|
let line = getline(lnum) " last line
|
|
let cline = getline(v:lnum) " current line
|
|
let pline = getline(lnum - 1) " previous to last line
|
|
let ind = indent(lnum)
|
|
if line =~ '^\s*##'
|
|
return indent(lnum)
|
|
end
|
|
|
|
let restore_ic=&ic
|
|
let &ic=1 " ignore case
|
|
|
|
let ind = <SID>HtmlIndentSum(lnum, -1)
|
|
let ind = <SID>HtmlIndentSum(lnum, -1)
|
|
let ind = ind + <SID>HtmlIndentSum(v:lnum, 0)
|
|
|
|
let &ic=restore_ic
|
|
|
|
let ind = indent(lnum) + (&sw * ind)
|
|
|
|
" Indent after %anything: or <%anything NOT ending in />
|
|
if line =~ '^\s*%.*:\s*$'
|
|
let ind = ind + &sw
|
|
endif
|
|
|
|
" Unindent before %end* or </%anything
|
|
if cline =~ '^\s*%\s*end'
|
|
let ind = ind - &sw
|
|
endif
|
|
"
|
|
" Unindent before %else, %except, and %elif
|
|
if cline =~ '^\s*%\s*else' || cline =~ '^\s*%\s*except' || cline =~ '^\s*%\s*elif'
|
|
let ind = ind - &sw
|
|
endif
|
|
|
|
" Indent at the beginning of a python control block
|
|
if line =~ '<%$'
|
|
let ind = ind + &sw
|
|
endif
|
|
"
|
|
" Unindent at the end of the python block.
|
|
if cline =~ '^\s*%>$'
|
|
let scanlnum = lnum
|
|
" Scan backwards until we find the beginning of this python block.
|
|
while getline(scanlnum) !~ '<%$' && scanlnum > 0
|
|
let scanlnum = scanlnum - 1
|
|
endwhile
|
|
let ind = indent(scanlnum)
|
|
endif
|
|
|
|
" If we're inside a python block and the previous line ends in a colon,
|
|
" indent.
|
|
if IsInsidePythonBlock(lnum - 1)
|
|
" Indent after :
|
|
if line =~ '\:$'
|
|
let ind = ind + &sw
|
|
endif
|
|
endif
|
|
|
|
return ind
|
|
endfunction
|
|
|
|
|
|
" [-- helper function to assemble tag list --]
|
|
fun! <SID>HtmlIndentPush(tag)
|
|
if exists('g:html_indent_tags')
|
|
let g:html_indent_tags = g:html_indent_tags.'\|'.a:tag
|
|
else
|
|
let g:html_indent_tags = a:tag
|
|
endif
|
|
endfun
|
|
|
|
fun! <SID>MakoIndentPush(tag)
|
|
if exists('g:mako_indent_tags')
|
|
let g:mako_indent_tags = g:mako_indent_tags.'\|'.a:tag
|
|
else
|
|
let g:mako_indent_tags = a:tag
|
|
endif
|
|
endfun
|
|
|
|
" [-- <ELEMENT ? - - ...> --]
|
|
call <SID>HtmlIndentPush('a')
|
|
call <SID>HtmlIndentPush('abbr')
|
|
call <SID>HtmlIndentPush('address')
|
|
call <SID>HtmlIndentPush('applet')
|
|
call <SID>HtmlIndentPush('article')
|
|
call <SID>HtmlIndentPush('aside')
|
|
call <SID>HtmlIndentPush('audio')
|
|
call <SID>HtmlIndentPush('b')
|
|
call <SID>HtmlIndentPush('bdi')
|
|
call <SID>HtmlIndentPush('bdo')
|
|
call <SID>HtmlIndentPush('blockquote')
|
|
call <SID>HtmlIndentPush('button')
|
|
call <SID>HtmlIndentPush('canvas')
|
|
call <SID>HtmlIndentPush('caption')
|
|
call <SID>HtmlIndentPush('cite')
|
|
call <SID>HtmlIndentPush('code')
|
|
call <SID>HtmlIndentPush('colgroup')
|
|
call <SID>HtmlIndentPush('content')
|
|
call <SID>HtmlIndentPush('data')
|
|
call <SID>HtmlIndentPush('datalist')
|
|
call <SID>HtmlIndentPush('del')
|
|
call <SID>HtmlIndentPush('details')
|
|
call <SID>HtmlIndentPush('dfn')
|
|
call <SID>HtmlIndentPush('dialog')
|
|
call <SID>HtmlIndentPush('dir')
|
|
call <SID>HtmlIndentPush('div')
|
|
call <SID>HtmlIndentPush('dl')
|
|
call <SID>HtmlIndentPush('element')
|
|
call <SID>HtmlIndentPush('em')
|
|
call <SID>HtmlIndentPush('fieldset')
|
|
call <SID>HtmlIndentPush('figcaption')
|
|
call <SID>HtmlIndentPush('figure')
|
|
call <SID>HtmlIndentPush('footer')
|
|
call <SID>HtmlIndentPush('form')
|
|
call <SID>HtmlIndentPush('h1')
|
|
call <SID>HtmlIndentPush('h2')
|
|
call <SID>HtmlIndentPush('h3')
|
|
call <SID>HtmlIndentPush('h4')
|
|
call <SID>HtmlIndentPush('h5')
|
|
call <SID>HtmlIndentPush('h6')
|
|
call <SID>HtmlIndentPush('header')
|
|
call <SID>HtmlIndentPush('hgroup')
|
|
call <SID>HtmlIndentPush('i')
|
|
call <SID>HtmlIndentPush('iframe')
|
|
call <SID>HtmlIndentPush('ins')
|
|
call <SID>HtmlIndentPush('kbd')
|
|
call <SID>HtmlIndentPush('label')
|
|
call <SID>HtmlIndentPush('legend')
|
|
call <SID>HtmlIndentPush('li')
|
|
call <SID>HtmlIndentPush('main')
|
|
call <SID>HtmlIndentPush('map')
|
|
call <SID>HtmlIndentPush('mark')
|
|
call <SID>HtmlIndentPush('MediaStream')
|
|
call <SID>HtmlIndentPush('menu')
|
|
call <SID>HtmlIndentPush('menuitem')
|
|
call <SID>HtmlIndentPush('meter')
|
|
call <SID>HtmlIndentPush('nav')
|
|
call <SID>HtmlIndentPush('noembed')
|
|
call <SID>HtmlIndentPush('noscript')
|
|
call <SID>HtmlIndentPush('object')
|
|
call <SID>HtmlIndentPush('ol')
|
|
call <SID>HtmlIndentPush('optgroup')
|
|
call <SID>HtmlIndentPush('option')
|
|
call <SID>HtmlIndentPush('output')
|
|
call <SID>HtmlIndentPush('picture')
|
|
call <SID>HtmlIndentPush('pre')
|
|
call <SID>HtmlIndentPush('progress')
|
|
call <SID>HtmlIndentPush('q')
|
|
call <SID>HtmlIndentPush('rb')
|
|
call <SID>HtmlIndentPush('rp')
|
|
call <SID>HtmlIndentPush('rt')
|
|
call <SID>HtmlIndentPush('rtc')
|
|
call <SID>HtmlIndentPush('ruby')
|
|
call <SID>HtmlIndentPush('s')
|
|
call <SID>HtmlIndentPush('samp')
|
|
call <SID>HtmlIndentPush('script')
|
|
call <SID>HtmlIndentPush('section')
|
|
call <SID>HtmlIndentPush('select')
|
|
call <SID>HtmlIndentPush('shadow')
|
|
call <SID>HtmlIndentPush('slot')
|
|
call <SID>HtmlIndentPush('small')
|
|
call <SID>HtmlIndentPush('span')
|
|
call <SID>HtmlIndentPush('strong')
|
|
call <SID>HtmlIndentPush('style')
|
|
call <SID>HtmlIndentPush('sub')
|
|
call <SID>HtmlIndentPush('summary')
|
|
call <SID>HtmlIndentPush('sup')
|
|
call <SID>HtmlIndentPush('table')
|
|
call <SID>HtmlIndentPush('template')
|
|
call <SID>HtmlIndentPush('textarea')
|
|
call <SID>HtmlIndentPush('time')
|
|
call <SID>HtmlIndentPush('title')
|
|
call <SID>HtmlIndentPush('tt')
|
|
call <SID>HtmlIndentPush('u')
|
|
call <SID>HtmlIndentPush('ul')
|
|
call <SID>HtmlIndentPush('var')
|
|
call <SID>HtmlIndentPush('video')
|
|
|
|
" For some reason the default HTML indentation script doesn't consider these
|
|
" elements to be worthy of indentation.
|
|
call <SID>HtmlIndentPush('p')
|
|
call <SID>HtmlIndentPush('dt')
|
|
call <SID>HtmlIndentPush('dd')
|
|
|
|
|
|
" [-- <ELEMENT ? O O ...> --]
|
|
if !exists('g:html_indent_strict')
|
|
call <SID>HtmlIndentPush('body')
|
|
call <SID>HtmlIndentPush('head')
|
|
call <SID>HtmlIndentPush('html')
|
|
call <SID>HtmlIndentPush('tbody')
|
|
endif
|
|
|
|
|
|
" [-- <ELEMENT ? O - ...> --]
|
|
if !exists('g:html_indent_strict_table')
|
|
call <SID>HtmlIndentPush('th')
|
|
call <SID>HtmlIndentPush('td')
|
|
call <SID>HtmlIndentPush('tr')
|
|
call <SID>HtmlIndentPush('tfoot')
|
|
call <SID>HtmlIndentPush('thead')
|
|
endif
|
|
|
|
" [-- <OBSOLETE ELEMENTS ? - - ...> --]
|
|
call <SID>HtmlIndentPush('abbr')
|
|
call <SID>HtmlIndentPush('acronym')
|
|
call <SID>HtmlIndentPush('applet')
|
|
call <SID>HtmlIndentPush('audio')
|
|
call <SID>HtmlIndentPush('basefont')
|
|
call <SID>HtmlIndentPush('bgsound')
|
|
call <SID>HtmlIndentPush('big')
|
|
call <SID>HtmlIndentPush('blink')
|
|
call <SID>HtmlIndentPush('center')
|
|
call <SID>HtmlIndentPush('command')
|
|
call <SID>HtmlIndentPush('content')
|
|
call <SID>HtmlIndentPush('dir')
|
|
call <SID>HtmlIndentPush('element')
|
|
call <SID>HtmlIndentPush('embed')
|
|
call <SID>HtmlIndentPush('font')
|
|
call <SID>HtmlIndentPush('frame')
|
|
call <SID>HtmlIndentPush('frameset')
|
|
call <SID>HtmlIndentPush('image')
|
|
call <SID>HtmlIndentPush('img')
|
|
call <SID>HtmlIndentPush('isindex')
|
|
call <SID>HtmlIndentPush('keygen')
|
|
call <SID>HtmlIndentPush('listing')
|
|
call <SID>HtmlIndentPush('marquee')
|
|
call <SID>HtmlIndentPush('menuitem')
|
|
call <SID>HtmlIndentPush('multicol')
|
|
call <SID>HtmlIndentPush('nextid')
|
|
call <SID>HtmlIndentPush('nobr')
|
|
call <SID>HtmlIndentPush('noembed')
|
|
call <SID>HtmlIndentPush('noframes')
|
|
call <SID>HtmlIndentPush('object')
|
|
call <SID>HtmlIndentPush('plaintext')
|
|
call <SID>HtmlIndentPush('shadow')
|
|
call <SID>HtmlIndentPush('spacer')
|
|
call <SID>HtmlIndentPush('strike')
|
|
call <SID>HtmlIndentPush('tt')
|
|
call <SID>HtmlIndentPush('xmp')
|
|
|
|
" [-- <Mako Elements> --]
|
|
call <SID>MakoIndentPush('%def')
|
|
call <SID>MakoIndentPush('%block')
|
|
call <SID>MakoIndentPush('%call')
|
|
call <SID>MakoIndentPush('%doc')
|
|
call <SID>MakoIndentPush('%text')
|
|
call <SID>MakoIndentPush('%.\+:.\+')
|
|
|
|
delfun <SID>HtmlIndentPush
|
|
delfun <SID>MakoIndentPush
|
|
|
|
set cpo-=C
|
|
|
|
" [-- get number of regex matches in a string --]
|
|
fun! <SID>MatchCount(expr, pat)
|
|
let mpos = 0
|
|
let mcount = 0
|
|
let expr = a:expr
|
|
while (mpos > -1)
|
|
let mend = matchend(expr, a:pat)
|
|
if mend > -1
|
|
let mcount = mcount + 1
|
|
endif
|
|
if mend == mpos
|
|
let mpos = mpos + 1
|
|
else
|
|
let mpos = mend
|
|
endif
|
|
let expr = strpart(expr, mpos)
|
|
endwhile
|
|
return mcount
|
|
endfun
|
|
|
|
" [-- count indent-increasing tags of line a:lnum --]
|
|
fun! <SID>HtmlIndentOpen(lnum)
|
|
let s = substitute('x'.getline(a:lnum),
|
|
\ '.\{-}\(\(<\)\('.g:html_indent_tags.'\)\>\)', "\1", 'g')
|
|
let s = substitute(s, "[^\1].*$", '', '')
|
|
return strlen(s)
|
|
endfun
|
|
|
|
" [-- count indent-decreasing tags of line a:lnum --]
|
|
fun! <SID>HtmlIndentClose(lnum)
|
|
let s = substitute('x'.getline(a:lnum),
|
|
\ '.\{-}\(\(<\)/\('.g:html_indent_tags.'\)\>>\)', "\1", 'g')
|
|
let s = substitute(s, "[^\1].*$", '', '')
|
|
return strlen(s)
|
|
endfun
|
|
|
|
" [-- count indent-increasing mako tags of line a:lnum --]
|
|
fun! <SID>MakoIndentOpen(lnum)
|
|
let s = substitute('x'.getline(a:lnum),
|
|
\ '.\{-}\(\(<\)\('.g:mako_indent_tags.'\)\>\)', "\1", 'g')
|
|
let s = substitute(s, "[^\1].*$", '', '')
|
|
return strlen(s)
|
|
endfun
|
|
|
|
" [-- count indent-decreasing mako tags of line a:lnum --]
|
|
fun! <SID>MakoIndentClose(lnum)
|
|
let mcount = <SID>MatchCount(getline(a:lnum), '</\('.g:mako_indent_tags.'\)>')
|
|
let mcount = mcount + <SID>MatchCount(getline(a:lnum), '<\('.g:mako_indent_tags.'\)[^>]*/>')
|
|
return mcount
|
|
endfun
|
|
|
|
" [-- count indent-increasing '{' of (java|css) line a:lnum --]
|
|
fun! <SID>HtmlIndentOpenAlt(lnum)
|
|
return strlen(substitute(getline(a:lnum), '[^{]\+', '', 'g'))
|
|
endfun
|
|
|
|
" [-- count indent-decreasing '}' of (java|css) line a:lnum --]
|
|
fun! <SID>HtmlIndentCloseAlt(lnum)
|
|
return strlen(substitute(getline(a:lnum), '[^}]\+', '', 'g'))
|
|
endfun
|
|
|
|
" [-- return the sum of indents respecting the syntax of a:lnum --]
|
|
fun! <SID>HtmlIndentSum(lnum, style)
|
|
let open = <SID>HtmlIndentOpen(a:lnum) + <SID>MakoIndentOpen(a:lnum)
|
|
let close = <SID>HtmlIndentClose(a:lnum) + <SID>MakoIndentClose(a:lnum)
|
|
if a:style == match(getline(a:lnum), '^\s*</')
|
|
if a:style == match(getline(a:lnum), '^\s*</\('.g:html_indent_tags.'\|'.g:mako_indent_tags.'\)')
|
|
if 0 != open || 0 != close
|
|
return open - close
|
|
endif
|
|
endif
|
|
endif
|
|
if '' != &syntax &&
|
|
\ synIDattr(synID(a:lnum, 1, 1), 'name') =~ '\(css\|java\).*' &&
|
|
\ synIDattr(synID(a:lnum, strlen(getline(a:lnum)) - 1, 1), 'name')
|
|
\ =~ '\(css\|java\).*'
|
|
if a:style == match(getline(a:lnum), '^\s*}')
|
|
return <SID>HtmlIndentOpenAlt(a:lnum) - <SID>HtmlIndentCloseAlt(a:lnum)
|
|
endif
|
|
endif
|
|
return 0
|
|
endfun
|
|
|
|
" vim: set ts=4 sw=4:
|