Vim Tips Wiki
Advertisement
Tip 1635 Printable Monobook Previous Next

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)

Advertisement