1" 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: 0.9.4 6" Please email me if you found something I can do. Comments, bug report and 7" feature request are welcome. 8 9" Last Update: {{{ 10" 25th Sep 2002, by LH : 11" (*) 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 '%' 15" 2005/06/15, Moshe Kaminsky <kaminsky AT math.huji.ac.il> 16" (*) New variables: 17" g:tex_items, g:tex_itemize_env, g:tex_noindent_env 18" 2011/3/6, by Yichao Zhou <broken.zhou AT gmail.com> 19" (*) 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 24" 2011/9/25, by Yichao Zhou <broken.zhou AT gmail.com> 25" (*) Bug fix: smartindent-like indent for "[]" 26" (*) New features: Align with "&". 27" (*) New variable: g:tex_indent_and. 28" 2011/10/23 by Yichao Zhou <broken.zhou AT gmail.com> 29" (*) Bug fix: improve the smartindent-like indent for "{}" and 30" "[]". 31" 2012/02/27 by Yichao Zhou <broken.zhou AT gmail.com> 32" (*) Bug fix: support default folding marker. 33" (*) Indent with "&" is not very handy. Make it not enable by 34" default. 35" 2012/03/06 by Yichao Zhou <broken.zhou AT gmail.com> 36" (*) 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" 41" 2012/03/11 by Yichao Zhou <broken.zhou AT gmail.com> 42" (*) Modify "&" so that only indent when current line start with 43" "&". 44" 2012/03/12 by Yichao Zhou <broken.zhou AT gmail.com> 45" (*) Modify indentkeys. 46" 2012/03/18 by Yichao Zhou <broken.zhou AT gmail.com> 47" (*) Add &cpo 48" 2013/05/02 by Yichao Zhou <broken.zhou AT gmail.com> 49" (*) Fix problem about GetTeXIndent checker. Thank Albert Netymk 50" for reporting this. 51" 2014/06/23 by Yichao Zhou <broken.zhou AT gmail.com> 52" (*) 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. 57" 2014/08/03 by Yichao Zhou <broken.zhou AT gmail.com> 58" (*) Indent current line if last line has larger indentation 59" 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" 66" }}} 67 68" Document: {{{ 69" 70" To set the following options (ok, currently it's just one), add a line like 71" let g:tex_indent_items = 1 72" to your ~/.vimrc. 73" 74" * g:tex_indent_brace 75" 76" If this variable is unset or non-zero, it will use smartindent-like style 77" for "{}" and "[]". Now this only works if the open brace is the last 78" character of that line. 79" 80" % Example 1 81" \usetikzlibrary{ 82" external 83" } 84" 85" % Example 2 86" \tikzexternalize[ 87" prefix=tikz] 88" 89" * g:tex_indent_items 90" 91" If this variable is set, item-environments are indented like Emacs does 92" it, i.e., continuation lines are indented with a shiftwidth. 93" 94" NOTE: I've already set the variable below; delete the corresponding line 95" if you don't like this behaviour. 96" 97" Per default, it is unset. 98" 99" set unset 100" ---------------------------------------------------------------- 101" \begin{itemize} \begin{itemize} 102" \item blablabla \item blablabla 103" bla bla bla bla bla bla 104" \item blablabla \item blablabla 105" bla bla bla bla bla bla 106" \end{itemize} \end{itemize} 107" 108" 109" * g:tex_items 110" 111" A list of tokens to be considered as commands for the beginning of an item 112" command. The tokens should be separated with '\|'. The initial '\' should 113" be escaped. The default is '\\bibitem\|\\item'. 114" 115" * g:tex_itemize_env 116" 117" A list of environment names, separated with '\|', where the items (item 118" commands matching g:tex_items) may appear. The default is 119" 'itemize\|description\|enumerate\|thebibliography'. 120" 121" * g:tex_noindent_env 122" 123" A list of environment names. separated with '\|', where no indentation is 124" required. The default is 'document\|verbatim'. 125" }}} 126 127" Only define the function once 128if exists("b:did_indent") 129 finish 130endif 131 132let s:cpo_save = &cpo 133set cpo&vim 134 135" Define global variable {{{ 136 137let b:did_indent = 1 138 139if !exists("g:tex_indent_items") 140 let g:tex_indent_items = 1 141endif 142if !exists("g:tex_indent_brace") 143 let g:tex_indent_brace = 1 144endif 145if !exists("g:tex_max_scan_line") 146 let g:tex_max_scan_line = 60 147endif 148if g:tex_indent_items 149 if !exists("g:tex_itemize_env") 150 let g:tex_itemize_env = 'itemize\|description\|enumerate\|thebibliography' 151 endif 152 if !exists('g:tex_items') 153 let g:tex_items = '\\bibitem\|\\item' 154 endif 155else 156 let g:tex_items = '' 157endif 158 159if !exists("g:tex_noindent_env") 160 let g:tex_noindent_env = 'document\|verbatim\|lstlisting' 161endif "}}} 162 163" VIM Setting " {{{ 164setlocal autoindent 165setlocal nosmartindent 166setlocal indentexpr=GetTeXIndent() 167setlocal indentkeys& 168exec 'setlocal indentkeys+=[,(,{,),},],\&' . substitute(g:tex_items, '^\|\(\\|\)', ',=', 'g') 169let g:tex_items = '^\s*' . substitute(g:tex_items, '^\(\^\\s\*\)*', '', '') 170" }}} 171 172function! GetTeXIndent() " {{{ 173 " Find a non-blank line above the current line. 174 let lnum = prevnonblank(v:lnum - 1) 175 let cnum = v:lnum 176 177 " Comment line is not what we need. 178 while lnum != 0 && getline(lnum) =~ '^\s*%' 179 let lnum = prevnonblank(lnum - 1) 180 endwhile 181 182 " At the start of the file use zero indent. 183 if lnum == 0 184 return 0 185 endif 186 187 let line = substitute(getline(lnum), '\s*%.*', '','g') " last line 188 let cline = substitute(getline(v:lnum), '\s*%.*', '', 'g') " current line 189 190 " We are in verbatim, so do what our user what. 191 if synIDattr(synID(v:lnum, indent(v:lnum), 1), "name") == "texZone" 192 if empty(cline) 193 return indent(lnum) 194 else 195 return indent(v:lnum) 196 end 197 endif 198 199 if lnum == 0 200 return 0 201 endif 202 203 let ind = indent(lnum) 204 let stay = 1 205 206 " New code for comment: retain the indent of current line 207 if cline =~ '^\s*%' 208 return indent(v:lnum) 209 endif 210 211 " Add a 'shiftwidth' after beginning of environments. 212 " Don't add it for \begin{document} and \begin{verbatim} 213 " if line =~ '^\s*\\begin{\(.*\)}' && line !~ 'verbatim' 214 " LH modification : \begin does not always start a line 215 " ZYC modification : \end after \begin won't cause wrong indent anymore 216 if line =~ '\\begin{.*}' 217 if line !~ g:tex_noindent_env 218 let ind = ind + shiftwidth() 219 let stay = 0 220 endif 221 222 if g:tex_indent_items 223 " Add another sw for item-environments 224 if line =~ g:tex_itemize_env 225 let ind = ind + shiftwidth() 226 let stay = 0 227 endif 228 endif 229 endif 230 231 if cline =~ '\\end{.*}' 232 let retn = s:GetEndIndentation(v:lnum) 233 if retn != -1 234 return retn 235 endif 236 end 237 " Subtract a 'shiftwidth' when an environment ends 238 if cline =~ '\\end{.*}' 239 \ && cline !~ g:tex_noindent_env 240 \ && cline !~ '\\begin{.*}.*\\end{.*}' 241 if g:tex_indent_items 242 " Remove another sw for item-environments 243 if cline =~ g:tex_itemize_env 244 let ind = ind - shiftwidth() 245 let stay = 0 246 endif 247 endif 248 249 let ind = ind - shiftwidth() 250 let stay = 0 251 endif 252 253 if g:tex_indent_brace 254 if line =~ '[[{]$' 255 let ind += shiftwidth() 256 let stay = 0 257 endif 258 259 if cline =~ '^\s*\\\?[\]}]' && s:CheckPairedIsLastCharacter(v:lnum, indent(v:lnum)) 260 let ind -= shiftwidth() 261 let stay = 0 262 endif 263 264 if line !~ '^\s*\\\?[\]}]' 265 for i in range(indent(lnum)+1, strlen(line)-1) 266 let char = line[i] 267 if char == ']' || char == '}' 268 if s:CheckPairedIsLastCharacter(lnum, i) 269 let ind -= shiftwidth() 270 let stay = 0 271 endif 272 endif 273 endfor 274 endif 275 endif 276 277 " Special treatment for 'item' 278 " ---------------------------- 279 280 if g:tex_indent_items 281 " '\item' or '\bibitem' itself: 282 if cline =~ g:tex_items 283 let ind = ind - shiftwidth() 284 let stay = 0 285 endif 286 " lines following to '\item' are intented once again: 287 if line =~ g:tex_items 288 let ind = ind + shiftwidth() 289 let stay = 0 290 endif 291 endif 292 293 if stay 294 " If there is no obvious indentation hint, we trust our user. 295 if empty(cline) 296 return ind 297 else 298 return max([indent(v:lnum), s:GetLastBeginIndentation(v:lnum)]) 299 endif 300 else 301 return ind 302 endif 303endfunction "}}} 304 305function! s:GetLastBeginIndentation(lnum) " {{{ 306 let matchend = 1 307 for lnum in range(a:lnum-1, max([a:lnum - g:tex_max_scan_line, 1]), -1) 308 let line = getline(lnum) 309 if line =~ '\\end{.*}' 310 let matchend += 1 311 endif 312 if line =~ '\\begin{.*}' 313 let matchend -= 1 314 endif 315 if matchend == 0 316 if line =~ g:tex_noindent_env 317 return indent(lnum) 318 endif 319 if line =~ g:tex_itemize_env 320 return indent(lnum) + 2 * shiftwidth() 321 endif 322 return indent(lnum) + shiftwidth() 323 endif 324 endfor 325 return -1 326endfunction 327 328function! s:GetEndIndentation(lnum) " {{{ 329 if getline(a:lnum) =~ '\\begin{.*}.*\\end{.*}' 330 return -1 331 endif 332 333 let min_indent = 100 334 let matchend = 1 335 for lnum in range(a:lnum-1, max([a:lnum-g:tex_max_scan_line, 1]), -1) 336 let line = getline(lnum) 337 if line =~ '\\end{.*}' 338 let matchend += 1 339 endif 340 if line =~ '\\begin{.*}' 341 let matchend -= 1 342 endif 343 if matchend == 0 344 return indent(lnum) 345 endif 346 if !empty(line) 347 let min_indent = min([min_indent, indent(lnum)]) 348 endif 349 endfor 350 return min_indent - shiftwidth() 351endfunction 352 353" Most of the code is from matchparen.vim 354function! s:CheckPairedIsLastCharacter(lnum, col) "{{{ 355 let c_lnum = a:lnum 356 let c_col = a:col+1 357 358 let line = getline(c_lnum) 359 if line[c_col-1] == '\' 360 let c_col = c_col + 1 361 endif 362 let c = line[c_col-1] 363 364 let plist = split(&matchpairs, '.\zs[:,]') 365 let i = index(plist, c) 366 if i < 0 367 return 0 368 endif 369 370 " Figure out the arguments for searchpairpos(). 371 if i % 2 == 0 372 let s_flags = 'nW' 373 let c2 = plist[i + 1] 374 else 375 let s_flags = 'nbW' 376 let c2 = c 377 let c = plist[i - 1] 378 endif 379 if c == '[' 380 let c = '\[' 381 let c2 = '\]' 382 endif 383 384 " Find the match. When it was just before the cursor move it there for a 385 " moment. 386 let save_cursor = winsaveview() 387 call cursor(c_lnum, c_col) 388 389 " When not in a string or comment ignore matches inside them. 390 " We match "escape" for special items, such as lispEscapeSpecial. 391 let s_skip ='synIDattr(synID(line("."), col("."), 0), "name") ' . 392 \ '=~? "string\\|character\\|singlequote\\|escape\\|comment"' 393 execute 'if' s_skip '| let s_skip = 0 | endif' 394 395 let stopline = max([0, c_lnum - g:tex_max_scan_line]) 396 397 " Limit the search time to 300 msec to avoid a hang on very long lines. 398 " This fails when a timeout is not supported. 399 try 400 let [m_lnum, m_col] = searchpairpos(c, '', c2, s_flags, s_skip, stopline, 100) 401 catch /E118/ 402 endtry 403 404 call winrestview(save_cursor) 405 406 if m_lnum > 0 407 let line = getline(m_lnum) 408 return strlen(line) == m_col 409 endif 410 411 return 0 412endfunction "}}} 413 414let &cpo = s:cpo_save 415unlet s:cpo_save 416 417" vim: set sw=4 textwidth=80: 418