neovim

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

cobol.vim (8832B)


      1 " Vim indent file
      2 " Language:	cobol
      3 " Maintainer: Ankit Jain <ajatkj@yahoo.co.in>
      4 "     (formerly Tim Pope <vimNOSPAM@tpope.info>)
      5 " $Id: cobol.vim,v 1.1 2007/05/05 18:08:19 vimboss Exp $
      6 " Last Update:	By Ankit Jain on 22.03.2019
      7 " Ankit Jain      22.03.2019     Changes & fixes:
      8 "                                Allow chars in 1st 6 columns
      9 "                                #C22032019
     10 " Ankit Jain      24.09.2021     add b:undo_indent (request by tpope)
     11 
     12 if exists("b:did_indent")
     13    finish
     14 endif
     15 let b:did_indent = 1
     16 
     17 setlocal expandtab
     18 setlocal indentexpr=GetCobolIndent(v:lnum)
     19 setlocal indentkeys&
     20 setlocal indentkeys+=0<*>,0/,0$,0=01,=~division,=~section,0=~end,0=~then,0=~else,0=~when,*<Return>,.
     21 
     22 let b:undo_indent = "setlocal expandtab< indentexpr< indentkeys<"
     23 
     24 " Only define the function once.
     25 if exists("*GetCobolIndent")
     26    finish
     27 endif
     28 
     29 let s:skip = 'getline(".") =~ "^.\\{6\\}[*/$-]\\|\"[^\"]*\""'
     30 
     31 function! s:prevgood(lnum)
     32    " Find a non-blank line above the current line.
     33    " Skip over comments.
     34    let lnum = a:lnum
     35    while lnum > 0
     36        let lnum = prevnonblank(lnum - 1)
     37        let line = getline(lnum)
     38        if line !~? '^\s*[*/$-]' && line !~? '^.\{6\}[*/$CD-]'
     39            break
     40        endif
     41    endwhile
     42    return lnum
     43 endfunction
     44 
     45 function! s:stripped(lnum)
     46    return substitute(strpart(getline(a:lnum),0,72),'^\s*','','')
     47 endfunction
     48 
     49 function! s:optionalblock(lnum,ind,blocks,clauses)
     50    let ind = a:ind
     51    let clauses = '\c\<\%(\<NOT\s\+\)\@<!\%(NOT\s\+\)\=\%('.a:clauses.'\)'
     52    let begin = '\c-\@<!\<\%('.a:blocks.'\)\>'
     53    let beginfull = begin.'\ze.*\%(\n\%(\s*\%([*/$-].*\)\=\n\)*\)\=\s*\%('.clauses.'\)'
     54    let end   = '\c\<end-\%('.a:blocks.'\)\>\|\%(\.\%( \|$\)\)\@='
     55    let cline = s:stripped(a:lnum)
     56    let line  = s:stripped(s:prevgood(a:lnum))
     57    if cline =~? clauses "&& line !~? '^search\>'
     58        call cursor(a:lnum,1)
     59        let lastclause = searchpair(beginfull,clauses,end,'bWr',s:skip)
     60        if getline(lastclause) =~? clauses && s:stripped(lastclause) !~? '^'.begin
     61            let ind = indent(lastclause)
     62        elseif lastclause > 0
     63            let ind = indent(lastclause) + shiftwidth()
     64            "let ind = ind + shiftwidth()
     65        endif
     66    elseif line =~? clauses && cline !~? end
     67        let ind = ind + shiftwidth()
     68    endif
     69    return ind
     70 endfunction
     71 
     72 function! GetCobolIndent(lnum) abort
     73    let minshft = 6
     74    let ashft = minshft + 1
     75    let bshft = ashft + 4
     76    " (Obsolete) numbered lines
     77    " #C22032019: Columns 1-6 could have alphabets as well as numbers
     78    "if getline(a:lnum) =~? '^\s*\d\{6\}\%($\|[ */$CD-]\)'
     79    if getline(a:lnum) =~? '^\s*[a-zA-Z0-9]\{6\}\%($\|[ */$CD-]\)'
     80        return 0
     81    endif
     82    let cline = s:stripped(a:lnum)
     83    " Comments, etc. must start in the 7th column
     84    if cline =~? '^[*/$-]'
     85        return minshft
     86    elseif cline =~# '^[CD]' && indent(a:lnum) == minshft
     87        return minshft
     88    endif
     89    " Divisions, sections, and file descriptions start in area A
     90    if cline =~? '\<\(DIVISION\|SECTION\)\%($\|\.\)' || cline =~? '^[FS]D\>'
     91        return ashft
     92    endif
     93    " Fields
     94    if cline =~? '^0*\(1\|77\)\>'
     95        return ashft
     96    endif
     97    if cline =~? '^\d\+\>'
     98        let cnum = matchstr(cline,'^\d\+\>')
     99        let default = 0
    100        let step = -1
    101        while step < 2
    102        let lnum = a:lnum
    103        while lnum > 0 && lnum < line('$') && lnum > a:lnum - 500 && lnum < a:lnum + 500
    104            let lnum = step > 0 ? nextnonblank(lnum + step) : prevnonblank(lnum + step)
    105            let line = getline(lnum)
    106            let lindent = indent(lnum)
    107            if line =~? '^\s*\d\+\>'
    108                let num = matchstr(line,'^\s*\zs\d\+\>')
    109                if 0+cnum == num
    110                    return lindent
    111                elseif 0+cnum > num && default < lindent + shiftwidth()
    112                    let default = lindent + shiftwidth()
    113                endif
    114            elseif lindent < bshft && lindent >= ashft
    115                break
    116            endif
    117        endwhile
    118        let step = step + 2
    119        endwhile
    120        return default ? default : bshft
    121    endif
    122    let lnum = s:prevgood(a:lnum)
    123    " Hit the start of the file, use "zero" indent.
    124    if lnum == 0
    125        return ashft
    126    endif
    127    " Initial spaces are ignored
    128    let line = s:stripped(lnum)
    129    let ind = indent(lnum)
    130    " Paragraphs.  There may be some false positives.
    131    if cline =~? '^\(\a[A-Z0-9-]*[A-Z0-9]\|\d[A-Z0-9-]*\a\)\.' "\s*$'
    132        if cline !~? '^EXIT\s*\.' && line =~? '\.\s*$'
    133            return ashft
    134        endif
    135    endif
    136    " Paragraphs in the identification division.
    137    "if cline =~? '^\(PROGRAM-ID\|AUTHOR\|INSTALLATION\|' .
    138                "\ 'DATE-WRITTEN\|DATE-COMPILED\|SECURITY\)\>'
    139        "return ashft
    140    "endif
    141    if line =~? '\.$'
    142        " XXX
    143        return bshft
    144    endif
    145    if line =~? '^PERFORM\>'
    146        let perfline = substitute(line, '\c^PERFORM\s*', "", "")
    147        if perfline =~? '^\%(\k\+\s\+TIMES\)\=\s*$'
    148            let ind = ind + shiftwidth()
    149        elseif perfline =~? '^\%(WITH\s\+TEST\|VARYING\|UNTIL\)\>.*[^.]$'
    150            let ind = ind + shiftwidth()
    151        endif
    152    endif
    153    if line =~? '^\%(IF\|THEN\|ELSE\|READ\|EVALUATE\|SEARCH\|SELECT\)\>'
    154        let ind = ind + shiftwidth()
    155    endif
    156    let ind = s:optionalblock(a:lnum,ind,'ADD\|COMPUTE\|DIVIDE\|MULTIPLY\|SUBTRACT','ON\s\+SIZE\s\+ERROR')
    157    let ind = s:optionalblock(a:lnum,ind,'STRING\|UNSTRING\|ACCEPT\|DISPLAY\|CALL','ON\s\+OVERFLOW\|ON\s\+EXCEPTION')
    158    if cline !~? '^AT\s\+END\>' || line !~? '^SEARCH\>'
    159        let ind = s:optionalblock(a:lnum,ind,'DELETE\|REWRITE\|START\|WRITE\|READ','INVALID\s\+KEY\|AT\s\+END\|NO\s\+DATA\|AT\s\+END-OF-PAGE')
    160    endif
    161    if cline =~? '^WHEN\>'
    162        call cursor(a:lnum,1)
    163        " We also search for READ so that contained AT ENDs are skipped
    164        let lastclause = searchpair('\c-\@<!\<\%(SEARCH\|EVALUATE\|READ\)\>','\c\<\%(WHEN\|AT\s\+END\)\>','\c\<END-\%(SEARCH\|EVALUATE\|READ\)\>','bW',s:skip)
    165        let g:foo = s:stripped(lastclause)
    166        if s:stripped(lastclause) =~? '\c\<\%(WHEN\|AT\s\+END\)\>'
    167            "&& s:stripped(lastclause) !~? '^\%(SEARCH\|EVALUATE\|READ\)\>'
    168            let ind = indent(lastclause)
    169        elseif lastclause > 0
    170            let ind = indent(lastclause) + shiftwidth()
    171        endif
    172    elseif line =~? '^WHEN\>'
    173        let ind = ind + shiftwidth()
    174    endif
    175    "I'm not sure why I had this
    176    "if line =~? '^ELSE\>-\@!' && line !~? '\.$'
    177        "let ind = indent(s:prevgood(lnum))
    178    "endif
    179    if cline =~? '^\(END\)\>-\@!'
    180        " On lines with just END, 'guess' a simple shift left
    181        let ind = ind - shiftwidth()
    182    elseif cline =~? '^\(END-IF\|THEN\|ELSE\)\>-\@!'
    183        call cursor(a:lnum,indent(a:lnum))
    184        let match = searchpair('\c-\@<!\<IF\>','\c-\@<!\%(THEN\|ELSE\)\>','\c-\@<!\<END-IF\>\zs','bnW',s:skip)
    185        if match > 0
    186            let ind = indent(match)
    187        endif
    188    elseif cline =~? '^END-[A-Z]'
    189        let beginword = matchstr(cline,'\c\<END-\zs[A-Z0-9-]\+')
    190        let endword = 'END-'.beginword
    191        let first = 0
    192        let suffix = '.*\%(\n\%(\%(\s*\|.\{6\}\)[*/].*\n\)*\)\=\s*'
    193        if beginword =~? '^\%(ADD\|COMPUTE\|DIVIDE\|MULTIPLY\|SUBTRACT\)$'
    194            let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=ON\s\+SIZE\s\+ERROR'
    195            let g:beginword = beginword
    196            let first = 1
    197        elseif beginword =~? '^\%(STRING\|UNSTRING\)$'
    198            let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=ON\s\+OVERFLOW'
    199            let first = 1
    200        elseif beginword =~? '^\%(ACCEPT\|DISPLAY\)$'
    201            let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=ON\s\+EXCEPTION'
    202            let first = 1
    203        elseif beginword ==? 'CALL'
    204            let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=ON\s\+\%(EXCEPTION\|OVERFLOW\)'
    205            let first = 1
    206        elseif beginword =~? '^\%(DELETE\|REWRITE\|START\|READ\|WRITE\)$'
    207            let first = 1
    208            let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=\(INVALID\s\+KEY'
    209            if beginword =~? '^READ'
    210                let first = 0
    211                let beginword = beginword . '\|AT\s\+END\|NO\s\+DATA'
    212            elseif beginword =~? '^WRITE'
    213                let beginword = beginword . '\|AT\s\+END-OF-PAGE'
    214            endif
    215            let beginword = beginword . '\)'
    216        endif
    217        call cursor(a:lnum,indent(a:lnum))
    218        let match = searchpair('\c-\@<!\<'.beginword.'\>','','\c\<'.endword.'\>\zs','bnW'.(first? 'r' : ''),s:skip)
    219        if match > 0
    220            let ind = indent(match)
    221        elseif cline =~? '^\(END-\(READ\|EVALUATE\|SEARCH\|PERFORM\)\)\>'
    222            let ind = ind - shiftwidth()
    223        endif
    224    endif
    225    return ind < bshft ? bshft : ind
    226 endfunction