tex.vim 13 KB

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