tex.vim 14 KB

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