Start initial newcmd stuff.
This commit is contained in:
parent
84a034d7e9
commit
a811f8cb07
@ -581,7 +581,7 @@ class Application(QApplication):
|
||||
self._destroy_crashlogfile()
|
||||
sys.exit(1)
|
||||
|
||||
@cmdutils.register(instance='', nargs=0)
|
||||
@cmdutils.register(instance='', ignore_args=True)
|
||||
def restart(self, shutdown=True, pages=None):
|
||||
"""Restart qutebrowser while keeping existing tabs open."""
|
||||
# We don't use _recover_pages here as it's too forgiving when
|
||||
|
@ -78,9 +78,7 @@ class CommandDispatcher:
|
||||
if perc is None and count is None:
|
||||
perc = 100
|
||||
elif perc is None:
|
||||
perc = int(count)
|
||||
else:
|
||||
perc = float(perc)
|
||||
perc = count
|
||||
perc = qtutils.check_overflow(perc, 'int', fatal=False)
|
||||
frame = self._current_widget().page().currentFrame()
|
||||
m = frame.scrollBarMaximum(orientation)
|
||||
@ -161,28 +159,35 @@ class CommandDispatcher:
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd', name='open',
|
||||
split=False)
|
||||
def openurl(self, urlstr, count=None):
|
||||
def openurl(self, urlstr, bg=False, tab=False, count=None):
|
||||
"""Open a URL in the current/[count]th tab.
|
||||
|
||||
Args:
|
||||
urlstr: The URL to open, as string.
|
||||
bg: Whether to open in a background tab.
|
||||
tab: Whether to open in a tab.
|
||||
count: The tab index to open the URL in, or None.
|
||||
"""
|
||||
tab = self._tabs.cntwidget(count)
|
||||
try:
|
||||
url = urlutils.fuzzy_url(urlstr)
|
||||
except urlutils.FuzzyUrlError as e:
|
||||
raise cmdexc.CommandError(e)
|
||||
if tab is None:
|
||||
if count is None:
|
||||
# We want to open a URL in the current tab, but none exists
|
||||
# yet.
|
||||
self._tabs.tabopen(url)
|
||||
else:
|
||||
# Explicit count with a tab that doesn't exist.
|
||||
return
|
||||
if tab:
|
||||
self._tabs.tabopen(url, background=False, explicit=True)
|
||||
elif bg:
|
||||
self._tabs.tabopen(url, background=True, explicit=True)
|
||||
else:
|
||||
tab.openurl(url)
|
||||
curtab = self._tabs.cntwidget(count)
|
||||
if curtab is None:
|
||||
if count is None:
|
||||
# We want to open a URL in the current tab, but none exists
|
||||
# yet.
|
||||
self._tabs.tabopen(url)
|
||||
else:
|
||||
# Explicit count with a tab that doesn't exist.
|
||||
return
|
||||
else:
|
||||
curtab.openurl(url)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd', name='reload')
|
||||
def reloadpage(self, count=None):
|
||||
@ -206,29 +211,12 @@ class CommandDispatcher:
|
||||
if tab is not None:
|
||||
tab.stop()
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def print_preview(self, count=None):
|
||||
"""Preview printing of the current/[count]th tab.
|
||||
|
||||
Args:
|
||||
count: The tab index to print, or None.
|
||||
"""
|
||||
if not qtutils.check_print_compat():
|
||||
# WORKAROUND (remove this when we bump the requirements to 5.3.0)
|
||||
raise cmdexc.CommandError(
|
||||
"Printing on Qt < 5.3.0 on Windows is broken, please upgrade!")
|
||||
tab = self._tabs.cntwidget(count)
|
||||
if tab is not None:
|
||||
preview = QPrintPreviewDialog()
|
||||
preview.setAttribute(Qt.WA_DeleteOnClose)
|
||||
preview.paintRequested.connect(tab.print)
|
||||
preview.exec_()
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd', name='print')
|
||||
def printpage(self, count=None):
|
||||
def printpage(self, preview=False, count=None):
|
||||
"""Print the current/[count]th tab.
|
||||
|
||||
Args:
|
||||
preview: Whether to preview instead of printing.
|
||||
count: The tab index to print, or None.
|
||||
"""
|
||||
if not qtutils.check_print_compat():
|
||||
@ -237,9 +225,15 @@ class CommandDispatcher:
|
||||
"Printing on Qt < 5.3.0 on Windows is broken, please upgrade!")
|
||||
tab = self._tabs.cntwidget(count)
|
||||
if tab is not None:
|
||||
printdiag = QPrintDialog()
|
||||
printdiag.setAttribute(Qt.WA_DeleteOnClose)
|
||||
printdiag.open(lambda: tab.print(printdiag.printer()))
|
||||
if preview:
|
||||
diag = QPrintPreviewDialog()
|
||||
diag.setAttribute(Qt.WA_DeleteOnClose)
|
||||
diag.paintRequested.connect(tab.print)
|
||||
diag.exec_()
|
||||
else:
|
||||
diag = QPrintDialog()
|
||||
diag.setAttribute(Qt.WA_DeleteOnClose)
|
||||
diag.open(lambda: tab.print(printdiag.printer()))
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def back(self, count=1):
|
||||
@ -262,7 +256,8 @@ class CommandDispatcher:
|
||||
self._current_widget().go_forward()
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def hint(self, group='all', target='normal', *args):
|
||||
def hint(self, group=webelem.Group.all, target=hints.Target.normal,
|
||||
*args : {'nargs': '*'}):
|
||||
"""Start hinting.
|
||||
|
||||
Args:
|
||||
@ -281,9 +276,9 @@ class CommandDispatcher:
|
||||
- `yank-primary`: Yank the link to the primary selection.
|
||||
- `fill`: Fill the commandline with the command given as
|
||||
argument.
|
||||
- `cmd-tab`: Fill the commandline with `:open-tab` and the
|
||||
- `cmd-tab`: Fill the commandline with `:open -t` and the
|
||||
link.
|
||||
- `cmd-tag-bg`: Fill the commandline with `:open-tab-bg` and
|
||||
- `cmd-tag-bg`: Fill the commandline with `:open -b` and
|
||||
the link.
|
||||
- `rapid`: Open the link in a new tab and stay in hinting mode.
|
||||
- `download`: Download the link.
|
||||
@ -305,18 +300,8 @@ class CommandDispatcher:
|
||||
frame = widget.page().mainFrame()
|
||||
if frame is None:
|
||||
raise cmdexc.CommandError("No frame focused!")
|
||||
try:
|
||||
group_enum = webelem.Group[group.replace('-', '_')]
|
||||
except KeyError:
|
||||
raise cmdexc.CommandError("Unknown hinting group {}!".format(
|
||||
group))
|
||||
try:
|
||||
target_enum = hints.Target[target.replace('-', '_')]
|
||||
except KeyError:
|
||||
raise cmdexc.CommandError("Unknown hinting target {}!".format(
|
||||
target))
|
||||
widget.hintmanager.start(frame, self._tabs.current_url(), group_enum,
|
||||
target_enum, *args)
|
||||
widget.hintmanager.start(frame, self._tabs.current_url(), group,
|
||||
target, *args)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd', hide=True)
|
||||
def follow_hint(self):
|
||||
@ -324,43 +309,31 @@ class CommandDispatcher:
|
||||
self._current_widget().hintmanager.follow_hint()
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def prev_page(self):
|
||||
def prev_page(self, tab=False):
|
||||
"""Open a "previous" link.
|
||||
|
||||
This tries to automaticall click on typical "Previous Page" links using
|
||||
some heuristics.
|
||||
|
||||
Args:
|
||||
tab: Whether to open a new tab.
|
||||
"""
|
||||
self._prevnext(prev=True, newtab=False)
|
||||
self._prevnext(prev=True, newtab=tab)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def next_page(self):
|
||||
def next_page(self, tab=False):
|
||||
"""Open a "next" link.
|
||||
|
||||
This tries to automatically click on typical "Next Page" links using
|
||||
some heuristics.
|
||||
|
||||
Args:
|
||||
tab: Whether to open a new tab.
|
||||
"""
|
||||
self._prevnext(prev=False, newtab=False)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def prev_page_tab(self):
|
||||
"""Open a "previous" link in a new tab.
|
||||
|
||||
This tries to automatically click on typical "Previous Page" links
|
||||
using some heuristics.
|
||||
"""
|
||||
self._prevnext(prev=True, newtab=True)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def next_page_tab(self):
|
||||
"""Open a "next" link in a new tab.
|
||||
|
||||
This tries to automatically click on typical "Previous Page" links
|
||||
using some heuristics.
|
||||
"""
|
||||
self._prevnext(prev=False, newtab=True)
|
||||
self._prevnext(prev=False, newtab=tab)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd', hide=True)
|
||||
def scroll(self, dx, dy, count=1):
|
||||
def scroll(self, dx : float, dy : float, count=1):
|
||||
"""Scroll the current tab by 'count * dx/dy'.
|
||||
|
||||
Args:
|
||||
@ -368,40 +341,30 @@ class CommandDispatcher:
|
||||
dy: How much to scroll in x-direction.
|
||||
count: multiplier
|
||||
"""
|
||||
dx = int(int(count) * float(dx))
|
||||
dy = int(int(count) * float(dy))
|
||||
dx *= count
|
||||
dy *= count
|
||||
cmdutils.check_overflow(dx, 'int')
|
||||
cmdutils.check_overflow(dy, 'int')
|
||||
self._current_widget().page().currentFrame().scroll(dx, dy)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd', hide=True)
|
||||
def scroll_perc_x(self, perc=None, count=None):
|
||||
"""Scroll horizontally to a specific percentage of the page.
|
||||
def scroll_perc(self, perc : float = None,
|
||||
horizontal : {'flag': 'x'} = False, count=None):
|
||||
"""Scroll to a specific percentage of the page.
|
||||
|
||||
The percentage can be given either as argument or as count.
|
||||
If no percentage is given, the page is scrolled to the end.
|
||||
|
||||
Args:
|
||||
perc: Percentage to scroll.
|
||||
horizontal: Whether to scroll horizontally.
|
||||
count: Percentage to scroll.
|
||||
"""
|
||||
self._scroll_percent(perc, count, Qt.Horizontal)
|
||||
self._scroll_percent(perc, count,
|
||||
Qt.Horizontal if horizontal else Qt.Vertical)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd', hide=True)
|
||||
def scroll_perc_y(self, perc=None, count=None):
|
||||
"""Scroll vertically to a specific percentage of the page.
|
||||
|
||||
The percentage can be given either as argument or as count.
|
||||
If no percentage is given, the page is scrolled to the end.
|
||||
|
||||
Args:
|
||||
perc: Percentage to scroll.
|
||||
count: Percentage to scroll.
|
||||
"""
|
||||
self._scroll_percent(perc, count, Qt.Vertical)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd', hide=True)
|
||||
def scroll_page(self, x, y, count=1):
|
||||
def scroll_page(self, x : int, y : int, count=1):
|
||||
"""Scroll the frame page-wise.
|
||||
|
||||
Args:
|
||||
@ -411,52 +374,36 @@ class CommandDispatcher:
|
||||
"""
|
||||
frame = self._current_widget().page().currentFrame()
|
||||
size = frame.geometry()
|
||||
dx = int(count) * float(x) * size.width()
|
||||
dy = int(count) * float(y) * size.height()
|
||||
dx = count * x * size.width()
|
||||
dy = count * y * size.height()
|
||||
cmdutils.check_overflow(dx, 'int')
|
||||
cmdutils.check_overflow(dy, 'int')
|
||||
frame.scroll(dx, dy)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def yank(self, sel=False):
|
||||
"""Yank the current URL to the clipboard or primary selection.
|
||||
def yank(self, title=False, sel=False):
|
||||
"""Yank the current URL/title to the clipboard or primary selection.
|
||||
|
||||
Args:
|
||||
sel: True to use primary selection, False to use clipboard
|
||||
title: Whether to yank the title instead of the URL.
|
||||
"""
|
||||
clipboard = QApplication.clipboard()
|
||||
urlstr = self._tabs.current_url().toString(
|
||||
QUrl.FullyEncoded | QUrl.RemovePassword)
|
||||
if title:
|
||||
s = self._tabs.tabText(self._tabs.currentIndex())
|
||||
else:
|
||||
s = self._tabs.current_url().toString(
|
||||
QUrl.FullyEncoded | QUrl.RemovePassword)
|
||||
if sel and clipboard.supportsSelection():
|
||||
mode = QClipboard.Selection
|
||||
target = "primary selection"
|
||||
else:
|
||||
mode = QClipboard.Clipboard
|
||||
target = "clipboard"
|
||||
log.misc.debug("Yanking to {}: '{}'".format(target, urlstr))
|
||||
clipboard.setText(urlstr, mode)
|
||||
log.misc.debug("Yanking to {}: '{}'".format(target, s))
|
||||
clipboard.setText(s, mode)
|
||||
message.info("URL yanked to {}".format(target))
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def yank_title(self, sel=False):
|
||||
"""Yank the current title to the clipboard or primary selection.
|
||||
|
||||
Args:
|
||||
sel: True to use primary selection, False to use clipboard
|
||||
"""
|
||||
clipboard = QApplication.clipboard()
|
||||
title = self._tabs.tabText(self._tabs.currentIndex())
|
||||
mode = QClipboard.Selection if sel else QClipboard.Clipboard
|
||||
if sel and clipboard.supportsSelection():
|
||||
mode = QClipboard.Selection
|
||||
target = "primary selection"
|
||||
else:
|
||||
mode = QClipboard.Clipboard
|
||||
target = "clipboard"
|
||||
log.misc.debug("Yanking to {}: '{}'".format(target, title))
|
||||
clipboard.setText(title, mode)
|
||||
message.info("Title yanked to {}".format(target))
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def zoom_in(self, count=1):
|
||||
"""Increase the zoom level for the current tab.
|
||||
@ -503,24 +450,6 @@ class CommandDispatcher:
|
||||
continue
|
||||
self._tabs.close_tab(tab)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd', split=False)
|
||||
def open_tab(self, urlstr):
|
||||
"""Open a new tab with a given url."""
|
||||
try:
|
||||
url = urlutils.fuzzy_url(urlstr)
|
||||
except urlutils.FuzzyUrlError as e:
|
||||
raise cmdexc.CommandError(e)
|
||||
self._tabs.tabopen(url, background=False, explicit=True)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd', split=False)
|
||||
def open_tab_bg(self, urlstr):
|
||||
"""Open a new tab in background."""
|
||||
try:
|
||||
url = urlutils.fuzzy_url(urlstr)
|
||||
except urlutils.FuzzyUrlError as e:
|
||||
raise cmdexc.CommandError(e)
|
||||
self._tabs.tabopen(url, background=True, explicit=True)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def undo(self):
|
||||
"""Re-open a closed tab (optionally skipping [count] closed tabs)."""
|
||||
@ -559,7 +488,7 @@ class CommandDispatcher:
|
||||
else:
|
||||
raise cmdexc.CommandError("Last tab")
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd', nargs=(0, 1))
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def paste(self, sel=False, tab=False):
|
||||
"""Open a page from the clipboard.
|
||||
|
||||
@ -589,16 +518,7 @@ class CommandDispatcher:
|
||||
widget.openurl(url)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def paste_tab(self, sel=False):
|
||||
"""Open a page from the clipboard in a new tab.
|
||||
|
||||
Args:
|
||||
sel: True to use primary selection, False to use clipboard
|
||||
"""
|
||||
self.paste(sel, True)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def tab_focus(self, index=None, count=None):
|
||||
def tab_focus(self, index : int = None, count=None):
|
||||
"""Select the tab given as argument/[count].
|
||||
|
||||
Args:
|
||||
@ -622,7 +542,7 @@ class CommandDispatcher:
|
||||
idx))
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def tab_move(self, direction=None, count=None):
|
||||
def tab_move(self, direction : ('+', '-') = None, count=None):
|
||||
"""Move the current tab.
|
||||
|
||||
Args:
|
||||
@ -698,26 +618,19 @@ class CommandDispatcher:
|
||||
quickmarks.prompt_save(self._tabs.current_url())
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def quickmark_load(self, name):
|
||||
def quickmark_load(self, name, tab=False, bg=False):
|
||||
"""Load a quickmark."""
|
||||
urlstr = quickmarks.get(name)
|
||||
url = QUrl(urlstr)
|
||||
if not url.isValid():
|
||||
raise cmdexc.CommandError("Invalid URL {} ({})".format(
|
||||
urlstr, url.errorString()))
|
||||
self._current_widget().openurl(url)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def quickmark_load_tab(self, name):
|
||||
"""Load a quickmark in a new tab."""
|
||||
url = quickmarks.get(name)
|
||||
self._tabs.tabopen(url, background=False, explicit=True)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def quickmark_load_tab_bg(self, name):
|
||||
"""Load a quickmark in a new background tab."""
|
||||
url = quickmarks.get(name)
|
||||
self._tabs.tabopen(url, background=True, explicit=True)
|
||||
if tab:
|
||||
self._tabs.tabopen(url, background=False, explicit=True)
|
||||
elif bg:
|
||||
self._tabs.tabopen(url, background=True, explicit=True)
|
||||
else:
|
||||
self._current_widget().openurl(url)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd', name='inspector')
|
||||
def toggle_inspector(self):
|
||||
|
40
qutebrowser/commands/argparser.py
Normal file
40
qutebrowser/commands/argparser.py
Normal file
@ -0,0 +1,40 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
# qutebrowser is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# qutebrowser is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""argparse.ArgumentParser subclass to parse qutebrowser commands."""
|
||||
|
||||
import argparse
|
||||
|
||||
|
||||
class ArgumentParserError(Exception):
|
||||
|
||||
"""Exception raised when the ArgumentParser signals an error."""
|
||||
|
||||
|
||||
class ArgumentParser(argparse.ArgumentParser):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(add_help=False)
|
||||
|
||||
def exit(self, status=0, msg=None):
|
||||
raise AssertionError('exit called, this should never happen. '
|
||||
'Status: {}, message: {}'.format(status, msg))
|
||||
|
||||
def error(self, msg):
|
||||
raise ArgumentParserError(msg)
|
@ -23,11 +23,12 @@ Module attributes:
|
||||
cmd_dict: A mapping from command-strings to command objects.
|
||||
"""
|
||||
|
||||
import enum
|
||||
import inspect
|
||||
import collections
|
||||
|
||||
from qutebrowser.utils import usertypes, qtutils
|
||||
from qutebrowser.commands import command, cmdexc
|
||||
from qutebrowser.utils import usertypes, qtutils, log
|
||||
from qutebrowser.commands import command, cmdexc, argparser
|
||||
|
||||
cmd_dict = {}
|
||||
|
||||
@ -68,23 +69,19 @@ def arg_or_count(arg, count, default=None, countzero=None):
|
||||
The value to use.
|
||||
|
||||
Raise:
|
||||
ValueError: If nothing was set or the value couldn't be converted to
|
||||
an integer.
|
||||
ValueError: If nothing was set.
|
||||
"""
|
||||
if count is not None and arg is not None:
|
||||
raise ValueError("Both count and argument given!")
|
||||
elif arg is not None:
|
||||
try:
|
||||
return int(arg)
|
||||
except ValueError:
|
||||
raise ValueError("Invalid number: {}".format(arg))
|
||||
return arg
|
||||
elif count is not None:
|
||||
if countzero is not None and count == 0:
|
||||
return countzero
|
||||
else:
|
||||
return int(count)
|
||||
return count
|
||||
elif default is not None:
|
||||
return int(default)
|
||||
return default
|
||||
else:
|
||||
raise ValueError("Either count or argument have to be set!")
|
||||
|
||||
@ -99,7 +96,6 @@ class register: # pylint: disable=invalid-name
|
||||
Attributes:
|
||||
instance: The instance to be used as "self", as a dotted string.
|
||||
name: The name (as string) or names (as list) of the command.
|
||||
nargs: A (minargs, maxargs) tuple of valid argument counts, or an int.
|
||||
split: Whether to split the arguments.
|
||||
hide: Whether to hide the command or not.
|
||||
completion: Which completion to use for arguments, as a list of
|
||||
@ -107,11 +103,18 @@ class register: # pylint: disable=invalid-name
|
||||
modes/not_modes: List of modes to use/not use.
|
||||
needs_js: If javascript is needed for this command.
|
||||
debug: Whether this is a debugging command (only shown with --debug).
|
||||
ignore_args: Whether to ignore the arguments of the function.
|
||||
|
||||
Class attributes:
|
||||
AnnotationInfo: Named tuple for info from an annotation.
|
||||
"""
|
||||
|
||||
def __init__(self, instance=None, name=None, nargs=None, split=True,
|
||||
hide=False, completion=None, modes=None, not_modes=None,
|
||||
needs_js=False, debug=False):
|
||||
AnnotationInfo = collections.namedtuple('AnnotationInfo',
|
||||
'kwargs, typ, name, flag')
|
||||
|
||||
def __init__(self, instance=None, name=None, split=True, hide=False,
|
||||
completion=None, modes=None, not_modes=None, needs_js=False,
|
||||
debug=False, ignore_args=False):
|
||||
"""Save decorator arguments.
|
||||
|
||||
Gets called on parse-time with the decorator arguments.
|
||||
@ -125,13 +128,13 @@ class register: # pylint: disable=invalid-name
|
||||
self.name = name
|
||||
self.split = split
|
||||
self.hide = hide
|
||||
self.nargs = nargs
|
||||
self.instance = instance
|
||||
self.completion = completion
|
||||
self.modes = modes
|
||||
self.not_modes = not_modes
|
||||
self.needs_js = needs_js
|
||||
self.debug = debug
|
||||
self.ignore_args = ignore_args
|
||||
if modes is not None:
|
||||
for m in modes:
|
||||
if not isinstance(m, usertypes.KeyMode):
|
||||
@ -155,74 +158,156 @@ class register: # pylint: disable=invalid-name
|
||||
Return:
|
||||
The original function (unmodified).
|
||||
"""
|
||||
names = []
|
||||
if self.name is None:
|
||||
name = func.__name__.lower().replace('_', '-')
|
||||
else:
|
||||
name = self.name
|
||||
if isinstance(name, str):
|
||||
mainname = name
|
||||
names.append(name)
|
||||
else:
|
||||
mainname = name[0]
|
||||
names += name
|
||||
if mainname in cmd_dict:
|
||||
names = self._get_names(func)
|
||||
log.commands.vdebug("Registering command {}".format(names[0]))
|
||||
if any(name in cmd_dict for name in names):
|
||||
raise ValueError("{} is already registered!".format(name))
|
||||
argspec = inspect.getfullargspec(func)
|
||||
if 'self' in argspec.args and self.instance is None:
|
||||
raise ValueError("{} is a class method, but instance was not "
|
||||
"given!".format(mainname))
|
||||
count, nargs = self._get_nargs_count(argspec)
|
||||
if func.__doc__ is not None:
|
||||
desc = func.__doc__.splitlines()[0].strip()
|
||||
else:
|
||||
desc = ""
|
||||
has_count, desc, parser = self._inspect_func(func)
|
||||
cmd = command.Command(
|
||||
name=mainname, split=self.split, hide=self.hide, nargs=nargs,
|
||||
count=count, desc=desc, instance=self.instance, handler=func,
|
||||
name=names[0], split=self.split, hide=self.hide, count=has_count,
|
||||
desc=desc, instance=self.instance, handler=func,
|
||||
completion=self.completion, modes=self.modes,
|
||||
not_modes=self.not_modes, needs_js=self.needs_js, debug=self.debug)
|
||||
not_modes=self.not_modes, needs_js=self.needs_js, debug=self.debug,
|
||||
parser=parser)
|
||||
for name in names:
|
||||
cmd_dict[name] = cmd
|
||||
return func
|
||||
|
||||
def _get_nargs_count(self, spec):
|
||||
"""Get the number of command-arguments and count-support for a func.
|
||||
def _get_names(self, func):
|
||||
"""Get the name(s) which should be used for the current command.
|
||||
|
||||
If the name hasn't been overridden explicitely, the function name is
|
||||
transformed.
|
||||
|
||||
If it has been set, it can either be a string which is
|
||||
used directly, or an iterable.
|
||||
|
||||
Args:
|
||||
spec: A FullArgSpec as returned by inspect.
|
||||
func: The function to get the name for.
|
||||
|
||||
Return:
|
||||
A (count, (minargs, maxargs)) tuple, with maxargs=None if there are
|
||||
infinite args. count is True if the function supports count, else
|
||||
False.
|
||||
|
||||
Mapping from old nargs format to (minargs, maxargs):
|
||||
? (0, 1)
|
||||
N (N, N)
|
||||
+ (1, None)
|
||||
* (0, None)
|
||||
A list of names, with the main name being the first item.
|
||||
"""
|
||||
count = 'count' in spec.args
|
||||
# we assume count always has a default (and it should!)
|
||||
if self.nargs is not None:
|
||||
# If nargs is overriden, use that.
|
||||
if isinstance(self.nargs, collections.Iterable):
|
||||
# Iterable (min, max)
|
||||
# pylint: disable=unpacking-non-sequence
|
||||
minargs, maxargs = self.nargs
|
||||
else:
|
||||
# Single int
|
||||
minargs, maxargs = self.nargs, self.nargs
|
||||
if self.name is None:
|
||||
return [func.__name__.lower().replace('_', '-')]
|
||||
elif isinstance(self.name, str):
|
||||
return [self.name]
|
||||
else:
|
||||
defaultcount = (len(spec.defaults) if spec.defaults is not None
|
||||
else 0)
|
||||
argcount = len(spec.args)
|
||||
if 'self' in spec.args:
|
||||
argcount -= 1
|
||||
minargs = argcount - defaultcount
|
||||
if spec.varargs is not None:
|
||||
maxargs = None
|
||||
return self.name
|
||||
|
||||
def _inspect_func(self, func):
|
||||
"""Inspect a function to get useful informations from it.
|
||||
|
||||
Args:
|
||||
func: The function to look at.
|
||||
|
||||
Return:
|
||||
A (has_count, desc, parser) tuple.
|
||||
has_count: Whether the command supports a count.
|
||||
desc: The description of the command.
|
||||
parser: The ArgumentParser to use when parsing the commandline.
|
||||
"""
|
||||
signature = inspect.signature(func)
|
||||
if 'self' in signature.parameters and self.instance is None:
|
||||
raise ValueError("{} is a class method, but instance was not "
|
||||
"given!".format(mainname))
|
||||
has_count = 'count' in signature.parameters
|
||||
parser = argparser.ArgumentParser()
|
||||
if func.__doc__ is not None:
|
||||
desc = func.__doc__.splitlines()[0].strip()
|
||||
else:
|
||||
desc = ""
|
||||
if not self.ignore_args:
|
||||
for param in signature.parameters.values():
|
||||
if param.name in ('self', 'count'):
|
||||
continue
|
||||
args = []
|
||||
kwargs = {}
|
||||
annotation_info = self._parse_annotation(param)
|
||||
if annotation_info.typ is not None:
|
||||
typ = annotation_info.typ
|
||||
else:
|
||||
typ = self._infer_type(param)
|
||||
kwargs.update(self._type_to_argparse(typ))
|
||||
kwargs.update(annotation_info.kwargs)
|
||||
if (param.kind == inspect.Parameter.VAR_POSITIONAL and
|
||||
'nargs' not in kwargs): # annotation_info overrides it
|
||||
kwargs['nargs'] = '*'
|
||||
is_flag = typ == bool
|
||||
args += self._get_argparse_args(param, annotation_info,
|
||||
is_flag)
|
||||
log.commands.vdebug('Adding argument {} of type {} -> '
|
||||
'args {}, kwargs {}'.format(
|
||||
param.name, typ, args, kwargs))
|
||||
parser.add_argument(*args, **kwargs)
|
||||
return has_count, desc, parser
|
||||
|
||||
def _get_argparse_args(self, param, annotation_info, is_flag):
|
||||
"""Get a list of positional argparse arguments.
|
||||
|
||||
Args:
|
||||
param: The inspect.Parameter instance for the current parameter.
|
||||
annotation_info: An AnnotationInfo tuple for the parameter.
|
||||
is_flag: Whether the option is a flag or not.
|
||||
"""
|
||||
args = []
|
||||
name = annotation_info.name or param.name
|
||||
shortname = annotation_info.flag or param.name[0]
|
||||
if is_flag:
|
||||
args.append('--{}'.format(name))
|
||||
args.append('-{}'.format(shortname))
|
||||
else:
|
||||
args.append(name)
|
||||
return args
|
||||
|
||||
def _parse_annotation(self, param):
|
||||
"""Get argparse arguments and type from a parameter annotation.
|
||||
|
||||
Args:
|
||||
param: A inspect.Parameter instance.
|
||||
|
||||
Return:
|
||||
An AnnotationInfo namedtuple.
|
||||
kwargs: A dict of keyword args to add to the
|
||||
argparse.ArgumentParser.add_argument call.
|
||||
typ: The type to use for this argument.
|
||||
flag: The short name/flag if overridden.
|
||||
name: The long name if overridden.
|
||||
"""
|
||||
info = {'kwargs': {}, 'typ': None, 'flag': None, 'name': None}
|
||||
log.commands.vdebug("Parsing annotation {}".format(param.annotation))
|
||||
if param.annotation is not inspect.Parameter.empty:
|
||||
if isinstance(param.annotation, dict):
|
||||
for field in ('type', 'flag', 'name'):
|
||||
if field in param.annotation:
|
||||
info[field] = param.annotation[field]
|
||||
del param.annotation[field]
|
||||
info['kwargs'] = param.annotation
|
||||
else:
|
||||
maxargs = argcount - int(count) # -1 if count is defined
|
||||
return (count, (minargs, maxargs))
|
||||
info['typ'] = param.annotation
|
||||
return self.AnnotationInfo(**info)
|
||||
|
||||
def _infer_type(self, param):
|
||||
"""Get the type of an argument from its default value."""
|
||||
if param.default is None or param.default is inspect.Parameter.empty:
|
||||
return None
|
||||
else:
|
||||
return type(param.default)
|
||||
|
||||
def _type_to_argparse(self, typ):
|
||||
"""Get argparse keyword arguments based on a type."""
|
||||
kwargs = {}
|
||||
try:
|
||||
is_enum = issubclass(typ, enum.Enum)
|
||||
except TypeError:
|
||||
is_enum = False
|
||||
if isinstance(typ, tuple):
|
||||
kwargs['choices'] = typ
|
||||
elif is_enum:
|
||||
kwargs['choices'] = [e.name.replace('_', '-') for e in typ]
|
||||
elif typ is bool:
|
||||
kwargs['action'] = 'store_true'
|
||||
elif typ is not None:
|
||||
kwargs['type'] = typ
|
||||
|
||||
return kwargs
|
||||
|
@ -19,11 +19,11 @@
|
||||
|
||||
"""Contains the Command class, a skeleton for a command."""
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication, QUrl
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
from PyQt5.QtWebKit import QWebSettings
|
||||
|
||||
from qutebrowser.commands import cmdexc
|
||||
from qutebrowser.utils import log, utils
|
||||
from qutebrowser.commands import cmdexc, argparser
|
||||
from qutebrowser.utils import log, utils, message
|
||||
|
||||
|
||||
class Command:
|
||||
@ -34,7 +34,6 @@ class Command:
|
||||
name: The main name of the command.
|
||||
split: Whether to split the arguments.
|
||||
hide: Whether to hide the arguments or not.
|
||||
nargs: A (minargs, maxargs) tuple, maxargs = None if there's no limit.
|
||||
count: Whether the command supports a count, or not.
|
||||
desc: The description of the command.
|
||||
instance: How to get to the "self" argument of the handler.
|
||||
@ -43,20 +42,20 @@ class Command:
|
||||
completion: Completions to use for arguments, as a list of strings.
|
||||
needs_js: Whether the command needs javascript enabled
|
||||
debug: Whether this is a debugging command (only shown with --debug).
|
||||
parser: The ArgumentParser to use to parse this command.
|
||||
"""
|
||||
|
||||
# TODO:
|
||||
# we should probably have some kind of typing / argument casting for args
|
||||
# this might be combined with help texts or so as well
|
||||
|
||||
def __init__(self, name, split, hide, nargs, count, desc, instance,
|
||||
handler, completion, modes, not_modes, needs_js, debug):
|
||||
def __init__(self, name, split, hide, count, desc, instance, handler,
|
||||
completion, modes, not_modes, needs_js, debug, parser):
|
||||
# I really don't know how to solve this in a better way, I tried.
|
||||
# pylint: disable=too-many-arguments
|
||||
self.name = name
|
||||
self.split = split
|
||||
self.hide = hide
|
||||
self.nargs = nargs
|
||||
self.count = count
|
||||
self.desc = desc
|
||||
self.instance = instance
|
||||
@ -66,15 +65,12 @@ class Command:
|
||||
self.not_modes = not_modes
|
||||
self.needs_js = needs_js
|
||||
self.debug = debug
|
||||
self.parser = parser
|
||||
|
||||
def check(self, args):
|
||||
"""Check if the argument count is valid and the command is permitted.
|
||||
|
||||
Args:
|
||||
args: The supplied arguments
|
||||
def _check_prerequisites(self):
|
||||
"""Check if the command is permitted to run currently.
|
||||
|
||||
Raise:
|
||||
ArgumentCountError if the argument count is wrong.
|
||||
PrerequisitesError if the command can't be called currently.
|
||||
"""
|
||||
# We don't use modeman.instance() here to avoid a circular import
|
||||
@ -94,20 +90,6 @@ class Command:
|
||||
QWebSettings.JavascriptEnabled):
|
||||
raise cmdexc.PrerequisitesError(
|
||||
"{}: This command needs javascript enabled.".format(self.name))
|
||||
if self.nargs[1] is None and self.nargs[0] <= len(args):
|
||||
pass
|
||||
elif self.nargs[0] <= len(args) <= self.nargs[1]:
|
||||
pass
|
||||
else:
|
||||
if self.nargs[0] == self.nargs[1]:
|
||||
argcnt = str(self.nargs[0])
|
||||
elif self.nargs[1] is None:
|
||||
argcnt = '{}-inf'.format(self.nargs[0])
|
||||
else:
|
||||
argcnt = '{}-{}'.format(self.nargs[0], self.nargs[1])
|
||||
raise cmdexc.ArgumentCountError(
|
||||
"{}: {} args expected, but got {}".format(self.name, argcnt,
|
||||
len(args)))
|
||||
|
||||
def run(self, args=None, count=None):
|
||||
"""Run the command.
|
||||
@ -120,23 +102,29 @@ class Command:
|
||||
"""
|
||||
dbgout = ["command called:", self.name]
|
||||
if args:
|
||||
dbgout += args
|
||||
dbgout.append(str(args))
|
||||
if count is not None:
|
||||
dbgout.append("(count={})".format(count))
|
||||
log.commands.debug(' '.join(dbgout))
|
||||
|
||||
posargs = []
|
||||
kwargs = {}
|
||||
app = QCoreApplication.instance()
|
||||
|
||||
# Replace variables (currently only {url})
|
||||
new_args = []
|
||||
for arg in args:
|
||||
if arg == '{url}':
|
||||
urlstr = app.mainwindow.tabs.current_url().toString(
|
||||
QUrl.FullyEncoded | QUrl.RemovePassword)
|
||||
new_args.append(urlstr)
|
||||
try:
|
||||
namespace = self.parser.parse_args(args)
|
||||
except argparser.ArgumentParserError as e:
|
||||
message.error(str(e))
|
||||
return
|
||||
|
||||
for name, arg in vars(namespace).items():
|
||||
if isinstance(arg, list):
|
||||
# If we got a list, we assume that's our *args, so we don't add
|
||||
# it to kwargs.
|
||||
# FIXME: This approach is rather naive, but for now it works.
|
||||
posargs += arg
|
||||
else:
|
||||
new_args.append(arg)
|
||||
kwargs[name] = arg
|
||||
|
||||
if self.instance is not None:
|
||||
# Add the 'self' parameter.
|
||||
@ -144,9 +132,12 @@ class Command:
|
||||
obj = app
|
||||
else:
|
||||
obj = utils.dotted_getattr(app, self.instance)
|
||||
new_args.insert(0, obj)
|
||||
posargs.insert(0, obj)
|
||||
|
||||
if count is not None and self.count:
|
||||
kwargs = {'count': count}
|
||||
|
||||
self.handler(*new_args, **kwargs)
|
||||
self._check_prerequisites()
|
||||
log.commands.debug('posargs: {}'.format(posargs))
|
||||
log.commands.debug('kwargs: {}'.format(kwargs))
|
||||
self.handler(*posargs, **kwargs)
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
"""Module containing command managers (SearchRunner and CommandRunner)."""
|
||||
|
||||
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject
|
||||
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QCoreApplication, QUrl
|
||||
from PyQt5.QtWebKitWidgets import QWebPage
|
||||
|
||||
from qutebrowser.config import config
|
||||
@ -198,14 +198,18 @@ class CommandRunner:
|
||||
parts = text.strip().split(maxsplit=1)
|
||||
if not parts:
|
||||
raise cmdexc.NoSuchCommandError("No command given")
|
||||
cmdstr = parts[0]
|
||||
elif len(parts) > 1:
|
||||
cmdstr, argstr = parts
|
||||
else:
|
||||
cmdstr = parts[0]
|
||||
argstr = None
|
||||
if aliases:
|
||||
new_cmd = self._get_alias(text, alias_no_args)
|
||||
if new_cmd is not None:
|
||||
log.commands.debug("Re-parsing with '{}'.".format(new_cmd))
|
||||
return self.parse(new_cmd, aliases=False)
|
||||
try:
|
||||
cmd = cmdutils.cmd_dict[cmdstr]
|
||||
self._cmd = cmdutils.cmd_dict[cmdstr]
|
||||
except KeyError:
|
||||
if fallback:
|
||||
parts = text.split(' ')
|
||||
@ -215,36 +219,38 @@ class CommandRunner:
|
||||
else:
|
||||
raise cmdexc.NoSuchCommandError(
|
||||
'{}: no such command'.format(cmdstr))
|
||||
if len(parts) == 1:
|
||||
args = []
|
||||
elif cmd.split:
|
||||
args = utils.safe_shlex_split(parts[1])
|
||||
if argstr is None:
|
||||
self._args = []
|
||||
elif self._cmd.split:
|
||||
self._args = utils.safe_shlex_split(argstr)
|
||||
else:
|
||||
args = parts[1].split(maxsplit=cmd.nargs[0] - 1)
|
||||
self._cmd = cmd
|
||||
self._args = args
|
||||
retargs = args[:]
|
||||
# If split=False, we still want to split the flags, but not
|
||||
# everything after that.
|
||||
# We first split the arg string and check the index of the first
|
||||
# non-flag args, then we re-split again properly.
|
||||
# example:
|
||||
#
|
||||
# input: "--foo -v bar baz"
|
||||
# first split: ['--foo', '-v', 'bar', 'baz']
|
||||
# 0 1 2 3
|
||||
# second split: ['--foo', '-v', 'bar baz']
|
||||
# (maxsplit=2)
|
||||
split_args = argstr.split()
|
||||
for i, arg in enumerate(split_args):
|
||||
if not arg.startswith('-'):
|
||||
self._args = argstr.split(maxsplit=i)
|
||||
break
|
||||
else:
|
||||
# If there are only flags, we got it right on the first try
|
||||
# already.
|
||||
self._args = split_args
|
||||
retargs = self._args[:]
|
||||
if text.endswith(' '):
|
||||
retargs.append('')
|
||||
return [cmdstr] + retargs
|
||||
|
||||
def _check(self):
|
||||
"""Check if the argument count for the command is correct."""
|
||||
self._cmd.check(self._args)
|
||||
|
||||
def _run(self, count=None):
|
||||
"""Run a command with an optional count.
|
||||
|
||||
Args:
|
||||
count: Count to pass to the command.
|
||||
"""
|
||||
if count is not None:
|
||||
self._cmd.run(self._args, count=count)
|
||||
else:
|
||||
self._cmd.run(self._args)
|
||||
|
||||
def run(self, text, count=None):
|
||||
"""Parse a command from a line of text.
|
||||
"""Parse a command from a line of text and run it.
|
||||
|
||||
Args:
|
||||
text: The text to parse.
|
||||
@ -255,8 +261,15 @@ class CommandRunner:
|
||||
self.run(sub, count)
|
||||
return
|
||||
self.parse(text)
|
||||
self._check()
|
||||
self._run(count=count)
|
||||
app = QCoreApplication.instance()
|
||||
cur_url = app.mainwindow.tabs.current_url().toString(
|
||||
QUrl.FullyEncoded | QUrl.RemovePassword)
|
||||
self._args = [cur_url if e == '{url}' else e for e in self._args]
|
||||
if count is not None:
|
||||
self._cmd.run(self._args, count=count)
|
||||
else:
|
||||
self._cmd.run(self._args)
|
||||
|
||||
|
||||
@pyqtSlot(str, int)
|
||||
def run_safely(self, text, count=None):
|
||||
|
@ -336,7 +336,7 @@ class ConfigManager(QObject):
|
||||
@cmdutils.register(name='set', instance='config',
|
||||
completion=[Completion.section, Completion.option,
|
||||
Completion.value])
|
||||
def set_wrapper(self, sectname, optname, value):
|
||||
def set_command(self, sectname, optname, value, temp=False):
|
||||
"""Set an option.
|
||||
|
||||
//
|
||||
@ -347,36 +347,15 @@ class ConfigManager(QObject):
|
||||
sectname: The section where the option is in.
|
||||
optname: The name of the option.
|
||||
value: The value to set.
|
||||
temp: Set value temporarely.
|
||||
"""
|
||||
try:
|
||||
self.set('conf', sectname, optname, value)
|
||||
self.set('temp' if temp else 'conf', sectname, optname, value)
|
||||
except (NoOptionError, NoSectionError, configtypes.ValidationError,
|
||||
ValueError) as e:
|
||||
raise cmdexc.CommandError("set: {} - {}".format(
|
||||
e.__class__.__name__, e))
|
||||
|
||||
@cmdutils.register(name='set-temp', instance='config',
|
||||
completion=[Completion.section, Completion.option,
|
||||
Completion.value])
|
||||
def set_temp_wrapper(self, sectname, optname, value):
|
||||
"""Set a temporary option.
|
||||
|
||||
//
|
||||
|
||||
Wrapper for self.set() to output exceptions in the status bar.
|
||||
|
||||
Args:
|
||||
sectname: The section where the option is in.
|
||||
optname: The name of the option.
|
||||
value: The value to set.
|
||||
"""
|
||||
try:
|
||||
self.set('temp', sectname, optname, value)
|
||||
except (NoOptionError, NoSectionError,
|
||||
configtypes.ValidationError) as e:
|
||||
raise cmdexc.CommandError("set: {} - {}".format(
|
||||
e.__class__.__name__, e))
|
||||
|
||||
def set(self, layer, sectname, optname, value):
|
||||
"""Set an option.
|
||||
|
||||
|
@ -585,11 +585,11 @@ DATA = collections.OrderedDict([
|
||||
typ.KeyBindingName(), typ.KeyBinding(),
|
||||
('o', 'set-cmd-text ":open "'),
|
||||
('go', 'set-cmd-text :open {url}'),
|
||||
('O', 'set-cmd-text ":open-tab "'),
|
||||
('gO', 'set-cmd-text :open-tab {url}'),
|
||||
('xo', 'set-cmd-text ":open-tab-bg "'),
|
||||
('xO', 'set-cmd-text :open-tab-bg {url}'),
|
||||
('ga', 'open-tab about:blank'),
|
||||
('O', 'set-cmd-text ":open -t "'),
|
||||
('gO', 'set-cmd-text :open -t {url}'),
|
||||
('xo', 'set-cmd-text ":open -b "'),
|
||||
('xO', 'set-cmd-text :open -b {url}'),
|
||||
('ga', 'open -t about:blank'),
|
||||
('d', 'tab-close'),
|
||||
('co', 'tab-only'),
|
||||
('T', 'tab-focus'),
|
||||
@ -608,8 +608,8 @@ DATA = collections.OrderedDict([
|
||||
(';I', 'hint images tab'),
|
||||
('.i', 'hint images tab-bg'),
|
||||
(';o', 'hint links fill :open {hint-url}'),
|
||||
(';O', 'hint links fill :open-tab {hint-url}'),
|
||||
('.o', 'hint links fill :open-tab-bg {hint-url}'),
|
||||
(';O', 'hint links fill :open -t {hint-url}'),
|
||||
('.o', 'hint links fill :open -b {hint-url}'),
|
||||
(';y', 'hint links yank'),
|
||||
(';Y', 'hint links yank-primary'),
|
||||
(';r', 'hint links rapid'),
|
||||
@ -619,33 +619,33 @@ DATA = collections.OrderedDict([
|
||||
('k', 'scroll 0 -50'),
|
||||
('l', 'scroll 50 0'),
|
||||
('u', 'undo'),
|
||||
('gg', 'scroll-perc-y 0'),
|
||||
('G', 'scroll-perc-y'),
|
||||
('gg', 'scroll-perc 0'),
|
||||
('G', 'scroll-perc'),
|
||||
('n', 'search-next'),
|
||||
('N', 'search-prev'),
|
||||
('i', 'enter-mode insert'),
|
||||
('yy', 'yank'),
|
||||
('yY', 'yank sel'),
|
||||
('yt', 'yank-title'),
|
||||
('yT', 'yank-title sel'),
|
||||
('yY', 'yank -s'),
|
||||
('yt', 'yank -t'),
|
||||
('yT', 'yank -ts'),
|
||||
('pp', 'paste'),
|
||||
('pP', 'paste sel'),
|
||||
('Pp', 'paste-tab'),
|
||||
('PP', 'paste-tab sel'),
|
||||
('pP', 'paste -s'),
|
||||
('Pp', 'paste -t'),
|
||||
('PP', 'paste -ts'),
|
||||
('m', 'quickmark-save'),
|
||||
('b', 'set-cmd-text ":quickmark-load "'),
|
||||
('B', 'set-cmd-text ":quickmark-load-tab "'),
|
||||
('B', 'set-cmd-text ":quickmark-load -t "'),
|
||||
('sf', 'save'),
|
||||
('ss', 'set-cmd-text ":set "'),
|
||||
('sl', 'set-cmd-text ":set-temp "'),
|
||||
('sl', 'set-cmd-text ":set -t"'),
|
||||
('sk', 'set-cmd-text ":set keybind "'),
|
||||
('-', 'zoom-out'),
|
||||
('+', 'zoom-in'),
|
||||
('=', 'zoom'),
|
||||
('[[', 'prev-page'),
|
||||
(']]', 'next-page'),
|
||||
('{{', 'prev-page-tab'),
|
||||
('}}', 'next-page-tab'),
|
||||
('{{', 'prev-page -t'),
|
||||
('}}', 'next-page -t'),
|
||||
('wi', 'inspector'),
|
||||
('gd', 'download-page'),
|
||||
('ad', 'cancel-download'),
|
||||
@ -654,7 +654,7 @@ DATA = collections.OrderedDict([
|
||||
('<Ctrl-Q>', 'quit'),
|
||||
('<Ctrl-Shift-T>', 'undo'),
|
||||
('<Ctrl-W>', 'tab-close'),
|
||||
('<Ctrl-T>', 'open-tab about:blank'),
|
||||
('<Ctrl-T>', 'open -t about:blank'),
|
||||
('<Ctrl-F>', 'scroll-page 0 1'),
|
||||
('<Ctrl-B>', 'scroll-page 0 -1'),
|
||||
('<Ctrl-D>', 'scroll-page 0 0.5'),
|
||||
|
@ -32,7 +32,7 @@ from qutebrowser.config import config, style
|
||||
|
||||
|
||||
@cmdutils.register(debug=True)
|
||||
def debug_crash(typ='exception'):
|
||||
def debug_crash(typ : ('exception', 'segfault') = 'exception'):
|
||||
"""Crash for debugging purposes.
|
||||
|
||||
Args:
|
||||
|
@ -35,15 +35,14 @@ def init():
|
||||
_commandrunner = runners.CommandRunner()
|
||||
|
||||
|
||||
@cmdutils.register(nargs=(2, None))
|
||||
def later(ms, *command):
|
||||
@cmdutils.register()
|
||||
def later(ms : int, *command : {'nargs': '+'}):
|
||||
"""Execute a command after some time.
|
||||
|
||||
Args:
|
||||
ms: How many milliseconds to wait.
|
||||
command: The command/args to run.
|
||||
"""
|
||||
ms = int(ms)
|
||||
timer = usertypes.Timer(name='later')
|
||||
timer.setSingleShot(True)
|
||||
if ms < 0:
|
||||
|
@ -141,7 +141,7 @@ class MainWindow(QWidget):
|
||||
if rect.isValid():
|
||||
self.completion.setGeometry(rect)
|
||||
|
||||
@cmdutils.register(instance='mainwindow', name=['quit', 'q'], nargs=0)
|
||||
@cmdutils.register(instance='mainwindow', name=['quit', 'q'])
|
||||
def close(self):
|
||||
"""Quit qutebrowser.
|
||||
|
||||
|
@ -221,20 +221,20 @@ class WebView(QWebView):
|
||||
e: The QMouseEvent.
|
||||
"""
|
||||
if self._force_open_target is not None:
|
||||
self.open_target = self._force_open_target
|
||||
self._open_target = self._force_open_target
|
||||
self._force_open_target = None
|
||||
log.mouse.debug("Setting force target: {}".format(
|
||||
self.open_target))
|
||||
self._open_target))
|
||||
elif (e.button() == Qt.MidButton or
|
||||
e.modifiers() & Qt.ControlModifier):
|
||||
if config.get('tabs', 'background-tabs'):
|
||||
self.open_target = usertypes.ClickTarget.tab_bg
|
||||
self._open_target = usertypes.ClickTarget.tab_bg
|
||||
else:
|
||||
self.open_target = usertypes.ClickTarget.tab
|
||||
self._open_target = usertypes.ClickTarget.tab
|
||||
log.mouse.debug("Middle click, setting target: {}".format(
|
||||
self.open_target))
|
||||
self._open_target))
|
||||
else:
|
||||
self.open_target = usertypes.ClickTarget.normal
|
||||
self._open_target = usertypes.ClickTarget.normal
|
||||
log.mouse.debug("Normal click, setting normal target")
|
||||
|
||||
def shutdown(self):
|
||||
|
Loading…
Reference in New Issue
Block a user