]> git.notmuchmail.org Git - notmuch/blob - vim/notmuch.vim
vim: show first message of the thread
[notmuch] / vim / notmuch.vim
1 if exists("g:loaded_notmuch_rb")
2         finish
3 endif
4
5 if !has("ruby") || version < 700
6         finish
7 endif
8
9 let g:loaded_notmuch_rb = "yep"
10
11 let g:notmuch_rb_folders_maps = {
12         \ '<Enter>':    'folders_show_search()',
13         \ 's':          'folders_search_prompt()',
14         \ '=':          'folders_refresh()',
15         \ }
16
17 let g:notmuch_rb_search_maps = {
18         \ 'q':          'kill_this_buffer()',
19         \ '<Enter>':    'search_show_thread(1)',
20         \ '<Space>':    'search_show_thread(2)',
21         \ 'A':          'search_tag("-inbox -unread")',
22         \ 'I':          'search_tag("-unread")',
23         \ 't':          'search_tag("")',
24         \ 's':          'search_search_prompt()',
25         \ '=':          'search_refresh()',
26         \ '?':          'search_info()',
27         \ }
28
29 let g:notmuch_rb_show_maps = {
30         \ 'q':          'kill_this_buffer()',
31         \ 'A':          'show_tag("-inbox -unread")',
32         \ 'I':          'show_tag("-unread")',
33         \ 't':          'show_tag("")',
34         \ 'o':          'show_open_msg()',
35         \ 'e':          'show_extract_msg()',
36         \ 's':          'show_save_msg()',
37         \ 'r':          'show_reply()',
38         \ '?':          'show_info()',
39         \ '<Tab>':      'show_next_msg()',
40         \ }
41
42 let g:notmuch_rb_compose_maps = {
43         \ ',s':         'compose_send()',
44         \ ',q':         'compose_quit()',
45         \ }
46
47 let s:notmuch_rb_folders_default = [
48         \ [ 'new', 'tag:inbox and tag:unread' ],
49         \ [ 'inbox', 'tag:inbox' ],
50         \ [ 'unread', 'tag:unread' ],
51         \ ]
52
53 let s:notmuch_rb_date_format_default = '%d.%m.%y'
54 let s:notmuch_rb_datetime_format_default = '%d.%m.%y %H:%M:%S'
55 let s:notmuch_rb_reader_default = 'mutt -f %s'
56 let s:notmuch_rb_sendmail_default = 'sendmail'
57 let s:notmuch_rb_folders_count_threads_default = 0
58
59 if !exists('g:notmuch_rb_date_format')
60         let g:notmuch_rb_date_format = s:notmuch_rb_date_format_default
61 endif
62
63 if !exists('g:notmuch_rb_datetime_format')
64         let g:notmuch_rb_datetime_format = s:notmuch_rb_datetime_format_default
65 endif
66
67 if !exists('g:notmuch_rb_reader')
68         let g:notmuch_rb_reader = s:notmuch_rb_reader_default
69 endif
70
71 if !exists('g:notmuch_rb_sendmail')
72         let g:notmuch_rb_sendmail = s:notmuch_rb_sendmail_default
73 endif
74
75 if !exists('g:notmuch_rb_folders_count_threads')
76         let g:notmuch_rb_folders_count_threads = s:notmuch_rb_folders_count_threads_default
77 endif
78
79 function! s:new_file_buffer(type, fname)
80         exec printf('edit %s', a:fname)
81         execute printf('set filetype=notmuch-%s', a:type)
82         execute printf('set syntax=notmuch-%s', a:type)
83         ruby $curbuf.init(VIM::evaluate('a:type'))
84         ruby $buf_queue.push($curbuf.number)
85 endfunction
86
87 function! s:compose_unload()
88         if b:compose_done
89                 return
90         endif
91         if input('[s]end/[q]uit? ') =~ '^s'
92                 call s:compose_send()
93         endif
94 endfunction
95
96 "" actions
97
98 function! s:compose_quit()
99         let b:compose_done = 1
100         call s:kill_this_buffer()
101 endfunction
102
103 function! s:compose_send()
104         let b:compose_done = 1
105         let fname = expand('%')
106
107         " remove headers
108         0,4d
109         write
110
111         let cmdtxt = g:notmuch_sendmail . ' -t -f ' . s:reply_from . ' < ' . fname
112         let out = system(cmdtxt)
113         let err = v:shell_error
114         if err
115                 undo
116                 write
117                 echohl Error
118                 echo 'Eeek! unable to send mail'
119                 echo out
120                 echohl None
121                 return
122         endif
123         call delete(fname)
124         echo 'Mail sent successfully.'
125         call s:kill_this_buffer()
126 endfunction
127
128 function! s:show_next_msg()
129 ruby << EOF
130         r, c = $curwin.cursor
131         n = $curbuf.line_number
132         i = $messages.index { |m| n >= m.start && n <= m.end }
133         m = $messages[i + 1]
134         if m
135                 r = m.body_start + 1
136                 VIM::command("normal #{m.start}zt")
137                 $curwin.cursor = r, c
138         end
139 EOF
140 endfunction
141
142 function! s:show_reply()
143         ruby open_reply get_message.mail
144         let b:compose_done = 0
145         call s:set_map(g:notmuch_rb_compose_maps)
146         autocmd BufUnload <buffer> call s:compose_unload()
147         startinsert!
148 endfunction
149
150 function! s:show_info()
151         ruby vim_puts get_message.inspect
152 endfunction
153
154 function! s:show_extract_msg()
155 ruby << EOF
156         m = get_message
157         m.mail.attachments.each do |a|
158                 File.open(a.filename, 'w') do |f|
159                         f.write a.body.decoded
160                         print "Extracted '#{a.filename}'"
161                 end
162         end
163 EOF
164 endfunction
165
166 function! s:show_open_msg()
167 ruby << EOF
168         m = get_message
169         mbox = File.expand_path('~/.notmuch/vim_mbox')
170         cmd = VIM::evaluate('g:notmuch_rb_reader') % mbox
171         system "notmuch show --format=mbox id:#{m.message_id} > #{mbox} && #{cmd}"
172 EOF
173 endfunction
174
175 function! s:show_save_msg()
176         let file = input('File name: ')
177 ruby << EOF
178         file = VIM::evaluate('file')
179         m = get_message
180         system "notmuch show --format=mbox id:#{m.message_id} > #{file}"
181 EOF
182 endfunction
183
184 function! s:show_tag(intags)
185         if empty(a:intags)
186                 let tags = input('tags: ')
187         else
188                 let tags = a:intags
189         endif
190         ruby do_tag(get_cur_view, VIM::evaluate('l:tags'))
191         call s:show_next_thread()
192 endfunction
193
194 function! s:search_search_prompt()
195         let text = input('Search: ')
196         setlocal modifiable
197 ruby << EOF
198         $cur_search = VIM::evaluate('text')
199         $curbuf.reopen
200         search_render($cur_search)
201 EOF
202         setlocal nomodifiable
203 endfunction
204
205 function! s:search_info()
206         ruby vim_puts get_thread_id
207 endfunction
208
209 function! s:search_refresh()
210         setlocal modifiable
211         ruby $curbuf.reopen
212         ruby search_render($cur_search)
213         setlocal nomodifiable
214 endfunction
215
216 function! s:search_tag(intags)
217         if empty(a:intags)
218                 let tags = input('tags: ')
219         else
220                 let tags = a:intags
221         endif
222         ruby do_tag(get_thread_id, VIM::evaluate('l:tags'))
223         norm j
224 endfunction
225
226 function! s:folders_search_prompt()
227         let text = input('Search: ')
228         call s:search(text)
229 endfunction
230
231 function! s:folders_refresh()
232         setlocal modifiable
233         ruby $curbuf.reopen
234         ruby folders_render()
235         setlocal nomodifiable
236 endfunction
237
238 "" basic
239
240 function! s:show_cursor_moved()
241 ruby << EOF
242         if $render.is_ready?
243                 VIM::command('setlocal modifiable')
244                 $render.do_next
245                 VIM::command('setlocal nomodifiable')
246         end
247 EOF
248 endfunction
249
250 function! s:show_next_thread()
251         call s:kill_this_buffer()
252         if line('.') != line('$')
253                 norm j
254                 call s:search_show_thread(0)
255         else
256                 echo 'No more messages.'
257         endif
258 endfunction
259
260 function! s:kill_this_buffer()
261         ruby $curbuf.close
262         bdelete!
263 ruby << EOF
264         $buf_queue.pop
265         b = $buf_queue.last
266         VIM::command("buffer #{b}") if b
267 EOF
268 endfunction
269
270 function! s:set_map(maps)
271         nmapclear <buffer>
272         for [key, code] in items(a:maps)
273                 let cmd = printf(":call <SID>%s<CR>", code)
274                 exec printf('nnoremap <buffer> %s %s', key, cmd)
275         endfor
276 endfunction
277
278 function! s:new_buffer(type)
279         enew
280         setlocal buftype=nofile bufhidden=hide
281         keepjumps 0d
282         execute printf('set filetype=notmuch-%s', a:type)
283         execute printf('set syntax=notmuch-%s', a:type)
284         ruby $curbuf.init(VIM::evaluate('a:type'))
285         ruby $buf_queue.push($curbuf.number)
286 endfunction
287
288 function! s:set_menu_buffer()
289         setlocal nomodifiable
290         setlocal cursorline
291         setlocal nowrap
292 endfunction
293
294 "" main
295
296 function! s:show(thread_id)
297         call s:new_buffer('show')
298         setlocal modifiable
299 ruby << EOF
300         thread_id = VIM::evaluate('a:thread_id')
301         $cur_thread = thread_id
302         $messages.clear
303         $curbuf.render do |b|
304                 q = $curbuf.query(get_cur_view)
305                 q.sort = 0
306                 msgs = q.search_messages
307                 msgs.each do |msg|
308                         m = Mail.read(msg.filename)
309                         part = m.find_first_text
310                         nm_m = Message.new(msg, m)
311                         $messages << nm_m
312                         date_fmt = VIM::evaluate('g:notmuch_rb_datetime_format')
313                         date = Time.at(msg.date).strftime(date_fmt)
314                         nm_m.start = b.count
315                         b << "%s %s (%s)" % [msg['from'], date, msg.tags]
316                         b << "Subject: %s" % [msg['subject']]
317                         b << "To: %s" % msg['to']
318                         b << "Cc: %s" % msg['cc']
319                         b << "Date: %s" % msg['date']
320                         nm_m.body_start = b.count
321                         b << "--- %s ---" % part.mime_type
322                         part.convert.each_line do |l|
323                                 b << l.chomp
324                         end
325                         b << ""
326                         nm_m.end = b.count
327                 end
328                 b.delete(b.count)
329         end
330         $messages.each_with_index do |msg, i|
331                 VIM::command("syntax region nmShowMsg#{i}Desc start='\\%%%il' end='\\%%%il' contains=@nmShowMsgDesc" % [msg.start, msg.start + 1])
332                 VIM::command("syntax region nmShowMsg#{i}Head start='\\%%%il' end='\\%%%il' contains=@nmShowMsgHead" % [msg.start + 1, msg.body_start])
333                 VIM::command("syntax region nmShowMsg#{i}Body start='\\%%%il' end='\\%%%dl' contains=@nmShowMsgBody" % [msg.body_start, msg.end])
334         end
335 EOF
336         setlocal nomodifiable
337         call s:set_map(g:notmuch_rb_show_maps)
338 endfunction
339
340 function! s:search_show_thread(mode)
341 ruby << EOF
342         mode = VIM::evaluate('a:mode')
343         id = get_thread_id
344         case mode
345         when 0;
346         when 1; $cur_filter = nil
347         when 2; $cur_filter = $cur_search
348         end
349         VIM::command("call s:show('#{id}')")
350 EOF
351 endfunction
352
353 function! s:search(search)
354         call s:new_buffer('search')
355 ruby << EOF
356         $cur_search = VIM::evaluate('a:search')
357         search_render($cur_search)
358 EOF
359         call s:set_menu_buffer()
360         call s:set_map(g:notmuch_rb_search_maps)
361         autocmd CursorMoved <buffer> call s:show_cursor_moved()
362 endfunction
363
364 function! s:folders_show_search()
365 ruby << EOF
366         n = $curbuf.line_number
367         s = $searches[n - 1]
368         VIM::command("call s:search('#{s}')")
369 EOF
370 endfunction
371
372 function! s:folders()
373         call s:new_buffer('folders')
374         ruby folders_render()
375         call s:set_menu_buffer()
376         call s:set_map(g:notmuch_rb_folders_maps)
377 endfunction
378
379 "" root
380
381 function! s:set_defaults()
382         if exists('g:notmuch_rb_custom_search_maps')
383                 call extend(g:notmuch_rb_search_maps, g:notmuch_rb_custom_search_maps)
384         endif
385
386         if exists('g:notmuch_rb_custom_show_maps')
387                 call extend(g:notmuch_rb_show_maps, g:notmuch_rb_custom_show_maps)
388         endif
389
390         " TODO for now lets check the old folders too
391         if !exists('g:notmuch_rb_folders')
392                 if exists('g:notmuch_folders')
393                         let g:notmuch_rb_folders = g:notmuch_folders
394                 else
395                         let g:notmuch_rb_folders = s:notmuch_rb_folders_default
396                 endif
397         endif
398 endfunction
399
400 function! s:NotMuch()
401         call s:set_defaults()
402
403 ruby << EOF
404         require 'notmuch'
405         require 'rubygems'
406         require 'tempfile'
407         begin
408                 require 'mail'
409         rescue LoadError
410         end
411
412         $db_name = nil
413         $email_address = nil
414         $searches = []
415         $buf_queue = []
416         $threads = []
417         $messages = []
418         $config = {}
419         $mail_installed = defined?(Mail)
420
421         def get_config
422                 group = nil
423                 config = ENV['NOTMUCH_CONFIG'] || '~/.notmuch-config'
424                 File.open(File.expand_path(config)).each do |l|
425                         l.chomp!
426                         case l
427                         when /^\[(.*)\]$/
428                                 group = $1
429                         when ''
430                         when /^(.*)=(.*)$/
431                                 key = "%s.%s" % [group, $1]
432                                 value = $2
433                                 $config[key] = value
434                         end
435                 end
436
437                 $db_name = $config['database.path']
438                 $email_address = "%s <%s>" % [$config['user.name'], $config['user.primary_email']]
439         end
440
441         def vim_puts(s)
442                 VIM::command("echo '#{s.to_s}'")
443         end
444
445         def vim_p(s)
446                 VIM::command("echo '#{s.inspect}'")
447         end
448
449         def author_filter(a)
450                 # TODO email format, aliases
451                 a.strip!
452                 a.gsub!(/[\.@].*/, '')
453                 a.gsub!(/^ext /, '')
454                 a.gsub!(/ \(.*\)/, '')
455                 a
456         end
457
458         def get_thread_id
459                 n = $curbuf.line_number - 1
460                 return "thread:%s" % $threads[n]
461         end
462
463         def get_message
464                 n = $curbuf.line_number
465                 return $messages.find { |m| n >= m.start && n <= m.end }
466         end
467
468         def get_cur_view
469                 if $cur_filter
470                         return "#{$cur_thread} and (#{$cur_filter})"
471                 else
472                         return $cur_thread
473                 end
474         end
475
476         def open_reply(orig)
477                 help_lines = [
478                         'Notmuch-Help: Type in your message here; to help you use these bindings:',
479                         'Notmuch-Help:   ,s    - send the message (Notmuch-Help lines will be removed)',
480                         'Notmuch-Help:   ,q    - abort the message',
481                         ]
482                 reply = orig.reply do |m|
483                         # fix headers
484                         if not m[:reply_to]
485                                 m.to = [orig[:from].to_s, orig[:to].to_s]
486                         end
487                         m.cc = orig[:cc]
488                         m.from = $email_address
489                         m.charset = 'utf-8'
490                         m.content_transfer_encoding = '7bit'
491                 end
492
493                 dir = File.expand_path('~/.notmuch/compose')
494                 FileUtils.mkdir_p(dir)
495                 Tempfile.open(['nm-', '.mail'], dir) do |f|
496                         lines = []
497
498                         lines += help_lines
499                         lines << ''
500
501                         body_lines = []
502                         if $mail_installed
503                                 addr = Mail::Address.new(orig[:from].value)
504                                 name = addr.name
505                                 name = addr.local + "@" if name.nil? && !addr.local.nil?
506                         else
507                                 name = orig[:from]
508                         end
509                         name = "somebody" if name.nil?
510
511                         body_lines << "%s wrote:" % name
512                         part = orig.find_first_text
513                         part.convert.each_line do |l|
514                                 body_lines << "> %s" % l.chomp
515                         end
516                         body_lines << ""
517                         body_lines << ""
518                         body_lines << ""
519
520                         reply.body = body_lines.join("\n")
521
522                         lines += reply.to_s.lines.map { |e| e.chomp }
523                         lines << ""
524
525                         old_count = lines.count - 1
526
527                         f.puts(lines)
528
529                         sig_file = File.expand_path('~/.signature')
530                         if File.exists?(sig_file)
531                                 f.puts("-- ")
532                                 f.write(File.read(sig_file))
533                         end
534
535                         f.flush
536
537                         VIM::command("let s:reply_from='%s'" % reply.from.first.to_s)
538                         VIM::command("call s:new_file_buffer('compose', '#{f.path}')")
539                         VIM::command("call cursor(#{old_count}, 0)")
540                 end
541         end
542
543         def folders_render()
544                 $curbuf.render do |b|
545                         folders = VIM::evaluate('g:notmuch_rb_folders')
546                         count_threads = VIM::evaluate('g:notmuch_rb_folders_count_threads')
547                         $searches.clear
548                         folders.each do |name, search|
549                                 q = $curbuf.query(search)
550                                 $searches << search
551                                 count = count_threads ? q.search_threads.count : q.search_messages.count
552                                 b << "%9d %-20s (%s)" % [count, name, search]
553                         end
554                 end
555         end
556
557         def search_render(search)
558                 date_fmt = VIM::evaluate('g:notmuch_rb_date_format')
559                 q = $curbuf.query(search)
560                 q.sort = Notmuch::SORT_NEWEST_FIRST
561                 $threads.clear
562                 t = q.search_threads
563
564                 $render = $curbuf.render_staged(t) do |b, items|
565                         items.each do |e|
566                                 authors = e.authors.to_utf8.split(/[,|]/).map { |a| author_filter(a) }.join(",")
567                                 date = Time.at(e.newest_date).strftime(date_fmt)
568                                 subject = e.messages.first['subject']
569                                 if $mail_installed
570                                         subject = Mail::Field.new("Subject: " + subject).to_s
571                                 else
572                                         subject = subject.force_encoding('utf-8')
573                                 end
574                                 b << "%-12s %3s %-20.20s | %s (%s)" % [date, e.matched_messages, authors, subject, e.tags]
575                                 $threads << e.thread_id
576                         end
577                 end
578         end
579
580         def do_tag(filter, tags)
581                 $curbuf.do_write do |db|
582                         q = db.query(filter)
583                         q.search_messages.each do |e|
584                                 e.freeze
585                                 tags.split.each do |t|
586                                         case t
587                                         when /^-(.*)/
588                                                 e.remove_tag($1)
589                                         when /^\+(.*)/
590                                                 e.add_tag($1)
591                                         when /^([^\+^-].*)/
592                                                 e.add_tag($1)
593                                         end
594                                 end
595                                 e.thaw
596                                 e.tags_to_maildir_flags
597                         end
598                         q.destroy!
599                 end
600         end
601
602         module DbHelper
603                 def init(name)
604                         @name = name
605                         @db = Notmuch::Database.new($db_name)
606                         @queries = []
607                 end
608
609                 def query(*args)
610                         q = @db.query(*args)
611                         @queries << q
612                         q
613                 end
614
615                 def close
616                         @queries.delete_if { |q| ! q.destroy! }
617                         @db.close
618                 end
619
620                 def reopen
621                         close if @db
622                         @db = Notmuch::Database.new($db_name)
623                 end
624
625                 def do_write
626                         db = Notmuch::Database.new($db_name, :mode => Notmuch::MODE_READ_WRITE)
627                         begin
628                                 yield db
629                         ensure
630                                 db.close
631                         end
632                 end
633         end
634
635         class Message
636                 attr_accessor :start, :body_start, :end
637                 attr_reader :message_id, :filename, :mail
638
639                 def initialize(msg, mail)
640                         @message_id = msg.message_id
641                         @filename = msg.filename
642                         @mail = mail
643                         @start = 0
644                         @end = 0
645                         mail.import_headers(msg) if not $mail_installed
646                 end
647
648                 def to_s
649                         "id:%s" % @message_id
650                 end
651
652                 def inspect
653                         "id:%s, file:%s" % [@message_id, @filename]
654                 end
655         end
656
657         class StagedRender
658                 def initialize(buffer, enumerable, block)
659                         @b = buffer
660                         @enumerable = enumerable
661                         @block = block
662                         @last_render = 0
663
664                         @b.render { do_next }
665                 end
666
667                 def is_ready?
668                         @last_render - @b.line_number <= $curwin.height
669                 end
670
671                 def do_next
672                         items = @enumerable.take($curwin.height * 2)
673                         return if items.empty?
674                         @block.call @b, items
675                         @last_render = @b.count
676                 end
677         end
678
679         class VIM::Buffer
680                 include DbHelper
681
682                 def <<(a)
683                         append(count(), a)
684                 end
685
686                 def render_staged(enumerable, &block)
687                         StagedRender.new(self, enumerable, block)
688                 end
689
690                 def render
691                         old_count = count
692                         yield self
693                         (1..old_count).each do
694                                 delete(1)
695                         end
696                 end
697         end
698
699         class Notmuch::Tags
700                 def to_s
701                         to_a.join(" ")
702                 end
703         end
704
705         class Notmuch::Message
706                 def to_s
707                         "id:%s" % message_id
708                 end
709         end
710
711         # workaround for bug in vim's ruby
712         class Object
713                 def flush
714                 end
715         end
716
717         module SimpleMessage
718                 class Header < Array
719                         def self.parse(string)
720                                 return nil if string.empty?
721                                 return Header.new(string.split(/,\s+/))
722                         end
723
724                         def to_s
725                                 self.join(', ')
726                         end
727                 end
728
729                 def initialize(string = nil)
730                         @raw_source = string
731                         @body = nil
732                         @headers = {}
733
734                         return if not string
735
736                         if string =~ /(.*?(\r\n|\n))\2/m
737                                 head, body = $1, $' || '', $2
738                         else
739                                 head, body = string, ''
740                         end
741                         @body = body
742                 end
743
744                 def [](name)
745                         @headers[name.to_sym]
746                 end
747
748                 def []=(name, value)
749                         @headers[name.to_sym] = value
750                 end
751
752                 def format_header(value)
753                         value.to_s.tr('_', '-').gsub(/(\w+)/) { $1.capitalize }
754                 end
755
756                 def to_s
757                         buffer = ''
758                         @headers.each do |key, value|
759                                 buffer << "%s: %s\r\n" %
760                                         [format_header(key), value]
761                         end
762                         buffer << "\r\n"
763                         buffer << @body
764                         buffer
765                 end
766
767                 def body=(value)
768                         @body = value
769                 end
770
771                 def from
772                         @headers[:from]
773                 end
774
775                 def decoded
776                         @body
777                 end
778
779                 def mime_type
780                         'text/plain'
781                 end
782
783                 def multipart?
784                         false
785                 end
786
787                 def reply
788                         r = Mail::Message.new
789                         r[:from] = self[:to]
790                         r[:to] = self[:from]
791                         r[:cc] = self[:cc]
792                         r[:in_reply_to] = self[:message_id]
793                         r[:references] = self[:references]
794                         r
795                 end
796
797                 HEADERS = [ :from, :to, :cc, :references, :in_reply_to, :reply_to, :message_id ]
798
799                 def import_headers(m)
800                         HEADERS.each do |e|
801                                 dashed = format_header(e)
802                                 @headers[e] = Header.parse(m[dashed])
803                         end
804                 end
805         end
806
807         module Mail
808
809                 if not $mail_installed
810                         puts "WARNING: Install the 'mail' gem, without it support is limited"
811
812                         def self.read(filename)
813                                 Message.new(File.open(filename, 'rb') { |f| f.read })
814                         end
815
816                         class Message
817                                 include SimpleMessage
818                         end
819                 end
820
821                 class Message
822
823                         def find_first_text
824                                 return self if not multipart?
825                                 return text_part || html_part
826                         end
827
828                         def convert
829                                 if mime_type != "text/html"
830                                         text = decoded
831                                 else
832                                         IO.popen("elinks --dump", "w+") do |pipe|
833                                                 pipe.write(decode_body)
834                                                 pipe.close_write
835                                                 text = pipe.read
836                                         end
837                                 end
838                                 text
839                         end
840                 end
841         end
842
843         class String
844                 def to_utf8
845                         RUBY_VERSION >= "1.9" ? force_encoding('utf-8') : self
846                 end
847         end
848
849         get_config
850 EOF
851         call s:folders()
852 endfunction
853
854 command NotMuch :call s:NotMuch()
855
856 " vim: set noexpandtab: