neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

odin.vim (3807B)


      1 " Vim indent plugin file
      2 " Language: Odin
      3 " Maintainer: Maxim Kim <habamax@gmail.com>
      4 " Website: https://github.com/habamax/vim-odin
      5 " Last Change: 2024-01-15
      6 "
      7 " This file has been manually translated from Vim9 script.
      8 
      9 if exists("b:did_indent")
     10    finish
     11 endif
     12 let b:did_indent = 1
     13 
     14 let s:cpo_save = &cpo
     15 set cpo&vim
     16 
     17 let b:undo_indent = 'setlocal cindent< cinoptions< cinkeys< indentexpr<'
     18 
     19 setlocal cindent
     20 setlocal cinoptions=L0,m1,(s,j1,J1,l1,+0,:0,#1
     21 setlocal cinkeys=0{,0},0),0],!^F,:,o,O
     22 
     23 setlocal indentexpr=s:GetOdinIndent(v:lnum)
     24 
     25 function s:PrevLine(lnum) abort
     26    let plnum = a:lnum - 1
     27    while plnum > 1
     28        let plnum = prevnonblank(plnum)
     29        let pline = getline(plnum)
     30        " XXX: take into account nested multiline /* /* */ */ comments
     31        if pline =~# '\*/\s*$'
     32            while getline(plnum) !~# '/\*' && plnum > 1
     33                let plnum -= 1
     34            endwhile
     35            if getline(plnum) =~# '^\s*/\*'
     36                let plnum -= 1
     37            else
     38                break
     39            endif
     40        elseif pline =~# '^\s*//'
     41            let plnum -= 1
     42        else
     43            break
     44        endif
     45    endwhile
     46    return plnum
     47 endfunction
     48 
     49 function s:GetOdinIndent(lnum) abort
     50    let plnum = s:PrevLine(a:lnum)
     51    let pline = getline(plnum)
     52    let pindent = indent(plnum)
     53    " workaround of cindent "hang"
     54    " if the previous line looks like:
     55    " : #{}
     56    " : #whatever{whateverelse}
     57    " and variations where : # { } are in the string
     58    " cindent(lnum) hangs
     59    if pline =~# ':\s\+#.*{.*}'
     60        return pindent
     61    endif
     62 
     63    let indent = cindent(a:lnum)
     64    let line = getline(a:lnum)
     65 
     66    if line =~# '^\s*#\k\+'
     67        if pline =~# '[{:]\s*$'
     68            let indent = pindent + shiftwidth()
     69        else
     70            let indent = pindent
     71        endif
     72    elseif pline =~# 'switch\s.*{\s*$'
     73        let indent = pindent
     74    elseif pline =~# 'case\s*.*,\s*\(//.*\)\?$' " https://github.com/habamax/vim-odin/issues/8
     75        let indent = pindent + matchstr(pline, 'case\s*')->strcharlen()
     76    elseif line =~# '^\s*case\s\+.*,\s*$'
     77        let indent = pindent - shiftwidth()
     78    elseif pline =~# 'case\s*.*:\s*\(//.*\)\?$'
     79        if line !~# '^\s*}\s*$' && line !~# '^\s*case[[:space:]:]'
     80            let indent = pindent + shiftwidth()
     81        endif
     82    elseif pline =~# '^\s*@.*' && line !~# '^\s*}'
     83        let indent = pindent
     84    elseif pline =~# ':[:=].*}\s*$'
     85        let indent = pindent
     86    elseif pline =~# '^\s*}\s*$'
     87        if line !~# '^\s*}' && line !~# 'case\s*.*:\s*$'
     88            let indent = pindent
     89        else
     90            let indent = pindent - shiftwidth()
     91        endif
     92    elseif pline =~# '\S:\s*$'
     93        " looking up for a case something,
     94        "                       whatever,
     95        "                       anything:
     96        " ... 20 lines before
     97        for idx in range(plnum - 1, plnum - 21, -1)
     98            if plnum < 1
     99                break
    100            endif
    101            if getline(idx) =~# '^\s*case\s.*,\s*$'
    102                let indent = indent(idx) + shiftwidth()
    103                break
    104            endif
    105        endfor
    106    elseif pline =~# '{[^{]*}\s*$' && line !~# '^\s*[})]\s*$' " https://github.com/habamax/vim-odin/issues/2
    107        let indent = pindent
    108    elseif pline =~# '^\s*}\s*$' " https://github.com/habamax/vim-odin/issues/3
    109        " Find line with opening { and check if there is a label:
    110        " If there is, return indent of the closing }
    111        call cursor(plnum, 1)
    112        silent normal! %
    113        let brlnum = line('.')
    114        let brline = getline('.')
    115        if plnum != brlnum && (brline =~# '^\s*\k\+:\s\+for' || brline =~# '^\s*\k\+\s*:=')
    116            let indent = pindent
    117        endif
    118    endif
    119 
    120    return indent
    121 endfunction
    122 
    123 let &cpo = s:cpo_save
    124 unlet s:cpo_save