Hi All,

I just updated the mail.vim syntax file to include syntax folding. It
now supports folding away quoted text, headers, and signatures.

Does someone have comments? Issues are as follows:

    1. Someone who has fdm=syntax will start composing new mail with all
       text folded away (his signature, header, and quoted text). I
       presume this is useless. I avoid this by putting an autocommand
       that sets fdc=3 and fdl=9 for mail files. But perhaps this should
       be done by default in the ftplugin file, if the user has
       fdm=syntax.

    2. Bram uses expression folding: I attach the snipped he sent to me
       (off list). Perhaps this should go into the default ftplugin
       file, and add documentation saying mail can be folded by
       syntax/expression etc.

    3. Would be nice to have the important header fields unfolded. But
       that would involve splitting the header into multiple regions,
       which might or might not be desirable.

GI

-- 
A plateau is a high form of flattery.
" Vim syntax file
" Language:             Mail file
" Previous Maintainer:  Felix von Leitner <[EMAIL PROTECTED]>
" Maintainer:           Gautam Iyer <[EMAIL PROTECTED]>
" Last Change:          Fri 07 Nov 2008 11:22:29 PM PST

" Quit when a syntax file was already loaded
if exists("b:current_syntax")
  finish
endif

" The mail header is recognized starting with a "keyword:" line and ending
" with an empty line or other line that can't be in the header. All lines of
" the header are highlighted. Headers of quoted messages (quoted with >) are
" also highlighted.

" Syntax clusters
syn cluster mailHeaderFields    
contains=mailHeaderKey,mailSubject,mailHeaderEmail,@mailLinks
syn cluster mailLinks           contains=mailURL,mailEmail
syn cluster mailQuoteExps       
contains=mailQuoteExp1,mailQuoteExp2,mailQuoteExp3,mailQuoteExp4,mailQuoteExp5,mailQuoteExp6

syn case match
" For "From " matching case is required. The "From " is not matched in quoted
" emails
" According to RFC 2822 any printable ASCII character can appear in a field
" name, except ':'.
syn region      mailHeader      [EMAIL PROTECTED],@NoSpell start="^From 
.*\d\d\d\d$" skip="^\s" end="\v^[!-9;-~]*([^!-~]|$)"me=s-1 fold
syn match       mailHeaderKey   contained contains=mailEmail,@NoSpell 
"^From\s.*\d\d\d\d$"

" Nothing else depends on case. 
syn case ignore

" Headers in properly quoted (with "> " or ">") emails are matched
syn region      mailHeader      keepend [EMAIL 
PROTECTED],@mailQuoteExps,@NoSpell start="^\z(\(> 
\?\)*\)\v(newsgroups|x-([a-z\-])*|path|xref|message-id|from|((in-)?reply-)?to|b?cc|subject|return-path|received|date|replied):"
 skip="^\z1\s" end="\v^\z1[!-9;-~]*([^!-~]|$)"me=s-1 end="[EMAIL 
PROTECTED]"me=s-1 end="\v^\z1(\> ?)+"me=s-1 fold

" Usenet headers
syn match       mailHeaderKey   contained 
contains=mailHeaderEmail,mailEmail,@NoSpell "\v(^(\> 
?)*)@<=(Newsgroups|Followup-To|Message-ID|Supersedes|Control):.*$"


syn region      mailHeaderKey   contained 
contains=mailHeaderEmail,mailEmail,@mailQuoteExps,@NoSpell start="\v(^(\> 
?)*)@<=(to|b?cc):" skip=",$" end="$"
syn match       mailHeaderKey   contained 
contains=mailHeaderEmail,mailEmail,@NoSpell "\v(^(\> ?)*)@<=(from|reply-to):.*$"
syn match       mailHeaderKey   contained [EMAIL PROTECTED] "\v(^(\> 
?)*)@<=date:"
syn match       mailSubject     contained "\v^subject:.*$"
syn match       mailSubject     contained [EMAIL PROTECTED] "\v(^(\> 
?)+)@<=subject:.*$"

" Anything in the header between < and > is an email address
syn match       mailHeaderEmail contained [EMAIL PROTECTED] "<.\{-}>"

" Mail Signatures. (Begin with "-- ", end with change in quote level)
syn region      mailSignature   keepend [EMAIL PROTECTED],@mailQuoteExps 
start="^--\s$" end="^$" end="^\(> \?\)\+"me=s-1 fold
syn region      mailSignature   keepend contained [EMAIL 
PROTECTED],@mailQuoteExps,@NoSpell start="^\z(\(\([a-z]\+>\|[]|}>]\)[ 
\t]*\)\+\)--\s$" end="^\z1[ \t]*\([a-z]\+>\|[]|}>]\)"me=s-1 end="[EMAIL 
PROTECTED]"me=s-1 end="^\z1$" fold

" Treat verbatim Text special.
syn region      mailVerbatim    [EMAIL PROTECTED] keepend start="^#v+$" 
end="^#v-$" fold 
syn region      mailVerbatim    keepend contained [EMAIL PROTECTED],@NoSpell 
start="^\z(\(> \?\)\+\)#v+$" start="^\z(\(\([a-z]\+>\|[]|}>]\)[ \t]*\)\+\)#v+$" 
end="^\z1[ \t]*\([a-z]\+>\|[]|}>]\)"me=s-1 end="[EMAIL PROTECTED]"me=s-1 
end="^\z1#v-$" fold 

" URLs start with a known protocol or www,web,w3.
syn match mailURL [EMAIL PROTECTED] 
`\v<(((https?|ftp|gopher)://|(mailto|file|news):)[^'        
<>"]+|(www|web|w3)[a-z0-9_-]*\.[a-z0-9._-]+\.[^'        <>"]+)[a-z0-9/]`
syn match mailEmail [EMAIL PROTECTED] "\v[_=a-z\./[EMAIL PROTECTED]"

" Make sure quote markers in regions (header / signature) have correct color
"syn match mailQuoteExp1        contained "\v^(\> ?)"
"syn match mailQuoteExp2        contained "\v^(\> ?){2}"
"syn match mailQuoteExp3        contained "\v^(\> ?){3}"
"syn match mailQuoteExp4        contained "\v^(\> ?){4}"
"syn match mailQuoteExp5        contained "\v^(\> ?){5}"
"syn match mailQuoteExp6        contained "\v^(\> ?){6}"

syn match mailQuoteExp1 contained "\(\([a-z]\+>\|[]|}>]\)[ \t]*\)"
syn match mailQuoteExp2 contained "\(\([a-z]\+>\|[]|}>]\)[ \t]*\)\{2}"
syn match mailQuoteExp3 contained "\(\([a-z]\+>\|[]|}>]\)[ \t]*\)\{3}"
syn match mailQuoteExp4 contained "\(\([a-z]\+>\|[]|}>]\)[ \t]*\)\{4}"
syn match mailQuoteExp5 contained "\(\([a-z]\+>\|[]|}>]\)[ \t]*\)\{5}"
syn match mailQuoteExp6 contained "\(\([a-z]\+>\|[]|}>]\)[ \t]*\)\{6}"

" Even and odd quoted lines. Order is important here!
syn region      mailQuoted6     keepend 
contains=mailVerbatim,mailHeader,@mailLinks,mailSignature,@NoSpell 
start="^\z(\(\([a-z]\+>\|[]|}>]\)[ \t]*\)\{5}\([a-z]\+>\|[]|}>]\)\)" 
end="[EMAIL PROTECTED]" fold
syn region      mailQuoted5     keepend 
contains=mailQuoted6,mailVerbatim,mailHeader,@mailLinks,mailSignature,@NoSpell 
start="^\z(\(\([a-z]\+>\|[]|}>]\)[ \t]*\)\{4}\([a-z]\+>\|[]|}>]\)\)" 
end="[EMAIL PROTECTED]" fold
syn region      mailQuoted4     keepend 
contains=mailQuoted5,mailQuoted6,mailVerbatim,mailHeader,@mailLinks,mailSignature,@NoSpell
 start="^\z(\(\([a-z]\+>\|[]|}>]\)[ \t]*\)\{3}\([a-z]\+>\|[]|}>]\)\)" 
end="[EMAIL PROTECTED]" fold
syn region      mailQuoted3     keepend 
contains=mailQuoted4,mailQuoted5,mailQuoted6,mailVerbatim,mailHeader,@mailLinks,mailSignature,@NoSpell
 start="^\z(\(\([a-z]\+>\|[]|}>]\)[ \t]*\)\{2}\([a-z]\+>\|[]|}>]\)\)" 
end="[EMAIL PROTECTED]" fold
syn region      mailQuoted2     keepend 
contains=mailQuoted3,mailQuoted4,mailQuoted5,mailQuoted6,mailVerbatim,mailHeader,@mailLinks,mailSignature,@NoSpell
 start="^\z(\(\([a-z]\+>\|[]|}>]\)[ \t]*\)\{1}\([a-z]\+>\|[]|}>]\)\)" 
end="[EMAIL PROTECTED]" fold
syn region      mailQuoted1     keepend 
contains=mailQuoted2,mailQuoted3,mailQuoted4,mailQuoted5,mailQuoted6,mailVerbatim,mailHeader,@mailLinks,mailSignature,@NoSpell
 start="^\z([a-z]\+>\|[]|}>]\)" end="[EMAIL PROTECTED]" fold

" Need to sync on the header. Assume we can do that within 100 lines
if exists("mail_minlines")
    exec "syn sync minlines=" . mail_minlines
else
    syn sync minlines=100
endif

" Define the default highlighting.
hi def link mailVerbatim        Special
hi def link mailHeader          Statement
hi def link mailHeaderKey       Type
hi def link mailSignature       PreProc
hi def link mailHeaderEmail     mailEmail
hi def link mailEmail           Special
hi def link mailURL             String
hi def link mailSubject         LineNR
hi def link mailQuoted1         Comment
hi def link mailQuoted3         mailQuoted1
hi def link mailQuoted5         mailQuoted1
hi def link mailQuoted2         Identifier
hi def link mailQuoted4         mailQuoted2
hi def link mailQuoted6         mailQuoted2
hi def link mailQuoteExp1       mailQuoted1
hi def link mailQuoteExp2       mailQuoted2
hi def link mailQuoteExp3       mailQuoted3
hi def link mailQuoteExp4       mailQuoted4
hi def link mailQuoteExp5       mailQuoted5
hi def link mailQuoteExp6       mailQuoted6

let b:current_syntax = "mail"
" Bram's code for expression folding of mail.

func! MailFoldLevel(lnum)
  " fold level for quoted text depends on the quoting level
  let line = getline(a:lnum)
  if line =~ '^\s*[>}]'
    let line = substitute(line, '#', '', 'g')
    let line = substitute(line, '\s*[>}]', '#', 'g')
    let line = substitute(line, '[^#].*', '', '')
    return len(line)
  endif

  if a:lnum > 200
    return 0
  endif
  if line =~ '^\s'
    return '='
  endif
  let syn = synIDattr(synID(a:lnum, 1, 0), "name")
  if syn == 'mailHeader' || line =~? '^message-id:'
    return 20
  endif
  return 0
endfunc

setl foldmethod=expr
setl foldexpr=MailFoldLevel(v:lnum)
setl foldlevel=1

Attachment: pgpdKKERJRgxM.pgp
Description: PGP signature

Reply via email to