Vim Tips Wiki
(rewording, deleting redundancy, adding to explanation)
(allow shorthand with try...catch, minor improvement to try...catch, and adding new problems these rules suffer)
Line 85: Line 85:
 
syn region VimFoldTryContainer
 
syn region VimFoldTryContainer
 
\ start="\<try\>"
 
\ start="\<try\>"
\ end="\<endtry\>"
+
\ end="\<endt\%[ry]\>"
 
\ skip=/"[^"]\{-\}\("\|$\)/
 
\ skip=/"[^"]\{-\}\("\|$\)/
 
\ transparent
 
\ transparent
Line 94: Line 94:
 
syn region VimFoldTry
 
syn region VimFoldTry
 
\ start="\<try\>"
 
\ start="\<try\>"
\ end="\s*catch\>"ms=s-1,me=s-1
+
\ end="\s*\(fina\%[lly]\|cat\%[ch]\)\>"ms=s-1,me=s-1
 
\ skip=/"[^"]\{-\}\("\|$\)/
 
\ skip=/"[^"]\{-\}\("\|$\)/
 
\ fold transparent
 
\ fold transparent
Line 102: Line 102:
 
\ contains=TOP
 
\ contains=TOP
 
syn region VimFoldCatch
 
syn region VimFoldCatch
\ start="\<catch\>"
+
\ start="\<cat\%[ch]\>"
\ end="\s*\(finally\|catch\)\>"ms=s-1,me=s-1
+
\ end="\s*\(cat\%[ch]\|fina\%[lly]\)\>"ms=s-1,me=s-1
 
\ skip=/"[^"]\{-\}\("\|$\)/
 
\ skip=/"[^"]\{-\}\("\|$\)/
 
\ fold transparent
 
\ fold transparent
Line 111: Line 111:
 
\ contains=TOP
 
\ contains=TOP
 
syn region VimFoldFinally
 
syn region VimFoldFinally
\ start="\<finally\>"
+
\ start="\<fina\%[lly]\>"
\ end="\s*endtry\>"
+
\ end="\<endt\%[ry]\>"
 
\ skip=/"[^"]\{-\}\("\|$\)/
 
\ skip=/"[^"]\{-\}\("\|$\)/
 
\ fold transparent
 
\ fold transparent
Line 133: Line 133:
   
 
These syntax folds are not quite perfect, and suffer from at least the following:
 
These syntax folds are not quite perfect, and suffer from at least the following:
*Sometimes, especially when commenting out an "else", you will need to type '''<tt>:syn sync fromstart</tt>''' to update folds; you may want to map this command to a key.
+
*Sometimes, especially when deleting or commenting out an "else", "catch", or "finally", you will need to type '''<tt>:syn sync fromstart</tt>''' to update folds. You may want to map this command to a key if you need to do it often.
 
*Only limited support for comments and strings. The "skip" group could probably be improved; currently, it will skip anything between two " characters or anything after a single " character.
 
*Only limited support for comments and strings. The "skip" group could probably be improved; currently, it will skip anything between two " characters or anything after a single " character.
  +
*Some keywords (such as "else" and "catch") must be preceded by nothing but whitespace to properly trigger fold behavior; this may be an issue depending on coding style.
  +
*Because so many of these regions end with an "end<blah>", some shorthand endings (like "en" for "endif") will not work. "\%[]" groups are used when possible to allow as many shorthand keywords as possible, but you should specify at least as many characters to make the keyword unambiguous to a search pattern.
   
 
==References==
 
==References==

Revision as of 15:51, 6 December 2007

Previous TipNext Tip

Tip: #1376 - Syntax folding of Vim scripts

Created: November 3, 2006 5:42 Complexity: intermediate Author: Ingo Karkat Version: 6.0 Karma: 18/6 Imported from: Tip#1376

Many syntax files provide fold information. Unfortunately, the vimscript syntax file does not. You will need to define your own syntax folding, or resign yourself to inserting fold markers all over the place (which, incidentally, the vim.vim syntax file does). Here is a good set of syntax folding definitions that you can at least use as a starting point.

The following code allows folding of various Vim script constructs via foldmethod=syntax. Put the following text into 'after/syntax/vim.vim', located either in your system-wide or home Vim directory (see :help after-directory).

Use setlocal foldmethod=syntax to use these folds, in an autocommand or a mapping.

" The default Vim syntax file lacks the 'fold' definitions, so define them.

" fold functions
syn region VimFold
      \ start="\<fu\%[nction]!\=\s\+\(<[sS][iI][dD]>\|[Ss]:\|\u\)\i*\ze\s*("
      \ end="\<endfu\%[nction]\>"
      \ skip=/"[^"]\{-\}\("\|$\)/
      \ transparent fold
      \ keepend extend
      \ containedin=TOP,vimComment,vimLineComment,vimCommentString,vimString

" fold while loops
syn region VimFold
      \ start="\<wh\%[ile]\>"
      \ end="\<endw\%[hile]\>"
      \ skip=/"[^"]\{-\}\("\|$\)/
      \ transparent fold
      \ keepend extend
      \ containedin=TOP,vimComment,vimLineComment,vimCommentString,vimString

" fold for loops
syn region VimFold
      \ start="\<for\>"
      \ end="\<endfo\%[r]\>"
      \ skip=/"[^"]\{-\}\("\|$\)/
      \ transparent fold
      \ keepend extend
      \ containedin=TOP,vimComment,vimLineComment,vimCommentString,vimString

" fold augroups
syn region VimFold
      \ start="\<aug\%[roup]\ze\s\+\(END\>\)\@!"
      \ end="\<aug\%[roup]\s\+END\>"
      \ skip=/"[^"]\{-\}\("\|$\)/
      \ transparent fold
      \ keepend extend
      \ containedin=TOP,vimComment,vimLineComment,vimCommentString,vimString

" fold if...else...endif constructs
syn region VimFoldIfContainer
      \ start="\<if\>"
      \ end="\<endif\>"
      \ skip=/"[^"]\{-\}\("\|$\)/
      \ transparent
      \ keepend extend
      \ containedin=TOP,
      \   vimComment,vimLineComment,vimCommentString,vimString
      \ contains=NONE
syn region VimFoldIfBeg
      \ start="\<if\>"
      \ end="\s*else\%[if]\>"ms=s-1,me=s-1
      \ skip=/"[^"]\{-\}\("\|$\)/
      \ fold transparent
      \ keepend
      \ contained containedin=VimFoldIfContainer
      \ nextgroup=VimFoldIfEnd
      \ contains=TOP
syn region VimFoldIfEnd
      \ start="\s*else\%[if]\>"
      \ end="\<endif\>"
      \ skip=/"[^"]\{-\}\("\|$\)/
      \ fold transparent
      \ keepend
      \ contained containedin=VimFoldIfContainer
      \ contains=TOP

" fold try...catch...finally...endtry constructs
syn region VimFoldTryContainer
      \ start="\<try\>"
      \ end="\<endt\%[ry]\>"
      \ skip=/"[^"]\{-\}\("\|$\)/
      \ transparent
      \ keepend extend
      \ containedin=TOP,
      \   vimComment,vimLineComment,vimCommentString,vimString
      \ contains=NONE
syn region VimFoldTry
      \ start="\<try\>"
      \ end="\s*\(fina\%[lly]\|cat\%[ch]\)\>"ms=s-1,me=s-1
      \ skip=/"[^"]\{-\}\("\|$\)/
      \ fold transparent
      \ keepend
      \ contained containedin=VimFoldTryContainer
      \ nextgroup=VimFoldCatch,VimFoldFinally
      \ contains=TOP
syn region VimFoldCatch
      \ start="\<cat\%[ch]\>"
      \ end="\s*\(cat\%[ch]\|fina\%[lly]\)\>"ms=s-1,me=s-1
      \ skip=/"[^"]\{-\}\("\|$\)/
      \ fold transparent
      \ keepend
      \ contained containedin=VimFoldTryContainer
      \ nextgroup=VimFoldFinally
      \ contains=TOP
syn region VimFoldFinally
      \ start="\<fina\%[lly]\>"
      \ end="\<endt\%[ry]\>"
      \ skip=/"[^"]\{-\}\("\|$\)/
      \ fold transparent
      \ keepend
      \ contained containedin=VimFoldTryContainer
      \ contains=TOP

These syntax groups set up regions between start and end patterns as long as they don't start within a comment, and attempt to skip over commented-out end patterns with the skip pattern.

Most of the syntax rules have a simple "begin" and "end" keyword that set up a fold region normally, using "keepend" and "extend" to allow syntax highlighting of end markers and nesting, respectively.

The "if...else...endif" construct is a little different and works as follows:

  1. VimFoldIfContainer matches the entire if...endif region
  2. VimFoldIfBeg is only contained in VimFoldIfContainer, and matches if...else, then backs up the end of the region to allow another match on the else.
  3. VimFoldIfEnd is also only contained in a VimFoldIfContainer, and will match else...endif.
  4. Note that VimFoldIfBeg does not have the "extend" argument, meaning that even if the "else" does not match to end VimFoldBeg, it will not extend beyond the confines of the VimFoldIfContainer (which ends at "endif").

"try...catch" constructs work similarly to "if...else...endif" constructs.

These syntax folds are not quite perfect, and suffer from at least the following:

  • Sometimes, especially when deleting or commenting out an "else", "catch", or "finally", you will need to type :syn sync fromstart to update folds. You may want to map this command to a key if you need to do it often.
  • Only limited support for comments and strings. The "skip" group could probably be improved; currently, it will skip anything between two " characters or anything after a single " character.
  • Some keywords (such as "else" and "catch") must be preceded by nothing but whitespace to properly trigger fold behavior; this may be an issue depending on coding style.
  • Because so many of these regions end with an "end<blah>", some shorthand endings (like "en" for "endif") will not work. "\%[]" groups are used when possible to allow as many shorthand keywords as possible, but you should specify at least as many characters to make the keyword unambiguous to a search pattern.

References


Comments

Todo: fix problems mentioned.