From 7787a67c45d7309483687fbb516bf126dd275a1d Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 25 Apr 2014 10:10:58 +0200 Subject: [PATCH] Add modes=[]/not_modes=[] to cmdutils.register --- TODO | 2 -- qutebrowser/commands/command.py | 20 +++++++++++++++----- qutebrowser/commands/exceptions.py | 7 +++++++ qutebrowser/commands/parsers.py | 9 ++++++++- qutebrowser/commands/utils.py | 10 ++++++++-- qutebrowser/keyinput/modes.py | 3 ++- qutebrowser/widgets/completion.py | 6 ++++-- qutebrowser/widgets/statusbar.py | 9 ++++++--- 8 files changed, 50 insertions(+), 16 deletions(-) diff --git a/TODO b/TODO index 94b343f3d..9acda2186 100644 --- a/TODO +++ b/TODO @@ -79,8 +79,6 @@ catch import errors for PyQt and QtWebKit Allow binding to empty values for keys to override defaults How do we handle empty values in input bar? Human-readable error messages for unknown settings / wrong interpolations / ... -- Add mode=[]/no_mode=[] to cmdutils.register so we can avoid executing - commands in the wrong mode - Add more element-selection-detection code (with options?) based on: -> javascript: http://stackoverflow.com/a/2848120/2085149 -> microFocusChanged and check active element via: diff --git a/qutebrowser/commands/command.py b/qutebrowser/commands/command.py index 4c80e8220..b6fc482c0 100644 --- a/qutebrowser/commands/command.py +++ b/qutebrowser/commands/command.py @@ -19,7 +19,8 @@ import logging -from qutebrowser.commands.exceptions import ArgumentCountError +from qutebrowser.commands.exceptions import (ArgumentCountError, + InvalidModeError) from PyQt5.QtCore import pyqtSignal, QObject @@ -55,7 +56,7 @@ class Command(QObject): signal = pyqtSignal(tuple) def __init__(self, name, maxsplit, hide, nargs, count, desc, instance, - handler, completion): + handler, completion, modes, not_modes): super().__init__() self.name = name self.maxsplit = maxsplit @@ -66,18 +67,27 @@ class Command(QObject): self.instance = instance self.handler = handler self.completion = completion + self.modes = modes + self.not_modes = not_modes def check(self, args): - """Check if the argument count is valid. - - Raise ArgumentCountError if not. + """Check if the argument count is valid and the command is permitted. Args: args: The supplied arguments Raise: ArgumentCountError if the argument count is wrong. + InvalidModeError if the command can't be called in this mode. """ + import qutebrowser.keyinput.modes as modeman + if self.modes is not None and modeman.manager.mode not in self.modes: + raise InvalidModeError("This command is only allowed in {} " + "mode.".format('/'.join(self.modes))) + elif (self.not_modes is not None and + modeman.manager.mode in self.not_modes): + raise InvalidModeError("This command is not allowed in {} " + "mode.".format('/'.join(self.not_modes))) if self.nargs[1] is None and self.nargs[0] <= len(args): pass elif self.nargs[0] <= len(args) <= self.nargs[1]: diff --git a/qutebrowser/commands/exceptions.py b/qutebrowser/commands/exceptions.py index 58b84f648..328afcb24 100644 --- a/qutebrowser/commands/exceptions.py +++ b/qutebrowser/commands/exceptions.py @@ -33,3 +33,10 @@ class ArgumentCountError(TypeError): """Raised when a command was called with an invalid count of arguments.""" pass + + +class InvalidModeError(Exception): + + """Raised when a command is called in a wrong input mode.""" + + pass diff --git a/qutebrowser/commands/parsers.py b/qutebrowser/commands/parsers.py index 3d0c87bbf..70a728154 100644 --- a/qutebrowser/commands/parsers.py +++ b/qutebrowser/commands/parsers.py @@ -24,7 +24,7 @@ import qutebrowser.config.config as config import qutebrowser.commands.utils as cmdutils import qutebrowser.utils.message as message from qutebrowser.commands.exceptions import (ArgumentCountError, - NoSuchCommandError) + NoSuchCommandError, InvalidModeError) def split_cmdline(text): @@ -202,6 +202,7 @@ class CommandParser: NoSuchCommandError: if a command wasn't found. ArgumentCountError: if a command was called with the wrong count of arguments. + InvalidModeError: if a command can't be called in this mode. Return: True if command was called (handler returnstatus is ignored!). @@ -228,5 +229,11 @@ class CommandParser: return False else: raise + except InvalidModeError as e: + if ignore_exc: + message.error("{}: {}".format(self._cmd.name, e)) + return False + else: + raise self._run(count=count) return True diff --git a/qutebrowser/commands/utils.py b/qutebrowser/commands/utils.py index e3f252b39..92cedb123 100644 --- a/qutebrowser/commands/utils.py +++ b/qutebrowser/commands/utils.py @@ -47,10 +47,11 @@ class register: # pylint: disable=invalid-name hide: Whether to hide the command or not. completion: Which completion to use for arguments, as a list of strings. + modes/not_modes: List of modes to use/not use. """ def __init__(self, instance=None, name=None, nargs=None, maxsplit=-1, - hide=False, completion=None): + hide=False, completion=None, modes=None, not_modes=None): """Save decorator arguments. Gets called on parse-time with the decorator arguments. @@ -58,12 +59,16 @@ class register: # pylint: disable=invalid-name Args: See class attributes. """ + if modes is not None and not_modes is not None: + raise ValueError("Only modes or not_modes can be given!") self.name = name self.maxsplit = maxsplit self.hide = hide self.nargs = nargs self.instance = instance self.completion = completion + self.modes = modes + self.not_modes = not_modes def __call__(self, func): """Register the command before running the function. @@ -95,7 +100,8 @@ class register: # pylint: disable=invalid-name cmd = Command(name=mainname, maxsplit=self.maxsplit, hide=self.hide, nargs=nargs, count=count, desc=desc, instance=self.instance, handler=func, - completion=self.completion) + completion=self.completion, modes=self.modes, + not_modes=self.not_modes) for name in names: cmd_dict[name] = cmd return func diff --git a/qutebrowser/keyinput/modes.py b/qutebrowser/keyinput/modes.py index 765660c74..3b0d9637b 100644 --- a/qutebrowser/keyinput/modes.py +++ b/qutebrowser/keyinput/modes.py @@ -158,7 +158,8 @@ class ModeManager(QObject): logging.debug("New mode stack: {}".format(self._mode_stack)) self.left.emit(mode) - @cmdutils.register(instance='modeman', name='leave_mode', hide=True) + @cmdutils.register(instance='modeman', name='leave_mode', + not_modes=['normal'], hide=True) def leave_current_mode(self): if self.mode == "normal": raise ValueError("Can't leave normal mode!") diff --git a/qutebrowser/widgets/completion.py b/qutebrowser/widgets/completion.py index c9c97166d..0eda29991 100644 --- a/qutebrowser/widgets/completion.py +++ b/qutebrowser/widgets/completion.py @@ -297,12 +297,14 @@ class CompletionView(QTreeView): selmod.clearSelection() selmod.clearCurrentIndex() - @cmdutils.register(instance='mainwindow.completion', hide=True) + @cmdutils.register(instance='mainwindow.completion', hide=True, + modes=['command']) def completion_item_prev(self): """Select the previous completion item.""" self._next_prev_item(prev=True) - @cmdutils.register(instance='mainwindow.completion', hide=True) + @cmdutils.register(instance='mainwindow.completion', hide=True, + modes=['command']) def completion_item_next(self): """Select the next completion item.""" self._next_prev_item(prev=False) diff --git a/qutebrowser/widgets/statusbar.py b/qutebrowser/widgets/statusbar.py index 471b4f9e5..efe976494 100644 --- a/qutebrowser/widgets/statusbar.py +++ b/qutebrowser/widgets/statusbar.py @@ -290,7 +290,8 @@ class _Command(QLineEdit): self.setFocus() self.show_cmd.emit() - @cmdutils.register(instance='mainwindow.status.cmd', hide=True) + @cmdutils.register(instance='mainwindow.status.cmd', hide=True, + modes=['command']) def command_history_prev(self): """Handle Up presses (go back in history).""" try: @@ -303,7 +304,8 @@ class _Command(QLineEdit): if item: self.set_cmd_text(item) - @cmdutils.register(instance='mainwindow.status.cmd', hide=True) + @cmdutils.register(instance='mainwindow.status.cmd', hide=True, + modes=['command']) def command_history_next(self): """Handle Down presses (go forward in history).""" if not self.history.browsing: @@ -315,7 +317,8 @@ class _Command(QLineEdit): if item: self.set_cmd_text(item) - @cmdutils.register(instance='mainwindow.status.cmd', hide=True) + @cmdutils.register(instance='mainwindow.status.cmd', hide=True, + modes=['command']) def command_accept(self): """Handle the command in the status bar.