" Vim indent file " Language: Hare " Maintainer: Amelia Clarke " Last Change: 2024-04-14 " Upstream: https://git.sr.ht/~sircmpwn/hare.vim if exists('b:did_indent') finish endif let b:did_indent = 1 let s:cpo_save = &cpo set cpo&vim " L0 -> don't deindent labels " (s -> use one indent after a trailing ( " m1 -> if ) starts a line, indent it the same as its matching ( " ks -> add an extra indent to extra lines in an if expression or for expression " j1 -> indent code inside {} one level when in parentheses " J1 -> see j1 " *0 -> don't search for unclosed block comments " #1 -> don't deindent lines that begin with # setlocal cinoptions=L0,(s,m1,ks,j1,J1,*0,#1 " Controls which keys reindent the current line. " 0{ -> { at beginning of line " 0} -> } at beginning of line " 0) -> ) at beginning of line " 0] -> ] at beginning of line " !^F -> (not inserted) " o -> or `o` command " O -> `O` command " e -> else " 0=case -> case setlocal indentkeys=0{,0},0),0],!^F,o,O,e,0=case setlocal cinwords=if,else,for,switch,match setlocal indentexpr=GetHareIndent() let b:undo_indent = 'setl cino< cinw< inde< indk<' if exists('*GetHareIndent()') finish endif function! FloorCindent(lnum) return cindent(a:lnum) / shiftwidth() * shiftwidth() endfunction function! GetHareIndent() let line = getline(v:lnum) let prevlnum = prevnonblank(v:lnum - 1) let prevline = getline(prevlnum) let prevprevline = getline(prevnonblank(prevlnum - 1)) " This is all very hacky and imperfect, but it's tough to do much better when " working with regex-based indenting rules. " If the previous line ended with =, indent by one shiftwidth. if prevline =~# '\v\=\s*(//.*)?$' return indent(prevlnum) + shiftwidth() endif " If the previous line ended in a semicolon and the line before that ended " with =, deindent by one shiftwidth. if prevline =~# '\v;\s*(//.*)?$' && prevprevline =~# '\v\=\s*(//.*)?$' return indent(prevlnum) - shiftwidth() endif " TODO: The following edge-case is still indented incorrectly: " case => " if (foo) { " bar; " }; " | // cursor is incorrectly deindented by one shiftwidth. " " This only happens if the {} block is the first statement in the case body. " If `case` is typed, the case will also be incorrectly deindented by one " shiftwidth. Are you having fun yet? " Deindent cases. if line =~# '\v^\s*case' " If the previous line was also a case, don't do any special indenting. if prevline =~# '\v^\s*case' return indent(prevlnum) end " If the previous line was a multiline case, deindent by one shiftwidth. if prevline =~# '\v\=\>\s*(//.*)?$' return indent(prevlnum) - shiftwidth() endif " If the previous line started a block, deindent by one shiftwidth. " This handles the first case in a switch/match block. if prevline =~# '\v\{\s*(//.*)?$' return FloorCindent(v:lnum) - shiftwidth() end " If the previous line ended in a semicolon and the line before that wasn't " a case, deindent by one shiftwidth. if prevline =~# '\v;\s*(//.*)?$' && prevprevline !~# '\v\=\>\s*(//.*)?$' return FloorCindent(v:lnum) - shiftwidth() end let l:indent = FloorCindent(v:lnum) " If a normal cindent would indent the same amount as the previous line, " deindent by one shiftwidth. This fixes some issues with `case let` blocks. if l:indent == indent(prevlnum) return l:indent - shiftwidth() endif " Otherwise, do a normal cindent. return l:indent endif " Don't indent an extra shiftwidth for cases which span multiple lines. if prevline =~# '\v\=\>\s*(//.*)?$' && prevline !~# '\v^\s*case\W' return indent(prevlnum) endif " Indent the body of a case. " If the previous line ended in a semicolon and the line before that was a " case, don't do any special indenting. if prevline =~# '\v;\s*(//.*)?$' && prevprevline =~# '\v\=\>\s*(//.*)?$' \ && line !~# '\v^\s*}' return indent(prevlnum) endif let l:indent = FloorCindent(v:lnum) " If the previous line was a case and a normal cindent wouldn't indent, indent " an extra shiftwidth. if prevline =~# '\v\=\>\s*(//.*)?$' && l:indent == indent(prevlnum) return l:indent + shiftwidth() endif " If everything above is false, do a normal cindent. return l:indent endfunction let &cpo = s:cpo_save unlet s:cpo_save " vim: et sw=2 sts=2 ts=8