Skip to content

Commit

Permalink
Don't lose the focus when refreshing a thread
Browse files Browse the repository at this point in the history
This commit allows keeping the currently focused message selected
across thread refreshes.

Since this operation can take a long time in large threads, a
`search_threads_rebuild_limit` option is introduced. When defined,
it sets the maximum amount of messages that will be iterated upon
when trying to find the previously focused message.
  • Loading branch information
lenormf authored and pazz committed May 10, 2020
1 parent 3ea8478 commit 8e96d50
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 0 deletions.
28 changes: 28 additions & 0 deletions alot/buffers/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ def __init__(self, ui, initialquery='', sort_order=None):
default_order = settings.get('search_threads_sort_order')
self.sort_order = sort_order or default_order
self.result_count = 0
self.search_threads_rebuild_limit = \
settings.get('search_threads_rebuild_limit')
self.isinitialized = False
self.threadlist = None
self.rebuild()
Buffer.__init__(self, ui, self.body)

Expand All @@ -44,12 +47,16 @@ def get_info(self):
def rebuild(self, reverse=False):
self.isinitialized = True
self.reversed = reverse
selected_thread = None

if reverse:
order = self._REVERSE[self.sort_order]
else:
order = self.sort_order

if self.threadlist:
selected_thread = self.get_selected_thread()

exclude_tags = settings.get_notmuch_setting('search', 'exclude_tags')
if exclude_tags:
exclude_tags = [t for t in exclude_tags.split(';') if t]
Expand All @@ -72,6 +79,9 @@ def rebuild(self, reverse=False):
self.listbox = urwid.ListBox(self.threadlist)
self.body = self.listbox

if selected_thread:
self.focus_thread(selected_thread)

def get_selected_threadline(self):
"""
returns curently focussed :class:`alot.widgets.ThreadlineWidget`
Expand All @@ -92,6 +102,14 @@ def consume_pipe(self):
while not self.threadlist.empty:
self.threadlist._get_next_item()

def consume_pipe_until(self, predicate, limit=0):
n = limit
while not limit or n > 0:
if self.threadlist.empty \
or predicate(self.threadlist._get_next_item()):
break
n -= 1

def focus_first(self):
if not self.reversed:
self.body.set_focus(0)
Expand All @@ -108,3 +126,13 @@ def focus_last(self):
else:
self.rebuild(reverse=True)

def focus_thread(self, thread):
tid = thread.get_thread_id()
self.consume_pipe_until(lambda w:
w and w.get_thread().get_thread_id() == tid,
self.search_threads_rebuild_limit)

for pos, threadlinewidget in enumerate(self.threadlist.get_lines()):
if threadlinewidget.get_thread().get_thread_id() == tid:
self.body.set_focus(pos)
break
4 changes: 4 additions & 0 deletions alot/defaults/alot.rc.spec
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ initial_command = string(default='search tag:inbox AND NOT tag:killed')
# default sort order of results in a search
search_threads_sort_order = option('oldest_first', 'newest_first', 'message_id', 'unsorted', default='newest_first')

# maximum amount of threads that will be consumed to try to restore the focus, upon triggering a search buffer rebuild
# when set to 0, no limit is set (can be very slow in searches that yield thousands of results)
search_threads_rebuild_limit = integer(default=0)

# in case more than one account has an address book:
# Set this to True to make tab completion for recipients during compose only
# look in the abook of the account matching the sender address
Expand Down
11 changes: 11 additions & 0 deletions docs/source/configuration/alotrc_table
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,17 @@
:default: [{buffer_no}: search] for "{querystring}", {input_queue} {result_count} of {total_messages} messages


.. _search-threads-rebuild-limit:

.. describe:: search_threads_rebuild_limit

maximum amount of threads that will be consumed to try to restore the focus, upon triggering a search buffer rebuild
when set to 0, no limit is set (can be very slow in searches that yield thousands of results)

:type: integer
:default: 0


.. _search-threads-sort-order:

.. describe:: search_threads_sort_order
Expand Down

0 comments on commit 8e96d50

Please sign in to comment.