]> git.notmuchmail.org Git - notmuch/blobdiff - vim/plugin/notmuch.vim
nmbug: move from contrib to devel
[notmuch] / vim / plugin / notmuch.vim
index 968c4c1652b5d3ebab46d3e1759fc4ef40aacf4c..8f27fb9273d2efb124c6de8f27cd8ceeaee23deb 100644 (file)
 " along with Notmuch.  If not, see <http://www.gnu.org/licenses/>.
 "
 " Authors: Bart Trojanowski <bart@jukie.net>
-
+" Contributors: Felipe Contreras <felipe.contreras@gmail.com>,
+"   Peter Hartman <peterjohnhartman@gmail.com>
+"
 " --- configuration defaults {{{1
 
 let s:notmuch_defaults = {
         \ 'g:notmuch_cmd':                           'notmuch'                    ,
+        \ 'g:notmuch_sendmail':                      '/usr/sbin/sendmail'         ,
         \ 'g:notmuch_debug':                         0                            ,
         \
         \ 'g:notmuch_search_newest_first':           1                            ,
@@ -45,7 +48,7 @@ let s:notmuch_defaults = {
         \ 'g:notmuch_show_part_end_regexp':          '\fpart}'                   ,
         \ 'g:notmuch_show_marker_regexp':            '\f\\(message\\|header\\|body\\|attachment\\|part\\)[{}].*$',
         \
-        \ 'g:notmuch_show_message_parse_regexp':     '\(id:[^ ]*\) depth:\([0-9]*\) match:\([0-9]*\) filename:\(.*\)$',
+        \ 'g:notmuch_show_message_parse_regexp':     '\(id:[^ ]*\) depth:\([0-9]*\) match:\([0-9]*\) excluded:\([0-9]*\) filename:\(.*\)$',
         \ 'g:notmuch_show_tags_regexp':              '(\([^)]*\))$'               ,
         \
         \ 'g:notmuch_show_signature_regexp':         '^\(-- \?\|_\+\)$'           ,
@@ -55,7 +58,7 @@ let s:notmuch_defaults = {
         \
         \ 'g:notmuch_compose_insert_mode_start':     1                            ,
         \ 'g:notmuch_compose_header_help':           1                            ,
-        \ 'g:notmuch_compose_temp_file_dir':         '~/.notmuch/compose/'        ,
+        \ 'g:notmuch_compose_temp_file_dir':         '~/.notmuch/compose        ,
         \ }
 
 " defaults for g:notmuch_initial_search_words
@@ -117,8 +120,10 @@ let g:notmuch_search_maps = {
         \ '<Space>':    ':call <SID>NM_search_show_thread(0)<CR>',
         \ '<Enter>':    ':call <SID>NM_search_show_thread(1)<CR>',
         \ '<C-]>':      ':call <SID>NM_search_expand(''<cword>'')<CR>',
+        \ 'I':          ':call <SID>NM_search_mark_read_thread()<CR>',
         \ 'a':          ':call <SID>NM_search_archive_thread()<CR>',
         \ 'A':          ':call <SID>NM_search_mark_read_then_archive_thread()<CR>',
+        \ 'D':          ':call <SID>NM_search_delete_thread()<CR>',
         \ 'f':          ':call <SID>NM_search_filter()<CR>',
         \ 'm':          ':call <SID>NM_new_mail()<CR>',
         \ 'o':          ':call <SID>NM_search_toggle_order()<CR>',
@@ -144,10 +149,13 @@ let g:notmuch_show_maps = {
         \ 'b':          ':call <SID>NM_show_fold_toggle(''b'', ''bdy'', !g:notmuch_show_fold_bodies)<CR>',
         \ 'c':          ':call <SID>NM_show_fold_toggle(''c'', ''cit'', !g:notmuch_show_fold_citations)<CR>',
         \ 'h':          ':call <SID>NM_show_fold_toggle(''h'', ''hdr'', !g:notmuch_show_fold_headers)<CR>',
-        \ 'i':          ':call <SID>NM_show_fold_toggle(''s'', ''sig'', !g:notmuch_show_fold_signatures)<CR>',
+        \ 'i':          ':call <SID>NM_show_fold_toggle(''i'', ''sig'', !g:notmuch_show_fold_signatures)<CR>',
         \
+        \ 'I':          ':call <SID>NM_show_mark_read_thread()<CR>',
         \ 'a':          ':call <SID>NM_show_archive_thread()<CR>',
         \ 'A':          ':call <SID>NM_show_mark_read_then_archive_thread()<CR>',
+        \ 'D':          ':call <SID>NM_show_delete_thread()<CR>',
+        \ 'd':          ':call <SID>NM_show_delete_message()<CR>',
         \ 'N':          ':call <SID>NM_show_mark_read_then_next_open_message()<CR>',
         \ 'v':          ':call <SID>NM_show_view_all_mime_parts()<CR>',
         \ '+':          ':call <SID>NM_show_add_tag()<CR>',
@@ -254,12 +262,12 @@ function! s:NM_cmd_search_fmtline(line)
                 return 'ERROR PARSING: ' . a:line
         endif
         let max = g:notmuch_search_from_column_width
-        let flist = []
-        for at in split(m[4], ", ")
-                let p = min([stridx(at, "."), stridx(at, "@")])
-                call insert(flist, tolower(at[0:p - 1]))
+        let flist = {}
+        for at in split(m[4], '[|,] ')
+                let p = split(at, '[@.]')
+                let flist[p[0]] = 1
         endfor
-        let from = join(flist, ", ")
+        let from = join(keys(flist), ", ")
         return printf("%-12s %3s %-20.20s | %s (%s)", m[2], m[3], from, m[5], m[6])
 endfunction
 
@@ -306,13 +314,23 @@ function! s:NM_search_edit()
         endif
 endfunction
 
+function! s:NM_search_mark_read_thread()
+        call <SID>NM_tag([], ['-unread'])
+        norm j
+endfunction
+
 function! s:NM_search_archive_thread()
-        call <SID>NM_add_remove_tags([], '-', ['inbox'])
+        call <SID>NM_tag([], ['-inbox'])
         norm j
 endfunction
 
 function! s:NM_search_mark_read_then_archive_thread()
-        call <SID>NM_add_remove_tags([], '-', ['unread', 'inbox'])
+        call <SID>NM_tag([], ['-unread', '-inbox'])
+        norm j
+endfunction
+
+function! s:NM_search_delete_thread()
+        call <SID>NM_tag([], ['+delete','-inbox','-unread'])
         norm j
 endfunction
 
@@ -403,7 +421,8 @@ function! s:NM_search_add_remove_tags(prompt, prefix, intags)
         else
                 let tags = a:intags
         endif
-        call <SID>NM_add_remove_tags([], a:prefix, tags)
+        call map(tags, 'a:prefix . v:val')
+        call <SID>NM_tag([], tags)
 endfunction
 
 " --- implement show screen {{{1
@@ -492,15 +511,31 @@ function! s:NM_show_next_thread()
         endif
 endfunction
 
+function! s:NM_show_mark_read_thread()
+        call <SID>NM_tag(b:nm_search_words, ['-unread'])
+        call <SID>NM_show_next_thread()
+endfunction
+
 function! s:NM_show_archive_thread()
-        echo 'not implemented'
+        call <SID>NM_tag(b:nm_search_words, ['-inbox'])
+        call <SID>NM_show_next_thread()
 endfunction
 
 function! s:NM_show_mark_read_then_archive_thread()
-        call <SID>NM_add_remove_tags(b:nm_search_words, '-', ['unread', 'inbox'])
+        call <SID>NM_tag(b:nm_search_words, ['-unread', '-inbox'])
         call <SID>NM_show_next_thread()
 endfunction
 
+function! s:NM_show_delete_thread()
+        call <SID>NM_tag(b:nm_search_words, ['+delete', '-inbox', '-unread'])
+        call <SID>NM_show_next_thread()
+endfunction
+
+function! s:NM_show_delete_message()
+        let msg = <SID>NM_show_get_message_for_line(line('.'))
+        call <SID>NM_tag([msg['id']], ['+delete', '-inbox', '-unread'])
+endfunction
+
 function! s:NM_show_mark_read_then_next_open_message()
         echo 'not implemented'
 endfunction
@@ -561,7 +596,8 @@ function! s:NM_show_advance_marking_read_and_archiving()
                 let filter = <SID>NM_combine_tags('tag:', advance_tags, 'OR', '()')
                          \ + ['AND']
                          \ + <SID>NM_combine_tags('', ids, 'OR', '()')
-                call <SID>NM_add_remove_tags(filter, '-', advance_tags)
+                call map(advance_tags, '"-" . v:val')
+                call <SID>NM_tag(filter, advance_tags)
                 call <SID>NM_show_next(1, 1)
                 return
         endif
@@ -580,7 +616,8 @@ function! s:NM_show_advance_marking_read_and_archiving()
                         " do this last to hide the latency
                         let filter = <SID>NM_combine_tags('tag:', advance_tags, 'OR', '()')
                                  \ + ['AND', msg_top['id']]
-                        call <SID>NM_add_remove_tags(filter, '-', advance_tags)
+                        call map(advance_tags, '"-" . v:val')
+                        call <SID>NM_tag(filter, advance_tags)
                 endif
                 return
         endif
@@ -710,8 +747,11 @@ function! s:NM_cmd_show_parse(inlines)
                                 elseif mode_type == 'cit'
                                         if part_end || match(line, g:notmuch_show_citation_regexp) == -1
                                                 let outlnum = len(info['disp'])
-                                                let foldinfo = [ mode_type, mode_start, outlnum-1, len(info['msgs']),
-                                                               \ printf('[ %d-line citation.  Press "c" to show. ]', outlnum - mode_start) ]
+                                                if !part_end
+                                                        let outlnum = outlnum - 1
+                                                endif
+                                                let foldinfo = [ mode_type, mode_start, outlnum, len(info['msgs']),
+                                                               \ printf('[ %d-line citation.  Press "c" to show. ]', 1 + outlnum - mode_start) ]
                                                 let mode_type = ''
                                         endif
                                 elseif mode_type == 'sig'
@@ -719,8 +759,8 @@ function! s:NM_cmd_show_parse(inlines)
                                         if (outlnum - mode_start) > g:notmuch_show_signature_lines_max
                                                 let mode_type = ''
                                         elseif part_end
-                                                let foldinfo = [ mode_type, mode_start, outlnum-1, len(info['msgs']),
-                                                               \ printf('[ %d-line signature.  Press "s" to show. ]', outlnum - mode_start) ]
+                                                let foldinfo = [ mode_type, mode_start, outlnum, len(info['msgs']),
+                                                               \ printf('[ %d-line signature.  Press "i" to show. ]', 1 + outlnum - mode_start) ]
                                                 let mode_type = ''
                                         endif
                                 endif
@@ -728,7 +768,7 @@ function! s:NM_cmd_show_parse(inlines)
 
                         if part_end
                                 " FIXME: this is a hack for handling two folds being added for one line
-                                "         we should handle addinga fold in a function
+                                "         we should handle adding a fold in a function
                                 if len(foldinfo) && foldinfo[1] < foldinfo[2]
                                         call add(info['folds'], foldinfo[0:3])
                                         let info['foldtext'][foldinfo[1]] = foldinfo[4]
@@ -759,7 +799,14 @@ function! s:NM_cmd_show_parse(inlines)
                                 endif
                                 call add(info['disp'],
                                          \ printf('--- %s ---', in_part))
-                                let part_start = len(info['disp']) + 1
+                                " We don't yet handle nested parts, so pop
+                                " multipart/* immediately so text/plain
+                                " sub-parts are parsed properly
+                                if match(in_part, '^multipart/') != -1
+                                        let in_part = ''
+                                else
+                                        let part_start = len(info['disp']) + 1
+                                endif
                         endif
 
                 elseif in_header
@@ -823,7 +870,8 @@ function! s:NM_cmd_show_parse(inlines)
                                         let msg['id'] = m[1]
                                         let msg['depth'] = m[2]
                                         let msg['match'] = m[3]
-                                        let msg['filename'] = m[4]
+                                        let msg['excluded'] = m[4]
+                                        let msg['filename'] = m[5]
                                 endif
 
                                 let in_message = 1
@@ -941,71 +989,30 @@ function! s:NM_compose_send()
         let fname = expand('%')
         let lnum = 1
         let line = getline(lnum)
-        let hdrs = {}
         let lst_hdr = ''
         while match(line, '^$') == -1
-                if match(line, '^Notmuch-Help:') != -1
-                        " skip it
-                elseif strlen(lst_hdr) && match(line, '^\s') != -1
-                        let hdrs[lst_hdr][-1] = hdrs[lst_hdr][-1] . substitute(line, '^\s*', ' ', '')
-                else
-                        let m = matchlist(line, '^\(\w[^:]*\):\s*\(.*\)\s*$')
-                        if !len(m)
-                                cursor(lnum, 0)
-                                throw printf('Eeek! invalid header on line %d', lnum)
-                        endif
-                        let key = substitute(m[1], '\<\w', '\U&', 'g')
-                        if strlen(m[2])
-                                if !has_key(hdrs, key)
-                                        let hdrs[key] = []
-                                endif
-                                call add(hdrs[key], m[2])
-                        endif
-                        let lst_hdr = key
+                if !exists("hdr_starts") && match(line, '^Notmuch-Help:') == -1
+                        let hdr_starts = lnum - 1
                 endif
                 let lnum = lnum + 1
                 let line = getline(lnum)
         endwhile
-        let body_starts = lnum
-
-        "[-a header] [-b bcc-addr] [-c cc-addr] [-s subject] to-addr
-        let cmd = ['mail']
-        let tos = []
-        for [key, vals] in items(hdrs)
-                if key == 'To'
-                        call extend(tos, vals)
-                elseif key == 'Bcc'
-                        for adr in vals
-                                call add(cmd, '-b')
-                                call add(cmd, adr)
-                        endfor
-                elseif key == 'Cc'
-                        for adr in vals
-                                call add(cmd, '-c')
-                                call add(cmd, adr)
-                        endfor
-                elseif key == 'Subject'
-                        for txt in vals
-                                call add(cmd, '-s')
-                                call add(cmd, txt)
-                        endfor
-                else
-                        for val in vals
-                                call add(cmd, '-a')
-                                call add(cmd, key . ': ' . val)
-                        endfor
-                endif
-        endfor
-        call extend(cmd, tos)
+        let body_starts = lnum - 1
 
-        " TODO: make sure we have at least one target
-        " TODO: ask about empty jubject, etc
-
-        exec printf('0,%dd', body_starts)
+        call append(body_starts, 'Date: ' . strftime('%a, %d %b %Y %H:%M:%S %z'))
+        exec printf(':0,%dd', hdr_starts)
         write
 
-        call map(cmd, 's:NM_shell_escape(v:val)')
-        let cmdtxt = join(cmd) . '< ' . fname
+        let line = getline(1)
+        let m = matchlist(line, '^From:\s*\(.*\)\s*<\(.*\)>$')
+        if (len(m) >= 2)
+                let from = m[2]
+        else
+                let m = matchlist(line, '^From:\s*\(.*\)$')
+                let from = m[1]
+        endif
+
+        let cmdtxt = g:notmuch_sendmail . ' -t -f ' . from . ' < ' . fname
         let out = system(cmdtxt)
         let err = v:shell_error
         if err
@@ -1075,11 +1082,9 @@ 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
+        " TODO: do this properly (still), i.e., allow for multiple email accounts
+        let email = substitute(system('notmuch config get user.primary_email'), '\v(^\s*|\s*$|\n)', '', 'g')
+       return email
 endfunction
 
 function! s:NM_compose_find_line_match(start, pattern, failure)
@@ -1237,13 +1242,16 @@ function! s:NM_run(args)
         call map(words, 's:NM_shell_escape(v:val)')
         let cmd = g:notmuch_cmd . ' ' . join(words) . '< /dev/null'
 
-        let start = reltime()
-        let out = system(cmd)
-        let err = v:shell_error
-        let delta = reltime(start)
-
         if exists('g:notmuch_debug') && g:notmuch_debug
+                let start = reltime()
+                let out = system(cmd)
+                let err = v:shell_error
+                let delta = reltime(start)
+
                 echo printf('[%s] {%s} %s', reltimestr(delta), string(err), string(cmd))
+        else
+                let out = system(cmd)
+                let err = v:shell_error
         endif
 
         if err
@@ -1314,12 +1322,11 @@ function! s:NM_search_expand(arg)
         let b:nm_prev_bufnr = prev_bufnr
 endfunction
 
-function! s:NM_add_remove_tags(filter, prefix, tags)
+function! s:NM_tag(filter, tags)
         let filter = len(a:filter) ? a:filter : [<SID>NM_search_thread_id()]
         if !len(filter)
-                throw 'Eeek! I couldn''t find the thead id!'
+                throw 'Eeek! I couldn''t find the thread id!'
         endif
-        call map(a:tags, 'a:prefix . v:val')
         let args = ['tag']
         call extend(args, a:tags)
         call add(args, '--')