2022-09-28 03:48:36 -07:00
|
|
|
" Vim indent file
|
2024-05-25 16:11:50 -07:00
|
|
|
" Language: Hare
|
|
|
|
" Maintainer: Amelia Clarke <selene@perilune.dev>
|
|
|
|
" Last Change: 2024-04-14
|
|
|
|
" Upstream: https://git.sr.ht/~sircmpwn/hare.vim
|
2022-09-28 03:48:36 -07:00
|
|
|
|
2024-05-25 16:11:50 -07:00
|
|
|
if exists('b:did_indent')
|
2022-09-28 03:48:36 -07:00
|
|
|
finish
|
|
|
|
endif
|
|
|
|
let b:did_indent = 1
|
|
|
|
|
2024-05-25 16:11:50 -07:00
|
|
|
let s:cpo_save = &cpo
|
|
|
|
set cpo&vim
|
2022-09-28 03:48:36 -07:00
|
|
|
|
|
|
|
" 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 -> <C-f> (not inserted)
|
|
|
|
" o -> <CR> 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()
|
|
|
|
|
2024-05-25 16:11:50 -07:00
|
|
|
let b:undo_indent = 'setl cino< cinw< inde< indk<'
|
|
|
|
|
|
|
|
if exists('*GetHareIndent()')
|
|
|
|
finish
|
|
|
|
endif
|
2023-08-29 02:03:29 -07:00
|
|
|
|
2022-09-28 03:48:36 -07:00
|
|
|
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.
|
2024-05-25 16:11:50 -07:00
|
|
|
if prevline =~# '\v;\s*(//.*)?$' && prevprevline =~# '\v\=\>\s*(//.*)?$'
|
|
|
|
\ && line !~# '\v^\s*}'
|
2022-09-28 03:48:36 -07:00
|
|
|
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
|
|
|
|
|
2024-05-25 16:11:50 -07:00
|
|
|
let &cpo = s:cpo_save
|
|
|
|
unlet s:cpo_save
|
|
|
|
|
|
|
|
" vim: et sw=2 sts=2 ts=8
|