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