aboutsummaryrefslogtreecommitdiff
path: root/vim/after/ftplugin/mail.vim
blob: f4a4c91da84ff43b5f38e887d5ec74394d94c671 (plain) (blame)
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
" Don't append spaces after quote chars, for strict compliance with
" format=flowed
let b:quote_space = 0
let b:undo_ftplugin .= '|unlet b:quote_space'

" If something hasn't already moved the cursor, we'll move to an optimal point
" to start writing
function! s:SuggestStart() abort

  " Move to top of buffer
  call setpos('.', [0, 1, 1, 0])

  " Move to body text
  call search('\m^$', 'c') | +

  " Start by trying to move to the first quoted line; this may fail if there's
  " no quote, which is fine
  call search('\m^>', 'c')

  " Delete quoted blank lines or quoted greetings until we get to something
  " with substance.  Yes, I like Perl, how could you tell?
  while getline('.') =~? '^> *'
        \ . '\%('
          \ . '\%('
            \ . 'g[''\u2019]\=day'
            \ . '\|\%(good \)\=\%(morning\|afternoon\|evening\)'
            \ . '\|h[eu]\%(ll\|rr\)o\+'
            \ . '\|hey\+'
            \ . '\|hi\+'
            \ . '\|sup'
            \ . '\|what[''\u2019]\=s up'
            \ . '\|yo'
          \ . '\)'
          \ . '[[:punct:] ]*'
          \ . '\%('
            \ . '\a\+'
            \ . '[[:punct:] ]*'
          \ . '\)\='
        \ . '\)\=$'
    delete
  endwhile

  " Now move to the first quoted or unquoted blank line
  call search('\m^>\= *$', 'c')
endfunction
command! -bar -buffer SuggestStart
      \ call s:SuggestStart()
let b:undo_ftplugin .= '|delcommand SuggestStart'
SuggestStart

" Normalise quoting
function! s:StrictQuote() abort
  let body = 0
  for lnum in range(1, line('$'))

    " Get current line
    let line = getline(lnum)

    " Skip lines until we hit a blank line, meaning body text
    let body = body || !strlen(line)
    if !body
      continue
    endif

    " Get the leading quote string, if any; skip if there isn't one
    let quote = matchstr(line, '^>[> ]*')
    if !strlen(quote)
      continue
    endif

    " Normalise the quote with no spaces
    let quote = substitute(quote, '[^>]', '', 'g')

    " Re-set the line
    let line = substitute(line, '^[> ]\+', quote, '')
    call setline(lnum, line)

  endfor
endfunction
command -bar -buffer StrictQuote
      \ call s:StrictQuote()
let b:undo_ftplugin .= '|delcommand StrictQuote'
StrictQuote

" Add a space to the end of wrapped lines for format-flowed mail
setlocal formatoptions+=w
let b:undo_ftplugin .= '|setlocal formatoptions<'

" Mail-specific handling for custom vim-squeeze-repeat-blanks plugin
if exists('loaded_squeeze_repeat_blanks')

  " Set the blank line pattern
  let b:squeeze_repeat_blanks_blank = '^[ >]*$'
  let b:undo_ftplugin .= '|unlet b:squeeze_repeat_blanks_blank'

  " If there is anything quoted in this message (i.e. it looks like a reply),
  " squeeze blanks, but don't report lines deleted
  if search('\m^>', 'cnw')
    silent SqueezeRepeatBlanks
  endif

endif

" Spellcheck documents we're actually editing (not just viewing)
if &modifiable && !&readonly
  setlocal spell
  let b:undo_ftplugin .= '|setlocal spell<'
endif

" Stop here if the user doesn't want ftplugin mappings
if exists('no_plugin_maps') || exists('no_mail_maps')
  finish
endif

" Flag messages as important/unimportant
nnoremap <buffer> <LocalLeader>h
      \ :<C-U>call mail#FlagImportant()<CR>
let b:undo_ftplugin .= '|nunmap <buffer> <LocalLeader>h'
nnoremap <buffer> <LocalLeader>l
      \ :<C-U>call mail#FlagUnimportant()<CR>
let b:undo_ftplugin .= '|nunmap <buffer> <LocalLeader>l'

" Quote operator
nnoremap <buffer> <expr> <LocalLeader>q
      \ quote#Quote()
xnoremap <buffer> <expr> <LocalLeader>q
      \ quote#Quote()
let b:undo_ftplugin .= '|nunmap <buffer> <LocalLeader>q'
      \ . '|xunmap <buffer> <LocalLeader>q'

" Quote operator with reformatting
nnoremap <buffer> <expr> <LocalLeader>Q
      \ quote#QuoteReformat()
xnoremap <buffer> <expr> <LocalLeader>Q
      \ quote#QuoteReformat()
let b:undo_ftplugin .= '|nunmap <buffer> <LocalLeader>Q'
      \ . '|xunmap <buffer> <LocalLeader>Q'

" Maps using autoloaded function for quoted paragraph movement
nnoremap <buffer> <silent> <LocalLeader>[
      \ :<C-U>call mail#NewBlank(v:count1, 1, 0)<CR>
nnoremap <buffer> <silent> <LocalLeader>]
      \ :<C-U>call mail#NewBlank(v:count1, 0, 0)<CR>
onoremap <buffer> <silent> <LocalLeader>[
      \ :<C-U>call mail#NewBlank(v:count1, 1, 0)<CR>
onoremap <buffer> <silent> <LocalLeader>]
      \ :<C-U>call mail#NewBlank(v:count1, 0, 0)<CR>
xnoremap <buffer> <silent> <LocalLeader>[
      \ :<C-U>call mail#NewBlank(v:count1, 1, 1)<CR>
xnoremap <buffer> <silent> <LocalLeader>]
      \ :<C-U>call mail#NewBlank(v:count1, 0, 1)<CR>
let b:undo_ftplugin .= '|nunmap <buffer> <LocalLeader>['
      \ . '|nunmap <buffer> <LocalLeader>]'
      \ . '|ounmap <buffer> <LocalLeader>['
      \ . '|ounmap <buffer> <LocalLeader>]'
      \ . '|xunmap <buffer> <LocalLeader>['
      \ . '|xunmap <buffer> <LocalLeader>]'