Add cmdutils.Value instead of using count=True/win_id=True

This commit is contained in:
Florian Bruhin 2018-11-30 12:45:01 +01:00
parent d549d4d5e2
commit 569bb0fa09
13 changed files with 128 additions and 94 deletions

View File

@ -480,8 +480,9 @@ For `typing.Union` types, the given `choices` are only checked if other types
The following arguments are supported for `@cmdutils.argument`:
- `flag`: Customize the short flag (`-x`) the argument will get.
- `win_id=True`: Mark the argument as special window ID argument.
- `count=True`: Mark the argument as special count argument.
- `value`: Tell qutebrowser to fill the argument with special values:
- `value=cmdutils.Value.count`: The `count` given by the user to the command.
- `value=cmdutils.Value.win_id`: The window ID of the current window.
- `completion`: A completion function (see `qutebrowser.completions.models.*`)
to use when completing arguments for the given command.
- `choices`: The allowed string choices for the argument.

View File

@ -21,9 +21,12 @@
import inspect
import typing
import enum
from qutebrowser.utils import qtutils
from qutebrowser.commands import command, cmdexc
# pylint: disable=unused-import
from qutebrowser.utils.usertypes import CommandValue as Value
class CommandError(cmdexc.Error):

View File

@ -230,7 +230,7 @@ class CommandDispatcher:
tabbar.setSelectionBehaviorOnRemove(old_selection_behavior)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def tab_close(self, prev=False, next_=False, opposite=False,
force=False, count=None):
"""Close the current/[count]th tab.
@ -253,7 +253,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window',
name='tab-pin')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def tab_pin(self, count=None):
"""Pin/Unpin the current/[count]th tab.
@ -274,7 +274,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', name='open',
maxsplit=0, scope='window')
@cmdutils.argument('url', completion=urlmodel.url)
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def openurl(self, url=None, related=False,
bg=False, tab=False, window=False, count=None, secure=False,
private=False):
@ -372,7 +372,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', name='reload',
scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def reloadpage(self, force=False, count=None):
"""Reload the current/[count]th tab.
@ -385,7 +385,7 @@ class CommandDispatcher:
tab.reload(force=force)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def stop(self, count=None):
"""Stop loading in the current/[count]th tab.
@ -423,7 +423,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', name='print',
scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
@cmdutils.argument('pdf', flag='f', metavar='file')
def printpage(self, preview=False, count=None, *, pdf=None):
"""Print the current/[count]th tab.
@ -514,7 +514,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('win_id', completion=miscmodels.window)
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def tab_give(self, win_id: int = None, keep: bool = False,
count: int = None) -> None:
"""Give the current tab to a new or existing window if win_id given.
@ -575,7 +575,7 @@ class CommandDispatcher:
raise cmdutils.CommandError(e)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def back(self, tab=False, bg=False, window=False, count=1):
"""Go back in the history of the current tab.
@ -588,7 +588,7 @@ class CommandDispatcher:
self._back_forward(tab, bg, window, count, forward=False)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def forward(self, tab=False, bg=False, window=False, count=1):
"""Go forward in the history of the current tab.
@ -603,7 +603,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('where', choices=['prev', 'next', 'up', 'increment',
'decrement'])
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def navigate(self, where: str, tab: bool = False, bg: bool = False,
window: bool = False, count: int = 1) -> None:
"""Open typical prev/next links or navigate using the URL path.
@ -668,7 +668,7 @@ class CommandDispatcher:
raise cmdutils.CommandError(e)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def scroll_px(self, dx: int, dy: int, count: int = 1) -> None:
"""Scroll the current tab by 'count * dx/dy' pixels.
@ -684,7 +684,7 @@ class CommandDispatcher:
self._current_widget().scroller.delta(dx, dy)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def scroll(self, direction: str, count: int = 1) -> None:
"""Scroll the current tab in the given direction.
@ -721,7 +721,7 @@ class CommandDispatcher:
func(count=count)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
@cmdutils.argument('horizontal', flag='x')
def scroll_to_perc(self, perc: float = None, horizontal: bool = False,
count: int = None) -> None:
@ -762,7 +762,7 @@ class CommandDispatcher:
self._current_widget().scroller.to_anchor(name)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
@cmdutils.argument('top_navigate', metavar='ACTION',
choices=('prev', 'decrement'))
@cmdutils.argument('bottom_navigate', metavar='ACTION',
@ -891,7 +891,7 @@ class CommandDispatcher:
maybe=True)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def zoom_in(self, count=1, quiet=False):
"""Increase the zoom level for the current tab.
@ -908,7 +908,7 @@ class CommandDispatcher:
message.info("Zoom level: {}%".format(int(perc)), replace=True)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def zoom_out(self, count=1, quiet=False):
"""Decrease the zoom level for the current tab.
@ -925,7 +925,7 @@ class CommandDispatcher:
message.info("Zoom level: {}%".format(int(perc)), replace=True)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def zoom(self, zoom=None, count=None, quiet=False):
"""Set the zoom level for the current tab.
@ -1005,7 +1005,7 @@ class CommandDispatcher:
raise cmdutils.CommandError("Nothing to undo!")
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def tab_prev(self, count=1):
"""Switch to the previous tab, or switch [count] tabs back.
@ -1025,7 +1025,7 @@ class CommandDispatcher:
log.webview.debug("First tab")
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def tab_next(self, count=1):
"""Switch to the next tab, or switch [count] tabs forward.
@ -1093,7 +1093,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window',
maxsplit=0)
@cmdutils.argument('index', completion=miscmodels.buffer)
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def buffer(self, index=None, count=None):
"""Select tab by index or url/title best match.
@ -1123,7 +1123,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('index', choices=['last'])
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def tab_focus(self, index: typing.Union[str, int] = None,
count: int = None, no_last: bool = False) -> None:
"""Select the tab given as argument/[count].
@ -1165,7 +1165,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('index', choices=['+', '-'])
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def tab_move(self, index: typing.Union[str, int] = None,
count: int = None) -> None:
"""Move the current tab according to the argument and [count].
@ -1212,7 +1212,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window',
maxsplit=0, no_replace_variables=True)
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def spawn(self, cmdline, userscript=False, verbose=False,
output=False, detach=False, count=None):
"""Spawn a command in a shell.
@ -1830,7 +1830,7 @@ class CommandDispatcher:
tab.search.search(text, **options)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def search_next(self, count=1):
"""Continue the search to the ([count]th) next term.
@ -1864,7 +1864,7 @@ class CommandDispatcher:
tab.search.next_result(result_cb=cb)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def search_prev(self, count=1):
"""Continue the search to the ([count]th) previous term.
@ -1899,7 +1899,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def move_to_next_line(self, count=1):
"""Move the cursor or selection to the next line.
@ -1910,7 +1910,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def move_to_prev_line(self, count=1):
"""Move the cursor or selection to the prev line.
@ -1921,7 +1921,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def move_to_next_char(self, count=1):
"""Move the cursor or selection to the next char.
@ -1932,7 +1932,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def move_to_prev_char(self, count=1):
"""Move the cursor or selection to the previous char.
@ -1943,7 +1943,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def move_to_end_of_word(self, count=1):
"""Move the cursor or selection to the end of the word.
@ -1954,7 +1954,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def move_to_next_word(self, count=1):
"""Move the cursor or selection to the next word.
@ -1965,7 +1965,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def move_to_prev_word(self, count=1):
"""Move the cursor or selection to the previous word.
@ -1988,7 +1988,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def move_to_start_of_next_block(self, count=1):
"""Move the cursor or selection to the start of next block.
@ -1999,7 +1999,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def move_to_start_of_prev_block(self, count=1):
"""Move the cursor or selection to the start of previous block.
@ -2010,7 +2010,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def move_to_end_of_next_block(self, count=1):
"""Move the cursor or selection to the end of next block.
@ -2021,7 +2021,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def move_to_end_of_prev_block(self, count=1):
"""Move the cursor or selection to the end of previous block.
@ -2056,7 +2056,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window',
debug=True)
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def debug_webaction(self, action, count=1):
"""Execute a webaction.
@ -2256,7 +2256,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window',
name='tab-mute')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def tab_mute(self, count=None):
"""Mute/Unmute the current/[count]th tab.

View File

@ -1013,7 +1013,7 @@ class DownloadModel(QAbstractListModel):
raise cmdutils.CommandError("There's no download {}!".format(count))
@cmdutils.register(instance='download-model', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def download_cancel(self, all_=False, count=0):
"""Cancel the last/[count]th download.
@ -1039,7 +1039,7 @@ class DownloadModel(QAbstractListModel):
download.cancel()
@cmdutils.register(instance='download-model', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def download_delete(self, count=0):
"""Delete the last/[count]th download from disk.
@ -1060,7 +1060,7 @@ class DownloadModel(QAbstractListModel):
log.downloads.debug("deleted download {}".format(download))
@cmdutils.register(instance='download-model', scope='window', maxsplit=0)
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def download_open(self, cmdline: str = None, count: int = 0) -> None:
"""Open the last/[count]th download.
@ -1086,7 +1086,7 @@ class DownloadModel(QAbstractListModel):
download.open_file(cmdline)
@cmdutils.register(instance='download-model', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def download_retry(self, count=0):
"""Retry the first failed/[count]th download.
@ -1121,7 +1121,7 @@ class DownloadModel(QAbstractListModel):
download.remove()
@cmdutils.register(instance='download-model', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def download_remove(self, all_=False, count=0):
"""Remove the last/[count]th download from the list.

View File

@ -37,18 +37,13 @@ class ArgInfo:
"""Information about an argument."""
win_id = attr.ib(False)
count = attr.ib(False)
value = attr.ib(None)
hide = attr.ib(False)
metavar = attr.ib(None)
flag = attr.ib(None)
completion = attr.ib(None)
choices = attr.ib(None)
def __attrs_post_init__(self):
if self.win_id and self.count:
raise TypeError("Argument marked as both count/win_id!")
class Command:
@ -116,7 +111,6 @@ class Command:
self.parser.add_argument('-h', '--help', action=argparser.HelpAction,
default=argparser.SUPPRESS, nargs=0,
help=argparser.SUPPRESS)
self._check_func()
self.opt_args = collections.OrderedDict()
self.namespace = None
self._count = None
@ -130,6 +124,7 @@ class Command:
self._qute_args = getattr(self.handler, 'qute_args', {})
self.handler.qute_args = None
self._check_func()
self._inspect_func()
def _check_prerequisites(self, win_id):
@ -154,9 +149,14 @@ class Command:
def _check_func(self):
"""Make sure the function parameters don't violate any rules."""
signature = inspect.signature(self.handler)
if 'self' in signature.parameters and self._instance is None:
raise TypeError("{} is a class method, but instance was not "
"given!".format(self.name[0]))
if 'self' in signature.parameters:
if self._instance is None:
raise TypeError("{} is a class method, but instance was not "
"given!".format(self.name[0]))
arg_info = self.get_arg_info(signature.parameters['self'])
if arg_info.value is not None:
raise TypeError("{}: Can't fill 'self' with value!"
.format(self.name))
elif 'self' not in signature.parameters and self._instance is not None:
raise TypeError("{} is not a class method, but instance was "
"given!".format(self.name[0]))
@ -186,13 +186,18 @@ class Command:
True if the parameter is special, False otherwise.
"""
arg_info = self.get_arg_info(param)
if arg_info.count:
if arg_info.value is None:
return False
elif arg_info.value == usertypes.CommandValue.count:
if param.default is inspect.Parameter.empty:
raise TypeError("{}: handler has count parameter "
"without default!".format(self.name))
return True
elif arg_info.win_id:
elif arg_info.value == usertypes.CommandValue.win_id:
return True
else:
raise TypeError("{}: Invalid value={!r} for argument '{}'!"
.format(self.name, arg_info.value, param.name))
return False
def _inspect_func(self):
@ -325,9 +330,8 @@ class Command:
return param.annotation
elif param.default not in [None, inspect.Parameter.empty]:
return type(param.default)
elif arginfo.count or arginfo.win_id or param.kind in [
inspect.Parameter.VAR_POSITIONAL,
inspect.Parameter.VAR_KEYWORD]:
elif arginfo.value or param.kind in [inspect.Parameter.VAR_POSITIONAL,
inspect.Parameter.VAR_KEYWORD]:
return None
else:
return str
@ -447,15 +451,13 @@ class Command:
# Special case for 'self'.
self._get_self_arg(win_id, param, args)
continue
elif arg_info.count:
# Special case for count parameter.
elif arg_info.value == usertypes.CommandValue.count:
self._get_count_arg(param, args, kwargs)
continue
# elif arg_info.win_id:
elif arg_info.win_id:
# Special case for win_id parameter.
elif arg_info.value == usertypes.CommandValue.win_id:
self._get_win_id_arg(win_id, param, args, kwargs)
continue
value = self._get_param_value(param)
if param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD:
args.append(value)

View File

@ -79,7 +79,7 @@ class ConfigCommands:
@cmdutils.register(instance='config-commands')
@cmdutils.argument('option', completion=configmodel.option)
@cmdutils.argument('value', completion=configmodel.value)
@cmdutils.argument('win_id', win_id=True)
@cmdutils.argument('win_id', value=cmdutils.Value.win_id)
@cmdutils.argument('pattern', flag='u')
def set(self, win_id, option=None, value=None, temp=False, print_=False,
*, pattern=None):
@ -127,7 +127,7 @@ class ConfigCommands:
@cmdutils.register(instance='config-commands', maxsplit=1,
no_cmd_split=True, no_replace_variables=True)
@cmdutils.argument('command', completion=configmodel.bind)
@cmdutils.argument('win_id', win_id=True)
@cmdutils.argument('win_id', value=cmdutils.Value.win_id)
def bind(self, win_id, key=None, command=None, *, mode='normal',
default=False):
"""Bind a key to a command.

View File

@ -45,7 +45,7 @@ class MacroRecorder:
self._last_register = None
@cmdutils.register(instance='macro-recorder', name='record-macro')
@cmdutils.argument('win_id', win_id=True)
@cmdutils.argument('win_id', value=cmdutils.Value.win_id)
def record_macro_command(self, win_id, register=None):
"""Start or stop recording a macro.
@ -70,8 +70,8 @@ class MacroRecorder:
self._recording_macro = register
@cmdutils.register(instance='macro-recorder', name='run-macro')
@cmdutils.argument('win_id', win_id=True)
@cmdutils.argument('count', count=True)
@cmdutils.argument('win_id', value=cmdutils.Value.win_id)
@cmdutils.argument('count', value=cmdutils.Value.count)
def run_macro_command(self, win_id, count=1, register=None):
"""Run a recorded macro.

View File

@ -115,7 +115,7 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
@cmdutils.register(instance='status-command', name='set-cmd-text',
scope='window', maxsplit=0)
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def set_cmd_text_command(self, text, count=None, space=False, append=False,
run_on_count=False):
"""Preset the statusbar to some text.

View File

@ -508,7 +508,7 @@ class SessionManager(QObject):
@cmdutils.register(instance='session-manager')
@cmdutils.argument('name', completion=miscmodels.session)
@cmdutils.argument('win_id', win_id=True)
@cmdutils.argument('win_id', value=cmdutils.Value.win_id)
@cmdutils.argument('with_private', flag='p')
def session_save(self, name: typing.Union[str, Sentinel] = default,
current: bool = False,

View File

@ -44,7 +44,7 @@ from qutebrowser.qt import sip
@cmdutils.register(maxsplit=1, no_cmd_split=True, no_replace_variables=True)
@cmdutils.argument('win_id', win_id=True)
@cmdutils.argument('win_id', value=cmdutils.Value.win_id)
def later(ms: int, command: str, win_id: int) -> None:
"""Execute a command after some time.
@ -74,8 +74,8 @@ def later(ms: int, command: str, win_id: int) -> None:
@cmdutils.register(maxsplit=1, no_cmd_split=True, no_replace_variables=True)
@cmdutils.argument('win_id', win_id=True)
@cmdutils.argument('count', count=True)
@cmdutils.argument('win_id', value=cmdutils.Value.win_id)
@cmdutils.argument('count', value=cmdutils.Value.count)
def repeat(times: int, command: str, win_id: int, count: int = None) -> None:
"""Repeat a given command.
@ -95,8 +95,8 @@ def repeat(times: int, command: str, win_id: int, count: int = None) -> None:
@cmdutils.register(maxsplit=1, no_cmd_split=True, no_replace_variables=True)
@cmdutils.argument('win_id', win_id=True)
@cmdutils.argument('count', count=True)
@cmdutils.argument('win_id', value=cmdutils.Value.win_id)
@cmdutils.argument('count', value=cmdutils.Value.count)
def run_with_count(count_arg: int, command: str, win_id: int,
count: int = 1) -> None:
"""Run a command with the given count.
@ -122,7 +122,7 @@ def message_error(text):
@cmdutils.register()
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def message_info(text, count=1):
"""Show an info message in the statusbar.
@ -288,8 +288,8 @@ def debug_set_fake_clipboard(s=None):
@cmdutils.register()
@cmdutils.argument('win_id', win_id=True)
@cmdutils.argument('count', count=True)
@cmdutils.argument('win_id', value=cmdutils.Value.win_id)
@cmdutils.argument('count', value=cmdutils.Value.count)
def repeat_command(win_id, count=None):
"""Repeat the last executed command.
@ -358,7 +358,7 @@ def debug_log_filter(filters: str) -> None:
@cmdutils.register()
@cmdutils.argument('current_win_id', win_id=True)
@cmdutils.argument('current_win_id', value=cmdutils.Value.win_id)
def window_only(current_win_id):
"""Close all windows except for the current one."""
for win_id, window in objreg.window_registry.items():
@ -377,7 +377,7 @@ def nop():
@cmdutils.register()
@cmdutils.argument('win_id', win_id=True)
@cmdutils.argument('win_id', value=cmdutils.Value.win_id)
def version(win_id, paste=False):
"""Show version information.

View File

@ -256,6 +256,14 @@ MessageLevel = enum.Enum('MessageLevel', ['error', 'warning', 'info'])
IgnoreCase = enum.Enum('IgnoreCase', ['smart', 'never', 'always'])
class CommandValue(enum.Enum):
"""Special values which are injected when running a command handler."""
count = 1
win_id = 2
class Question(QObject):
"""A question asked to the user, e.g. via the status bar.

View File

@ -190,23 +190,39 @@ class TestRegister:
def test_win_id(self):
@cmdutils.register()
@cmdutils.argument('win_id', win_id=True)
@cmdutils.argument('win_id', value=cmdutils.Value.win_id)
def fun(win_id):
"""Blah."""
assert objects.commands['fun']._get_call_args(42) == ([42], {})
def test_count(self):
@cmdutils.register()
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def fun(count=0):
"""Blah."""
assert objects.commands['fun']._get_call_args(42) == ([0], {})
def test_fill_self(self):
with pytest.raises(TypeError, match="fun: Can't fill 'self' with "
"value!"):
@cmdutils.register(instance='foobar')
@cmdutils.argument('self', value=cmdutils.Value.count)
def fun(self):
"""Blah."""
def test_fill_invalid(self):
with pytest.raises(TypeError, match="fun: Invalid value='foo' for "
"argument 'arg'!"):
@cmdutils.register()
@cmdutils.argument('arg', value='foo')
def fun(arg):
"""Blah."""
def test_count_without_default(self):
with pytest.raises(TypeError, match="fun: handler has count parameter "
"without default!"):
@cmdutils.register()
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def fun(count):
"""Blah."""
@ -344,6 +360,17 @@ class TestArgument:
}
assert fun.qute_args == expected
def test_arginfo_boolean(self):
@cmdutils.argument('special1', value=cmdutils.Value.count)
@cmdutils.argument('special2', value=cmdutils.Value.win_id)
@cmdutils.argument('normal')
def fun(special1, special2, normal):
"""Blah."""
assert fun.qute_args['special1'].value
assert fun.qute_args['special2'].value
assert not fun.qute_args['normal'].value
def test_wrong_order(self):
"""When @cmdutils.argument is used above (after) @register, fail."""
with pytest.raises(ValueError, match=r"@cmdutils.argument got called "
@ -353,13 +380,6 @@ class TestArgument:
def fun(bar):
"""Blah."""
def test_count_and_win_id_same_arg(self):
with pytest.raises(TypeError,
match="Argument marked as both count/win_id!"):
@cmdutils.argument('arg', count=True, win_id=True)
def fun(arg=0):
"""Blah."""
def test_no_docstring(self, caplog):
with caplog.at_level(logging.WARNING):
@cmdutils.register()

View File

@ -112,12 +112,12 @@ def cmdutils_patch(monkeypatch, stubs, miscmodels_patch):
"""docstring."""
@cmdutils.argument('url', completion=miscmodels_patch.url)
@cmdutils.argument('count', count=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
def openurl(url=None, related=False, bg=False, tab=False, window=False,
count=None):
"""docstring."""
@cmdutils.argument('win_id', win_id=True)
@cmdutils.argument('win_id', value=cmdutils.Value.win_id)
@cmdutils.argument('command', completion=miscmodels_patch.command)
def bind(key, win_id, command=None, *, mode='normal'):
"""docstring."""