blob: a748cfbb408f8ae41c002283fcfe5a41d93a7a63 [file] [log] [blame]
Bram Moolenaareb3dc872018-05-13 22:34:24 +02001" Vim indent file
2" Language: LaTeX
3" Maintainer: Yichao Zhou <broken.zhou AT gmail.com>
4" Created: Sat, 16 Feb 2002 16:50:19 +0100
5" Version: 1.0.0
Bram Moolenaar328da0d2016-03-04 22:22:32 +01006" Please email me if you found something I can do. Comments, bug report and
7" feature request are welcome.
Bram Moolenaar61d35bd2012-03-28 20:51:51 +02008
Bram Moolenaareb3dc872018-05-13 22:34:24 +02009" Last Update: {{{
Bram Moolenaar61d35bd2012-03-28 20:51:51 +020010" 25th Sep 2002, by LH :
Bram Moolenaarf1568ec2011-12-14 21:17:39 +010011" (*) better support for the option
12" (*) use some regex instead of several '||'.
13" Oct 9th, 2003, by JT:
14" (*) don't change indentation of lines starting with '%'
Bram Moolenaar61d35bd2012-03-28 20:51:51 +020015" 2005/06/15, Moshe Kaminsky <kaminsky AT math.huji.ac.il>
Bram Moolenaarf1568ec2011-12-14 21:17:39 +010016" (*) New variables:
17" g:tex_items, g:tex_itemize_env, g:tex_noindent_env
Bram Moolenaareb3dc872018-05-13 22:34:24 +020018" 2011/3/6, by Yichao Zhou <broken.zhou AT gmail.com>
Bram Moolenaarf1568ec2011-12-14 21:17:39 +010019" (*) Don't change indentation of lines starting with '%'
20" I don't see any code with '%' and it doesn't work properly
21" so I add some code.
22" (*) New features: Add smartindent-like indent for "{}" and "[]".
23" (*) New variables: g:tex_indent_brace
Bram Moolenaareb3dc872018-05-13 22:34:24 +020024" 2011/9/25, by Yichao Zhou <broken.zhou AT gmail.com>
Bram Moolenaarf1568ec2011-12-14 21:17:39 +010025" (*) Bug fix: smartindent-like indent for "[]"
26" (*) New features: Align with "&".
Bram Moolenaar61d35bd2012-03-28 20:51:51 +020027" (*) New variable: g:tex_indent_and.
Bram Moolenaareb3dc872018-05-13 22:34:24 +020028" 2011/10/23 by Yichao Zhou <broken.zhou AT gmail.com>
Bram Moolenaarf1568ec2011-12-14 21:17:39 +010029" (*) Bug fix: improve the smartindent-like indent for "{}" and
30" "[]".
Bram Moolenaareb3dc872018-05-13 22:34:24 +020031" 2012/02/27 by Yichao Zhou <broken.zhou AT gmail.com>
Bram Moolenaar61d35bd2012-03-28 20:51:51 +020032" (*) Bug fix: support default folding marker.
33" (*) Indent with "&" is not very handy. Make it not enable by
34" default.
Bram Moolenaareb3dc872018-05-13 22:34:24 +020035" 2012/03/06 by Yichao Zhou <broken.zhou AT gmail.com>
Bram Moolenaar61d35bd2012-03-28 20:51:51 +020036" (*) Modify "&" behavior and make it default again. Now "&"
37" won't align when there are more then one "&" in the previous
38" line.
39" (*) Add indent "\left(" and "\right)"
40" (*) Trust user when in "verbatim" and "lstlisting"
Bram Moolenaareb3dc872018-05-13 22:34:24 +020041" 2012/03/11 by Yichao Zhou <broken.zhou AT gmail.com>
Bram Moolenaar61d35bd2012-03-28 20:51:51 +020042" (*) Modify "&" so that only indent when current line start with
Bram Moolenaar328da0d2016-03-04 22:22:32 +010043" "&".
Bram Moolenaareb3dc872018-05-13 22:34:24 +020044" 2012/03/12 by Yichao Zhou <broken.zhou AT gmail.com>
Bram Moolenaar61d35bd2012-03-28 20:51:51 +020045" (*) Modify indentkeys.
Bram Moolenaareb3dc872018-05-13 22:34:24 +020046" 2012/03/18 by Yichao Zhou <broken.zhou AT gmail.com>
Bram Moolenaar61d35bd2012-03-28 20:51:51 +020047" (*) Add &cpo
Bram Moolenaareb3dc872018-05-13 22:34:24 +020048" 2013/05/02 by Yichao Zhou <broken.zhou AT gmail.com>
Bram Moolenaarad3b3662013-05-17 18:14:19 +020049" (*) Fix problem about GetTeXIndent checker. Thank Albert Netymk
50" for reporting this.
Bram Moolenaareb3dc872018-05-13 22:34:24 +020051" 2014/06/23 by Yichao Zhou <broken.zhou AT gmail.com>
Bram Moolenaar328da0d2016-03-04 22:22:32 +010052" (*) Remove the feature g:tex_indent_and because it is buggy.
53" (*) If there is not any obvious indentation hints, we do not
54" alert our user's current indentation.
55" (*) g:tex_indent_brace now only works if the open brace is the
56" last character of that line.
Bram Moolenaareb3dc872018-05-13 22:34:24 +020057" 2014/08/03 by Yichao Zhou <broken.zhou AT gmail.com>
Bram Moolenaar328da0d2016-03-04 22:22:32 +010058" (*) Indent current line if last line has larger indentation
Bram Moolenaareb3dc872018-05-13 22:34:24 +020059" 2016/11/08 by Yichao Zhou <broken.zhou AT gmail.com>
60" (*) Fix problems for \[ and \]. Thanks Bruno for reporting.
61" 2017/04/30 by Yichao Zhou <broken.zhou AT gmail.com>
62" (*) Fix a bug between g:tex_noindent_env and g:tex_indent_items
63" Now g:tex_noindent_env='document\|verbatim\|itemize' (Emacs
64" style) is supported. Thanks Miles Wheeler for reporting.
65" 2018/02/07 by Yichao Zhou <broken.zhou AT gmail.com>
66" (*) Make indentation more smart in the normal mode
Bram Moolenaar328da0d2016-03-04 22:22:32 +010067"
Bram Moolenaar61d35bd2012-03-28 20:51:51 +020068" }}}
Bram Moolenaareb3dc872018-05-13 22:34:24 +020069
70" Document: {{{
71"
72" To set the following options (ok, currently it's just one), add a line like
73" let g:tex_indent_items = 1
74" to your ~/.vimrc.
75"
76" * g:tex_indent_brace
77"
78" If this variable is unset or non-zero, it will use smartindent-like style
79" for "{}" and "[]". Now this only works if the open brace is the last
80" character of that line.
81"
82" % Example 1
83" \usetikzlibrary{
84" external
85" }
86"
87" % Example 2
88" \tikzexternalize[
89" prefix=tikz]
90"
91" * g:tex_indent_items
92"
93" If this variable is set, item-environments are indented like Emacs does
94" it, i.e., continuation lines are indented with a shiftwidth.
95"
96" set unset
97" ------------------------------------------------------
98" \begin{itemize} \begin{itemize}
99" \item blablabla \item blablabla
100" bla bla bla bla bla bla
101" \item blablabla \item blablabla
102" bla bla bla bla bla bla
103" \end{itemize} \end{itemize}
104"
105"
106" * g:tex_items
107"
108" A list of tokens to be considered as commands for the beginning of an item
109" command. The tokens should be separated with '\|'. The initial '\' should
110" be escaped. The default is '\\bibitem\|\\item'.
111"
112" * g:tex_itemize_env
113"
114" A list of environment names, separated with '\|', where the items (item
115" commands matching g:tex_items) may appear. The default is
116" 'itemize\|description\|enumerate\|thebibliography'.
117"
118" * g:tex_noindent_env
119"
120" A list of environment names. separated with '\|', where no indentation is
121" required. The default is 'document\|verbatim'.
122" }}}
123
124" Only define the function once
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100125if exists("b:did_indent")
126 finish
127endif
Bram Moolenaar61d35bd2012-03-28 20:51:51 +0200128
129let s:cpo_save = &cpo
130set cpo&vim
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200131
132" Define global variable {{{
133
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100134let b:did_indent = 1
135
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100136if !exists("g:tex_indent_items")
137 let g:tex_indent_items = 1
138endif
139if !exists("g:tex_indent_brace")
140 let g:tex_indent_brace = 1
141endif
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100142if !exists("g:tex_max_scan_line")
143 let g:tex_max_scan_line = 60
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100144endif
145if g:tex_indent_items
146 if !exists("g:tex_itemize_env")
147 let g:tex_itemize_env = 'itemize\|description\|enumerate\|thebibliography'
148 endif
149 if !exists('g:tex_items')
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200150 let g:tex_items = '\\bibitem\|\\item'
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100151 endif
152else
153 let g:tex_items = ''
154endif
155
Bram Moolenaar61d35bd2012-03-28 20:51:51 +0200156if !exists("g:tex_noindent_env")
157 let g:tex_noindent_env = 'document\|verbatim\|lstlisting'
158endif "}}}
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200159
160" VIM Setting " {{{
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100161setlocal autoindent
162setlocal nosmartindent
163setlocal indentexpr=GetTeXIndent()
Bram Moolenaar61d35bd2012-03-28 20:51:51 +0200164setlocal indentkeys&
165exec 'setlocal indentkeys+=[,(,{,),},],\&' . substitute(g:tex_items, '^\|\(\\|\)', ',=', 'g')
166let g:tex_items = '^\s*' . substitute(g:tex_items, '^\(\^\\s\*\)*', '', '')
Bram Moolenaar7db25fe2018-05-13 00:02:36 +0200167" }}}
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200168
169function! GetTeXIndent() " {{{
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100170 " Find a non-blank line above the current line.
171 let lnum = prevnonblank(v:lnum - 1)
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100172 let cnum = v:lnum
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100173
174 " Comment line is not what we need.
175 while lnum != 0 && getline(lnum) =~ '^\s*%'
176 let lnum = prevnonblank(lnum - 1)
177 endwhile
178
179 " At the start of the file use zero indent.
180 if lnum == 0
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200181 return 0
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100182 endif
183
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100184 let line = substitute(getline(lnum), '\s*%.*', '','g') " last line
185 let cline = substitute(getline(v:lnum), '\s*%.*', '', 'g') " current line
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100186
Bram Moolenaar61d35bd2012-03-28 20:51:51 +0200187 " We are in verbatim, so do what our user what.
188 if synIDattr(synID(v:lnum, indent(v:lnum), 1), "name") == "texZone"
189 if empty(cline)
190 return indent(lnum)
191 else
192 return indent(v:lnum)
193 end
194 endif
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200195
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100196 if lnum == 0
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200197 return 0
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100198 endif
199
200 let ind = indent(lnum)
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100201 let stay = 1
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100202
203 " New code for comment: retain the indent of current line
204 if cline =~ '^\s*%'
205 return indent(v:lnum)
206 endif
207
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200208 " Add a 'shiftwidth' after beginning of environments.
209 " Don't add it for \begin{document} and \begin{verbatim}
210 " if line =~ '^\s*\\begin{\(.*\)}' && line !~ 'verbatim'
211 " LH modification : \begin does not always start a line
212 " ZYC modification : \end after \begin won't cause wrong indent anymore
213 if line =~ '\\begin{.*}'
214 if line !~ g:tex_noindent_env
215 let ind = ind + shiftwidth()
216 let stay = 0
217 endif
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100218
219 if g:tex_indent_items
220 " Add another sw for item-environments
221 if line =~ g:tex_itemize_env
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200222 let ind = ind + shiftwidth()
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100223 let stay = 0
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100224 endif
225 endif
226 endif
227
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100228 if cline =~ '\\end{.*}'
229 let retn = s:GetEndIndentation(v:lnum)
230 if retn != -1
231 return retn
232 endif
233 end
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100234 " Subtract a 'shiftwidth' when an environment ends
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100235 if cline =~ '\\end{.*}'
236 \ && cline !~ g:tex_noindent_env
237 \ && cline !~ '\\begin{.*}.*\\end{.*}'
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100238 if g:tex_indent_items
239 " Remove another sw for item-environments
240 if cline =~ g:tex_itemize_env
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200241 let ind = ind - shiftwidth()
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100242 let stay = 0
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100243 endif
244 endif
245
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200246 let ind = ind - shiftwidth()
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100247 let stay = 0
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100248 endif
249
250 if g:tex_indent_brace
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200251 if line =~ '[[{]$'
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200252 let ind += shiftwidth()
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100253 let stay = 0
254 endif
255
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200256 if cline =~ '^\s*\\\?[\]}]' && s:CheckPairedIsLastCharacter(v:lnum, indent(v:lnum))
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200257 let ind -= shiftwidth()
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100258 let stay = 0
259 endif
260
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200261 if line !~ '^\s*\\\?[\]}]'
262 for i in range(indent(lnum)+1, strlen(line)-1)
263 let char = line[i]
264 if char == ']' || char == '}'
265 if s:CheckPairedIsLastCharacter(lnum, i)
266 let ind -= shiftwidth()
267 let stay = 0
268 endif
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100269 endif
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200270 endfor
271 endif
Bram Moolenaar61d35bd2012-03-28 20:51:51 +0200272 endif
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100273
274 " Special treatment for 'item'
275 " ----------------------------
276
277 if g:tex_indent_items
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100278 " '\item' or '\bibitem' itself:
279 if cline =~ g:tex_items
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200280 let ind = ind - shiftwidth()
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100281 let stay = 0
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100282 endif
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100283 " lines following to '\item' are intented once again:
284 if line =~ g:tex_items
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200285 let ind = ind + shiftwidth()
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100286 let stay = 0
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100287 endif
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100288 endif
289
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200290 if stay && mode() == 'i'
291 " If there is no obvious indentation hint, and indentation is triggered
292 " in insert mode, we trust our user.
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100293 if empty(cline)
294 return ind
295 else
296 return max([indent(v:lnum), s:GetLastBeginIndentation(v:lnum)])
297 endif
298 else
299 return ind
300 endif
301endfunction "}}}
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200302
303function! s:GetLastBeginIndentation(lnum) " {{{
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100304 let matchend = 1
305 for lnum in range(a:lnum-1, max([a:lnum - g:tex_max_scan_line, 1]), -1)
306 let line = getline(lnum)
307 if line =~ '\\end{.*}'
308 let matchend += 1
309 endif
310 if line =~ '\\begin{.*}'
311 let matchend -= 1
312 endif
313 if matchend == 0
Bram Moolenaar7db25fe2018-05-13 00:02:36 +0200314 if line =~ g:tex_noindent_env
315 return indent(lnum)
316 endif
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200317 if line =~ g:tex_itemize_env
318 return indent(lnum) + 2 * shiftwidth()
319 endif
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200320 return indent(lnum) + shiftwidth()
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100321 endif
322 endfor
323 return -1
324endfunction
325
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200326function! s:GetEndIndentation(lnum) " {{{
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100327 if getline(a:lnum) =~ '\\begin{.*}.*\\end{.*}'
328 return -1
329 endif
330
331 let min_indent = 100
332 let matchend = 1
333 for lnum in range(a:lnum-1, max([a:lnum-g:tex_max_scan_line, 1]), -1)
334 let line = getline(lnum)
335 if line =~ '\\end{.*}'
336 let matchend += 1
337 endif
338 if line =~ '\\begin{.*}'
339 let matchend -= 1
340 endif
341 if matchend == 0
342 return indent(lnum)
343 endif
344 if !empty(line)
345 let min_indent = min([min_indent, indent(lnum)])
346 endif
347 endfor
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200348 return min_indent - shiftwidth()
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100349endfunction
350
351" Most of the code is from matchparen.vim
352function! s:CheckPairedIsLastCharacter(lnum, col) "{{{
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100353 let c_lnum = a:lnum
354 let c_col = a:col+1
355
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200356 let line = getline(c_lnum)
357 if line[c_col-1] == '\'
358 let c_col = c_col + 1
359 endif
360 let c = line[c_col-1]
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100361
Bram Moolenaar328da0d2016-03-04 22:22:32 +0100362 let plist = split(&matchpairs, '.\zs[:,]')
363 let i = index(plist, c)
364 if i < 0
365 return 0
366 endif
367
368 " Figure out the arguments for searchpairpos().
369 if i % 2 == 0
370 let s_flags = 'nW'
371 let c2 = plist[i + 1]
372 else
373 let s_flags = 'nbW'
374 let c2 = c
375 let c = plist[i - 1]
376 endif
377 if c == '['
378 let c = '\['
379 let c2 = '\]'
380 endif
381
382 " Find the match. When it was just before the cursor move it there for a
383 " moment.
384 let save_cursor = winsaveview()
385 call cursor(c_lnum, c_col)
386
387 " When not in a string or comment ignore matches inside them.
388 " We match "escape" for special items, such as lispEscapeSpecial.
389 let s_skip ='synIDattr(synID(line("."), col("."), 0), "name") ' .
390 \ '=~? "string\\|character\\|singlequote\\|escape\\|comment"'
391 execute 'if' s_skip '| let s_skip = 0 | endif'
392
393 let stopline = max([0, c_lnum - g:tex_max_scan_line])
394
395 " Limit the search time to 300 msec to avoid a hang on very long lines.
396 " This fails when a timeout is not supported.
397 try
398 let [m_lnum, m_col] = searchpairpos(c, '', c2, s_flags, s_skip, stopline, 100)
399 catch /E118/
400 endtry
401
402 call winrestview(save_cursor)
403
404 if m_lnum > 0
405 let line = getline(m_lnum)
406 return strlen(line) == m_col
407 endif
408
409 return 0
Bram Moolenaareb3dc872018-05-13 22:34:24 +0200410endfunction "}}}
411
Bram Moolenaarb6b046b2011-12-30 13:11:27 +0100412let &cpo = s:cpo_save
413unlet s:cpo_save
414
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100415" vim: set sw=4 textwidth=80: