X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=vim%2Fplugin%2Fnotmuch.vim;h=0adca0b0c574922ec78a90a1e14a74d4a8b9105b;hp=15958f18c02c407d93056717aa858b825c4cfc47;hb=350e0136963d14d3dfe2ba88e80c217b483d5949;hpb=480903adac81ec03613c4edf46c9c2f6a2766c4c diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 15958f18..0adca0b0 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -52,6 +52,10 @@ let s:notmuch_defaults = { \ 'g:notmuch_show_signature_lines_max': 12 , \ \ 'g:notmuch_show_citation_regexp': '^\s*>' , + \ + \ 'g:notmuch_compose_insert_mode_start': 1 , + \ 'g:notmuch_compose_header_help': 1 , + \ 'g:notmuch_compose_temp_file_dir': '~/.notmuch/compose/' , \ } " defaults for g:notmuch_initial_search_words @@ -78,6 +82,24 @@ let s:notmuch_folders_defaults = [ \ [ 'unread', 'tag:unread' ], \ ] +" defaults for g:notmuch_signature +" override with: let g:notmuch_signature = [ ... ] +let s:notmuch_signature_defaults = [ + \ '', + \ '-- ', + \ 'email sent from notmuch.vim plugin' + \ ] + +" defaults for g:notmuch_compose_headers +" override with: let g:notmuch_compose_headers = [ ... ] +let s:notmuch_compose_headers_defaults = [ + \ 'From', + \ 'To', + \ 'Cc', + \ 'Bcc', + \ 'Subject' + \ ] + " --- keyboard mapping definitions {{{1 " --- --- bindings for folders mode {{{2 @@ -138,6 +160,16 @@ let g:notmuch_show_maps = { \ '?': ':echo NM_show_message_id() . '' @ '' . join(NM_show_search_words())', \ } +" --- --- bindings for compose screen {{{2 +let g:notmuch_compose_nmaps = { + \ ',s': ':call NM_compose_send()', + \ ',a': ':call NM_compose_attach()', + \ ',q': ':call NM_kill_this_buffer()', + \ '': ':call NM_compose_next_entry_area()', + \ } +let g:notmuch_compose_imaps = { + \ '': '=NM_compose_next_entry_area()', + \ } " --- implement folders screen {{{1 @@ -156,7 +188,7 @@ function! s:NM_cmd_folders(words) call add(searches, search) endfor - call NM_newBuffer('folders', join(disp, "\n")) + call NM_newBuffer('', 'folders', join(disp, "\n")) let b:nm_searches = searches let b:nm_timestamp = reltime() @@ -204,7 +236,7 @@ function! s:NM_cmd_search(words) let disp = copy(lines) call map(disp, 's:NM_cmd_search_fmtline(v:val)') - call NM_newBuffer('search', join(disp, "\n")) + call NM_newBuffer('', 'search', join(disp, "\n")) let b:nm_raw_lines = lines let b:nm_search_words = a:words @@ -349,8 +381,7 @@ endfunction function! s:NM_search_thread_id() if !exists('b:nm_raw_lines') - echoe 'no b:nm_raw_lines' - return '' + throw 'Eeek! no b:nm_raw_lines' endif let mnum = line('.') - 1 if len(b:nm_raw_lines) <= mnum @@ -387,7 +418,7 @@ function! s:NM_cmd_show(words) let info = s:NM_cmd_show_parse(lines) setlocal bufhidden=hide - call NM_newBuffer('show', join(info['disp'], "\n")) + call NM_newBuffer('', 'show', join(info['disp'], "\n")) setlocal bufhidden=delete let b:nm_words = a:words let b:nm_raw_info = info @@ -589,8 +620,7 @@ endfunction function! s:NM_show_message_id() if !exists('b:nm_raw_info') - echoe 'no b:nm_raw_info' - return '' + throw 'Eeek! no b:nm_raw_info' endif let msg = NM_show_get_message_for_line(line('.')) if has_key(msg,'id') @@ -601,8 +631,7 @@ endfunction function! s:NM_show_search_words() if !exists('b:nm_words') - echoe 'no b:nm_words' - return [] + throw 'Eeek! no b:nm_words' endif return b:nm_words endfunction @@ -843,26 +872,231 @@ function! NM_cmd_show_foldtext() endfunction +" --- implement compose screen {{{1 + +function! s:NM_cmd_compose(words, body_lines) + let lines = !g:notmuch_compose_header_help ? [] : [ + \ 'Notmuch-Help: Type in your message here; to help you use these bindings:', + \ 'Notmuch-Help: ,a - attach a file', + \ 'Notmuch-Help: ,s - send the message (Notmuch-Help lines will be removed)', + \ 'Notmuch-Help: ,q - abort the message', + \ 'Notmuch-Help: - skip through header lines', + \ ] + let start_on_line = 0 + + let hdrs = { } + for word in a:words + let m = matchlist(word, '^\([^:]\+\):\s*\(.*\)\s*$') + if !len(m) + throw 'Eeek! bad parameter ''' . string(word) . '''' + endif + let key = substitute(m[1], '\<\w', '\U&', 'g') + if !has_key(hdrs, key) + let hdrs[key] = [] + endif + if strlen(m[2]) + call add(hdrs[key], m[2]) + endif + endfor + + if !has_key(hdrs, 'From') || !len(hdrs['From']) + let me = NM_compose_get_user_email() + let hdrs['From'] = [ me ] + endif + + for key in g:notmuch_compose_headers + let text = has_key(hdrs, key) ? join(hdrs[key], ', ') : '' + call add(lines, key . ': ' . text) + if !start_on_line && !strlen(text) + let start_on_line = len(lines) + endif + endfor + + for [key,val] in items(hdrs) + if match(g:notmuch_compose_headers, key) == -1 + let line = key . ': ' . join(val, ', ') + call add(lines, line) + endif + endfor + + call extend(lines, [ '', '' ]) + if !start_on_line + let start_on_line = len(lines) + 1 + endif + + if len(a:body_lines) + call extend(lines, a:body_lines) + else + call add(lines, '') + endif + call extend(lines, g:notmuch_signature) + + let prev_bufnr = bufnr('%') + setlocal bufhidden=hide + call NM_newFileBuffer(g:notmuch_compose_temp_file_dir, '%s.mail', + \ 'compose', lines) + setlocal bufhidden=hide + + call NM_set_map('n', g:notmuch_compose_nmaps) + call NM_set_map('i', g:notmuch_compose_imaps) + + call cursor(start_on_line, strlen(start_on_line) + 1) + if g:notmuch_compose_insert_mode_start + startinsert! + endif + echo 'Type your message, use to jump to next header and then body.' +endfunction + +function! s:NM_compose_send() + echo 'not implemented' +endfunction + +function! s:NM_compose_attach() + echo 'not implemented' +endfunction + +function! s:NM_compose_next_entry_area() + let lnum = line('.') + let hdr_end = NM_compose_find_line_match(1,'^$',1) + echo 'header end = ' . string(hdr_end) + if lnum < hdr_end + let lnum = lnum + 1 + let line = getline(lnum) + if match(line, '^\([^:]\+\):\s*$') == -1 + call cursor(lnum, strlen(line) + 1) + return '' + endif + while match(getline(lnum+1), '^\s') != -1 + let lnum = lnum + 1 + endwhile + call cursor(lnum, strlen(getline(lnum)) + 1) + return '' + + elseif lnum == hdr_end + call cursor(lnum+1, strlen(getline(lnum+1)) + 1) + return '' + endif + if mode() == 'i' + if !getbufvar(bufnr('.'), '&et') + return "\t" + endif + let space = '' + let shiftwidth = a:shiftwidth + let shiftwidth = shiftwidth - ((virtcol('.')-1) % shiftwidth) + " we assume no one has shiftwidth set to more than 40 :) + return ' '[0:shiftwidth] + endif +endfunction + +" --- --- compose screen helper functions {{{2 + +function! s:NM_compose_get_user_email() + let name = substitute(system('id -u -n'), '\v(^\s*|\s*$|\n)', '', 'g') + let fqdn = substitute(system('hostname -f'), '\v(^\s*|\s*$|\n)', '', 'g') + + " TODO: do this properly + return name . '@' . fqdn +endfunction + +function! s:NM_compose_find_line_match(start, pattern, failure) + let lnum = a:start + let lend = line('$') + while lnum < lend + if match(getline(lnum), a:pattern) != -1 + return lnum + endif + let lnum = lnum + 1 + endwhile + return a:failure +endfunction + + " --- notmuch helper functions {{{1 -function! s:NM_newBuffer(type, content) - enew - setlocal buftype=nofile readonly modifiable +function! s:NM_newBuffer(how, type, content) + if strlen(a:how) + exec a:how + else + enew + endif + setlocal buftype=nofile readonly modifiable scrolloff=0 sidescrolloff=0 silent put=a:content keepjumps 0d setlocal nomodifiable - set scrolloff=0 - set sidescrolloff=0 execute printf('set filetype=notmuch-%s', a:type) execute printf('set syntax=notmuch-%s', a:type) let b:nm_type = a:type endfunction +function! s:NM_newFileBuffer(fdir, fname, type, lines) + let fdir = expand(a:fdir) + if !isdirectory(fdir) + call mkdir(fdir, 'p') + endif + let file_name = NM_mktemp(fdir, a:fname) + if writefile(a:lines, file_name) + throw 'Eeek! couldn''t write to temporary file ' . file_name + endif + exec printf('edit %s', file_name) + setlocal buftype= noreadonly modifiable scrolloff=0 sidescrolloff=0 + execute printf('set filetype=notmuch-%s', a:type) + execute printf('set syntax=notmuch-%s', a:type) + let b:nm_type = a:type +endfunction + +function! s:NM_mktemp(dir, name) + let time_stamp = strftime('%Y%m%d-%H%M%S') + let file_name = substitute(a:dir,'/*$','/','') . printf(a:name, time_stamp) + " TODO: check if it exists, try again + return file_name +endfunction + function! s:NM_shell_escape(word) + " TODO: use shellescape() let word = substitute(a:word, '''', '\\''', 'g') return '''' . word . '''' endfunction +" this function was taken from git.vim, then fixed up +" http://github.com/motemen/git-vim +function! s:NM_shell_split(cmd) + let l:split_cmd = [] + let cmd = a:cmd + let iStart = 0 + while 1 + let t = match(cmd, '\S', iStart) + if t < iStart + break + endif + let iStart = t + + let iSpace = match(cmd, '\v(\s|$)', iStart) + if iSpace < iStart + break + endif + + let iQuote1 = match(cmd, '\(^["'']\|[^\\]\@<=["'']\)', iStart) + if iQuote1 > iSpace || iQuote1 < iStart + let iEnd = iSpace - 1 + let l:split_cmd += [ cmd[iStart : iEnd] ] + else + let q = cmd[iQuote1] + let iQuote2 = match(cmd, '[^\\]\@<=[' . q . ']', iQuote1 + 1) + if iQuote2 < iQuote1 + throw 'No matching ' . q . ' quote' + endif + let iEnd = iQuote2 + let l:split_cmd += [ cmd[iStart+1 : iEnd-1 ] ] + endif + + + let iStart = iEnd + 1 + endwhile + + return l:split_cmd +endfunction + + function! s:NM_run(args) let words = a:args call map(words, 's:NM_shell_escape(v:val)') @@ -976,6 +1210,12 @@ if !exists('g:notmuch_folders') let g:notmuch_folders = s:notmuch_folders_defaults endif +if !exists('g:notmuch_signature') + let g:notmuch_signature = s:notmuch_signature_defaults +endif +if !exists('g:notmuch_compose_headers') + let g:notmuch_compose_headers = s:notmuch_compose_headers_defaults +endif " --- assign keymaps {{{1 @@ -996,12 +1236,12 @@ function! NotMuch(args) let args = 'folders' endif - let words = split(args) - if words[0] == 'folders' + let words = NM_shell_split(args) + if words[0] == 'folders' || words[0] == 'f' let words = words[1:] call NM_cmd_folders(words) - elseif words[0] == 'search' + elseif words[0] == 'search' || words[0] == 's' if len(words) > 1 let words = words[1:] elseif exists('b:nm_search_words') @@ -1013,6 +1253,10 @@ function! NotMuch(args) elseif words[0] == 'show' echoe 'show is not yet implemented.' + + elseif words[0] == 'new' || words[0] == 'compose' + let words = words[1:] + call NM_cmd_compose(words, []) endif endfunction function! CompleteNotMuch(arg_lead, cmd_line, cursor_pos)