From 7e02b448e7684a0b5619ccc1d9144441b909b618 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Tue, 24 Nov 2009 23:25:31 -0500 Subject: [PATCH 001/110] message: add flags to notmuch_message_t This patch allows for different flags, internal to notmuch, to be set on a message object. The patch does not define any such flags, just the facilities to manage these flags. Signed-off-by: Bart Trojanowski --- lib/message.cc | 19 +++++++++++++++++++ lib/notmuch.h | 14 ++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/lib/message.cc b/lib/message.cc index 1e325e23..e0834f1c 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -37,6 +37,7 @@ struct _notmuch_message { char *filename; notmuch_message_file_t *message_file; notmuch_message_list_t *replies; + unsigned long flags; Xapian::Document doc; }; @@ -108,6 +109,7 @@ _notmuch_message_create (const void *talloc_owner, message->doc_id = doc_id; message->frozen = 0; + message->flags = 0; /* Each of these will be lazily created as needed. */ message->message_id = NULL; @@ -445,6 +447,23 @@ notmuch_message_get_filename (notmuch_message_t *message) return message->filename; } +notmuch_bool_t +notmuch_message_get_flag (notmuch_message_t *message, + notmuch_message_flag_t flag) +{ + return message->flags & (1 << flag); +} + +void +notmuch_message_set_flag (notmuch_message_t *message, + notmuch_message_flag_t flag, notmuch_bool_t enable) +{ + if (enable) + message->flags |= (1 << flag); + else + message->flags &= ~(1 << flag); +} + time_t notmuch_message_get_date (notmuch_message_t *message) { diff --git a/lib/notmuch.h b/lib/notmuch.h index 8bba442f..c232c580 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -684,6 +684,20 @@ notmuch_message_get_replies (notmuch_message_t *message); const char * notmuch_message_get_filename (notmuch_message_t *message); +/* Message flags */ +typedef enum _notmuch_message_flag { +} notmuch_message_flag_t; + +/* Get a value of a flag for the email corresponding to 'message'. */ +notmuch_bool_t +notmuch_message_get_flag (notmuch_message_t *message, + notmuch_message_flag_t flag); + +/* Set a value of a flag for the email corresponding to 'message'. */ +void +notmuch_message_set_flag (notmuch_message_t *message, + notmuch_message_flag_t flag, notmuch_bool_t value); + /* Get the date of 'message' as a time_t value. * * For the original textual representation of the Date header from the From 62878f71c2f2f1f8aabc6eeb3cab116bd38522db Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Tue, 24 Nov 2009 23:28:39 -0500 Subject: [PATCH 002/110] have _notmuch_thread_create mark which messages matched the query When _notmuch_thread_create() is given a query string, it can return more messages than just those matching the query. To distinguish those that matched the query expression, the MATCHING_SEARCH flag is set appropriately. Signed-off-by: Bart Trojanowski --- lib/notmuch.h | 1 + lib/thread.cc | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/lib/notmuch.h b/lib/notmuch.h index c232c580..3974820c 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -686,6 +686,7 @@ notmuch_message_get_filename (notmuch_message_t *message); /* Message flags */ typedef enum _notmuch_message_flag { + NOTMUCH_MSG_FLAG_MATCHING_SEARCH, } notmuch_message_flag_t; /* Get a value of a flag for the email corresponding to 'message'. */ diff --git a/lib/thread.cc b/lib/thread.cc index 58d88c2d..9e4cb5c8 100644 --- a/lib/thread.cc +++ b/lib/thread.cc @@ -132,6 +132,7 @@ _thread_add_matched_message (notmuch_thread_t *thread, notmuch_message_t *message) { time_t date; + notmuch_message_t *hashed_message; date = notmuch_message_get_date (message); @@ -142,6 +143,13 @@ _thread_add_matched_message (notmuch_thread_t *thread, thread->newest = date; thread->matched_messages++; + + if (g_hash_table_lookup_extended (thread->message_hash, + notmuch_message_get_message_id (message), NULL, + (void **) &hashed_message)) { + notmuch_message_set_flag (hashed_message, + NOTMUCH_MSG_FLAG_MATCHING_SEARCH, 1); + } } static void From b9e96ccb0d5242033704ff81fee0c720772a312f Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Tue, 24 Nov 2009 23:34:15 -0500 Subject: [PATCH 003/110] notmuch-show: identify which messages printed matched the query string The show command outputs all messages in the threads that match the search-terms. This patch introduces a 'match:[01]' entry to the 'message{' line output by the show command. Value of 1 indicates that the message is matching the search expression. Signed-off-by: Bart Trojanowski --- notmuch-show.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/notmuch-show.c b/notmuch-show.c index edebacaa..f189e943 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -155,9 +155,10 @@ show_message (void *ctx, notmuch_message_t *message, int indent) const char *name, *value; unsigned int i; - printf ("\fmessage{ id:%s depth:%d filename:%s\n", + printf ("\fmessage{ id:%s depth:%d match:%d filename:%s\n", notmuch_message_get_message_id (message), indent, + notmuch_message_get_flag (message, NOTMUCH_MSG_FLAG_MATCHING_SEARCH), notmuch_message_get_filename (message)); printf ("\fheader{\n"); From 0265a0030348dbed4816d0619ac8806e76640184 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 18 Nov 2009 16:43:42 -0500 Subject: [PATCH 004/110] primitive notmuch mail interface for vim --- vim/plugin/notmuch.vim | 116 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 vim/plugin/notmuch.vim diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim new file mode 100644 index 00000000..865624fe --- /dev/null +++ b/vim/plugin/notmuch.vim @@ -0,0 +1,116 @@ +" notmuch.vim plugin --- run notmuch within vim +" +" Copyright © Carl Worth +" +" This file is part of Notmuch. +" +" Notmuch is free software: you can redistribute it and/or modify it +" under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" Notmuch is distributed in the hope that it will be useful, but +" WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +" General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with Notmuch. If not, see . +" +" Authors: Bart Trojanowski + +" --- defaults + +if !exists('g:notmuch_cmd') + let g:notmuch_cmd = 'notmuch' +endif + + +" --- implement search screen + +function! s:NM_cmd_search(words) + let data = split(s:NM_run(['search'] + a:words), "\n") + let disp = copy(data) + call map(disp, 'substitute(v:val, "^thread:\\S* ", "", "")' ) + + call s:NM_newBuffer('search', join(disp, "\n")) + let b:nm_raw_data = data + + nnoremap :call NM_search_display() +endfunction + +function! s:NM_search_display() + let line = line('.') + if !exists('b:nm_raw_data') + echo 'no b:nm_raw_data' + else + let info = b:nm_raw_data[line] + let what = split(info, '\W\+')[0] + call s:NM_cmd_show([what]) + endif +endfunction + + +" --- implement show screen + +function! s:NM_cmd_show(words) + let data = s:NM_run(['show'] + a:words) + + call s:NM_newBuffer('show', data) + let b:nm_raw_data = data +endfunction + + +" --- helper function + +function! s:NM_newBuffer(ft, content) + enew + setlocal buftype=nofile readonly modifiable + setlocal bufhidden=delete + silent put=a:content + keepjumps 0d + setlocal nomodifiable + setlocal cursorline + execute printf('setlocal filetype=notmuch-%s', a:ft) +endfunction + +function! s:NM_run(args) + let cmd = g:notmuch_cmd . ' ' . join(a:args) . '< /dev/null' + let out = system(cmd) + if v:shell_error + echohl Error + echo substitute(out, '\n*$', '', '') + echohl None + return '' + else + return out + endif +endfunction + + +" --- command handler + +function! NotMuch(args) + if !strlen(a:args) + call s:NM_cmd_search(['tag:inbox']) + return + endif + + echo "blarg!" + + let words = split(a:args) + " TODO: handle commands passed as arguments +endfunction +function! CompleteNotMuch(arg_lead, cmd_line, cursor_pos) + return [] +endfunction + + +" --- glue + +command! -nargs=* -complete=customlist,CompleteNotMuch NotMuch call NotMuch() +cabbrev notmuch =(getcmdtype()==':' && getcmdpos()==1 ? 'NotMuch' : 'notmuch') + +" --- hacks, only for development :) + +nnoremap ,nmr :source ~/.vim/plugin/notmuch.vim:call NotMuch('') From 5e7df3c17e0d07d5252820beb5ef1e0bfea86498 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 18 Nov 2009 21:00:17 -0500 Subject: [PATCH 005/110] move from search to show with Enter, and back with q --- vim/plugin/notmuch.vim | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 865624fe..a15f4df5 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -25,18 +25,22 @@ if !exists('g:notmuch_cmd') let g:notmuch_cmd = 'notmuch' endif - " --- implement search screen function! s:NM_cmd_search(words) - let data = split(s:NM_run(['search'] + a:words), "\n") - let disp = copy(data) + let data = s:NM_run(['search'] + a:words) + "let data = substitute(data, '27/27', '25/27', '') + "let data = substitute(data, '\[4/4\]', '[0/4]', '') + let lines = split(data, "\n") + let disp = copy(lines) call map(disp, 'substitute(v:val, "^thread:\\S* ", "", "")' ) call s:NM_newBuffer('search', join(disp, "\n")) - let b:nm_raw_data = data + let b:nm_raw_data = lines nnoremap :call NM_search_display() + setlocal cursorline + setlocal nowrap endfunction function! s:NM_search_display() @@ -45,7 +49,7 @@ function! s:NM_search_display() echo 'no b:nm_raw_data' else let info = b:nm_raw_data[line] - let what = split(info, '\W\+')[0] + let what = split(info, '\s\+')[0] call s:NM_cmd_show([what]) endif endfunction @@ -54,10 +58,14 @@ endfunction " --- implement show screen function! s:NM_cmd_show(words) + let bufnr = bufnr('%') let data = s:NM_run(['show'] + a:words) call s:NM_newBuffer('show', data) + setlocal bufhidden=delete let b:nm_raw_data = data + + exec printf("nnoremap q :b %d", bufnr) endfunction @@ -66,12 +74,11 @@ endfunction function! s:NM_newBuffer(ft, content) enew setlocal buftype=nofile readonly modifiable - setlocal bufhidden=delete silent put=a:content keepjumps 0d setlocal nomodifiable - setlocal cursorline - execute printf('setlocal filetype=notmuch-%s', a:ft) + execute printf('set filetype=notmuch-%s', a:ft) + execute printf('set syntax=notmuch-%s', a:ft) endfunction function! s:NM_run(args) From 3493ea0ed5bd20b961aafa01eeddaf8cbc49b52f Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 18 Nov 2009 21:00:43 -0500 Subject: [PATCH 006/110] added syntax files for search and show screens --- vim/syntax/notmuch-search.vim | 22 ++++++++++++++++++++++ vim/syntax/notmuch-show.vim | 13 +++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 vim/syntax/notmuch-search.vim create mode 100644 vim/syntax/notmuch-show.vim diff --git a/vim/syntax/notmuch-search.vim b/vim/syntax/notmuch-search.vim new file mode 100644 index 00000000..eb7d88fa --- /dev/null +++ b/vim/syntax/notmuch-search.vim @@ -0,0 +1,22 @@ +" notmuch search mode syntax file + +" TODO: I cannot figure out why nmSearchTags is not matching anything :( + +syntax region nmSearchDate start="^" end="\%13v" +syntax region nmSearchCountAndFrom start="\%14v\[" end=";" oneline contains=nmSearchCount,nmSearchFrom +syntax match nmSearchFrom ' .*;' contained +syntax region nmSearchCount start="\%14v\[" end="\]" contained contains=nmSearchCountZero,nmSearchCountSome,nmSearchCountAll +syntax match nmSearchCountZero '0/\(\d\+\)' contained +syntax match nmSearchCountSome '\([1-9]\d*\)/\(\d\+\)' contained +syntax match nmSearchCountAll '\(\d\+\)/\1' contained +syntax match nmSearchTags /([^)]\+)$/ + +highlight link nmSearchDate Statement +"highlight link nmSearchCount Comment +highlight link nmSearchCountZero Function +highlight link nmSearchCountSome Special +highlight link nmSearchCountAll Type +highlight link nmSearchFrom Include +highlight link nmSearchTags String + +highlight CursorLine term=reverse cterm=reverse gui=reverse diff --git a/vim/syntax/notmuch-show.vim b/vim/syntax/notmuch-show.vim new file mode 100644 index 00000000..06dd2ea2 --- /dev/null +++ b/vim/syntax/notmuch-show.vim @@ -0,0 +1,13 @@ +" notmuch show mode syntax file + +syntax region nmShowMessage start=" message{" end=" message}" contains=nmShowHeader,nmShowBody,nmShowAttachment,nmShowPart +syntax region nmShowHeader start=" header{" end=" header}" contained +syntax region nmShowBody start=" body{" end=" body}" contained contains=nmShowAttachment,nmShowPart +syntax region nmShowAttachment start=" attachment{" end=" attachment}" contained +syntax region nmShowPart start=" part{" end=" part}" contained + +highlight link nmShowMessage Error +highlight link nmShowHeader Type +highlight link nmShowBody Statement +highlight link nmShowAttachment Statement +highlight link nmShowPart String From dd7bab62731a104e2f7dcc717fc90ab92b7f53f9 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 18 Nov 2009 21:00:56 -0500 Subject: [PATCH 007/110] simplify install with a Makefile --- vim/Makefile | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 vim/Makefile diff --git a/vim/Makefile b/vim/Makefile new file mode 100644 index 00000000..89e18be1 --- /dev/null +++ b/vim/Makefile @@ -0,0 +1,24 @@ +.PHONY: all help install link symlink + +FILES = plugin/notmuch.vim \ + $(wildcard syntax/notmuch-*.vim) + +PREFIX = $(shell ls -d ~/.vim/) + +OUT_FILES = $(FILES:%=${PREFIX}/%) + +all: help + +help: + @echo "I don't actually build anything, but I will help you install" + @echo "notmuch support for vim." + @echo + @echo " make install - copy plugin scripts and syntax files to ~/.vim" + @echo " make symlink - create symlinks in ~/.vim (useful for development)" + +install: ${OUT_FILES} +link symlink: + ${MAKE} SYMLINK=1 install + +${OUT_FILES}: ${PREFIX}/%: % + $(if ${SYMLINK},ln -fs,cp) `pwd`/$< $@ From df5137ff34d97b6dcdc90c8e07d9fb523b7bc2be Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 18 Nov 2009 21:03:51 -0500 Subject: [PATCH 008/110] README --- vim/README | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 vim/README diff --git a/vim/README b/vim/README new file mode 100644 index 00000000..bd453a40 --- /dev/null +++ b/vim/README @@ -0,0 +1,10 @@ +This directory contains a vim script that allows reading notmuch mail +through vim. + +To install: + + make install + +To run: + + vim -c ':NotMuch' From cfb18a6cbb3e247c910c427ec2dce96740870730 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 18 Nov 2009 21:13:24 -0500 Subject: [PATCH 009/110] reverse order so that the latest is at top --- vim/plugin/notmuch.vim | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index a15f4df5..00ee9842 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -25,10 +25,18 @@ if !exists('g:notmuch_cmd') let g:notmuch_cmd = 'notmuch' endif +if !exists('g:notmuch_search_reverse') + let g:notmuch_search_reverse = 1 +endif + " --- implement search screen function! s:NM_cmd_search(words) - let data = s:NM_run(['search'] + a:words) + let cmd = ['search'] + if g:notmuch_search_reverse + let cmd = cmd + ['--reverse'] + endif + let data = s:NM_run(cmd + a:words) "let data = substitute(data, '27/27', '25/27', '') "let data = substitute(data, '\[4/4\]', '[0/4]', '') let lines = split(data, "\n") From 02fbef68c5c433513fe3a3a71dde83f39d770bad Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 18 Nov 2009 21:13:46 -0500 Subject: [PATCH 010/110] add 's' binding to let you search for different terms --- vim/plugin/notmuch.vim | 1 + 1 file changed, 1 insertion(+) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 00ee9842..77e3021d 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -47,6 +47,7 @@ function! s:NM_cmd_search(words) let b:nm_raw_data = lines nnoremap :call NM_search_display() + nnoremap s :call NM_cmd_search(split(input('NotMuch Search:'))) setlocal cursorline setlocal nowrap endfunction From 3fe89c43dd484cc90efabc12055c9dda5383d009 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 18 Nov 2009 21:18:24 -0500 Subject: [PATCH 011/110] updated README --- vim/README | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/vim/README b/vim/README index bd453a40..c55875b1 100644 --- a/vim/README +++ b/vim/README @@ -1,10 +1,28 @@ This directory contains a vim script that allows reading notmuch mail through vim. -To install: +NOTE: this is a work in progress. Patches welcome. +To install: make install To run: - vim -c ':NotMuch' + + from vim: + :NotMuch + +Buffer types: + [notmuch-search] + You are presented with the search results when you run :NotMuch. + + Keybindings: + - show the selected message + s - alter search criteria + + [notmuch-show] + This is the display of the message. + + Keybindings: + q - return to search display + From 905a08788e0e1620ff4202269af2a8e4666767e1 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 18 Nov 2009 21:27:50 -0500 Subject: [PATCH 012/110] make from search screen display the correct message --- vim/plugin/notmuch.vim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 77e3021d..90678b93 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -53,11 +53,11 @@ function! s:NM_cmd_search(words) endfunction function! s:NM_search_display() - let line = line('.') if !exists('b:nm_raw_data') echo 'no b:nm_raw_data' else - let info = b:nm_raw_data[line] + let line = line('.') + let info = b:nm_raw_data[line-1] let what = split(info, '\s\+')[0] call s:NM_cmd_show([what]) endif @@ -78,7 +78,7 @@ function! s:NM_cmd_show(words) endfunction -" --- helper function +" --- helper functions function! s:NM_newBuffer(ft, content) enew From c80ab27d08540d3f434629f62bdf2f6a13a1cf41 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 19 Nov 2009 12:30:38 -0500 Subject: [PATCH 013/110] grab all the pattern matchers from the emacs script --- vim/plugin/notmuch.vim | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 90678b93..2b92ad68 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -29,6 +29,28 @@ if !exists('g:notmuch_search_reverse') let g:notmuch_search_reverse = 1 endif +" --- used to match output of notmuch + +let s:notmuch_show_message_begin_regexp = '^ message{' +let s:notmuch_show_message_end_regexp = '^ message}' +let s:notmuch_show_header_begin_regexp = '^ header{' +let s:notmuch_show_header_end_regexp = '^ header}' +let s:notmuch_show_body_begin_regexp = '^ body{' +let s:notmuch_show_body_end_regexp = '^ body}' +let s:notmuch_show_attachment_begin_regexp = '^ attachment{' +let s:notmuch_show_attachment_end_regexp = '^ attachment}' +let s:notmuch_show_part_begin_regexp = '^ part{' +let s:notmuch_show_part_end_regexp = '^ part}' +let s:notmuch_show_marker_regexp = '^ \\(message\\|header\\|body\\|attachment\\|part\\)[{}].*$' + +let s:notmuch_show_id_regexp = '\(id:[^ ]*\)' +let s:notmuch_show_depth_regexp = ' depth:\([0-9]*\) ' +let s:notmuch_show_filename_regexp = 'filename:\(.*\)$' +let s:notmuch_show_tags_regexp = '(\([^)]*\))$' + +let s:notmuch_show_signature_regexp = '^\(-- \?\|_\+\)$' +let s:notmuch_show_signature_lines_max = 12 + " --- implement search screen function! s:NM_cmd_search(words) From c6314fa2347fff97436acc0591cc4e6e557a19d6 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 19 Nov 2009 12:30:59 -0500 Subject: [PATCH 014/110] naively fold all signatures --- vim/plugin/notmuch.vim | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 2b92ad68..a57b2ae8 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -96,9 +96,36 @@ function! s:NM_cmd_show(words) setlocal bufhidden=delete let b:nm_raw_data = data + call s:NM_cmd_show_mkfolds() + exec printf("nnoremap q :b %d", bufnr) endfunction +function! s:NM_cmd_show_mkfolds() + let modetype = '' + let modeline = -1 + let lnum = 1 + while lnum <= line('$') + let line = getline(lnum) + if modetype == '' + if match(line, s:notmuch_show_signature_regexp) != -1 + let modetype = 'sig' + let modeline = lnum + echo "start=" . modeline + endif + elseif modetype == 'sig' + if (lnum - modeline) > s:notmuch_show_signature_lines_max + let modetype = '' + elseif match(line, s:notmuch_show_part_end_regexp) != -1 + exec printf('%d,%dfold', modeline, lnum) + let modetype = '' + endif + endif + + let lnum = lnum + 1 + endwhile +endfunction + " --- helper functions From 71bdd859dc6f80a918412396cb66c219e0e60669 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 19 Nov 2009 12:35:41 -0500 Subject: [PATCH 015/110] folding for citations --- vim/plugin/notmuch.vim | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index a57b2ae8..5fe438e7 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -51,6 +51,8 @@ let s:notmuch_show_tags_regexp = '(\([^)]*\))$' let s:notmuch_show_signature_regexp = '^\(-- \?\|_\+\)$' let s:notmuch_show_signature_lines_max = 12 +let s:notmuch_show_citation_regexp = '^\s*>' + " --- implement search screen function! s:NM_cmd_search(words) @@ -111,7 +113,14 @@ function! s:NM_cmd_show_mkfolds() if match(line, s:notmuch_show_signature_regexp) != -1 let modetype = 'sig' let modeline = lnum - echo "start=" . modeline + elseif match(line, s:notmuch_show_citation_regexp) != -1 + let modetype = 'cit' + let modeline = lnum + endif + elseif modetype == 'cit' + if match(line, s:notmuch_show_citation_regexp) == -1 + exec printf('%d,%dfold', modeline, lnum) + let modetype = '' endif elseif modetype == 'sig' if (lnum - modeline) > s:notmuch_show_signature_lines_max From 89dc64726f9a396b0a0912788e1736141968c8b3 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 19 Nov 2009 16:20:16 -0500 Subject: [PATCH 016/110] first attempt to fold the message nicely --- vim/plugin/notmuch.vim | 47 +++++++++++++++++++++++++++++++++-- vim/syntax/notmuch-search.vim | 6 ++--- vim/syntax/notmuch-show.vim | 17 +++++++++---- 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 5fe438e7..70f38e2a 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -99,17 +99,53 @@ function! s:NM_cmd_show(words) let b:nm_raw_data = data call s:NM_cmd_show_mkfolds() + setlocal foldtext=NM_cmd_show_foldtext() + setlocal fillchars= + setlocal foldcolumn=5 exec printf("nnoremap q :b %d", bufnr) endfunction function! s:NM_cmd_show_mkfolds() + let msg_start = -1 + let hdr_start = -1 + let bdy_start = -1 + let prt_start = -1 let modetype = '' let modeline = -1 let lnum = 1 + let b:nm_fold_data = {} while lnum <= line('$') let line = getline(lnum) - if modetype == '' + if match(line, s:notmuch_show_message_begin_regexp) != -1 + let msg_start = lnum + elseif match(line, s:notmuch_show_message_end_regexp) != -1 + exec printf('%d,%dfold', msg_start, lnum) + exec printf('%dfoldopen', msg_start) + let b:nm_fold_data[msg_start] = ['msg', getline(msg_start)] + + elseif match(line, s:notmuch_show_header_begin_regexp) != -1 + let hdr_start = lnum + elseif match(line, s:notmuch_show_header_end_regexp) != -1 + exec printf('%d,%dfold', hdr_start, lnum) + exec printf('%dfoldclose', hdr_start) + let b:nm_fold_data[hdr_start] = ['hdr', '* ' . getline(hdr_start+1) . ' [ Press "h" for full header. ]'] + + elseif match(line, s:notmuch_show_body_begin_regexp) != -1 + let bdy_start = lnum + elseif match(line, s:notmuch_show_body_end_regexp) != -1 + exec printf('%d,%dfold', bdy_start, lnum) + exec printf('%dfoldopen', bdy_start) + let b:nm_fold_data[bdy_start] = ['bdy', getline(bdy_start)] + + elseif match(line, s:notmuch_show_part_begin_regexp) != -1 + let prt_start = lnum + elseif match(line, s:notmuch_show_part_end_regexp) != -1 + exec printf('%d,%dfold', prt_start, lnum) + exec printf('%dfoldopen', prt_start) + let b:nm_fold_data[msg_start] = ['msg', getline(prt_start)] + + elseif modetype == '' if match(line, s:notmuch_show_signature_regexp) != -1 let modetype = 'sig' let modeline = lnum @@ -120,13 +156,16 @@ function! s:NM_cmd_show_mkfolds() elseif modetype == 'cit' if match(line, s:notmuch_show_citation_regexp) == -1 exec printf('%d,%dfold', modeline, lnum) + let b:nm_fold_data[modeline] = [modetype, printf('[ %d-line citation. Press "c" to show. ]', lnum - modeline)] let modetype = '' endif elseif modetype == 'sig' if (lnum - modeline) > s:notmuch_show_signature_lines_max let modetype = '' elseif match(line, s:notmuch_show_part_end_regexp) != -1 - exec printf('%d,%dfold', modeline, lnum) + let modeline2 = lnum - 1 + exec printf('%d,%dfold', modeline, modeline2) + let b:nm_fold_data[modeline] = [modetype, printf('[ %d-line signature. Press "s" to show. ]', modeline2 - modeline)] let modetype = '' endif endif @@ -135,6 +174,10 @@ function! s:NM_cmd_show_mkfolds() endwhile endfunction +function! NM_cmd_show_foldtext() + return b:nm_fold_data[v:foldstart][1] +endfunction + " --- helper functions diff --git a/vim/syntax/notmuch-search.vim b/vim/syntax/notmuch-search.vim index eb7d88fa..4b694722 100644 --- a/vim/syntax/notmuch-search.vim +++ b/vim/syntax/notmuch-search.vim @@ -2,10 +2,10 @@ " TODO: I cannot figure out why nmSearchTags is not matching anything :( -syntax region nmSearchDate start="^" end="\%13v" -syntax region nmSearchCountAndFrom start="\%14v\[" end=";" oneline contains=nmSearchCount,nmSearchFrom +syntax region nmSearchDate start='^' end='\%13v' +syntax region nmSearchCountAndFrom start='\%14v\[' end=';' oneline contains=nmSearchCount,nmSearchFrom syntax match nmSearchFrom ' .*;' contained -syntax region nmSearchCount start="\%14v\[" end="\]" contained contains=nmSearchCountZero,nmSearchCountSome,nmSearchCountAll +syntax region nmSearchCount start='\%14v\[' end='\]' contained contains=nmSearchCountZero,nmSearchCountSome,nmSearchCountAll syntax match nmSearchCountZero '0/\(\d\+\)' contained syntax match nmSearchCountSome '\([1-9]\d*\)/\(\d\+\)' contained syntax match nmSearchCountAll '\(\d\+\)/\1' contained diff --git a/vim/syntax/notmuch-show.vim b/vim/syntax/notmuch-show.vim index 06dd2ea2..02e12e99 100644 --- a/vim/syntax/notmuch-show.vim +++ b/vim/syntax/notmuch-show.vim @@ -1,13 +1,20 @@ " notmuch show mode syntax file -syntax region nmShowMessage start=" message{" end=" message}" contains=nmShowHeader,nmShowBody,nmShowAttachment,nmShowPart -syntax region nmShowHeader start=" header{" end=" header}" contained -syntax region nmShowBody start=" body{" end=" body}" contained contains=nmShowAttachment,nmShowPart -syntax region nmShowAttachment start=" attachment{" end=" attachment}" contained -syntax region nmShowPart start=" part{" end=" part}" contained +syntax region nmShowMessage start=' message{' end=' message}' contains=nmBlockStart,nmShowHeader,nmShowBody,nmShowAttachment,nmShowPart,nmBlockEnd +syntax region nmShowHeader start=' header{' end=' header}' contained contains=nmBlockStart,nmBlockEnd +syntax region nmShowBody start=' body{' end=' body}' contained contains=nmBlockStart,nmShowAttachment,nmShowPart,nmBlockEnd +syntax region nmShowAttachment start=' attachment{' end=' attachment}' contained contains=nmBlockStart,nmBlockEnd +syntax region nmShowPart start=' part{' end=' part}' contained contains=nmBlockStart,nmBlockEnd + +syntax region nmBlockStart start='^ [a-z]\+{' end='$' oneline +syntax region nmBlockEnd start='^ [a-z]\+}' end='$' oneline highlight link nmShowMessage Error highlight link nmShowHeader Type highlight link nmShowBody Statement highlight link nmShowAttachment Statement highlight link nmShowPart String +highlight link nmBlockStart Ignore +highlight link nmBlockEnd Ignore + +highlight Folded term=reverse ctermfg=LightGrey ctermbg=Black guifg=LightGray guibg=Black From c53b9455049e638ac2cb03d8e1b9e1f01e5eb625 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 19 Nov 2009 22:47:09 -0500 Subject: [PATCH 017/110] completely rewritten show handling --- vim/plugin/notmuch.vim | 239 +++++++++++++++++++++++++++++------------ 1 file changed, 172 insertions(+), 67 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 70f38e2a..18e6a598 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -43,9 +43,7 @@ let s:notmuch_show_part_begin_regexp = '^ part{' let s:notmuch_show_part_end_regexp = '^ part}' let s:notmuch_show_marker_regexp = '^ \\(message\\|header\\|body\\|attachment\\|part\\)[{}].*$' -let s:notmuch_show_id_regexp = '\(id:[^ ]*\)' -let s:notmuch_show_depth_regexp = ' depth:\([0-9]*\) ' -let s:notmuch_show_filename_regexp = 'filename:\(.*\)$' +let s:notmuch_show_message_parse_regexp = '\(id:[^ ]*\) depth:\([0-9]*\) filename:\(.*\)$' let s:notmuch_show_tags_regexp = '(\([^)]*\))$' let s:notmuch_show_signature_regexp = '^\(-- \?\|_\+\)$' @@ -53,6 +51,11 @@ let s:notmuch_show_signature_lines_max = 12 let s:notmuch_show_citation_regexp = '^\s*>' +let s:notmuch_show_headers = [ 'Subject', 'From' ] + +let s:notmuch_show_fold_signatures = 1 +let s:notmuch_show_fold_citations = 1 + " --- implement search screen function! s:NM_cmd_search(words) @@ -68,7 +71,7 @@ function! s:NM_cmd_search(words) call map(disp, 'substitute(v:val, "^thread:\\S* ", "", "")' ) call s:NM_newBuffer('search', join(disp, "\n")) - let b:nm_raw_data = lines + let b:nm_raw_lines = lines nnoremap :call NM_search_display() nnoremap s :call NM_cmd_search(split(input('NotMuch Search:'))) @@ -77,11 +80,11 @@ function! s:NM_cmd_search(words) endfunction function! s:NM_search_display() - if !exists('b:nm_raw_data') - echo 'no b:nm_raw_data' + if !exists('b:nm_raw_lines') + echo 'no b:nm_raw_lines' else let line = line('.') - let info = b:nm_raw_data[line-1] + let info = b:nm_raw_lines[line-1] let what = split(info, '\s\+')[0] call s:NM_cmd_show([what]) endif @@ -93,10 +96,13 @@ endfunction function! s:NM_cmd_show(words) let bufnr = bufnr('%') let data = s:NM_run(['show'] + a:words) + let lines = split(data, "\n") - call s:NM_newBuffer('show', data) + let info = s:NM_cmd_show_parse(lines) + + call s:NM_newBuffer('show', join(info['disp'], "\n")) setlocal bufhidden=delete - let b:nm_raw_data = data + let b:nm_raw_info = info call s:NM_cmd_show_mkfolds() setlocal foldtext=NM_cmd_show_foldtext() @@ -106,76 +112,175 @@ function! s:NM_cmd_show(words) exec printf("nnoremap q :b %d", bufnr) endfunction -function! s:NM_cmd_show_mkfolds() - let msg_start = -1 - let hdr_start = -1 - let bdy_start = -1 - let prt_start = -1 - let modetype = '' - let modeline = -1 - let lnum = 1 - let b:nm_fold_data = {} - while lnum <= line('$') - let line = getline(lnum) - if match(line, s:notmuch_show_message_begin_regexp) != -1 - let msg_start = lnum - elseif match(line, s:notmuch_show_message_end_regexp) != -1 - exec printf('%d,%dfold', msg_start, lnum) - exec printf('%dfoldopen', msg_start) - let b:nm_fold_data[msg_start] = ['msg', getline(msg_start)] +" s:NM_cmd_show_parse returns the following dictionary: +" 'disp': lines to display +" 'msgs': message info dicts { start, end, id, depth, filename, descr, header } +" 'folds': fold info arrays [ type, start, end ] +" 'foldtext': fold text indexed by start line +function! s:NM_cmd_show_parse(inlines) + let info = { 'disp': [], + \ 'msgs': [], + \ 'folds': [], + \ 'foldtext': {} } + let msg = {} + let hdr = {} - elseif match(line, s:notmuch_show_header_begin_regexp) != -1 - let hdr_start = lnum - elseif match(line, s:notmuch_show_header_end_regexp) != -1 - exec printf('%d,%dfold', hdr_start, lnum) - exec printf('%dfoldclose', hdr_start) - let b:nm_fold_data[hdr_start] = ['hdr', '* ' . getline(hdr_start+1) . ' [ Press "h" for full header. ]'] + let in_message = 0 + let in_header = 0 + let in_body = 0 + let in_part = 0 - elseif match(line, s:notmuch_show_body_begin_regexp) != -1 - let bdy_start = lnum - elseif match(line, s:notmuch_show_body_end_regexp) != -1 - exec printf('%d,%dfold', bdy_start, lnum) - exec printf('%dfoldopen', bdy_start) - let b:nm_fold_data[bdy_start] = ['bdy', getline(bdy_start)] + let body_start = -1 - elseif match(line, s:notmuch_show_part_begin_regexp) != -1 - let prt_start = lnum - elseif match(line, s:notmuch_show_part_end_regexp) != -1 - exec printf('%d,%dfold', prt_start, lnum) - exec printf('%dfoldopen', prt_start) - let b:nm_fold_data[msg_start] = ['msg', getline(prt_start)] + let mode_type = '' + let mode_start = -1 - elseif modetype == '' - if match(line, s:notmuch_show_signature_regexp) != -1 - let modetype = 'sig' - let modeline = lnum - elseif match(line, s:notmuch_show_citation_regexp) != -1 - let modetype = 'cit' - let modeline = lnum + let inlnum = 0 + for line in a:inlines + let inlnum = inlnum + 1 + let foldinfo = [] + + if in_part + if match(line, s:notmuch_show_part_end_regexp) != -1 + call add(info['disp'], '') + let in_part = 0 + else + call add(info['disp'], line) + end + + if in_part && mode_type == '' + if match(line, s:notmuch_show_signature_regexp) != -1 + let mode_type = 'sig' + let mode_start = len(info['disp']) + "echoe 'TYPE: ' . mode_type . ' @' . mode_start + elseif match(line, s:notmuch_show_citation_regexp) != -1 + let mode_type = 'cit' + let mode_start = len(info['disp']) + "echoe 'TYPE: ' . mode_type . ' @' . mode_start + endif + elseif mode_type == 'cit' + if !in_part || match(line, s:notmuch_show_citation_regexp) == -1 + let outlnum = len(info['disp']) + let foldinfo = [ mode_type, mode_start, outlnum, + \ printf('[ %d-line citation. Press "c" to show. ]', outlnum - mode_start) ] + let mode_type = '' + endif + elseif mode_type == 'sig' + let outlnum = len(info['disp']) + if (outlnum - mode_start) > s:notmuch_show_signature_lines_max + let mode_type = '' + elseif !in_part + let outlnum = outlnum - 1 + let foldinfo = [ mode_type, mode_start, outlnum, + \ printf('[ %d-line signature. Press "s" to show. ]', outlnum - mode_start) ] + let mode_type = '' + endif endif - elseif modetype == 'cit' - if match(line, s:notmuch_show_citation_regexp) == -1 - exec printf('%d,%dfold', modeline, lnum) - let b:nm_fold_data[modeline] = [modetype, printf('[ %d-line citation. Press "c" to show. ]', lnum - modeline)] - let modetype = '' + + elseif in_body + if match(line, s:notmuch_show_body_end_regexp) != -1 + let body_end = len(info['disp']) + let foldinfo = [ 'body', body_start, body_end, + \ printf('[ BODY %d - %d lines ]', len(info['msgs']), body_end - body_start) ] + + let in_body = 0 + + elseif match(line, s:notmuch_show_part_begin_regexp) != -1 + let in_part = 1 + let m = matchlist(line, 'ID: \(\d\+\), Content-type: \(\S\+\)') + if len(m) + call add(info['disp'], + \ printf('--- part %d --- %s ---', m[1], m[2])) + endif endif - elseif modetype == 'sig' - if (lnum - modeline) > s:notmuch_show_signature_lines_max - let modetype = '' - elseif match(line, s:notmuch_show_part_end_regexp) != -1 - let modeline2 = lnum - 1 - exec printf('%d,%dfold', modeline, modeline2) - let b:nm_fold_data[modeline] = [modetype, printf('[ %d-line signature. Press "s" to show. ]', modeline2 - modeline)] - let modetype = '' + + elseif in_header + if in_header == 1 + let msg['descr'] = line + call add(info['disp'], line) + let in_header = 2 + + else + if match(line, s:notmuch_show_header_end_regexp) != -1 + let msg['header'] = hdr + let in_header = 0 + let hdr = {} + else + let m = matchlist(line, '^\(\w\+\):\s*\(.*\)$') + if len(m) + let hdr[m[1]] = m[2] + if match(s:notmuch_show_headers, m[1]) != -1 + call add(info['disp'], line) + endif + endif + endif + endif + + elseif in_message + if match(line, s:notmuch_show_message_end_regexp) != -1 + let msg['end'] = len(info['disp']) + call add(info['disp'], '') + + let foldinfo = [ 'match', msg['start'], msg['end'], + \ printf('[ MSG %d - %s ]', len(info['msgs']), msg['descr']) ] + + call add(info['msgs'], msg) + let msg = {} + let in_message = 0 + let in_header = 0 + let in_body = 0 + let in_part = 0 + + elseif match(line, s:notmuch_show_header_begin_regexp) != -1 + let in_header = 1 + continue + + elseif match(line, s:notmuch_show_body_begin_regexp) != -1 + let body_start = len(info['disp']) + 1 + let in_body = 1 + continue + endif + + else + if match(line, s:notmuch_show_message_begin_regexp) != -1 + let msg['start'] = len(info['disp']) + 1 + + let m = matchlist(line, s:notmuch_show_message_parse_regexp) + if len(m) + let msg['id'] = m[1] + let msg['depth'] = m[2] + let msg['filename'] = m[3] + endif + + let in_message = 1 endif endif - let lnum = lnum + 1 - endwhile + if len(foldinfo) + call add(info['folds'], foldinfo[0:2]) + let info['foldtext'][foldinfo[1]] = foldinfo[3] + endif + endfor + return info +endfunction + +function! s:NM_cmd_show_mkfolds() + let info = b:nm_raw_info + + for afold in info['folds'] + exec printf('%d,%dfold', afold[1], afold[2]) + if (afold[0] == 'sig' && s:notmuch_show_fold_signatures) + \ || (afold[0] == 'cit' && s:notmuch_show_fold_citations) + exec printf('%dfoldclose', afold[1]) + else + exec printf('%dfoldopen', afold[1]) + endif + endfor endfunction function! NM_cmd_show_foldtext() - return b:nm_fold_data[v:foldstart][1] + let foldtext = b:nm_raw_info['foldtext'] + return foldtext[v:foldstart] endfunction From 8a31802b94b935bcb5cb784e7dacead467972241 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 01:13:50 -0500 Subject: [PATCH 018/110] parsing rewritten one more time --- vim/plugin/notmuch.vim | 93 ++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 35 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 18e6a598..d7723781 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -105,9 +105,10 @@ function! s:NM_cmd_show(words) let b:nm_raw_info = info call s:NM_cmd_show_mkfolds() + call s:NM_cmd_show_mksyntax() setlocal foldtext=NM_cmd_show_foldtext() setlocal fillchars= - setlocal foldcolumn=5 + setlocal foldcolumn=6 exec printf("nnoremap q :b %d", bufnr) endfunction @@ -128,9 +129,10 @@ function! s:NM_cmd_show_parse(inlines) let in_message = 0 let in_header = 0 let in_body = 0 - let in_part = 0 + let in_part = '' let body_start = -1 + let part_start = -1 let mode_type = '' let mode_start = -1 @@ -140,44 +142,62 @@ function! s:NM_cmd_show_parse(inlines) let inlnum = inlnum + 1 let foldinfo = [] - if in_part + if strlen(in_part) + let part_end = 0 + if match(line, s:notmuch_show_part_end_regexp) != -1 - call add(info['disp'], '') - let in_part = 0 + let part_end = len(info['disp']) else call add(info['disp'], line) - end + endif - if in_part && mode_type == '' - if match(line, s:notmuch_show_signature_regexp) != -1 - let mode_type = 'sig' - let mode_start = len(info['disp']) - "echoe 'TYPE: ' . mode_type . ' @' . mode_start - elseif match(line, s:notmuch_show_citation_regexp) != -1 - let mode_type = 'cit' - let mode_start = len(info['disp']) - "echoe 'TYPE: ' . mode_type . ' @' . mode_start - endif - elseif mode_type == 'cit' - if !in_part || match(line, s:notmuch_show_citation_regexp) == -1 + if in_part == 'text/plain' + if !part_end && mode_type == '' + if match(line, s:notmuch_show_signature_regexp) != -1 + let mode_type = 'sig' + let mode_start = len(info['disp']) + elseif match(line, s:notmuch_show_citation_regexp) != -1 + let mode_type = 'cit' + let mode_start = len(info['disp']) + endif + elseif mode_type == 'cit' + if part_end || match(line, s:notmuch_show_citation_regexp) == -1 + let outlnum = len(info['disp']) -1 + let foldinfo = [ mode_type, mode_start, outlnum, + \ printf('[ %d-line citation. Press "c" to show. ]', outlnum - mode_start) ] + let mode_type = '' + endif + elseif mode_type == 'sig' let outlnum = len(info['disp']) - let foldinfo = [ mode_type, mode_start, outlnum, - \ printf('[ %d-line citation. Press "c" to show. ]', outlnum - mode_start) ] - let mode_type = '' - endif - elseif mode_type == 'sig' - let outlnum = len(info['disp']) - if (outlnum - mode_start) > s:notmuch_show_signature_lines_max - let mode_type = '' - elseif !in_part - let outlnum = outlnum - 1 - let foldinfo = [ mode_type, mode_start, outlnum, - \ printf('[ %d-line signature. Press "s" to show. ]', outlnum - mode_start) ] - let mode_type = '' + if (outlnum - mode_start) > s:notmuch_show_signature_lines_max + echoe 'line ' . outlnum . ' stopped matching' + let mode_type = '' + elseif part_end + let foldinfo = [ mode_type, mode_start, outlnum, + \ printf('[ %d-line signature. Press "s" to show. ]', outlnum - mode_start) ] + let mode_type = '' + endif endif endif + 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 + if len(foldinfo) + call add(info['folds'], foldinfo[0:2]) + let info['foldtext'][foldinfo[1]] = foldinfo[3] + endif + + let foldinfo = [ 'text', part_start, part_end, + \ printf('[ %d-line %s. Press "p" to show. ]', part_end - part_start, in_part) ] + let in_part = '' + call add(info['disp'], '') + endif + elseif in_body + if !has_key(msg,'body_start') + let msg['body_start'] = len(info['disp']) + 1 + endif if match(line, s:notmuch_show_body_end_regexp) != -1 let body_end = len(info['disp']) let foldinfo = [ 'body', body_start, body_end, @@ -186,12 +206,14 @@ function! s:NM_cmd_show_parse(inlines) let in_body = 0 elseif match(line, s:notmuch_show_part_begin_regexp) != -1 - let in_part = 1 let m = matchlist(line, 'ID: \(\d\+\), Content-type: \(\S\+\)') + let in_part = 'unknown' if len(m) - call add(info['disp'], - \ printf('--- part %d --- %s ---', m[1], m[2])) + let in_part = m[2] endif + call add(info['disp'], + \ printf('--- %s ---', in_part)) + let part_start = len(info['disp']) + 1 endif elseif in_header @@ -199,6 +221,7 @@ function! s:NM_cmd_show_parse(inlines) let msg['descr'] = line call add(info['disp'], line) let in_header = 2 + let msg['hdr_start'] = len(info['disp']) + 1 else if match(line, s:notmuch_show_header_end_regexp) != -1 @@ -229,7 +252,7 @@ function! s:NM_cmd_show_parse(inlines) let in_message = 0 let in_header = 0 let in_body = 0 - let in_part = 0 + let in_part = '' elseif match(line, s:notmuch_show_header_begin_regexp) != -1 let in_header = 1 From 010eac8b434eee317b0d28eac9bcf544fc6994d1 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 01:15:00 -0500 Subject: [PATCH 019/110] pretty colouring and folding for message show --- vim/plugin/notmuch.vim | 15 +++++++++++++++ vim/syntax/notmuch-show.vim | 31 +++++++++++++++++-------------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index d7723781..6e1f8b14 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -301,6 +301,21 @@ function! s:NM_cmd_show_mkfolds() endfor endfunction +function! s:NM_cmd_show_mksyntax() + let info = b:nm_raw_info + let cnt = 0 + for msg in info['msgs'] + let cnt = cnt + 1 + let start = msg['start'] + let hdr_start = msg['hdr_start'] + let body_start = msg['body_start'] + let end = msg['end'] + exec printf('syntax region nmShowMsg%dDesc start=''\%%%dl'' end=''\%%%dl'' contains=@nmShowMsgDesc', cnt, start, start+1) + exec printf('syntax region nmShowMsg%dHead start=''\%%%dl'' end=''\%%%dl'' contains=@nmShowMsgHead', cnt, hdr_start, body_start) + exec printf('syntax region nmShowMsg%dBody start=''\%%%dl'' end=''\%%%dl'' contains=@nmShowMsgBody', cnt, body_start, end) + endfor +endfunction + function! NM_cmd_show_foldtext() let foldtext = b:nm_raw_info['foldtext'] return foldtext[v:foldstart] diff --git a/vim/syntax/notmuch-show.vim b/vim/syntax/notmuch-show.vim index 02e12e99..20c6b88f 100644 --- a/vim/syntax/notmuch-show.vim +++ b/vim/syntax/notmuch-show.vim @@ -1,20 +1,23 @@ " notmuch show mode syntax file -syntax region nmShowMessage start=' message{' end=' message}' contains=nmBlockStart,nmShowHeader,nmShowBody,nmShowAttachment,nmShowPart,nmBlockEnd -syntax region nmShowHeader start=' header{' end=' header}' contained contains=nmBlockStart,nmBlockEnd -syntax region nmShowBody start=' body{' end=' body}' contained contains=nmBlockStart,nmShowAttachment,nmShowPart,nmBlockEnd -syntax region nmShowAttachment start=' attachment{' end=' attachment}' contained contains=nmBlockStart,nmBlockEnd -syntax region nmShowPart start=' part{' end=' part}' contained contains=nmBlockStart,nmBlockEnd +syntax cluster nmShowMsgDesc contains=nmShowMsgDescWho,nmShowMsgDescDate,nmShowMsgDescTags +syntax match nmShowMsgDescWho /[^)]\+)/ contained +syntax match nmShowMsgDescDate / ([^)]\+[0-9]) / contained +syntax match nmShowMsgDescTags /([^)]\+)$/ contained -syntax region nmBlockStart start='^ [a-z]\+{' end='$' oneline -syntax region nmBlockEnd start='^ [a-z]\+}' end='$' oneline +syntax cluster nmShowMsgHead contains=nmShowMsgHeadKey,nmShowMsgHeadVal +syntax match nmShowMsgHeadKey /^[^:]\+: / contained +syntax match nmShowMsgHeadVal /^\([^:]\+: \)\@<=.*/ contained -highlight link nmShowMessage Error -highlight link nmShowHeader Type -highlight link nmShowBody Statement -highlight link nmShowAttachment Statement -highlight link nmShowPart String -highlight link nmBlockStart Ignore -highlight link nmBlockEnd Ignore +syntax cluster nmShowMsgBody contains=@nmShowMsgBodyMail,@nmShowMsgBodyGit +syntax include @nmShowMsgBodyMail syntax/mail.vim +syntax include @nmShowMsgBodyGit syntax/git-diff.vim + +highlight nmShowMsgDescWho term=reverse cterm=reverse gui=reverse +highlight link nmShowMsgDescDate Type +highlight link nmShowMsgDescTags String + +highlight link nmShowMsgHeadKey Macro +"highlight link nmShowMsgHeadVal NONE highlight Folded term=reverse ctermfg=LightGrey ctermbg=Black guifg=LightGray guibg=Black From 3dc96c6dc8885448b48c6a6a557df5a266f40f04 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 01:35:33 -0500 Subject: [PATCH 020/110] added ^n to handle walking messages --- vim/README | 1 + vim/plugin/notmuch.vim | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/vim/README b/vim/README index c55875b1..1ed2c424 100644 --- a/vim/README +++ b/vim/README @@ -25,4 +25,5 @@ Buffer types: Keybindings: q - return to search display + ^n - next message diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 6e1f8b14..94eb0bba 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -94,7 +94,7 @@ endfunction " --- implement show screen function! s:NM_cmd_show(words) - let bufnr = bufnr('%') + let prev_bufnr = bufnr('%') let data = s:NM_run(['show'] + a:words) let lines = split(data, "\n") @@ -103,6 +103,7 @@ function! s:NM_cmd_show(words) call s:NM_newBuffer('show', join(info['disp'], "\n")) setlocal bufhidden=delete let b:nm_raw_info = info + let b:nm_prev_bufnr = prev_bufnr call s:NM_cmd_show_mkfolds() call s:NM_cmd_show_mksyntax() @@ -110,7 +111,26 @@ function! s:NM_cmd_show(words) setlocal fillchars= setlocal foldcolumn=6 - exec printf("nnoremap q :b %d", bufnr) + exec printf("nnoremap q :b %d", b:nm_prev_bufnr) + nnoremap :call NM_cmd_show_next() +endfunction + +function! s:NM_cmd_show_next() + let info = b:nm_raw_info + let lnum = line('.') + let cnt = 0 + for msg in info['msgs'] + let cnt = cnt + 1 + if lnum >= msg['start'] + continue + endif + + exec printf('norm %dG', msg['start']) + norm zz + return + endfor + norm qj + call NM_search_display() endfunction " s:NM_cmd_show_parse returns the following dictionary: From 1e0005e6d0740e3af6b247a4cf7c7a42a461f4b0 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 01:39:22 -0500 Subject: [PATCH 021/110] fix a corner case with folding a single line citation --- vim/plugin/notmuch.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 94eb0bba..3b16a995 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -182,7 +182,7 @@ function! s:NM_cmd_show_parse(inlines) endif elseif mode_type == 'cit' if part_end || match(line, s:notmuch_show_citation_regexp) == -1 - let outlnum = len(info['disp']) -1 + let outlnum = len(info['disp']) let foldinfo = [ mode_type, mode_start, outlnum, \ printf('[ %d-line citation. Press "c" to show. ]', outlnum - mode_start) ] let mode_type = '' From 5a2d760067559b3fabf8718d189e815e7e6402da Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 01:57:57 -0500 Subject: [PATCH 022/110] toggle signatures and citations with s/c respectively --- vim/README | 2 ++ vim/plugin/notmuch.vim | 25 +++++++++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/vim/README b/vim/README index 1ed2c424..e4128b71 100644 --- a/vim/README +++ b/vim/README @@ -26,4 +26,6 @@ Buffer types: Keybindings: q - return to search display ^n - next message + s - toggle folding of signatures on and off + c - toggle folding of citations on and off diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 3b16a995..968b9aa6 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -53,8 +53,8 @@ let s:notmuch_show_citation_regexp = '^\s*>' let s:notmuch_show_headers = [ 'Subject', 'From' ] -let s:notmuch_show_fold_signatures = 1 -let s:notmuch_show_fold_citations = 1 +let g:notmuch_show_fold_signatures = 1 +let g:notmuch_show_fold_citations = 1 " --- implement search screen @@ -113,6 +113,8 @@ function! s:NM_cmd_show(words) exec printf("nnoremap q :b %d", b:nm_prev_bufnr) nnoremap :call NM_cmd_show_next() + nnoremap c :call NM_cmd_show_fold_toggle('c', 'cit', !g:notmuch_show_fold_citations) + nnoremap s :call NM_cmd_show_fold_toggle('s', 'sig', !g:notmuch_show_fold_signatures) endfunction function! s:NM_cmd_show_next() @@ -133,6 +135,21 @@ function! s:NM_cmd_show_next() call NM_search_display() endfunction +function! s:NM_cmd_show_fold_toggle(key, type, fold) + let info = b:nm_raw_info + let act = 'open' + if a:fold + let act = 'close' + endif + for fld in info['folds'] + if fld[0] == a:type + exec printf('%dfold%s', fld[1], act) + endif + endfor + exec printf('nnoremap %s :call NM_cmd_show_fold_toggle(''%s'', ''%s'', %d)', a:key, a:key, a:type, !a:fold) +endfunction + + " s:NM_cmd_show_parse returns the following dictionary: " 'disp': lines to display " 'msgs': message info dicts { start, end, id, depth, filename, descr, header } @@ -312,8 +329,8 @@ function! s:NM_cmd_show_mkfolds() for afold in info['folds'] exec printf('%d,%dfold', afold[1], afold[2]) - if (afold[0] == 'sig' && s:notmuch_show_fold_signatures) - \ || (afold[0] == 'cit' && s:notmuch_show_fold_citations) + if (afold[0] == 'sig' && g:notmuch_show_fold_signatures) + \ || (afold[0] == 'cit' && g:notmuch_show_fold_citations) exec printf('%dfoldclose', afold[1]) else exec printf('%dfoldopen', afold[1]) From 5c7ebe31d58d649bfb68627d642dde1cc6cf6493 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 09:35:12 -0500 Subject: [PATCH 023/110] make it possible to set config options from outside the script --- vim/plugin/notmuch.vim | 127 ++++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 52 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 968b9aa6..01511602 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -19,44 +19,65 @@ " " Authors: Bart Trojanowski -" --- defaults +" --- configuration defaults {{{1 -if !exists('g:notmuch_cmd') - let g:notmuch_cmd = 'notmuch' +let s:notmuch_defaults = { + \ 'g:notmuch_cmd': 'notmuch' , + \ 'g:notmuch_search_reverse': 1 , + \ 'g:notmuch_show_fold_signatures': 1 , + \ 'g:notmuch_show_fold_citations': 1 , + \ + \ 'g:notmuch_show_message_begin_regexp': '^ message{' , + \ 'g:notmuch_show_message_end_regexp': '^ message}' , + \ 'g:notmuch_show_header_begin_regexp': '^ header{' , + \ 'g:notmuch_show_header_end_regexp': '^ header}' , + \ 'g:notmuch_show_body_begin_regexp': '^ body{' , + \ 'g:notmuch_show_body_end_regexp': '^ body}' , + \ 'g:notmuch_show_attachment_begin_regexp': '^ attachment{' , + \ 'g:notmuch_show_attachment_end_regexp': '^ attachment}' , + \ 'g:notmuch_show_part_begin_regexp': '^ part{' , + \ 'g:notmuch_show_part_end_regexp': '^ part}' , + \ 'g:notmuch_show_marker_regexp': '^ \\(message\\|header\\|body\\|attachment\\|part\\)[{}].*$', + \ + \ 'g:notmuch_show_message_parse_regexp': '\(id:[^ ]*\) depth:\([0-9]*\) filename:\(.*\)$', + \ 'g:notmuch_show_tags_regexp': '(\([^)]*\))$' , + \ + \ 'g:notmuch_show_signature_regexp': '^\(-- \?\|_\+\)$' , + \ 'g:notmuch_show_signature_lines_max': 12 , + \ + \ 'g:notmuch_show_citation_regexp': '^\s*>' , + \ } + +" for some reason NM_set_defaults() didn't work for arrays... +if !exists('g:notmuch_show_headers') + let g:notmuch_show_headers = [ 'Subject', 'From' ] endif -if !exists('g:notmuch_search_reverse') - let g:notmuch_search_reverse = 1 -endif +" --- process and set the defaults {{{1 -" --- used to match output of notmuch +function! NM_set_defaults(force) + for [key, dflt] in items(s:notmuch_defaults) + let cmd = '' + if !a:force && exists(key) && type(dflt) == type(eval(key)) + continue + elseif type(dflt) == type(0) + let cmd = printf('let %s = %d', key, dflt) + elseif type(dflt) == type('') + let cmd = printf('let %s = ''%s''', key, dflt) + "elseif type(dflt) == type([]) + " let cmd = printf('let %s = %s', key, string(dflt)) + else + echoe printf('E: Unknown type in NM_set_defaults(%d) using [%s,%s]', + \ a:force, key, string(dflt)) + continue + endif + echoe cmd + exec cmd + endfor +endfunction +call NM_set_defaults(0) -let s:notmuch_show_message_begin_regexp = '^ message{' -let s:notmuch_show_message_end_regexp = '^ message}' -let s:notmuch_show_header_begin_regexp = '^ header{' -let s:notmuch_show_header_end_regexp = '^ header}' -let s:notmuch_show_body_begin_regexp = '^ body{' -let s:notmuch_show_body_end_regexp = '^ body}' -let s:notmuch_show_attachment_begin_regexp = '^ attachment{' -let s:notmuch_show_attachment_end_regexp = '^ attachment}' -let s:notmuch_show_part_begin_regexp = '^ part{' -let s:notmuch_show_part_end_regexp = '^ part}' -let s:notmuch_show_marker_regexp = '^ \\(message\\|header\\|body\\|attachment\\|part\\)[{}].*$' - -let s:notmuch_show_message_parse_regexp = '\(id:[^ ]*\) depth:\([0-9]*\) filename:\(.*\)$' -let s:notmuch_show_tags_regexp = '(\([^)]*\))$' - -let s:notmuch_show_signature_regexp = '^\(-- \?\|_\+\)$' -let s:notmuch_show_signature_lines_max = 12 - -let s:notmuch_show_citation_regexp = '^\s*>' - -let s:notmuch_show_headers = [ 'Subject', 'From' ] - -let g:notmuch_show_fold_signatures = 1 -let g:notmuch_show_fold_citations = 1 - -" --- implement search screen +" --- implement search screen {{{1 function! s:NM_cmd_search(words) let cmd = ['search'] @@ -91,7 +112,7 @@ function! s:NM_search_display() endfunction -" --- implement show screen +" --- implement show screen {{{1 function! s:NM_cmd_show(words) let prev_bufnr = bufnr('%') @@ -182,7 +203,7 @@ function! s:NM_cmd_show_parse(inlines) if strlen(in_part) let part_end = 0 - if match(line, s:notmuch_show_part_end_regexp) != -1 + if match(line, g:notmuch_show_part_end_regexp) != -1 let part_end = len(info['disp']) else call add(info['disp'], line) @@ -190,15 +211,15 @@ function! s:NM_cmd_show_parse(inlines) if in_part == 'text/plain' if !part_end && mode_type == '' - if match(line, s:notmuch_show_signature_regexp) != -1 + if match(line, g:notmuch_show_signature_regexp) != -1 let mode_type = 'sig' let mode_start = len(info['disp']) - elseif match(line, s:notmuch_show_citation_regexp) != -1 + elseif match(line, g:notmuch_show_citation_regexp) != -1 let mode_type = 'cit' let mode_start = len(info['disp']) endif elseif mode_type == 'cit' - if part_end || match(line, s:notmuch_show_citation_regexp) == -1 + if part_end || match(line, g:notmuch_show_citation_regexp) == -1 let outlnum = len(info['disp']) let foldinfo = [ mode_type, mode_start, outlnum, \ printf('[ %d-line citation. Press "c" to show. ]', outlnum - mode_start) ] @@ -206,7 +227,7 @@ function! s:NM_cmd_show_parse(inlines) endif elseif mode_type == 'sig' let outlnum = len(info['disp']) - if (outlnum - mode_start) > s:notmuch_show_signature_lines_max + if (outlnum - mode_start) > g:notmuch_show_signature_lines_max echoe 'line ' . outlnum . ' stopped matching' let mode_type = '' elseif part_end @@ -235,14 +256,14 @@ function! s:NM_cmd_show_parse(inlines) if !has_key(msg,'body_start') let msg['body_start'] = len(info['disp']) + 1 endif - if match(line, s:notmuch_show_body_end_regexp) != -1 + if match(line, g:notmuch_show_body_end_regexp) != -1 let body_end = len(info['disp']) let foldinfo = [ 'body', body_start, body_end, \ printf('[ BODY %d - %d lines ]', len(info['msgs']), body_end - body_start) ] let in_body = 0 - elseif match(line, s:notmuch_show_part_begin_regexp) != -1 + elseif match(line, g:notmuch_show_part_begin_regexp) != -1 let m = matchlist(line, 'ID: \(\d\+\), Content-type: \(\S\+\)') let in_part = 'unknown' if len(m) @@ -261,7 +282,7 @@ function! s:NM_cmd_show_parse(inlines) let msg['hdr_start'] = len(info['disp']) + 1 else - if match(line, s:notmuch_show_header_end_regexp) != -1 + if match(line, g:notmuch_show_header_end_regexp) != -1 let msg['header'] = hdr let in_header = 0 let hdr = {} @@ -269,7 +290,7 @@ function! s:NM_cmd_show_parse(inlines) let m = matchlist(line, '^\(\w\+\):\s*\(.*\)$') if len(m) let hdr[m[1]] = m[2] - if match(s:notmuch_show_headers, m[1]) != -1 + if match(g:notmuch_show_headers, m[1]) != -1 call add(info['disp'], line) endif endif @@ -277,7 +298,7 @@ function! s:NM_cmd_show_parse(inlines) endif elseif in_message - if match(line, s:notmuch_show_message_end_regexp) != -1 + if match(line, g:notmuch_show_message_end_regexp) != -1 let msg['end'] = len(info['disp']) call add(info['disp'], '') @@ -291,21 +312,21 @@ function! s:NM_cmd_show_parse(inlines) let in_body = 0 let in_part = '' - elseif match(line, s:notmuch_show_header_begin_regexp) != -1 + elseif match(line, g:notmuch_show_header_begin_regexp) != -1 let in_header = 1 continue - elseif match(line, s:notmuch_show_body_begin_regexp) != -1 + elseif match(line, g:notmuch_show_body_begin_regexp) != -1 let body_start = len(info['disp']) + 1 let in_body = 1 continue endif else - if match(line, s:notmuch_show_message_begin_regexp) != -1 + if match(line, g:notmuch_show_message_begin_regexp) != -1 let msg['start'] = len(info['disp']) + 1 - let m = matchlist(line, s:notmuch_show_message_parse_regexp) + let m = matchlist(line, g:notmuch_show_message_parse_regexp) if len(m) let msg['id'] = m[1] let msg['depth'] = m[2] @@ -359,7 +380,7 @@ function! NM_cmd_show_foldtext() endfunction -" --- helper functions +" --- helper functions {{{1 function! s:NM_newBuffer(ft, content) enew @@ -385,7 +406,7 @@ function! s:NM_run(args) endfunction -" --- command handler +" --- command handler {{{1 function! NotMuch(args) if !strlen(a:args) @@ -403,11 +424,13 @@ function! CompleteNotMuch(arg_lead, cmd_line, cursor_pos) endfunction -" --- glue +" --- glue {{{1 command! -nargs=* -complete=customlist,CompleteNotMuch NotMuch call NotMuch() cabbrev notmuch =(getcmdtype()==':' && getcmdpos()==1 ? 'NotMuch' : 'notmuch') -" --- hacks, only for development :) +" --- hacks, only for development :) {{{1 nnoremap ,nmr :source ~/.vim/plugin/notmuch.vim:call NotMuch('') + +" vim: set ft=vim ts=8 sw=8 et foldmethod=marker : From fe2a905110a9527e77e9c40ba8dd9aab369af6b9 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 09:42:29 -0500 Subject: [PATCH 024/110] make search screen mappings configurable via dictionary --- vim/plugin/notmuch.vim | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 01511602..b9fc8d22 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -53,6 +53,13 @@ if !exists('g:notmuch_show_headers') let g:notmuch_show_headers = [ 'Subject', 'From' ] endif +" --- keyboard mapping definitions {{{1 + +let g:notmuch_search_maps = { + \ '': ':call NM_search_display()', + \ 's': ':call NM_cmd_search(split(input(''NotMuch Search:'')))', + \ } + " --- process and set the defaults {{{1 function! NM_set_defaults(force) @@ -77,6 +84,15 @@ function! NM_set_defaults(force) endfunction call NM_set_defaults(0) +" --- assign keymaps {{{1 + +function! s:NM_set_map(maps) + for [key, code] in items(a:maps) + exec printf('nnoremap %s %s', key, code) + endfor +endfunction + + " --- implement search screen {{{1 function! s:NM_cmd_search(words) @@ -94,8 +110,7 @@ function! s:NM_cmd_search(words) call s:NM_newBuffer('search', join(disp, "\n")) let b:nm_raw_lines = lines - nnoremap :call NM_search_display() - nnoremap s :call NM_cmd_search(split(input('NotMuch Search:'))) + call NM_set_map(g:notmuch_search_maps) setlocal cursorline setlocal nowrap endfunction From f8c4b938405838a0608631ce68c88cc623c301ef Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 09:49:11 -0500 Subject: [PATCH 025/110] cleanup default handling code --- vim/plugin/notmuch.vim | 81 ++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index b9fc8d22..b2f46dde 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -48,10 +48,12 @@ let s:notmuch_defaults = { \ 'g:notmuch_show_citation_regexp': '^\s*>' , \ } -" for some reason NM_set_defaults() didn't work for arrays... -if !exists('g:notmuch_show_headers') - let g:notmuch_show_headers = [ 'Subject', 'From' ] -endif +" defaults for g:notmuch_show_headers +" override with: let g:notmuch_show_headers = [ ... ] +let s:notmuch_show_headers_defaults = [ + \ 'Subject', + \ 'From' + \ ] " --- keyboard mapping definitions {{{1 @@ -60,39 +62,6 @@ let g:notmuch_search_maps = { \ 's': ':call NM_cmd_search(split(input(''NotMuch Search:'')))', \ } -" --- process and set the defaults {{{1 - -function! NM_set_defaults(force) - for [key, dflt] in items(s:notmuch_defaults) - let cmd = '' - if !a:force && exists(key) && type(dflt) == type(eval(key)) - continue - elseif type(dflt) == type(0) - let cmd = printf('let %s = %d', key, dflt) - elseif type(dflt) == type('') - let cmd = printf('let %s = ''%s''', key, dflt) - "elseif type(dflt) == type([]) - " let cmd = printf('let %s = %s', key, string(dflt)) - else - echoe printf('E: Unknown type in NM_set_defaults(%d) using [%s,%s]', - \ a:force, key, string(dflt)) - continue - endif - echoe cmd - exec cmd - endfor -endfunction -call NM_set_defaults(0) - -" --- assign keymaps {{{1 - -function! s:NM_set_map(maps) - for [key, code] in items(a:maps) - exec printf('nnoremap %s %s', key, code) - endfor -endfunction - - " --- implement search screen {{{1 function! s:NM_cmd_search(words) @@ -395,7 +364,7 @@ function! NM_cmd_show_foldtext() endfunction -" --- helper functions {{{1 +" --- notmuch helper functions {{{1 function! s:NM_newBuffer(ft, content) enew @@ -420,6 +389,42 @@ function! s:NM_run(args) endif endfunction +" --- process and set the defaults {{{1 + +function! NM_set_defaults(force) + for [key, dflt] in items(s:notmuch_defaults) + let cmd = '' + if !a:force && exists(key) && type(dflt) == type(eval(key)) + continue + elseif type(dflt) == type(0) + let cmd = printf('let %s = %d', key, dflt) + elseif type(dflt) == type('') + let cmd = printf('let %s = ''%s''', key, dflt) + "elseif type(dflt) == type([]) + " let cmd = printf('let %s = %s', key, string(dflt)) + else + echoe printf('E: Unknown type in NM_set_defaults(%d) using [%s,%s]', + \ a:force, key, string(dflt)) + continue + endif + echoe cmd + exec cmd + endfor +endfunction +call NM_set_defaults(0) + +" for some reason NM_set_defaults() didn't work for arrays... +if !exists('g:notmuch_show_headers') + let g:notmuch_show_headers = s:notmuch_show_headers_defaults +endif + +" --- assign keymaps {{{1 + +function! s:NM_set_map(maps) + for [key, code] in items(a:maps) + exec printf('nnoremap %s %s', key, code) + endfor +endfunction " --- command handler {{{1 From b0a00164169dba02f5cc9180a54f370d2c4d4b07 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 09:56:10 -0500 Subject: [PATCH 026/110] define keymap for show screen as a dictionary --- vim/plugin/notmuch.vim | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index b2f46dde..27fa684d 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -57,9 +57,18 @@ let s:notmuch_show_headers_defaults = [ " --- keyboard mapping definitions {{{1 +" --- --- bindings for search screen {{{2 let g:notmuch_search_maps = { - \ '': ':call NM_search_display()', - \ 's': ':call NM_cmd_search(split(input(''NotMuch Search:'')))', + \ '': ':call NM_search_display()', + \ 's': ':call NM_cmd_search(split(input(''NotMuch Search:'')))', + \ } + +" --- --- bindings for show screen {{{2 +let g:notmuch_show_maps = { + \ 'q': ':call NM_cmd_show_quit()', + \ '': ':call NM_cmd_show_next()', + \ 'c': ':call NM_cmd_show_fold_toggle(''c'', ''cit'', !g:notmuch_show_fold_citations)', + \ 's': ':call NM_cmd_show_fold_toggle(''s'', ''sig'', !g:notmuch_show_fold_signatures)', \ } " --- implement search screen {{{1 @@ -112,14 +121,15 @@ function! s:NM_cmd_show(words) call s:NM_cmd_show_mkfolds() call s:NM_cmd_show_mksyntax() + call NM_set_map(g:notmuch_show_maps) setlocal foldtext=NM_cmd_show_foldtext() setlocal fillchars= setlocal foldcolumn=6 - exec printf("nnoremap q :b %d", b:nm_prev_bufnr) - nnoremap :call NM_cmd_show_next() - nnoremap c :call NM_cmd_show_fold_toggle('c', 'cit', !g:notmuch_show_fold_citations) - nnoremap s :call NM_cmd_show_fold_toggle('s', 'sig', !g:notmuch_show_fold_signatures) +endfunction + +function! s:NM_cmd_show_quit() + exec printf(":buffer %d", b:nm_prev_bufnr) endfunction function! s:NM_cmd_show_next() @@ -407,7 +417,6 @@ function! NM_set_defaults(force) \ a:force, key, string(dflt)) continue endif - echoe cmd exec cmd endfor endfunction From 804715316b1374709e08b58ffdc3900f31807e7a Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 10:19:31 -0500 Subject: [PATCH 027/110] add dummy entries to search screen keymap --- vim/plugin/notmuch.vim | 74 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 5 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 27fa684d..9e460e09 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -48,6 +48,12 @@ let s:notmuch_defaults = { \ 'g:notmuch_show_citation_regexp': '^\s*>' , \ } +" defaults for g:notmuch_initial_search_words +" override with: let g:notmuch_initial_search_words = [ ... ] +let s:notmuch_initial_search_words_defaults = [ + \ 'tag:inbox' + \ ] + " defaults for g:notmuch_show_headers " override with: let g:notmuch_show_headers = [ ... ] let s:notmuch_show_headers_defaults = [ @@ -59,8 +65,17 @@ let s:notmuch_show_headers_defaults = [ " --- --- bindings for search screen {{{2 let g:notmuch_search_maps = { - \ '': ':call NM_search_display()', - \ 's': ':call NM_cmd_search(split(input(''NotMuch Search:'')))', + \ '': ':call NM_search_show_thread()', + \ 'a': ':call NM_search_archive_thread()', + \ 'f': ':call NM_search_filter()', + \ 'm': ':call NM_new_mail()', + \ 'o': ':call NM_search_toggle_order()', + \ 'r': ':call NM_search_reply_to_thread()', + \ 's': ':call NM_search_prompt()', + \ 't': ':call NM_search_filter_by_tag()', + \ '+': ':call NM_search_add_tag()', + \ '-': ':call NM_search_remove_tag()', + \ '=': ':call NM_search_refresh_view()', \ } " --- --- bindings for show screen {{{2 @@ -78,6 +93,7 @@ function! s:NM_cmd_search(words) if g:notmuch_search_reverse let cmd = cmd + ['--reverse'] endif + let g:notmuch_current_search_words = a:words let data = s:NM_run(cmd + a:words) "let data = substitute(data, '27/27', '25/27', '') "let data = substitute(data, '\[4/4\]', '[0/4]', '') @@ -93,7 +109,7 @@ function! s:NM_cmd_search(words) setlocal nowrap endfunction -function! s:NM_search_display() +function! s:NM_search_show_thread() if !exists('b:nm_raw_lines') echo 'no b:nm_raw_lines' else @@ -104,6 +120,47 @@ function! s:NM_search_display() endif endfunction +function! s:NM_search_prompt() + let new_list = input('NotMuch Search: ', join(g:notmuch_current_search_words, ' ')) + call NM_cmd_search(split(new_list)) +endfunction + +function! s:NM_search_archive_thread() + echoe 'Not implemented' +endfunction + +function! s:NM_search_filter() + echoe 'Not implemented' +endfunction + +function! s:NM_new_mail() + echoe 'Not implemented' +endfunction + +function! s:NM_search_toggle_order() + echoe 'Not implemented' +endfunction + +function! s:NM_search_reply_to_thread() + echoe 'Not implemented' +endfunction + +function! s:NM_search_filter_by_tag() + echoe 'Not implemented' +endfunction + +function! s:NM_search_add_tag() + echoe 'Not implemented' +endfunction + +function! s:NM_search_remove_tag() + echoe 'Not implemented' +endfunction + +function! s:NM_search_refresh_view() + echoe 'Not implemented' +endfunction + " --- implement show screen {{{1 @@ -147,7 +204,7 @@ function! s:NM_cmd_show_next() return endfor norm qj - call NM_search_display() + call NM_search_show_thread() endfunction function! s:NM_cmd_show_fold_toggle(key, type, fold) @@ -426,6 +483,13 @@ call NM_set_defaults(0) if !exists('g:notmuch_show_headers') let g:notmuch_show_headers = s:notmuch_show_headers_defaults endif +if !exists('g:notmuch_initial_search_words') + let g:notmuch_initial_search_words = s:notmuch_initial_search_words_defaults +endif + +" this is the default querry +let g:notmuch_current_search_words = g:notmuch_initial_search_words + " --- assign keymaps {{{1 @@ -439,7 +503,7 @@ endfunction function! NotMuch(args) if !strlen(a:args) - call s:NM_cmd_search(['tag:inbox']) + call s:NM_cmd_search(g:notmuch_current_search_words) return endif From 84f33e6546eb11a30eed74652fa408ae7ac192be Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 10:57:25 -0500 Subject: [PATCH 028/110] added tagging and refresh to search screen --- vim/README | 6 +++- vim/plugin/notmuch.vim | 81 +++++++++++++++++++++++++++++++++--------- 2 files changed, 69 insertions(+), 18 deletions(-) diff --git a/vim/README b/vim/README index e4128b71..ba6eb5fe 100644 --- a/vim/README +++ b/vim/README @@ -18,7 +18,11 @@ Buffer types: Keybindings: - show the selected message - s - alter search criteria + s - enter search criteria + S - alter search criteria + + - add tag(s) to selected message + - - remove tag(s) from selected message + = - refresh display [notmuch-show] This is the display of the message. diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 9e460e09..a10b9a3a 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -72,9 +72,10 @@ let g:notmuch_search_maps = { \ 'o': ':call NM_search_toggle_order()', \ 'r': ':call NM_search_reply_to_thread()', \ 's': ':call NM_search_prompt()', + \ 'S': ':call NM_search_edit()', \ 't': ':call NM_search_filter_by_tag()', - \ '+': ':call NM_search_add_tag()', - \ '-': ':call NM_search_remove_tag()', + \ '+': ':call NM_search_add_tags([])', + \ '-': ':call NM_search_remove_tags([])', \ '=': ':call NM_search_refresh_view()', \ } @@ -109,24 +110,34 @@ function! s:NM_cmd_search(words) setlocal nowrap endfunction +" --- --- search screen action functions {{{2 + function! s:NM_search_show_thread() - if !exists('b:nm_raw_lines') - echo 'no b:nm_raw_lines' - else - let line = line('.') - let info = b:nm_raw_lines[line-1] - let what = split(info, '\s\+')[0] - call s:NM_cmd_show([what]) + let id = NM_search_find_thread_id() + if id != '' + call s:NM_cmd_show([id]) endif endfunction function! s:NM_search_prompt() - let new_list = input('NotMuch Search: ', join(g:notmuch_current_search_words, ' ')) - call NM_cmd_search(split(new_list)) + " TODO: input() can support completion + let text = input('NotMuch Search: ') + if strlen(text) + call NM_cmd_search(split(text)) + endif +endfunction + +function! s:NM_search_edit() + " TODO: input() can support completion + let text = input('NotMuch Search: ', join(g:notmuch_current_search_words, ' ')) + if strlen(text) + call NM_cmd_search(split(text)) + endif endfunction function! s:NM_search_archive_thread() - echoe 'Not implemented' + call NM_search_remove_tags('inbox') + norm j endfunction function! s:NM_search_filter() @@ -149,18 +160,54 @@ function! s:NM_search_filter_by_tag() echoe 'Not implemented' endfunction -function! s:NM_search_add_tag() - echoe 'Not implemented' +function! s:NM_search_add_tags(tags) + call NM_search_add_remove_tags('Add Tag(s): ', '+', a:tags) endfunction -function! s:NM_search_remove_tag() - echoe 'Not implemented' +function! s:NM_search_remove_tags(tags) + call NM_search_add_remove_tags('Remove Tag(s): ', '-', a:tags) endfunction function! s:NM_search_refresh_view() - echoe 'Not implemented' + let lno = line('.') + call s:NM_cmd_search(g:notmuch_current_search_words) + " FIXME: should find the line of the thread we were on if possible + exec printf('norm %dG', lno) endfunction +" --- --- search screen helper functions {{{2 + +function! s:NM_search_find_thread_id() + if !exists('b:nm_raw_lines') + echoe 'no b:nm_raw_lines' + return '' + else + let line = line('.') + let info = b:nm_raw_lines[line-1] + let what = split(info, '\s\+')[0] + return what + endif +endfunction + +function! s:NM_search_add_remove_tags(prompt, prefix, intags) + let id = NM_search_find_thread_id() + if id != '' + if type(a:intags) != type([]) || len(a:intags) == 0 + " TODO: input() can support completion + let text = input(a:prompt) + if !strlen(text) + return + endif + let tags = split(text, ' ') + else + let tags = a:intags + endif + call map(tags, 'a:prefix . v:val') + " TODO: handle errors + call NM_run(['tag'] + tags + ['--', id]) + call NM_search_refresh_view() + endif +endfunction " --- implement show screen {{{1 From 7888bffce748ecfe0b49460bcda6033a4a74a66e Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 10:58:34 -0500 Subject: [PATCH 029/110] fix showing thread --- vim/plugin/notmuch.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index a10b9a3a..b78a6382 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -113,7 +113,7 @@ endfunction " --- --- search screen action functions {{{2 function! s:NM_search_show_thread() - let id = NM_search_find_thread_id() + let id = NM_search_find_thread_id() if id != '' call s:NM_cmd_show([id]) endif From 882621927483635d37eed70eef007f1ef97662d0 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 10:59:31 -0500 Subject: [PATCH 030/110] cleanup calls to script functions, use --- vim/plugin/notmuch.vim | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index b78a6382..d661c565 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -102,7 +102,7 @@ function! s:NM_cmd_search(words) let disp = copy(lines) call map(disp, 'substitute(v:val, "^thread:\\S* ", "", "")' ) - call s:NM_newBuffer('search', join(disp, "\n")) + call NM_newBuffer('search', join(disp, "\n")) let b:nm_raw_lines = lines call NM_set_map(g:notmuch_search_maps) @@ -115,7 +115,7 @@ endfunction function! s:NM_search_show_thread() let id = NM_search_find_thread_id() if id != '' - call s:NM_cmd_show([id]) + call NM_cmd_show([id]) endif endfunction @@ -170,7 +170,7 @@ endfunction function! s:NM_search_refresh_view() let lno = line('.') - call s:NM_cmd_search(g:notmuch_current_search_words) + call NM_cmd_search(g:notmuch_current_search_words) " FIXME: should find the line of the thread we were on if possible exec printf('norm %dG', lno) endfunction @@ -218,13 +218,13 @@ function! s:NM_cmd_show(words) let info = s:NM_cmd_show_parse(lines) - call s:NM_newBuffer('show', join(info['disp'], "\n")) + call NM_newBuffer('show', join(info['disp'], "\n")) setlocal bufhidden=delete let b:nm_raw_info = info let b:nm_prev_bufnr = prev_bufnr - call s:NM_cmd_show_mkfolds() - call s:NM_cmd_show_mksyntax() + call NM_cmd_show_mkfolds() + call NM_cmd_show_mksyntax() call NM_set_map(g:notmuch_show_maps) setlocal foldtext=NM_cmd_show_foldtext() setlocal fillchars= @@ -550,7 +550,7 @@ endfunction function! NotMuch(args) if !strlen(a:args) - call s:NM_cmd_search(g:notmuch_current_search_words) + call NM_cmd_search(g:notmuch_current_search_words) return endif From de85b4752d51567ded73e9bbed75d0b8f5bfea71 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 11:13:49 -0500 Subject: [PATCH 031/110] added support for archive command --- vim/README | 1 + vim/plugin/notmuch.vim | 39 +++++++++++++++++++++++---------------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/vim/README b/vim/README index ba6eb5fe..dffc88a4 100644 --- a/vim/README +++ b/vim/README @@ -18,6 +18,7 @@ Buffer types: Keybindings: - show the selected message + a - archive message (remove inbox tag) s - enter search criteria S - alter search criteria + - add tag(s) to selected message diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index d661c565..ecf7b9de 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -136,7 +136,10 @@ function! s:NM_search_edit() endfunction function! s:NM_search_archive_thread() - call NM_search_remove_tags('inbox') + call NM_add_remove_tags('-', ['inbox']) + setlocal modifiable + s/(\([^)]*\)\\([^)]*\))$/(\1\2)/ + setlocal nomodifiable norm j endfunction @@ -190,23 +193,27 @@ function! s:NM_search_find_thread_id() endfunction function! s:NM_search_add_remove_tags(prompt, prefix, intags) - let id = NM_search_find_thread_id() - if id != '' - if type(a:intags) != type([]) || len(a:intags) == 0 - " TODO: input() can support completion - let text = input(a:prompt) - if !strlen(text) - return - endif - let tags = split(text, ' ') - else - let tags = a:intags + if type(a:intags) != type([]) || len(a:intags) == 0 + " TODO: input() can support completion + let text = input(a:prompt) + if !strlen(text) + return endif - call map(tags, 'a:prefix . v:val') - " TODO: handle errors - call NM_run(['tag'] + tags + ['--', id]) - call NM_search_refresh_view() + call NM_add_remove_tags(prefix, split(text, ' ')) + else + call NM_add_remove_tags(prefix, a:intags) endif + call NM_search_refresh_view() +endfunction + +function! s:NM_add_remove_tags(prefix, tags) + let id = NM_search_find_thread_id() + if id == '' + echoe 'Eeek! I couldn''t find the thead id!' + endif + call map(a:tags, 'a:prefix . v:val') + " TODO: handle errors + call NM_run(['tag'] + a:tags + ['--', id]) endfunction " --- implement show screen {{{1 From dbd90c1fc72c4b26073524587db721a276607594 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 12:05:43 -0500 Subject: [PATCH 032/110] added search filtering --- vim/README | 2 ++ vim/plugin/notmuch.vim | 71 +++++++++++++++++++++++++++++++----------- 2 files changed, 54 insertions(+), 19 deletions(-) diff --git a/vim/README b/vim/README index dffc88a4..d6ee2384 100644 --- a/vim/README +++ b/vim/README @@ -19,8 +19,10 @@ Buffer types: Keybindings: - show the selected message a - archive message (remove inbox tag) + f - filter the current search terms s - enter search criteria S - alter search criteria + f - filter the current search terms with tags + - add tag(s) to selected message - - remove tag(s) from selected message = - refresh display diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index ecf7b9de..dbe19853 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -74,6 +74,7 @@ let g:notmuch_search_maps = { \ 's': ':call NM_search_prompt()', \ 'S': ':call NM_search_edit()', \ 't': ':call NM_search_filter_by_tag()', + \ 'q': ':call NM_kill_buffer()', \ '+': ':call NM_search_add_tags([])', \ '-': ':call NM_search_remove_tags([])', \ '=': ':call NM_search_refresh_view()', @@ -81,10 +82,10 @@ let g:notmuch_search_maps = { " --- --- bindings for show screen {{{2 let g:notmuch_show_maps = { - \ 'q': ':call NM_cmd_show_quit()', - \ '': ':call NM_cmd_show_next()', - \ 'c': ':call NM_cmd_show_fold_toggle(''c'', ''cit'', !g:notmuch_show_fold_citations)', - \ 's': ':call NM_cmd_show_fold_toggle(''s'', ''sig'', !g:notmuch_show_fold_signatures)', + \ '': ':call NM_cmd_show_next()', + \ 'c': ':call NM_cmd_show_fold_toggle(''c'', ''cit'', !g:notmuch_show_fold_citations)', + \ 's': ':call NM_cmd_show_fold_toggle(''s'', ''sig'', !g:notmuch_show_fold_signatures)', + \ 'q': ':call NM_kill_buffer()', \ } " --- implement search screen {{{1 @@ -94,7 +95,6 @@ function! s:NM_cmd_search(words) if g:notmuch_search_reverse let cmd = cmd + ['--reverse'] endif - let g:notmuch_current_search_words = a:words let data = s:NM_run(cmd + a:words) "let data = substitute(data, '27/27', '25/27', '') "let data = substitute(data, '\[4/4\]', '[0/4]', '') @@ -104,6 +104,7 @@ function! s:NM_cmd_search(words) call NM_newBuffer('search', join(disp, "\n")) let b:nm_raw_lines = lines + let b:nm_search_words = a:words call NM_set_map(g:notmuch_search_maps) setlocal cursorline @@ -123,13 +124,17 @@ function! s:NM_search_prompt() " TODO: input() can support completion let text = input('NotMuch Search: ') if strlen(text) - call NM_cmd_search(split(text)) + let tags = split(text) + else + let tags = s:notmuch_initial_search_words_defaults endif + setlocal bufhidden=delete + call NM_cmd_search(tags) endfunction function! s:NM_search_edit() " TODO: input() can support completion - let text = input('NotMuch Search: ', join(g:notmuch_current_search_words, ' ')) + let text = input('NotMuch Search: ', join(b:nm_search_words, ' ')) if strlen(text) call NM_cmd_search(split(text)) endif @@ -137,6 +142,7 @@ endfunction function! s:NM_search_archive_thread() call NM_add_remove_tags('-', ['inbox']) + " TODO: this could be made better and more generic setlocal modifiable s/(\([^)]*\)\\([^)]*\))$/(\1\2)/ setlocal nomodifiable @@ -144,7 +150,30 @@ function! s:NM_search_archive_thread() endfunction function! s:NM_search_filter() - echoe 'Not implemented' + call NM_search_filter_helper('Filter: ', '') +endfunction + +function! s:NM_search_filter_by_tag() + call NM_search_filter_helper('Filter Tag(s): ', 'tag:') +endfunction + +function! s:NM_search_filter_helper(prompt, prefix) + " TODO: input() can support completion + let text = input(a:prompt) + if !strlen(text) + return + endif + + let tags = split(text) + map(tags, 'a:prefix . v:val') + let tags = b:nm_search_words + tags + echo tags + + let prev_bufnr = bufnr('%') + setlocal bufhidden=hide + call NM_cmd_search(tags) + setlocal bufhidden=delete + let b:nm_prev_bufnr = prev_bufnr endfunction function! s:NM_new_mail() @@ -159,10 +188,6 @@ function! s:NM_search_reply_to_thread() echoe 'Not implemented' endfunction -function! s:NM_search_filter_by_tag() - echoe 'Not implemented' -endfunction - function! s:NM_search_add_tags(tags) call NM_search_add_remove_tags('Add Tag(s): ', '+', a:tags) endfunction @@ -173,7 +198,7 @@ endfunction function! s:NM_search_refresh_view() let lno = line('.') - call NM_cmd_search(g:notmuch_current_search_words) + call NM_cmd_search(b:nm_search_words) " FIXME: should find the line of the thread we were on if possible exec printf('norm %dG', lno) endfunction @@ -225,6 +250,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")) setlocal bufhidden=delete let b:nm_raw_info = info @@ -239,8 +265,13 @@ function! s:NM_cmd_show(words) endfunction -function! s:NM_cmd_show_quit() - exec printf(":buffer %d", b:nm_prev_bufnr) +function! s:NM_kill_buffer() + if exists('b:nm_prev_bufnr') + setlocal bufhidden=delete + exec printf(":buffer %d", b:nm_prev_bufnr) + else + echo "Nothing to kill." + endif endfunction function! s:NM_cmd_show_next() @@ -541,9 +572,6 @@ if !exists('g:notmuch_initial_search_words') let g:notmuch_initial_search_words = s:notmuch_initial_search_words_defaults endif -" this is the default querry -let g:notmuch_current_search_words = g:notmuch_initial_search_words - " --- assign keymaps {{{1 @@ -557,7 +585,12 @@ endfunction function! NotMuch(args) if !strlen(a:args) - call NM_cmd_search(g:notmuch_current_search_words) + if exists('b:nm_search_words') + let words = b:nm_search_words + else + let words = g:notmuch_initial_search_words + endif + call NM_cmd_search(words) return endif From 0f7b098f63058fd2a0869453739f3e44a9876fcc Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 12:16:32 -0500 Subject: [PATCH 033/110] crude order toggle --- vim/README | 1 + vim/plugin/notmuch.vim | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/vim/README b/vim/README index d6ee2384..37cbf77d 100644 --- a/vim/README +++ b/vim/README @@ -20,6 +20,7 @@ Buffer types: - show the selected message a - archive message (remove inbox tag) f - filter the current search terms + o - toggle search screen order s - enter search criteria S - alter search criteria f - filter the current search terms with tags diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index dbe19853..ed67d34a 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -181,7 +181,10 @@ function! s:NM_new_mail() endfunction function! s:NM_search_toggle_order() - echoe 'Not implemented' + let g:notmuch_search_reverse = !g:notmuch_search_reverse + " FIXME: maybe this would be better done w/o reading re-reading the lines + " reversing the b:nm_raw_lines and the buffer lines would be better + call NM_search_refresh_view() endfunction function! s:NM_search_reply_to_thread() @@ -198,6 +201,7 @@ endfunction function! s:NM_search_refresh_view() let lno = line('.') + setlocal bufhidden=delete call NM_cmd_search(b:nm_search_words) " FIXME: should find the line of the thread we were on if possible exec printf('norm %dG', lno) From 72b7251d9aa766e1ee58f7f140de9a223ffe920c Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 12:37:52 -0500 Subject: [PATCH 034/110] fix after merge, --reverse replaced with --sort= --- vim/plugin/notmuch.vim | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index ed67d34a..b328bcc6 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -23,7 +23,7 @@ let s:notmuch_defaults = { \ 'g:notmuch_cmd': 'notmuch' , - \ 'g:notmuch_search_reverse': 1 , + \ 'g:notmuch_search_newest_first': 1 , \ 'g:notmuch_show_fold_signatures': 1 , \ 'g:notmuch_show_fold_citations': 1 , \ @@ -92,8 +92,10 @@ let g:notmuch_show_maps = { function! s:NM_cmd_search(words) let cmd = ['search'] - if g:notmuch_search_reverse - let cmd = cmd + ['--reverse'] + if g:notmuch_search_newest_first + let cmd = cmd + ['--sort=newest-first'] + else + let cmd = cmd + ['--sort=oldest-first'] endif let data = s:NM_run(cmd + a:words) "let data = substitute(data, '27/27', '25/27', '') @@ -181,7 +183,7 @@ function! s:NM_new_mail() endfunction function! s:NM_search_toggle_order() - let g:notmuch_search_reverse = !g:notmuch_search_reverse + let g:notmuch_search_newest_first = !g:notmuch_search_newest_first " FIXME: maybe this would be better done w/o reading re-reading the lines " reversing the b:nm_raw_lines and the buffer lines would be better call NM_search_refresh_view() From acb696165c89fbc2f7030dcee5814f24a18628ce Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 13:50:29 -0500 Subject: [PATCH 035/110] more endless toil with syntax --- vim/plugin/notmuch.vim | 32 ++++++++++++++++++++++++++++---- vim/syntax/notmuch-search.vim | 4 ++-- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index b328bcc6..dab53359 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -23,7 +23,10 @@ let s:notmuch_defaults = { \ 'g:notmuch_cmd': 'notmuch' , + \ \ 'g:notmuch_search_newest_first': 1 , + \ 'g:notmuch_search_from_column_width': 20 , + \ \ 'g:notmuch_show_fold_signatures': 1 , \ 'g:notmuch_show_fold_citations': 1 , \ @@ -102,16 +105,37 @@ function! s:NM_cmd_search(words) "let data = substitute(data, '\[4/4\]', '[0/4]', '') let lines = split(data, "\n") let disp = copy(lines) - call map(disp, 'substitute(v:val, "^thread:\\S* ", "", "")' ) + "call map(disp, 'substitute(v:val, "^thread:\\S* ", "", "")' ) + call map(disp, 's:NM_cmd_search_fmtline(v:val)') call NM_newBuffer('search', join(disp, "\n")) let b:nm_raw_lines = lines let b:nm_search_words = a:words + call NM_cmd_search_mksyntax() call NM_set_map(g:notmuch_search_maps) setlocal cursorline setlocal nowrap endfunction +function! s:NM_cmd_search_fmtline(line) + let m = matchlist(a:line, '^\(thread:\S\+\)\s\([^]]\+\]\) \([^;]\+\); \(.*\) (\([^(]*\))$') + if !len(m) + return 'ERROR PARSING: ' . a:line + endif + let max = g:notmuch_search_from_column_width + let from = m[3] + if strlen(from) >= max + let from = m[3][0:max-4] . '...' + endif + return printf('%s %-20s | %s (%s)', m[2], from, m[4], m[5]) +endfunction +function! s:NM_cmd_search_mksyntax() + syntax clear nmSearchFrom + "syntax region nmSearchFrom start='\]\@<=' end='.'me=e+5,he=e+5,re=e+5 oneline contained + "syntax match nmSearchFrom /\]\@<=.\{10\}/ oneline contained + exec printf('syntax match nmSearchFrom /\(\] \)\@<=.\{%d\}/ oneline contained', g:notmuch_search_from_column_width) + "exec printf('syntax region nmSearchFrom start=''\%%%dv'' end=''\%%%dv'' oneline contained', 20, 30) +endfunction " --- --- search screen action functions {{{2 @@ -167,7 +191,7 @@ function! s:NM_search_filter_helper(prompt, prefix) endif let tags = split(text) - map(tags, 'a:prefix . v:val') + map(tags, 'and a:prefix . v:val') let tags = b:nm_search_words + tags echo tags @@ -230,9 +254,9 @@ function! s:NM_search_add_remove_tags(prompt, prefix, intags) if !strlen(text) return endif - call NM_add_remove_tags(prefix, split(text, ' ')) + call NM_add_remove_tags(a:prefix, split(text, ' ')) else - call NM_add_remove_tags(prefix, a:intags) + call NM_add_remove_tags(a:prefix, a:intags) endif call NM_search_refresh_view() endfunction diff --git a/vim/syntax/notmuch-search.vim b/vim/syntax/notmuch-search.vim index 4b694722..832b2b84 100644 --- a/vim/syntax/notmuch-search.vim +++ b/vim/syntax/notmuch-search.vim @@ -3,9 +3,9 @@ " TODO: I cannot figure out why nmSearchTags is not matching anything :( syntax region nmSearchDate start='^' end='\%13v' -syntax region nmSearchCountAndFrom start='\%14v\[' end=';' oneline contains=nmSearchCount,nmSearchFrom -syntax match nmSearchFrom ' .*;' contained +syntax region nmSearchCountAndFrom start='\%14v\[' end='|' oneline contains=nmSearchCount,nmSearchFrom syntax region nmSearchCount start='\%14v\[' end='\]' contained contains=nmSearchCountZero,nmSearchCountSome,nmSearchCountAll +syntax region nmSearchFrom start='\]\@<=' end='|' oneline contained syntax match nmSearchCountZero '0/\(\d\+\)' contained syntax match nmSearchCountSome '\([1-9]\d*\)/\(\d\+\)' contained syntax match nmSearchCountAll '\(\d\+\)/\1' contained From e2006a2f3cd1bc47b45f2b880f4dd5ba775d1b3b Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 14:18:42 -0500 Subject: [PATCH 036/110] implemented folding bodies and headers --- vim/README | 8 +++++--- vim/plugin/notmuch.vim | 25 +++++++++++++++++++++---- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/vim/README b/vim/README index 37cbf77d..31f1e20b 100644 --- a/vim/README +++ b/vim/README @@ -32,8 +32,10 @@ Buffer types: This is the display of the message. Keybindings: - q - return to search display ^n - next message - s - toggle folding of signatures on and off - c - toggle folding of citations on and off + b - toggle folding of message bodies + c - toggle folding of citations + h - toggle folding of extra header lines + s - toggle folding of signatures + q - return to search display diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index dab53359..4a4a2016 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -29,6 +29,8 @@ let s:notmuch_defaults = { \ \ 'g:notmuch_show_fold_signatures': 1 , \ 'g:notmuch_show_fold_citations': 1 , + \ 'g:notmuch_show_fold_bodies': 0 , + \ 'g:notmuch_show_fold_headers': 1 , \ \ 'g:notmuch_show_message_begin_regexp': '^ message{' , \ 'g:notmuch_show_message_end_regexp': '^ message}' , @@ -61,7 +63,10 @@ let s:notmuch_initial_search_words_defaults = [ " override with: let g:notmuch_show_headers = [ ... ] let s:notmuch_show_headers_defaults = [ \ 'Subject', - \ 'From' + \ 'To', + \ 'Cc', + \ 'Bcc', + \ 'Date' \ ] " --- keyboard mapping definitions {{{1 @@ -85,8 +90,11 @@ let g:notmuch_search_maps = { " --- --- bindings for show screen {{{2 let g:notmuch_show_maps = { + \ '': ':call NM_cmd_show_prev()', \ '': ':call NM_cmd_show_next()', + \ 'b': ':call NM_cmd_show_fold_toggle(''b'', ''bdy'', !g:notmuch_show_fold_bodies)', \ 'c': ':call NM_cmd_show_fold_toggle(''c'', ''cit'', !g:notmuch_show_fold_citations)', + \ 'h': ':call NM_cmd_show_fold_toggle(''h'', ''hdr'', !g:notmuch_show_fold_headers)', \ 's': ':call NM_cmd_show_fold_toggle(''s'', ''sig'', !g:notmuch_show_fold_signatures)', \ 'q': ':call NM_kill_buffer()', \ } @@ -304,6 +312,10 @@ function! s:NM_kill_buffer() endif endfunction +function! s:NM_cmd_show_prev() + echoe "not implemented" +endfunction + function! s:NM_cmd_show_next() let info = b:nm_raw_info let lnum = line('.') @@ -394,7 +406,6 @@ function! s:NM_cmd_show_parse(inlines) elseif mode_type == 'sig' let outlnum = len(info['disp']) if (outlnum - mode_start) > g:notmuch_show_signature_lines_max - echoe 'line ' . outlnum . ' stopped matching' let mode_type = '' elseif part_end let foldinfo = [ mode_type, mode_start, outlnum, @@ -424,7 +435,7 @@ function! s:NM_cmd_show_parse(inlines) endif if match(line, g:notmuch_show_body_end_regexp) != -1 let body_end = len(info['disp']) - let foldinfo = [ 'body', body_start, body_end, + let foldinfo = [ 'bdy', body_start, body_end, \ printf('[ BODY %d - %d lines ]', len(info['msgs']), body_end - body_start) ] let in_body = 0 @@ -449,6 +460,10 @@ function! s:NM_cmd_show_parse(inlines) else if match(line, g:notmuch_show_header_end_regexp) != -1 + let hdr_start = msg['hdr_start']+1 + let hdr_end = len(info['disp']) + let foldinfo = [ 'hdr', hdr_start, hdr_end, + \ printf('[ %d-line headers. Press "h" to show. ]', hdr_end - hdr_start) ] let msg['header'] = hdr let in_header = 0 let hdr = {} @@ -468,7 +483,7 @@ function! s:NM_cmd_show_parse(inlines) let msg['end'] = len(info['disp']) call add(info['disp'], '') - let foldinfo = [ 'match', msg['start'], msg['end'], + let foldinfo = [ 'msg', msg['start'], msg['end'], \ printf('[ MSG %d - %s ]', len(info['msgs']), msg['descr']) ] call add(info['msgs'], msg) @@ -518,6 +533,8 @@ function! s:NM_cmd_show_mkfolds() exec printf('%d,%dfold', afold[1], afold[2]) if (afold[0] == 'sig' && g:notmuch_show_fold_signatures) \ || (afold[0] == 'cit' && g:notmuch_show_fold_citations) + \ || (afold[0] == 'bdy' && g:notmuch_show_fold_bodies) + \ || (afold[0] == 'hdr' && g:notmuch_show_fold_headers) exec printf('%dfoldclose', afold[1]) else exec printf('%dfoldopen', afold[1]) From 75ae11ebd222cbbc19817be0cc6998cb6b1456d4 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 14:53:46 -0500 Subject: [PATCH 037/110] lot more stubs for future keybindings --- vim/plugin/notmuch.vim | 126 +++++++++++++++++++++++++++++++---------- 1 file changed, 97 insertions(+), 29 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 4a4a2016..9e5ee39a 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -56,7 +56,7 @@ let s:notmuch_defaults = { " defaults for g:notmuch_initial_search_words " override with: let g:notmuch_initial_search_words = [ ... ] let s:notmuch_initial_search_words_defaults = [ - \ 'tag:inbox' + \ 'tag:inbox and tag:unread', \ ] " defaults for g:notmuch_show_headers @@ -66,7 +66,7 @@ let s:notmuch_show_headers_defaults = [ \ 'To', \ 'Cc', \ 'Bcc', - \ 'Date' + \ 'Date', \ ] " --- keyboard mapping definitions {{{1 @@ -82,7 +82,7 @@ let g:notmuch_search_maps = { \ 's': ':call NM_search_prompt()', \ 'S': ':call NM_search_edit()', \ 't': ':call NM_search_filter_by_tag()', - \ 'q': ':call NM_kill_buffer()', + \ 'q': ':call NM_kill_this_buffer()', \ '+': ':call NM_search_add_tags([])', \ '-': ':call NM_search_remove_tags([])', \ '=': ':call NM_search_refresh_view()', @@ -90,15 +90,29 @@ let g:notmuch_search_maps = { " --- --- bindings for show screen {{{2 let g:notmuch_show_maps = { - \ '': ':call NM_cmd_show_prev()', - \ '': ':call NM_cmd_show_next()', - \ 'b': ':call NM_cmd_show_fold_toggle(''b'', ''bdy'', !g:notmuch_show_fold_bodies)', - \ 'c': ':call NM_cmd_show_fold_toggle(''c'', ''cit'', !g:notmuch_show_fold_citations)', - \ 'h': ':call NM_cmd_show_fold_toggle(''h'', ''hdr'', !g:notmuch_show_fold_headers)', - \ 's': ':call NM_cmd_show_fold_toggle(''s'', ''sig'', !g:notmuch_show_fold_signatures)', - \ 'q': ':call NM_kill_buffer()', + \ '': ':call NM_show_prev()', + \ '': ':call NM_show_next()', + \ 'q': ':call NM_kill_this_buffer()', + \ + \ 'b': ':call NM_show_fold_toggle(''b'', ''bdy'', !g:notmuch_show_fold_bodies)', + \ 'c': ':call NM_show_fold_toggle(''c'', ''cit'', !g:notmuch_show_fold_citations)', + \ 'h': ':call NM_show_fold_toggle(''h'', ''hdr'', !g:notmuch_show_fold_headers)', + \ 's': ':call NM_show_fold_toggle(''s'', ''sig'', !g:notmuch_show_fold_signatures)', + \ + \ 'a': ':call NM_show_archive_thread()', + \ 'A': ':call NM_show_mark_read_then_archive_thread()', + \ 'N': ':call NM_show_mark_read_then_next_open_message()', + \ 'v': ':call NM_show_view_all_mime_parts()', + \ '+': ':call NM_show_add_tag()', + \ '-': ':call NM_show_remove_tag()', + \ '': ':call NM_show_advance_marking_read_and_archiving()', + \ '\|': ':call NM_show_pipe_message()', + \ + \ 'r': ':call NM_show_reply()', + \ 'm': ':call NM_new_mail()', \ } + " --- implement search screen {{{1 function! s:NM_cmd_search(words) @@ -210,10 +224,6 @@ function! s:NM_search_filter_helper(prompt, prefix) let b:nm_prev_bufnr = prev_bufnr endfunction -function! s:NM_new_mail() - echoe 'Not implemented' -endfunction - function! s:NM_search_toggle_order() let g:notmuch_search_newest_first = !g:notmuch_search_newest_first " FIXME: maybe this would be better done w/o reading re-reading the lines @@ -222,7 +232,7 @@ function! s:NM_search_toggle_order() endfunction function! s:NM_search_reply_to_thread() - echoe 'Not implemented' + echo 'not implemented' endfunction function! s:NM_search_add_tags(tags) @@ -303,20 +313,11 @@ function! s:NM_cmd_show(words) endfunction -function! s:NM_kill_buffer() - if exists('b:nm_prev_bufnr') - setlocal bufhidden=delete - exec printf(":buffer %d", b:nm_prev_bufnr) - else - echo "Nothing to kill." - endif -endfunction - -function! s:NM_cmd_show_prev() +function! s:NM_show_prev() echoe "not implemented" endfunction -function! s:NM_cmd_show_next() +function! s:NM_show_next() let info = b:nm_raw_info let lnum = line('.') let cnt = 0 @@ -334,7 +335,57 @@ function! s:NM_cmd_show_next() call NM_search_show_thread() endfunction -function! s:NM_cmd_show_fold_toggle(key, type, fold) +function! s:NM_show_archive_thread() + echo 'not implemented' +endfunction + +function! s:NM_show_mark_read_then_archive_thread() + echo 'not implemented' +endfunction + +function! s:NM_show_next_message() + echo 'not implemented' +endfunction + +function! s:NM_show_mark_read_then_next_open_message() + echo 'not implemented' +endfunction + +function! s:NM_show_previous_message() + echo 'not implemented' +endfunction + +function! s:NM_show_reply() + echo 'not implemented' +endfunction + +function! s:NM_show_view_all_mime_parts() + echo 'not implemented' +endfunction + +function! s:NM_show_view_raw_message() + echo 'not implemented' +endfunction + +function! s:NM_show_add_tag() + echo 'not implemented' +endfunction + +function! s:NM_show_remove_tag() + echo 'not implemented' +endfunction + +function! s:NM_show_advance_marking_read_and_archiving() + echo 'not implemented' +endfunction + +function! s:NM_show_pipe_message() + echo 'not implemented' +endfunction + +" --- --- search screen helper functions {{{2 + +function! s:NM_show_fold_toggle(key, type, fold) let info = b:nm_raw_info let act = 'open' if a:fold @@ -345,7 +396,7 @@ function! s:NM_cmd_show_fold_toggle(key, type, fold) exec printf('%dfold%s', fld[1], act) endif endfor - exec printf('nnoremap %s :call NM_cmd_show_fold_toggle(''%s'', ''%s'', %d)', a:key, a:key, a:type, !a:fold) + exec printf('nnoremap %s :call NM_show_fold_toggle(''%s'', ''%s'', %d)', a:key, a:key, a:type, !a:fold) endfunction @@ -399,7 +450,7 @@ 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, + let foldinfo = [ mode_type, mode_start, outlnum-1, \ printf('[ %d-line citation. Press "c" to show. ]', outlnum - mode_start) ] let mode_type = '' endif @@ -588,6 +639,23 @@ function! s:NM_run(args) endif endfunction +" --- external mail handling helpers {{{1 + +function! s:NM_new_mail() + echo 'not implemented' +endfunction + +" --- other helpers {{{1 + +function! s:NM_kill_this_buffer() + if exists('b:nm_prev_bufnr') + setlocal bufhidden=delete + exec printf(":buffer %d", b:nm_prev_bufnr) + else + echo "Nothing to kill." + endif +endfunction + " --- process and set the defaults {{{1 function! NM_set_defaults(force) From 71c9dbb71db5de37d647ca9899e4749be305b622 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 15:23:02 -0500 Subject: [PATCH 038/110] make control-p go to previous message --- vim/README | 1 + vim/plugin/notmuch.vim | 52 +++++++++++++++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/vim/README b/vim/README index 31f1e20b..20779994 100644 --- a/vim/README +++ b/vim/README @@ -33,6 +33,7 @@ Buffer types: Keybindings: ^n - next message + ^p - previous message b - toggle folding of message bodies c - toggle folding of citations h - toggle folding of extra header lines diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 9e5ee39a..2ddc8160 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -90,8 +90,8 @@ let g:notmuch_search_maps = { " --- --- bindings for show screen {{{2 let g:notmuch_show_maps = { - \ '': ':call NM_show_prev()', - \ '': ':call NM_show_next()', + \ '': ':call NM_show_prev(1)', + \ '': ':call NM_show_next(1)', \ 'q': ':call NM_kill_this_buffer()', \ \ 'b': ':call NM_show_fold_toggle(''b'', ''bdy'', !g:notmuch_show_fold_bodies)', @@ -313,26 +313,56 @@ function! s:NM_cmd_show(words) endfunction -function! s:NM_show_prev() - echoe "not implemented" -endfunction - -function! s:NM_show_next() +function! s:NM_show_prev(can_change_thread) + let info = b:nm_raw_info + let lnum = line('.') + for msg in reverse(copy(info['msgs'])) + if lnum <= msg['start'] + continue + endif + + exec printf('norm %dG', msg['start']) + " TODO: try to fit the message on screen + norm zz + return + endfor + if !a:can_change_thread + return + endif + call NM_kill_this_buffer() + if line('.') != line('0') + norm k + call NM_search_show_thread() + norm G + call NM_show_prev(0) + else + echo 'No more messages.' + endif +endfunction + +function! s:NM_show_next(can_change_thread) let info = b:nm_raw_info let lnum = line('.') - let cnt = 0 for msg in info['msgs'] - let cnt = cnt + 1 if lnum >= msg['start'] continue endif exec printf('norm %dG', msg['start']) + " TODO: try to fit the message on screen norm zz return endfor - norm qj - call NM_search_show_thread() + if !a:can_change_thread + return + endif + call NM_kill_this_buffer() + if line('.') != line('$') + norm j + call NM_search_show_thread() + else + echo 'No more messages.' + endif endfunction function! s:NM_show_archive_thread() From f3d3e74b97ad3d0824e1a9a38c26252b4a0a74a4 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 15:42:18 -0500 Subject: [PATCH 039/110] debug code to measure how long calls to system() take --- vim/plugin/notmuch.vim | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 2ddc8160..57bcdac9 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -658,8 +658,15 @@ endfunction function! s:NM_run(args) let cmd = g:notmuch_cmd . ' ' . join(a:args) . '< /dev/null' + + let start = reltime() let out = system(cmd) - if v:shell_error + let err = v:shell_error + let delta = reltime(start) + + echo printf('[%s] {%s} %s', reltimestr(delta), string(err), string(cmd)) + + if err echohl Error echo substitute(out, '\n*$', '', '') echohl None From 3e4f9009ae680d91b25b3ec2441c026acec3c174 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 15:42:42 -0500 Subject: [PATCH 040/110] avoid reloading search screen when we add/remove tags --- vim/plugin/notmuch.vim | 47 +++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 57bcdac9..c45b8e15 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -189,11 +189,8 @@ function! s:NM_search_edit() endfunction function! s:NM_search_archive_thread() + call NM_add_remove_tags_on_screen('-', ['inbox']) call NM_add_remove_tags('-', ['inbox']) - " TODO: this could be made better and more generic - setlocal modifiable - s/(\([^)]*\)\\([^)]*\))$/(\1\2)/ - setlocal nomodifiable norm j endfunction @@ -272,21 +269,12 @@ function! s:NM_search_add_remove_tags(prompt, prefix, intags) if !strlen(text) return endif - call NM_add_remove_tags(a:prefix, split(text, ' ')) + let tags = split(text, ' ') else - call NM_add_remove_tags(a:prefix, a:intags) + let tags = a:intags endif - call NM_search_refresh_view() -endfunction - -function! s:NM_add_remove_tags(prefix, tags) - let id = NM_search_find_thread_id() - if id == '' - echoe 'Eeek! I couldn''t find the thead id!' - endif - call map(a:tags, 'a:prefix . v:val') - " TODO: handle errors - call NM_run(['tag'] + a:tags + ['--', id]) + call NM_add_remove_tags(a:prefix, tags) + call NM_add_remove_tags_on_screen(a:prefix, tags) endfunction " --- implement show screen {{{1 @@ -693,6 +681,31 @@ function! s:NM_kill_this_buffer() endif endfunction +function! s:NM_add_remove_tags(prefix, tags) + let id = NM_search_find_thread_id() + if id == '' + echoe 'Eeek! I couldn''t find the thead id!' + endif + call map(a:tags, 'a:prefix . v:val') + " TODO: handle errors + call NM_run(['tag'] + a:tags + ['--', id]) +endfunction + +function! s:NM_add_remove_tags_on_screen(prefix, tags) + let online = '' + setlocal modifiable + if a:prefix == '-' + for tagname in a:tags + exec printf('silent %ss/(\([^)]*\)\<%s\>\([^)]*\))$/(\1\2)/', online, tagname) + endfor + else + for tagname in a:tags + exec printf('silent %ss/(\([^)]*\)\([^)]*\))$/(\1 %s)/', online, tagname) + endfor + endif + setlocal nomodifiable +endfunction + " --- process and set the defaults {{{1 function! NM_set_defaults(force) From 64339e6324d2fdc13eb3a7e357390271616528b9 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 15:47:01 -0500 Subject: [PATCH 041/110] don't fold single lines --- vim/plugin/notmuch.vim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index c45b8e15..09df1ed9 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -468,8 +468,10 @@ 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, - \ printf('[ %d-line citation. Press "c" to show. ]', outlnum - mode_start) ] + if mode_start != outlnum + let foldinfo = [ mode_type, mode_start, outlnum-1, + \ printf('[ %d-line citation. Press "c" to show. ]', outlnum - mode_start) ] + endif let mode_type = '' endif elseif mode_type == 'sig' From 4bcb88462212f387d39b4a277f0015dacc6916cd Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 15:47:25 -0500 Subject: [PATCH 042/110] clear the nmap before creating our bindings --- vim/plugin/notmuch.vim | 1 + 1 file changed, 1 insertion(+) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 09df1ed9..d3b11ba6 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -743,6 +743,7 @@ endif " --- assign keymaps {{{1 function! s:NM_set_map(maps) + nmapclear for [key, code] in items(a:maps) exec printf('nnoremap %s %s', key, code) endfor From 99f41984077c3e4cc9fa7a272c06149a2a029035 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 20 Nov 2009 15:53:46 -0500 Subject: [PATCH 043/110] keep the ,nmr hack around --- vim/plugin/notmuch.vim | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index d3b11ba6..abb3cb46 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -747,6 +747,8 @@ function! s:NM_set_map(maps) for [key, code] in items(a:maps) exec printf('nnoremap %s %s', key, code) endfor + " --- this is a hack for development :) + nnoremap ,nmr :source ~/.vim/plugin/notmuch.vim:call NotMuch('') endfunction " --- command handler {{{1 @@ -777,8 +779,4 @@ endfunction command! -nargs=* -complete=customlist,CompleteNotMuch NotMuch call NotMuch() cabbrev notmuch =(getcmdtype()==':' && getcmdpos()==1 ? 'NotMuch' : 'notmuch') -" --- hacks, only for development :) {{{1 - -nnoremap ,nmr :source ~/.vim/plugin/notmuch.vim:call NotMuch('') - " vim: set ft=vim ts=8 sw=8 et foldmethod=marker : From 42595845996e0495c40ca6a60987ffbef5c25704 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Sat, 21 Nov 2009 00:04:52 -0500 Subject: [PATCH 044/110] correct fold line counts --- vim/plugin/notmuch.vim | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index abb3cb46..43f6f542 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -479,8 +479,10 @@ 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, - \ printf('[ %d-line signature. Press "s" to show. ]', outlnum - mode_start) ] + if mode_start != outlnum + let foldinfo = [ mode_type, mode_start, outlnum-1, + \ printf('[ %d-line signature. Press "s" to show. ]', outlnum - mode_start) ] + endif let mode_type = '' endif endif @@ -534,7 +536,7 @@ function! s:NM_cmd_show_parse(inlines) let hdr_start = msg['hdr_start']+1 let hdr_end = len(info['disp']) let foldinfo = [ 'hdr', hdr_start, hdr_end, - \ printf('[ %d-line headers. Press "h" to show. ]', hdr_end - hdr_start) ] + \ printf('[ %d-line headers. Press "h" to show. ]', hdr_end + 1 - hdr_start) ] let msg['header'] = hdr let in_header = 0 let hdr = {} From de063624e9364fc46ec47b559342defc040b2ed0 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Sat, 21 Nov 2009 18:34:51 -0500 Subject: [PATCH 045/110] NM_show_prev() -> NM_show_previous() --- vim/plugin/notmuch.vim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 43f6f542..756472c4 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -90,7 +90,7 @@ let g:notmuch_search_maps = { " --- --- bindings for show screen {{{2 let g:notmuch_show_maps = { - \ '': ':call NM_show_prev(1)', + \ '': ':call NM_show_previous(1)', \ '': ':call NM_show_next(1)', \ 'q': ':call NM_kill_this_buffer()', \ @@ -301,7 +301,7 @@ function! s:NM_cmd_show(words) endfunction -function! s:NM_show_prev(can_change_thread) +function! s:NM_show_previous(can_change_thread) let info = b:nm_raw_info let lnum = line('.') for msg in reverse(copy(info['msgs'])) @@ -322,7 +322,7 @@ function! s:NM_show_prev(can_change_thread) norm k call NM_search_show_thread() norm G - call NM_show_prev(0) + call NM_show_previous(0) else echo 'No more messages.' endif From 9e3cc68875602c72109c2e27ba07a193865560fd Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Sat, 21 Nov 2009 21:33:41 -0500 Subject: [PATCH 046/110] remove some debug code from NM_cmd_search() --- vim/plugin/notmuch.vim | 3 --- 1 file changed, 3 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 756472c4..dfa4c432 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -123,11 +123,8 @@ function! s:NM_cmd_search(words) let cmd = cmd + ['--sort=oldest-first'] endif let data = s:NM_run(cmd + a:words) - "let data = substitute(data, '27/27', '25/27', '') - "let data = substitute(data, '\[4/4\]', '[0/4]', '') let lines = split(data, "\n") let disp = copy(lines) - "call map(disp, 'substitute(v:val, "^thread:\\S* ", "", "")' ) call map(disp, 's:NM_cmd_search_fmtline(v:val)') call NM_newBuffer('search', join(disp, "\n")) From 33c896dd717b73dda48b0e4543aaf4376c57c44a Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Sat, 21 Nov 2009 22:24:54 -0500 Subject: [PATCH 047/110] add notmuch-folders support mode --- vim/README | 9 ++- vim/plugin/notmuch.vim | 105 ++++++++++++++++++++++++++++++--- vim/syntax/notmuch-folders.vim | 12 ++++ 3 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 vim/syntax/notmuch-folders.vim diff --git a/vim/README b/vim/README index 20779994..e4ad4eaa 100644 --- a/vim/README +++ b/vim/README @@ -13,6 +13,12 @@ To run: :NotMuch Buffer types: + [notmuch-folders] + Folder list, or technically a list of saved searches. + + Keybindings: + - show the selected search + [notmuch-search] You are presented with the search results when you run :NotMuch. @@ -23,7 +29,8 @@ Buffer types: o - toggle search screen order s - enter search criteria S - alter search criteria - f - filter the current search terms with tags + t - filter the current search terms with tags + q - return to folder display, or undo filter + - add tag(s) to selected message - - remove tag(s) from selected message = - refresh display diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index dfa4c432..f134e652 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -69,8 +69,26 @@ let s:notmuch_show_headers_defaults = [ \ 'Date', \ ] +" defaults for g:notmuch_folders +" override with: let g:notmuch_folders = [ ... ] +let s:notmuch_folders_defaults = [ + \ [ 'new', 'tag:inbox and tag:unread' ], + \ [ 'inbox', 'tag:inbox' ], + \ [ 'unread', 'tag:unread' ], + \ ] + " --- keyboard mapping definitions {{{1 +" --- --- bindings for folders mode {{{2 + +let g:notmuch_folders_maps = { + \ 's': ':call NM_folders_notmuch_search()', + \ 'q': ':call NM_kill_this_buffer()', + \ '<': ':call NM_folders_beginning_of_buffer()', + \ '=': ':call NM_folders_refresh_view()', + \ '': ':call NM_folders_show_search()', + \ } + " --- --- bindings for search screen {{{2 let g:notmuch_search_maps = { \ '': ':call NM_search_show_thread()', @@ -113,6 +131,66 @@ let g:notmuch_show_maps = { \ } +" --- implement folders screen {{{1 + +function! s:NM_cmd_folders(words) + if len(a:words) + echoe 'Not exapecting any arguments for folders command.' + endif + let cmd = ['count'] + let disp = [] + let searches = [] + for entry in g:notmuch_folders + let [ name, search ] = entry + let data = s:NM_run(cmd + [search]) + let cnt = matchlist(data, '\(\d\+\)')[1] + call add(disp, printf('%9d %-20s (%s)', cnt, name, search)) + call add(searches, search) + endfor + + call NM_newBuffer('folders', join(disp, "\n")) + let b:nm_searches = searches + let b:nm_timestamp = reltime() + + call NM_cmd_folders_mksyntax() + call NM_set_map(g:notmuch_folders_maps) + setlocal cursorline + setlocal nowrap +endfunction + +function! s:NM_cmd_folders_mksyntax() +endfunction + +" --- --- folders screen action functions {{{2 + +function! s:NM_folders_notmuch_search() + echo 'not implemented' +endfunction + +function! s:NM_kill_this_buffer() + echo 'not implemented' +endfunction + +function! s:NM_folders_beginning_of_buffer() + echo 'not implemented' +endfunction + +function! s:NM_folders_notmuch_folder() + echo 'not implemented' +endfunction + +function! s:NM_folders_show_search() + let line = line('.') + let search = b:nm_searches[line-1] + + let prev_bufnr = bufnr('%') + setlocal bufhidden=hide + call NM_cmd_search([search]) + setlocal bufhidden=delete + let b:nm_prev_bufnr = prev_bufnr +endfunction + + " --- implement search screen {{{1 function! s:NM_cmd_search(words) @@ -737,6 +815,9 @@ endif if !exists('g:notmuch_initial_search_words') let g:notmuch_initial_search_words = s:notmuch_initial_search_words_defaults endif +if !exists('g:notmuch_folders') + let g:notmuch_folders = s:notmuch_folders_defaults +endif " --- assign keymaps {{{1 @@ -753,20 +834,28 @@ endfunction " --- command handler {{{1 function! NotMuch(args) - if !strlen(a:args) - if exists('b:nm_search_words') + let args = a:args + if !strlen(args) + let args = 'folders' + endif + + let words = split(args) + if words[0] == 'folders' + let words = words[1:] + call NM_cmd_folders(words) + elseif words[0] == 'search' + if len(words) > 1 + let words = words[1:] + elseif exists('b:nm_search_words') let words = b:nm_search_words else let words = g:notmuch_initial_search_words endif call NM_cmd_search(words) - return + + elseif words[0] == 'show' + echoe 'show is not yet implemented.' endif - - echo "blarg!" - - let words = split(a:args) - " TODO: handle commands passed as arguments endfunction function! CompleteNotMuch(arg_lead, cmd_line, cursor_pos) return [] diff --git a/vim/syntax/notmuch-folders.vim b/vim/syntax/notmuch-folders.vim new file mode 100644 index 00000000..9477f86f --- /dev/null +++ b/vim/syntax/notmuch-folders.vim @@ -0,0 +1,12 @@ +" notmuch folders mode syntax file + +syntax region nmFoldersCount start='^' end='\%10v' +syntax region nmFoldersName start='\%11v' end='\%31v' +syntax match nmFoldersSearch /([^()]\+)$/ + +highlight link nmFoldersCount Statement +highlight link nmFoldersName Type +highlight link nmFoldersSearch String + +highlight CursorLine term=reverse cterm=reverse gui=reverse + From 5a9d5fb20091a34efdf6716d4481799097ec9269 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Sat, 21 Nov 2009 23:14:53 -0500 Subject: [PATCH 048/110] make searching, updates and returning to folder view work --- vim/README | 2 ++ vim/plugin/notmuch.vim | 40 ++++++++++++++++++++-------------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/vim/README b/vim/README index e4ad4eaa..38df560d 100644 --- a/vim/README +++ b/vim/README @@ -18,6 +18,8 @@ Buffer types: Keybindings: - show the selected search + s - enter search criteria + = - refresh display [notmuch-search] You are presented with the search results when you run :NotMuch. diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index f134e652..308fc05d 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -82,9 +82,8 @@ let s:notmuch_folders_defaults = [ " --- --- bindings for folders mode {{{2 let g:notmuch_folders_maps = { - \ 's': ':call NM_folders_notmuch_search()', + \ 's': ':call NM_search_prompt()', \ 'q': ':call NM_kill_this_buffer()', - \ '<': ':call NM_folders_beginning_of_buffer()', \ '=': ':call NM_folders_refresh_view()', \ '': ':call NM_folders_show_search()', \ } @@ -163,20 +162,11 @@ endfunction " --- --- folders screen action functions {{{2 -function! s:NM_folders_notmuch_search() - echo 'not implemented' -endfunction - -function! s:NM_kill_this_buffer() - echo 'not implemented' -endfunction - -function! s:NM_folders_beginning_of_buffer() - echo 'not implemented' -endfunction - -function! s:NM_folders_notmuch_folder() - echo 'not implemented' +function! s:NM_folders_refresh_view() + let lno = line('.') + setlocal bufhidden=delete + call s:NM_cmd_folders([]) + exec printf('norm %dG', lno) endfunction function! s:NM_folders_show_search() @@ -251,8 +241,17 @@ function! s:NM_search_prompt() else let tags = s:notmuch_initial_search_words_defaults endif - setlocal bufhidden=delete + let prev_bufnr = bufnr('%') + if b:nm_type == 'search' + " TODO: we intend to replace the current buffer, + " ... maybe we could just clear it + setlocal bufhidden=delete + else + setlocal bufhidden=hide + endif call NM_cmd_search(tags) + setlocal bufhidden=delete + let b:nm_prev_bufnr = prev_bufnr endfunction function! s:NM_search_edit() @@ -713,14 +712,15 @@ endfunction " --- notmuch helper functions {{{1 -function! s:NM_newBuffer(ft, content) +function! s:NM_newBuffer(type, content) enew setlocal buftype=nofile readonly modifiable silent put=a:content keepjumps 0d setlocal nomodifiable - execute printf('set filetype=notmuch-%s', a:ft) - execute printf('set syntax=notmuch-%s', a:ft) + 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_run(args) From e8971117ff1c71c8eee85ba87ad9f91bb1184108 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Sat, 21 Nov 2009 23:17:41 -0500 Subject: [PATCH 049/110] fix returning to folders after searching a few times --- vim/plugin/notmuch.vim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 308fc05d..d786cedf 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -241,12 +241,13 @@ function! s:NM_search_prompt() else let tags = s:notmuch_initial_search_words_defaults endif - let prev_bufnr = bufnr('%') if b:nm_type == 'search' " TODO: we intend to replace the current buffer, " ... maybe we could just clear it + let prev_bufnr = b:nm_prev_bufnr setlocal bufhidden=delete else + let prev_bufnr = bufnr('%') setlocal bufhidden=hide endif call NM_cmd_search(tags) From 5736ea3027a5ebf9824997fa05d05dd74284d66a Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Sat, 21 Nov 2009 23:48:39 -0500 Subject: [PATCH 050/110] vim: place ... more inteligently when shortening 'from' list in search --- vim/plugin/notmuch.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index d786cedf..9cee5008 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -212,7 +212,7 @@ function! s:NM_cmd_search_fmtline(line) let max = g:notmuch_search_from_column_width let from = m[3] if strlen(from) >= max - let from = m[3][0:max-4] . '...' + let from = substitute(m[3][0:max-4], '[^A-Za-z1-9_]*$', '', '') . '...' endif return printf('%s %-20s | %s (%s)', m[2], from, m[4], m[5]) endfunction From a2f6319c9ac8f7f3f991dc56713f0f7902796820 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Sat, 21 Nov 2009 23:52:24 -0500 Subject: [PATCH 051/110] vim plugin: removed some dead code --- vim/plugin/notmuch.vim | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 9cee5008..7ba7f9c1 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -218,10 +218,7 @@ function! s:NM_cmd_search_fmtline(line) endfunction function! s:NM_cmd_search_mksyntax() syntax clear nmSearchFrom - "syntax region nmSearchFrom start='\]\@<=' end='.'me=e+5,he=e+5,re=e+5 oneline contained - "syntax match nmSearchFrom /\]\@<=.\{10\}/ oneline contained exec printf('syntax match nmSearchFrom /\(\] \)\@<=.\{%d\}/ oneline contained', g:notmuch_search_from_column_width) - "exec printf('syntax region nmSearchFrom start=''\%%%dv'' end=''\%%%dv'' oneline contained', 20, 30) endfunction " --- --- search screen action functions {{{2 @@ -797,6 +794,7 @@ function! NM_set_defaults(force) let cmd = printf('let %s = %d', key, dflt) elseif type(dflt) == type('') let cmd = printf('let %s = ''%s''', key, dflt) + " FIXME: not sure why this didn't work when dflt is an array "elseif type(dflt) == type([]) " let cmd = printf('let %s = %s', key, string(dflt)) else From e67ad108c80424a1138e9d2eea37844977fc1eff Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Sat, 21 Nov 2009 23:59:01 -0500 Subject: [PATCH 052/110] vim: highlight []-blocks in search view --- vim/syntax/notmuch-search.vim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vim/syntax/notmuch-search.vim b/vim/syntax/notmuch-search.vim index 832b2b84..3c2b2729 100644 --- a/vim/syntax/notmuch-search.vim +++ b/vim/syntax/notmuch-search.vim @@ -9,6 +9,7 @@ syntax region nmSearchFrom start='\]\@<=' end='|' oneline contained syntax match nmSearchCountZero '0/\(\d\+\)' contained syntax match nmSearchCountSome '\([1-9]\d*\)/\(\d\+\)' contained syntax match nmSearchCountAll '\(\d\+\)/\1' contained +syntax match nmSearchSquareBracketText '\(\[\w\+\]\)' syntax match nmSearchTags /([^)]\+)$/ highlight link nmSearchDate Statement @@ -17,6 +18,7 @@ highlight link nmSearchCountZero Function highlight link nmSearchCountSome Special highlight link nmSearchCountAll Type highlight link nmSearchFrom Include +highlight link nmSearchSquareBracketText Special highlight link nmSearchTags String highlight CursorLine term=reverse cterm=reverse gui=reverse From dda6b7eb1c5a75dc31595376212d0e30c5fd61ed Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Sun, 22 Nov 2009 00:10:27 -0500 Subject: [PATCH 053/110] vim: added searching for word under cursor with ^] --- vim/README | 2 ++ vim/plugin/notmuch.vim | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/vim/README b/vim/README index 38df560d..91fc7a34 100644 --- a/vim/README +++ b/vim/README @@ -36,6 +36,7 @@ Buffer types: + - add tag(s) to selected message - - remove tag(s) from selected message = - refresh display + ^] - search using word under cursor [notmuch-show] This is the display of the message. @@ -48,4 +49,5 @@ Buffer types: h - toggle folding of extra header lines s - toggle folding of signatures q - return to search display + ^] - search using word under cursor diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 7ba7f9c1..3bb9d363 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -91,6 +91,7 @@ let g:notmuch_folders_maps = { " --- --- bindings for search screen {{{2 let g:notmuch_search_maps = { \ '': ':call NM_search_show_thread()', + \ '': ':call NM_search_expand('''')', \ 'a': ':call NM_search_archive_thread()', \ 'f': ':call NM_search_filter()', \ 'm': ':call NM_new_mail()', @@ -109,6 +110,7 @@ let g:notmuch_search_maps = { let g:notmuch_show_maps = { \ '': ':call NM_show_previous(1)', \ '': ':call NM_show_next(1)', + \ '': ':call NM_search_expand('''')', \ 'q': ':call NM_kill_this_buffer()', \ \ 'b': ':call NM_show_fold_toggle(''b'', ''bdy'', !g:notmuch_show_fold_bodies)', @@ -758,6 +760,15 @@ function! s:NM_kill_this_buffer() endif endfunction +function! s:NM_search_expand(arg) + let word = expand(a:arg) + let prev_bufnr = bufnr('%') + setlocal bufhidden=hide + call NM_cmd_search([word]) + setlocal bufhidden=delete + let b:nm_prev_bufnr = prev_bufnr +endfunction + function! s:NM_add_remove_tags(prefix, tags) let id = NM_search_find_thread_id() if id == '' From 251ec73587e92f386c9d24bc781bad38a70e3afb Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Sun, 22 Nov 2009 00:16:25 -0500 Subject: [PATCH 054/110] vim: ingore would-be-folds with line count of 1 or fewer --- vim/plugin/notmuch.vim | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 3bb9d363..15252d2d 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -542,10 +542,8 @@ 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']) - if mode_start != outlnum - let foldinfo = [ mode_type, mode_start, outlnum-1, - \ printf('[ %d-line citation. Press "c" to show. ]', outlnum - mode_start) ] - endif + let foldinfo = [ mode_type, mode_start, outlnum-1, + \ printf('[ %d-line citation. Press "c" to show. ]', outlnum - mode_start) ] let mode_type = '' endif elseif mode_type == 'sig' @@ -553,10 +551,8 @@ function! s:NM_cmd_show_parse(inlines) if (outlnum - mode_start) > g:notmuch_show_signature_lines_max let mode_type = '' elseif part_end - if mode_start != outlnum - let foldinfo = [ mode_type, mode_start, outlnum-1, - \ printf('[ %d-line signature. Press "s" to show. ]', outlnum - mode_start) ] - endif + let foldinfo = [ mode_type, mode_start, outlnum-1, + \ printf('[ %d-line signature. Press "s" to show. ]', outlnum - mode_start) ] let mode_type = '' endif endif @@ -565,7 +561,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 - if len(foldinfo) + if len(foldinfo) && foldinfo[1] < foldinfo[2] call add(info['folds'], foldinfo[0:2]) let info['foldtext'][foldinfo[1]] = foldinfo[3] endif @@ -665,7 +661,7 @@ function! s:NM_cmd_show_parse(inlines) endif endif - if len(foldinfo) + if len(foldinfo) && foldinfo[1] < foldinfo[2] call add(info['folds'], foldinfo[0:2]) let info['foldtext'][foldinfo[1]] = foldinfo[3] endif From 0210f960f10db27ea2556d61340bca24302baf56 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Sun, 22 Nov 2009 00:29:57 -0500 Subject: [PATCH 055/110] vim: have ? show details of what's under cursor in search/show views --- vim/README | 2 ++ vim/plugin/notmuch.vim | 36 ++++++++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/vim/README b/vim/README index 91fc7a34..ff0828ff 100644 --- a/vim/README +++ b/vim/README @@ -36,6 +36,7 @@ Buffer types: + - add tag(s) to selected message - - remove tag(s) from selected message = - refresh display + ? - reveal the thread ID of what's under cursor ^] - search using word under cursor [notmuch-show] @@ -49,5 +50,6 @@ Buffer types: h - toggle folding of extra header lines s - toggle folding of signatures q - return to search display + ? - reveal the message and thread IDs of what's under cursor ^] - search using word under cursor diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 15252d2d..e13ea9f7 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -104,6 +104,7 @@ let g:notmuch_search_maps = { \ '+': ':call NM_search_add_tags([])', \ '-': ':call NM_search_remove_tags([])', \ '=': ':call NM_search_refresh_view()', + \ '?': ':echo NM_search_thread_id()', \ } " --- --- bindings for show screen {{{2 @@ -129,6 +130,7 @@ let g:notmuch_show_maps = { \ \ 'r': ':call NM_show_reply()', \ 'm': ':call NM_new_mail()', + \ '?': ':echo NM_show_thread_id() . '' '' . NM_show_message_id()', \ } @@ -226,7 +228,7 @@ endfunction " --- --- search screen action functions {{{2 function! s:NM_search_show_thread() - let id = NM_search_find_thread_id() + let id = NM_search_thread_id() if id != '' call NM_cmd_show([id]) endif @@ -324,7 +326,7 @@ endfunction " --- --- search screen helper functions {{{2 -function! s:NM_search_find_thread_id() +function! s:NM_search_thread_id() if !exists('b:nm_raw_lines') echoe 'no b:nm_raw_lines' return '' @@ -363,6 +365,7 @@ function! s:NM_cmd_show(words) setlocal bufhidden=hide call NM_newBuffer('show', join(info['disp'], "\n")) setlocal bufhidden=delete + let b:nm_words = a:words let b:nm_raw_info = info let b:nm_prev_bufnr = prev_bufnr @@ -475,7 +478,32 @@ function! s:NM_show_pipe_message() echo 'not implemented' endfunction -" --- --- search screen helper functions {{{2 +" --- --- show screen helper functions {{{2 + +function! s:NM_show_thread_id() + if !exists('b:nm_words') + echoe 'no b:nm_words' + return '' + endif + return b:nm_words[0] +endfunction + +function! s:NM_show_message_id() + if !exists('b:nm_raw_info') + echoe 'no b:nm_raw_info' + return '' + endif + let info = b:nm_raw_info + let lnum = line('.') + for msg in info['msgs'] + if lnum < msg['start'] + continue + endif + + return msg['id'] + endfor + return '' +endfunction function! s:NM_show_fold_toggle(key, type, fold) let info = b:nm_raw_info @@ -766,7 +794,7 @@ function! s:NM_search_expand(arg) endfunction function! s:NM_add_remove_tags(prefix, tags) - let id = NM_search_find_thread_id() + let id = NM_search_thread_id() if id == '' echoe 'Eeek! I couldn''t find the thead id!' endif From b2830acc04514b62a31975291158915b3b919284 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Sun, 22 Nov 2009 00:35:38 -0500 Subject: [PATCH 056/110] vim: use ,s for editing search query (save 'S' for marking things as spam) --- vim/README | 2 +- vim/plugin/notmuch.vim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vim/README b/vim/README index ff0828ff..9f1ff571 100644 --- a/vim/README +++ b/vim/README @@ -30,7 +30,7 @@ Buffer types: f - filter the current search terms o - toggle search screen order s - enter search criteria - S - alter search criteria + es - alter search criteria t - filter the current search terms with tags q - return to folder display, or undo filter + - add tag(s) to selected message diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index e13ea9f7..2d2f9785 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -98,7 +98,7 @@ let g:notmuch_search_maps = { \ 'o': ':call NM_search_toggle_order()', \ 'r': ':call NM_search_reply_to_thread()', \ 's': ':call NM_search_prompt()', - \ 'S': ':call NM_search_edit()', + \ ',s': ':call NM_search_edit()', \ 't': ':call NM_search_filter_by_tag()', \ 'q': ':call NM_kill_this_buffer()', \ '+': ':call NM_search_add_tags([])', From 54a7df40a25ff7584e981ac35d121ac89cfa637e Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Sun, 22 Nov 2009 00:42:42 -0500 Subject: [PATCH 057/110] vim: fix an error in the logic for finding message under cursor in show screen --- vim/plugin/notmuch.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 2d2f9785..aece360b 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -496,7 +496,7 @@ function! s:NM_show_message_id() let info = b:nm_raw_info let lnum = line('.') for msg in info['msgs'] - if lnum < msg['start'] + if lnum >= msg['start'] continue endif From 384037285fa268cc75eedb0dc81e1781f4d45806 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Sun, 22 Nov 2009 15:59:27 -0500 Subject: [PATCH 058/110] vim: cleanup a few minor glitches --- vim/plugin/notmuch.vim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index aece360b..e9370990 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -242,13 +242,13 @@ function! s:NM_search_prompt() else let tags = s:notmuch_initial_search_words_defaults endif + let prev_bufnr = bufnr('%') if b:nm_type == 'search' " TODO: we intend to replace the current buffer, " ... maybe we could just clear it let prev_bufnr = b:nm_prev_bufnr setlocal bufhidden=delete else - let prev_bufnr = bufnr('%') setlocal bufhidden=hide endif call NM_cmd_search(tags) @@ -288,7 +288,6 @@ function! s:NM_search_filter_helper(prompt, prefix) let tags = split(text) map(tags, 'and a:prefix . v:val') let tags = b:nm_search_words + tags - echo tags let prev_bufnr = bufnr('%') setlocal bufhidden=hide @@ -780,7 +779,7 @@ function! s:NM_kill_this_buffer() setlocal bufhidden=delete exec printf(":buffer %d", b:nm_prev_bufnr) else - echo "Nothing to kill." + echo "This is the last buffer; use :q to quit." endif endfunction From e9ca8e5037a4292443eb1cac8540757f118b83f4 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Sun, 22 Nov 2009 17:17:20 -0500 Subject: [PATCH 059/110] vim: cleanup tag filtering Given an existing search expression and a regular filter, the resulting search will be: EXISTING AND ( NEW ) With a tag filter each of the tags given will be prefixed with tag: and separated by AND. --- vim/plugin/notmuch.vim | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index e9370990..7ba35f37 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -271,14 +271,14 @@ function! s:NM_search_archive_thread() endfunction function! s:NM_search_filter() - call NM_search_filter_helper('Filter: ', '') + call NM_search_filter_helper('Filter: ', '', '') endfunction function! s:NM_search_filter_by_tag() - call NM_search_filter_helper('Filter Tag(s): ', 'tag:') + call NM_search_filter_helper('Filter Tag(s): ', 'tag:', 'and') endfunction -function! s:NM_search_filter_helper(prompt, prefix) +function! s:NM_search_filter_helper(prompt, prefix, joiner) " TODO: input() can support completion let text = input(a:prompt) if !strlen(text) @@ -286,8 +286,17 @@ function! s:NM_search_filter_helper(prompt, prefix) endif let tags = split(text) - map(tags, 'and a:prefix . v:val') - let tags = b:nm_search_words + tags + if strlen(a:prefix) + call map(tags, 'a:prefix . v:val') + endif + if strlen(a:joiner) + let idx = len(tags) - 1 + while idx > 0 + call insert(tags, a:joiner, idx) + let idx = idx - 1 + endwhile + endif + let tags = b:nm_search_words + ['and', '''('] + tags + [')'''] let prev_bufnr = bufnr('%') setlocal bufhidden=hide From 418a7f3108273c5b8a0ff36ab1bb3b9886089648 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Mon, 23 Nov 2009 09:28:40 -0500 Subject: [PATCH 060/110] vim: add git-diff.vim in README, make syntax work w/o the script --- vim/README | 7 +++++++ vim/syntax/notmuch-show.vim | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/vim/README b/vim/README index 9f1ff571..02bd3e65 100644 --- a/vim/README +++ b/vim/README @@ -3,15 +3,22 @@ through vim. NOTE: this is a work in progress. Patches welcome. +The vim interface makes use of the git-diff.vim syntax file which is +available from + http://github.com/motemen/git-vim/blob/master/syntax/git-diff.vim + + To install: make install + To run: vim -c ':NotMuch' from vim: :NotMuch + Buffer types: [notmuch-folders] Folder list, or technically a list of saved searches. diff --git a/vim/syntax/notmuch-show.vim b/vim/syntax/notmuch-show.vim index 20c6b88f..20bcc399 100644 --- a/vim/syntax/notmuch-show.vim +++ b/vim/syntax/notmuch-show.vim @@ -11,7 +11,9 @@ syntax match nmShowMsgHeadVal /^\([^:]\+: \)\@<=.*/ contained syntax cluster nmShowMsgBody contains=@nmShowMsgBodyMail,@nmShowMsgBodyGit syntax include @nmShowMsgBodyMail syntax/mail.vim -syntax include @nmShowMsgBodyGit syntax/git-diff.vim + +" git-diff.vim marks up diffs in emails, see README for details +silent! syntax include @nmShowMsgBodyGit syntax/git-diff.vim highlight nmShowMsgDescWho term=reverse cterm=reverse gui=reverse highlight link nmShowMsgDescDate Type From 6bc0ec618d55aed84b1b0a810c0f1ac877a4e430 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Mon, 23 Nov 2009 20:05:51 -0500 Subject: [PATCH 061/110] vim: preserve previous buffer number when refreshing search --- vim/plugin/notmuch.vim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 7ba35f37..0addd76a 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -326,8 +326,10 @@ endfunction function! s:NM_search_refresh_view() let lno = line('.') + let prev_bufnr = b:nm_prev_bufnr setlocal bufhidden=delete call NM_cmd_search(b:nm_search_words) + let b:nm_prev_bufnr = prev_bufnr " FIXME: should find the line of the thread we were on if possible exec printf('norm %dG', lno) endfunction From f275f5f7f0fd919b3f5a531ceb379006b740ee12 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Mon, 23 Nov 2009 20:20:34 -0500 Subject: [PATCH 062/110] vim: fix column formatting for >9 messages in search view --- vim/plugin/notmuch.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 0addd76a..0681c124 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -218,7 +218,7 @@ function! s:NM_cmd_search_fmtline(line) if strlen(from) >= max let from = substitute(m[3][0:max-4], '[^A-Za-z1-9_]*$', '', '') . '...' endif - return printf('%s %-20s | %s (%s)', m[2], from, m[4], m[5]) + return printf('%-20s %-20s | %s (%s)', m[2], from, m[4], m[5]) endfunction function! s:NM_cmd_search_mksyntax() syntax clear nmSearchFrom From 845732464cced1d798fdf480e34b7bdf471b491a Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Mon, 23 Nov 2009 20:23:41 -0500 Subject: [PATCH 063/110] vim: fix shell escaping for () in search terms --- vim/plugin/notmuch.vim | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 0681c124..47bb4caf 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -296,7 +296,7 @@ function! s:NM_search_filter_helper(prompt, prefix, joiner) let idx = idx - 1 endwhile endif - let tags = b:nm_search_words + ['and', '''('] + tags + [')'''] + let tags = b:nm_search_words + ['and', '('] + tags + [')'] let prev_bufnr = bufnr('%') setlocal bufhidden=hide @@ -757,8 +757,15 @@ function! s:NM_newBuffer(type, content) let b:nm_type = a:type endfunction +function! s:NM_shell_escape(word) + let word = substitute(a:word, '''', '\\''', 'g') + return '''' . word . '''' +endfunction + function! s:NM_run(args) - let cmd = g:notmuch_cmd . ' ' . join(a:args) . '< /dev/null' + let words = a: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) From be19c210ca1cb7e4fe1de5ab5847fabbedbacc9a Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Mon, 23 Nov 2009 20:24:22 -0500 Subject: [PATCH 064/110] vim: fix '?' command in message display --- vim/plugin/notmuch.vim | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 47bb4caf..d2650855 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -130,7 +130,7 @@ let g:notmuch_show_maps = { \ \ 'r': ':call NM_show_reply()', \ 'm': ':call NM_new_mail()', - \ '?': ':echo NM_show_thread_id() . '' '' . NM_show_message_id()', + \ '?': ':echo NM_show_message_id() . '' @ '' . join(NM_show_search_words())', \ } @@ -506,7 +506,7 @@ function! s:NM_show_message_id() let info = b:nm_raw_info let lnum = line('.') for msg in info['msgs'] - if lnum >= msg['start'] + if lnum > msg['end'] continue endif @@ -515,6 +515,14 @@ function! s:NM_show_message_id() return '' endfunction +function! s:NM_show_search_words() + if !exists('b:nm_words') + echoe 'no b:nm_words' + return [] + endif + return b:nm_words +endfunction + function! s:NM_show_fold_toggle(key, type, fold) let info = b:nm_raw_info let act = 'open' From b740392b3de8fad233e1cf9db7c881208d76115c Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Mon, 23 Nov 2009 20:25:47 -0500 Subject: [PATCH 065/110] vim: include search terms when showing message --- vim/plugin/notmuch.vim | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index d2650855..aff49266 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -230,7 +230,13 @@ endfunction function! s:NM_search_show_thread() let id = NM_search_thread_id() if id != '' - call NM_cmd_show([id]) + let words = [id] + if exists('b:nm_search_words') + let words = ['('] + b:nm_search_words + [')', 'and', id] + endif + if len(words) + call NM_cmd_show(words) + endif endif endfunction From 76dc061de31fbbe5dde0558e45fec17a06b2bf71 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Mon, 23 Nov 2009 20:26:28 -0500 Subject: [PATCH 066/110] vim: include stubs for Tab-ing thorugh folds in show view --- vim/plugin/notmuch.vim | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index aff49266..fbe4cd9e 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -128,6 +128,10 @@ let g:notmuch_show_maps = { \ '': ':call NM_show_advance_marking_read_and_archiving()', \ '\|': ':call NM_show_pipe_message()', \ + \ '': ':call NM_show_previous_fold()', + \ '': ':call NM_show_next_fold()', + \ '': ':call NM_show_toggle_fold()', + \ \ 'r': ':call NM_show_reply()', \ 'm': ':call NM_new_mail()', \ '?': ':echo NM_show_message_id() . '' @ '' . join(NM_show_search_words())', @@ -494,16 +498,21 @@ function! s:NM_show_pipe_message() echo 'not implemented' endfunction -" --- --- show screen helper functions {{{2 - -function! s:NM_show_thread_id() - if !exists('b:nm_words') - echoe 'no b:nm_words' - return '' - endif - return b:nm_words[0] +function! s:NM_show_previous_fold() + echo 'not implemented' endfunction +function! s:NM_show_next_fold() + echo 'not implemented' +endfunction + +function! s:NM_show_toggle_fold() + echo 'not implemented' +endfunction + + +" --- --- show screen helper functions {{{2 + function! s:NM_show_message_id() if !exists('b:nm_raw_info') echoe 'no b:nm_raw_info' From 553637313bd152071e20035c95fb80b0257b835c Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 25 Nov 2009 00:06:11 -0500 Subject: [PATCH 067/110] vim: make timing info a debug option --- vim/plugin/notmuch.vim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index fbe4cd9e..e9763ebe 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -23,6 +23,7 @@ let s:notmuch_defaults = { \ 'g:notmuch_cmd': 'notmuch' , + \ 'g:notmuch_debug': 0 , \ \ 'g:notmuch_search_newest_first': 1 , \ 'g:notmuch_search_from_column_width': 20 , @@ -795,7 +796,9 @@ function! s:NM_run(args) let err = v:shell_error let delta = reltime(start) - echo printf('[%s] {%s} %s', reltimestr(delta), string(err), string(cmd)) + if exists('g:notmuch_debug') && g:notmuch_debug + echo printf('[%s] {%s} %s', reltimestr(delta), string(err), string(cmd)) + endif if err echohl Error From a01e1335bea5fc583e1ab5e1a2ea8ad81ba725ce Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 25 Nov 2009 00:13:32 -0500 Subject: [PATCH 068/110] vim: minor improvements to search screen syntax matching --- vim/syntax/notmuch-search.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vim/syntax/notmuch-search.vim b/vim/syntax/notmuch-search.vim index 3c2b2729..71839fd9 100644 --- a/vim/syntax/notmuch-search.vim +++ b/vim/syntax/notmuch-search.vim @@ -2,9 +2,9 @@ " TODO: I cannot figure out why nmSearchTags is not matching anything :( -syntax region nmSearchDate start='^' end='\%13v' +syntax region nmSearchDate start='^' end='\%13v' oneline syntax region nmSearchCountAndFrom start='\%14v\[' end='|' oneline contains=nmSearchCount,nmSearchFrom -syntax region nmSearchCount start='\%14v\[' end='\]' contained contains=nmSearchCountZero,nmSearchCountSome,nmSearchCountAll +syntax region nmSearchCount start='\[' end='\]' oneline contained contains=nmSearchCountZero,nmSearchCountSome,nmSearchCountAll syntax region nmSearchFrom start='\]\@<=' end='|' oneline contained syntax match nmSearchCountZero '0/\(\d\+\)' contained syntax match nmSearchCountSome '\([1-9]\d*\)/\(\d\+\)' contained From 9d9b03c837edde2aaed1cd9f8472d2be45c406bf Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 25 Nov 2009 00:36:11 -0500 Subject: [PATCH 069/110] vim: return nothing instead of failting if there is no message id --- vim/plugin/notmuch.vim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index e9763ebe..3ceefe58 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -525,8 +525,10 @@ function! s:NM_show_message_id() if lnum > msg['end'] continue endif - - return msg['id'] + if has_key(msg,'id') + return msg['id'] + endif + return '' endfor return '' endfunction From 5a32a1d48f790d5bb63e5e7e70b989cd94692c0a Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 25 Nov 2009 00:37:10 -0500 Subject: [PATCH 070/110] vim: fold messages that don't match a query --- vim/plugin/notmuch.vim | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 3ceefe58..8f6c7748 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -45,7 +45,7 @@ let s:notmuch_defaults = { \ 'g:notmuch_show_part_end_regexp': '^ part}' , \ 'g:notmuch_show_marker_regexp': '^ \\(message\\|header\\|body\\|attachment\\|part\\)[{}].*$', \ - \ 'g:notmuch_show_message_parse_regexp': '\(id:[^ ]*\) depth:\([0-9]*\) filename:\(.*\)$', + \ 'g:notmuch_show_message_parse_regexp': '\(id:[^ ]*\) depth:\([0-9]*\) match:\([0-9]*\) filename:\(.*\)$', \ 'g:notmuch_show_tags_regexp': '(\([^)]*\))$' , \ \ 'g:notmuch_show_signature_regexp': '^\(-- \?\|_\+\)$' , @@ -606,7 +606,7 @@ 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, + let foldinfo = [ mode_type, mode_start, outlnum-1, len(info['msgs']), \ printf('[ %d-line citation. Press "c" to show. ]', outlnum - mode_start) ] let mode_type = '' endif @@ -615,7 +615,7 @@ 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, + let foldinfo = [ mode_type, mode_start, outlnum-1, len(info['msgs']), \ printf('[ %d-line signature. Press "s" to show. ]', outlnum - mode_start) ] let mode_type = '' endif @@ -626,11 +626,11 @@ function! s:NM_cmd_show_parse(inlines) " FIXME: this is a hack for handling two folds being added for one line " we should handle addinga fold in a function if len(foldinfo) && foldinfo[1] < foldinfo[2] - call add(info['folds'], foldinfo[0:2]) - let info['foldtext'][foldinfo[1]] = foldinfo[3] + call add(info['folds'], foldinfo[0:3]) + let info['foldtext'][foldinfo[1]] = foldinfo[4] endif - let foldinfo = [ 'text', part_start, part_end, + let foldinfo = [ 'text', part_start, part_end, len(info['msgs']), \ printf('[ %d-line %s. Press "p" to show. ]', part_end - part_start, in_part) ] let in_part = '' call add(info['disp'], '') @@ -642,7 +642,7 @@ function! s:NM_cmd_show_parse(inlines) endif if match(line, g:notmuch_show_body_end_regexp) != -1 let body_end = len(info['disp']) - let foldinfo = [ 'bdy', body_start, body_end, + let foldinfo = [ 'bdy', body_start, body_end, len(info['msgs']), \ printf('[ BODY %d - %d lines ]', len(info['msgs']), body_end - body_start) ] let in_body = 0 @@ -669,7 +669,7 @@ function! s:NM_cmd_show_parse(inlines) if match(line, g:notmuch_show_header_end_regexp) != -1 let hdr_start = msg['hdr_start']+1 let hdr_end = len(info['disp']) - let foldinfo = [ 'hdr', hdr_start, hdr_end, + let foldinfo = [ 'hdr', hdr_start, hdr_end, len(info['msgs']), \ printf('[ %d-line headers. Press "h" to show. ]', hdr_end + 1 - hdr_start) ] let msg['header'] = hdr let in_header = 0 @@ -690,7 +690,7 @@ function! s:NM_cmd_show_parse(inlines) let msg['end'] = len(info['disp']) call add(info['disp'], '') - let foldinfo = [ 'msg', msg['start'], msg['end'], + let foldinfo = [ 'msg', msg['start'], msg['end'], len(info['msgs']), \ printf('[ MSG %d - %s ]', len(info['msgs']), msg['descr']) ] call add(info['msgs'], msg) @@ -718,7 +718,8 @@ function! s:NM_cmd_show_parse(inlines) if len(m) let msg['id'] = m[1] let msg['depth'] = m[2] - let msg['filename'] = m[3] + let msg['match'] = m[3] + let msg['filename'] = m[4] endif let in_message = 1 @@ -726,8 +727,8 @@ function! s:NM_cmd_show_parse(inlines) endif if len(foldinfo) && foldinfo[1] < foldinfo[2] - call add(info['folds'], foldinfo[0:2]) - let info['foldtext'][foldinfo[1]] = foldinfo[3] + call add(info['folds'], foldinfo[0:3]) + let info['foldtext'][foldinfo[1]] = foldinfo[4] endif endfor return info @@ -738,14 +739,20 @@ function! s:NM_cmd_show_mkfolds() for afold in info['folds'] exec printf('%d,%dfold', afold[1], afold[2]) + let state = 'open' if (afold[0] == 'sig' && g:notmuch_show_fold_signatures) \ || (afold[0] == 'cit' && g:notmuch_show_fold_citations) \ || (afold[0] == 'bdy' && g:notmuch_show_fold_bodies) \ || (afold[0] == 'hdr' && g:notmuch_show_fold_headers) - exec printf('%dfoldclose', afold[1]) - else - exec printf('%dfoldopen', afold[1]) + let state = 'close' + elseif afold[0] == 'msg' + let idx = afold[3] + let msg = info['msgs'][idx] + if has_key(msg,'match') && msg['match'] == '0' + let state = 'close' + endif endif + exec printf('%dfold%s', afold[1], state) endfor endfunction From b440aeb23e8ddc3c88c697718aedab0ab9ca3245 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 25 Nov 2009 14:12:29 -0500 Subject: [PATCH 071/110] vim: pass filter expression to add/remove tag functions --- vim/plugin/notmuch.vim | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 8f6c7748..f0106604 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -276,8 +276,8 @@ function! s:NM_search_edit() endfunction function! s:NM_search_archive_thread() - call NM_add_remove_tags_on_screen('-', ['inbox']) - call NM_add_remove_tags('-', ['inbox']) + call NM_add_remove_tags_on_screen('', '-', ['inbox']) + call NM_add_remove_tags([], '-', ['inbox']) norm j endfunction @@ -370,8 +370,8 @@ function! s:NM_search_add_remove_tags(prompt, prefix, intags) else let tags = a:intags endif - call NM_add_remove_tags(a:prefix, tags) - call NM_add_remove_tags_on_screen(a:prefix, tags) + call NM_add_remove_tags([], a:prefix, tags) + call NM_add_remove_tags_on_screen('', a:prefix, tags) endfunction " --- implement show screen {{{1 @@ -845,26 +845,31 @@ function! s:NM_search_expand(arg) let b:nm_prev_bufnr = prev_bufnr endfunction -function! s:NM_add_remove_tags(prefix, tags) - let id = NM_search_thread_id() - if id == '' +function! s:NM_add_remove_tags(filter, prefix, tags) + let filter = len(a:filter) ? a:filter : [NM_search_thread_id()] + if !len(filter) echoe 'Eeek! I couldn''t find the thead id!' endif + echo 'filter = ' . string(filter) . ' ... ' . string(type(filter)) call map(a:tags, 'a:prefix . v:val') " TODO: handle errors - call NM_run(['tag'] + a:tags + ['--', id]) + let args = ['tag'] + call extend(args, a:tags) + call add(args, '--') + call extend(args, filter) + echo 'NUM_run( ' . string(args) . ' )' + call NM_run(args) endfunction -function! s:NM_add_remove_tags_on_screen(prefix, tags) - let online = '' +function! s:NM_add_remove_tags_on_screen(online, prefix, tags) setlocal modifiable if a:prefix == '-' for tagname in a:tags - exec printf('silent %ss/(\([^)]*\)\<%s\>\([^)]*\))$/(\1\2)/', online, tagname) + exec printf('silent! %ss/(\([^)]*\)\<%s\>\([^)]*\))$/(\1\2)/', string(a:online), tagname) endfor else for tagname in a:tags - exec printf('silent %ss/(\([^)]*\)\([^)]*\))$/(\1 %s)/', online, tagname) + exec printf('silent! %ss/(\([^)]*\)\([^)]*\))$/(\1 %s)/', string(a:online), tagname) endfor endif setlocal nomodifiable From 0f39d2c4deef6f774e63d78a226857039d0cd978 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 25 Nov 2009 14:17:34 -0500 Subject: [PATCH 072/110] vim: allow show_next/previous to skip non-matching messages --- vim/plugin/notmuch.vim | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index f0106604..c95e6b0e 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -110,8 +110,8 @@ let g:notmuch_search_maps = { " --- --- bindings for show screen {{{2 let g:notmuch_show_maps = { - \ '': ':call NM_show_previous(1)', - \ '': ':call NM_show_next(1)', + \ '': ':call NM_show_previous(1, 0)', + \ '': ':call NM_show_next(1, 0)', \ '': ':call NM_search_expand('''')', \ 'q': ':call NM_kill_this_buffer()', \ @@ -399,10 +399,13 @@ function! s:NM_cmd_show(words) endfunction -function! s:NM_show_previous(can_change_thread) +function! s:NM_show_previous(can_change_thread, find_matching) let info = b:nm_raw_info let lnum = line('.') for msg in reverse(copy(info['msgs'])) + if a:find_matching && msg['match'] == '0' + continue + endif if lnum <= msg['start'] continue endif @@ -426,10 +429,13 @@ function! s:NM_show_previous(can_change_thread) endif endfunction -function! s:NM_show_next(can_change_thread) +function! s:NM_show_next(can_change_thread, find_matching) let info = b:nm_raw_info let lnum = line('.') for msg in info['msgs'] + if a:find_matching && msg['match'] == '0' + continue + endif if lnum >= msg['start'] continue endif From 898b173a182ee37d6e54f5f09284f99a8aef8892 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 25 Nov 2009 14:18:29 -0500 Subject: [PATCH 073/110] vim: more cleanup and fixes for show_next/previous handlers --- vim/plugin/notmuch.vim | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index c95e6b0e..7927dd62 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -410,20 +410,19 @@ function! s:NM_show_previous(can_change_thread, find_matching) continue endif - exec printf('norm %dG', msg['start']) + exec printf('norm %dGzt', msg['start']) " TODO: try to fit the message on screen - norm zz return endfor if !a:can_change_thread return endif call NM_kill_this_buffer() - if line('.') != line('0') + if line('.') > 1 norm k call NM_search_show_thread() norm G - call NM_show_previous(0) + call NM_show_previous(0, a:find_matching) else echo 'No more messages.' endif @@ -440,14 +439,16 @@ function! s:NM_show_next(can_change_thread, find_matching) continue endif - exec printf('norm %dG', msg['start']) + exec printf('norm %dGzt', msg['start']) " TODO: try to fit the message on screen - norm zz return endfor - if !a:can_change_thread - return + if a:can_change_thread + call NM_show_next_thread() endif +endfunction + +function! s:NM_show_next_thread() call NM_kill_this_buffer() if line('.') != line('$') norm j @@ -465,10 +466,6 @@ function! s:NM_show_mark_read_then_archive_thread() echo 'not implemented' endfunction -function! s:NM_show_next_message() - echo 'not implemented' -endfunction - function! s:NM_show_mark_read_then_next_open_message() echo 'not implemented' endfunction From 329f95eb77b3661247a461db2cfe190140864b65 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 25 Nov 2009 14:19:02 -0500 Subject: [PATCH 074/110] vim: refactor get_message_for_line out of show_message_id --- vim/plugin/notmuch.vim | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 7927dd62..b6bc6120 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -517,22 +517,25 @@ endfunction " --- --- show screen helper functions {{{2 +function! s:NM_show_get_message_for_line(line) + for msg in b:nm_raw_info['msgs'] + if a:line > msg['end'] + continue + endif + return msg + endfor + return {} +endfunction + function! s:NM_show_message_id() if !exists('b:nm_raw_info') echoe 'no b:nm_raw_info' return '' endif - let info = b:nm_raw_info - let lnum = line('.') - for msg in info['msgs'] - if lnum > msg['end'] - continue - endif - if has_key(msg,'id') - return msg['id'] - endif - return '' - endfor + let msg = NM_show_get_message_for_line(line('.')) + if has_key(msg,'id') + return msg['id'] + endif return '' endfunction From 4c9ddb9ac152df442c6971e4448b0839179a5c66 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 25 Nov 2009 14:19:35 -0500 Subject: [PATCH 075/110] vim: don't use scrolloff/sidesscrolloff in notmuch buffers --- vim/plugin/notmuch.vim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index b6bc6120..b4eeb416 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -791,6 +791,8 @@ function! s:NM_newBuffer(type, content) 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 From 8c8dacb26a08acc91cee723276851feb369743d0 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 25 Nov 2009 14:20:44 -0500 Subject: [PATCH 076/110] vim: Space archives/reads and advances to next message --- vim/plugin/notmuch.vim | 63 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index b4eeb416..c8a27ad7 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -494,8 +494,69 @@ function! s:NM_show_remove_tag() echo 'not implemented' endfunction +" if entire message is not visible scroll down 1/2 page or less to get to the bottom of message +" otherwise go to next message +" any message that is viewed entirely has inbox and unread tags removed function! s:NM_show_advance_marking_read_and_archiving() - echo 'not implemented' + let advance_tags = ['unread', 'inbox'] + + let vis_top = line('w0') + let vis_bot = line('w$') + + let msg_top = NM_show_get_message_for_line(vis_top) + if !has_key(msg_top,'id') + echo "No top visible message." + endif + + " if the top message is the last message, just expunge the entire thread and move on + if msg_top['end'] == line('$') + let ids = [] + for msg in b:nm_raw_info['msgs'] + if has_key(msg,'match') && msg['match'] != '0' + if len(ids) + call add(ids, 'OR') + endif + call add(ids, msg['id']) + endif + endfor + + let filter = ['('] + advance_tags + [')', 'AND', '('] + ids + [')'] +echo 'NM_add_remove_tags ALL filter=' . string(filter) + call NM_add_remove_tags(filter, '-', advance_tags) + call NM_show_next(1, 1) + return + endif + + let msg_bot = NM_show_get_message_for_line(vis_bot) + if !has_key(msg_bot,'id') + echo "No bottom visible message." + endif + + echo 'top=' . msg_top['id'] . ' bot=' . msg_top['id'] + + " if entire message fits on the screen, read/archive it, move to the next one + if msg_top['id'] != msg_bot['id'] || msg_top['end'] <= vis_bot + call NM_add_remove_tags_on_screen(msg_top['start'], '-', advance_tags) + exec printf('norm %dG', vis_top) + call NM_show_next(0, 1) + if has_key(msg_top,'match') && msg_top['match'] != '0' + redraw + " do this last to hide the latency + let filter = ['('] + advance_tags + [')', 'AND', msg_top['id']] +echo 'NM_add_remove_tags 1 filter=' . string(filter) + call NM_add_remove_tags(filter, '-', advance_tags) + endif + return + endif + + " entire message does not fit on the screen, scroll down to bottom, max 1/2 screen + let jmp = winheight(winnr()) / 2 + let max = msg_bot['end'] - vis_bot + if jmp > max + let jmp = max + endif + exec printf('norm %dGzt', vis_top + jmp) + return endfunction function! s:NM_show_pipe_message() From 29b420700e45785dbfb5e0fac7b0fa0e1da689d8 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 25 Nov 2009 14:31:36 -0500 Subject: [PATCH 077/110] vim: removing debug statements --- vim/plugin/notmuch.vim | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index c8a27ad7..e1822a41 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -521,7 +521,6 @@ function! s:NM_show_advance_marking_read_and_archiving() endfor let filter = ['('] + advance_tags + [')', 'AND', '('] + ids + [')'] -echo 'NM_add_remove_tags ALL filter=' . string(filter) call NM_add_remove_tags(filter, '-', advance_tags) call NM_show_next(1, 1) return @@ -532,8 +531,6 @@ echo 'NM_add_remove_tags ALL filter=' . string(filter) echo "No bottom visible message." endif - echo 'top=' . msg_top['id'] . ' bot=' . msg_top['id'] - " if entire message fits on the screen, read/archive it, move to the next one if msg_top['id'] != msg_bot['id'] || msg_top['end'] <= vis_bot call NM_add_remove_tags_on_screen(msg_top['start'], '-', advance_tags) @@ -543,7 +540,6 @@ echo 'NM_add_remove_tags ALL filter=' . string(filter) redraw " do this last to hide the latency let filter = ['('] + advance_tags + [')', 'AND', msg_top['id']] -echo 'NM_add_remove_tags 1 filter=' . string(filter) call NM_add_remove_tags(filter, '-', advance_tags) endif return @@ -919,14 +915,12 @@ function! s:NM_add_remove_tags(filter, prefix, tags) if !len(filter) echoe 'Eeek! I couldn''t find the thead id!' endif - echo 'filter = ' . string(filter) . ' ... ' . string(type(filter)) call map(a:tags, 'a:prefix . v:val') - " TODO: handle errors let args = ['tag'] call extend(args, a:tags) call add(args, '--') call extend(args, filter) - echo 'NUM_run( ' . string(args) . ' )' + " TODO: handle errors call NM_run(args) endfunction From e2fd1d9970d5ad61017a307ab133990150192d37 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 25 Nov 2009 19:26:36 -0500 Subject: [PATCH 078/110] vim: fix some error checking in NM_search_thread_id() --- vim/plugin/notmuch.vim | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index e1822a41..ade2e45d 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -351,12 +351,15 @@ function! s:NM_search_thread_id() if !exists('b:nm_raw_lines') echoe 'no b:nm_raw_lines' return '' - else - let line = line('.') - let info = b:nm_raw_lines[line-1] - let what = split(info, '\s\+')[0] - return what endif + let mnum = line('.') - 1 + if len(b:nm_raw_lines) <= mnum + return '' + endif + echo 'len=' . string(len(b:nm_raw_lines)) . ' mnum=' . string(mnum) + let info = b:nm_raw_lines[mnum] + let what = split(info, '\s\+')[0] + return what endfunction function! s:NM_search_add_remove_tags(prompt, prefix, intags) From 7a7be482f79b13130fa2b053df9fdea6b86d4c95 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Wed, 25 Nov 2009 20:01:13 -0500 Subject: [PATCH 079/110] vim: fix a case where we started with :NotMuch search --- vim/plugin/notmuch.vim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index ade2e45d..e41daed1 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -254,7 +254,7 @@ function! s:NM_search_prompt() let tags = s:notmuch_initial_search_words_defaults endif let prev_bufnr = bufnr('%') - if b:nm_type == 'search' + if b:nm_type == 'search' && exists('b:nm_prev_bufnr') " TODO: we intend to replace the current buffer, " ... maybe we could just clear it let prev_bufnr = b:nm_prev_bufnr @@ -1000,6 +1000,7 @@ function! NotMuch(args) if words[0] == 'folders' let words = words[1:] call NM_cmd_folders(words) + elseif words[0] == 'search' if len(words) > 1 let words = words[1:] From 480903adac81ec03613c4edf46c9c2f6a2766c4c Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 26 Nov 2009 22:22:30 -0500 Subject: [PATCH 080/110] vim: allow for different types of mappings not just normal mode ones --- vim/plugin/notmuch.vim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index e41daed1..15958f18 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -161,7 +161,7 @@ function! s:NM_cmd_folders(words) let b:nm_timestamp = reltime() call NM_cmd_folders_mksyntax() - call NM_set_map(g:notmuch_folders_maps) + call NM_set_map('n', g:notmuch_folders_maps) setlocal cursorline setlocal nowrap endfunction @@ -209,7 +209,7 @@ function! s:NM_cmd_search(words) let b:nm_search_words = a:words call NM_cmd_search_mksyntax() - call NM_set_map(g:notmuch_search_maps) + call NM_set_map('n', g:notmuch_search_maps) setlocal cursorline setlocal nowrap endfunction @@ -395,7 +395,7 @@ function! s:NM_cmd_show(words) call NM_cmd_show_mkfolds() call NM_cmd_show_mksyntax() - call NM_set_map(g:notmuch_show_maps) + call NM_set_map('n', g:notmuch_show_maps) setlocal foldtext=NM_cmd_show_foldtext() setlocal fillchars= setlocal foldcolumn=6 @@ -979,10 +979,10 @@ endif " --- assign keymaps {{{1 -function! s:NM_set_map(maps) +function! s:NM_set_map(type, maps) nmapclear for [key, code] in items(a:maps) - exec printf('nnoremap %s %s', key, code) + exec printf('%snoremap %s %s', a:type, key, code) endfor " --- this is a hack for development :) nnoremap ,nmr :source ~/.vim/plugin/notmuch.vim:call NotMuch('') From bbca6e03c650fcd29e88c8aa2cdd987195e3903a Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 26 Nov 2009 22:24:33 -0500 Subject: [PATCH 081/110] vim: add a line splitter that understands quotes this makes it possible to tokenise expressions like :NotMuch compose 'subject: one two three' to:bart@jukie.net --- vim/plugin/notmuch.vim | 46 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 15958f18..7c69bc8b 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -863,6 +863,46 @@ function! s:NM_shell_escape(word) 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)') @@ -996,12 +1036,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') From 5bb149aab27b68d48b165f1e0dae19d1a83cc6f2 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 26 Nov 2009 22:25:43 -0500 Subject: [PATCH 082/110] vim: cleanup settings in newBuffer() and make them local --- vim/plugin/notmuch.vim | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 7c69bc8b..8e3a92ab 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -847,12 +847,10 @@ endfunction function! s:NM_newBuffer(type, content) enew - setlocal buftype=nofile readonly modifiable + 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 From 0aa5f7d250a5a157fce51c1769c95c7fb5a2056b Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 26 Nov 2009 22:30:13 -0500 Subject: [PATCH 083/110] vim: add support for :NotMuch compose ... but it doesn't send yet. --- vim/plugin/notmuch.vim | 140 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 8e3a92ab..99be6261 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -52,6 +52,8 @@ let s:notmuch_defaults = { \ 'g:notmuch_show_signature_lines_max': 12 , \ \ 'g:notmuch_show_citation_regexp': '^\s*>' , + \ + \ 'g:notmuch_compose_temp_file_dir': '~/.notmuch/compose/' , \ } " defaults for g:notmuch_initial_search_words @@ -78,6 +80,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 @@ -843,6 +863,92 @@ function! NM_cmd_show_foldtext() endfunction +" --- implement compose screen {{{1 + +function! s:NM_cmd_compose(words, body_lines) + let 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_cmd_compose_mksyntax() + call NM_set_map('n', g:notmuch_compose_nmaps) + call NM_set_map('i', g:notmuch_compose_imaps) + + exec printf('norm %dG', start_on_line) + startinsert! + echo 'Type your message, use to jump to next header and then body.' +endfunction +function! s:NM_cmd_compose_mksyntax() + silent! setlocal syntax=mail +endfunction + +function! s:NM_compose_send() + echo 'not implemented' +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 + + " --- notmuch helper functions {{{1 function! s:NM_newBuffer(type, content) @@ -856,7 +962,31 @@ function! s:NM_newBuffer(type, content) 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 @@ -1014,6 +1144,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 @@ -1051,6 +1187,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) From b078a0c8c2ce72e1273bed87627e25dcd833a967 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 26 Nov 2009 22:32:02 -0500 Subject: [PATCH 084/110] vim: add support for in compose mode this will skip to the next header in insert and normal modes, and behave like otherwise. --- vim/plugin/notmuch.vim | 55 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 99be6261..d3e31353 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -158,6 +158,15 @@ 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()', + \ ',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 @@ -938,6 +947,40 @@ function! s:NM_compose_send() 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 + echo 'mode=' . mode() + 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() @@ -948,6 +991,18 @@ function! s:NM_compose_get_user_email() 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 From 805633beccd51752ee458424a342601318d5ceae Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 26 Nov 2009 22:32:17 -0500 Subject: [PATCH 085/110] vim: syntax highlighting for notmuch-compose mode --- vim/syntax/notmuch-compose.vim | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 vim/syntax/notmuch-compose.vim diff --git a/vim/syntax/notmuch-compose.vim b/vim/syntax/notmuch-compose.vim new file mode 100644 index 00000000..fe4efd4b --- /dev/null +++ b/vim/syntax/notmuch-compose.vim @@ -0,0 +1,2 @@ +silent! setlocal syntax=mail + From 8bafbac75c53631d0db351e20fb5f5bb0fcfb48e Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 26 Nov 2009 23:04:53 -0500 Subject: [PATCH 086/110] vim: add a helpful header to notmuch-compose mode --- vim/plugin/notmuch.vim | 20 ++++++++++++++------ vim/syntax/notmuch-compose.vim | 7 ++++++- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index d3e31353..341f3370 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -53,6 +53,7 @@ let s:notmuch_defaults = { \ \ 'g:notmuch_show_citation_regexp': '^\s*>' , \ + \ 'g:notmuch_compose_header_help': 1 , \ 'g:notmuch_compose_temp_file_dir': '~/.notmuch/compose/' , \ } @@ -161,6 +162,7 @@ let g:notmuch_show_maps = { " --- --- 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()', \ } @@ -875,7 +877,13 @@ endfunction " --- implement compose screen {{{1 function! s:NM_cmd_compose(words, body_lines) - let 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 = { } @@ -931,22 +939,22 @@ function! s:NM_cmd_compose(words, body_lines) \ 'compose', lines) setlocal bufhidden=hide - call NM_cmd_compose_mksyntax() call NM_set_map('n', g:notmuch_compose_nmaps) call NM_set_map('i', g:notmuch_compose_imaps) - exec printf('norm %dG', start_on_line) + call cursor(start_on_line, strlen(start_on_line) + 1) startinsert! echo 'Type your message, use to jump to next header and then body.' endfunction -function! s:NM_cmd_compose_mksyntax() - silent! setlocal syntax=mail -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) diff --git a/vim/syntax/notmuch-compose.vim b/vim/syntax/notmuch-compose.vim index fe4efd4b..19adb756 100644 --- a/vim/syntax/notmuch-compose.vim +++ b/vim/syntax/notmuch-compose.vim @@ -1,2 +1,7 @@ -silent! setlocal syntax=mail +runtime! syntax/mail.vim +syntax region nmComposeHelp contains=nmComposeHelpLine start='^Notmuch-Help:\%1l' end='^\(Notmuch-Help:\)\@!' +syntax match nmComposeHelpLine /Notmuch-Help:/ contained + +highlight link nmComposeHelp Include +highlight link nmComposeHelpLine Error From aa312db8cd333d3739011e2299905542c9031946 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 26 Nov 2009 23:09:57 -0500 Subject: [PATCH 087/110] vim: make insert in compose mode configurable --- vim/plugin/notmuch.vim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 341f3370..3c9c3162 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -53,6 +53,7 @@ let s:notmuch_defaults = { \ \ '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/' , \ } @@ -943,7 +944,9 @@ function! s:NM_cmd_compose(words, body_lines) call NM_set_map('i', g:notmuch_compose_imaps) call cursor(start_on_line, strlen(start_on_line) + 1) - startinsert! + if g:notmuch_compose_insert_mode_start + startinsert! + endif echo 'Type your message, use to jump to next header and then body.' endfunction @@ -976,7 +979,6 @@ function! s:NM_compose_next_entry_area() call cursor(lnum+1, strlen(getline(lnum+1)) + 1) return '' endif - echo 'mode=' . mode() if mode() == 'i' if !getbufvar(bufnr('.'), '&et') return "\t" From 9012c652827be6ac4d748de50be5c93a6d4e97eb Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 26 Nov 2009 23:11:38 -0500 Subject: [PATCH 088/110] vim: replace echo\nreturn with trhow in a few places --- vim/plugin/notmuch.vim | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 3c9c3162..b70c6edc 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -381,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 @@ -621,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') @@ -633,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 From 350e0136963d14d3dfe2ba88e80c217b483d5949 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 01:01:37 -0500 Subject: [PATCH 089/110] vim: allow overriding how newBuffer is created --- vim/plugin/notmuch.vim | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index b70c6edc..0adca0b0 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -188,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() @@ -236,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 @@ -418,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 @@ -1013,8 +1013,12 @@ endfunction " --- notmuch helper functions {{{1 -function! s:NM_newBuffer(type, content) - enew +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 From 651b215f0f6d4f220ff67941dbecd54692382472 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 01:02:37 -0500 Subject: [PATCH 090/110] vim: make sure headers begin with \w --- vim/plugin/notmuch.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 0adca0b0..63095ed5 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -886,7 +886,7 @@ function! s:NM_cmd_compose(words, body_lines) let hdrs = { } for word in a:words - let m = matchlist(word, '^\([^:]\+\):\s*\(.*\)\s*$') + let m = matchlist(word, '^\(\w[^:]*\):\s*\(.*\)\s*$') if !len(m) throw 'Eeek! bad parameter ''' . string(word) . '''' endif From 05d76deb2eb3aaf09444e8cfb59a438c3d774bea Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 01:02:50 -0500 Subject: [PATCH 091/110] vim: store previous buffer number when starting to compose --- vim/plugin/notmuch.vim | 1 + 1 file changed, 1 insertion(+) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 63095ed5..63a711fd 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -936,6 +936,7 @@ function! s:NM_cmd_compose(words, body_lines) call NM_newFileBuffer(g:notmuch_compose_temp_file_dir, '%s.mail', \ 'compose', lines) setlocal bufhidden=hide + let b:nm_prev_bufnr = prev_bufnr call NM_set_map('n', g:notmuch_compose_nmaps) call NM_set_map('i', g:notmuch_compose_imaps) From b5e28d86153c15461f277ef1b0b827d3fe4a5fc1 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 01:03:35 -0500 Subject: [PATCH 092/110] vim: implement sending with ,s from compose buffer --- vim/plugin/notmuch.vim | 106 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 3 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 63a711fd..47a22610 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -949,7 +949,99 @@ function! s:NM_cmd_compose(words, body_lines) endfunction function! s:NM_compose_send() - echo 'not implemented' + call NM_assert_buffer_type('compose') + 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 + endif + let lnum = lnum + 1 + let line = getline(lnum) + endwhile + let body_starts = lnum + 1 + exec printf('0,%dd', body_starts) + write + + "[-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) + + call map(cmd, 's:NM_shell_escape(v:val)') + let cmdtxt = join(cmd) . '< ' . fname + let out = system(cmdtxt) + let err = v:shell_error + if err + undo + write + call NM_newBuffer('new', 'error', + \ "While running...\n" . + \ ' ' . cmdtxt . "\n" . + \ "\n" . + \ "Failed with...\n" . + \ substitute(out, '^', ' ', 'g')) + echohl Error + echo 'Eeek! unable to send mail' + echohl None + return + endif + + if !exists('b:nm_prev_bufnr') + bdelete + else + let prev_bufnr = b:nm_prev_bufnr + bdelete + if prev_bufnr == bufnr('%') + exec printf("buffer %d", prev_bufnr) + endif + endif + call delete(fname) + echo 'Mail sent successfully.' endfunction function! s:NM_compose_attach() @@ -1045,6 +1137,13 @@ function! s:NM_newFileBuffer(fdir, fname, type, lines) let b:nm_type = a:type endfunction +function! s:NM_assert_buffer_type(type) + if !exists('b:nm_type') || b:nm_type != a:type + throw printf('Eeek! expected type %s, but got %s.', a:type, + \ exists(b:nm_type) ? b:nm_type : 'something else') + endif +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) @@ -1132,8 +1231,9 @@ endfunction function! s:NM_kill_this_buffer() if exists('b:nm_prev_bufnr') - setlocal bufhidden=delete - exec printf(":buffer %d", b:nm_prev_bufnr) + let prev_bufnr = b:nm_prev_bufnr + bdelete + exec printf("buffer %d", prev_bufnr) else echo "This is the last buffer; use :q to quit." endif From becc49eee7b2fdf20cb32055fdbfba7b4a5159ac Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 01:17:36 -0500 Subject: [PATCH 093/110] vim: fix message parsing patterns if a message did not contain a trailing CR, we may not be able to match ^\f --- vim/plugin/notmuch.vim | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 47a22610..e94d44bd 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -33,17 +33,17 @@ let s:notmuch_defaults = { \ 'g:notmuch_show_fold_bodies': 0 , \ 'g:notmuch_show_fold_headers': 1 , \ - \ 'g:notmuch_show_message_begin_regexp': '^ message{' , - \ 'g:notmuch_show_message_end_regexp': '^ message}' , - \ 'g:notmuch_show_header_begin_regexp': '^ header{' , - \ 'g:notmuch_show_header_end_regexp': '^ header}' , - \ 'g:notmuch_show_body_begin_regexp': '^ body{' , - \ 'g:notmuch_show_body_end_regexp': '^ body}' , - \ 'g:notmuch_show_attachment_begin_regexp': '^ attachment{' , - \ 'g:notmuch_show_attachment_end_regexp': '^ attachment}' , - \ 'g:notmuch_show_part_begin_regexp': '^ part{' , - \ 'g:notmuch_show_part_end_regexp': '^ part}' , - \ 'g:notmuch_show_marker_regexp': '^ \\(message\\|header\\|body\\|attachment\\|part\\)[{}].*$', + \ 'g:notmuch_show_message_begin_regexp': ' message{' , + \ 'g:notmuch_show_message_end_regexp': ' message}' , + \ 'g:notmuch_show_header_begin_regexp': ' header{' , + \ 'g:notmuch_show_header_end_regexp': ' header}' , + \ 'g:notmuch_show_body_begin_regexp': ' body{' , + \ 'g:notmuch_show_body_end_regexp': ' body}' , + \ 'g:notmuch_show_attachment_begin_regexp': ' attachment{' , + \ 'g:notmuch_show_attachment_end_regexp': ' attachment}' , + \ 'g:notmuch_show_part_begin_regexp': ' part{' , + \ 'g:notmuch_show_part_end_regexp': ' part}' , + \ 'g:notmuch_show_marker_regexp': ' \\(message\\|header\\|body\\|attachment\\|part\\)[{}].*$', \ \ 'g:notmuch_show_message_parse_regexp': '\(id:[^ ]*\) depth:\([0-9]*\) match:\([0-9]*\) filename:\(.*\)$', \ 'g:notmuch_show_tags_regexp': '(\([^)]*\))$' , From 5b8f74b51291171a0d5bb6212dbff17a2c202e8e Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 01:18:00 -0500 Subject: [PATCH 094/110] vim: force deleting buffers --- vim/plugin/notmuch.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index e94d44bd..af812668 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -1232,7 +1232,7 @@ endfunction function! s:NM_kill_this_buffer() if exists('b:nm_prev_bufnr') let prev_bufnr = b:nm_prev_bufnr - bdelete + bdelete! exec printf("buffer %d", prev_bufnr) else echo "This is the last buffer; use :q to quit." From a04334e95903cfeb4f26d1820eeeb0ed63487dea Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 01:31:16 -0500 Subject: [PATCH 095/110] vim: fix regexp for cleaning search list --- vim/plugin/notmuch.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index af812668..b63417b8 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -1270,7 +1270,7 @@ function! s:NM_add_remove_tags_on_screen(online, prefix, tags) endfor else for tagname in a:tags - exec printf('silent! %ss/(\([^)]*\)\([^)]*\))$/(\1 %s)/', string(a:online), tagname) + exec printf('silent! %ss/(\([^)]*\))$/(\1 %s)/', string(a:online), tagname) endfor endif setlocal nomodifiable From dfb0b97b3cbc38952de39ef7d23deadf59cab731 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 01:34:08 -0500 Subject: [PATCH 096/110] vim: cleanup error messages --- vim/plugin/notmuch.vim | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index b63417b8..95e9c98c 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -175,7 +175,7 @@ let g:notmuch_compose_imaps = { function! s:NM_cmd_folders(words) if len(a:words) - echoe 'Not exapecting any arguments for folders command.' + throw 'Not exapecting any arguments for folders command.' endif let cmd = ['count'] let disp = [] @@ -387,7 +387,6 @@ function! s:NM_search_thread_id() if len(b:nm_raw_lines) <= mnum return '' endif - echo 'len=' . string(len(b:nm_raw_lines)) . ' mnum=' . string(mnum) let info = b:nm_raw_lines[mnum] let what = split(info, '\s\+')[0] return what @@ -539,7 +538,7 @@ function! s:NM_show_advance_marking_read_and_archiving() let msg_top = NM_show_get_message_for_line(vis_top) if !has_key(msg_top,'id') - echo "No top visible message." + throw "No top visible message." endif " if the top message is the last message, just expunge the entire thread and move on @@ -562,7 +561,7 @@ function! s:NM_show_advance_marking_read_and_archiving() let msg_bot = NM_show_get_message_for_line(vis_bot) if !has_key(msg_bot,'id') - echo "No bottom visible message." + throw "No bottom visible message." endif " if entire message fits on the screen, read/archive it, move to the next one @@ -1051,7 +1050,6 @@ 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) @@ -1251,7 +1249,7 @@ endfunction function! s:NM_add_remove_tags(filter, prefix, tags) let filter = len(a:filter) ? a:filter : [NM_search_thread_id()] if !len(filter) - echoe 'Eeek! I couldn''t find the thead id!' + throw 'Eeek! I couldn''t find the thead id!' endif call map(a:tags, 'a:prefix . v:val') let args = ['tag'] From 43cfdab6088fb4cefb2b3a7d443f1479e0e29f8a Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 09:35:49 -0500 Subject: [PATCH 097/110] vim: have '?' show search words in search mode --- vim/plugin/notmuch.vim | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 95e9c98c..d406a7eb 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -127,7 +127,7 @@ let g:notmuch_search_maps = { \ '+': ':call NM_search_add_tags([])', \ '-': ':call NM_search_remove_tags([])', \ '=': ':call NM_search_refresh_view()', - \ '?': ':echo NM_search_thread_id()', + \ '?': ':echo NM_search_thread_id() . '' @ '' . join(NM_get_search_words())', \ } " --- --- bindings for show screen {{{2 @@ -157,7 +157,7 @@ let g:notmuch_show_maps = { \ \ 'r': ':call NM_show_reply()', \ 'm': ':call NM_new_mail()', - \ '?': ':echo NM_show_message_id() . '' @ '' . join(NM_show_search_words())', + \ '?': ':echo NM_show_message_id() . '' @ '' . join(NM_get_search_words())', \ } " --- --- bindings for compose screen {{{2 @@ -419,7 +419,7 @@ function! s:NM_cmd_show(words) setlocal bufhidden=hide call NM_newBuffer('', 'show', join(info['disp'], "\n")) setlocal bufhidden=delete - let b:nm_words = a:words + let b:nm_search_words = a:words let b:nm_raw_info = info let b:nm_prev_bufnr = prev_bufnr @@ -628,13 +628,6 @@ function! s:NM_show_message_id() return '' endfunction -function! s:NM_show_search_words() - if !exists('b:nm_words') - throw 'Eeek! no b:nm_words' - endif - return b:nm_words -endfunction - function! s:NM_show_fold_toggle(key, type, fold) let info = b:nm_raw_info let act = 'open' @@ -1227,6 +1220,13 @@ endfunction " --- other helpers {{{1 +function! s:NM_get_search_words() + if !exists('b:nm_search_words') + throw 'Eeek! no b:nm_search_words' + endif + return b:nm_search_words +endfunction + function! s:NM_kill_this_buffer() if exists('b:nm_prev_bufnr') let prev_bufnr = b:nm_prev_bufnr From 5030989ee0fa6ad0fda2f010dae9fbccc057a350 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 09:43:06 -0500 Subject: [PATCH 098/110] vim: README updates and corrections --- vim/README | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/vim/README b/vim/README index 02bd3e65..d8bea97f 100644 --- a/vim/README +++ b/vim/README @@ -3,9 +3,17 @@ through vim. NOTE: this is a work in progress. Patches welcome. -The vim interface makes use of the git-diff.vim syntax file which is -available from - http://github.com/motemen/git-vim/blob/master/syntax/git-diff.vim +Dependencies: + notmuch: + Naturally, it expects you have notmuch installed and configured. + + mail: + To send mail, notmuch.vim uses the UNIX mail command. + + git-diff: + The vim interface makes use of the git-diff.vim syntax file + which is available from + http://github.com/motemen/git-vim/blob/master/syntax/git-diff.vim To install: @@ -37,7 +45,7 @@ Buffer types: f - filter the current search terms o - toggle search screen order s - enter search criteria - es - alter search criteria + ,s - alter search criteria t - filter the current search terms with tags q - return to folder display, or undo filter + - add tag(s) to selected message @@ -50,6 +58,7 @@ Buffer types: This is the display of the message. Keybindings: + - mark read, archive, go to next matching message ^n - next message ^p - previous message b - toggle folding of message bodies From efa9df2d49b522cc981dc1ab0637219047753483 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 11:04:54 -0500 Subject: [PATCH 099/110] vim: add a helper to combine tag search expressions --- vim/plugin/notmuch.vim | 53 ++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index d406a7eb..daff4aab 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -269,7 +269,7 @@ function! s:NM_search_show_thread() if id != '' let words = [id] if exists('b:nm_search_words') - let words = ['('] + b:nm_search_words + [')', 'and', id] + let words = ['('] + b:nm_search_words + [')', 'AND', id] endif if len(words) call NM_cmd_show(words) @@ -323,23 +323,13 @@ endfunction function! s:NM_search_filter_helper(prompt, prefix, joiner) " TODO: input() can support completion - let text = input(a:prompt) + let text = substitute(input(a:prompt), '\v(^\s*|\s*$|\n)', '', 'g') if !strlen(text) return endif - let tags = split(text) - if strlen(a:prefix) - call map(tags, 'a:prefix . v:val') - endif - if strlen(a:joiner) - let idx = len(tags) - 1 - while idx > 0 - call insert(tags, a:joiner, idx) - let idx = idx - 1 - endwhile - endif - let tags = b:nm_search_words + ['and', '('] + tags + [')'] + let tags = b:nm_search_words + ['AND'] + \ + NM_combine_tags(a:prefix, split(text), a:joiner, '()') let prev_bufnr = bufnr('%') setlocal bufhidden=hide @@ -546,14 +536,12 @@ function! s:NM_show_advance_marking_read_and_archiving() let ids = [] for msg in b:nm_raw_info['msgs'] if has_key(msg,'match') && msg['match'] != '0' - if len(ids) - call add(ids, 'OR') - endif call add(ids, msg['id']) endif endfor - - let filter = ['('] + advance_tags + [')', 'AND', '('] + ids + [')'] + let filter = NM_combine_tags('tag:', advance_tags, 'OR', '()') + \ + ['AND'] + \ + NM_combine_tags('', ids, 'OR', '()') call NM_add_remove_tags(filter, '-', advance_tags) call NM_show_next(1, 1) return @@ -572,7 +560,8 @@ function! s:NM_show_advance_marking_read_and_archiving() if has_key(msg_top,'match') && msg_top['match'] != '0' redraw " do this last to hide the latency - let filter = ['('] + advance_tags + [')', 'AND', msg_top['id']] + let filter = NM_combine_tags('tag:', advance_tags, 'OR', '()') + \ + ['AND', msg_top['id']] call NM_add_remove_tags(filter, '-', advance_tags) endif return @@ -1218,6 +1207,30 @@ function! s:NM_new_mail() echo 'not implemented' endfunction +" --- tag manipulation helpers {{{1 + +" used to combine an array of words with prefixes and separators +" example: +" NM_combine_tags('tag:', ['one', 'two', 'three'], 'OR', '()') +" -> ['(', 'tag:one', 'OR', 'tag:two', 'OR', 'tag:three', ')'] +function s:NM_combine_tags(word_prefix, words, separator, brackets) + let res = [] + for word in a:words + if len(res) && strlen(a:separator) + call add(res, a:separator) + endif + call add(res, a:word_prefix . word) + endfor + if len(res) > 1 && strlen(a:brackets) + if strlen(a:brackets) != 2 + throw 'Eeek! brackets arg to NM_combine_tags must be 2 chars' + endif + call insert(res, a:brackets[0]) + call add(res, a:brackets[1]) + endif + return res +endfunction + " --- other helpers {{{1 function! s:NM_get_search_words() From d1eb2c6ce55fa3cf3ea97d27c3dbb4c2b69419da Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 13:06:46 -0500 Subject: [PATCH 100/110] vim: make it possible to replace NM_cobine_tags() --- vim/plugin/notmuch.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index daff4aab..8ef6ac5a 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -1213,7 +1213,7 @@ endfunction " example: " NM_combine_tags('tag:', ['one', 'two', 'three'], 'OR', '()') " -> ['(', 'tag:one', 'OR', 'tag:two', 'OR', 'tag:three', ')'] -function s:NM_combine_tags(word_prefix, words, separator, brackets) +function! s:NM_combine_tags(word_prefix, words, separator, brackets) let res = [] for word in a:words if len(res) && strlen(a:separator) From ef8127076072f743f396cb3d3df946423c1dbbd4 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 13:08:30 -0500 Subject: [PATCH 101/110] vim: have ,nmr just reload the plugin w/o restarting state --- vim/plugin/notmuch.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 8ef6ac5a..4e164b8d 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -1337,7 +1337,7 @@ function! s:NM_set_map(type, maps) exec printf('%snoremap %s %s', a:type, key, code) endfor " --- this is a hack for development :) - nnoremap ,nmr :source ~/.vim/plugin/notmuch.vim:call NotMuch('') + nnoremap ,nmr :runtime! plugin/notmuch.vim endfunction " --- command handler {{{1 From b76852dcc517dc3fc754c26b438f0875e4cfbb3f Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 13:32:57 -0500 Subject: [PATCH 102/110] vim: generalize compose buffer function further --- vim/plugin/notmuch.vim | 73 +++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 4e164b8d..ef3260ed 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -856,13 +856,7 @@ 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 lines = [] let start_on_line = 0 let hdrs = { } @@ -900,7 +894,7 @@ function! s:NM_cmd_compose(words, body_lines) endif endfor - call extend(lines, [ '', '' ]) + call add(lines, '') if !start_on_line let start_on_line = len(lines) + 1 endif @@ -908,25 +902,10 @@ function! s:NM_cmd_compose(words, body_lines) if len(a:body_lines) call extend(lines, a:body_lines) else - call add(lines, '') + call extend(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 - let b:nm_prev_bufnr = prev_bufnr - - 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.' + call NM_newComposeBuffer(lines, start_on_line) endfunction function! s:NM_compose_send() @@ -1117,6 +1096,50 @@ function! s:NM_newFileBuffer(fdir, fname, type, lines) let b:nm_type = a:type endfunction +function! s:NM_newComposeBuffer(lines, start_on_line) + let lines = a:lines + let start_on_line = a:start_on_line + let real_hdr_start = 1 + if g:notmuch_compose_header_help + let help_lines = [ + \ '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', + \ ] + call extend(lines, help_lines, 0) + let real_hdr_start = len(help_lines) + if start_on_line > 0 + let start_on_line = start_on_line + len(help_lines) + endif + 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 + let b:nm_prev_bufnr = prev_bufnr + + call NM_set_map('n', g:notmuch_compose_nmaps) + call NM_set_map('i', g:notmuch_compose_imaps) + + if start_on_line > 0 && start_on_line <= len(lines) + call cursor(start_on_line, strlen(getline(start_on_line)) + 1) + else + call cursor(real_hdr_start, strlen(getline(real_hdr_start) + 1) + call NM_compose_next_entry_area() + endif + + 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_assert_buffer_type(type) if !exists('b:nm_type') || b:nm_type != a:type throw printf('Eeek! expected type %s, but got %s.', a:type, From fd805c16c3fdcc4170a42d3cacb9b16cdfa11ff7 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 14:02:25 -0500 Subject: [PATCH 103/110] vim: fix off-by-one error when removing header from message to send out --- vim/plugin/notmuch.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index ef3260ed..a4d04e26 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -938,7 +938,7 @@ function! s:NM_compose_send() let lnum = lnum + 1 let line = getline(lnum) endwhile - let body_starts = lnum + 1 + let body_starts = lnum exec printf('0,%dd', body_starts) write From e13bdc2c0e10dfa2786f65ee185e8a6563feb2db Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 14:05:13 -0500 Subject: [PATCH 104/110] vim: don't remove headers until after parsing them --- vim/plugin/notmuch.vim | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index a4d04e26..f32a134f 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -939,8 +939,6 @@ function! s:NM_compose_send() let line = getline(lnum) endwhile let body_starts = lnum - exec printf('0,%dd', body_starts) - write "[-a header] [-b bcc-addr] [-c cc-addr] [-s subject] to-addr let cmd = ['mail'] @@ -972,6 +970,12 @@ function! s:NM_compose_send() endfor call extend(cmd, tos) + " TODO: make sure we have at least one target + " TODO: ask about empty jubject, etc + + exec printf('0,%dd', body_starts) + write + call map(cmd, 's:NM_shell_escape(v:val)') let cmdtxt = join(cmd) . '< ' . fname let out = system(cmdtxt) From 0ef04e14ffac768b211510fab5b351cfab38b6ee Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 16:47:39 -0500 Subject: [PATCH 105/110] vim: few compose mode updates, including README --- vim/README | 15 +++++++++++++++ vim/plugin/notmuch.vim | 5 +++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/vim/README b/vim/README index d8bea97f..b2328814 100644 --- a/vim/README +++ b/vim/README @@ -25,6 +25,7 @@ To run: from vim: :NotMuch + :NotMuch new to:bart@jukie.net 'subject:this is a test' Buffer types: @@ -33,6 +34,7 @@ Buffer types: Keybindings: - show the selected search + m - compose a new message s - enter search criteria = - refresh display @@ -44,6 +46,7 @@ Buffer types: a - archive message (remove inbox tag) f - filter the current search terms o - toggle search screen order + m - compose a new message s - enter search criteria ,s - alter search criteria t - filter the current search terms with tags @@ -64,8 +67,20 @@ Buffer types: b - toggle folding of message bodies c - toggle folding of citations h - toggle folding of extra header lines + m - compose a new message s - toggle folding of signatures q - return to search display ? - reveal the message and thread IDs of what's under cursor ^] - search using word under cursor + [notmuch-compose] + When you're writing an email, you're in this mode. + + Insert-mode keybindings: + - go to the next header line + + Normal-mode keybindings: + - go to the next header line + ,s - send this message + ,q - abort this message + diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index f32a134f..37781c0c 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -105,6 +105,7 @@ let s:notmuch_compose_headers_defaults = [ " --- --- bindings for folders mode {{{2 let g:notmuch_folders_maps = { + \ 'm': ':call NM_new_mail()', \ 's': ':call NM_search_prompt()', \ 'q': ':call NM_kill_this_buffer()', \ '=': ':call NM_folders_refresh_view()', @@ -1134,7 +1135,7 @@ function! s:NM_newComposeBuffer(lines, start_on_line) if start_on_line > 0 && start_on_line <= len(lines) call cursor(start_on_line, strlen(getline(start_on_line)) + 1) else - call cursor(real_hdr_start, strlen(getline(real_hdr_start) + 1) + call cursor(real_hdr_start, strlen(getline(real_hdr_start)) + 1) call NM_compose_next_entry_area() endif @@ -1231,7 +1232,7 @@ endfunction " --- external mail handling helpers {{{1 function! s:NM_new_mail() - echo 'not implemented' + call NM_cmd_compose([], []) endfunction " --- tag manipulation helpers {{{1 From ab3ce6196ee32ce19626d6f11bc3763dd13bce66 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 16:48:18 -0500 Subject: [PATCH 106/110] vim: primitive reply to thread --- vim/README | 1 + vim/plugin/notmuch.vim | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/vim/README b/vim/README index b2328814..3965eeb4 100644 --- a/vim/README +++ b/vim/README @@ -47,6 +47,7 @@ Buffer types: f - filter the current search terms o - toggle search screen order m - compose a new message + r - reply to thread s - enter search criteria ,s - alter search criteria t - filter the current search terms with tags diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 37781c0c..23feb7de 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -347,7 +347,14 @@ function! s:NM_search_toggle_order() endfunction function! s:NM_search_reply_to_thread() - echo 'not implemented' + let cmd = ['reply'] + call add(cmd, NM_search_thread_id()) + call add(cmd, 'AND') + call extend(cmd, NM_get_search_words()) + + let data = NM_run(cmd) + let lines = split(data, "\n") + call NM_newComposeBuffer(lines, 0) endfunction function! s:NM_search_add_tags(tags) From e5a25c769240a91b1b5bc5e4349e85ec368b5cfb Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 16:52:00 -0500 Subject: [PATCH 107/110] vim: primitive reply to message --- vim/README | 1 + vim/plugin/notmuch.vim | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/vim/README b/vim/README index 3965eeb4..a139dfce 100644 --- a/vim/README +++ b/vim/README @@ -69,6 +69,7 @@ Buffer types: c - toggle folding of citations h - toggle folding of extra header lines m - compose a new message + r - reply to the message s - toggle folding of signatures q - return to search display ? - reveal the message and thread IDs of what's under cursor diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 23feb7de..9932e3f1 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -506,7 +506,14 @@ function! s:NM_show_previous_message() endfunction function! s:NM_show_reply() - echo 'not implemented' + let cmd = ['reply'] + call add(cmd, NM_show_message_id()) + call add(cmd, 'AND') + call extend(cmd, NM_get_search_words()) + + let data = NM_run(cmd) + let lines = split(data, "\n") + call NM_newComposeBuffer(lines, 0) endfunction function! s:NM_show_view_all_mime_parts() From dffee11a40dd85b174b726b602a3f53112229aff Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 17:18:41 -0500 Subject: [PATCH 108/110] vim: don't toggle folds that are inside closed folds in show mode --- vim/plugin/notmuch.vim | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index 9932e3f1..cb7f34f5 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -639,9 +639,19 @@ function! s:NM_show_fold_toggle(key, type, fold) let act = 'close' endif for fld in info['folds'] - if fld[0] == a:type - exec printf('%dfold%s', fld[1], act) + if fld[0] != a:type + continue endif + "let idx = fld[3] + "let msg = info['msgs'][idx] + "if has_key(msg,'match') && msg['match'] == '0' + " continue + "endif + let cls = foldclosed(fld[1]) + if cls != -1 && cls != fld[1] + continue + endif + exec printf('%dfold%s', fld[1], act) endfor exec printf('nnoremap %s :call NM_show_fold_toggle(''%s'', ''%s'', %d)', a:key, a:key, a:type, !a:fold) endfunction From 16a00de92421e1397e5089d9e9f41b44f4f51c22 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 17:43:01 -0500 Subject: [PATCH 109/110] vim: make it possible to start a search in show mode --- vim/README | 3 ++- vim/plugin/notmuch.vim | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/vim/README b/vim/README index a139dfce..299c7f89 100644 --- a/vim/README +++ b/vim/README @@ -68,9 +68,10 @@ Buffer types: b - toggle folding of message bodies c - toggle folding of citations h - toggle folding of extra header lines + i - toggle folding of signatures m - compose a new message r - reply to the message - s - toggle folding of signatures + s - enter search criteria q - return to search display ? - reveal the message and thread IDs of what's under cursor ^] - search using word under cursor diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index cb7f34f5..c5655617 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -137,11 +137,12 @@ let g:notmuch_show_maps = { \ '': ':call NM_show_next(1, 0)', \ '': ':call NM_search_expand('''')', \ 'q': ':call NM_kill_this_buffer()', + \ 's': ':call NM_search_prompt()', \ \ 'b': ':call NM_show_fold_toggle(''b'', ''bdy'', !g:notmuch_show_fold_bodies)', \ 'c': ':call NM_show_fold_toggle(''c'', ''cit'', !g:notmuch_show_fold_citations)', \ 'h': ':call NM_show_fold_toggle(''h'', ''hdr'', !g:notmuch_show_fold_headers)', - \ 's': ':call NM_show_fold_toggle(''s'', ''sig'', !g:notmuch_show_fold_signatures)', + \ 'i': ':call NM_show_fold_toggle(''s'', ''sig'', !g:notmuch_show_fold_signatures)', \ \ 'a': ':call NM_show_archive_thread()', \ 'A': ':call NM_show_mark_read_then_archive_thread()', From e6628e78d9ce3f9383a4699df9063a648617b428 Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Fri, 27 Nov 2009 18:02:05 -0500 Subject: [PATCH 110/110] vim: use more consistently in search view In search view will show the thead, but folding messages that don't match the current search expression. Conversly, always shows all messages in the thread. --- vim/README | 3 ++- vim/plugin/notmuch.vim | 20 +++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/vim/README b/vim/README index 299c7f89..8cd3b1a2 100644 --- a/vim/README +++ b/vim/README @@ -42,7 +42,8 @@ Buffer types: You are presented with the search results when you run :NotMuch. Keybindings: - - show the selected message + - show the selected thread colapsing unmatched items + - show the entire selected thread a - archive message (remove inbox tag) f - filter the current search terms o - toggle search screen order diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim index c5655617..b415f500 100644 --- a/vim/plugin/notmuch.vim +++ b/vim/plugin/notmuch.vim @@ -114,7 +114,8 @@ let g:notmuch_folders_maps = { " --- --- bindings for search screen {{{2 let g:notmuch_search_maps = { - \ '': ':call NM_search_show_thread()', + \ '': ':call NM_search_show_thread(0)', + \ '': ':call NM_search_show_thread(1)', \ '': ':call NM_search_expand('''')', \ 'a': ':call NM_search_archive_thread()', \ 'f': ':call NM_search_filter()', @@ -266,17 +267,14 @@ endfunction " --- --- search screen action functions {{{2 -function! s:NM_search_show_thread() - let id = NM_search_thread_id() - if id != '' - let words = [id] - if exists('b:nm_search_words') - let words = ['('] + b:nm_search_words + [')', 'AND', id] - endif - if len(words) - call NM_cmd_show(words) - endif +function! s:NM_search_show_thread(everything) + let words = [ NM_search_thread_id() ] + if !a:everything && exists('b:nm_search_words') + call extend(words, ['AND', '(']) + call extend(words, b:nm_search_words) + call add(words, ')') endif + call NM_cmd_show(words) endfunction function! s:NM_search_prompt()