"
" Authors: Bart Trojanowski <bart@jukie.net>
-" --- defaults
-
-if !exists('g:notmuch_cmd')
- let g:notmuch_cmd = 'notmuch'
-endif
-
-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 = '^\fmessage{'
-let s:notmuch_show_message_end_regexp = '^\fmessage}'
-let s:notmuch_show_header_begin_regexp = '^\fheader{'
-let s:notmuch_show_header_end_regexp = '^\fheader}'
-let s:notmuch_show_body_begin_regexp = '^\fbody{'
-let s:notmuch_show_body_end_regexp = '^\fbody}'
-let s:notmuch_show_attachment_begin_regexp = '^\fattachment{'
-let s:notmuch_show_attachment_end_regexp = '^\fattachment}'
-let s:notmuch_show_part_begin_regexp = '^\fpart{'
-let s:notmuch_show_part_end_regexp = '^\fpart}'
-let s:notmuch_show_marker_regexp = '^\f\\(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 s:notmuch_show_fold_signatures = 1
-let s:notmuch_show_fold_citations = 1
-
-" --- implement search screen
+" --- configuration defaults {{{1
+
+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': '^\fmessage{' ,
+ \ 'g:notmuch_show_message_end_regexp': '^\fmessage}' ,
+ \ 'g:notmuch_show_header_begin_regexp': '^\fheader{' ,
+ \ 'g:notmuch_show_header_end_regexp': '^\fheader}' ,
+ \ 'g:notmuch_show_body_begin_regexp': '^\fbody{' ,
+ \ 'g:notmuch_show_body_end_regexp': '^\fbody}' ,
+ \ 'g:notmuch_show_attachment_begin_regexp': '^\fattachment{' ,
+ \ 'g:notmuch_show_attachment_end_regexp': '^\fattachment}' ,
+ \ 'g:notmuch_show_part_begin_regexp': '^\fpart{' ,
+ \ 'g:notmuch_show_part_end_regexp': '^\fpart}' ,
+ \ 'g:notmuch_show_marker_regexp': '^\f\\(message\\|header\\|body\\|attachment\\|part\\)[{}].*$',
+ \
+ \ 'g:notmuch_show_message_parse_regexp': '\(id:[^ ]*\) depth:\([0-9]*\) filename:\(.*\)$',
+ \ 'g:notmuch_show_tags_regexp': '(\([^)]*\))$' ,
+ \
+ \ 'g:notmuch_show_signature_regexp': '^\(-- \?\|_\+\)$' ,
+ \ 'g:notmuch_show_signature_lines_max': 12 ,
+ \
+ \ 'g:notmuch_show_citation_regexp': '^\s*>' ,
+ \ }
+
+" 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
+
+let g:notmuch_search_maps = {
+ \ '<Enter>': ':call <SID>NM_search_display()<CR>',
+ \ 's': ':call <SID>NM_cmd_search(split(input(''NotMuch Search:'')))<CR>',
+ \ }
+
+" --- implement search screen {{{1
function! s:NM_cmd_search(words)
let cmd = ['search']
call s:NM_newBuffer('search', join(disp, "\n"))
let b:nm_raw_lines = lines
- nnoremap <buffer> <Enter> :call <SID>NM_search_display()<CR>
- nnoremap <buffer> s :call <SID>NM_cmd_search(split(input('NotMuch Search:')))<CR>
+ call <SID>NM_set_map(g:notmuch_search_maps)
setlocal cursorline
setlocal nowrap
endfunction
endfunction
-" --- implement show screen
+" --- implement show screen {{{1
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")
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()
setlocal foldtext=NM_cmd_show_foldtext()
setlocal fillchars=
- setlocal foldcolumn=5
+ setlocal foldcolumn=6
- exec printf("nnoremap <buffer> q :b %d<CR>", bufnr)
+ exec printf("nnoremap <buffer> q :b %d<CR>", b:nm_prev_bufnr)
+ nnoremap <buffer> <C-N> :call <SID>NM_cmd_show_next()<CR>
+ nnoremap <buffer> c :call <SID>NM_cmd_show_fold_toggle('c', 'cit', !g:notmuch_show_fold_citations)<CR>
+ nnoremap <buffer> s :call <SID>NM_cmd_show_fold_toggle('s', 'sig', !g:notmuch_show_fold_signatures)<CR>
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 <SID>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 <buffer> %s :call <SID>NM_cmd_show_fold_toggle(''%s'', ''%s'', %d)<CR>', 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 }
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
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
+ if strlen(in_part)
+ let part_end = 0
+
+ if match(line, g:notmuch_show_part_end_regexp) != -1
+ let part_end = len(info['disp'])
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
+ endif
+
+ if in_part == 'text/plain'
+ if !part_end && mode_type == ''
+ if match(line, g:notmuch_show_signature_regexp) != -1
+ let mode_type = 'sig'
+ let mode_start = len(info['disp'])
+ 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, 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) ]
+ 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 = ''
+ 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,
+ \ printf('[ %d-line signature. Press "s" to show. ]', outlnum - mode_start) ]
+ let mode_type = ''
+ endif
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
+
+ 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 match(line, s:notmuch_show_body_end_regexp) != -1
+ if !has_key(msg,'body_start')
+ let msg['body_start'] = len(info['disp']) + 1
+ endif
+ 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
- let in_part = 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)
- 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
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
+ if match(line, g:notmuch_show_header_end_regexp) != -1
let msg['header'] = hdr
let in_header = 0
let hdr = {}
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
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'], '')
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
+ 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]
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])
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]
endfunction
-" --- helper functions
+" --- notmuch helper functions {{{1
function! s:NM_newBuffer(ft, content)
enew
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)
-" --- command handler
+" 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 <buffer> %s %s', key, code)
+ endfor
+endfunction
+
+" --- command handler {{{1
function! NotMuch(args)
if !strlen(a:args)
endfunction
-" --- glue
+" --- glue {{{1
command! -nargs=* -complete=customlist,CompleteNotMuch NotMuch call NotMuch(<q-args>)
cabbrev notmuch <c-r>=(getcmdtype()==':' && getcmdpos()==1 ? 'NotMuch' : 'notmuch')<CR>
-" --- hacks, only for development :)
+" --- hacks, only for development :) {{{1
nnoremap ,nmr :source ~/.vim/plugin/notmuch.vim<CR>:call NotMuch('')<CR>
+
+" vim: set ft=vim ts=8 sw=8 et foldmethod=marker :