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
" }}}
|