From a410d56a7894d5818f58564f33c2c8281c0d45fb Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 15 Apr 2014 18:02:07 +0200 Subject: [PATCH] Implement command history --- qutebrowser/app.py | 5 +++ qutebrowser/config/config.py | 73 +++++++++++++++++++++++++++++++- qutebrowser/config/configdata.py | 5 +++ qutebrowser/widgets/statusbar.py | 6 ++- 4 files changed, 86 insertions(+), 3 deletions(-) diff --git a/qutebrowser/app.py b/qutebrowser/app.py index beedd31b9..26dea4637 100644 --- a/qutebrowser/app.py +++ b/qutebrowser/app.py @@ -136,6 +136,7 @@ class QuteBrowser(QApplication): self.config.changed.connect( self.mainwindow.completion.on_config_changed) self.config.changed.connect(self.mainwindow.on_config_changed) + self.config.changed.connect(config.cmd_history.on_config_changed) self.mainwindow.show() self._python_hacks() @@ -379,6 +380,10 @@ class QuteBrowser(QApplication): config.config.save() except AttributeError: logging.exception("Could not save config.") + try: + config.cmd_history.save() + except AttributeError: + logging.exception("Could not save command history.") try: self._save_geometry() config.state.save() diff --git a/qutebrowser/config/config.py b/qutebrowser/config/config.py index 55a4c19c5..0fb3fe450 100644 --- a/qutebrowser/config/config.py +++ b/qutebrowser/config/config.py @@ -30,7 +30,7 @@ import configparser from configparser import ConfigParser, ExtendedInterpolation from collections.abc import MutableMapping -from PyQt5.QtCore import pyqtSignal, QObject +from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject #from qutebrowser.utils.misc import read_file import qutebrowser.config.configdata as configdata @@ -40,6 +40,7 @@ from qutebrowser.config.conftypes import ValidationError config = None state = None +cmd_history = None class NoSectionError(configparser.NoSectionError): @@ -62,12 +63,14 @@ def init(configdir): Args: configdir: The directory where the configs are stored in. """ - global config, state + global config, state, cmd_history logging.debug("Config init, configdir {}".format(configdir)) #config = Config(configdir, 'qutebrowser.conf', # read_file('qutebrowser.conf')) config = Config(configdir, 'qutebrowser.conf') state = ReadWriteConfigParser(configdir, 'state') + cmd_history = LineConfigParser(configdir, 'cmd_history', + ('general', 'cmd_histlen')) class Config(QObject): @@ -400,6 +403,72 @@ class ReadWriteConfigParser(ReadConfigParser): self.write(f) +class LineConfigParser: + + """Parser for configuration files which are simply line-based. + + Attributes: + data: A list of lines. + _configdir: The directory to read the config from. + _configfile: The config file path. + """ + + def __init__(self, configdir, fname, limit=None): + """Config constructor. + + Args: + configdir: Directory to read the config from. + fname: Filename of the config file. + limit: Config tuple (section, option) which contains a limit. + """ + self._configdir = configdir + self._configfile = os.path.join(self._configdir, fname) + self._limit = limit + self.data = None + if not os.path.isfile(self._configfile): + return + logging.debug("Reading config from {}".format(self._configfile)) + self.read(self._configfile) + + def read(self, filename): + """Read the data from a file.""" + with open(filename, 'r') as f: + self.data = [line.rstrip('\n') for line in f.readlines()] + + def write(self, fp, limit=-1): + """Write the data to a file. + + Arguments: + fp: A file object to write the data to. + limit: How many lines to write, or -1 for no limit. + """ + if limit == -1: + data = self.data + else: + data = self.data[-limit:] + fp.write('\n'.join(data)) + + def save(self): + """Save the config file.""" + limit = -1 if self._limit is None else config.get(*self._limit) + if limit == 0: + return + if not os.path.exists(self._configdir): + os.makedirs(self._configdir, 0o755) + logging.debug("Saving config to {}".format(self._configfile)) + with open(self._configfile, 'w') as f: + self.write(f, limit) + + @pyqtSlot(str, str) + def on_config_changed(self, section, option): + """Delete the file if the limit was changed to 0.""" + if self._limit is None: + return + if (section, option) == self._limit and config.get(*self._limit) == 0: + if os.path.exists(self._configfile): + os.remove(self._configfile) + + class SectionProxy(MutableMapping): """A proxy for a single section from a config. diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index ac9f3106c..5a520b431 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -138,6 +138,11 @@ def configdata(): ('autosave', SettingValue(types.Bool, "true"), "Whether to save the config automatically on quit."), + + ('cmd_histlen', + SettingValue(types.Int, "100"), + "How many commands to save in the history. 0: no history / -1: " + "unlimited") )), ('tabbar', sect.KeyValue( diff --git a/qutebrowser/widgets/statusbar.py b/qutebrowser/widgets/statusbar.py index 94a979c2c..578dbb455 100644 --- a/qutebrowser/widgets/statusbar.py +++ b/qutebrowser/widgets/statusbar.py @@ -25,6 +25,7 @@ from PyQt5.QtWidgets import (QWidget, QLineEdit, QProgressBar, QLabel, QShortcut) from PyQt5.QtGui import QPainter, QKeySequence, QValidator +import qutebrowser.config.config as config from qutebrowser.config.style import set_register_stylesheet, get_stylesheet import qutebrowser.commands.keys as keys from qutebrowser.utils.url import urlstring @@ -267,7 +268,10 @@ class _Command(QLineEdit): self.returnPressed.connect(self._on_return_pressed) self.textEdited.connect(self._histbrowse_stop) self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Ignored) - self.history = [] + if config.cmd_history.data is None: + self.history = [] + else: + self.history = config.cmd_history.data self._shortcuts = [] for (key, handler) in [