Search code examples
vimindentationsassauto-indent

How do I define indents in vim based on curly braces?


I use https://github.com/cakebaker/scss-syntax.vim for syntax highlighting SCSS (or SASS) files on vim, which works very well for syntax highlighting. However, the plugin does not come with an indent file and am having trouble writing one.

I would like to set the indent to look like this:

enter image description here

However, if i do gg=G, I get:

enter image description here

I suspect that it does not understand nested indent based on braces. I tried all the different combinations of

set cindent

set nocindent

set autoindent

set smartindent

and tried to use the code from Tab key == 4 spaces and auto-indent after curly braces in Vim , including

set tabstop=2

set shiftwidth=2

set expandtab

...but nested braces indent never seems to work.

I believe that I might want to write a custom indent file, and all I need is indentation based on braces with nested levels. How should I go about this? If someone has an indentation file for filetypes with similar syntax, that will be great as well.


Solution

  • This is a quick hack, based on the built-in perl indentation code (in indent/perl.vim). Hopefully you can use it to get what you want to do. See the more detailed comments in either the perl indentation code or another one of the files in the indent directory for more details.

    setlocal indentexpr=GetMyIndent()
    function! GetMyIndent()
        let cline = getline(v:lnum)
    
        " Find a non-blank 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)
        let ind = indent(lnum)
    
        " Indent blocks enclosed by {}, (), or []
        " Find a real opening brace
        let bracepos = match(line, '[(){}\[\]]', matchend(line, '^\s*[)}\]]'))
        while bracepos != -1
            let brace = strpart(line, bracepos, 1)
            if brace == '(' || brace == '{' || brace == '['
                let ind = ind + &sw
            else
                let ind = ind - &sw
            endif
            let bracepos = match(line, '[(){}\[\]]', bracepos + 1)
        endwhile
        let bracepos = matchend(cline, '^\s*[)}\]]')
        if bracepos != -1
            let ind = ind - &sw
        endif
    
        return ind
    endfunction
    

    Save that file as ~/.vim/indent/something.vim where something is your file type (replace ~/.vim with the path to vimfiles if you're on Windows.

    You might also want to stick this at the start of the file (but only if there isn't some other indent declaration that might be loaded first):

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