Patrick Crosby's Internet Presents

Vim Objective-C Colon Indentation

02 Oct 2009

Vim's objective-c mode has an annoying indentation issue. It tries to line colons up on subsequent lines, like so:

[self performSelectorOnMainThread:@selector(finishLoad) 
                       withObject:nil 
                    waitUntilDone:NO];

That's nice, but it has an annoying bug that makes it try to align the colons with a previous line that is unrelated:

if ([someVariable isEqualToString:@"blah"]) {
[self performSelectorOnMainThread:@selector(finishLoad) 
                       withObject:nil 
                    waitUntilDone:NO];
}

This all takes place in indent/objc.vim (full path on a MacPorts installation is /opt/local/share/vim/vim72/indent/objc.vim, for MacVim it is /Applications/MacVim.app/Contents/Resources/vim/runtime/indent/objc.vim).

There is probably a way to fix this in a .vimrc file, but I just edited objc.vim. At the bottom of the file is a function GetObjCIndent. Change the second if statement to match the following:

function GetObjCIndent()
    let theIndent = cindent(v:lnum)

    let prev_line = getline(v:lnum - 1)
    let cur_line = getline(v:lnum)

    if prev_line !~# ":" || cur_line !~# ":"
        return theIndent
    endif

    if prev_line !~# ";" && prev_line !~# "{"
        let prev_colon_pos = s:GetWidth(prev_line, ":")
        let delta = s:GetWidth(cur_line, ":") - s:LeadingWhiteSpace(cur_line)
        let theIndent = prev_colon_pos - delta
    endif

    return theIndent
endfunction

There are some refinements that could be made to fix it for more cases, but this one fixes the one that was driving me crazy.