1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
# Copyright (C) 2011-2018 Patrick Totzke <patricktotzke@gmail.com>
# This file is released under the GNU GPL, version 3 or a later revision.
# For further details see the COPYING file
import urwid
from notmuch import NotmuchError
from .buffer import Buffer
from ..settings.const import settings
from ..walker import PipeWalker
from ..widgets.search import ThreadlineWidget
class SearchBuffer(Buffer):
"""shows a result list of threads for a query"""
modename = 'search'
threads = []
_REVERSE = {'oldest_first': 'newest_first',
'newest_first': 'oldest_first'}
def __init__(self, ui, initialquery='', sort_order=None):
self.dbman = ui.dbman
self.ui = ui
self.querystring = initialquery
default_order = settings.get('search_threads_sort_order')
self.sort_order = sort_order or default_order
self.result_count = 0
self.isinitialized = False
self.proc = None # process that fills our pipe
self.rebuild()
Buffer.__init__(self, ui, self.body)
def __str__(self):
formatstring = '[search] for "%s" (%d message%s)'
return formatstring % (self.querystring, self.result_count,
's' if self.result_count > 1 else '')
def get_info(self):
info = {}
info['querystring'] = self.querystring
info['result_count'] = self.result_count
info['result_count_positive'] = 's' if self.result_count > 1 else ''
return info
def cleanup(self):
self.kill_filler_process()
def kill_filler_process(self):
"""
terminates the process that fills this buffers
:class:`~alot.walker.PipeWalker`.
"""
if self.proc:
if self.proc.is_alive():
self.proc.terminate()
def rebuild(self, reverse=False):
self.isinitialized = True
self.reversed = reverse
self.kill_filler_process()
if reverse:
order = self._REVERSE[self.sort_order]
else:
order = self.sort_order
exclude_tags = settings.get_notmuch_setting('search', 'exclude_tags')
if exclude_tags:
exclude_tags = [t for t in exclude_tags.split(';') if t]
try:
self.result_count = self.dbman.count_messages(self.querystring)
self.pipe, self.proc = self.dbman.get_threads(self.querystring,
order,
exclude_tags)
except NotmuchError:
self.ui.notify('malformed query string: %s' % self.querystring,
'error')
self.listbox = urwid.ListBox([])
self.body = self.listbox
return
self.threadlist = PipeWalker(self.pipe, ThreadlineWidget,
dbman=self.dbman,
reverse=reverse)
self.listbox = urwid.ListBox(self.threadlist)
self.body = self.listbox
def get_selected_threadline(self):
"""
returns curently focussed :class:`alot.widgets.ThreadlineWidget`
from the result list.
"""
threadlinewidget, _ = self.threadlist.get_focus()
return threadlinewidget
def get_selected_thread(self):
"""returns currently selected :class:`~alot.db.Thread`"""
threadlinewidget = self.get_selected_threadline()
thread = None
if threadlinewidget:
thread = threadlinewidget.get_thread()
return thread
def consume_pipe(self):
while not self.threadlist.empty:
self.threadlist._get_next_item()
def focus_first(self):
if not self.reversed:
self.body.set_focus(0)
else:
self.rebuild(reverse=False)
def focus_last(self):
if self.reversed:
self.body.set_focus(0)
elif self.result_count < 200 or self.sort_order not in self._REVERSE:
self.consume_pipe()
num_lines = len(self.threadlist.get_lines())
self.body.set_focus(num_lines - 1)
else:
self.rebuild(reverse=True)
|