| 
									
										
										
										
											2007-05-05 18:24:42 +00:00
										 |  |  | " Vim indent file | 
					
						
							|  |  |  | " Language:	cobol | 
					
						
							|  |  |  | " Author:	Tim Pope <vimNOSPAM@tpope.info> | 
					
						
							| 
									
										
										
										
											2010-01-06 20:54:52 +01:00
										 |  |  | " $Id: cobol.vim,v 1.1 2007/05/05 18:08:19 vimboss Exp $ | 
					
						
							| 
									
										
										
										
											2007-05-05 18:24:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | if exists("b:did_indent") | 
					
						
							|  |  |  |     finish | 
					
						
							|  |  |  | endif | 
					
						
							|  |  |  | let b:did_indent = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | setlocal expandtab | 
					
						
							|  |  |  | setlocal indentexpr=GetCobolIndent(v:lnum) | 
					
						
							|  |  |  | setlocal indentkeys& | 
					
						
							|  |  |  | setlocal indentkeys+=0<*>,0/,0$,0=01,=~division,=~section,0=~end,0=~then,0=~else,0=~when,*<Return>,. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | " Only define the function once. | 
					
						
							|  |  |  | if exists("*GetCobolIndent") | 
					
						
							|  |  |  |     finish | 
					
						
							|  |  |  | endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | let s:skip = 'getline(".") =~ "^.\\{6\\}[*/$-]\\|\"[^\"]*\""' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function! s:prevgood(lnum) | 
					
						
							|  |  |  |     " Find a non-blank line above the current line. | 
					
						
							|  |  |  |     " Skip over comments. | 
					
						
							|  |  |  |     let lnum = a:lnum | 
					
						
							|  |  |  |     while lnum > 0 | 
					
						
							|  |  |  |         let lnum = prevnonblank(lnum - 1) | 
					
						
							|  |  |  |         let line = getline(lnum) | 
					
						
							|  |  |  |         if line !~? '^\s*[*/$-]' && line !~? '^.\{6\}[*/$CD-]' | 
					
						
							|  |  |  |             break | 
					
						
							|  |  |  |         endif | 
					
						
							|  |  |  |     endwhile | 
					
						
							|  |  |  |     return lnum | 
					
						
							|  |  |  | endfunction | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function! s:stripped(lnum) | 
					
						
							|  |  |  |     return substitute(strpart(getline(a:lnum),0,72),'^\s*','','') | 
					
						
							|  |  |  | endfunction | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function! s:optionalblock(lnum,ind,blocks,clauses) | 
					
						
							|  |  |  |     let ind = a:ind | 
					
						
							|  |  |  |     let clauses = '\c\<\%(\<NOT\s\+\)\@<!\%(NOT\s\+\)\=\%('.a:clauses.'\)' | 
					
						
							|  |  |  |     let begin = '\c-\@<!\<\%('.a:blocks.'\)\>' | 
					
						
							|  |  |  |     let beginfull = begin.'\ze.*\%(\n\%(\s*\%([*/$-].*\)\=\n\)*\)\=\s*\%('.clauses.'\)' | 
					
						
							|  |  |  |     let end   = '\c\<end-\%('.a:blocks.'\)\>\|\%(\.\%( \|$\)\)\@=' | 
					
						
							|  |  |  |     let cline = s:stripped(a:lnum) | 
					
						
							|  |  |  |     let line  = s:stripped(s:prevgood(a:lnum)) | 
					
						
							|  |  |  |     if cline =~? clauses "&& line !~? '^search\>' | 
					
						
							|  |  |  |         call cursor(a:lnum,1) | 
					
						
							|  |  |  |         let lastclause = searchpair(beginfull,clauses,end,'bWr',s:skip) | 
					
						
							|  |  |  |         if getline(lastclause) =~? clauses && s:stripped(lastclause) !~? '^'.begin | 
					
						
							|  |  |  |             let ind = indent(lastclause) | 
					
						
							|  |  |  |         elseif lastclause > 0 | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |             let ind = indent(lastclause) + shiftwidth() | 
					
						
							|  |  |  |             "let ind = ind + shiftwidth() | 
					
						
							| 
									
										
										
										
											2007-05-05 18:24:42 +00:00
										 |  |  |         endif | 
					
						
							|  |  |  |     elseif line =~? clauses && cline !~? end | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |         let ind = ind + shiftwidth() | 
					
						
							| 
									
										
										
										
											2007-05-05 18:24:42 +00:00
										 |  |  |     endif | 
					
						
							|  |  |  |     return ind | 
					
						
							|  |  |  | endfunction | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function! GetCobolIndent(lnum) abort | 
					
						
							|  |  |  |     let minshft = 6 | 
					
						
							|  |  |  |     let ashft = minshft + 1 | 
					
						
							|  |  |  |     let bshft = ashft + 4 | 
					
						
							|  |  |  |     " (Obsolete) numbered lines | 
					
						
							|  |  |  |     if getline(a:lnum) =~? '^\s*\d\{6\}\%($\|[ */$CD-]\)' | 
					
						
							|  |  |  |         return 0 | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     let cline = s:stripped(a:lnum) | 
					
						
							|  |  |  |     " Comments, etc. must start in the 7th column | 
					
						
							|  |  |  |     if cline =~? '^[*/$-]' | 
					
						
							|  |  |  |         return minshft | 
					
						
							|  |  |  |     elseif cline =~# '^[CD]' && indent(a:lnum) == minshft | 
					
						
							|  |  |  |         return minshft | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     " Divisions, sections, and file descriptions start in area A | 
					
						
							|  |  |  |     if cline =~? '\<\(DIVISION\|SECTION\)\%($\|\.\)' || cline =~? '^[FS]D\>' | 
					
						
							|  |  |  |         return ashft | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     " Fields | 
					
						
							|  |  |  |     if cline =~? '^0*\(1\|77\)\>' | 
					
						
							|  |  |  |         return ashft | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     if cline =~? '^\d\+\>' | 
					
						
							|  |  |  |         let cnum = matchstr(cline,'^\d\+\>') | 
					
						
							|  |  |  |         let default = 0 | 
					
						
							|  |  |  |         let step = -1 | 
					
						
							|  |  |  |         while step < 2 | 
					
						
							|  |  |  |         let lnum = a:lnum | 
					
						
							|  |  |  |         while lnum > 0 && lnum < line('$') && lnum > a:lnum - 500 && lnum < a:lnum + 500 | 
					
						
							|  |  |  |             let lnum = step > 0 ? nextnonblank(lnum + step) : prevnonblank(lnum + step) | 
					
						
							|  |  |  |             let line = getline(lnum) | 
					
						
							|  |  |  |             let lindent = indent(lnum) | 
					
						
							|  |  |  |             if line =~? '^\s*\d\+\>' | 
					
						
							|  |  |  |                 let num = matchstr(line,'^\s*\zs\d\+\>') | 
					
						
							|  |  |  |                 if 0+cnum == num | 
					
						
							|  |  |  |                     return lindent | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |                 elseif 0+cnum > num && default < lindent + shiftwidth() | 
					
						
							|  |  |  |                     let default = lindent + shiftwidth() | 
					
						
							| 
									
										
										
										
											2007-05-05 18:24:42 +00:00
										 |  |  |                 endif | 
					
						
							|  |  |  |             elseif lindent < bshft && lindent >= ashft | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |             endif | 
					
						
							|  |  |  |         endwhile | 
					
						
							|  |  |  |         let step = step + 2 | 
					
						
							|  |  |  |         endwhile | 
					
						
							|  |  |  |         return default ? default : bshft | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     let lnum = s:prevgood(a:lnum) | 
					
						
							|  |  |  |     " Hit the start of the file, use "zero" indent. | 
					
						
							|  |  |  |     if lnum == 0 | 
					
						
							|  |  |  |         return ashft | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     " Initial spaces are ignored | 
					
						
							|  |  |  |     let line = s:stripped(lnum) | 
					
						
							|  |  |  |     let ind = indent(lnum) | 
					
						
							|  |  |  |     " Paragraphs.  There may be some false positives. | 
					
						
							|  |  |  |     if cline =~? '^\(\a[A-Z0-9-]*[A-Z0-9]\|\d[A-Z0-9-]*\a\)\.' "\s*$' | 
					
						
							|  |  |  |         if cline !~? '^EXIT\s*\.' && line =~? '\.\s*$' | 
					
						
							|  |  |  |             return ashft | 
					
						
							|  |  |  |         endif | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     " Paragraphs in the identification division. | 
					
						
							|  |  |  |     "if cline =~? '^\(PROGRAM-ID\|AUTHOR\|INSTALLATION\|' . | 
					
						
							|  |  |  |                 "\ 'DATE-WRITTEN\|DATE-COMPILED\|SECURITY\)\>' | 
					
						
							|  |  |  |         "return ashft | 
					
						
							|  |  |  |     "endif | 
					
						
							|  |  |  |     if line =~? '\.$' | 
					
						
							|  |  |  |         " XXX | 
					
						
							|  |  |  |         return bshft | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     if line =~? '^PERFORM\>' | 
					
						
							|  |  |  |         let perfline = substitute(line, '\c^PERFORM\s*', "", "") | 
					
						
							|  |  |  |         if perfline =~? '^\%(\k\+\s\+TIMES\)\=\s*$' | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |             let ind = ind + shiftwidth() | 
					
						
							| 
									
										
										
										
											2007-05-05 18:24:42 +00:00
										 |  |  |         elseif perfline =~? '^\%(WITH\s\+TEST\|VARYING\|UNTIL\)\>.*[^.]$' | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |             let ind = ind + shiftwidth() | 
					
						
							| 
									
										
										
										
											2007-05-05 18:24:42 +00:00
										 |  |  |         endif | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     if line =~? '^\%(IF\|THEN\|ELSE\|READ\|EVALUATE\|SEARCH\|SELECT\)\>' | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |         let ind = ind + shiftwidth() | 
					
						
							| 
									
										
										
										
											2007-05-05 18:24:42 +00:00
										 |  |  |     endif | 
					
						
							|  |  |  |     let ind = s:optionalblock(a:lnum,ind,'ADD\|COMPUTE\|DIVIDE\|MULTIPLY\|SUBTRACT','ON\s\+SIZE\s\+ERROR') | 
					
						
							|  |  |  |     let ind = s:optionalblock(a:lnum,ind,'STRING\|UNSTRING\|ACCEPT\|DISPLAY\|CALL','ON\s\+OVERFLOW\|ON\s\+EXCEPTION') | 
					
						
							|  |  |  |     if cline !~? '^AT\s\+END\>' || line !~? '^SEARCH\>' | 
					
						
							|  |  |  |         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') | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     if cline =~? '^WHEN\>' | 
					
						
							|  |  |  |         call cursor(a:lnum,1) | 
					
						
							|  |  |  |         " We also search for READ so that contained AT ENDs are skipped | 
					
						
							|  |  |  |         let lastclause = searchpair('\c-\@<!\<\%(SEARCH\|EVALUATE\|READ\)\>','\c\<\%(WHEN\|AT\s\+END\)\>','\c\<END-\%(SEARCH\|EVALUATE\|READ\)\>','bW',s:skip) | 
					
						
							|  |  |  |         let g:foo = s:stripped(lastclause) | 
					
						
							|  |  |  |         if s:stripped(lastclause) =~? '\c\<\%(WHEN\|AT\s\+END\)\>' | 
					
						
							|  |  |  |             "&& s:stripped(lastclause) !~? '^\%(SEARCH\|EVALUATE\|READ\)\>' | 
					
						
							|  |  |  |             let ind = indent(lastclause) | 
					
						
							|  |  |  |         elseif lastclause > 0 | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |             let ind = indent(lastclause) + shiftwidth() | 
					
						
							| 
									
										
										
										
											2007-05-05 18:24:42 +00:00
										 |  |  |         endif | 
					
						
							|  |  |  |     elseif line =~? '^WHEN\>' | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |         let ind = ind + shiftwidth() | 
					
						
							| 
									
										
										
										
											2007-05-05 18:24:42 +00:00
										 |  |  |     endif | 
					
						
							|  |  |  |     "I'm not sure why I had this | 
					
						
							|  |  |  |     "if line =~? '^ELSE\>-\@!' && line !~? '\.$' | 
					
						
							|  |  |  |         "let ind = indent(s:prevgood(lnum)) | 
					
						
							|  |  |  |     "endif | 
					
						
							|  |  |  |     if cline =~? '^\(END\)\>-\@!' | 
					
						
							|  |  |  |         " On lines with just END, 'guess' a simple shift left | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |         let ind = ind - shiftwidth() | 
					
						
							| 
									
										
										
										
											2007-05-05 18:24:42 +00:00
										 |  |  |     elseif cline =~? '^\(END-IF\|THEN\|ELSE\)\>-\@!' | 
					
						
							|  |  |  |         call cursor(a:lnum,indent(a:lnum)) | 
					
						
							|  |  |  |         let match = searchpair('\c-\@<!\<IF\>','\c-\@<!\%(THEN\|ELSE\)\>','\c-\@<!\<END-IF\>\zs','bnW',s:skip) | 
					
						
							|  |  |  |         if match > 0 | 
					
						
							|  |  |  |             let ind = indent(match) | 
					
						
							|  |  |  |         endif | 
					
						
							|  |  |  |     elseif cline =~? '^END-[A-Z]' | 
					
						
							|  |  |  |         let beginword = matchstr(cline,'\c\<END-\zs[A-Z0-9-]\+') | 
					
						
							|  |  |  |         let endword = 'END-'.beginword | 
					
						
							|  |  |  |         let first = 0 | 
					
						
							|  |  |  |         let suffix = '.*\%(\n\%(\%(\s*\|.\{6\}\)[*/].*\n\)*\)\=\s*' | 
					
						
							|  |  |  |         if beginword =~? '^\%(ADD\|COMPUTE\|DIVIDE\|MULTIPLY\|SUBTRACT\)$' | 
					
						
							|  |  |  |             let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=ON\s\+SIZE\s\+ERROR' | 
					
						
							|  |  |  |             let g:beginword = beginword | 
					
						
							|  |  |  |             let first = 1 | 
					
						
							|  |  |  |         elseif beginword =~? '^\%(STRING\|UNSTRING\)$' | 
					
						
							|  |  |  |             let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=ON\s\+OVERFLOW' | 
					
						
							|  |  |  |             let first = 1 | 
					
						
							|  |  |  |         elseif beginword =~? '^\%(ACCEPT\|DISPLAY\)$' | 
					
						
							|  |  |  |             let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=ON\s\+EXCEPTION' | 
					
						
							|  |  |  |             let first = 1 | 
					
						
							|  |  |  |         elseif beginword ==? 'CALL' | 
					
						
							|  |  |  |             let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=ON\s\+\%(EXCEPTION\|OVERFLOW\)' | 
					
						
							|  |  |  |             let first = 1 | 
					
						
							|  |  |  |         elseif beginword =~? '^\%(DELETE\|REWRITE\|START\|READ\|WRITE\)$' | 
					
						
							|  |  |  |             let first = 1 | 
					
						
							|  |  |  |             let beginword = beginword . suffix . '\<\%(NOT\s\+\)\=\(INVALID\s\+KEY' | 
					
						
							|  |  |  |             if beginword =~? '^READ' | 
					
						
							|  |  |  |                 let first = 0 | 
					
						
							|  |  |  |                 let beginword = beginword . '\|AT\s\+END\|NO\s\+DATA' | 
					
						
							|  |  |  |             elseif beginword =~? '^WRITE' | 
					
						
							|  |  |  |                 let beginword = beginword . '\|AT\s\+END-OF-PAGE' | 
					
						
							|  |  |  |             endif | 
					
						
							|  |  |  |             let beginword = beginword . '\)' | 
					
						
							|  |  |  |         endif | 
					
						
							|  |  |  |         call cursor(a:lnum,indent(a:lnum)) | 
					
						
							|  |  |  |         let match = searchpair('\c-\@<!\<'.beginword.'\>','','\c\<'.endword.'\>\zs','bnW'.(first? 'r' : ''),s:skip) | 
					
						
							|  |  |  |         if match > 0 | 
					
						
							|  |  |  |             let ind = indent(match) | 
					
						
							|  |  |  |         elseif cline =~? '^\(END-\(READ\|EVALUATE\|SEARCH\|PERFORM\)\)\>' | 
					
						
							| 
									
										
										
										
											2017-06-13 18:12:01 +02:00
										 |  |  |             let ind = ind - shiftwidth() | 
					
						
							| 
									
										
										
										
											2007-05-05 18:24:42 +00:00
										 |  |  |         endif | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     return ind < bshft ? bshft : ind | 
					
						
							|  |  |  | endfunction |