From a64a9b3219d0fd9241c6fcb6960f013588950571 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Thu, 4 Feb 2021 17:09:19 +0100 Subject: commands/thread: add --thread option to tagging commands Makes the command affect the whole thread, rather than just those messages matching the query. --- alot/commands/search.py | 119 ++++++++++++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 54 deletions(-) diff --git a/alot/commands/search.py b/alot/commands/search.py index 82a3cf39..9e4a3688 100644 --- a/alot/commands/search.py +++ b/alot/commands/search.py @@ -88,38 +88,42 @@ class RefinePromptCommand(Command): RetagPromptCommand = registerCommand(MODE, 'retagprompt')(RetagPromptCommand) +_tag_help_common = 'By default, this command applies only to the currently ' \ + 'focused thread, and furthermore only to those messages in the thread ' \ + 'that match the search query. This behaviour may be changed by the --all ' \ + 'and --thread options.' + +_tag_opt_all = (['--all'], + {'action' : 'store_true', + 'dest' : 'all_threads', + 'default' : False, + 'help' : 'apply to all threads rather than only the focused one'}) +_tag_opt_thread = (['--thread'], + {'action' : 'store_true', + 'dest' : 'thread', + 'default' : False, + 'help' : 'apply to all messages in the thread rather than only those' + 'matching the query'}) +_tag_opt_tags = (['tags'], {'help': 'comma separated list of tags'}) @registerCommand( MODE, 'tag', forced={'action': 'add'}, - arguments=[ - (['--all'], {'action': 'store_true', 'dest': 'allmessages', - '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', + arguments = [ _tag_opt_all, _tag_opt_thread, _tag_opt_tags ], + help = 'Add tags to messages. ' + _tag_help_common, ) @registerCommand( MODE, 'retag', forced={'action': 'set'}, - arguments=[ - (['--all'], {'action': 'store_true', 'dest': 'allmessages', - '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', + arguments = [ _tag_opt_all, _tag_opt_thread, _tag_opt_tags ], + help = 'Set tags to messages. ' + _tag_help_common, ) @registerCommand( MODE, 'untag', forced={'action': 'remove'}, - arguments=[ - (['--all'], {'action': 'store_true', 'dest': 'allmessages', - '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', + arguments = [ _tag_opt_all, _tag_opt_thread, _tag_opt_tags ], + help = 'Remove tags from messages. ' + _tag_help_common, ) @registerCommand( MODE, 'toggletags', forced={'action': 'toggle'}, - arguments=[ - (['tags'], {'help': 'comma separated list of tags'})], + arguments = [ _tag_opt_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 ' 'tagged with it') @@ -128,7 +132,13 @@ class TagCommand(Command): """manipulate message tags""" repeatable = True - def __init__(self, tags='', action='add', allmessages=False, **kwargs): + _tags = None + _action = None + _all_threads = None + _thread = None + + def __init__(self, tags = '', action = 'add', all_threads = False, + thread = False, **kwargs): """ :param tags: comma separated list of tagstrings to set :type tags: str @@ -136,12 +146,12 @@ class TagCommand(Command): and removes all other if 'set' or toggle individually if 'toggle' :type action: str - :param allmessages: tag all messages in search result - :type allmessages: bool """ - self.tagsstring = tags - self.action = action - self.allm = allmessages + self._tags = frozenset(filter(None, tags.split(','))) + self._action = action + self._all_threads = all_threads + self._thread = thread + super().__init__(**kwargs) async def apply(self, ui): @@ -152,38 +162,31 @@ class TagCommand(Command): if threadline_widget is None: return - testquery = searchbuffer.querystring - thread = threadline_widget.get_thread() - if not self.allm: - testquery = "(%s) AND thread:%s" % (testquery, thread.id) - logging.debug('all? %s', self.allm) - logging.debug('q: %s', testquery) - - def refresh(): - # update total result count - if not self.allm: - threadline_widget.rebuild() - searchbuffer.result_count = searchbuffer.dbman.count_messages( - searchbuffer.querystring) - else: - searchbuffer.rebuild() - - ui.update() + if self._all_threads: + if self._thread: + ui.notify('--all with --thread is not supported yet', + priority = 'error') + return + testquery = searchbuffer.querystring + else: + thread = threadline_widget.get_thread() + testquery = 'thread:' + thread.id - tags = frozenset(filter(None, self.tagsstring.split(','))) + if not self._thread: + testquery += ' and (%s)' % searchbuffer.querystring try: - if self.action == 'add': - await ui.dbman.tags_add(testquery, tags) - if self.action == 'set': - await ui.dbman.tags_set(testquery, tags) - elif self.action == 'remove': - await ui.dbman.tags_remove(testquery, tags) - elif self.action == 'toggle': - if not self.allm: + if self._action == 'add': + await ui.dbman.tags_add(testquery, self._tags) + if self._action == 'set': + await ui.dbman.tags_set(testquery, self._tags) + elif self._action == 'remove': + await ui.dbman.tags_remove(testquery, self._tags) + elif self._action == 'toggle': + if not self._all_threads: to_remove = set() to_add = set() - for t in tags: + for t in self._tags: if t in thread.get_tags(): to_remove.add(t) else: @@ -194,7 +197,15 @@ class TagCommand(Command): ui.notify('index in read-only mode', priority='error') return - refresh() + # update total result count + if not self._all_threads: + threadline_widget.rebuild() + searchbuffer.result_count = searchbuffer.dbman.count_messages( + searchbuffer.querystring) + else: + searchbuffer.rebuild() + + ui.update() @registerCommand( MODE, 'move', help='move focus in search buffer', -- cgit v1.2.3