diff options
author | Florian Bruhin <me@the-compiler.org> | 2021-03-18 15:15:22 +0100 |
---|---|---|
committer | Florian Bruhin <me@the-compiler.org> | 2021-03-18 15:15:22 +0100 |
commit | 3d1f975391ef61a43490e93b4ce0c54fdd5c22ab (patch) | |
tree | 058b862985d6d99afc64dcdebe4994908feab061 | |
parent | f3e604d7fbf2ceb8f15a92c5ba7c177c83ee4db1 (diff) | |
download | qutebrowser-3d1f975391ef61a43490e93b4ce0c54fdd5c22ab.tar.gz qutebrowser-3d1f975391ef61a43490e93b4ce0c54fdd5c22ab.zip |
Move completion fallback handling out of CommandParser
This makes CompletionParser.parse simpler and makes ParseResult.cmd and
.args non-Optional. Them being Optional would mean we would've to either
resort to more complex typing with Literal, or to check whether they are
really non-None everywhere.
Since fallback=True is only used at one point, let's just handle this at
the calling site instead.
In theory, this changes the behavior when the cmdstr is empty and
self._partial_match is set, because we now raise early and
self._completion_match isn't called anymore. In practice, I think this
shouldn't make a difference anywhere, and tests seem to agree.
If cmdstr is empty and self._partial_match is False, the behavior should
be the same, because objects.commands[''] will raise KeyError.
-rw-r--r-- | qutebrowser/commands/parser.py | 29 | ||||
-rw-r--r-- | qutebrowser/completion/completer.py | 23 |
2 files changed, 21 insertions, 31 deletions
diff --git a/qutebrowser/commands/parser.py b/qutebrowser/commands/parser.py index 547641281..5adbc003c 100644 --- a/qutebrowser/commands/parser.py +++ b/qutebrowser/commands/parser.py @@ -20,7 +20,7 @@ """Module for parsing commands entered into the browser.""" import dataclasses -from typing import Optional, List, Mapping, Iterator, List, Union +from typing import Optional, List, Mapping, Iterator, Union from qutebrowser.commands import cmdexc, command from qutebrowser.misc import split, objects @@ -32,8 +32,8 @@ class ParseResult: """The result of parsing a commandline.""" - cmd: Optional[command.Command] - args: Optional[List[str]] + cmd: command.Command + args: List[str] cmdline: List[str] @@ -118,27 +118,16 @@ class CommandParser: """Wrapper over _parse_all_gen.""" return list(self._parse_all_gen(text, **kwargs)) - def parse( - self, - text: str, - *, - fallback: bool = False, - keep: bool = False, - ) -> ParseResult: + def parse(self, text: str, *, keep: bool = False) -> ParseResult: """Split the commandline text into command and arguments. Args: text: Text to parse. - fallback: Whether to do a fallback splitting when the command was - unknown. - keep: Whether to keep special chars and whitespace - - Return: - A ParseResult tuple. + keep: Whether to keep special chars and whitespace. """ cmdstr, sep, argstr = text.partition(' ') - if not cmdstr and not fallback: + if not cmdstr: raise cmdexc.NoSuchCommandError("No command given") if self._partial_match: @@ -147,11 +136,7 @@ class CommandParser: try: cmd = objects.commands[cmdstr] except KeyError: - if not fallback: - raise cmdexc.NoSuchCommandError( - '{}: no such command'.format(cmdstr)) - cmdline = split.split(text, keep=keep) - return ParseResult(cmd=None, args=None, cmdline=cmdline) + raise cmdexc.NoSuchCommandError(f'{cmdstr}: no such command') args = self._split_args(cmd, argstr, keep) if keep and args: diff --git a/qutebrowser/completion/completer.py b/qutebrowser/completion/completer.py index 548ace2c7..778333854 100644 --- a/qutebrowser/completion/completer.py +++ b/qutebrowser/completion/completer.py @@ -25,8 +25,8 @@ from typing import TYPE_CHECKING from PyQt5.QtCore import pyqtSlot, QObject, QTimer from qutebrowser.config import config -from qutebrowser.commands import parser -from qutebrowser.misc import objects +from qutebrowser.commands import parser, cmdexc +from qutebrowser.misc import objects, split from qutebrowser.utils import log, utils, debug, objreg from qutebrowser.completion.models import miscmodels if TYPE_CHECKING: @@ -139,12 +139,18 @@ class Completer(QObject): if not text or not text.strip(): # Only ":", empty part under the cursor with nothing before/after return [], '', [] - result = parser.CommandParser().parse(text, fallback=True, keep=True) - parts = [x for x in result.cmdline if x] + + try: + parse_result = parser.CommandParser().parse(text, keep=True) + except cmdexc.NoSuchCommandError: + cmdline = split.split(text, keep=True) + else: + cmdline = parse_result.cmdline + + parts = [x for x in cmdline if x] pos = self._cmd.cursorPosition() - len(self._cmd.prefix()) pos = min(pos, len(text)) # Qt treats 2-byte UTF-16 chars as 2 chars - log.completion.debug('partitioning {} around position {}'.format(parts, - pos)) + log.completion.debug(f'partitioning {parts} around position {pos}') for i, part in enumerate(parts): pos -= len(part) if pos <= 0: @@ -155,11 +161,10 @@ class Completer(QObject): center = parts[i].strip() # strip trailing whitespace included as a separate token postfix = [x.strip() for x in parts[i+1:] if not x.isspace()] - log.completion.debug( - "partitioned: {} '{}' {}".format(prefix, center, postfix)) + log.completion.debug(f"partitioned: {prefix} '{center}' {postfix}") return prefix, center, postfix - raise utils.Unreachable("Not all parts consumed: {}".format(parts)) + raise utils.Unreachable(f"Not all parts consumed: {parts}") @pyqtSlot(str) def on_selection_changed(self, text): |