First kinda working version

This commit is contained in:
Florian Bruhin 2014-03-03 21:06:10 +01:00
parent 97ae3adb4a
commit af0b6901be
6 changed files with 68 additions and 86 deletions

View File

@ -54,7 +54,8 @@ from qutebrowser.widgets.mainwindow import MainWindow
from qutebrowser.widgets.crash import CrashDialog
from qutebrowser.commands.keys import KeyParser
from qutebrowser.utils.appdirs import AppDirs
from qutebrowser.utils.misc import set_trace
from qutebrowser.utils.misc import dotted_getattr
from qutebrowser.utils.debug import set_trace
class QuteBrowser(QApplication):
@ -180,6 +181,14 @@ class QuteBrowser(QApplication):
Registers all commands, connects its signals, and sets up keyparser.
"""
for key, cmd in sorted(cmdutils.cmd_dict.items()):
cmd.signal.connect(self.command_handler)
if cmd.instance is not None:
func = '.'.join([cmd.instance if cmd.instance else 'app',
cmd.handler.__name__])
else:
func = cmd.handler.__name__
logging.debug("Registered command: {} -> {}".format(key, func))
self.keyparser.from_config_sect(config.config['keybind'])
def _process_init_args(self):
@ -322,7 +331,7 @@ class QuteBrowser(QApplication):
logging.debug("maybe_quit quitting.")
self.quit()
@cmdutils.register(instance='app', split_args=False)
@cmdutils.register(instance='', split_args=False)
def pyeval(self, s):
"""Evaluate a python string and display the results as a webpage.
@ -340,7 +349,7 @@ class QuteBrowser(QApplication):
qutescheme.pyeval_output = out
self.mainwindow.tabs.cur.openurl('qute:pyeval')
@cmdutils.register(instance='app', hide=True)
@cmdutils.register(instance='', hide=True)
def crash(self):
"""Crash for debugging purposes.
@ -353,7 +362,7 @@ class QuteBrowser(QApplication):
raise Exception("Forced crash")
@pyqtSlot()
@cmdutils.register(instance='app', name=['q', 'quit'], nargs=0)
@cmdutils.register(instance='', name=['q', 'quit'], nargs=0)
def shutdown(self, do_quit=True):
"""Try to shutdown everything cleanly.
@ -399,3 +408,28 @@ class QuteBrowser(QApplication):
"""
logging.debug("Shutdown complete, quitting.")
self.quit()
@pyqtSlot(tuple)
def command_handler(self, tpl):
"""Handle commands which need an instance..
Args:
tpl: An (instance, func, count, args) tuple.
instance: How to get the current instance of the target object
from app.py, as a dotted string, e.g.
'mainwindow.tabs.cur'.
func: The function name to be called (as string).
count: The count given to the command, or None.
args: A list of arguments given to the command.
"""
(instance, func, count, args) = tpl
if instance == '':
obj = self
else:
obj = dotted_getattr(self, instance)
handler = getattr(obj, func)
if count is not None:
handler(*args, count=count)
else:
handler(*args)

View File

@ -21,8 +21,10 @@ import logging
from qutebrowser.commands.exceptions import ArgumentCountError
from PyQt5.QtCore import pyqtSignal, QObject
class Command:
class Command(QObject):
"""Base skeleton for a command.
@ -31,11 +33,14 @@ class Command:
"""
signal = pyqtSignal(tuple)
# FIXME:
# 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_args, hide, nargs, count, desc, handler):
def __init__(self, name, split_args, hide, nargs, count, desc, instance,
handler):
super().__init__()
self.name = name
self.split_args = split_args
@ -43,6 +48,7 @@ class Command:
self.nargs = nargs
self.count = count
self.desc = desc
self.instance = instance
self.handler = handler
def check(self, args):
@ -78,7 +84,13 @@ class Command:
dbgout.append("(count={})".format(count))
logging.debug(' '.join(dbgout))
if count is not None and self.count:
if self.instance is not None and self.count and count is not None:
self.signal.emit((self.instance, self.handler.__name__, count,
args))
elif self.instance is not None:
self.signal.emit((self.instance, self.handler.__name__, None,
args))
elif count is not None and self.count:
return self.handler(*args, count=count)
else:
return self.handler(*args)

View File

@ -1,32 +0,0 @@
# 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/>.
"""All command classes.
These are automatically propagated from commands.utils
via inspect.
A command class can set the following properties:
nargs -- Number of arguments. Either a number, '?' (0 or 1), '+' (1 or
more), or '*' (any). Default: 0
name -- The name of the command, or a list of aliases.
split_args -- If arguments should be split or not. Default: True
count -- If the command supports a count. Default: False
hide -- If the command should be hidden in tab completion. Default: False
"""

View File

@ -15,7 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Exception classes for commands.utils and commands.template.
"""Exception classes for commands.utils and commands.command.
Defined here to avoid circular dependency hell.

View File

@ -19,6 +19,7 @@
import shlex
import inspect
import logging
import functools
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject
@ -26,7 +27,7 @@ from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebKitWidgets import QWebPage
import qutebrowser.config.config as config
from qutebrowser.commands.template import Command
from qutebrowser.commands.command import Command
from qutebrowser.commands.exceptions import (ArgumentCountError,
NoSuchCommandError)
@ -62,12 +63,9 @@ class register:
names += name
count, nargs = self._get_nargs_count(func)
desc = func.__doc__.splitlines()[0].strip().rstrip('.')
if self.instance is not None:
handler = functools.partial(func, instance])
else:
handler = func
cmd = Command(mainname, self.split_args, self.hide, nargs, count, desc,
handler=handler)
cmd = Command(name=mainname, split_args=self.split_args,
hide=self.hide, nargs=nargs, count=count, desc=desc,
instance=self.instance, handler=func)
for name in names:
cmd_dict[name] = cmd
return func

View File

@ -17,37 +17,11 @@
"""Other utilities which don't fit anywhere else."""
import sys
import os.path
from PyQt5.QtCore import pyqtRemoveInputHook
#import qutebrowser.commands.utils as cmdutils
try:
# pylint: disable=import-error
from ipdb import set_trace as pdb_set_trace
except ImportError:
from pdb import set_trace as pdb_set_trace
from functools import reduce
import qutebrowser
# FIXME we can';t do this because of circular imports
#@cmdutils.register(name='settrace', hide=True)
def set_trace():
"""Set a tracepoint in the Python debugger that works with Qt.
Based on http://stackoverflow.com/a/1745965/2085149
"""
print()
print("When done debugging, remember to execute:")
print(" from PyQt5 import QtCore; QtCore.pyqtRestoreInputHook()")
print("before executing c(ontinue).")
pyqtRemoveInputHook()
return pdb_set_trace()
def read_file(filename):
"""Get the contents of a file contained with qutebrowser.
@ -63,19 +37,15 @@ def read_file(filename):
return f.read()
def trace_lines(do_trace):
"""Turn on/off printing each executed line.
def dotted_getattr(obj, path):
"""getattr supporting the dot notation.
Args:
do_trace: Whether to start tracing (True) or stop it (False).
obj: The object where to start.
path: A dotted object path as a string.
Return:
The object at path.
"""
def trace(frame, event, _):
"""Trace function passed to sys.settrace."""
print("{}, {}:{}".format(event, frame.f_code.co_filename,
frame.f_lineno))
return trace
if do_trace:
sys.settrace(trace)
else:
sys.settrace(None)
return reduce(getattr, path.split('.'), obj)