コード例 #1
0
class Text(textbase.TextBase):
    """Text displayed in the statusbar.

    Attributes:
        _normaltext: The "permanent" text. Never automatically cleared.
        _temptext: The temporary text to display.

        The temptext is shown from StatusBar when a temporary text or error is
        available. If not, the permanent text is shown.
    """

    Text = usertypes.enum('Text', ['normal', 'temp'])

    def __init__(self, parent=None):
        super().__init__(parent)
        self._normaltext = ''
        self._temptext = ''

    def set_text(self, which, text):
        """Set a text.

        Args:
            which: Which text to set, a self.Text instance.
            text: The text to set.
        """
        log.statusbar.debug("Setting {} text to '{}'.".format(
            which.name, text))
        if which is self.Text.normal:
            self._normaltext = text
        elif which is self.Text.temp:
            self._temptext = text
        else:
            raise ValueError("Invalid value {} for which!".format(which))
        self.update_text()

    @pyqtSlot(str)
    def maybe_reset_text(self, text):
        """Clear a normal text if it still matches an expected text."""
        if self._normaltext == text:
            log.statusbar.debug("Resetting: '{}'".format(text))
            self.set_text(self.Text.normal, '')
        else:
            log.statusbar.debug("Ignoring reset: '{}'".format(text))

    def update_text(self):
        """Update QLabel text when needed."""
        if self._temptext:
            self.setText(self._temptext)
        elif self._normaltext:
            self.setText(self._normaltext)
        else:
            self.setText('')
コード例 #2
0
ファイル: bar.py プロジェクト: thelazyoxymoron/qutebrowser
class ColorFlags:

    """Flags which change the appearance of the statusbar.

    Attributes:
        prompt: If we're currently in prompt-mode.
        insert: If we're currently in insert mode.
        command: If we're currently in command mode.
        mode: The current caret mode (CaretMode.off/.on/.selection).
        private: Whether this window is in private browsing mode.
        passthrough: If we're currently in passthrough-mode.
    """

    CaretMode = usertypes.enum('CaretMode', ['off', 'on', 'selection'])
    prompt = attr.ib(False)
    insert = attr.ib(False)
    command = attr.ib(False)
    caret = attr.ib(CaretMode.off)
    private = attr.ib(False)
    passthrough = attr.ib(False)

    def to_stringlist(self):
        """Get a string list of set flags used in the stylesheet.

        This also combines flags in ways they're used in the sheet.
        """
        strings = []
        if self.prompt:
            strings.append('prompt')
        if self.insert:
            strings.append('insert')
        if self.command:
            strings.append('command')
        if self.private:
            strings.append('private')
        if self.passthrough:
            strings.append('passthrough')

        if self.private and self.command:
            strings.append('private-command')

        if self.caret == self.CaretMode.on:
            strings.append('caret')
        elif self.caret == self.CaretMode.selection:
            strings.append('caret-selection')
        else:
            assert self.caret == self.CaretMode.off

        return strings
コード例 #3
0
class MessageMock:
    """Helper object for message_mock.

    Attributes:
        _monkeypatch: The pytest monkeypatch fixture.
        MessageLevel: An enum with possible message levels.
        Message: A namedtuple representing a message.
        messages: A list of Message tuples.
    """

    Message = collections.namedtuple('Message',
                                     ['level', 'win_id', 'text', 'immediate'])
    MessageLevel = usertypes.enum('Level', ('error', 'info', 'warning'))

    def __init__(self, monkeypatch):
        self._monkeypatch = monkeypatch
        self.messages = []

    def _handle(self, level, win_id, text, immediately=False):
        self.messages.append(self.Message(level, win_id, text, immediately))

    def _handle_error(self, *args, **kwargs):
        self._handle(self.MessageLevel.error, *args, **kwargs)

    def _handle_info(self, *args, **kwargs):
        self._handle(self.MessageLevel.info, *args, **kwargs)

    def _handle_warning(self, *args, **kwargs):
        self._handle(self.MessageLevel.warning, *args, **kwargs)

    def getmsg(self):
        """Get the only message in self.messages.

        Raises ValueError if there are multiple or no messages.
        """
        if len(self.messages) != 1:
            raise ValueError("Got {} messages but expected a single "
                             "one.".format(len(self.messages)))
        return self.messages[0]

    def patch(self, module_path):
        """Patch message.* in the given module (as a string)."""
        self._monkeypatch.setattr(module_path + '.error', self._handle_error)
        self._monkeypatch.setattr(module_path + '.info', self._handle_info)
        self._monkeypatch.setattr(module_path + '.warning',
                                  self._handle_warning)
コード例 #4
0
ファイル: webelem.py プロジェクト: axs221/qutebrowser
    FILTERS: A dictionary of filter functions for the modes.
             The filter for "links" filters javascript:-links and a-tags
             without "href".
"""

import collections.abc
import functools

from PyQt5.QtCore import QRect, QUrl
from PyQt5.QtWebKit import QWebElement

from qutebrowser.config import config
from qutebrowser.utils import log, usertypes, utils


Group = usertypes.enum("Group", ["all", "links", "images", "url", "prevnext", "focus"])


SELECTORS = {
    Group.all: (
        "a, area, textarea, select, input:not([type=hidden]), button, "
        "frame, iframe, link, [onclick], [onmousedown], [role=link], "
        "[role=option], [role=button], img"
    ),
    Group.links: "a, area, link, [role=link]",
    Group.images: "img",
    Group.url: "[src], [href]",
    Group.prevnext: "a, area, button, link, [role=button]",
    Group.focus: "*:focus",
}
コード例 #5
0
# 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/>.
"""Tests for qutebrowser.commands.argparser."""

import inspect

import pytest
from PyQt5.QtCore import QUrl

from qutebrowser.commands import argparser, cmdexc
from qutebrowser.utils import usertypes

Enum = usertypes.enum('Enum', ['foo', 'foo_bar'])


class TestArgumentParser:
    @pytest.fixture
    def parser(self):
        return argparser.ArgumentParser('foo')

    def test_name(self, parser):
        assert parser.name == 'foo'

    def test_exit(self, parser):
        parser.add_argument('--help', action='help')

        with pytest.raises(argparser.ArgumentParserExit) as excinfo:
            parser.parse_args(['--help'])
コード例 #6
0
ファイル: test_enum.py プロジェクト: HalosGhost/qutebrowser
 def setUp(self):
     self.enum = usertypes.enum('Enum', ['one', 'two'])
コード例 #7
0
ファイル: webelem.py プロジェクト: julianuu/qutebrowser
    SELECTORS: CSS selectors for different groups of elements.
    FILTERS: A dictionary of filter functions for the modes.
             The filter for "links" filters javascript:-links and a-tags
             without "href".
"""

import collections.abc

from PyQt5.QtCore import QUrl, Qt, QEvent, QTimer
from PyQt5.QtGui import QMouseEvent

from qutebrowser.config import config
from qutebrowser.utils import log, usertypes, utils, qtutils


Group = usertypes.enum('Group', ['all', 'links', 'images', 'url', 'prevnext',
                                 'inputs'])


SELECTORS = {
    Group.all: ('a, area, textarea, select, input:not([type=hidden]), button, '
                'frame, iframe, link, [onclick], [onmousedown], [role=link], '
                '[role=option], [role=button], img'),
    Group.links: 'a, area, link, [role=link]',
    Group.images: 'img',
    Group.url: '[src], [href]',
    Group.prevnext: 'a, area, button, link, [role=button]',
    Group.inputs: ('input[type=text], input[type=email], input[type=url], '
                   'input[type=tel], input[type=number], '
                   'input[type=password], input[type=search], '
                   'input:not([type]), textarea'),
}
コード例 #8
0
import itertools
import functools

from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QTimer, QUrl
from PyQt5.QtGui import QPalette
from PyQt5.QtWidgets import QApplication, QStyleFactory
from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtWebKitWidgets import QWebView, QWebPage, QWebFrame

from qutebrowser.config import config
from qutebrowser.keyinput import modeman
from qutebrowser.utils import message, log, usertypes, utils, qtutils, objreg
from qutebrowser.browser import webpage, hints, webelem


LoadStatus = usertypes.enum('LoadStatus', ['none', 'success', 'success_https',
                                           'error', 'warn', 'loading'])


tab_id_gen = itertools.count(0)


class WebView(QWebView):

    """One browser tab in TabbedBrowser.

    Our own subclass of a QWebView with some added bells and whistles.

    Attributes:
        hintmanager: The HintManager instance for this view.
        progress: loading progress of this page.
        scroll_pos: The current scroll position as (x%, y%) tuple.
コード例 #9
0
def enum():
    return usertypes.enum('Enum', ['one', 'two'])
コード例 #10
0
ファイル: websettings.py プロジェクト: rahonen/qutebrowser
Module attributes:
    ATTRIBUTES: A mapping from internal setting names to QWebSetting enum
                constants.
    SETTERS: A mapping from setting names to QWebSetting setter method names.
    settings: The global QWebSettings singleton instance.
"""

import os.path

from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtCore import QStandardPaths

from qutebrowser.config import config
from qutebrowser.utils import usertypes, standarddir, objreg

MapType = usertypes.enum('MapType', ['attribute', 'setter', 'static_setter'])

MAPPINGS = {
    'permissions': {
        'allow-images': (MapType.attribute, QWebSettings.AutoLoadImages),
        'allow-javascript': (MapType.attribute,
                             QWebSettings.JavascriptEnabled),
        'javascript-can-open-windows': (MapType.attribute,
                                        QWebSettings.JavascriptCanOpenWindows),
        'javascript-can-close-windows':
        (MapType.attribute, QWebSettings.JavascriptCanCloseWindows),
        'javascript-can-access-clipboard':
        (MapType.attribute, QWebSettings.JavascriptCanAccessClipboard),
        #'allow-java':
        #   (MapType.attribute, QWebSettings.JavaEnabled),
        'allow-plugins': (MapType.attribute, QWebSettings.PluginsEnabled),
コード例 #11
0
# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.
"""The main statusbar widget."""

import collections

from PyQt5.QtCore import (pyqtSignal, pyqtSlot, pyqtProperty, Qt, QTime, QSize,
                          QTimer)
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QStackedLayout, QSizePolicy

from qutebrowser.config import config, style
from qutebrowser.utils import usertypes, log, objreg, utils
from qutebrowser.mainwindow.statusbar import (command, progress, keystring,
                                              percentage, url, prompt)
from qutebrowser.mainwindow.statusbar import text as textwidget

PreviousWidget = usertypes.enum('PreviousWidget',
                                ['none', 'prompt', 'command'])
Severity = usertypes.enum('Severity', ['normal', 'warning', 'error'])


class StatusBar(QWidget):
    """The statusbar at the bottom of the mainwindow.

    Attributes:
        txt: The Text widget in the statusbar.
        keystring: The KeyString widget in the statusbar.
        percentage: The Percentage widget in the statusbar.
        url: The UrlText widget in the statusbar.
        prog: The Progress widget in the statusbar.
        cmd: The Command widget in the statusbar.
        _hbox: The main QHBoxLayout.
        _stack: The QStackedLayout with cmd/txt widgets.
コード例 #12
0
ファイル: test_cmdutils.py プロジェクト: thuck/qutebrowser
class TestRegister:
    def test_simple(self):
        @cmdutils.register()
        def fun():
            """Blah."""
            pass

        cmd = cmdutils.cmd_dict['fun']
        assert cmd.handler is fun
        assert cmd.name == 'fun'
        assert len(cmdutils.cmd_dict) == 1
        assert not cmdutils.aliases

    def test_underlines(self):
        """Make sure the function name is normalized correctly (_ -> -)."""
        @cmdutils.register()
        def eggs_bacon():
            """Blah."""
            pass

        assert cmdutils.cmd_dict['eggs-bacon'].name == 'eggs-bacon'
        assert 'eggs_bacon' not in cmdutils.cmd_dict

    def test_lowercasing(self):
        """Make sure the function name is normalized correctly (uppercase)."""
        @cmdutils.register()
        def Test():  # pylint: disable=invalid-name
            """Blah."""
            pass

        assert cmdutils.cmd_dict['test'].name == 'test'
        assert 'Test' not in cmdutils.cmd_dict

    def test_explicit_name(self):
        """Test register with explicit name."""
        @cmdutils.register(name='foobar')
        def fun():
            """Blah."""
            pass

        assert cmdutils.cmd_dict['foobar'].name == 'foobar'
        assert 'fun' not in cmdutils.cmd_dict
        assert len(cmdutils.cmd_dict) == 1
        assert not cmdutils.aliases

    def test_multiple_names(self):
        """Test register with name being a list."""
        @cmdutils.register(name=['foobar', 'blub'])
        def fun():
            """Blah."""
            pass

        assert cmdutils.cmd_dict['foobar'].name == 'foobar'
        assert cmdutils.cmd_dict['blub'].name == 'foobar'
        assert 'fun' not in cmdutils.cmd_dict
        assert len(cmdutils.cmd_dict) == 2
        assert cmdutils.aliases == ['blub']

    def test_multiple_registrations(self):
        """Make sure registering the same name twice raises ValueError."""
        @cmdutils.register(name=['foobar', 'blub'])
        def fun():
            """Blah."""
            pass

        with pytest.raises(ValueError):

            @cmdutils.register(name=['blah', 'blub'])
            def fun2():
                """Blah."""
                pass

    def test_instance(self):
        """Make sure the instance gets passed to Command."""
        @cmdutils.register(instance='foobar')
        def fun(self):
            """Blah."""
            pass

        assert cmdutils.cmd_dict['fun']._instance == 'foobar'

    def test_kwargs(self):
        """Make sure the other keyword arguments get passed to Command."""
        @cmdutils.register(hide=True)
        def fun():
            """Blah."""
            pass

        assert cmdutils.cmd_dict['fun'].hide

    def test_star_args(self):
        """Check handling of *args."""
        @cmdutils.register()
        def fun(*args):
            """Blah."""
            pass

        with pytest.raises(argparser.ArgumentParserError):
            cmdutils.cmd_dict['fun'].parser.parse_args([])

    def test_star_args_optional(self):
        """Check handling of *args withstar_args_optional."""
        @cmdutils.register(star_args_optional=True)
        def fun(*args):
            """Blah."""
            assert not args

        cmd = cmdutils.cmd_dict['fun']
        cmd.namespace = cmd.parser.parse_args([])
        args, kwargs = cmd._get_call_args(win_id=0)
        fun(*args, **kwargs)

    @pytest.mark.parametrize('inp, expected', [(['--arg'], True),
                                               (['-a'], True), ([], False)])
    def test_flag(self, inp, expected):
        @cmdutils.register()
        def fun(arg=False):
            """Blah."""
            assert arg == expected

        cmd = cmdutils.cmd_dict['fun']
        cmd.namespace = cmd.parser.parse_args(inp)
        assert cmd.namespace.arg == expected

    def test_flag_argument(self):
        @cmdutils.register()
        @cmdutils.argument('arg', flag='b')
        def fun(arg=False):
            """Blah."""
            assert arg

        cmd = cmdutils.cmd_dict['fun']

        with pytest.raises(argparser.ArgumentParserError):
            cmd.parser.parse_args(['-a'])

        cmd.namespace = cmd.parser.parse_args(['-b'])
        assert cmd.namespace.arg
        args, kwargs = cmd._get_call_args(win_id=0)
        fun(*args, **kwargs)

    def test_partial_arg(self):
        """Test with only some arguments decorated with @cmdutils.argument."""
        @cmdutils.register()
        @cmdutils.argument('arg1', flag='b')
        def fun(arg1=False, arg2=False):
            """Blah."""
            pass

    def test_win_id(self):
        @cmdutils.register()
        @cmdutils.argument('win_id', win_id=True)
        def fun(win_id):
            """Blah."""
            pass

        assert cmdutils.cmd_dict['fun']._get_call_args(42) == ([42], {})

    def test_count(self):
        @cmdutils.register()
        @cmdutils.argument('count', count=True)
        def fun(count=0):
            """Blah."""
            pass

        assert cmdutils.cmd_dict['fun']._get_call_args(42) == ([0], {})

    def test_count_without_default(self):
        with pytest.raises(TypeError) as excinfo:

            @cmdutils.register()
            @cmdutils.argument('count', count=True)
            def fun(count):
                """Blah."""
                pass

        expected = "fun: handler has count parameter without default!"
        assert str(excinfo.value) == expected

    @pytest.mark.parametrize('hide', [True, False])
    def test_pos_args(self, hide):
        @cmdutils.register()
        @cmdutils.argument('arg', hide=hide)
        def fun(arg):
            """Blah."""
            pass

        pos_args = cmdutils.cmd_dict['fun'].pos_args
        if hide:
            assert pos_args == []
        else:
            assert pos_args == [('arg', 'arg')]

    Enum = usertypes.enum('Test', ['x', 'y'])

    @pytest.mark.parametrize(
        'typ, inp, choices, expected',
        [
            (int, '42', None, 42),
            (int, 'x', None, cmdexc.ArgumentTypeError),
            (str, 'foo', None, 'foo'),
            (typing.Union[str, int], 'foo', None, 'foo'),
            (typing.Union[str, int], '42', None, 42),

            # Choices
            (str, 'foo', ['foo'], 'foo'),
            (str, 'bar', ['foo'], cmdexc.ArgumentTypeError),

            # Choices with Union: only checked when it's a str
            (typing.Union[str, int], 'foo', ['foo'], 'foo'),
            (typing.Union[str, int], 'bar', ['foo'], cmdexc.ArgumentTypeError),
            (typing.Union[str, int], '42', ['foo'], 42),
            (Enum, 'x', None, Enum.x),
            (Enum, 'z', None, cmdexc.ArgumentTypeError),
        ])
    def test_typed_args(self, typ, inp, choices, expected):
        @cmdutils.register()
        @cmdutils.argument('arg', choices=choices)
        def fun(arg: typ):
            """Blah."""
            assert arg == expected

        cmd = cmdutils.cmd_dict['fun']
        cmd.namespace = cmd.parser.parse_args([inp])

        if expected is cmdexc.ArgumentTypeError:
            with pytest.raises(cmdexc.ArgumentTypeError):
                cmd._get_call_args(win_id=0)
        else:
            args, kwargs = cmd._get_call_args(win_id=0)
            assert args == [expected]
            assert kwargs == {}
            fun(*args, **kwargs)

    def test_choices_no_annotation(self):
        # https://github.com/The-Compiler/qutebrowser/issues/1871
        @cmdutils.register()
        @cmdutils.argument('arg', choices=['foo', 'bar'])
        def fun(arg):
            """Blah."""
            pass

        cmd = cmdutils.cmd_dict['fun']
        cmd.namespace = cmd.parser.parse_args(['fish'])

        with pytest.raises(cmdexc.ArgumentTypeError):
            cmd._get_call_args(win_id=0)

    def test_choices_no_annotation_kwonly(self):
        # https://github.com/The-Compiler/qutebrowser/issues/1871
        @cmdutils.register()
        @cmdutils.argument('arg', choices=['foo', 'bar'])
        def fun(*, arg='foo'):
            """Blah."""
            pass

        cmd = cmdutils.cmd_dict['fun']
        cmd.namespace = cmd.parser.parse_args(['--arg=fish'])

        with pytest.raises(cmdexc.ArgumentTypeError):
            cmd._get_call_args(win_id=0)

    def test_pos_arg_info(self):
        @cmdutils.register()
        @cmdutils.argument('foo', choices=('a', 'b'))
        @cmdutils.argument('bar', choices=('x', 'y'))
        @cmdutils.argument('opt')
        def fun(foo, bar, opt=False):
            """Blah."""
            pass

        cmd = cmdutils.cmd_dict['fun']
        assert cmd.get_pos_arg_info(0) == command.ArgInfo(choices=('a', 'b'))
        assert cmd.get_pos_arg_info(1) == command.ArgInfo(choices=('x', 'y'))
        with pytest.raises(IndexError):
            cmd.get_pos_arg_info(2)

    def test_keyword_only_without_default(self):
        # https://github.com/The-Compiler/qutebrowser/issues/1872
        def fun(*, target):
            """Blah."""
            pass

        with pytest.raises(TypeError) as excinfo:
            fun = cmdutils.register()(fun)

        expected = ("fun: handler has keyword only argument 'target' without "
                    "default!")
        assert str(excinfo.value) == expected

    def test_typed_keyword_only_without_default(self):
        # https://github.com/The-Compiler/qutebrowser/issues/1872
        def fun(*, target: int):
            """Blah."""
            pass

        with pytest.raises(TypeError) as excinfo:
            fun = cmdutils.register()(fun)

        expected = ("fun: handler has keyword only argument 'target' without "
                    "default!")
        assert str(excinfo.value) == expected
コード例 #13
0
ファイル: standarddir.py プロジェクト: swalladge/qutebrowser
import sys
import shutil
import os.path
import contextlib

from PyQt5.QtCore import QStandardPaths
from PyQt5.QtWidgets import QApplication

from qutebrowser.utils import log, debug, usertypes, message

# The cached locations
_locations = {}


Location = usertypes.enum('Location', ['config', 'auto_config',
                                       'data', 'system_data',
                                       'cache', 'download', 'runtime'])


APPNAME = 'qutebrowser'


class EmptyValueError(Exception):

    """Error raised when QStandardPaths returns an empty value."""


@contextlib.contextmanager
def _unset_organization():
    """Temporarily unset QApplication.organizationName().
コード例 #14
0
def test_unique():
    """Make sure elements need to be unique."""
    with pytest.raises(TypeError):
        usertypes.enum('Enum', ['item', 'item'])
コード例 #15
0
def test_start():
    """Test the start= argument."""
    e = usertypes.enum('Enum', ['three', 'four'], start=3)
    assert e.three.value == 3
    assert e.four.value == 4
コード例 #16
0
"""KeyChainParser for "hint" and "normal" modes.

Module attributes:
    STARTCHARS: Possible chars for starting a commandline input.
"""

from PyQt5.QtCore import pyqtSlot, Qt

from qutebrowser.utils import message
from qutebrowser.config import config
from qutebrowser.keyinput import keyparser
from qutebrowser.utils import usertypes, log, objreg, utils


STARTCHARS = ":/?"
LastPress = usertypes.enum('LastPress', ['none', 'filtertext', 'keystring'])


class NormalKeyParser(keyparser.CommandKeyParser):

    """KeyParser for normal mode with added STARTCHARS detection and more.

    Attributes:
        _partial_timer: Timer to clear partial keypresses.
    """

    def __init__(self, win_id, parent=None):
        super().__init__(win_id, parent, supports_count=True,
                         supports_chains=True)
        self.read_config('normal')
        self._partial_timer = usertypes.Timer(self, 'partial-match')
コード例 #17
0
Module attributes:
    STARTCHARS: Possible chars for starting a commandline input.
"""

import traceback

from PyQt5.QtCore import pyqtSlot, Qt

from qutebrowser.commands import cmdexc
from qutebrowser.config import config
from qutebrowser.keyinput import keyparser
from qutebrowser.utils import usertypes, log, message, objreg, utils


STARTCHARS = ":/?"
LastPress = usertypes.enum('LastPress', ['none', 'filtertext', 'keystring'])


class NormalKeyParser(keyparser.CommandKeyParser):

    """KeyParser for normal mode with added STARTCHARS detection and more.

    Attributes:
        _partial_timer: Timer to clear partial keypresses.
    """

    def __init__(self, win_id, parent=None):
        super().__init__(win_id, parent, supports_count=True,
                         supports_chains=True)
        self.read_config('normal')
        self._partial_timer = usertypes.Timer(self, 'partial-match')
コード例 #18
0
"""The main statusbar widget."""

import collections

from PyQt5.QtCore import (pyqtSignal, pyqtSlot, pyqtProperty, Qt, QTime, QSize,
                          QTimer)
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QStackedLayout, QSizePolicy

from qutebrowser.config import config, style
from qutebrowser.utils import usertypes, log, objreg, utils
from qutebrowser.mainwindow.statusbar import (command, progress, keystring,
                                              percentage, url, prompt,
                                              tabindex)
from qutebrowser.mainwindow.statusbar import text as textwidget

PreviousWidget = usertypes.enum('PreviousWidget',
                                ['none', 'prompt', 'command'])
Severity = usertypes.enum('Severity', ['normal', 'warning', 'error'])
CaretMode = usertypes.enum('CaretMode', ['off', 'on', 'selection'])


class StatusBar(QWidget):
    """The statusbar at the bottom of the mainwindow.

    Attributes:
        txt: The Text widget in the statusbar.
        keystring: The KeyString widget in the statusbar.
        percentage: The Percentage widget in the statusbar.
        url: The UrlText widget in the statusbar.
        prog: The Progress widget in the statusbar.
        cmd: The Command widget in the statusbar.
        _hbox: The main QHBoxLayout.
コード例 #19
0
ファイル: hints.py プロジェクト: xManusx/qutebrowser
from PyQt5.QtWebKit import QWebElement
from PyQt5.QtWebKitWidgets import QWebPage

from qutebrowser.config import config
from qutebrowser.keyinput import modeman, modeparsers
from qutebrowser.browser import webelem
from qutebrowser.commands import userscripts, cmdexc, cmdutils, runners
from qutebrowser.utils import usertypes, log, qtutils, message, objreg
from qutebrowser.misc import guiprocess


ElemTuple = collections.namedtuple('ElemTuple', ['elem', 'label'])


Target = usertypes.enum('Target', ['normal', 'tab', 'tab_fg', 'tab_bg',
                                   'window', 'yank', 'yank_primary', 'run',
                                   'fill', 'hover', 'download', 'userscript',
                                   'spawn'])


@pyqtSlot(usertypes.KeyMode)
def on_mode_entered(mode, win_id):
    """Stop hinting when insert mode was entered."""
    if mode == usertypes.KeyMode.insert:
        modeman.maybe_leave(win_id, usertypes.KeyMode.hint, 'insert mode')


class HintContext:

    """Context namespace used for hinting.

    Attributes:
コード例 #20
0
    from PyQt5.QtWebEngineWidgets import QWebEngineProfile
except ImportError:  # pragma: no cover
    QWebEngineProfile = None

import qutebrowser
from qutebrowser.utils import log, utils, standarddir, usertypes, qtutils
from qutebrowser.misc import objects, earlyinit, sql
from qutebrowser.browser import pdfjs


DistributionInfo = collections.namedtuple(
    'DistributionInfo', ['id', 'parsed', 'version', 'pretty'])


Distribution = usertypes.enum(
    'Distribution', ['unknown', 'ubuntu', 'debian', 'void', 'arch',
                     'gentoo', 'fedora', 'opensuse', 'linuxmint', 'manjaro'])


def distribution():
    """Get some information about the running Linux distribution.

    Returns:
        A DistributionInfo object, or None if no info could be determined.
            parsed: A Distribution enum member
            version: A Version object, or None
            pretty: Always a string (might be "Unknown")
    """
    filename = os.environ.get('QUTE_FAKE_OS_RELEASE', '/etc/os-release')
    info = {}
    try:
コード例 #21
0
# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.

"""The main statusbar widget."""

from PyQt5.QtCore import pyqtSignal, pyqtSlot, pyqtProperty, Qt, QSize, QTimer
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QStackedLayout, QSizePolicy

from qutebrowser.config import config, style
from qutebrowser.utils import usertypes, log, objreg, utils
from qutebrowser.mainwindow.statusbar import (command, progress, keystring,
                                              percentage, url, prompt,
                                              tabindex)
from qutebrowser.mainwindow.statusbar import text as textwidget


CaretMode = usertypes.enum('CaretMode', ['off', 'on', 'selection'])


class StatusBar(QWidget):

    """The statusbar at the bottom of the mainwindow.

    Attributes:
        txt: The Text widget in the statusbar.
        keystring: The KeyString widget in the statusbar.
        percentage: The Percentage widget in the statusbar.
        url: The UrlText widget in the statusbar.
        prog: The Progress widget in the statusbar.
        cmd: The Command widget in the statusbar.
        _hbox: The main QHBoxLayout.
        _stack: The QStackedLayout with cmd/txt widgets.
コード例 #22
0
ファイル: base.py プロジェクト: jamesstidard/qutebrowser
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.
"""The base completion model for completion in the command line.

Module attributes:
    Role: An enum of user defined model roles.
"""

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItemModel, QStandardItem

from qutebrowser.utils import usertypes

Role = usertypes.enum('Role', ['sort', 'userdata'],
                      start=Qt.UserRole,
                      is_int=True)


class BaseCompletionModel(QStandardItemModel):
    """A simple QStandardItemModel adopted for completions.

    Used for showing completions later in the CompletionView. Supports setting
    marks and adding new categories/items easily.

    Class Attributes:
        COLUMN_WIDTHS: The width percentages of the columns used in the
                        completion view.
        DUMB_SORT: the dumb sorting used by the model
    """
コード例 #23
0
ファイル: hints.py プロジェクト: har5ha/qutebrowser
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QEvent, Qt, QUrl
from PyQt5.QtGui import QMouseEvent, QClipboard
from PyQt5.QtWidgets import QApplication

from qutebrowser.config import config
from qutebrowser.keyinput import modeman
from qutebrowser.browser import webelem
from qutebrowser.commands import userscripts, cmdexc, cmdutils
from qutebrowser.utils import usertypes, log, qtutils, message, objreg


ElemTuple = collections.namedtuple('ElemTuple', ['elem', 'label'])


Target = usertypes.enum('Target', ['normal', 'tab', 'tab_bg', 'yank',
                                   'yank_primary', 'fill', 'rapid', 'download',
                                   'userscript', 'spawn'])


@pyqtSlot(usertypes.KeyMode)
def on_mode_entered(mode):
    """Stop hinting when insert mode was entered."""
    if mode == usertypes.KeyMode.insert:
        modeman.maybe_leave(usertypes.KeyMode.hint, 'insert mode')


class HintContext:

    """Context namespace used for hinting.

    Attributes:
コード例 #24
0
class BaseKeyParser(QObject):
    """Parser for vim-like key sequences and shortcuts.

    Not intended to be instantiated directly. Subclasses have to override
    execute() to do whatever they want to.

    Class Attributes:
        Match: types of a match between a binding and the keystring.
            partial: No keychain matched yet, but it's still possible in the
                     future.
            definitive: Keychain matches exactly.
            ambiguous: There are both a partial and a definitive match.
            none: No more matches possible.

        Types: type of a keybinding.
            chain: execute() was called via a chain-like keybinding
            special: execute() was called via a special keybinding

        do_log: Whether to log keypresses or not.

    Attributes:
        bindings: Bound keybindings
        special_bindings: Bound special bindings (<Foo>).
        _win_id: The window ID this keyparser is associated with.
        _warn_on_keychains: Whether a warning should be logged when binding
                            keychains in a section which does not support them.
        _keystring: The currently entered key sequence
        _timer: Timer for delayed execution.
        _modename: The name of the input mode associated with this keyparser.
        _supports_count: Whether count is supported
        _supports_chains: Whether keychains are supported

    Signals:
        keystring_updated: Emitted when the keystring is updated.
                           arg: New keystring.
    """

    keystring_updated = pyqtSignal(str)
    do_log = True

    Match = usertypes.enum('Match',
                           ['partial', 'definitive', 'ambiguous', 'none'])
    Type = usertypes.enum('Type', ['chain', 'special'])

    def __init__(self,
                 win_id,
                 parent=None,
                 supports_count=None,
                 supports_chains=False):
        super().__init__(parent)
        self._win_id = win_id
        self._timer = None
        self._modename = None
        self._keystring = ''
        if supports_count is None:
            supports_count = supports_chains
        self._supports_count = supports_count
        self._supports_chains = supports_chains
        self._warn_on_keychains = True
        self.bindings = {}
        self.special_bindings = {}

    def __repr__(self):
        return utils.get_repr(self,
                              supports_count=self._supports_count,
                              supports_chains=self._supports_chains)

    def _debug_log(self, message):
        """Log a message to the debug log if logging is active.

        Args:
            message: The message to log.
        """
        if self.do_log:
            log.keyboard.debug(message)

    def _handle_special_key(self, e):
        """Handle a new keypress with special keys (<Foo>).

        Return True if the keypress has been handled, and False if not.

        Args:
            e: the KeyPressEvent from Qt.

        Return:
            True if event has been handled, False otherwise.
        """
        binding = utils.keyevent_to_string(e)
        if binding is None:
            self._debug_log("Ignoring only-modifier keyeevent.")
            return False
        binding = binding.lower()
        try:
            cmdstr = self.special_bindings[binding]
        except KeyError:
            self._debug_log("No binding found for {}.".format(binding))
            return False
        self.execute(cmdstr, self.Type.special)
        return True

    def _split_count(self):
        """Get count and command from the current keystring.

        Return:
            A (count, command) tuple.
        """
        if self._supports_count:
            (countstr, cmd_input) = re.match(r'^(\d*)(.*)',
                                             self._keystring).groups()
            count = int(countstr) if countstr else None
        else:
            cmd_input = self._keystring
            count = None
        return count, cmd_input

    def _handle_single_key(self, e):
        """Handle a new keypress with a single key (no modifiers).

        Separate the keypress into count/command, then check if it matches
        any possible command, and either run the command, ignore it, or
        display an error.

        Args:
            e: the KeyPressEvent from Qt.

        Return:
            True if event has been handled, False otherwise.
        """
        txt = e.text()
        key = e.key()
        self._debug_log("Got key: 0x{:x} / text: '{}'".format(key, txt))

        if key == Qt.Key_Escape:
            self._debug_log("Escape pressed, discarding '{}'.".format(
                self._keystring))
            self._keystring = ''
            return

        if (not txt) or unicodedata.category(txt) == 'Cc':  # control chars
            self._debug_log("Ignoring, no text char")
            return False

        self._stop_delayed_exec()
        self._keystring += txt

        count, cmd_input = self._split_count()

        if not cmd_input:
            # Only a count, no command yet, but we handled it
            return True

        match, binding = self._match_key(cmd_input)

        if not isinstance(match, self.Match):
            raise TypeError("Value {} is no Match member!".format(match))

        if match == self.Match.definitive:
            self._debug_log("Definitive match for '{}'.".format(
                self._keystring))
            self._keystring = ''
            self.execute(binding, self.Type.chain, count)
        elif match == self.Match.ambiguous:
            self._debug_log("Ambigious match for '{}'.".format(
                self._keystring))
            self._handle_ambiguous_match(binding, count)
        elif match == self.Match.partial:
            self._debug_log("No match for '{}' (added {})".format(
                self._keystring, txt))
        elif match == self.Match.none:
            self._debug_log("Giving up with '{}', no matches".format(
                self._keystring))
            self._keystring = ''
            return False
        return True

    def _match_key(self, cmd_input):
        """Try to match a given keystring with any bound keychain.

        Args:
            cmd_input: The command string to find.

        Return:
            A tuple (matchtype, binding).
                matchtype: Match.definitive, Match.ambiguous, Match.partial or
                           Match.none
                binding: - None with Match.partial/Match.none
                         - The found binding with Match.definitive/
                           Match.ambiguous
        """
        # A (cmd_input, binding) tuple (k, v of bindings) or None.
        definitive_match = None
        partial_match = False
        # Check definitive match
        try:
            definitive_match = (cmd_input, self.bindings[cmd_input])
        except KeyError:
            pass
        # Check partial match
        for binding in self.bindings:
            if definitive_match is not None and binding == definitive_match[0]:
                # We already matched that one
                continue
            elif binding.startswith(cmd_input):
                partial_match = True
                break
        if definitive_match is not None and partial_match:
            return (self.Match.ambiguous, definitive_match[1])
        elif definitive_match is not None:
            return (self.Match.definitive, definitive_match[1])
        elif partial_match:
            return (self.Match.partial, None)
        else:
            return (self.Match.none, None)

    def _stop_delayed_exec(self):
        """Stop a delayed execution if any is running."""
        if self._timer is not None:
            if self.do_log:
                log.keyboard.debug("Stopping delayed execution.")
            self._timer.stop()
            self._timer = None

    def _handle_ambiguous_match(self, binding, count):
        """Handle an ambiguous match.

        Args:
            binding: The command-string to execute.
            count: The count to pass.
        """
        self._debug_log("Ambiguous match for '{}'".format(self._keystring))
        time = config.get('input', 'timeout')
        if time == 0:
            # execute immediately
            self._keystring = ''
            self.execute(binding, self.Type.chain, count)
        else:
            # execute in `time' ms
            self._debug_log("Scheduling execution of {} in {}ms".format(
                binding, time))
            self._timer = usertypes.Timer(self, 'ambigious_match')
            self._timer.setSingleShot(True)
            self._timer.setInterval(time)
            self._timer.timeout.connect(
                functools.partial(self.delayed_exec, binding, count))
            self._timer.start()

    def delayed_exec(self, command, count):
        """Execute a delayed command.

        Args:
            command/count: As if passed to self.execute()
        """
        self._debug_log("Executing delayed command now!")
        self._timer = None
        self._keystring = ''
        self.keystring_updated.emit(self._keystring)
        self.execute(command, self.Type.chain, count)

    def handle(self, e):
        """Handle a new keypress and call the respective handlers.

        Args:
            e: the KeyPressEvent from Qt
        """
        handled = self._handle_special_key(e)
        if handled or not self._supports_chains:
            return handled
        handled = self._handle_single_key(e)
        self.keystring_updated.emit(self._keystring)
        return handled

    def read_config(self, modename=None):
        """Read the configuration.

        Config format: key = command, e.g.:
            <Ctrl+Q> = quit

        Args:
            modename: Name of the mode to use.
        """
        if modename is None:
            if self._modename is None:
                raise ValueError("read_config called with no mode given, but "
                                 "None defined so far!")
            modename = self._modename
        else:
            self._modename = modename
        self.bindings = {}
        self.special_bindings = {}
        keyconfparser = objreg.get('key-config')
        for (key, cmd) in keyconfparser.get_bindings_for(modename).items():
            if not cmd:
                continue
            elif key.startswith('<') and key.endswith('>'):
                keystr = utils.normalize_keystr(key[1:-1])
                self.special_bindings[keystr] = cmd
            elif self._supports_chains:
                self.bindings[key] = cmd
            elif self._warn_on_keychains:
                log.keyboard.warning(
                    "Ignoring keychain '{}' in mode '{}' because "
                    "keychains are not supported there.".format(key, modename))

    def execute(self, cmdstr, keytype, count=None):
        """Handle a completed keychain.

        Args:
            cmdstr: The command to execute as a string.
            keytype: Type.chain or Type.special
            count: The count if given.
        """
        raise NotImplementedError

    @pyqtSlot(str)
    def on_keyconfig_changed(self, mode):
        """Re-read the config if a keybinding was changed."""
        if self._modename is None:
            raise AttributeError("on_keyconfig_changed called but no section "
                                 "defined!")
        if mode == self._modename:
            self.read_config()
コード例 #25
0
ファイル: bar.py プロジェクト: shioyama/qutebrowser
# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.

"""The main statusbar widget."""

import collections

from PyQt5.QtCore import pyqtSignal, pyqtSlot, pyqtProperty, Qt, QTime, QSize, QTimer
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QStackedLayout, QSizePolicy

from qutebrowser.config import config, style
from qutebrowser.utils import usertypes, log, objreg, utils
from qutebrowser.mainwindow.statusbar import command, progress, keystring, percentage, url, prompt, tabindex
from qutebrowser.mainwindow.statusbar import text as textwidget


PreviousWidget = usertypes.enum("PreviousWidget", ["none", "prompt", "command"])
Severity = usertypes.enum("Severity", ["normal", "warning", "error"])
CaretMode = usertypes.enum("CaretMode", ["off", "on", "selection"])


class StatusBar(QWidget):

    """The statusbar at the bottom of the mainwindow.

    Attributes:
        txt: The Text widget in the statusbar.
        keystring: The KeyString widget in the statusbar.
        percentage: The Percentage widget in the statusbar.
        url: The UrlText widget in the statusbar.
        prog: The Progress widget in the statusbar.
        cmd: The Command widget in the statusbar.
コード例 #26
0
ファイル: webview.py プロジェクト: larryhynes/qutebrowser
import itertools
import functools

from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QTimer, QUrl
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtWebKitWidgets import QWebView, QWebPage

from qutebrowser.config import config
from qutebrowser.keyinput import modeman
from qutebrowser.utils import message, log, usertypes, utils, qtutils, objreg
from qutebrowser.browser import webpage, hints, webelem
from qutebrowser.commands import cmdexc


LoadStatus = usertypes.enum('LoadStatus', ['none', 'success', 'error', 'warn',
                                           'loading'])


tab_id_gen = itertools.count(0)


class WebView(QWebView):

    """One browser tab in TabbedBrowser.

    Our own subclass of a QWebView with some added bells and whistles.

    Attributes:
        hintmanager: The HintManager instance for this view.
        progress: loading progress of this page.
        scroll_pos: The current scroll position as (x%, y%) tuple.
コード例 #27
0
class BaseKeyParser(QObject):
    """Parser for vim-like key sequences and shortcuts.

    Not intended to be instantiated directly. Subclasses have to override
    execute() to do whatever they want to.

    Class Attributes:
        Match: types of a match between a binding and the keystring.
            partial: No keychain matched yet, but it's still possible in the
                     future.
            definitive: Keychain matches exactly.
            none: No more matches possible.

        Types: type of a key binding.
            chain: execute() was called via a chain-like key binding
            special: execute() was called via a special key binding

        do_log: Whether to log keypresses or not.
        passthrough: Whether unbound keys should be passed through with this
                     handler.

    Attributes:
        bindings: Bound key bindings
        special_bindings: Bound special bindings (<Foo>).
        _win_id: The window ID this keyparser is associated with.
        _warn_on_keychains: Whether a warning should be logged when binding
                            keychains in a section which does not support them.
        _keystring: The currently entered key sequence
        _modename: The name of the input mode associated with this keyparser.
        _supports_count: Whether count is supported
        _supports_chains: Whether keychains are supported

    Signals:
        keystring_updated: Emitted when the keystring is updated.
                           arg: New keystring.
        request_leave: Emitted to request leaving a mode.
                       arg 0: Mode to leave.
                       arg 1: Reason for leaving.
                       arg 2: Ignore the request if we're not in that mode
    """

    keystring_updated = pyqtSignal(str)
    request_leave = pyqtSignal(usertypes.KeyMode, str, bool)
    do_log = True
    passthrough = False

    Match = usertypes.enum('Match', ['partial', 'definitive', 'other', 'none'])
    Type = usertypes.enum('Type', ['chain', 'special'])

    def __init__(self,
                 win_id,
                 parent=None,
                 supports_count=None,
                 supports_chains=False):
        super().__init__(parent)
        self._win_id = win_id
        self._modename = None
        self._keystring = ''
        if supports_count is None:
            supports_count = supports_chains
        self._supports_count = supports_count
        self._supports_chains = supports_chains
        self._warn_on_keychains = True
        self.bindings = {}
        self.special_bindings = {}
        config.instance.changed.connect(self._on_config_changed)

    def __repr__(self):
        return utils.get_repr(self,
                              supports_count=self._supports_count,
                              supports_chains=self._supports_chains)

    def _debug_log(self, message):
        """Log a message to the debug log if logging is active.

        Args:
            message: The message to log.
        """
        if self.do_log:
            log.keyboard.debug(message)

    def _handle_special_key(self, e):
        """Handle a new keypress with special keys (<Foo>).

        Return True if the keypress has been handled, and False if not.

        Args:
            e: the KeyPressEvent from Qt.

        Return:
            True if event has been handled, False otherwise.
        """
        binding = utils.keyevent_to_string(e)
        if binding is None:
            self._debug_log("Ignoring only-modifier keyeevent.")
            return False

        if binding not in self.special_bindings:
            key_mappings = config.val.bindings.key_mappings
            try:
                binding = key_mappings['<{}>'.format(binding)][1:-1]
            except KeyError:
                pass

        try:
            cmdstr = self.special_bindings[binding]
        except KeyError:
            self._debug_log("No special binding found for {}.".format(binding))
            return False
        count, _command = self._split_count(self._keystring)
        self.execute(cmdstr, self.Type.special, count)
        self.clear_keystring()
        return True

    def _split_count(self, keystring):
        """Get count and command from the current keystring.

        Args:
            keystring: The key string to split.

        Return:
            A (count, command) tuple.
        """
        if self._supports_count:
            (countstr, cmd_input) = re.match(r'^(\d*)(.*)', keystring).groups()
            count = int(countstr) if countstr else None
            if count == 0 and not cmd_input:
                cmd_input = keystring
                count = None
        else:
            cmd_input = keystring
            count = None
        return count, cmd_input

    def _handle_single_key(self, e):
        """Handle a new keypress with a single key (no modifiers).

        Separate the keypress into count/command, then check if it matches
        any possible command, and either run the command, ignore it, or
        display an error.

        Args:
            e: the KeyPressEvent from Qt.

        Return:
            A self.Match member.
        """
        txt = e.text()
        key = e.key()
        self._debug_log("Got key: 0x{:x} / text: '{}'".format(key, txt))

        if len(txt) == 1:
            category = unicodedata.category(txt)
            is_control_char = (category == 'Cc')
        else:
            is_control_char = False

        if (not txt) or is_control_char:
            self._debug_log("Ignoring, no text char")
            return self.Match.none

        count, cmd_input = self._split_count(self._keystring + txt)
        match, binding = self._match_key(cmd_input)
        if match == self.Match.none:
            mappings = config.val.bindings.key_mappings
            mapped = mappings.get(txt, None)
            if mapped is not None:
                txt = mapped
                count, cmd_input = self._split_count(self._keystring + txt)
                match, binding = self._match_key(cmd_input)

        self._keystring += txt
        if match == self.Match.definitive:
            self._debug_log("Definitive match for '{}'.".format(
                self._keystring))
            self.clear_keystring()
            self.execute(binding, self.Type.chain, count)
        elif match == self.Match.partial:
            self._debug_log("No match for '{}' (added {})".format(
                self._keystring, txt))
        elif match == self.Match.none:
            self._debug_log("Giving up with '{}', no matches".format(
                self._keystring))
            self.clear_keystring()
        elif match == self.Match.other:
            pass
        else:
            raise AssertionError("Invalid match value {!r}".format(match))
        return match

    def _match_key(self, cmd_input):
        """Try to match a given keystring with any bound keychain.

        Args:
            cmd_input: The command string to find.

        Return:
            A tuple (matchtype, binding).
                matchtype: Match.definitive, Match.partial or Match.none.
                binding: - None with Match.partial/Match.none.
                         - The found binding with Match.definitive.
        """
        if not cmd_input:
            # Only a count, no command yet, but we handled it
            return (self.Match.other, None)
        # A (cmd_input, binding) tuple (k, v of bindings) or None.
        definitive_match = None
        partial_match = False
        # Check definitive match
        try:
            definitive_match = (cmd_input, self.bindings[cmd_input])
        except KeyError:
            pass
        # Check partial match
        for binding in self.bindings:
            if definitive_match is not None and binding == definitive_match[0]:
                # We already matched that one
                continue
            elif binding.startswith(cmd_input):
                partial_match = True
                break
        if definitive_match is not None:
            return (self.Match.definitive, definitive_match[1])
        elif partial_match:
            return (self.Match.partial, None)
        else:
            return (self.Match.none, None)

    def handle(self, e):
        """Handle a new keypress and call the respective handlers.

        Args:
            e: the KeyPressEvent from Qt

        Return:
            True if the event was handled, False otherwise.
        """
        handled = self._handle_special_key(e)

        if handled or not self._supports_chains:
            return handled
        match = self._handle_single_key(e)
        # don't emit twice if the keystring was cleared in self.clear_keystring
        if self._keystring:
            self.keystring_updated.emit(self._keystring)
        return match != self.Match.none

    @config.change_filter('bindings')
    def _on_config_changed(self):
        self._read_config()

    def _read_config(self, modename=None):
        """Read the configuration.

        Config format: key = command, e.g.:
            <Ctrl+Q> = quit

        Args:
            modename: Name of the mode to use.
        """
        if modename is None:
            if self._modename is None:
                raise ValueError("read_config called with no mode given, but "
                                 "None defined so far!")
            modename = self._modename
        else:
            self._modename = modename
        self.bindings = {}
        self.special_bindings = {}

        for key, cmd in config.key_instance.get_bindings_for(modename).items():
            assert cmd
            self._parse_key_command(modename, key, cmd)

    def _parse_key_command(self, modename, key, cmd):
        """Parse the keys and their command and store them in the object."""
        if utils.is_special_key(key):
            self.special_bindings[key[1:-1]] = cmd
        elif self._supports_chains:
            self.bindings[key] = cmd
        elif self._warn_on_keychains:
            log.keyboard.warning("Ignoring keychain '{}' in mode '{}' because "
                                 "keychains are not supported there.".format(
                                     key, modename))

    def execute(self, cmdstr, keytype, count=None):
        """Handle a completed keychain.

        Args:
            cmdstr: The command to execute as a string.
            keytype: Type.chain or Type.special
            count: The count if given.
        """
        raise NotImplementedError

    def clear_keystring(self):
        """Clear the currently entered key sequence."""
        if self._keystring:
            self._debug_log("discarding keystring '{}'.".format(
                self._keystring))
            self._keystring = ''
            self.keystring_updated.emit(self._keystring)
コード例 #28
0
ファイル: bar.py プロジェクト: iggy/qutebrowser
# You should have received a copy of the GNU General Public License
# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.
"""The main statusbar widget."""

import collections

from PyQt5.QtCore import pyqtSignal, pyqtSlot, pyqtProperty, Qt, QTime
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QStackedLayout, QSizePolicy

from qutebrowser.config import config, style
from qutebrowser.utils import usertypes, log, objreg, utils
from qutebrowser.widgets.statusbar import (command, progress, keystring,
                                           percentage, url, prompt)
from qutebrowser.widgets.statusbar import text as textwidget

PreviousWidget = usertypes.enum('PreviousWidget',
                                ['none', 'prompt', 'command'])


class StatusBar(QWidget):
    """The statusbar at the bottom of the mainwindow.

    Attributes:
        txt: The Text widget in the statusbar.
        keystring: The KeyString widget in the statusbar.
        percentage: The Percentage widget in the statusbar.
        url: The UrlText widget in the statusbar.
        prog: The Progress widget in the statusbar.
        cmd: The Command widget in the statusbar.
        _hbox: The main QHBoxLayout.
        _stack: The QStackedLayout with cmd/txt widgets.
        _text_queue: A deque of (error, text) tuples to be displayed.
コード例 #29
0
class DocstringParser:
    """Generate documentation based on a docstring of a command handler.

    The docstring needs to follow the format described in CONTRIBUTING.

    Attributes:
        _state: The current state of the parser state machine.
        _cur_arg_name: The name of the argument we're currently handling.
        _short_desc_parts: The short description of the function as list.
        _long_desc_parts: The long description of the function as list.
        short_desc: The short description of the function.
        long_desc: The long description of the function.
        arg_descs: A dict of argument names to their descriptions
    """

    State = usertypes.enum(
        'State',
        ['short', 'desc', 'desc_hidden', 'arg_start', 'arg_inside', 'misc'])

    def __init__(self, func):
        """Constructor.

        Args:
            func: The function to parse the docstring for.
        """
        self._state = self.State.short
        self._cur_arg_name = None
        self._short_desc_parts = []
        self._long_desc_parts = []
        self.arg_descs = collections.OrderedDict()
        doc = inspect.getdoc(func)
        handlers = {
            self.State.short: self._parse_short,
            self.State.desc: self._parse_desc,
            self.State.desc_hidden: self._skip,
            self.State.arg_start: self._parse_arg_start,
            self.State.arg_inside: self._parse_arg_inside,
            self.State.misc: self._skip,
        }
        if doc is None:
            if sys.flags.optimize < 2:
                log.commands.warning(
                    "Function {}() from {} has no docstring".format(
                        utils.qualname(func), inspect.getsourcefile(func)))
            self.long_desc = ""
            self.short_desc = ""
            return
        for line in doc.splitlines():
            handler = handlers[self._state]
            stop = handler(line)
            if stop:
                break
        for k, v in self.arg_descs.items():
            desc = ' '.join(v)
            desc = re.sub(r', or None($|\.)', r'\1', desc)
            desc = re.sub(r', or None', r', or not given', desc)
            self.arg_descs[k] = desc
        self.long_desc = ' '.join(self._long_desc_parts)
        self.short_desc = ' '.join(self._short_desc_parts)

    def _process_arg(self, line):
        """Helper method to process a line like 'fooarg: Blah blub'."""
        self._cur_arg_name, argdesc = line.split(':', maxsplit=1)
        self._cur_arg_name = self._cur_arg_name.strip().lstrip('*')
        self.arg_descs[self._cur_arg_name] = [argdesc.strip()]

    def _skip(self, line):
        """Handler to ignore everything until we get 'Args:'."""
        if line.startswith('Args:'):
            self._state = self.State.arg_start

    def _parse_short(self, line):
        """Parse the short description (first block) in the docstring."""
        if not line:
            self._state = self.State.desc
        else:
            self._short_desc_parts.append(line.strip())

    def _parse_desc(self, line):
        """Parse the long description in the docstring."""
        if line.startswith('Args:'):
            self._state = self.State.arg_start
        elif line.strip() == '//':
            self._state = self.State.desc_hidden
        elif line.strip():
            self._long_desc_parts.append(line.strip())

    def _parse_arg_start(self, line):
        """Parse first argument line."""
        self._process_arg(line)
        self._state = self.State.arg_inside

    def _parse_arg_inside(self, line):
        """Parse subsequent argument lines."""
        argname = self._cur_arg_name
        if re.match(r'^[A-Z][a-z]+:$', line):
            if not self.arg_descs[argname][-1].strip():
                self.arg_descs[argname] = self.arg_descs[argname][:-1]
                return True
        elif not line.strip():
            self.arg_descs[argname].append('\n\n')
        elif line[4:].startswith(' '):
            self.arg_descs[argname].append(line.strip() + '\n')
        else:
            self._process_arg(line)
        return False
コード例 #30
0
ファイル: test_enum.py プロジェクト: HalosGhost/qutebrowser
 def test_start(self):
     """Test the start= argument."""
     e = usertypes.enum('Enum', ['three', 'four'], start=3)
     self.assertEqual(e.three.value, 3)
     self.assertEqual(e.four.value, 4)
コード例 #31
0
ファイル: bar.py プロジェクト: Konubinix/qutebrowser
import collections

from PyQt5.QtCore import (pyqtSignal, pyqtSlot, pyqtProperty, Qt, QTime, QSize,
                          QTimer)
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QStackedLayout, QSizePolicy

from qutebrowser.config import config, style
from qutebrowser.utils import usertypes, log, objreg, utils
from qutebrowser.mainwindow.statusbar import (command, progress, keystring,
                                              percentage, url, prompt,
                                              tabindex)
from qutebrowser.mainwindow.statusbar import text as textwidget


PreviousWidget = usertypes.enum('PreviousWidget', ['none', 'prompt',
                                                   'command'])
Severity = usertypes.enum('Severity', ['normal', 'warning', 'error'])
CaretMode = usertypes.enum('CaretMode', ['off', 'on', 'selection'])


class StatusBar(QWidget):

    """The statusbar at the bottom of the mainwindow.

    Attributes:
        txt: The Text widget in the statusbar.
        keystring: The KeyString widget in the statusbar.
        percentage: The Percentage widget in the statusbar.
        url: The UrlText widget in the statusbar.
        prog: The Progress widget in the statusbar.
        cmd: The Command widget in the statusbar.
コード例 #32
0
import functools
import html

import attr
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QApplication, QDialog, QPushButton, QHBoxLayout,
                             QVBoxLayout, QLabel, QMessageBox)
from PyQt5.QtNetwork import QSslSocket

from qutebrowser.config import config
from qutebrowser.utils import usertypes, objreg, version, qtutils, log
from qutebrowser.misc import objects, msgbox


_Result = usertypes.enum(
    '_Result',
    ['quit', 'restart', 'restart_webkit', 'restart_webengine'],
    is_int=True, start=QDialog.Accepted + 1)


@attr.s
class _Button:

    """A button passed to BackendProblemDialog."""

    text = attr.ib()
    setting = attr.ib()
    value = attr.ib()
    default = attr.ib(default=False)


class _Dialog(QDialog):
コード例 #33
0
from qutebrowser.browser import pdfjs


@attr.s
class DistributionInfo:

    """Information about the running distribution."""

    id = attr.ib()
    parsed = attr.ib()
    version = attr.ib()
    pretty = attr.ib()


Distribution = usertypes.enum(
    'Distribution', ['unknown', 'ubuntu', 'debian', 'void', 'arch',
                     'gentoo', 'fedora', 'opensuse', 'linuxmint', 'manjaro'])


def distribution():
    """Get some information about the running Linux distribution.

    Returns:
        A DistributionInfo object, or None if no info could be determined.
            parsed: A Distribution enum member
            version: A Version object, or None
            pretty: Always a string (might be "Unknown")
    """
    filename = os.environ.get('QUTE_FAKE_OS_RELEASE', '/etc/os-release')
    info = {}
    try:
コード例 #34
0
ファイル: browsertab.py プロジェクト: xijia37/qutebrowser
        webkittab.init()


class WebTabError(Exception):
    """Base class for various errors."""


class UnsupportedOperationError(WebTabError):
    """Raised when an operation is not supported with the given backend."""


TerminationStatus = usertypes.enum(
    'TerminationStatus',
    [
        'normal',
        'abnormal',  # non-zero exit status
        'crashed',  # e.g. segfault
        'killed',
        'unknown',
    ])


class TabData:
    """A simple namespace with a fixed set of attributes.

    Attributes:
        keep_icon: Whether the (e.g. cloned) icon should not be cleared on page
                   load.
        inspector: The QWebInspector used for this webview.
        viewing_source: Set if we're currently showing a source view.
        override_target: Override for open_target for fake clicks (like hints).
コード例 #35
0
"""pytest helper to monkeypatch the message module."""

import logging
import collections

import pytest

from qutebrowser.utils import usertypes


Message = collections.namedtuple('Message', ['level', 'win_id', 'text',
                                             'immediate'])


Level = usertypes.enum('Level', ('error', 'info', 'warning'))


class MessageMock:

    """Helper object for message_mock.

    Attributes:
        _monkeypatch: The pytest monkeypatch fixture.
        Message: A namedtuple representing a message.
        messages: A list of Message tuples.
        caplog: The pytest-capturelog fixture.
        Level: The Level type for easier usage as a fixture.
    """

    Level = Level
コード例 #36
0
ファイル: webelem.py プロジェクト: nielsema/qutebrowser
             without "href".
"""

import collections.abc

from html.parser import HTMLParser

from PyQt5.QtCore import QUrl, Qt, QEvent, QTimer
from PyQt5.QtGui import QMouseEvent

from qutebrowser.config import config
from qutebrowser.keyinput import modeman
from qutebrowser.utils import log, usertypes, utils, qtutils, objreg


Group = usertypes.enum('Group', ['all', 'links', 'images', 'url', 'prevnext',
                                 'inputs', 'headers'])


SELECTORS = {
    Group.all: ('a, area, textarea, select, input:not([type=hidden]), button, '
                'frame, iframe, link, [onclick], [onmousedown], [role=link], '
                '[role=option], [role=button], img'),
    Group.links: 'a, area, link, [role=link]',
    Group.images: 'img',
    Group.url: '[src], [href]',
    Group.prevnext: 'a, area, button, link, [role=button]',
    Group.inputs: ('input[type=text], input[type=email], input[type=url], '
                   'input[type=tel], input[type=number], '
                   'input[type=password], input[type=search], '
                   'input:not([type]), textarea'),
    Group.headers: ('h1, h2, h3, h4, h5, h6'),
コード例 #37
0
ファイル: basecompletion.py プロジェクト: har5ha/qutebrowser
# You should have received a copy of the GNU General Public License
# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.

"""The base completion model for completion in the command line.

Module attributes:
    Role: An enum of user defined model roles.
"""

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItemModel, QStandardItem

from qutebrowser.utils import usertypes, qtutils


Role = usertypes.enum('Role', ['marks', 'sort'], start=Qt.UserRole,
                      is_int=True)


class BaseCompletionModel(QStandardItemModel):

    """A simple QStandardItemModel adopted for completions.

    Used for showing completions later in the CompletionView. Supports setting
    marks and adding new categories/items easily.
    """

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setColumnCount(3)

    def _get_marks(self, needle, haystack):
コード例 #38
0
import datetime

import pkg_resources
from PyQt5.QtCore import pyqtSlot, Qt, QSize
from PyQt5.QtWidgets import (QDialog, QLabel, QTextEdit, QPushButton,
                             QVBoxLayout, QHBoxLayout, QCheckBox,
                             QDialogButtonBox, QApplication)

import qutebrowser
from qutebrowser.utils import version, log, utils, objreg, usertypes
from qutebrowser.misc import (miscwidgets, autoupdate, msgbox, httpclient,
                              pastebin)
from qutebrowser.config import config, configfiles

Result = usertypes.enum('Result', ['restore', 'no_restore'],
                        is_int=True,
                        start=QDialog.Accepted + 1)


def parse_fatal_stacktrace(text):
    """Get useful information from a fatal faulthandler stacktrace.

    Args:
        text: The text to parse.

    Return:
        A tuple with the first element being the error type, and the second
        element being the first stacktrace frame.
    """
    lines = [
        r'Fatal Python error: (.*)',
コード例 #39
0
ファイル: browsertab.py プロジェクト: swalladge/qutebrowser

class WebTabError(Exception):

    """Base class for various errors."""


class UnsupportedOperationError(WebTabError):

    """Raised when an operation is not supported with the given backend."""


TerminationStatus = usertypes.enum('TerminationStatus', [
    'normal',
    'abnormal',  # non-zero exit status
    'crashed',   # e.g. segfault
    'killed',
    'unknown',
])


@attr.s
class TabData:

    """A simple namespace with a fixed set of attributes.

    Attributes:
        keep_icon: Whether the (e.g. cloned) icon should not be cleared on page
                   load.
        inspector: The QWebInspector used for this webview.
        viewing_source: Set if we're currently showing a source view.
コード例 #40
0
"""The tab widget used for TabbedBrowser from browser.py."""

import collections
import functools

from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QSize, QRect, QTimer
from PyQt5.QtWidgets import (QTabWidget, QTabBar, QSizePolicy, QCommonStyle,
                             QStyle, QStylePainter, QStyleOptionTab)
from PyQt5.QtGui import QIcon, QPalette, QColor

from qutebrowser.utils import qtutils, objreg, utils, usertypes
from qutebrowser.config import config
from qutebrowser.browser import webview


PixelMetrics = usertypes.enum('PixelMetrics', ['icon_padding'],
                              start=QStyle.PM_CustomBase, is_int=True)


class TabWidget(QTabWidget):

    """The tab widget used for TabbedBrowser.

    Signals:
        tab_index_changed: Emitted when the current tab was changed.
                           arg 0: The index of the tab which is now focused.
                           arg 1: The total count of tabs.
    """

    tab_index_changed = pyqtSignal(int, int)

    def __init__(self, win_id, parent=None):
コード例 #41
0
ファイル: test_cmdutils.py プロジェクト: mgoral/qutebrowser
class TestRegister:

    # pylint: disable=unused-variable

    def test_simple(self):
        @cmdutils.register()
        def fun():
            """Blah."""
            pass

        cmd = cmdutils.cmd_dict['fun']
        assert cmd.handler is fun
        assert cmd.name == 'fun'
        assert len(cmdutils.cmd_dict) == 1
        assert not cmdutils.aliases

    def test_underlines(self):
        """Make sure the function name is normalized correctly (_ -> -)."""
        @cmdutils.register()
        def eggs_bacon():
            """Blah."""
            pass

        assert cmdutils.cmd_dict['eggs-bacon'].name == 'eggs-bacon'
        assert 'eggs_bacon' not in cmdutils.cmd_dict

    def test_lowercasing(self):
        """Make sure the function name is normalized correctly (uppercase)."""
        @cmdutils.register()
        def Test():  # pylint: disable=invalid-name
            """Blah."""
            pass

        assert cmdutils.cmd_dict['test'].name == 'test'
        assert 'Test' not in cmdutils.cmd_dict

    def test_explicit_name(self):
        """Test register with explicit name."""
        @cmdutils.register(name='foobar')
        def fun():
            """Blah."""
            pass

        assert cmdutils.cmd_dict['foobar'].name == 'foobar'
        assert 'fun' not in cmdutils.cmd_dict
        assert len(cmdutils.cmd_dict) == 1
        assert not cmdutils.aliases

    def test_multiple_names(self):
        """Test register with name being a list."""
        @cmdutils.register(name=['foobar', 'blub'])
        def fun():
            """Blah."""
            pass

        assert cmdutils.cmd_dict['foobar'].name == 'foobar'
        assert cmdutils.cmd_dict['blub'].name == 'foobar'
        assert 'fun' not in cmdutils.cmd_dict
        assert len(cmdutils.cmd_dict) == 2
        assert cmdutils.aliases == ['blub']

    def test_multiple_registrations(self):
        """Make sure registering the same name twice raises ValueError."""
        @cmdutils.register(name=['foobar', 'blub'])
        def fun():
            """Blah."""
            pass

        with pytest.raises(ValueError):

            @cmdutils.register(name=['blah', 'blub'])
            def fun2():
                """Blah."""
                pass

    def test_instance(self):
        """Make sure the instance gets passed to Command."""
        @cmdutils.register(instance='foobar')
        def fun(self):
            """Blah."""
            pass

        assert cmdutils.cmd_dict['fun']._instance == 'foobar'

    def test_kwargs(self):
        """Make sure the other keyword arguments get passed to Command."""
        @cmdutils.register(hide=True)
        def fun():
            """Blah."""
            pass

        assert cmdutils.cmd_dict['fun'].hide

    def test_star_args(self):
        """Check handling of *args."""
        @cmdutils.register()
        def fun(*args):
            """Blah."""
            pass

        with pytest.raises(argparser.ArgumentParserError):
            cmdutils.cmd_dict['fun'].parser.parse_args([])

    def test_star_args_optional(self):
        """Check handling of *args withstar_args_optional."""
        @cmdutils.register(star_args_optional=True)
        def fun(*args):
            """Blah."""
            pass

        cmdutils.cmd_dict['fun'].parser.parse_args([])

    def test_flag(self):
        @cmdutils.register()
        def fun(arg=False):
            """Blah."""
            pass

        parser = cmdutils.cmd_dict['fun'].parser
        assert parser.parse_args(['--arg']).arg
        assert parser.parse_args(['-a']).arg
        assert not parser.parse_args([]).arg

    def test_flag_argument(self):
        @cmdutils.register()
        @cmdutils.argument('arg', flag='b')
        def fun(arg=False):
            """Blah."""
            pass

        parser = cmdutils.cmd_dict['fun'].parser

        assert parser.parse_args(['-b']).arg
        with pytest.raises(argparser.ArgumentParserError):
            parser.parse_args(['-a'])

    def test_partial_arg(self):
        """Test with only some arguments decorated with @cmdutils.argument."""
        @cmdutils.register()
        @cmdutils.argument('arg1', flag='b')
        def fun(arg1=False, arg2=False):
            """Blah."""
            pass

    def test_win_id(self):
        @cmdutils.register()
        @cmdutils.argument('win_id', win_id=True)
        def fun(win_id):
            """Blah."""
            pass

        assert cmdutils.cmd_dict['fun']._get_call_args(42) == ([42], {})

    def test_count(self):
        @cmdutils.register()
        @cmdutils.argument('count', count=True)
        def fun(count=0):
            """Blah."""
            pass

        assert cmdutils.cmd_dict['fun']._get_call_args(42) == ([0], {})

    def test_count_without_default(self):
        with pytest.raises(TypeError) as excinfo:

            @cmdutils.register()
            @cmdutils.argument('count', count=True)
            def fun(count):
                """Blah."""
                pass

        expected = "fun: handler has count parameter without default!"
        assert str(excinfo.value) == expected

    @pytest.mark.parametrize('hide', [True, False])
    def test_pos_args(self, hide):
        @cmdutils.register()
        @cmdutils.argument('arg', hide=hide)
        def fun(arg):
            """Blah."""
            pass

        pos_args = cmdutils.cmd_dict['fun'].pos_args
        if hide:
            assert pos_args == []
        else:
            assert pos_args == [('arg', 'arg')]

    Enum = usertypes.enum('Test', ['x', 'y'])

    @pytest.mark.parametrize(
        'typ, inp, choices, expected',
        [
            (int, '42', None, 42),
            (int, 'x', None, cmdexc.ArgumentTypeError),
            (str, 'foo', None, 'foo'),
            (typing.Union[str, int], 'foo', None, 'foo'),
            (typing.Union[str, int], '42', None, 42),

            # Choices
            (str, 'foo', ['foo'], 'foo'),
            (str, 'bar', ['foo'], cmdexc.ArgumentTypeError),

            # Choices with Union: only checked when it's a str
            (typing.Union[str, int], 'foo', ['foo'], 'foo'),
            (typing.Union[str, int], 'bar', ['foo'], cmdexc.ArgumentTypeError),
            (typing.Union[str, int], '42', ['foo'], 42),
            (Enum, 'x', None, Enum.x),
            (Enum, 'z', None, cmdexc.ArgumentTypeError),
        ])
    def test_typed_args(self, typ, inp, choices, expected):
        @cmdutils.register()
        @cmdutils.argument('arg', choices=choices)
        def fun(arg: typ):
            """Blah."""
            pass

        cmd = cmdutils.cmd_dict['fun']
        cmd.namespace = cmd.parser.parse_args([inp])

        if expected is cmdexc.ArgumentTypeError:
            with pytest.raises(cmdexc.ArgumentTypeError):
                cmd._get_call_args(win_id=0)
        else:
            assert cmd._get_call_args(win_id=0) == ([expected], {})
コード例 #42
0
import collections
import functools

from PyQt5.QtCore import (pyqtSignal, pyqtSlot, Qt, QSize, QRect, QPoint,
                          QTimer, QUrl)
from PyQt5.QtWidgets import (QTabWidget, QTabBar, QSizePolicy, QCommonStyle,
                             QStyle, QStylePainter, QStyleOptionTab,
                             QStyleFactory, QWidget)
from PyQt5.QtGui import QIcon, QPalette, QColor

from qutebrowser.utils import qtutils, objreg, utils, usertypes, log
from qutebrowser.config import config
from qutebrowser.misc import objects


PixelMetrics = usertypes.enum('PixelMetrics', ['icon_padding'],
                              start=QStyle.PM_CustomBase, is_int=True)


class TabWidget(QTabWidget):

    """The tab widget used for TabbedBrowser.

    Signals:
        tab_index_changed: Emitted when the current tab was changed.
                           arg 0: The index of the tab which is now focused.
                           arg 1: The total count of tabs.
    """

    tab_index_changed = pyqtSignal(int, int)

    def __init__(self, win_id, parent=None):
コード例 #43
0
Module attributes:
    ATTRIBUTES: A mapping from internal setting names to QWebSetting enum
                constants.
    SETTERS: A mapping from setting names to QWebSetting setter method names.
    settings: The global QWebSettings singleton instance.
"""

import os.path

from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtCore import QStandardPaths

from qutebrowser.config import config
from qutebrowser.utils import usertypes, standarddir, objreg

MapType = usertypes.enum('MapType', ['attribute', 'setter', 'static_setter'])


MAPPINGS = {
    'permissions': {
        'allow-images':
            (MapType.attribute, QWebSettings.AutoLoadImages),
        'allow-javascript':
            (MapType.attribute, QWebSettings.JavascriptEnabled),
        'javascript-can-open-windows':
            (MapType.attribute, QWebSettings.JavascriptCanOpenWindows),
        'javascript-can-close-windows':
            (MapType.attribute, QWebSettings.JavascriptCanCloseWindows),
        'javascript-can-access-clipboard':
            (MapType.attribute, QWebSettings.JavascriptCanAccessClipboard),
        #'allow-java':
コード例 #44
0
import os
import sys
import shutil
import os.path
import contextlib

from PyQt5.QtCore import QStandardPaths
from PyQt5.QtWidgets import QApplication

from qutebrowser.utils import log, debug, usertypes, message, utils

# The cached locations
_locations = {}

Location = usertypes.enum('Location', [
    'config', 'auto_config', 'data', 'system_data', 'cache', 'download',
    'runtime'
])

APPNAME = 'qutebrowser'


class EmptyValueError(Exception):
    """Error raised when QStandardPaths returns an empty value."""


@contextlib.contextmanager
def _unset_organization():
    """Temporarily unset QApplication.organizationName().

    This is primarily needed in config.py.
    """
コード例 #45
0
ファイル: test_enum.py プロジェクト: lahwaacz/qutebrowser
def enum():
    return usertypes.enum("Enum", ["one", "two"])
コード例 #46
0
ファイル: webelem.py プロジェクト: zky001/qutebrowser
    SELECTORS: CSS selectors for different groups of elements.
    FILTERS: A dictionary of filter functions for the modes.
             The filter for "links" filters javascript:-links and a-tags
             without "href".
"""

import collections.abc
import functools

from PyQt5.QtCore import QRect, QUrl
from PyQt5.QtWebKit import QWebElement

from qutebrowser.config import config
from qutebrowser.utils import log, usertypes, utils

Group = usertypes.enum('Group',
                       ['all', 'links', 'images', 'url', 'prevnext', 'focus'])

SELECTORS = {
    Group.all: ('a, area, textarea, select, input:not([type=hidden]), button, '
                'frame, iframe, link, [onclick], [onmousedown], [role=link], '
                '[role=option], [role=button], img'),
    Group.links:
    'a, area, link, [role=link]',
    Group.images:
    'img',
    Group.url:
    '[src], [href]',
    Group.prevnext:
    'a, area, button, link, [role=button]',
    Group.focus:
    '*:focus',
コード例 #47
0
ファイル: test_enum.py プロジェクト: lahwaacz/qutebrowser
def test_start():
    """Test the start= argument."""
    e = usertypes.enum("Enum", ["three", "four"], start=3)
    assert e.three.value == 3
    assert e.four.value == 4
コード例 #48
0
ファイル: downloads.py プロジェクト: jamesstidard/qutebrowser
import collections
import functools
import pathlib
import tempfile

import sip
from PyQt5.QtCore import (pyqtSlot, pyqtSignal, Qt, QObject, QModelIndex,
                          QTimer, QAbstractListModel)

from qutebrowser.commands import cmdexc, cmdutils
from qutebrowser.config import config
from qutebrowser.utils import (usertypes, standarddir, utils, message, log,
                               qtutils)


ModelRole = usertypes.enum('ModelRole', ['item'], start=Qt.UserRole,
                           is_int=True)


# Remember the last used directory
last_used_directory = None


# All REFRESH_INTERVAL milliseconds, speeds will be recalculated and downloads
# redrawn.
_REFRESH_INTERVAL = 500


class UnsupportedAttribute:

    """Class which is used to create attributes which are not supported.
コード例 #49
0
ファイル: test_enum.py プロジェクト: lahwaacz/qutebrowser
def test_is_int():
    """Test the is_int argument."""
    int_enum = usertypes.enum("Enum", ["item"], is_int=True)
    no_int_enum = usertypes.enum("Enum", ["item"])
    assert isinstance(int_enum.item, int)
    assert not isinstance(no_int_enum.item, int)
コード例 #50
0
ファイル: hints.py プロジェクト: posativ/qutebrowser
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QEvent, Qt, QUrl
from PyQt5.QtGui import QMouseEvent, QClipboard
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebKit import QWebElement

from qutebrowser.config import config
from qutebrowser.keyinput import modeman, modeparsers
from qutebrowser.browser import webelem
from qutebrowser.commands import userscripts, cmdexc, cmdutils, runners
from qutebrowser.utils import usertypes, log, qtutils, message, objreg

ElemTuple = collections.namedtuple('ElemTuple', ['elem', 'label'])

Target = usertypes.enum('Target', [
    'normal', 'tab', 'tab_bg', 'window', 'yank', 'yank_primary', 'run', 'fill',
    'hover', 'rapid', 'rapid_win', 'download', 'userscript', 'spawn'
])


@pyqtSlot(usertypes.KeyMode)
def on_mode_entered(mode, win_id):
    """Stop hinting when insert mode was entered."""
    if mode == usertypes.KeyMode.insert:
        modeman.maybe_leave(win_id, usertypes.KeyMode.hint, 'insert mode')


class HintContext:
    """Context namespace used for hinting.

    Attributes:
        frames: The QWebFrames to use.
コード例 #51
0
ファイル: test_enum.py プロジェクト: lahwaacz/qutebrowser
def test_unique():
    """Make sure elements need to be unique."""
    with pytest.raises(TypeError):
        usertypes.enum("Enum", ["item", "item"])
コード例 #52
0
ファイル: downloads.py プロジェクト: a2batic/qutebrowser
from PyQt5.QtCore import (pyqtSlot, pyqtSignal, QObject, QTimer,
                          Qt, QVariant, QAbstractListModel, QModelIndex, QUrl)
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply
# We need this import so PyQt can use it inside pyqtSlot
from PyQt5.QtWebKitWidgets import QWebPage  # pylint: disable=unused-import

from qutebrowser.config import config
from qutebrowser.commands import cmdexc, cmdutils
from qutebrowser.utils import (message, usertypes, log, utils, urlutils,
                               objreg, standarddir, qtutils)
from qutebrowser.browser import http
from qutebrowser.browser.network import networkmanager


ModelRole = usertypes.enum('ModelRole', ['item'], start=Qt.UserRole,
                           is_int=True)


RetryInfo = collections.namedtuple('RetryInfo', ['request', 'manager'])


DownloadPath = collections.namedtuple('DownloadPath', ['filename',
                                                       'question'])


# Remember the last used directory
last_used_directory = None


# All REFRESH_INTERVAL milliseconds, speeds will be recalculated and downloads
# redrawn.
コード例 #53
0
ファイル: url.py プロジェクト: peterlvilim/qutebrowser
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.

"""URL displayed in the statusbar."""

from PyQt5.QtCore import pyqtSlot, pyqtProperty, Qt

from qutebrowser.browser import webview
from qutebrowser.mainwindow.statusbar import textbase
from qutebrowser.config import style
from qutebrowser.utils import usertypes


# Note this has entries for success/error/warn from widgets.webview:LoadStatus
UrlType = usertypes.enum('UrlType', ['success', 'error', 'warn', 'hover',
                                     'normal'])


class UrlText(textbase.TextBase):

    """URL displayed in the statusbar.

    Attributes:
        _normal_url: The normal URL to be displayed as a UrlType instance.
        _normal_url_type: The type of the normal URL as a UrlType instance.
        _hover_url: The URL we're currently hovering over.
        _ssl_errors: Whether SSL errors occured while loading.

    Class attributes:
        _urltype: The URL type to show currently (normal/ok/error/warn/hover).
                  Accessed via the urltype property.
コード例 #54
0
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.

"""Tests for qutebrowser.commands.argparser."""

import inspect

import pytest
from PyQt5.QtCore import QUrl

from qutebrowser.commands import argparser, cmdexc
from qutebrowser.utils import usertypes, objreg


Enum = usertypes.enum("Enum", ["foo", "foo_bar"])


class FakeTabbedBrowser:
    def __init__(self):
        self.opened_url = None

    def tabopen(self, url):
        self.opened_url = url


class TestArgumentParser:
    @pytest.fixture
    def parser(self):
        return argparser.ArgumentParser("foo")
コード例 #55
0
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.

"""Tests for qutebrowser.commands.argparser."""

import inspect

import pytest
from PyQt5.QtCore import QUrl

from qutebrowser.commands import argparser, cmdexc
from qutebrowser.utils import usertypes, objreg


Enum = usertypes.enum('Enum', ['foo', 'foo_bar'])


class FakeTabbedBrowser:

    def __init__(self):
        self.opened_url = None

    def tabopen(self, url):
        self.opened_url = url


class TestArgumentParser:

    @pytest.fixture
    def parser(self):
コード例 #56
0
ファイル: base.py プロジェクト: Dietr1ch/qutebrowser
# You should have received a copy of the GNU General Public License
# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.

"""The base completion model for completion in the command line.

Module attributes:
    Role: An enum of user defined model roles.
"""

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItemModel, QStandardItem

from qutebrowser.utils import usertypes


Role = usertypes.enum('Role', ['sort', 'userdata'], start=Qt.UserRole,
                      is_int=True)


class BaseCompletionModel(QStandardItemModel):

    """A simple QStandardItemModel adopted for completions.

    Used for showing completions later in the CompletionView. Supports setting
    marks and adding new categories/items easily.

    Class Attributes:
        COLUMN_WIDTHS: The width percentages of the columns used in the
                        completion view.
        DUMB_SORT: the dumb sorting used by the model
    """
コード例 #57
0
ファイル: text.py プロジェクト: zky001/qutebrowser
class Text(textbase.TextBase):

    """Text displayed in the statusbar.

    Attributes:
        _normaltext: The "permanent" text. Never automatically cleared.
        _temptext: The temporary text to display.
        _jstext: The text javascript wants to display.

        The temptext is shown from StatusBar when a temporary text or error is
        available. If not, the permanent text is shown.
    """

    Text = usertypes.enum('Text', ['normal', 'temp', 'js'])

    def __init__(self, parent=None):
        super().__init__(parent)
        self._normaltext = ''
        self._temptext = ''
        self._jstext = ''
        objreg.get('config').changed.connect(self.update_text)

    def set_text(self, which, text):
        """Set a text.

        Args:
            which: Which text to set, a self.Text instance.
            text: The text to set.
        """
        log.statusbar.debug("Setting {} text to '{}'.".format(
            which.name, text))
        if which is self.Text.normal:
            self._normaltext = text
        elif which is self.Text.temp:
            self._temptext = text
        elif which is self.Text.js:
            self._jstext = text
        else:
            raise ValueError("Invalid value {} for which!".format(which))
        self.update_text()

    @pyqtSlot(str)
    def maybe_reset_text(self, text):
        """Clear a normal text if it still matches an expected text."""
        if self._normaltext == text:
            log.statusbar.debug("Resetting: '{}'".format(text))
            self.set_text(self.Text.normal, '')
        else:
            log.statusbar.debug("Ignoring reset: '{}'".format(text))

    @config.change_filter('ui', 'display-statusbar-messages')
    def update_text(self):
        """Update QLabel text when needed."""
        if self._temptext:
            self.setText(self._temptext)
        elif self._jstext and config.get('ui', 'display-statusbar-messages'):
            self.setText(self._jstext)
        elif self._normaltext:
            self.setText(self._normaltext)
        else:
            self.setText('')

    @pyqtSlot(str)
    def on_statusbar_message(self, val):
        """Called when javascript tries to set a statusbar message."""
        self._jstext = val

    @pyqtSlot()
    def on_load_started(self):
        """Clear jstext when page loading started."""
        self._jstext = ''

    @pyqtSlot(int)
    def on_tab_changed(self, tab):
        """Set the correct jstext when the current tab changed."""
        self._jstext = tab.statusbar_message