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