created October 5, 2009 · complexity basic · author Black panda · version 7.0
Here is the beginning of a script that helps indenting JavaFX source files. JavaFX is a new GUI-based scripting language developed by Sun Microsystems to compete with Adobe Flash and Microsoft Silverlight.
Please help to improve the code so that it can be included as a plugin at Vim scripts.
set debug=msg,throw
if exists("b:did_indent")
finish
endif
let b:did_indent = 1
setlocal indentkeys=0{,0},0],!^F,o,O,e
"if exists("*GetFxIndent")
" finish
"endif
" removes JavaFX quoted strings from a line
function! s:removeQuotedStrings(orig_line)
"todo needs to be more robust
"right now it barely handles double and single quotes, but
"there could be code interpolation.
" see http://java.sun.com/javafx/1/tutorials/core/dataTypes/#string
let quote1 = matchstr(a:orig_line, "['\"]")
if empty(quote1)
return a:orig_line
endif
let escaped_quote = '\\' . quote1
" replace escaped quotes, for example '\\"'
let line = substitute(a:orig_line, escaped_quote, '__', "g")
" call confirm('-->' . line)
" match the quoted token, for example: /'[^']\+'/
let quote_pattern = quote1 . '[^' . quote1 . ']\+' . quote1
" call confirm(quote_pattern)
return substitute(line, quote_pattern, '""', "g")
endfunction
function! s:SkipJavaFxBlanksAndComments(startline)
let lnum = a:startline
while lnum > 1
let lnum = prevnonblank(lnum)
if getline(lnum) =~ '\*/\s*$'
while getline(lnum) !~ '/\*' && lnum > 1
let lnum = lnum - 1
endwhile
if getline(lnum) =~ '^\s*/\*'
let lnum = lnum - 1
else
break
endif
elseif getline(lnum) =~ '^\s*//'
let lnum = lnum - 1
else
break
endif
endwhile
return lnum
endfunction
" meant to matche the property syntax x : y
let s:property_regex = '^\s*\(\%(\i\|\s\)\+\):\(.*\)$'
function! GetFxIndent()
if v:lnum == 1
return indent(v:lnum)
endif
let theCIndent = cindent(v:lnum)
" If we're in the middle of a comment or at the end of a java-like
" statement or block, use cindent
if getline(v:lnum) =~ '^\s*[\*/;]'
return theCIndent
endif
" find start of previous line, in case it was a continuation line
let lnum = s:SkipJavaFxBlanksAndComments(v:lnum - 1)
let prev_lnum = lnum
while prev_lnum > 1
let earlier_prev = s:SkipJavaFxBlanksAndComments(prev_lnum - 1)
if getline(earlier_prev) !~ '\%(\i\|\s\),\s*$'
break
endif
let prev_lnum = earlier_prev
endwhile
" call confirm('current indent is: ' . indent(v:lnum) .
" \ "\ncindent wants it to be: " . theCIndent .
" \ "\nprevious line num: " . prev_lnum)
" let's get rid of the contents of the strings in the line.
let current_line = s:removeQuotedStrings(getline(v:lnum))
let prev_line = s:removeQuotedStrings(getline(prev_lnum))
" call confirm('prev_line is: ' . prev_line)
if current_line =~ '^\s*\]'
return indent(prev_lnum) - &sw
endif
" take care of property-type format x: y
let captures = matchlist(prev_line, s:property_regex)
if ! empty(captures)
" call confirm(string(captures))
if captures[1] =~ '{' || captures[2] =~ '{'
" call confirm("if1")
if captures[2] =~ '}'
" call confirm("if2")
" this may be a complete block enclosure on one line
return indent(prev_lnum)
else
" call confirm("if3")
" a block is starting in the property.
return indent(prev_lnum) + &sw
endif
" call confirm("if4")
elseif captures[0] =~ '^\s*\<\%(var\|def\)\>'
" call confirm("if5")
" what we thought was a property-type format was really a
" declaration of a variable.
return theCIndent
elseif current_line =~ '^\s*}'
" call confirm("if6")
" the end of the property block
return indent(prev_lnum) - &sw
elseif captures[0] =~ '['
" call confirm("if7")
" the end of the property block
return indent(prev_lnum) + &sw
else
" call confirm("if8")
return indent(prev_lnum)
endif
" end of property-type format x: y check on prev_line
" call confirm("if9")
elseif current_line =~ '^\s*}'
" call confirm("if9a")
return indent(prev_lnum) -&sw
elseif prev_line =~ '{'
" call confirm("if10")
" maybe it's a completely enclosed block.
" if so, we can keep the previus indent
if prev_line =~ '{[^}]\+}'
" call confirm("if11")
return indent(prev_lnum)
else
return indent(prev_lnum) + &sw
endif
elseif prev_line =~ '^\s*}'
" call confirm("if12")
if current_line =~ '^\s*}'
" call confirm("if13")
"return indent(prev_lnum) -&sw
"return theCIndent
else
" call confirm("if14")
return indent(prev_lnum)
endif
elseif match(current_line, s:property_regex) > -1
" call confirm("if15")
return indent(prev_lnum)
endif
" call confirm('normal flow')
return theCIndent
endfunction
" Set the function to do the work.
setlocal indentexpr=GetFxIndent()
Comments[]
This tip arose from a discussion on the vim_dev mailing list. The aim of posting the script here is to seek feedback to improve the code. Black panda may decide to upload the plugin to vim.org/scripts, and in three months or so, we can evaluate whether to keep this script here.
Please make any fixes to the code, or add comments on the talk page. JohnBeckett 04:24, October 8, 2009 (UTC)