Gregory Seidman wrote:
I'm finding that smartindent is routinely wrong about how I want things to
be indented in JS, but I haven't been able to find an indent script. I'd be
interested in working on it myself, but I don't know the first thing about
how the function referred to when setting indentexpr is expected to behave.

Is anyone already working on an indentation file for JavaScript? If so, I'd
be interested in helping. If not, would anyone be interested in
collaborating on it?

--Greg
Hi,

I have a pretty working JS indentation script - javascript.vim, but it handles only most common cases. It uses the build in C indentation rules and does a bit of correction. Really much more corrections is required in order to indent JavaScript correctly for all the cases. Maybe C indent is a bad starting point for a complete JavaScript indentation solution. I've also tried using syntax in order to calculate indentation but this attempt lead me to even worth results - javascript.vim.bad. Maybe you can fix the syntax based version, as it is more promising. IIRC some changes were required in the syntax script in order to get better indentation results...

Currently I'm not programming in JavaScript, so I doubt I can devote much time to fixing its indentation script. But probably I will be, so I am interested in having a complete JavaScript indentation solution in Vim.
" Description:  ECMAScript indenter
" Author:       After Johannes Zellner <[EMAIL PROTECTED]>
" URL:          http://www.zellner.org/vim/indent/html.vim
" Last Change:  Fri, 7 May 2004 20:00:00 +0200
" Globals:

" Only load this indent file when no other was loaded.
if exists("b:did_indent")
        finish
endif
let b:did_indent = 1


" [-- local settings (must come before aborting the script) --]
setlocal indentexpr=ECMAScriptIndentGet(v:lnum)
setlocal indentkeys=o,O,*<Return>,<BS>,{,}


set cpo-=C

fun! <SID>GetSyntax(lnum)
        let s1Comment = 0
        let s2Comment = 0
        if &syntax == ''
                return ''
        endif
        let s1 = synIDattr(synID(a:lnum, matchend(getline(a:lnum), '^\s*') + 1, 
1), 'name')
        if s1 == ''
                let s1 = 'java'
        endif
        if s1 =~? 'comment'
                let s1Comment = 1
        endif
        let s1 = matchstr(s1, '^\(java\)')
        if strlen(getline(a:lnum)) <= 1
                let s2 = s1
                let s2Comment = s1Comment
        else
                let s2 = synIDattr(synID(a:lnum, match(getline(a:lnum), '\s*$') 
- 1, 1), 'name')
                if s2 == ''
                        let s2 = 'java'
                endif
                if s2 =~? 'comment'
                        let s2Comment = 1
                endif
                let s2 = matchstr(s2, '^\(java\)')
        endif

        if s1Comment && s2Comment
                return 'comment'
        endif
        if s1 == 'java' && s2 == 'java'
                return 'java'
        endif
        if s1 == s2
                return s1
        endif
        return ''
endfun

fun! ECMAScriptIndentGet(lnum)
        " Syntax of current line
        let curSyntax = <SID>GetSyntax(a:lnum)

        let restore_ic=&ic
        let &ic=1 " ignore case

        let ind = 0 " Indent in sw multipliers. Added to indent of previous 
line.
        let presizeIndent = -1 " Indent in spaces. int is ignores if 
presizeIndent != -1.
        
        " Script source is indented seperatly from commments.
        if curSyntax == 'java'

                " Find a non-empty line above the current line.
                let plnum = prevnonblank(a:lnum - 1)
                let prevSyntax = <SID>GetSyntax(plnum)
                " Skip comments.
                " BUG: will not work when comments is mixed with other text in 
the same line.
                while plnum > 0 && (prevSyntax == 'comment' || prevSyntax == '')
                        let plnum = prevnonblank(plnum - 1)
                        let prevSyntax = <SID>GetSyntax(plnum)
                endwhile

                " Hit the start of the file, use zero indent.
                if plnum == 0
                        presizeIndent = 0
                else

                        " Add 1 sw indent for each non closed { or (.
                        let ind = strlen(substitute(getline(plnum), '[^{(]\+', 
'', 'g')) -
                                                \ 
strlen(substitute(getline(plnum), '[^})]\+', '', 'g'))

                        " let restPos = matchend(getline(plnum), '^\s*}')
                        " if restPos == -1
                        "       let ind = strlen(substitute(getline(plnum), 
'[^{]\+', '', 'g')) -
                        "                               \ 
strlen(substitute(getline(plnum), '[^}]\+', '', 'g'))
                        " else
                        "       let rest = strpart(getline(plnum), restPos)
                        "       let ind = strlen(substitute(rest, '[^{]\+', '', 
'g')) -
                        "                               \ 
strlen(substitute(rest, '[^}]\+', '', 'g'))
                        " endif

                        " if match(getline(a:lnum), '^\s*}') == 0
                        "       let ind = ind - 
strlen(substitute(substitute(getline(a:lnum), '^\s*\([}\s]\+\)', '\1', ''),
                        "                               \ '\s\+', '', ''))
                        " endif

                        " Also add 1 sw indent if it looks like statement from 
previous line is continued on current one. This
                        " indent is used only if there is no non closed { or ( 
found on previous line.
                        if ind == 0
                                let plClose = (match(getline(plnum), 
'[;{}]\s*$') != -1)
                                if !plClose
                                        " Dont indent more then once for each 
continues statement. So chech if line previous to previous has
                                        " statement end look. Indent only if it 
does.
                                        let pplnum = prevnonblank(plnum - 1)
                                        if pplnum == 0 || 
match(getline(pplnum), '[;{}]\s*$') != -1
                                                let ind = ind + 1
                                        endif
                                else " In case previous line have statement end 
there is a check required to see if it was extra
                                     " indented because of statement spaned 
across multiple lines.
                                        let pplnum = prevnonblank(plnum - 1)
                                        if pplnum != 0 && match(getline(pplnum, 
'[;{}]\s*$') == -1
                                                let ind = ind - 1
                                        endif
                                endif
                        endif
                
                endif

        elseif curSyntax == 'comment'

                " Find a non-empty line above the current line.
                let plnum = prevnonblank(a:lnum - 1)
                let prevSyntax = <SID>GetSyntax(plnum)
                " Dont skip comments.
                " BUG: will not work when comments is mixed with other text in 
the same line.
                while plnum > 0 && prevSyntax == ''
                        let plnum = plnum - 1
                        let prevSyntax = <SID>GetSyntax(plnum)
                endwhile

                " Align middle part of C style comment with begin part.
                if a:lnum > 0 && getline(a:lnum) =~ '^\s*\*'
                        " Find comment start
                        let commentStartLine = a:lnum - 1
                        let secondCommentLine = 1
                        while commentStartLine > 0
                                let line = getline(commentStartLine)
                                if line =~ '^\s*/\*'
                                        break
                                endif
                                if line =~ '^\s*\*'
                                        let secondCommentLine = 0
                                        break
                                endif
                                let commentStartLine = commentStartLine - 1
                        endwhile
                        " And indent one more space, but only for the first 
comment line. Other lines get indent from previous
                        " ones - for speed.
                        if secondCommentLine && commentStartLine > 0
                                let presizeIndent = indent(commentStartLine) + 1
                        endif
                endif

        endif

        let &ic=restore_ic

        if presizeIndent != -1
                return presizeIndent
        else
                return indent(plnum) + (&sw * ind)
        endif
endfun

" [-- EOF <runtime>/indent/javascript.vim --]

Attachment: javascript.vim
Description: application/octetstream

Reply via email to