File: tex.vim

package info (click to toggle)
vim-latexsuite 1%3A1.10.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 5,424 kB
  • sloc: xml: 5,159; python: 906; makefile: 92; perl: 59; sh: 14
file content (388 lines) | stat: -rw-r--r-- 11,253 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
" Vim indent file
"
" Options: {{{
"
" The options are mostly compatible with the indent/tex.vim distributed by
" vim.
" Here, we have one new option: g:tex_indent_ifelsefi
"
" To set the following options, add a line like
"   let g:tex_indent_items = 1
" to your ~/ftplugin/tex.vim.
"
"
" * g:tex_indent_brace = 1
"
"   If this variable is unset or non-zero, it will use smartindent-like style
"   for "{}", "[]" and "()".
"
"
" * g:tex_indent_items = 1
"
"   If this variable is set, item-environments are indented like Emacs does
"   it, i.e., continuation lines are indented with a shiftwidth.
"
"              set                                unset
"   ----------------------------------------------------------------
"       \begin{itemize}                      \begin{itemize}
"         \item blablabla                      \item blablabla
"           bla bla bla                        bla bla bla
"         \item blablabla                      \item blablabla
"           bla bla bla                        bla bla bla
"       \end{itemize}                        \end{itemize}
"
"
" * g:tex_items = '\\bibitem\|\\item'
"
"   A list of tokens to be considered as commands for the beginning of an item
"   command. The tokens should be separated with '\|'. The initial '\' should
"   be escaped.
"
"
" * g:tex_itemize_env = 'itemize\|description\|enumerate\|thebibliography'.
"
"   A list of environment names, separated with '\|', where the items (item
"   commands matching g:tex_items) may appear.
"
"
" * g:tex_noindent_env = 'document\|verbatim\|comment\|lstlisting'
"
"   A list of environment names. separated with '\|', where no indentation is
"   required.
"
"
" * g:tex_indent_ifelsefi = 1
"
"   If this is set to one, we try to indent something like
"   \ifnum...
"     bar
"   \else
"     foo
"   \fi
"   correctly. This is quite tough, since there are commands like
"   \ifthenelse{condition}{then}{else}, which uses braces instead of \else and
"   \fi. Our heuristic: only add indentation, if \if... is not followed by a
"   '{', (and only if \if,\else,\or,\fi occur at the beginning of the line).
"
" }}}

if exists('b:suppress_latex_suite') && b:suppress_latex_suite == 1
	finish
endif

if exists("b:did_indent")
	finish
endif
if v:version < 700
	echohl WarningMsg
	echo "Indentation of latex-suite requires vim version >= 700.\n"
				\ . "Fallback to default indentation."
	echohl None
	finish
endif
let b:did_indent = 1

" Check whether the options exist and assign default values
if !exists("g:tex_indent_brace")
	let g:tex_indent_brace = 1
endif
if !exists("g:tex_indent_items")
	let g:tex_indent_items = 1
endif
if !exists('g:tex_items')
	let g:tex_items = '\\bibitem\|\\item'
endif
if !exists("g:tex_itemize_env")
	let g:tex_itemize_env = 'itemize\|description\|enumerate\|thebibliography'
endif
if !exists("g:tex_noindent_env")
	let g:tex_noindent_env = 'document\|verbatim\|comment\|lstlisting'
endif
if !exists("g:tex_indent_ifelsefi")
	let g:tex_indent_ifelsefi = 1
endif

setlocal autoindent
setlocal nosmartindent
setlocal indentexpr=Tex_CalcIdent()
setlocal indentkeys+=},],.,)

" Cache {{{
" Internally, the indentation uses a cache for precompiled patterns
" and the last indented line. However, the cache cannot be used, if the
" options have changed.
"
" CacheOptions: puts options into a list {{{
function! s:CacheOptions()
	return [
				\ g:tex_indent_brace,
				\ g:tex_indent_items,
				\ g:tex_items,
				\ g:tex_itemize_env,
				\ g:tex_noindent_env,
				\ g:tex_indent_ifelsefi,
				\ ]
endfunction
" }}}
" SetCache: Remembers the options used to set up the cache. {{{
function! s:SetCache()
	let s:cache_options = s:CacheOptions()
endfunction
" }}}
" CanUseCache: Can we use the cache? {{{
function! s:CanUseCache()
	return s:cache_options == s:CacheOptions()
endfunction
" }}}
" Initialize the cache {{{
let s:cache_options = []
" }}}
" }}}

" Function DeepestNesting:   compute indentation of a line {{{
" This function computes the deepest/smallest nesting on the current line. We
" start with 0, each match of openregexp increases nesting and each match of
" closeregexp decreases nesting.
" The return value is the deepest indentation of the current line and the
" additional indentation which should be used for the next line.
" Parameters:
"   line              This string should be indented
"
" All the regexps should be able to be combined via \|, preferably single
" atoms (enclose them in '\%(', '\)'!)
function! s:DeepestNesting(line)
	let indent = 0
	let pos = 0

	let deepest = 0

	" Now, we look through the line for matching patterns
	while pos >= 0
		" Look for the next match of one of the patterns.

		" Do we have the function matchstrpos() (introduced in version 7.4.1684)?
		if exists('*matchstrpos')
			" Here, we explicitly use the 'count' option of 'matchstrpos' such that
			" '^' matches only at the beginning of the string (and not at 'pos')
			let strpos = matchstrpos( a:line, s:all, pos, 1 )
			let pos = strpos[2]
			let str = strpos[0]
		else
			" Here, we explicitly use the 'count' option of 'match'/'matchend' such that
			" '^' matches only at the beginning of the string (and not at 'pos')
			" Does not work with version < 7
			let start = match( a:line, s:all, pos, 1 )
			if start < 0
				" No more matches were found.
				break
			end
			let pos = matchend( a:line, s:all, start, 1 )
			let str = a:line[ start : pos-1 ]
		end

		if pos <= 0
			" No more matches were found.
			break
		endif

		" Check which pattern has matched
		if str =~ '^' . s:openextraregexp . '$'
			let indent += 2
		elseif str =~ '^' . s:closeextraregexp . '$'
			let indent -= 2
		elseif str =~ '^' . s:openregexp . '$'
			let indent += 1
		elseif str =~ '^' . s:closeregexp . '$'
			let indent -= 1
		else
			" For a hanging line, do not alter indent,
			" but possibly update the deepest indentation
			let deepest = min([deepest, indent - 1])
		endif

		" Update deepest indentation
		let deepest = min([deepest, indent])
	endwhile

	return [deepest, indent - deepest]
endfunction
" }}}
" Function AssemblePatterns: pre-compute patterns{{{
" This function uses the options to assemble various patterns. These patterns
" do not depend on the line which is indented and can be pre-computed.
" This function also sets option-dependent indentkeys
" Description Of Patterns:
"   openregexp        Causes 1 indentation more
"   closeregexp       Causes 1 indentation less
"   openextraregexp   Causes 2 indentations more
"   closeextraregexp  Causes 2 indentations less
"   hangingregexp     Only this line has 1 indentation less
function! s:AssemblePatterns()
	" Add a 'shiftwidth' after beginning
	" and subtract a 'shiftwidth' after the end of environments.
	" Don't add it for \begin{document} and \begin{verbatim}, see
	" g:tex_noindent_env
	let open = '\\begin\s*{\%('.g:tex_noindent_env.'\)\@!.\{-\}}'
	let close = '\\end\s*{\%('.g:tex_noindent_env.'\)\@!.\{-\}}'

	if g:tex_indent_brace
		let open  = open  . '\|[[{(]\|\\left\.'
		let close = close . '\|[]})]\|\\right\.'
	endif

	if g:tex_indent_items
		" For itemize-like environments: add or subtract two 'shiftwidth'
		let s:openextraregexp  = '\\begin\s*{\%('.g:tex_itemize_env.'\)\*\?}'
		let s:closeextraregexp = '\\end\s*{\%('.g:tex_itemize_env.'\)\*\?}'

		" Special treatment for items, they will hang
		let hanging = g:tex_items
	else
		" Extra environment indentation
		let s:openextraregexp  = ''
		let s:closeextraregexp = ''

		" No hanging expression
		let hanging = ''
	endif

	if g:tex_indent_ifelsefi
		" Do match '\if..' only if it is not followed by '{'
		" Require \fi, and \if... only at beginning of line,
		" otherwise,
		"     \newif\ifbarfoo
		" would be indented.
		" Expection: If a line starts with '\if...' and
		" contains an '\fi', it is not indented, e.g.:
		"     \ifbarfoo\foobaz\fi
		" Exception: '\expandafter\ifx\csname barfoo \endcsname'
		" is quite common and indented.
		let open .= '\|^\s*\%(\\expandafter\)\?\\if\a*\>{\@!\%(.*\\fi\)\@!'
		let close .= '\|^\s*\\fi\>'
		let elseor = '\\else\>\|\\or\>'
		if hanging != ''
			let hanging = elseor . '\|' . hanging
		else
			let hanging = elseor
		end
	end

	" Wrap open and close in parentheses
	let s:openregexp  = '\%(' . open  . '\)'
	let s:closeregexp = '\%(' . close . '\)'

	" Wrap hanging in parentheses, match only at beginning of line
	let s:hangingregexp = '^\s*\%(' . hanging . '\)'

	" Accumulate all patterns.
	let s:all = ''
	if s:openregexp != ''
		let s:all .= '\|' . s:openregexp
	endif
	if s:closeregexp != ''
		let s:all .= '\|' . s:closeregexp
	endif
	if s:openextraregexp != ''
		let s:all .= '\|' . s:openextraregexp
	endif
	if s:closeextraregexp != ''
		let s:all .= '\|' . s:closeextraregexp
	endif
	if s:hangingregexp != ''
		let s:all .= '\|' . s:hangingregexp
	endif
	if s:all == ''
		" No expressions given. Replace by a regexp which matches nowhere
		let s:all = '\_$.'
	else
		" Strip the first '\|'
		let s:all = s:all[2:]
	end


	" Add indentkeys depending on options
	let items_keys = substitute(g:tex_items, '^\|\(\\|\)', ',0=', 'g')
	if g:tex_indent_items
		exec 'setlocal indentkeys+=' . items_keys
	else
		exec 'setlocal indentkeys-=' . items_keys
	endif

	let ifelsefi_keys = '0=\\else,0=\\or,0=\\fi'
	if g:tex_indent_ifelsefi
		exec 'setlocal indentkeys+=' . ifelsefi_keys
	else
		exec 'setlocal indentkeys-=' . ifelsefi_keys
	endif
endfunction
" }}}
" Function Tex_CalcIndent:   to be used as indentexpr {{{
" This function can be used as indentexpr.
function! Tex_CalcIdent()
	" Check whether we can use the cache
	let can_use_cache = s:CanUseCache()
	call s:SetCache()

	if !can_use_cache
		call s:AssemblePatterns()
	endif

	" Current line number
	let clnum = v:lnum

	" Code for comment: If current line is a comment, do not alter the
	" indentation
	let cline = getline(clnum) " Content of current line
	if cline =~ '^\s*%'
		return indent(clnum)
	endif

	" Strip comments
	let cline = substitute(cline, '\\\@<!\(\\\\\)*\zs%.*', '', '')
	" Strip leading whitespace
	let cline = substitute(cline, '^\s*', '', '')

	" Find a non-blank line above the current line, which is more than a comment.
	let plnum = prevnonblank(clnum - 1)
	while plnum != 0
		if getline(plnum) !~ '^\s*%'
			break
		endif
		let plnum = prevnonblank(plnum - 1)
	endwhile

	" At the start of the file use zero indent.
	if plnum == 0
		return 0
	endif

	" Current indentation of previous line
	let pind = indent(plnum)
	" Content of previous line
	let pline = getline(plnum)
	" Strip comments
	let pline = substitute(pline, '\\\@<!\(\\\\\)*\zs%.*', '', '')
	" Strip leading whitespace
	let pline = substitute(pline, '^\s*', '', '')

	" Compute the deepest indentation on the current line
	let cindent = s:DeepestNesting( cline )

	" Compute the offset to the deepest indentation from the previous line
	if can_use_cache && s:cache_lnum == plnum && s:cache_line ==# pline
		let pindent = s:cache_indent
	else
		let pindent = s:DeepestNesting( pline )
	endif

	" Cache the result of the current line
	let s:cache_lnum   = clnum
	let s:cache_indent = cindent
	let s:cache_line   = cline

	" Add one shiftwidth per indentation level
	let ind = pind + &shiftwidth * ( cindent[0] + pindent[1] )

	return ind
endfunction
" }}}