Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Requery #1558

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open

Requery #1558

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion alot/buffers/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ def rebuild(self, reverse=False):

self.threadlist = IterableWalker(threads, ThreadlineWidget,
dbman=self.dbman,
reverse=reverse)
reverse=reverse,
querystring=self.querystring)

self.listbox = urwid.ListBox(self.threadlist)
self.body = self.listbox
Expand Down
67 changes: 52 additions & 15 deletions alot/commands/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from .globals import PromptCommand
from .globals import MoveCommand
from .globals import SaveQueryCommand as GlobalSaveQueryCommand
from .globals import SearchCommand
from .common import RetagPromptCommand
from .. import commands

Expand Down Expand Up @@ -97,73 +98,106 @@ async def apply(self, ui):
RetagPromptCommand = registerCommand(MODE, 'retagprompt')(RetagPromptCommand)


@registerCommand(
MODE, 'fullthreads', help='search for full threads')
class FullThreadCommand(Command):

"""search for full threads"""
async def apply(self, ui):
querystring = ui.current_buffer.querystring
if not querystring:
ui.notify('empty query string')
return
if ' ' in querystring:
querystring = '"{%s}"' % querystring # '{"%s"}' does not work!
else:
querystring = '{%s}' % querystring
cmd = SearchCommand(query=['thread:%s' % querystring])
await ui.apply_command(cmd)


@registerCommand(
MODE, 'tag', forced={'action': 'add'},
arguments=[
(['--no-flush'], {'action': 'store_false', 'dest': 'flush',
'default': 'True',
'help': 'postpone a writeout to the index'}),
(['--fullthread'], {'action': 'store_true', 'dest': 'fullthread',
'default': False,
'help': 'tag all messages in the selected thread'}),
(['--all'], {'action': 'store_true', 'dest': 'allmessages',
'default': False,
'help': 'tag all messages that match the current search query'}),
'default': False,
'help': 'tag all messages that match the current search query'}),
(['tags'], {'help': 'comma separated list of tags'})],
help='add tags to all messages in the selected thread',
help='add tags to all matched messages in the selected thread',
)
@registerCommand(
MODE, 'retag', forced={'action': 'set'},
arguments=[
(['--no-flush'], {'action': 'store_false', 'dest': 'flush',
'default': 'True',
'help': 'postpone a writeout to the index'}),
(['--fullthread'], {'action': 'store_true', 'dest': 'fullthread',
'default': False,
'help': 'retag all messages in the selected thread'}),
(['--all'], {'action': 'store_true', 'dest': 'allmessages',
'default': False,
'help': 'retag all messages that match the current query'}),
'default': False,
'help': 'retag all messages that match the current query'}),
(['tags'], {'help': 'comma separated list of tags'})],
help='set tags to all messages in the selected thread',
help='set tags to all matched messages in the selected thread',
)
@registerCommand(
MODE, 'untag', forced={'action': 'remove'},
arguments=[
(['--no-flush'], {'action': 'store_false', 'dest': 'flush',
'default': 'True',
'help': 'postpone a writeout to the index'}),
(['--fullthread'], {'action': 'store_true', 'dest': 'fullthread',
'default': False,
'help': 'untag all messages in the selected thread'}),
(['--all'], {'action': 'store_true', 'dest': 'allmessages',
'default': False,
'help': 'untag all messages that match the current query'}),
'default': False,
'help': 'untag all messages that match the current query'}),
(['tags'], {'help': 'comma separated list of tags'})],
help='remove tags from all messages in the selected thread',
help='remove tags from all matched messages in the selected thread',
)
@registerCommand(
MODE, 'toggletags', forced={'action': 'toggle'},
arguments=[
(['--no-flush'], {'action': 'store_false', 'dest': 'flush',
'default': 'True',
'help': 'postpone a writeout to the index'}),
(['--fullthread'], {'action': 'store_true', 'dest': 'fullthread',
'default': False,
'help': 'toggle tags of all messages in the selected thread'}),
(['tags'], {'help': 'comma separated list of tags'})],
help='flip presence of tags on the selected thread: a tag is considered present '
'and will be removed if at least one message in this thread is '
help='flip presence of tags on the matched messages in the selected thread: a tag is considered present '
'and will be removed if at least one matched message in this thread is '
'tagged with it')
class TagCommand(Command):

"""manipulate message tags"""
repeatable = True

def __init__(self, tags='', action='add', allmessages=False, flush=True,
**kwargs):
def __init__(self, tags='', action='add', fullthread=False,
allmessages=False, flush=True, **kwargs):
"""
:param tags: comma separated list of tagstrings to set
:type tags: str
:param action: adds tags if 'add', removes them if 'remove', adds tags
and removes all other if 'set' or toggle individually if
'toggle'
:type action: str
:param fullthread: tag all messages in search result (instead of just matched ones)
:type fullthread: bool
:param allmessages: tag all messages in search result
:type allmessages: bool
:param flush: immediately write out to the index
:type flush: bool
"""
self.tagsstring = tags
self.action = action
self.fullthread = fullthread
self.allm = allmessages
self.flush = flush
Command.__init__(self, **kwargs)
Expand All @@ -179,8 +213,11 @@ async def apply(self, ui):
testquery = searchbuffer.querystring
thread = threadline_widget.get_thread()
if not self.allm:
testquery = "(%s) AND thread:%s" % (testquery,
thread.get_thread_id())
if self.fullthread:
testquery = "thread:%s" % thread.get_thread_id()
else:
testquery = "(%s) AND thread:%s" % (testquery,
thread.get_thread_id())
logging.debug('all? %s', self.allm)
logging.debug('q: %s', testquery)

Expand Down
8 changes: 8 additions & 0 deletions alot/commands/thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -1081,6 +1081,8 @@ async def apply(self, ui):
arguments=[
(['--all'], {'action': 'store_true',
'help': 'tag all messages in thread'}),
(['--fullthread'], {'action': 'store_true', 'dest': 'all',
'help': 'synonymous to `--all`'}),
(['--no-flush'], {'action': 'store_false', 'dest': 'flush',
'help': 'postpone a writeout to the index'}),
(['tags'], {'help': 'comma separated list of tags'})],
Expand All @@ -1091,6 +1093,8 @@ async def apply(self, ui):
arguments=[
(['--all'], {'action': 'store_true',
'help': 'tag all messages in thread'}),
(['--fullthread'], {'action': 'store_true', 'dest': 'all',
'help': 'synonymous to `--all`'}),
(['--no-flush'], {'action': 'store_false', 'dest': 'flush',
'help': 'postpone a writeout to the index'}),
(['tags'], {'help': 'comma separated list of tags'})],
Expand All @@ -1101,6 +1105,8 @@ async def apply(self, ui):
arguments=[
(['--all'], {'action': 'store_true',
'help': 'tag all messages in thread'}),
(['--fullthread'], {'action': 'store_true', 'dest': 'all',
'help': 'synonymous to `--all`'}),
(['--no-flush'], {'action': 'store_false', 'dest': 'flush',
'help': 'postpone a writeout to the index'}),
(['tags'], {'help': 'comma separated list of tags'})],
Expand All @@ -1111,6 +1117,8 @@ async def apply(self, ui):
arguments=[
(['--all'], {'action': 'store_true',
'help': 'tag all messages in thread'}),
(['--fullthread'], {'action': 'store_true', 'dest': 'all',
'help': 'synonymous to `--all`'}),
(['--no-flush'], {'action': 'store_false', 'dest': 'flush',
'help': 'postpone a writeout to the index'}),
(['tags'], {'help': 'comma separated list of tags'})],
Expand Down
12 changes: 8 additions & 4 deletions alot/db/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,18 +245,22 @@ def count_threads(self, querystring):
exclude_tags=settings.get('exclude_tags'))

@contextlib.contextmanager
def _with_notmuch_thread(self, tid):
def _with_notmuch_thread(self, tid, querystring=None):
"""returns :class:`notmuch2.Thread` with given id"""
if querystring:
query = 'thread:' + tid + ' AND (' + querystring + ')'
else:
query = 'thread:' + tid
with Database(path=self.path, mode=Database.MODE.READ_ONLY) as db:
try:
yield next(db.threads('thread:' + tid))
yield next(db.threads(query))
except NotmuchError:
errmsg = 'no thread with id %s exists!' % tid
raise NonexistantObjectError(errmsg)

def get_thread(self, tid):
def get_thread(self, tid, querystring=None):
"""returns :class:`Thread` with given thread id (str)"""
with self._with_notmuch_thread(tid) as thread:
with self._with_notmuch_thread(tid, querystring) as thread:
return Thread(self, thread)

@contextlib.contextmanager
Expand Down
10 changes: 8 additions & 2 deletions alot/db/thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class Thread:
directly provide contained messages as :class:`~alot.db.message.Message`.
"""

def __init__(self, dbman, thread):
def __init__(self, dbman, thread, querystring=None):
"""
:param dbman: db manager that is used for further lookups
:type dbman: :class:`~alot.db.DBManager`
Expand All @@ -26,21 +26,23 @@ def __init__(self, dbman, thread):
self._authors = None
self._id = thread.threadid
self._messages = {}
self._querystring = querystring
self._tags = set()

self.refresh(thread)

def refresh(self, thread=None):
"""refresh thread metadata from the index"""
if not thread:
with self._dbman._with_notmuch_thread(self._id) as thread:
with self._dbman._with_notmuch_thread(self._id, self._querystring) as thread:
self._refresh(thread)
else:
self._refresh(thread)

def _refresh(self, thread):
self._total_messages = len(thread)
self._notmuch_authors_string = thread.authors
self._matched_messages = thread.matched

subject_type = settings.get('thread_subject')
if subject_type == 'notmuch':
Expand Down Expand Up @@ -282,6 +284,10 @@ def get_total_messages(self):
"""returns number of contained messages"""
return self._total_messages

def get_matched_messages(self):
"""returns number of contained messages"""
return self._matched_messages

def matches(self, query):
"""
Check if this thread matches the given notmuch query.
Expand Down
8 changes: 4 additions & 4 deletions alot/defaults/default.bindings
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ q = exit

[search]
enter = select
a = toggletags inbox
& = toggletags killed
! = toggletags flagged
s = toggletags unread
a = toggletags --fullthread inbox
& = toggletags --fullthread killed
! = toggletags --fullthread flagged
s = toggletags --fullthread unread
l = retagprompt
O = refineprompt
| = refineprompt
Expand Down
2 changes: 1 addition & 1 deletion alot/defaults/default.theme
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
[[[mailcount]]]
normal = 'default','','light gray','default','g66','default'
focus = 'standout','','yellow','light gray','yellow','g58'
width = 'fit', 5,5
width = 'fit', 9,9
[[[tags]]]
normal = 'bold','','dark cyan','','dark cyan',''
focus = 'standout','','yellow','light gray','yellow','g58'
Expand Down
8 changes: 5 additions & 3 deletions alot/widgets/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,21 @@ class ThreadlineWidget(urwid.AttrMap):
selectable line widget that represents a :class:`~alot.db.Thread`
in the :class:`~alot.buffers.SearchBuffer`.
"""
def __init__(self, tid, dbman):

def __init__(self, tid, dbman, querystring=None):
self.dbman = dbman
self.tid = tid
self.thread = None # will be set by refresh()
self.tag_widgets = []
self.structure = None
self.querystring = querystring
self.rebuild()
normal = self.structure['normal']
focussed = self.structure['focus']
urwid.AttrMap.__init__(self, self.columns, normal, focussed)

def rebuild(self):
self.thread = self.dbman.get_thread(self.tid)
self.thread = self.dbman.get_thread(self.tid, self.querystring)
self.widgets = []
self.structure = settings.get_threadline_theming(self.thread)

Expand Down Expand Up @@ -170,7 +172,7 @@ def prepare_date_string(thread):


def prepare_mailcount_string(thread):
return "(%d)" % thread.get_total_messages()
return "(%d/%d)" % (thread.get_matched_messages(), thread.get_total_messages())


def prepare_authors_string(thread):
Expand Down