summaryrefslogtreecommitdiff
path: root/alot
diff options
context:
space:
mode:
authorPatrick Totzke <patricktotzke@gmail.com>2016-12-15 22:05:30 +0000
committerGitHub <noreply@github.com>2016-12-15 22:05:30 +0000
commitac5e05a515aa6a3b27ed23ce89840b15b900ce33 (patch)
tree4eb940772d132f378ca81ec235227554817d5386 /alot
parentd633feddaf77c171aafe1586a6306c4ba67d29d6 (diff)
parent72baf0229ffdebfe2fcd71c82301885fda89db8b (diff)
Merge pull request #885 from lucc/history
Save command line history across sessions
Diffstat (limited to 'alot')
-rw-r--r--alot/commands/globals.py12
-rw-r--r--alot/commands/thread.py3
-rw-r--r--alot/defaults/alot.rc.spec6
-rw-r--r--alot/ui.py81
4 files changed, 97 insertions, 5 deletions
diff --git a/alot/commands/globals.py b/alot/commands/globals.py
index 437b3644..d2d0285c 100644
--- a/alot/commands/globals.py
+++ b/alot/commands/globals.py
@@ -52,6 +52,7 @@ class ExitCommand(Command):
for b in ui.buffers:
b.cleanup()
ui.apply_command(FlushCommand(callback=ui.exit))
+ ui.cleanup()
if ui.db_was_locked:
msg = 'Database locked. Exit without saving?'
@@ -765,10 +766,11 @@ class ComposeCommand(Command):
else:
cmpl = AccountCompleter()
fromaddress = yield ui.prompt('From', completer=cmpl,
- tab=1)
+ tab=1, history=ui.senderhistory)
if fromaddress is None:
raise CommandCanceled()
+ ui.senderhistory.append(fromaddress)
self.envelope.add('From', fromaddress)
# find out the right account
@@ -820,12 +822,14 @@ class ComposeCommand(Command):
append_remaining=allbooks)
logging.debug(abooks)
completer = ContactsCompleter(abooks)
- to = yield ui.prompt('To',
- completer=completer)
+ to = yield ui.prompt('To', completer=completer,
+ history=ui.recipienthistory)
if to is None:
raise CommandCanceled()
- self.envelope.add('To', to.strip(' \t\n,'))
+ to = to.strip(' \t\n,')
+ ui.recipienthistory.append(to)
+ self.envelope.add('To', to)
if settings.get('ask_subject') and \
'Subject' not in self.envelope.headers:
diff --git a/alot/commands/thread.py b/alot/commands/thread.py
index 00ac3f45..4b2221de 100644
--- a/alot/commands/thread.py
+++ b/alot/commands/thread.py
@@ -436,7 +436,8 @@ class BounceMailCommand(Command):
completer = ContactsCompleter(abooks)
else:
completer = None
- to = yield ui.prompt('To', completer=completer)
+ to = yield ui.prompt('To', completer=completer,
+ history=ui.recipienthistory)
if to is None:
raise CommandCanceled()
diff --git a/alot/defaults/alot.rc.spec b/alot/defaults/alot.rc.spec
index 0bc4f9d9..d99a96e8 100644
--- a/alot/defaults/alot.rc.spec
+++ b/alot/defaults/alot.rc.spec
@@ -239,6 +239,12 @@ msg_summary_hides_threadwide_tags = boolean(default=True)
# first in the account block is used.
reply_account_header_priority = force_list(default=list(From,To,Cc,Envelope-To,X-Envelope-To,Delivered-To))
+# The number of command line history entries to save
+#
+# .. note:: You can set this to -1 to save *all* entries to disk but the
+# history file might get *very* long.
+history_size = integer(default=50)
+
# Key bindings
[bindings]
__many__ = string(default=None)
diff --git a/alot/ui.py b/alot/ui.py
index 09fc27cc..3a840082 100644
--- a/alot/ui.py
+++ b/alot/ui.py
@@ -2,7 +2,9 @@
# This file is released under the GNU GPL, version 3 or a later revision.
# For further details see the COPYING file
import logging
+import os
import signal
+
from twisted.internet import reactor, defer
import urwid
@@ -46,6 +48,10 @@ class UI(object):
"""interface mode identifier - type of current buffer"""
self.commandprompthistory = []
"""history of the command line prompt"""
+ self.senderhistory = []
+ """history of the sender prompt"""
+ self.recipienthistory = []
+ """history of the recipients prompt"""
self.input_queue = []
"""stores partial keyboard input"""
self.last_commandline = None
@@ -73,6 +79,21 @@ class UI(object):
signal.signal(signal.SIGINT, self.handle_signal)
signal.signal(signal.SIGUSR1, self.handle_signal)
+ # load histories
+ self._cache = os.path.join(
+ os.environ.get('XDG_CACHE_HOME', os.path.expanduser('~/.cache')),
+ 'alot', 'history')
+ self._cmd_hist_file = os.path.join(self._cache, 'commands')
+ self._sender_hist_file = os.path.join(self._cache, 'senders')
+ self._recipients_hist_file = os.path.join(self._cache, 'recipients')
+ size = settings.get('history_size')
+ self.commandprompthistory = self._load_history_from_file(
+ self._cmd_hist_file, size=size)
+ self.senderhistory = self._load_history_from_file(
+ self._sender_hist_file, size=size)
+ self.recipienthistory = self._load_history_from_file(
+ self._recipients_hist_file, size=size)
+
# set up main loop
self.mainloop = urwid.MainLoop(self.root_widget,
handle_mouse=False,
@@ -663,3 +684,63 @@ class UI(object):
if isinstance(self.current_buffer, SearchBuffer):
self.current_buffer.rebuild()
self.update()
+
+ def cleanup(self):
+ """Do the final clean up before shutting down."""
+ size = settings.get('history_size')
+ self._save_history_to_file(self.commandprompthistory,
+ self._cmd_hist_file, size=size)
+ self._save_history_to_file(self.senderhistory, self._sender_hist_file,
+ size=size)
+ self._save_history_to_file(self.recipienthistory,
+ self._recipients_hist_file, size=size)
+
+ @staticmethod
+ def _load_history_from_file(path, size=-1):
+ """Load a history list from a file and split it into lines.
+
+ :param path: the path to the file that should be loaded
+ :type path: str
+ :param size: the number of lines to load (0 means no lines, < 0 means
+ all lines)
+ :type size: int
+ :returns: a list of history items (the lines of the file)
+ :rtype: list(str)
+ """
+ if size == 0:
+ return []
+ if os.path.exists(path):
+ with open(path) as histfile:
+ lines = [line.rstrip('\n') for line in histfile]
+ if size > 0:
+ lines = lines[-size:]
+ return lines
+ else:
+ return []
+
+ @staticmethod
+ def _save_history_to_file(history, path, size=-1):
+ """Save a history list to a file for later loading (possibly in another
+ session).
+
+ :param history: the history list to save
+ :type history: list(str)
+ :param path: the path to the file where to save the history
+ :param size: the number of lines to save (0 means no lines, < 0 means
+ all lines)
+ :type size: int
+ :type path: str
+ :returns: None
+ """
+ if size == 0:
+ return
+ if size > 0:
+ history = history[-size:]
+ directory = os.path.dirname(path)
+ if not os.path.exists(directory):
+ os.makedirs(directory)
+ # Write linewise to avoid building a large string in menory.
+ with open(path, 'w') as histfile:
+ for line in history:
+ histfile.write(line)
+ histfile.write('\n')