codekingpro/portable-devtools
114k
1" Vim indent file2" Language: cobol3" 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.20197" Ankit Jain 22.03.2019 Changes & fixes:8" Allow chars in 1st 6 columns9" #C2203201910" Ankit Jain 24.09.2021 add b:undo_indent (request by tpope)11 12if exists("b:did_indent")13 finish14endif15let b:did_indent = 116 17setlocal expandtab18setlocal indentexpr=GetCobolIndent(v:lnum)19setlocal indentkeys&20setlocal indentkeys+=0<*>,0/,0$,0=01,=~division,=~section,0=~end,0=~then,0=~else,0=~when,*<Return>,.21 22let b:undo_indent = "setlocal expandtab< indentexpr< indentkeys<"23 24" Only define the function once.25if exists("*GetCobolIndent")26 finish27endif28 29let s:skip = 'getline(".") =~ "^.\\{6\\}[*/$-]\\|\"[^\"]*\""'30 31function! s:prevgood(lnum)32 " Find a non-blank line above the current line.33 " Skip over comments.34 let lnum = a:lnum35 while lnum > 036 let lnum = prevnonblank(lnum - 1)37 let line = getline(lnum)38 if line !~? '^\s*[*/$-]' && line !~? '^.\{6\}[*/$CD-]'39 break40 endif41 endwhile42 return lnum43endfunction44 45function! s:stripped(lnum)46 return substitute(strpart(getline(a:lnum),0,72),'^\s*','','')47endfunction48 49function! s:optionalblock(lnum,ind,blocks,clauses)50 let ind = a:ind51 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) !~? '^'.begin61 let ind = indent(lastclause)62 elseif lastclause > 063 let ind = indent(lastclause) + shiftwidth()64 "let ind = ind + shiftwidth()65 endif66 elseif line =~? clauses && cline !~? end67 let ind = ind + shiftwidth()68 endif69 return ind70endfunction71 72function! GetCobolIndent(lnum) abort73 let minshft = 674 let ashft = minshft + 175 let bshft = ashft + 476 " (Obsolete) numbered lines77 " #C22032019: Columns 1-6 could have alphabets as well as numbers78 "if getline(a:lnum) =~? '^\s*\d\{6\}\%($\|[ */$CD-]\)'79 if getline(a:lnum) =~? '^\s*[a-zA-Z0-9]\{6\}\%($\|[ */$CD-]\)'80 return 081 endif82 let cline = s:stripped(a:lnum)83 " Comments, etc. must start in the 7th column84 if cline =~? '^[*/$-]'85 return minshft86 elseif cline =~# '^[CD]' && indent(a:lnum) == minshft87 return minshft88 endif89 " Divisions, sections, and file descriptions start in area A90 if cline =~? '\<\(DIVISION\|SECTION\)\%($\|\.\)' || cline =~? '^[FS]D\>'91 return ashft92 endif93 " Fields94 if cline =~? '^0*\(1\|77\)\>'95 return ashft96 endif97 if cline =~? '^\d\+\>'98 let cnum = matchstr(cline,'^\d\+\>')99 let default = 0100 let step = -1101 while step < 2102 let lnum = a:lnum103 while lnum > 0 && lnum < line('$') && lnum > a:lnum - 500 && lnum < a:lnum + 500104 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 == num110 return lindent111 elseif 0+cnum > num && default < lindent + shiftwidth()112 let default = lindent + shiftwidth()113 endif114 elseif lindent < bshft && lindent >= ashft115 break116 endif117 endwhile118 let step = step + 2119 endwhile120 return default ? default : bshft121 endif122 let lnum = s:prevgood(a:lnum)123 " Hit the start of the file, use "zero" indent.124 if lnum == 0125 return ashft126 endif127 " Initial spaces are ignored128 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 ashft134 endif135 endif136 " Paragraphs in the identification division.137 "if cline =~? '^\(PROGRAM-ID\|AUTHOR\|INSTALLATION\|' .138 "\ 'DATE-WRITTEN\|DATE-COMPILED\|SECURITY\)\>'139 "return ashft140 "endif141 if line =~? '\.$'142 " XXX143 return bshft144 endif145 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 endif152 endif153 if line =~? '^\%(IF\|THEN\|ELSE\|READ\|EVALUATE\|SEARCH\|SELECT\)\>'154 let ind = ind + shiftwidth()155 endif156 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 endif161 if cline =~? '^WHEN\>'162 call cursor(a:lnum,1)163 " We also search for READ so that contained AT ENDs are skipped164 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 > 0170 let ind = indent(lastclause) + shiftwidth()171 endif172 elseif line =~? '^WHEN\>'173 let ind = ind + shiftwidth()174 endif175 "I'm not sure why I had this176 "if line =~? '^ELSE\>-\@!' && line !~? '\.$'177 "let ind = indent(s:prevgood(lnum))178 "endif179 if cline =~? '^\(END\)\>-\@!'180 " On lines with just END, 'guess' a simple shift left181 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 > 0186 let ind = indent(match)187 endif188 elseif cline =~? '^END-[A-Z]'189 let beginword = matchstr(cline,'\c\<END-\zs[A-Z0-9-]\+')190 let endword = 'END-'.beginword191 let first = 0192 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 = beginword196 let first = 1197 elseif beginword =~? '^\%(STRING\|UNSTRING\)$'198 let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=ON\s\+OVERFLOW'199 let first = 1200 elseif beginword =~? '^\%(ACCEPT\|DISPLAY\)$'201 let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=ON\s\+EXCEPTION'202 let first = 1203 elseif beginword ==? 'CALL'204 let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=ON\s\+\%(EXCEPTION\|OVERFLOW\)'205 let first = 1206 elseif beginword =~? '^\%(DELETE\|REWRITE\|START\|READ\|WRITE\)$'207 let first = 1208 let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=\(INVALID\s\+KEY'209 if beginword =~? '^READ'210 let first = 0211 let beginword = beginword . '\|AT\s\+END\|NO\s\+DATA'212 elseif beginword =~? '^WRITE'213 let beginword = beginword . '\|AT\s\+END-OF-PAGE'214 endif215 let beginword = beginword . '\)'216 endif217 call cursor(a:lnum,indent(a:lnum))218 let match = searchpair('\c-\@<!\<'.beginword.'\>','','\c\<'.endword.'\>\zs','bnW'.(first? 'r' : ''),s:skip)219 if match > 0220 let ind = indent(match)221 elseif cline =~? '^\(END-\(READ\|EVALUATE\|SEARCH\|PERFORM\)\)\>'222 let ind = ind - shiftwidth()223 endif224 endif225 return ind < bshft ? bshft : ind226endfunction227 