summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2021-03-18 15:15:22 +0100
committerFlorian Bruhin <me@the-compiler.org>2021-03-18 15:15:22 +0100
commit3d1f975391ef61a43490e93b4ce0c54fdd5c22ab (patch)
tree058b862985d6d99afc64dcdebe4994908feab061
parentf3e604d7fbf2ceb8f15a92c5ba7c177c83ee4db1 (diff)
downloadqutebrowser-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.py29
-rw-r--r--qutebrowser/completion/completer.py23
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):