File: folding.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 (546 lines) | stat: -rw-r--r-- 17,892 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
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
"=============================================================================
" 	     File: folding.vim
"      Author: Srinath Avadhanula
"      		   modifications/additions by Zhang Linbo, Gerd Wachsmuth
"     Created: Tue Apr 23 05:00 PM 2002 PST
" 
"  Description: functions to interact with Syntaxfolds.vim
"=============================================================================

nnoremap <Plug>Tex_RefreshFolds :call MakeTexFolds(1, 1)<cr>

augroup LatexSuite
	au LatexSuite User LatexSuiteFileType 
		\ call Tex_Debug('folding.vim: catching LatexSuiteFileType', 'fold') | 
		\ call Tex_SetFoldOptions()
augroup END

" Tex_SetFoldOptions: sets maps for every buffer {{{
" Description: 
function! Tex_SetFoldOptions()
	if exists('b:doneSetFoldOptions')
		return
	endif
	let b:doneSetFoldOptions = 1

	setlocal foldtext=TexFoldTextFunction()

	if g:Tex_Folding
		call MakeTexFolds(0, 0)
	endif

	let s:ml = '<Leader>'

	call Tex_MakeMap(s:ml."rf", "<Plug>Tex_RefreshFolds", 'n', '<silent> <buffer>')

	" Setup a local autocommand, if FileChangedShellPost is available
	if exists('##FileChangedShellPost')
		augroup LatexSuite
			autocmd FileChangedShellPost <buffer> call MakeTexFolds(1, 0)
		augroup END
	endif

endfunction " }}}
" Tex_FoldSections: creates section folds {{{
" Description:
" 	This function takes a comma seperated list of "sections" and creates fold
" 	definitions for them. The first item is supposed to be the "shallowest" field
" 	and the last is the "deepest". See g:Tex_FoldedSections for the default
" 	definition of the lst input argument.
"
" 	**works recursively**
function! Tex_FoldSections(lst, endpat)
	let i = match(a:lst, ',')
	if i > 0
		let s = strpart(a:lst, 0, i)
	else
		let s = a:lst
	endif
	if s =~ '%%fakesection'
		let s = '^\s*' . s
	else
		let pattern = ''
		let prefix = ''
		for label in split( s, "|" )
			let pattern .= prefix . '\\' . label . '\|' . '%%fake' . label
			let prefix = '\|'
		endfor
		" The line before the pattern could contain a mixture of "% =_" (within a
		" comment).
		" The pattern itself is ended by a non-word character "\W" or a newline.
		let s = '^\%(%[% =-]*\n\)\?\s*' . '\%(' . pattern . '\)' . '\%(\W\|\n\)'
	endif
	let endpat = s . '\|' . a:endpat
	if i > 0
		call Tex_FoldSections(strpart(a:lst,i+1), endpat)
	endif
	call AddSyntaxFoldItem(s, endpat, 0, -1)
endfunction
" }}}
" MakeTexFolds: function to create fold items for latex. {{{
"
" used in conjunction with MakeSyntaxFolds().
" see ../plugin/syntaxFolds.vim for documentation
function! MakeTexFolds(force, manual)
	if exists('g:Tex_Folding') && !g:Tex_Folding
		return
	endif
	if &ft != 'tex'
		return
	end

	" Setup folded items lists g:Tex_Foldedxxxx
	" 	1. Use default value if g:Tex_Foldedxxxxxx is not defined
	" 	2. prepend default value to g:Tex_Foldedxxxxxx if it starts with ','
	" 	3. append default value to g:Tex_Foldedxxxxxx if it ends with ','

	" Folding items which are not caught in any of the standard commands,
	" environments or sections.
	let s = 'item,slide,preamble,<<<'
	if !exists('g:Tex_FoldedMisc')
		let g:Tex_FoldedMisc = s
	elseif g:Tex_FoldedMisc[0] == ','
		let g:Tex_FoldedMisc = s . g:Tex_FoldedMisc
	elseif g:Tex_FoldedMisc =~ ',$'
		let g:Tex_FoldedMisc = g:Tex_FoldedMisc . s
	endif

	" By default do not fold any commands. It looks like trying to fold
	" commands is a difficult problem since commands can be arbitrarily nested
	" and the end patterns are not unique unlike the case of environments.
	" For this to work well, we need a regexp which will match a line only if
	" a command begins on that line but does not end on that line. This
	" requires a regexp which will match unbalanced curly braces and that is
	" apparently not doable with regexps.
	let s = ''
	if !exists('g:Tex_FoldedCommands')
		let g:Tex_FoldedCommands = s
	elseif g:Tex_FoldedCommands[0] == ','
		let g:Tex_FoldedCommands = s . g:Tex_FoldedCommands
	elseif g:Tex_FoldedCommands =~ ',$'
		let g:Tex_FoldedCommands = g:Tex_FoldedCommands . s
	endif

	let s = 'verbatim,comment,eq,gather,align,figure,table,thebibliography,'
			\. 'keywords,abstract,titlepage'
	if !exists('g:Tex_FoldedEnvironments')
		let g:Tex_FoldedEnvironments = s
	elseif g:Tex_FoldedEnvironments[0] == ','
		let g:Tex_FoldedEnvironments = s . g:Tex_FoldedEnvironments
	elseif g:Tex_FoldedEnvironments =~ ',$'
		let g:Tex_FoldedEnvironments = g:Tex_FoldedEnvironments . s
	endif
	
	if !exists('g:Tex_FoldedSections')
		let g:Tex_FoldedSections = 'part,chapter,section,'
								\. 'subsection,subsubsection,paragraph'
	endif

	" the order in which these calls are made decides the nestedness. in
	" latex, a table environment will always be embedded in either an item or
	" a section etc. not the other way around. so we first fold up all the
	" tables. and then proceed with the other regions.

	let b:numFoldItems = 0

	" ========================================================================
	" How to add new folding items {{{
	" ========================================================================
	"
	" Each of the following function calls defines a syntax fold region. Each
	" definition consists of a call to the AddSyntaxFoldItem() function.
	" 
	" The order in which the folds are defined is important. Juggling the
	" order of the function calls will create havoc with folding. The
	" "deepest" folding item needs to be called first. For example, if
	" the \begin{table} environment is a subset (or lies within) the \section
	" environment, then add the definition for the \table first.
	"
	" The AddSyntaxFoldItem() function takes either 4 or 6 arguments. When it
	" is called with 4 arguments, it is equivalent to calling it with 6
	" arguments with the last two left blank (i.e as empty strings)
	"
	" The explanation for each argument is as follows:
	"    startpat: a line matching this pattern defines the beginning of a fold.
	"    endpat  : a line matching this pattern defines the end of a fold.
	"    startoff: this is the offset from the starting line at which folding will
	"              actually start
	"    endoff  : like startoff, but gives the offset of the actual fold end from
	"              the line satisfying endpat.
	"              startoff and endoff are necessary when the folding region does
	"              not have a specific end pattern corresponding to a start
	"              pattern. for example in latex,
	"              \begin{section}
	"              defines the beginning of a section, but its not necessary to
	"              have a corresponding
	"              \end{section}
	"              the section is assumed to end 1 line _before_ another section
	"              starts.
	"    startskip: a pattern which defines the beginning of a "skipped" region.
	"
	"               For example, suppose we define a \itemize fold as follows:
	"               startpat =  '^\s*\\item',
	"               endpat = '^\s*\\item\|^\s*\\end{\(enumerate\|itemize\|description\)}',
	"               startoff = 0,
	"               endoff = -1
	"
	"               This defines a fold which starts with a line beginning with an
	"               \item and ending one line before a line beginning with an
	"               \item or \end{enumerate} etc.
	"
	"               Then, as long as \item's are not nested things are fine.
	"               However, once items begin to nest, the fold started by one
	"               \item can end because of an \item in an \itemize
	"               environment within this \item. i.e, the following can happen:
	"
	"               \begin{itemize}
	"               \item Some text <------- fold will start here
	"                     This item will contain a nested item
	"                     \begin{itemize} <----- fold will end here because next line contains \item...
	"                     \item Hello
	"                     \end{itemize} <----- ... instead of here.
	"               \item Next item of the parent itemize
	"               \end{itemize}
	"
	"               Therefore, in order to completely define a folding item which
	"               allows nesting, we need to also define a "skip" pattern.
	"               startskip and end skip do that.
	"               Leave '' when there is no nesting.
	"    endskip: the pattern which defines the end of the "skip" pattern for
	"             nested folds.
	"
	"    Example: 
	"    1. A syntax fold region for a latex section is
	"           startpat = "\\section{"
	"           endpat   = "\\section{"
	"           startoff = 0
	"           endoff   = -1
	"           startskip = ''
	"           endskip = ''
	"    Note that the start and end patterns are thus the same and endoff has a
	"    negative value to capture the effect of a section ending one line before
	"    the next starts.
	"    2. A syntax fold region for the \itemize environment is:
	"           startpat = '^\s*\\item',
	"           endpat = '^\s*\\item\|^\s*\\end{\(enumerate\|itemize\|description\)}',
	"           startoff = 0,
	"           endoff = -1,
	"           startskip = '^\s*\\begin{\(enumerate\|itemize\|description\)}',
	"           endskip = '^\s*\\end{\(enumerate\|itemize\|description\)}'
	"     Note the use of startskip and endskip to allow nesting.
	"
	"
	" }}}
	" ========================================================================
	
	" {{{ comment lines
	if g:Tex_FoldedMisc =~ '\<comments\>'
		call AddSyntaxFoldItem (
			\ '^%\([^%]\|[^f]\|[^a]\|[^k]\|[^e]\)',
			\ '^[^%]',
			\ 0,
			\ -1 
			\ )
	endif
	" }}}

	" {{{ items
	if g:Tex_FoldedMisc =~ '\<item\>'
		call AddSyntaxFoldItem (
			\ '^\s*\\item',
			\ '^\s*\\item\|^\s*\\end{\(enumerate\|itemize\|description\)}',
			\ 0,
			\ -1,
			\ '^\s*\\begin{\(enumerate\|itemize\|description\)}',
			\ '^\s*\\end{\(enumerate\|itemize\|description\)}'
			\ )
	endif
	" }}}

	" {{{ title
	if g:Tex_FoldedMisc =~ '\<title\>'
		call AddSyntaxFoldItem (
			\ '^\s*\\title\W',
			\ '^\s*\\maketitle',
			\ 0,
			\ 0
			\ )
	endif
	" }}}
 
	" Commands and Environments {{{
	" Fold the commands and environments in 2 passes.
	let pass = 0
	while pass < 2
		if pass == 0
			let lst = g:Tex_FoldedCommands
		else
			let lst = g:Tex_FoldedEnvironments
		endif
		while lst != ''
			let i = match(lst, ',')
			if i > 0
				let s = strpart(lst, 0, i)
				let lst = strpart(lst, i+1)
			else
				let s = lst
				let lst = ''
			endif
			if s != ''
				if pass == 0
					" NOTE: This pattern ensures that a command which is
					" terminated on the same line will not start a fold.
					" However, it will also refuse to fold certain commands
					" which have not terminated. eg:
					" 	\commandname{something \textbf{text} and
					" will _not_ start a fold.
					" In other words, the pattern is safe, but not exact.
					call AddSyntaxFoldItem('^\s*\\'.s.'{[^{}]*$','^[^}]*}',0,0)
				else
					if s =~ 'itemize\|enumerate\|description'
						" These environments can nest.
						call AddSyntaxFoldItem('^\s*\\begin{'.s,'\(^\|\s\)\s*\\end{'.s,0,0,'^\s*\\begin{'.s,'\(^\|\s\)\s*\\end{'.s)
					else
						call AddSyntaxFoldItem('^\s*\\begin{'.s,'\(^\|\s\)\s*\\end{'.s,0,0,'','')
					endif
				endif
			endif
		endwhile
		let pass = pass + 1
	endwhile
	" }}}

	" Sections {{{
	if g:Tex_FoldedSections != '' 
		call Tex_FoldSections(g:Tex_FoldedSections,
			\ '^\s*\\\%(frontmatter\|mainmatter\|backmatter\)\|'
			\. '^\s*\\begin{thebibliography\|^\s*\\endinput\|'
			\. '^\s*\\begin{slide\|^\s*\\\%(begin\|end\){document\|'
			\. '^\s*\\\%(\%(begin\|end\){appendix}\|appendix\)')
	endif
	" }}} 
	
	" {{{ slide
	if g:Tex_FoldedMisc =~ '\<slide\>'
		call AddSyntaxFoldItem (
			\ '^\s*\\begin{slide',
			\ '^\s*\\appendix\W\|^\s*\\chapter\W\|^\s*\\end{slide\|^\s*\\end{document',
			\ 0,
			\ 0
			\ )
	endif
	" }}}

	" {{{ preamble
	if g:Tex_FoldedMisc =~ '\<preamble\>'
		call AddSyntaxFoldItem (
			\ '^\s*\\document\(class\|style\).*{',
			\ '^\s*\\begin{document}',
			\ 0,
			\ -1 
			\ )
	endif
	" }}}

	" Manually folded regions {{{
	if g:Tex_FoldedMisc =~ '\(^\|,\)<<<\(,\|$\)'
		call AddSyntaxFoldItem (
			\ '<<<',
			\ '>>>',
			\ 0,
			\ 0
			\ )
	endif
	" }}}
	
	call MakeSyntaxFolds(a:force)

	" Open all folds if this function was triggered automatically
	" and g:Tex_AutoFolding is disabled
	if !a:manual && !g:Tex_AutoFolding
		normal! zR
	endif
endfunction

" }}}
" TexFoldTextFunction: create fold text for folds {{{
function! TexFoldTextFunction()
	" The dashes indicating the foldlevel together with
	" the number of lines are aligned to width '7'.
	let lines = v:foldend - v:foldstart + 1
	let myfoldtext = repeat('-', v:foldlevel-1) . '+'
				\. repeat(' ', 7-(v:foldlevel-1)-len(lines))
				\. lines . ' lines: '

	" Add some indent per foldlevel
	let myfoldtext .= repeat('> ', v:foldlevel-1)

	if getline(v:foldstart) =~ '^\s*\\begin{'
		let header = matchstr(getline(v:foldstart),
							\ '^\s*\\begin{\zs\([:alpha:]*\)[^}]*\ze}')
		let title = ''
		let caption = ''
		let label = ''
		let i = v:foldstart
		while i <= v:foldend
			if getline(i) =~ '\\caption'
				" distinguish between
				" \caption{fulldesc} - fulldesc will be displayed
				" \caption[shortdesc]{fulldesc} - shortdesc will be displayed
				if getline(i) =~ '\\caption\['
					let caption = matchstr(getline(i), '\\caption\[\zs[^\]]*')
					let caption = substitute(caption, '\zs\]{.*}[^}]*$', '', '')
				else
					let caption = matchstr(getline(i), '\\caption{\zs.*')
					let caption = substitute(caption, '\zs}[^}]*$', '', '')
				end
			elseif getline(i) =~ '\\label'
				let label = matchstr(getline(i), '\\label{\zs.*')
				" :FIXME: this does not work when \label contains a
				" newline or a }-character
				let label = substitute(label, '\([^}]*\)}.*$', '\1', '')
			elseif header =~ 'frame' && getline(i) =~ '\\begin{frame}.*{[^{}]*}\|\\frametitle\|%'
				if getline(i) =~ '\\begin{frame}'
					" The first argument inside {} is the frame title (the
					" second one is a subtitle)
					let title = matchstr(getline(i), '\\begin{frame}.\{-}{\zs[^{}]*\ze}')
				elseif getline(i) =~ '\\frametitle'
					let title = matchstr(getline(i), '\\frametitle{\zs[^}]*\ze}')
				elseif getline(i) =~ '%' && title == ''
					let title = substitute(getline(i), '^\(\s\|%\)*', '', '')
				endif
			end

			let i = i + 1
		endwhile

		if header =~ 'frame'
			if title == ''
				let title = getline(v:foldstart + 1)
			end
			" Count frames
			let frnum = 0
			for line in getline(1,v:foldstart)
				if line =~ '\\begin{frame}'
					let frnum=frnum+1
				endif
			endfor
			" Pad with spaces to length 2
			let frnum = repeat(' ', 2-len(frnum)) . frnum
			return myfoldtext . ': Frame ' . frnum . ': ' . title
		end

		" if no caption found, then use the second line.
		if caption == ''
			let caption = getline(v:foldstart + 1)
		end

		return myfoldtext . header.  ' ('.label.'): '.caption

	elseif getline(v:foldstart) =~ '^\s*%\+[% =-]*$'
		" Useless comment. Use the next line.
		return myfoldtext . getline(v:foldstart+1)
	elseif getline(v:foldstart) =~ '^\s*%%fake'
		" Just strip one '%' from the fakesection.
		return myfoldtext . substitute(getline(v:foldstart), '^\s*%%fake', '%', '')
	elseif getline(v:foldstart) =~ '^\s*%'
		" It's any other comment. Use it.
		return myfoldtext . getline(v:foldstart)
	elseif getline(v:foldstart) =~ '^\s*\\document\(class\|style\).*{'
		" This is the preamble.
		return myfoldtext . 'Preamble: ' . getline(v:foldstart)
	end

	let section_pattern = substitute(g:Tex_FoldedSections, ',\||', '\\|', 'g')
	let section_pattern = '\\\%(' . section_pattern .'\)\>'

	if getline(v:foldstart) =~ '^\s*' . section_pattern
		" This is a section. Search for the content of the mandatory argument {...}
		let type = matchstr(getline(v:foldstart), '^\s*\zs' . section_pattern)
		return myfoldtext . type . s:ParseSectionTitle(v:foldstart, section_pattern)
	else
		" This is something.
		return myfoldtext . getline(v:foldstart)
	end
endfunction
" }}}
" s:ParseSectionTitle: create fold text for sections {{{
" Search for the mandatory argument of the \section command and ignore the
" optional argument.
function! s:ParseSectionTitle(foldstart, section_pattern)
	let currlinenr = a:foldstart
	let currline = s:StripLine(getline(currlinenr))
	let currlinelen = strlen(currline)

	" Look for the section title after the section macro
	let index = match(currline, '^\s*' . a:section_pattern . '\zs')

	let maxlines = 10

	" Current depth of nested [] and {}:
	let currdepth = 0
	" Do we have found the mandatory argument?
	" (We are looking for '{' at depth 0)
	let found_mandatory = 0

	let string = ''

	while (currdepth > 0) || !found_mandatory
		if index >= currlinelen
			" Read a new line.
			let maxlines = maxlines - 1
			if maxlines < 0
				return string . ' Scanned too many lines'
			endif
			let currlinenr = currlinenr + 1
			let currline = s:StripLine(getline(currlinenr))
			let currlinelen = strlen(currline)

			let index = 0

			if found_mandatory
				let string .= ' '
			endif
			continue
		endif

		" Look for [] and {} at current position
		if currline[index] =~ '[[{]'
			if(currdepth == 0) && (currline[index] =~ '{')
				let found_mandatory = 1
			end
			let currdepth += 1
		elseif currline[index] =~ '[]}]'
			let currdepth -= 1
		endif

		" Look for the next interesting character
		let next_index = match( currline, '[{}[\]]', index + 1 )
		if next_index == -1
			let next_index = currlinelen + 1
		endif

		" Update the string
		if found_mandatory
			let string .= currline[index:next_index-1]
		endif
		let index = next_index
	endwhile

	return string
endfunction
" }}}
" s:StripLine: strips whitespace and comments {{{
function! s:StripLine( string )
	let string = matchstr( a:string, '^\s*\zs.*$')
	let comment = match( string, '\\\@<!\%(\\\\\)*\zs%')
	if comment > 0
		let string = string[0:comment-1]
	elseif comment == 0
		let string = ''
	endif
	return string
endfunction
" }}}

" vim:fdm=marker:ff=unix:noet:ts=4:sw=4