“================================================= ” File: vmail.vim “ Description: Vmail is a Vim interface to Gmail. ” Author: Daniel Choi “ ================================================
if exists(“g:loaded_vmail”) || &cp
finish
endif let g:loaded_vmail = 1
if !exists(“g:vmail_flagged_color”)
let g:vmail_flagged_color = "ctermfg=green guifg=green guibg=grey"
endif let s:mailbox = $VMAIL_MAILBOX let s:query = $VMAIL_QUERY let s:browser_command = $VMAIL_BROWSER let s:append_file = ''
let s:drb_uri = $DRB_URI
let s:client_script = “vmail_client ” . shellescape(s:drb_uri) . “ ” let s:set_window_width_command = s:client_script . “window_width= ” let s:list_mailboxes_command = s:client_script . “list_mailboxes ” let s:show_message_command = s:client_script . “show_message ” let s:update_command = s:client_script . “update” let s:fetch_headers_command = s:client_script . “fetch_headers ” let s:select_mailbox_command = s:client_script . “select_mailbox ” let s:search_command = s:client_script . “search ” let s:more_messages_command = s:client_script . “more_messages ” let s:flag_command = s:client_script . “flag ” let s:append_to_file_command = s:client_script . “append_to_file ” let s:move_to_command = s:client_script . “move_to ” let s:copy_to_command = s:client_script . “copy_to ” let s:new_message_template_command = s:client_script . “new_message_template ” let s:reply_template_command = s:client_script . “reply_template ” let s:forward_template_command = s:client_script . “forward_template ” let s:deliver_command = s:client_script . “deliver ” let s:save_attachments_command = s:client_script . “save_attachments ” let s:open_html_part_command = s:client_script . “open_html_part ” let s:show_help_command = s:client_script . “show_help”
let s:message_bufname = “current_message.txt”
function! VmailStatusLine()
return "%<%f\ " . s:mailbox . " " . s:query . "%r%=%-14.(%l,%c%V%)\ %Y %P"
endfunction
function! s:create_list_window()
setlocal nomodifiable setlocal noswapfile setlocal nowrap setlocal nonumber setlocal foldcolumn=0 setlocal nospell setlocal textwidth=0 setlocal noreadonly setlocal ft=vmailMessageList " let user set this " setlocal cursorline " we need the bufnr to find the window later let s:listbufnr = bufnr('%') let s:listbufname = bufname('%') setlocal statusline=%!VmailStatusLine() call s:message_list_window_mappings() autocmd BufNewFile,BufRead *.txt setlocal modifiable
endfunction
“ the message display buffer window function! s:create_message_window()
exec "split " . s:message_bufname setlocal modifiable setlocal buftype=nofile let s:message_window_bufnr = bufnr('%') call s:message_window_mappings() setlocal ft=mail close
endfunction
function! s:system_with_error_handling(command)
let res = system(a:command) if res =~ 'VMAIL_ERROR' echoe "ERROR" res return "" else return res end
endfunction
function! s:show_message(stay_in_message_list)
let line = getline(line(".")) if match(line, '^> Load') != -1 setlocal modifiable delete call s:more_messages() return endif let s:uid = shellescape(matchstr(line, '\S\+$')) if s:uid == "" return end " mark as read let newline = substitute(line, '^\V*+', '* ', '') let newline = substitute(newline, '^\V+ ', ' ', '') setlocal modifiable call setline(line('.'), newline) setlocal nomodifiable write " this just clears the command line and prevents the screen from " moving up when the next echo statement executes: " call feedkeys(":\<cr>") " redraw let command = s:show_message_command . s:uid echom "Loading message ". s:uid .". Please wait..." redrawstatus let res = s:system_with_error_handling(command) call s:focus_message_window() set modifiable 1,$delete put =res " critical: don't call execute 'normal \<cr>' " call feedkeys("<cr>") 1delete normal 1Gjk set nomodifiable if a:stay_in_message_list call s:focus_list_window() end redraw
endfunction
function! s:show_large_message()
call <SID>show_message(0) wincmd o 3split execute 'b'. s:listbufnr wincmd p
endfunction
“ from message window function! s:show_next_message()
let fullscreen = (bufwinnr(s:listbufnr) == -1) " we're in full screen message mode if fullscreen 3split exec 'b'. s:listbufnr else call s:focus_list_window() end normal j call s:show_message(1) normal zz wincmd p redraw
endfunction
function! s:show_previous_message()
let fullscreen = (bufwinnr(s:listbufnr) == -1) " we're in full screen message mode if fullscreen 3split exec 'b'. s:listbufnr else call s:focus_list_window() end normal k if line('.') != line('$') call s:show_message(1) endif normal zz wincmd p redraw
endfunction
“ from message list window function! s:show_next_message_in_list()
if line('.') != line('$') normal j call s:show_message(1) endif
endfunction
function! s:show_previous_message_in_list()
if line('.') != 1 normal k call s:show_message(1) endif
endfunction
“ invoked from withint message window function! s:show_raw()
let command = s:show_message_command . s:uid . ' raw' echo command setlocal modifiable 1,$delete let res = s:system_with_error_handling(command) put =res 1delete normal 1G setlocal nomodifiable
endfunction
function! s:focus_list_window()
if bufwinnr(s:listbufnr) == winnr() return end let winnr = bufwinnr(s:listbufnr) if winnr == -1 " create window split exec "buffer" . s:listbufnr else exec winnr . "wincmd w" endif call s:set_list_colors() " call feedkeys("\<c-l>") " prevents screen artifacts when user presses return too fast " turn this off though, because it causes an annoying flash
endfunction
function! s:focus_message_window()
let winnr = bufwinnr(s:message_window_bufnr) if winnr == -1 " create window exec "rightbelow split " . s:message_bufname else exec winnr . "wincmd w" endif
endfunction
func! s:close_message_window()
if winnr('$') > 1 close! else call s:focus_list_window() wincmd p close! normal z. endif
endfunc
“ gets new messages since last update function! s:update()
let command = s:update_command echo "Checking for new messages. Please wait..." let res = s:system_with_error_handling(command) let lines = split(res, '\n') if len(lines) > 0 setlocal modifiable call append(0, lines) setlocal nomodifiable write! let num = len(lines) call cursor(num, 0) normal z. redraw echom "You have " . num . " new message" . (num == 1 ? '' : 's') . "!" else redraw echom "No new messages" endif
endfunction
“ function argument a:read: Represents the next state ” 0 means unread, 1 means read. function! s:mark_as_read_unread(read) range
let uid_set = s:collect_uids(a:firstline, a:lastline) let nummsgs = len(uid_set) " decide whether to set messages to SEEN or UNSEEN let action = (a:read ? " +" : " -") . "FLAGS" " construct the imap command let command = s:flag_command . shellescape(join(uid_set, ',')) . action . " SEEN" " do the real imap flagging let res = s:system_with_error_handling(command) setlocal modifiable let lnum = a:firstline while lnum <= a:lastline let line = getline(lnum) if action ==# " +FLAGS" let newline = substitute(line, '^*+', '* ', '') let newline = substitute(newline, '^+ ', ' ', '') else let newline = substitute(line, '^ ', '+', '') let newline = substitute(newline, '^\* ', '*+', '') endif call setline(lnum, newline) let lnum += 1 endwhile setlocal nomodifiable write redraw echom nummsgs ." conversation(s) have been marked as " . (a:read ? "read" : "unread") . "."
endfunction
function! s:toggle_star() range
let uid_set = s:collect_uids(a:firstline, a:lastline) let nummsgs = len(uid_set) let flag_symbol = "^*" " check if starred already let action = " +FLAGS" if (match(getline(a:firstline), flag_symbol) != -1) let action = " -FLAGS" endif let command = s:flag_command . shellescape(join(uid_set, ',')) . action . " Flagged" if nummsgs == 1 echom "Toggling flag on message" else echom "Toggling flags on " . nummsgs . " messages" endif " toggle * on lines let res = s:system_with_error_handling(command) setlocal modifiable let lnum = a:firstline while lnum <= a:lastline let line = getline(lnum) if action == " +FLAGS" let newline = substitute(line, '^ ', '*', '') let newline = substitute(newline, '^+ ', '*+', '') else let newline = substitute(line, '^*+', '+ ', '') let newline = substitute(newline, '^* ', ' ', '') endif call setline(lnum, newline) let lnum += 1 endwhile setlocal nomodifiable write redraw if nummsgs == 1 echom "Toggled flag on message" else echom "Toggled flags on " . nummsgs . " messages" endif
endfunction
“ flag can be Deleted or spam func! s:delete_messages(flag) range
let uid_set = s:collect_uids(a:firstline, a:lastline) let nummsgs = len(uid_set) let command = s:flag_command . shellescape(join(uid_set, ',')) . " +FLAGS " . a:flag if nummsgs == 1 echom "Deleting message" else echom "Deleting " . nummsgs . " messages" endif let res = s:system_with_error_handling(command) setlocal modifiable exec "silent " . a:firstline . "," . a:lastline . "delete" setlocal nomodifiable write redraw echo nummsgs . " message" . (nummsgs == 1 ? '' : 's') . " marked " . a:flag
endfunc
func! s:archive_messages() range
let uid_set = s:collect_uids(a:firstline, a:lastline) let nummsgs = len(uid_set) let command = s:move_to_command . shellescape(join(uid_set, ',')) . ' ' . "all" echo "Archiving message" . (nummsgs == 1 ? '' : 's') let res = s:system_with_error_handling(command) setlocal modifiable exec "silent " . a:firstline . "," . a:lastline . "delete" setlocal nomodifiable write redraw echo nummsgs . " message" . (nummsgs == 1 ? '' : 's') . " archived"
endfunc
“ ——————————————————————————–
“ append text bodies of a set of messages to a file func! s:append_messages_to_file() range
let uid_set = s:collect_uids(a:firstline, a:lastline) let nummsgs = len(uid_set) let append_file = input("print messages to file: ", s:append_file) if append_file == '' echom "Canceled" return endif let s:append_file = append_file let command = s:append_to_file_command . shellescape(join(uid_set, ',')) . ' ' . s:append_file echo "Appending " . nummsgs . " message" . (nummsgs == 1 ? '' : 's') . " to " . s:append_file . ". Please wait..." let res = s:system_with_error_handling(command) echo res redraw
endfunc
“ ——————————————————————————– ” move to another mailbox function! s:move_to_mailbox(copy) range
let s:copy_to_mailbox = a:copy let uid_set = s:collect_uids(a:firstline, a:lastline) let s:nummsgs = len(uid_set) let s:uid_set = shellescape(join(uid_set, ',')) " now prompt use to select mailbox if !exists("s:mailboxes") call s:get_mailbox_list() endif leftabove split MailboxSelect setlocal buftype=nofile setlocal noswapfile setlocal modifiable resize 1 let prompt = "select mailbox to " . (a:copy ? 'copy' : 'move') . " to: " call setline(1, prompt) normal $ inoremap <silent> <buffer> <cr> <Esc>:call <SID>complete_move_to_mailbox()<CR> inoremap <silent> <buffer> <esc> <Esc>:q<cr> setlocal completefunc=CompleteMoveMailbox " c-p clears the line let s:firstline = a:firstline let s:lastline = a:lastline call feedkeys("a\<c-x>\<c-u>\<c-p>", 't') " save these in script scope to delete the lines when move completes
endfunction
function! s:complete_move_to_mailbox()
let mailbox = get(split(getline(line('.')), ": "), 1) close if s:copy_to_mailbox let command = s:copy_to_command . s:uid_set . ' ' . shellescape(mailbox) else let command = s:move_to_command . s:uid_set . ' ' . shellescape(mailbox) endif redraw echo "Moving uids ". s:uid_set . " to mailbox " . mailbox let res = s:system_with_error_handling(command) setlocal modifiable if !s:copy_to_mailbox exec "silent " . s:firstline . "," . s:lastline . "delete" end setlocal nomodifiable write redraw echo s:nummsgs . " message" . (s:nummsgs == 1 ? '' : 's') . ' ' . (s:copy_to_mailbox ? 'copied' : 'moved') . ' to ' . mailbox
endfunction
function! CompleteMoveMailbox(findstart, base)
if !exists("s:mailboxes") call s:get_mailbox_list() endif if a:findstart " locate the start of the word let line = getline('.') let start = col('.') - 1 while start > 0 && line[start - 1] =~ '\a' let start -= 1 endwhile return start else " find months matching with "a:base" let res = [] for m in s:mailboxes if m == s:mailbox continue endif if m =~ '^' . a:base call add(res, m) endif endfor return res endif
endfun “ ——————————————————————————–
function! s:get_mailbox_list()
let command = s:list_mailboxes_command redraw echo command let res = s:system_with_error_handling(command) let s:mailboxes = split(res, "\n", '')
endfunction
“ ——————————————————————————- ” select mailbox
function! s:mailbox_window()
call s:get_mailbox_list() leftabove split MailboxSelect setlocal buftype=nofile setlocal noswapfile setlocal modifiable resize 1 inoremap <silent> <buffer> <cr> <Esc>:call <SID>select_mailbox()<CR> inoremap <silent> <buffer> <esc> <Esc>:q<cr> setlocal completefunc=CompleteMailbox " c-p clears the line call setline(1, "select mailbox to switch to: ") normal $ call feedkeys("a\<c-x>\<c-u>\<c-p>", 't')
endfunction
function! CompleteMailbox(findstart, base)
if !exists("s:mailboxes") call s:get_mailbox_list() endif if a:findstart " locate the start of the word let line = getline('.') let start = col('.') - 1 while start > 0 && line[start - 1] =~ '\a' let start -= 1 endwhile return start else " find mailboxes matching with "a:base" let res = [] for m in s:mailboxes if m =~ '^' . a:base call add(res, m) endif endfor return res endif
endfun
function! s:select_mailbox()
let mailbox = get(split(getline(line('.')), ": "), 1) close call s:focus_message_window() close " check if mailbox is a real mailbox if (index(s:mailboxes, mailbox) == -1) return endif let s:mailbox = mailbox let s:query = "all" let command = s:select_mailbox_command . shellescape(s:mailbox) redraw echom "Selecting mailbox: ". s:mailbox . ". Please wait..." call s:system_with_error_handling(command) redraw " reset window width now call s:system_with_error_handling(s:set_window_width_command . winwidth(1)) " now get latest 100 messages call s:focus_list_window() setlocal modifiable let command = s:search_command . shellescape("all") echo "Loading messages..." let res = s:system_with_error_handling(command) silent 1,$delete silent! put! =res execute "normal Gdd\<c-y>" setlocal nomodifiable write normal gg redraw echom "Current mailbox: ". s:mailbox
endfunction
func! s:search_query()
if !exists("s:query") let s:query = "" endif let s:query = input("search query: ", s:query) call s:do_search()
endfunc
function! s:do_search()
" empty query if match(s:query, '^\s*$') != -1 return endif " close message window if open call s:focus_message_window() close let command = s:search_command . shellescape(s:query) redraw call s:focus_list_window() setlocal modifiable echo "Running query on " . s:mailbox . ": " . s:query . ". Please wait..." let res = s:system_with_error_handling(command) silent! 1,$delete silent! put! =res execute "silent normal Gdd\<c-y>" setlocal nomodifiable write normal gg
endfunction
function! s:more_messages()
let command = s:more_messages_command echo "Fetching more messages. Please wait..." let res = s:system_with_error_handling(command) setlocal modifiable let lines = split(res, "\n") call append(line('$'), lines) " execute "normal Gdd\<c-y>" setlocal nomodifiable normal j redraw echo "Done"
endfunction
“ ——————————————————————————– ” compose reply, compose, forward, save draft
function! s:compose_reply(all)
let command = s:reply_template_command if a:all let command = command . ' 1' endif call s:open_compose_window(command) " cursor after headers normal 1G}
endfunction
function! s:compose_message()
let command = s:new_message_template_command call s:open_compose_window(command) " position cursor after to:
“ call search(”^to:“) ” normal A endfunction
function! s:compose_forward()
let command = s:forward_template_command call s:open_compose_window(command)
“ call search(”^to:“) ” normal A endfunction
func! s:open_compose_window(command)
redraw echo a:command let res = s:system_with_error_handling(a:command) let previous_winnr = winnr() only split compose_message.txt setlocal modifiable wincmd p close! silent! 1,$delete silent! put! =res redraw "call feedkeys("\<cr>") call s:compose_window_mappings() setlocal completefunc=CompleteContact setlocal ft=mail normal 1G
endfunc
func! s:turn_into_compose_window()
call s:compose_window_mappings() setlocal completefunc=CompleteContact
endfunc
“ contacts.txt file should be generated. ” grep works well, does partial matches function! CompleteContact(findstart, base)
if !exists("s:mailboxes") call s:get_mailbox_list() endif if a:findstart " locate the start of the word let line = getline('.') let start = col('.') - 1 while start > 0 && line[start - 1] =~ '\a' let start -= 1 endwhile return start else " find contacts " model regex: match at beginning of line, or inside < > wrapping " email addr " '\(^ho\|<ho\)' " let regex = shellescape('\(^' . a:base . '\|<' . a:base . '\)') let regex = shellescape(a:base) let matches = s:system_with_error_handling("grep -i " . regex . " " . $VMAIL_CONTACTS_FILE) return split(matches, "\n") endif
endfun
func! s:close_and_focus_list_window()
call s:focus_list_window() wincmd p close! normal z.
endfunc
function! s:send_message()
let mail = join(getline(1,'$'), "\n") echo "Sending message" let res = system(s:deliver_command, mail) if match(res, '^Failed') == -1 write! call s:close_and_focus_list_window() endif echom substitute(res, '[\s\r\n]\+$', '', '') redraw
endfunction
“ ——————————————————————————– ” Update message list with new emails.
func! UPDATE_MESSAGE_LIST(filename)
if s:mailbox == 'INBOX' if bufnr('%') == s:listbufnr call s:update_and_redraw_message_list(a:filename) " If current_message is open with message list in another split. elseif bufname('%') == s:message_bufname && index(tabpagebuflist(), s:listbufnr) >= 0 let message_bufnr = bufnr('%') " Switch to message list window and update it. while bufnr('%') != s:listbufnr | wincmd w | endwhile call s:update_and_redraw_message_list(a:filename) while bufnr('%') != message_bufnr | wincmd w | endwhile else call s:update_message_list(a:filename) endif endif
endfunc
func! s:update_and_redraw_message_list(filename)
call s:update_message_list(a:filename) edit! redraw!
endfunc
func! s:update_message_list(filename)
let newer_contents = readfile(a:filename) let older_contents = readfile(s:listbufname) let updated_contents = extend(newer_contents, older_contents) call writefile(updated_contents, s:listbufname)
endfunc
“ ——————————————————————————–
“ call from inside message window with <Leader>h func! s:open_html_part()
let command = s:open_html_part_command " the command saves the html part to a local file let outfile = s:system_with_error_handling(command) " todo: allow user to change open in browser command? exec "!" . s:browser_command . ' ' . outfile
endfunc
func! s:save_attachments()
if !exists("s:savedir") let s:savedir = getcwd() . "/attachments" end let s:savedir = input("save attachments to directory: ", s:savedir, "dir") let command = s:save_attachments_command . s:savedir let res = s:system_with_error_handling(command) echo res
endfunc
func! s:attach_file(file)
normal gg normal } let attach = "attach: " . a:file put =attach
endfunc
“ ——————————————————————————–
func! s:toggle_maximize_window()
if winnr('$') > 1 only " normal z. elseif bufwinnr(s:listbufnr) == winnr() call s:show_message(1) else " we're in the message window call s:focus_list_window() wincmd p endif
endfunc
“ maybe not DRY enough, but fix that later ” also, come up with a more precise regex pattern for matching hyperlinks func! s:open_href(all) range
let pattern = 'https\?:[^ >)\]]\+' let n = 0 " range version if a:firstline < a:lastline let lnum = a:firstline while lnum <= a:lastline let href = matchstr(getline(lnum), pattern) if href != "" let command = s:browser_command ." ".shellescape(href)." &" call s:system_with_error_handling(command) let n += 1 endif let lnum += 1 endwhile echom 'opened '.n.' links' return end let line = search(pattern, 'cw') if line && a:all while line let href = matchstr(getline(line('.')), pattern) let command = s:browser_command ." ".shellescape(href)." &" call s:system_with_error_handling(command) let n += 1 let line = search('https\?:', 'W') endwhile echom 'opened '.n.' links' else let href = matchstr(getline(line('.')), pattern) let command = s:browser_command ." ".shellescape(href)." &" call s:system_with_error_handling(command) echom 'opened '.href endif
endfunc
“ ——————————————————————————– ” HELP func! s:show_help()
let command = s:browser_command . ' ' . shellescape('http://danielchoi.com/software/vmail.html') call s:system_with_error_handling(command) "let helpfile = s:system_with_error_handling(s:show_help_command) "exec "split " . helpfile
endfunc
“ ——————————————————————————– ” CONVENIENCE FUNCS
function! s:collect_uids(startline, endline)
let uid_set = [] let lnum = a:startline while lnum <= a:endline let uid = matchstr(getline(lnum), '\S\+$') call add(uid_set, uid) let lnum += 1 endwhile return uid_set
endfunc
“ ——————————————————————————– ” MAPPINGS
func! s:message_window_mappings()
if !hasmapto('<Plug>VmailMessageWindow_FocusListWindow') nmap <buffer> <CR> <Plug>VmailMessageWindow_FocusListWindow endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_FocusListWindow <C-W>=:call <SID>focus_list_window()<CR> if !hasmapto('<Plug>VmailMessageWindow_Reply') nmap <buffer> <leader>r <Plug>VmailMessageWindow_Reply endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_Reply :call <SID>compose_reply(0)<CR> if !hasmapto('<Plug>VmailMessageWindow_ReplyToAll') nmap <buffer> <leader>a <Plug>VmailMessageWindow_ReplyToAll endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_ReplyToAll :call <SID>compose_reply(1)<CR> if !hasmapto('<Plug>VmailMessageWindow_ShowRaw') nmap <buffer> <leader>R <Plug>VmailMessageWindow_ShowRaw endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_ShowRaw :call <SID>show_raw()<CR> if !hasmapto('<Plug>VmailMessageWindow_Forward') nmap <buffer> <leader>f <Plug>VmailMessageWindow_Forward endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_Forward :call <SID>compose_forward()<CR> if !hasmapto('<Plug>VmailMessageWindow_ShowNext') nmap <buffer> <C-j> <Plug>VmailMessageWindow_ShowNext nmap <buffer> <leader>j <Plug>VmailMessageWindow_ShowNext endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_ShowNext :call <SID>show_next_message()<CR> if !hasmapto('<Plug>VmailMessageWindow_ShowPrev') nmap <buffer> <C-k> <Plug>VmailMessageWindow_ShowPrev nmap <buffer> <leader>k <Plug>VmailMessageWindow_ShowPrev endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_ShowPrev :call <SID>show_previous_message()<CR> if !hasmapto('<Plug>VmailMessageWindow_ComposeMessage') nmap <buffer> <leader>c <Plug>VmailMessageWindow_ComposeMessage endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_ComposeMessage :call <SID>compose_message()<CR> if !hasmapto('<Plug>VmailMessageWindow_OpenHTML') nmap <buffer> <leader>h <Plug>VmailMessageWindow_OpenHTML endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_OpenHTML :call <SID>open_html_part()<CR> if !hasmapto('<Plug>VmailMessageWindow_CloseWindow') nmap <buffer> <leader>q <Plug>VmailMessageWindow_CloseWindow nmap <buffer> o <Plug>VmailMessageWindow_CloseWindow endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_CloseWindow :call <SID>close_message_window()<CR> if !hasmapto('<Plug>VmailMessageWindow_DeleteMessage') nmap <buffer> <leader># <Plug>VmailMessageWindow_DeleteMessage nmap <buffer> <leader>3 <Plug>VmailMessageWindow_DeleteMessage endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_DeleteMessage :close<cr>:call <SID>focus_list_window()<CR>:call <SID>delete_messages("Deleted")<CR> if !hasmapto('<Plug>VmailMessageWindow_ToggleStar') nmap <buffer> <leader>* <Plug>VmailMessageWindow_ToggleStar nmap <buffer> <leader>8 <Plug>VmailMessageWindow_ToggleStar endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_ToggleStar :call <SID>focus_list_window()<cr>:call <SID>toggle_star()<CR> if !hasmapto('<Plug>VmailMessageWindow_MarkAsRead') nmap <buffer> I <Plug>VmailMessageWindow_MarkAsRead endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_MarkAsRead :call <SID>focus_list_window()<cr>:call <SID>mark_as_read_unread(1)<CR> if !hasmapto('<Plug>VmailMessageWindow_MarkAsUnread') nmap <buffer> U <Plug>VmailMessageWindow_MarkAsUnread endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_MarkAsUnread :call <SID>focus_list_window()<cr>:call <SID>mark_as_read_unread(0)<CR> if !hasmapto('<Plug>VmailMessageWindow_MarkAsSpam') nmap <buffer> <leader>! <Plug>VmailMessageWindow_MarkAsSpam nmap <buffer> <leader>1 <Plug>VmailMessageWindow_MarkAsSpam endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_MarkAsSpam :close<cr>:call <SID>focus_list_window()<cr>:call <SID>delete_messages("spam")<CR> if !hasmapto('<Plug>VmailMessageWindow_ArchiveMessage') nmap <buffer> <leader>e <Plug>VmailMessageWindow_ArchiveMessage endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_ArchiveMessage :call <SID>focus_list_window()<cr>:call <SID>archive_messages()<CR> if !hasmapto('<Plug>VmailMessageWindow_MoveToMailbox') nmap <buffer> <leader>b <Plug>VmailMessageWindow_MoveToMailbox endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_MoveToMailbox :call <SID>focus_list_window()<cr>:call <SID>move_to_mailbox(0)<CR> if !hasmapto('<Plug>VmailMessageWindow_CopyToMailbox') nmap <buffer> <leader>B <Plug>VmailMessageWindow_CopyToMailbox endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_CopyToMailbox :call <SID>focus_list_window()<cr>:call <SID>move_to_mailbox(1)<CR> if !hasmapto('<Plug>VmailMessageWindow_Update') nmap <buffer> <leader>u <Plug>VmailMessageWindow_Update endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_Update :call <SID>focus_list_window()<cr>:call <SID>update()<CR> if !hasmapto('<Plug>VmailMessageWindow_SwitchMailBox') nmap <buffer> <leader>m <Plug>VmailMessageWindow_SwitchMailBox endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_SwitchMailBox :call <SID>focus_list_window()<cr>:call <SID>mailbox_window()<CR> if !hasmapto('<Plug>VmailMessageWindow_SaveAttachment') nmap <buffer> <leader>A <Plug>VmailMessageWindow_SaveAttachment endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_SaveAttachment :call <SID>save_attachments()<CR> if !hasmapto('<Plug>VmailMessageWindow_ToggleWindow') nmap <buffer> <Space> <Plug>VmailMessageWindow_ToggleWindow endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_ToggleWindow :call <SID>toggle_maximize_window()<cr> if !hasmapto('<Plug>VmailMessageWindow_AppendMessagesToFile') nmap <buffer> <leader>vp <Plug>VmailMessageWindow_AppendMessagesToFile endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_AppendMessagesToFile :call <SID>focus_list_window()<cr>:call <SID>append_messages_to_file()<CR> if !hasmapto('<Plug>VmailMessageWindow_Search') nmap <buffer> <leader>s <Plug>VmailMessageWindow_Search endif nnoremap <buffer> <unique> <script> <Plug>VmailMessageWindow_Search :call <SID>focus_list_window()<cr>:call <SID>search_query()<cr>
endfunc
func! s:message_list_window_mappings()
if !hasmapto('<Plug>VmailOpenMessage') nmap <buffer> <CR> <Plug>VmailOpenMessage nmap <buffer> o <Plug>VmailOpenMessage nmap <buffer> <LeftMouse> <Plug>VmailOpenMessage endif nnoremap <buffer> <unique> <script> <Plug>VmailOpenMessage :call <SID>show_message(0)<CR> if !hasmapto('<Plug>VmailOpenLargeMessage') nmap <buffer> O <Plug>VmailOpenLargeMessage endif nnoremap <buffer> <unique> <script> <Plug>VmailOpenLargeMessage :call <SID>show_large_message()<CR> if !hasmapto('<Plug>VmailPreviewMessage') nmap <buffer> l <Plug>VmailPreviewMessage endif nnoremap <buffer> <unique> <script> <Plug>VmailPreviewMessage :call <SID>show_message(1)<CR> if !hasmapto('<Plug>VmailExit') nmap <buffer> <leader>q <Plug>VmailExit endif nnoremap <buffer> <unique> <script> <Plug>VmailExit :qall!<CR> if !hasmapto('<Plug>VmailToggleStar') nmap <buffer> <leader>* <Plug>VmailToggleStar xmap <buffer> <leader>* <Plug>VmailToggleStar nmap <buffer> <leader>8 <Plug>VmailToggleStar xmap <buffer> <leader>8 <Plug>VmailToggleStar endif nnoremap <buffer> <unique> <script> <Plug>VmailToggleStar :call <SID>toggle_star()<CR> xnoremap <buffer> <unique> <script> <Plug>VmailToggleStar :call <SID>toggle_star()<CR> if !hasmapto('<Plug>VmailMarkAsUnread') nmap <buffer> U <Plug>VmailMarkAsUnread xmap <buffer> U <Plug>VmailMarkAsUnread endif nnoremap <buffer> <unique> <script> <Plug>VmailMarkAsUnread :call <SID>mark_as_read_unread(0)<CR> xnoremap <buffer> <unique> <script> <Plug>VmailMarkAsUnread :call <SID>mark_as_read_unread(0)<CR> if !hasmapto('<Plug>VmailMarkAsRead') nmap <buffer> I <Plug>VmailMarkAsRead xmap <buffer> I <Plug>VmailMarkAsRead endif nnoremap <buffer> <unique> <script> <Plug>VmailMarkAsRead :call <SID>mark_as_read_unread(1)<CR> xnoremap <buffer> <unique> <script> <Plug>VmailMarkAsRead :call <SID>mark_as_read_unread(1)<CR> if !hasmapto('<Plug>VmailDelete') nmap <buffer> <leader># <Plug>VmailDelete xmap <buffer> <leader># <Plug>VmailDelete nmap <buffer> <leader>3 <Plug>VmailDelete xmap <buffer> <leader>3 <Plug>VmailDelete endif nnoremap <buffer> <unique> <script> <Plug>VmailDelete :call <SID>delete_messages("Deleted")<CR> xnoremap <buffer> <unique> <script> <Plug>VmailDelete :call <SID>delete_messages("Deleted")<CR> if !hasmapto('<Plug>VmailMarkAsSpam') nmap <buffer> <leader>! <Plug>VmailMarkAsSpam xmap <buffer> <leader>! <Plug>VmailMarkAsSpam nmap <buffer> <leader>1 <Plug>VmailMarkAsSpam xmap <buffer> <leader>1 <Plug>VmailMarkAsSpam endif nnoremap <buffer> <unique> <script> <Plug>VmailMarkAsSpam :call <SID>delete_messages("spam")<CR> xnoremap <buffer> <unique> <script> <Plug>VmailMarkAsSpam :call <SID>delete_messages("spam")<CR> if !hasmapto('<Plug>VmailArchiveMessage') nmap <buffer> <leader>e <Plug>VmailArchiveMessage xmap <buffer> <leader>e <Plug>VmailArchiveMessage endif nnoremap <buffer> <unique> <script> <Plug>VmailArchiveMessage :call <SID>archive_messages()<CR> xnoremap <buffer> <unique> <script> <Plug>VmailArchiveMessage :call <SID>archive_messages()<CR> if !hasmapto('<Plug>VmailAppendMessagesToFile') nmap <buffer> <leader>vp <Plug>VmailAppendMessagesToFile xmap <buffer> <leader>vp <Plug>VmailAppendMessagesToFile endif nnoremap <buffer> <unique> <script> <Plug>VmailAppendMessagesToFile :call <SID>append_messages_to_file()<CR> xnoremap <buffer> <unique> <script> <Plug>VmailAppendMessagesToFile :call <SID>append_messages_to_file()<CR> if !hasmapto('<Plug>VmailUpdate') nmap <buffer> u <Plug>VmailUpdate nmap <buffer> <leader>u <Plug>VmailUpdate endif nnoremap <buffer> <unique> <script> <Plug>VmailUpdate :call <SID>update()<CR> if !hasmapto('<Plug>VmailSearch') nmap <buffer> <leader>s <Plug>VmailSearch endif nnoremap <buffer> <unique> <script> <Plug>VmailSearch :call <SID>search_query()<CR> if !hasmapto('<Plug>VmailSwitchMailbox') nmap <buffer> <leader>m <Plug>VmailSwitchMailbox endif nnoremap <buffer> <unique> <script> <Plug>VmailSwitchMailbox :call <SID>mailbox_window()<CR> if !hasmapto('<Plug>VmailMoveToMailbox') nmap <buffer> <leader>b <Plug>VmailMoveToMailbox xmap <buffer> <leader>b <Plug>VmailMoveToMailbox endif nnoremap <buffer> <unique> <script> <Plug>VmailMoveToMailbox :call <SID>move_to_mailbox(0)<CR> xnoremap <buffer> <unique> <script> <Plug>VmailMoveToMailbox :call <SID>move_to_mailbox(0)<CR> if !hasmapto('<Plug>VmailCopyToMailbox') nmap <buffer> <leader>B <Plug>VmailCopyToMailbox xmap <buffer> <leader>B <Plug>VmailCopyToMailbox endif nnoremap <buffer> <unique> <script> <Plug>VmailCopyToMailbox :call <SID>move_to_mailbox(1)<CR> xnoremap <buffer> <unique> <script> <Plug>VmailCopyToMailbox :call <SID>move_to_mailbox(1)<CR> if !hasmapto('<Plug>VmailComposeNew') nmap <buffer> <leader>c <Plug>VmailComposeNew endif nnoremap <buffer> <unique> <script> <Plug>VmailComposeNew :call <SID>compose_message()<CR> if !hasmapto('<Plug>VmailComposeReply') nmap <buffer> <Leader>r <Plug>VmailComposeReply endif nnoremap <buffer> <unique> <script> <Plug>VmailComposeReply :call <SID>show_message(0)<CR>:call <SID>compose_reply(0)<CR> if !hasmapto('<Plug>VmailComposeReplyAll') nmap <buffer> <Leader>a <Plug>VmailComposeReplyAll endif nnoremap <buffer> <unique> <script> <Plug>VmailComposeReplyAll :call <SID>show_message(0)<CR>:call <SID>compose_reply(1)<CR> if !hasmapto('<Plug>VmailForward') nmap <buffer> <Leader>f <Plug>VmailForward endif nnoremap <buffer> <unique> <script> <Plug>VmailForward :call <SID>show_message(0)<CR>:call <SID>compose_forward()<CR> if !hasmapto('<Plug>VmailShowNextMessage') nmap <buffer> <C-j> <Plug>VmailShowNextMessage endif nnoremap <buffer> <unique> <script> <Plug>VmailShowNextMessage :call <SID>show_next_message_in_list()<CR> if !hasmapto('<Plug>VmailShowPrevMessage') nmap <buffer> <C-k> <Plug>VmailShowPrevMessage endif nnoremap <buffer> <unique> <script> <Plug>VmailShowPrevMessage :call <SID>show_previous_message_in_list()<CR> if !hasmapto('<Plug>VmailToggleWindow') nmap <buffer> <Space> <Plug>VmailToggleWindow endif nnoremap <buffer> <unique> <script> <Plug>VmailToggleWindow :call <SID>toggle_maximize_window()<cr> autocmd CursorMoved <buffer> :redraw autocmd BufEnter,BufWinEnter <buffer> :call <SID>set_list_colors()
endfunc
func! s:compose_window_mappings()
if !hasmapto('<Plug>VmailComposeWinClose') nmap <buffer> <leader>q <Plug>VmailComposeWinClose endif nnoremap <buffer> <script> <Plug>VmailComposeWinClose :call <SID>close_and_focus_list_window()<CR> setlocal ai command! -bar -nargs=1 -complete=file VMAttach call s:attach_file(<f-args>)
endfunc
func! s:global_mappings()
" NOTE send_message is a global mapping, so user can load a saved " message from a file and send it nnoremap <silent> <leader>vs :call <SID>send_message()<CR> noremap <silent> <leader>o :call <SID>open_href(0)<cr> noremap <silent> <leader>O :call <SID>open_href(1)<cr> noremap <silent> <leader>? :call <SID>show_help()<cr> noremap <silent> <leader>qq :qal!<cr>
endfunc
func! s:set_list_colors()
if !exists("g:syntax_on") return endif syn clear syn match vmailSizeCol /|\s\+\(< 1k\|\d*\(b\|k\|M\|G\)\)\s\+|/ contains=vmailSeperator contained syn match vmailFirstCol /^.\{-}|/ nextgroup=vmailDateCol syn match vmailFirstColAnswered /An/ contained containedin=vmailFirstCol syn match vmailFirstColForward /\$F/ contained containedin=vmailFirstCol syn match vmailFirstColNotJunk /No/ contained containedin=vmailFirstCol " Examples matched by vmailDateCol: " | Dec 15 11:59pm | " | Dec 15 2008 | " | 15.12 23:59 | " | 15.12 2008 | syn match vmailDateCol /\s\+\(... \d\d \(\(\d\d:\d\d..\)\|\(\d\{4}\)\)\)\|\(\d\d\.\d\d \(\(\d\d:\d\d\)\|\(\d\{4}\)\)\)\s\+|/ nextgroup=vmailFromCol contains=vmailSeperator syn match vmailFromCol /\s.\{-}|\@=/ contained nextgroup=vmailFromSeperator syn match vmailFromColEmail /<[^ ]*/ contained containedin=vmailFromCol syn match vmailFromSeperator /|/ contained nextgroup=vmailSubject syn match vmailSubject /.*\s\+/ contained contains=vmailSizeCol syn match vmailSubjectRe /\cre:\|fwd\?:/ contained containedin=vmailSubject syn match vmailSeperator /|/ contained syn match vmailNewMessage /^\s*+.*/ syn match vmailStarredMessage /^\s*\*.*/ hi def link vmailFirstCol Comment hi def link vmailDateCol Statement hi def link vmailFromCol Identifier hi def link vmailSizeCol Constant hi def link vmailSeperator Comment hi def link vmailFromSeperator vmailSeperator hi def link vmailFromColEmail Comment hi def link vmailSubjectRe Type hi def link vmailFirstColSpec Number hi def link vmailFirstColAnswered vmailFirstColSpec hi def link vmailFirstColForward vmailFirstColSpec hi def link vmailFirstColNotJunk vmailFirstColSpec hi def link vmailSpecialMsg Special hi def link vmailNewMessage vmailSpecialMsg hi def link vmailStarredMessage vmailSpecialMsg syn match VmailBufferFlagged /^*.*/hs=s exec "hi def VmailBufferFlagged " . g:vmail_flagged_color
endfunc
“TODO see if using LocalLeader and maplocalleader makes more sense let mapleader = ”,“
call s:global_mappings()
call s:create_list_window()
call s:create_message_window()
call s:focus_list_window() “ to go list window
“ send window width call s:system_with_error_handling(s:set_window_width_command . winwidth(1))
autocmd bufreadpost *.txt call <SID>turn_into_compose_window() normal G call s:system_with_error_handling(s:select_mailbox_command . shellescape(s:mailbox)) call s:do_search()