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