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: 1.0.0 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" 2018/02/07 by Yichao Zhou <broken.zhou AT gmail.com> 66" (*) Make indentation more smart in the normal mode 67" 68" }}} 69 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 125if exists("b:did_indent") 126 finish 127endif 128 129let s:cpo_save = &cpo 130set cpo&vim 131 132" Define global variable {{{ 133 134let b:did_indent = 1 135 136if !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 142if !exists("g:tex_max_scan_line") 143 let g:tex_max_scan_line = 60 144endif 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') 150 let g:tex_items = '\\bibitem\|\\item' 151 endif 152else 153 let g:tex_items = '' 154endif 155 156if !exists("g:tex_noindent_env") 157 let g:tex_noindent_env = 'document\|verbatim\|lstlisting' 158endif "}}} 159 160" VIM Setting " {{{ 161setlocal autoindent 162setlocal nosmartindent 163setlocal indentexpr=GetTeXIndent() 164setlocal indentkeys& 165exec 'setlocal indentkeys+=[,(,{,),},],\&' . substitute(g:tex_items, '^\|\(\\|\)', ',=', 'g') 166let g:tex_items = '^\s*' . substitute(g:tex_items, '^\(\^\\s\*\)*', '', '') 167" }}} 168 169function! GetTeXIndent() " {{{ 170 " Find a non-blank line above the current line. 171 let lnum = prevnonblank(v:lnum - 1) 172 let cnum = v:lnum 173 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 181 return 0 182 endif 183 184 let line = substitute(getline(lnum), '\s*%.*', '','g') " last line 185 let cline = substitute(getline(v:lnum), '\s*%.*', '', 'g') " current line 186 187 " 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 195 196 if lnum == 0 197 return 0 198 endif 199 200 let ind = indent(lnum) 201 let stay = 1 202 203 " New code for comment: retain the indent of current line 204 if cline =~ '^\s*%' 205 return indent(v:lnum) 206 endif 207 208 " 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 218 219 if g:tex_indent_items 220 " Add another sw for item-environments 221 if line =~ g:tex_itemize_env 222 let ind = ind + shiftwidth() 223 let stay = 0 224 endif 225 endif 226 endif 227 228 if cline =~ '\\end{.*}' 229 let retn = s:GetEndIndentation(v:lnum) 230 if retn != -1 231 return retn 232 endif 233 end 234 " Subtract a 'shiftwidth' when an environment ends 235 if cline =~ '\\end{.*}' 236 \ && cline !~ g:tex_noindent_env 237 \ && cline !~ '\\begin{.*}.*\\end{.*}' 238 if g:tex_indent_items 239 " Remove another sw for item-environments 240 if cline =~ g:tex_itemize_env 241 let ind = ind - shiftwidth() 242 let stay = 0 243 endif 244 endif 245 246 let ind = ind - shiftwidth() 247 let stay = 0 248 endif 249 250 if g:tex_indent_brace 251 if line =~ '[[{]$' 252 let ind += shiftwidth() 253 let stay = 0 254 endif 255 256 if cline =~ '^\s*\\\?[\]}]' && s:CheckPairedIsLastCharacter(v:lnum, indent(v:lnum)) 257 let ind -= shiftwidth() 258 let stay = 0 259 endif 260 261 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 269 endif 270 endfor 271 endif 272 endif 273 274 " Special treatment for 'item' 275 " ---------------------------- 276 277 if g:tex_indent_items 278 " '\item' or '\bibitem' itself: 279 if cline =~ g:tex_items 280 let ind = ind - shiftwidth() 281 let stay = 0 282 endif 283 " lines following to '\item' are intented once again: 284 if line =~ g:tex_items 285 let ind = ind + shiftwidth() 286 let stay = 0 287 endif 288 endif 289 290 if stay && mode() == 'i' 291 " If there is no obvious indentation hint, and indentation is triggered 292 " in insert mode, we trust our user. 293 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 "}}} 302 303function! s:GetLastBeginIndentation(lnum) " {{{ 304 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 314 if line =~ g:tex_noindent_env 315 return indent(lnum) 316 endif 317 if line =~ g:tex_itemize_env 318 return indent(lnum) + 2 * shiftwidth() 319 endif 320 return indent(lnum) + shiftwidth() 321 endif 322 endfor 323 return -1 324endfunction 325 326function! s:GetEndIndentation(lnum) " {{{ 327 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 348 return min_indent - shiftwidth() 349endfunction 350 351" Most of the code is from matchparen.vim 352function! s:CheckPairedIsLastCharacter(lnum, col) "{{{ 353 let c_lnum = a:lnum 354 let c_col = a:col+1 355 356 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] 361 362 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 410endfunction "}}} 411 412let &cpo = s:cpo_save 413unlet s:cpo_save 414 415" vim: set sw=4 textwidth=80: 416