Bram Moolenaar | c81e5e7 | 2007-05-05 18:24:42 +0000 | [diff] [blame] | 1 | " Vim indent file |
| 2 | " Language: cobol |
Bram Moolenaar | 63b74a8 | 2019-03-24 15:09:13 +0100 | [diff] [blame] | 3 | " Maintainer: Ankit Jain <ajatkj@yahoo.co.in> |
| 4 | " (formerly Tim Pope <vimNOSPAM@tpope.info>) |
Bram Moolenaar | 5c73622 | 2010-01-06 20:54:52 +0100 | [diff] [blame] | 5 | " $Id: cobol.vim,v 1.1 2007/05/05 18:08:19 vimboss Exp $ |
Bram Moolenaar | 63b74a8 | 2019-03-24 15:09:13 +0100 | [diff] [blame] | 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 |
Bram Moolenaar | 6e64922 | 2021-10-04 21:32:54 +0100 | [diff] [blame] | 10 | " Ankit Jain 24.09.2021 add b:undo_indent (request by tpope) |
Bram Moolenaar | c81e5e7 | 2007-05-05 18:24:42 +0000 | [diff] [blame] | 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 | |
Bram Moolenaar | 6e64922 | 2021-10-04 21:32:54 +0100 | [diff] [blame] | 22 | let b:undo_indent = "setlocal expandtab< indentexpr< indentkeys<" |
| 23 | |
Bram Moolenaar | c81e5e7 | 2007-05-05 18:24:42 +0000 | [diff] [blame] | 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 |
Bram Moolenaar | 3ec574f | 2017-06-13 18:12:01 +0200 | [diff] [blame] | 63 | let ind = indent(lastclause) + shiftwidth() |
| 64 | "let ind = ind + shiftwidth() |
Bram Moolenaar | c81e5e7 | 2007-05-05 18:24:42 +0000 | [diff] [blame] | 65 | endif |
| 66 | elseif line =~? clauses && cline !~? end |
Bram Moolenaar | 3ec574f | 2017-06-13 18:12:01 +0200 | [diff] [blame] | 67 | let ind = ind + shiftwidth() |
Bram Moolenaar | c81e5e7 | 2007-05-05 18:24:42 +0000 | [diff] [blame] | 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 |
Bram Moolenaar | 63b74a8 | 2019-03-24 15:09:13 +0100 | [diff] [blame] | 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-]\)' |
Bram Moolenaar | c81e5e7 | 2007-05-05 18:24:42 +0000 | [diff] [blame] | 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 |
Bram Moolenaar | 3ec574f | 2017-06-13 18:12:01 +0200 | [diff] [blame] | 111 | elseif 0+cnum > num && default < lindent + shiftwidth() |
| 112 | let default = lindent + shiftwidth() |
Bram Moolenaar | c81e5e7 | 2007-05-05 18:24:42 +0000 | [diff] [blame] | 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*$' |
Bram Moolenaar | 3ec574f | 2017-06-13 18:12:01 +0200 | [diff] [blame] | 148 | let ind = ind + shiftwidth() |
Bram Moolenaar | c81e5e7 | 2007-05-05 18:24:42 +0000 | [diff] [blame] | 149 | elseif perfline =~? '^\%(WITH\s\+TEST\|VARYING\|UNTIL\)\>.*[^.]$' |
Bram Moolenaar | 3ec574f | 2017-06-13 18:12:01 +0200 | [diff] [blame] | 150 | let ind = ind + shiftwidth() |
Bram Moolenaar | c81e5e7 | 2007-05-05 18:24:42 +0000 | [diff] [blame] | 151 | endif |
| 152 | endif |
| 153 | if line =~? '^\%(IF\|THEN\|ELSE\|READ\|EVALUATE\|SEARCH\|SELECT\)\>' |
Bram Moolenaar | 3ec574f | 2017-06-13 18:12:01 +0200 | [diff] [blame] | 154 | let ind = ind + shiftwidth() |
Bram Moolenaar | c81e5e7 | 2007-05-05 18:24:42 +0000 | [diff] [blame] | 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 |
Bram Moolenaar | 3ec574f | 2017-06-13 18:12:01 +0200 | [diff] [blame] | 170 | let ind = indent(lastclause) + shiftwidth() |
Bram Moolenaar | c81e5e7 | 2007-05-05 18:24:42 +0000 | [diff] [blame] | 171 | endif |
| 172 | elseif line =~? '^WHEN\>' |
Bram Moolenaar | 3ec574f | 2017-06-13 18:12:01 +0200 | [diff] [blame] | 173 | let ind = ind + shiftwidth() |
Bram Moolenaar | c81e5e7 | 2007-05-05 18:24:42 +0000 | [diff] [blame] | 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 |
Bram Moolenaar | 3ec574f | 2017-06-13 18:12:01 +0200 | [diff] [blame] | 181 | let ind = ind - shiftwidth() |
Bram Moolenaar | c81e5e7 | 2007-05-05 18:24:42 +0000 | [diff] [blame] | 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\)\)\>' |
Bram Moolenaar | 3ec574f | 2017-06-13 18:12:01 +0200 | [diff] [blame] | 222 | let ind = ind - shiftwidth() |
Bram Moolenaar | c81e5e7 | 2007-05-05 18:24:42 +0000 | [diff] [blame] | 223 | endif |
| 224 | endif |
| 225 | return ind < bshft ? bshft : ind |
| 226 | endfunction |