Ejemplo n.º 1
0
    def _filter_number_hints(self):
        """Apply filters for numbered hints and renumber them.

        Return:
            Elements which are still visible
        """
        # renumber filtered hints
        elems = []
        for e in self._context.all_elems:
            try:
                if not self._is_hidden(e.label):
                    elems.append(e)
            except webelem.IsNullError:
                pass
        if not elems:
            # Whoops, filtered all hints
            modeman.leave(self._win_id, usertypes.KeyMode.hint,
                          'all filtered')
            return {}

        strings = self._hint_strings(elems)
        self._context.elems = {}
        for elem, string in zip(elems, strings):
            elem.label.setInnerXml(string)
            self._context.elems[string] = elem
        keyparsers = objreg.get('keyparsers', scope='window',
                                window=self._win_id)
        keyparser = keyparsers[usertypes.KeyMode.hint]
        keyparser.update_bindings(strings, preserve_filter=True)

        return self._context.elems
Ejemplo n.º 2
0
 def _on_aborted(self, key_mode):
     """Leave KEY_MODE whenever a prompt is aborted."""
     try:
         modeman.leave(self._win_id, key_mode, 'aborted', maybe=True)
     except objreg.RegistryUnavailableError:
         # window was deleted: ignore
         pass
Ejemplo n.º 3
0
    def filter_hints(self, filterstr):
        """Filter displayed hints according to a text.

        Args:
            filterstr: The string to filer with, or None to show all.
        """
        for elems in self._context.elems.values():
            if (filterstr is None or
                    str(elems.elem).lower().startswith(filterstr)):
                if self._is_hidden(elems.label):
                    # hidden element which matches again -> unhide it
                    elems.label.setStyleProperty('display', 'none')
            else:
                # element doesn't match anymore -> hide it
                elems.label.setStyleProperty('display', 'none')
        visible = {}
        for k, e in self._context.elems.items():
            if not self._is_hidden(e.label):
                visible[k] = e
        if not visible:
            # Whoops, filtered all hints
            modeman.leave(self._win_id, usertypes.KeyMode.hint, 'all filtered')
        elif len(visible) == 1 and config.get('hints', 'auto-follow'):
            # unpacking gets us the first (and only) key in the dict.
            self.fire(*visible)
Ejemplo n.º 4
0
    def filter_hints(self, filterstr):
        """Filter displayed hints according to a text.

        Args:
            filterstr: The string to filter with, or None to show all.
        """
        for elems in self._context.elems.values():
            try:
                if (filterstr is None or
                        filterstr.casefold() in str(elems.elem).casefold()):
                    if self._is_hidden(elems.label):
                        # hidden element which matches again -> show it
                        self._show_elem(elems.label)
                else:
                    # element doesn't match anymore -> hide it
                    self._hide_elem(elems.label)
            except webelem.IsNullError:
                pass
        visible = {}
        for k, e in self._context.elems.items():
            try:
                if not self._is_hidden(e.label):
                    visible[k] = e
            except webelem.IsNullError:
                pass
        if not visible:
            # Whoops, filtered all hints
            modeman.leave(self._win_id, usertypes.KeyMode.hint, 'all filtered')
        elif len(visible) == 1 and config.get('hints', 'auto-follow'):
            # unpacking gets us the first (and only) key in the dict.
            self.fire(*visible)
Ejemplo n.º 5
0
 def prompt_yes(self):
     """Answer yes to a yes/no prompt."""
     if self._question.mode != usertypes.PromptMode.yesno:
         # We just ignore this if we don't have a yes/no question.
         return
     self._question.answer = True
     modeman.leave(usertypes.KeyMode.yesno, 'yesno accept')
     self._question.done()
Ejemplo n.º 6
0
 def prompt_no(self):
     """Answer no to a yes/no prompt."""
     if self._question.mode != usertypes.PromptMode.yesno:
         # We just ignore this if we don't have a yes/no question.
         return
     self._question.answer = False
     modeman.leave(self._win_id, usertypes.KeyMode.yesno, 'prompt accept')
     self._question.done()
Ejemplo n.º 7
0
    def filter_hints(self, filterstr):
        """Filter displayed hints according to a text.

        Args:
            filterstr: The string to filter with, or None to use the filter
                       from previous call (saved in `self._filterstr`). If
                       `filterstr` is an empty string or if both `filterstr`
                       and `self._filterstr` are None, all hints are shown.
        """
        if filterstr is None:
            filterstr = self._context.filterstr
        else:
            self._context.filterstr = filterstr

        log.hints.debug("Filtering hints on {!r}".format(filterstr))

        visible = []
        # pylint: disable=not-an-iterable
        for label in self._context.all_labels:
            try:
                if self._filter_matches(filterstr, str(label.elem)):
                    visible.append(label)
                    # Show label again if it was hidden before
                    label.show()
                else:
                    # element doesn't match anymore -> hide it
                    label.hide()
            except webelem.Error:
                pass
        # pylint: enable=not-an-iterable

        if not visible:
            # Whoops, filtered all hints
            modeman.leave(self._win_id, usertypes.KeyMode.hint,
                          'all filtered')
            return

        if self._context.hint_mode == 'number':
            # renumber filtered hints
            strings = self._hint_strings(visible)
            self._context.labels = {}
            for label, string in zip(visible, strings):
                label.update_text('', string)
                self._context.labels[string] = label
            keyparsers = objreg.get('keyparsers', scope='window',
                                    window=self._win_id)
            keyparser = keyparsers[usertypes.KeyMode.hint]
            keyparser.update_bindings(strings, preserve_filter=True)

            # Note: filter_hints can be called with non-None filterstr only
            # when number mode is active
            if filterstr is not None:
                # pass self._context.labels as the dict of visible hints
                self._handle_auto_follow(filterstr=filterstr,
                                         visible=self._context.labels)
Ejemplo n.º 8
0
 def command_accept(self):
     """Execute the command currently in the commandline."""
     prefixes = {
         ':': '',
         '/': 'search -- ',
         '?': 'search -r -- ',
     }
     text = self.text()
     self.history.append(text)
     modeman.leave(self._win_id, usertypes.KeyMode.command, 'cmd accept')
     self.got_cmd.emit(prefixes[text[0]] + text[1:])
Ejemplo n.º 9
0
 def command_accept(self):
     """Execute the command currently in the commandline."""
     signals = {
         ':': self.got_cmd,
         '/': self.got_search,
         '?': self.got_search_rev,
     }
     text = self.text()
     self.history.append(text)
     modeman.leave(self._win_id, usertypes.KeyMode.command, 'cmd accept')
     if text[0] in signals:
         signals[text[0]].emit(text.lstrip(text[0]))
Ejemplo n.º 10
0
        def mouserelease_insertmode_cb(elem):
            """Callback which gets called from JS."""
            if elem is None:
                log.mouse.debug("Element vanished!")
                return

            if elem.is_editable():
                log.mouse.debug("Clicked editable element (delayed)!")
                modeman.enter(self._tab.win_id, usertypes.KeyMode.insert,
                              'click-delayed', only_if_normal=True)
            else:
                log.mouse.debug("Clicked non-editable element (delayed)!")
                if config.get('input', 'auto-leave-insert-mode'):
                    modeman.leave(self._tab.win_id, usertypes.KeyMode.insert,
                                  'click-delayed', maybe=True)
Ejemplo n.º 11
0
    def _on_global_mode_left(self, mode):
        """Leave prompt/yesno mode in this window if it was left elsewhere.

        This ensures no matter where a prompt was answered, we leave the prompt
        mode and dispose of the prompt object in every window.
        """
        if mode not in [usertypes.KeyMode.prompt, usertypes.KeyMode.yesno]:
            return
        modeman.leave(self._win_id, mode, 'left in other window', maybe=True)
        item = self._layout.takeAt(0)
        if item is not None:
            widget = item.widget()
            log.prompt.debug("Deleting prompt {}".format(widget))
            widget.hide()
            widget.deleteLater()
Ejemplo n.º 12
0
    def command_accept(self, rapid=False):
        """Execute the command currently in the commandline.

        Args:
            rapid: Run the command without closing or clearing the command bar.
        """
        text = self.text()
        self.history.append(text)

        was_search = self._handle_search()

        if not rapid:
            modeman.leave(self._win_id, usertypes.KeyMode.command,
                          'cmd accept')

        if not was_search:
            self.got_cmd[str].emit(text[1:])
Ejemplo n.º 13
0
    def _filter_non_number_hints(self):
        """Apply filters for letter/word hints.

        Return:
            Elements which are still visible
        """
        visible = {}
        for string, elem in self._context.elems.items():
            try:
                if not self._is_hidden(elem.label):
                    visible[string] = elem
            except webelem.IsNullError:
                pass
        if not visible:
            # Whoops, filtered all hints
            modeman.leave(self._win_id, usertypes.KeyMode.hint,
                          'all filtered')
        return visible
Ejemplo n.º 14
0
    def command_accept(self):
        """Execute the command currently in the commandline.

        Emit:
            got_cmd: If a new cmd was entered.
            got_search: If a new search was entered.
            got_search_rev: If a new reverse search was entered.
        """
        signals = {
            ':': self.got_cmd,
            '/': self.got_search,
            '?': self.got_search_rev,
        }
        text = self.text()
        self.history.append(text)
        modeman.leave(usertypes.KeyMode.command, 'cmd accept')
        if text[0] in signals:
            signals[text[0]].emit(text.lstrip(text[0]))
Ejemplo n.º 15
0
    def keyPressEvent(self, e):
        """Override keyPressEvent to ignore Return key presses.

        If this widget is focused, we are in passthrough key mode, and
        Enter/Shift+Enter/etc. will cause QLineEdit to think it's finished
        without command_accept to be called.
        """
        text = self.text()
        if text in modeparsers.STARTCHARS and e.key() == Qt.Key_Backspace:
            e.accept()
            modeman.leave(self._win_id, usertypes.KeyMode.command,
                          'prefix deleted')
            return
        if e.key() == Qt.Key_Return:
            e.ignore()
            return
        else:
            super().keyPressEvent(e)
Ejemplo n.º 16
0
 def _leave_modes_on_load(self):
     """Leave insert/hint mode when loading started."""
     try:
         url = self.current_url()
         if not url.isValid():
             url = None
     except qtutils.QtValueError:
         url = None
     if config.instance.get('input.insert_mode.leave_on_load',
                            url=url):
         modeman.leave(self._win_id, usertypes.KeyMode.insert,
                       'load started', maybe=True)
     else:
         log.modes.debug("Ignoring leave_on_load request due to setting.")
     if config.cache['hints.leave_on_load']:
         modeman.leave(self._win_id, usertypes.KeyMode.hint,
                       'load started', maybe=True)
     else:
         log.modes.debug("Ignoring leave_on_load request due to setting.")
Ejemplo n.º 17
0
    def _mousepress_insertmode_cb(self, elem):
        """Check if the clicked element is editable."""
        if elem is None:
            # Something didn't work out, let's find the focus element after
            # a mouse release.
            log.mouse.debug("Got None element, scheduling check on "
                            "mouse release")
            self._check_insertmode_on_release = True
            return

        if elem.is_editable():
            log.mouse.debug("Clicked editable element!")
            modeman.enter(self._tab.win_id, usertypes.KeyMode.insert,
                          'click', only_if_normal=True)
        else:
            log.mouse.debug("Clicked non-editable element!")
            if config.get('input', 'auto-leave-insert-mode'):
                modeman.leave(self._tab.win_id, usertypes.KeyMode.insert,
                              'click', maybe=True)
Ejemplo n.º 18
0
    def on_current_changed(self, idx):
        """Set last-focused-tab and leave hinting mode when focus changed."""
        mode_on_change = config.val.tabs.mode_on_change
        modes_to_save = [usertypes.KeyMode.insert,
                         usertypes.KeyMode.passthrough]
        if idx == -1 or self.shutting_down:
            # closing the last tab (before quitting) or shutting down
            return
        tab = self.widget(idx)
        if tab is None:
            log.webview.debug("on_current_changed got called with invalid "
                              "index {}".format(idx))
            return
        if self._now_focused is not None and mode_on_change == 'restore':
            current_mode = modeman.instance(self._win_id).mode
            if current_mode not in modes_to_save:
                current_mode = usertypes.KeyMode.normal
            self._now_focused.data.input_mode = current_mode

        log.modes.debug("Current tab changed, focusing {!r}".format(tab))
        tab.setFocus()

        modes_to_leave = [usertypes.KeyMode.hint, usertypes.KeyMode.caret]
        if mode_on_change != 'persist':
            modes_to_leave += modes_to_save
        for mode in modes_to_leave:
            modeman.leave(self._win_id, mode, 'tab changed', maybe=True)
        if mode_on_change == 'restore':
            modeman.enter(self._win_id, tab.data.input_mode,
                          'restore input mode for tab')
        if self._now_focused is not None:
            objreg.register('last-focused-tab', self._now_focused, update=True,
                            scope='window', window=self._win_id)
        self._now_focused = tab
        self.current_tab_changed.emit(tab)
        QTimer.singleShot(0, self._update_window_title)
        self._tab_insert_idx_left = self.currentIndex()
        self._tab_insert_idx_right = self.currentIndex() + 1
Ejemplo n.º 19
0
    def on_current_changed(self, idx):
        """Set last-focused-tab and leave hinting mode when focus changed."""
        mode_on_change = config.val.tabs.mode_on_change
        if idx == -1 or self.shutting_down:
            # closing the last tab (before quitting) or shutting down
            return
        tab = self.widget.widget(idx)
        if tab is None:
            log.webview.debug("on_current_changed got called with invalid "
                              "index {}".format(idx))
            return

        log.modes.debug("Current tab changed, focusing {!r}".format(tab))
        tab.setFocus()

        modes_to_leave = [usertypes.KeyMode.hint, usertypes.KeyMode.caret]

        mm_instance = modeman.instance(self._win_id)
        current_mode = mm_instance.mode
        log.modes.debug("Mode before tab change: {} (mode_on_change = {})"
                        .format(current_mode.name, mode_on_change))
        if mode_on_change == 'normal':
            modes_to_leave += modeman.INPUT_MODES
        for mode in modes_to_leave:
            modeman.leave(self._win_id, mode, 'tab changed', maybe=True)
        if (mode_on_change == 'restore' and
                current_mode not in modeman.PROMPT_MODES):
            modeman.enter(self._win_id, tab.data.input_mode, 'restore')
        if self._now_focused is not None:
            objreg.register('last-focused-tab', self._now_focused, update=True,
                            scope='window', window=self._win_id)
        log.modes.debug("Mode after tab change: {} (mode_on_change = {})"
                        .format(current_mode.name, mode_on_change))
        self._now_focused = tab
        self.current_tab_changed.emit(tab)
        QTimer.singleShot(0, self._update_window_title)
        self._tab_insert_idx_left = self.widget.currentIndex()
        self._tab_insert_idx_right = self.widget.currentIndex() + 1
Ejemplo n.º 20
0
    def on_current_changed(self, idx):
        """Set last-focused-tab and leave hinting mode when focus changed."""
        if idx == -1 or self.shutting_down:
            # closing the last tab (before quitting) or shutting down
            return
        tab = self.widget(idx)
        if tab is None:
            log.webview.debug("on_current_changed got called with invalid "
                              "index {}".format(idx))
            return

        log.modes.debug("Current tab changed, focusing {!r}".format(tab))
        tab.setFocus()
        for mode in [usertypes.KeyMode.hint, usertypes.KeyMode.insert,
                     usertypes.KeyMode.caret, usertypes.KeyMode.passthrough]:
            modeman.leave(self._win_id, mode, 'tab changed', maybe=True)
        if self._now_focused is not None:
            objreg.register('last-focused-tab', self._now_focused, update=True,
                            scope='window', window=self._win_id)
        self._now_focused = tab
        self.current_tab_changed.emit(tab)
        QTimer.singleShot(0, self._update_window_title)
        self._tab_insert_idx_left = self.currentIndex()
        self._tab_insert_idx_right = self.currentIndex() + 1
Ejemplo n.º 21
0
 def filter_hints(self, filterstr):
     """Filter displayed hints according to a text."""
     for elems in self._context.elems.values():
         if str(elems.elem).lower().startswith(filterstr):
             if elems.label['hidden'] == 'true':
                 # hidden element which matches again -> unhide it
                 elems.label['hidden'] = 'false'
                 css = self._get_hint_css(elems.elem, elems.label)
                 elems.label['style'] = css
         else:
             # element doesn't match anymore -> hide it
             elems.label['hidden'] = 'true'
             css = self._get_hint_css(elems.elem, elems.label)
             elems.label['style'] = css
     visible = {}
     for k, e in self._context.elems.items():
         if e.label['hidden'] != 'true':
             visible[k] = e
     if not visible:
         # Whoops, filtered all hints
         modeman.leave(usertypes.KeyMode.hint, 'all filtered')
     elif len(visible) == 1 and config.get('hints', 'auto-follow'):
         # unpacking gets us the first (and only) key in the dict.
         self.fire(*visible)
Ejemplo n.º 22
0
    def prompt_accept(self):
        """Accept the current prompt.

        //

        This executes the next action depending on the question mode, e.g. asks
        for the password or leaves the mode.
        """
        prompt = objreg.get('prompt', scope='window', window=self._win_id)
        if (self._question.mode == usertypes.PromptMode.user_pwd and
                self._question.user is None):
            # User just entered an username
            self._question.user = prompt.lineedit.text()
            prompt.txt.setText("Password:"******"Invalid question mode!")
Ejemplo n.º 23
0
    def _on_show_prompts(self, question):
        """Show a prompt for the given question.

        Args:
            question: A Question object or None.
        """
        item = self._layout.takeAt(0)
        if item is not None:
            widget = item.widget()
            log.prompt.debug("Deleting old prompt {}".format(widget))
            widget.hide()
            widget.deleteLater()

        if question is None:
            log.prompt.debug("No prompts left, hiding prompt container.")
            self._prompt = None
            self.hide()
            return

        classes = {
            usertypes.PromptMode.yesno: YesNoPrompt,
            usertypes.PromptMode.text: LineEditPrompt,
            usertypes.PromptMode.user_pwd: AuthenticationPrompt,
            usertypes.PromptMode.download: DownloadFilenamePrompt,
            usertypes.PromptMode.alert: AlertPrompt,
        }
        klass = classes[question.mode]
        prompt = klass(question)

        log.prompt.debug("Displaying prompt {}".format(prompt))
        self._prompt = prompt

        if not question.interrupted:
            # If this question was interrupted, we already connected the signal
            question.aborted.connect(
                lambda: modeman.leave(self._win_id, prompt.KEY_MODE, 'aborted',
                                      maybe=True))
        modeman.enter(self._win_id, prompt.KEY_MODE, 'question asked')

        self.setSizePolicy(prompt.sizePolicy())
        self._layout.addWidget(prompt)
        prompt.show()
        self.show()
        prompt.setFocus()
        self.update_geometry.emit()
Ejemplo n.º 24
0
    def start(self, rapid=False, group=webelem.Group.all, target=Target.normal,
              *args, win_id, mode=None, add_history=False):
        """Start hinting.

        Args:
            rapid: Whether to do rapid hinting. This is only possible with
                   targets `tab` (with `tabs.background_tabs=true`), `tab-bg`,
                   `window`, `run`, `hover`, `userscript` and `spawn`.
            add_history: Whether to add the spawned or yanked link to the
                         browsing history.
            group: The element types to hint.

                - `all`: All clickable elements.
                - `links`: Only links.
                - `images`: Only images.
                - `inputs`: Only input fields.

            target: What to do with the selected element.

                - `normal`: Open the link.
                - `current`: Open the link in the current tab.
                - `tab`: Open the link in a new tab (honoring the
                         `tabs.background_tabs` setting).
                - `tab-fg`: Open the link in a new foreground tab.
                - `tab-bg`: Open the link in a new background tab.
                - `window`: Open the link in a new window.
                - `hover` : Hover over the link.
                - `yank`: Yank the link to the clipboard.
                - `yank-primary`: Yank the link to the primary selection.
                - `run`: Run the argument as command.
                - `fill`: Fill the commandline with the command given as
                          argument.
                - `download`: Download the link.
                - `userscript`: Call a userscript with `$QUTE_URL` set to the
                                link.
                - `spawn`: Spawn a command.

            mode: The hinting mode to use.

                - `number`: Use numeric hints.
                - `letter`: Use the chars in the hints.chars setting.
                - `word`: Use hint words based on the html elements and the
                          extra words.

            *args: Arguments for spawn/userscript/run/fill.

                - With `spawn`: The executable and arguments to spawn.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `userscript`: The userscript to execute. Either store
                                     the userscript in
                                     `~/.local/share/qutebrowser/userscripts`
                                     (or `$XDG_DATA_DIR`), or use an absolute
                                     path.
                - With `fill`: The command to fill the statusbar with.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `run`: Same as `fill`.
        """
        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window=self._win_id)
        tab = tabbed_browser.currentWidget()
        if tab is None:
            raise cmdexc.CommandError("No WebView available yet!")

        mode_manager = objreg.get('mode-manager', scope='window',
                                  window=self._win_id)
        if mode_manager.mode == usertypes.KeyMode.hint:
            modeman.leave(win_id, usertypes.KeyMode.hint, 're-hinting')

        if rapid:
            if target in [Target.tab_bg, Target.window, Target.run,
                          Target.hover, Target.userscript, Target.spawn,
                          Target.download, Target.normal, Target.current]:
                pass
            elif target == Target.tab and config.val.tabs.background:
                pass
            else:
                name = target.name.replace('_', '-')
                raise cmdexc.CommandError("Rapid hinting makes no sense with "
                                          "target {}!".format(name))

        if mode is None:
            mode = config.val.hints.mode

        self._check_args(target, *args)
        self._context = HintContext()
        self._context.tab = tab
        self._context.target = target
        self._context.rapid = rapid
        self._context.hint_mode = mode
        self._context.add_history = add_history
        try:
            self._context.baseurl = tabbed_browser.current_url()
        except qtutils.QtValueError:
            raise cmdexc.CommandError("No URL set for this page yet!")
        self._context.args = args
        self._context.group = group
        selector = webelem.SELECTORS[self._context.group]
        self._context.tab.elements.find_css(selector, self._start_cb,
                                            only_visible=True)
Ejemplo n.º 25
0
    def _fire(self, keystr):
        """Fire a completed hint.

        Args:
            keystr: The keychain string to follow.
        """
        # Handlers which take a QWebElement
        elem_handlers = {
            Target.normal: self._actions.click,
            Target.current: self._actions.click,
            Target.tab: self._actions.click,
            Target.tab_fg: self._actions.click,
            Target.tab_bg: self._actions.click,
            Target.window: self._actions.click,
            Target.hover: self._actions.click,
            # _download needs a QWebElement to get the frame.
            Target.download: self._actions.download,
            Target.userscript: self._actions.call_userscript,
        }
        # Handlers which take a QUrl
        url_handlers = {
            Target.yank: self._actions.yank,
            Target.yank_primary: self._actions.yank,
            Target.run: self._actions.run_cmd,
            Target.fill: self._actions.preset_cmd_text,
            Target.spawn: self._actions.spawn,
        }
        elem = self._context.labels[keystr].elem

        if not elem.has_frame():
            message.error("This element has no webframe.")
            return

        if self._context.target in elem_handlers:
            handler = functools.partial(elem_handlers[self._context.target],
                                        elem, self._context)
        elif self._context.target in url_handlers:
            url = elem.resolve_url(self._context.baseurl)
            if url is None:
                message.error("No suitable link found for this element.")
                return
            handler = functools.partial(url_handlers[self._context.target],
                                        url, self._context)
            if self._context.add_history:
                objreg.get('web-history').add_url(url, "")
        else:
            raise ValueError("No suitable handler found!")

        if not self._context.rapid:
            modeman.leave(self._win_id, usertypes.KeyMode.hint, 'followed',
                          maybe=True)
        else:
            # Reset filtering
            self.filter_hints(None)
            # Undo keystring highlighting
            for string, label in self._context.labels.items():
                label.update_text('', string)

        try:
            handler()
        except HintingError as e:
            message.error(str(e))
Ejemplo n.º 26
0
    def start(self, rapid=False, group=webelem.Group.all, target=Target.normal,
              *args: {'nargs': '*'}, win_id):
        """Start hinting.

        Args:
            rapid: Whether to do rapid hinting. This is only possible with
                   targets `tab` (with background-tabs=true), `tab-bg`,
                   `window`, `run`, `hover`, `userscript` and `spawn`.
            group: The hinting mode to use.

                - `all`: All clickable elements.
                - `links`: Only links.
                - `images`: Only images.

            target: What to do with the selected element.

                - `normal`: Open the link in the current tab.
                - `tab`: Open the link in a new tab (honoring the
                         background-tabs setting).
                - `tab-fg`: Open the link in a new foreground tab.
                - `tab-bg`: Open the link in a new background tab.
                - `window`: Open the link in a new window.
                - `hover` : Hover over the link.
                - `yank`: Yank the link to the clipboard.
                - `yank-primary`: Yank the link to the primary selection.
                - `run`: Run the argument as command.
                - `fill`: Fill the commandline with the command given as
                          argument.
                - `download`: Download the link.
                - `userscript`: Call a userscript with `$QUTE_URL` set to the
                                link.
                - `spawn`: Spawn a command.

            *args: Arguments for spawn/userscript/run/fill.

                - With `spawn`: The executable and arguments to spawn.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `userscript`: The userscript to execute. Either store
                                     the userscript in
                                     `~/.local/share/qutebrowser/userscripts`
                                     (or `$XDG_DATA_DIR`), or use an absolute
                                     path.
                - With `fill`: The command to fill the statusbar with.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `run`: Same as `fill`.
        """
        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window=self._win_id)
        widget = tabbed_browser.currentWidget()
        if widget is None:
            raise cmdexc.CommandError("No WebView available yet!")
        mainframe = widget.page().mainFrame()
        if mainframe is None:
            raise cmdexc.CommandError("No frame focused!")
        mode_manager = objreg.get('mode-manager', scope='window',
                                  window=self._win_id)
        if mode_manager.mode == usertypes.KeyMode.hint:
            modeman.leave(win_id, usertypes.KeyMode.hint, 're-hinting')

        if rapid:
            if target in [Target.tab_bg, Target.window, Target.run,
                          Target.hover, Target.userscript, Target.spawn,
                          Target.download]:
                pass
            elif (target == Target.tab and
                  config.get('tabs', 'background-tabs')):
                pass
            else:
                name = target.name.replace('_', '-')
                raise cmdexc.CommandError("Rapid hinting makes no sense with "
                                          "target {}!".format(name))

        self._check_args(target, *args)
        self._context = HintContext()
        self._context.target = target
        self._context.rapid = rapid
        try:
            self._context.baseurl = tabbed_browser.current_url()
        except qtutils.QtValueError:
            raise cmdexc.CommandError("No URL set for this page yet!")
        self._context.frames = webelem.get_child_frames(mainframe)
        for frame in self._context.frames:
            # WORKAROUND for
            # https://github.com/The-Compiler/qutebrowser/issues/152
            frame.destroyed.connect(functools.partial(
                self._context.destroyed_frames.append, id(frame)))
        self._context.args = args
        self._context.mainframe = mainframe
        self._context.group = group
        self._init_elements()
        message_bridge = objreg.get('message-bridge', scope='window',
                                    window=self._win_id)
        message_bridge.set_text(self._get_text())
        self._connect_frame_signals()
        modeman.enter(self._win_id, usertypes.KeyMode.hint,
                      'HintManager.start')
Ejemplo n.º 27
0
    def start(self, rapid=False, group=webelem.Group.all, target=Target.normal,
              *args: {'nargs': '*'}, win_id):
        """Start hinting.

        Args:
            rapid: Whether to do rapid hinting. This is only possible with
                   targets `tab` (with background-tabs=true), `tab-bg`,
                   `window`, `run`, `hover`, `userscript` and `spawn`.
            group: The hinting mode to use.

                - `all`: All clickable elements.
                - `links`: Only links.
                - `images`: Only images.

            target: What to do with the selected element.

                - `normal`: Open the link in the current tab.
                - `tab`: Open the link in a new tab (honoring the
                         background-tabs setting).
                - `tab-fg`: Open the link in a new foreground tab.
                - `tab-bg`: Open the link in a new background tab.
                - `window`: Open the link in a new window.
                - `hover` : Hover over the link.
                - `yank`: Yank the link to the clipboard.
                - `yank-primary`: Yank the link to the primary selection.
                - `run`: Run the argument as command.
                - `fill`: Fill the commandline with the command given as
                          argument.
                - `download`: Download the link.
                - `userscript`: Call a userscript with `$QUTE_URL` set to the
                                link.
                - `spawn`: Spawn a command.

            *args: Arguments for spawn/userscript/run/fill.

                - With `spawn`: The executable and arguments to spawn.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `userscript`: The userscript to execute. Either store
                                     the userscript in
                                     `~/.local/share/qutebrowser/userscripts`
                                     (or `$XDG_DATA_DIR`), or use an absolute
                                     path.
                - With `fill`: The command to fill the statusbar with.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `run`: Same as `fill`.
        """
        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window=self._win_id)
        widget = tabbed_browser.currentWidget()
        if widget is None:
            raise cmdexc.CommandError("No WebView available yet!")
        mainframe = widget.page().mainFrame()
        if mainframe is None:
            raise cmdexc.CommandError("No frame focused!")
        mode_manager = objreg.get('mode-manager', scope='window',
                                  window=self._win_id)
        if mode_manager.mode == usertypes.KeyMode.hint:
            modeman.leave(win_id, usertypes.KeyMode.hint, 're-hinting')

        if rapid:
            if target in [Target.tab_bg, Target.window, Target.run,
                          Target.hover, Target.userscript, Target.spawn,
                          Target.download]:
                pass
            elif (target == Target.tab and
                  config.get('tabs', 'background-tabs')):
                pass
            else:
                name = target.name.replace('_', '-')
                raise cmdexc.CommandError("Rapid hinting makes no sense with "
                                          "target {}!".format(name))

        self._check_args(target, *args)
        self._context = HintContext()
        self._context.target = target
        self._context.rapid = rapid
        try:
            self._context.baseurl = tabbed_browser.current_url()
        except qtutils.QtValueError:
            raise cmdexc.CommandError("No URL set for this page yet!")
        self._context.frames = webelem.get_child_frames(mainframe)
        for frame in self._context.frames:
            # WORKAROUND for
            # https://github.com/The-Compiler/qutebrowser/issues/152
            frame.destroyed.connect(functools.partial(
                self._context.destroyed_frames.append, id(frame)))
        self._context.args = args
        self._context.mainframe = mainframe
        self._context.group = group
        self._init_elements()
        message_bridge = objreg.get('message-bridge', scope='window',
                                    window=self._win_id)
        message_bridge.set_text(self._get_text())
        self._connect_frame_signals()
        modeman.enter(self._win_id, usertypes.KeyMode.hint,
                      'HintManager.start')
Ejemplo n.º 28
0
    def start(
            self,  # pylint: disable=keyword-arg-before-vararg
            group: str = 'all',
            target: Target = Target.normal,
            *args: str,
            mode: str = None,
            add_history: bool = False,
            rapid: bool = False,
            first: bool = False) -> None:
        """Start hinting.

        Args:
            rapid: Whether to do rapid hinting. With rapid hinting, the hint
                   mode isn't left after a hint is followed, so you can easily
                   open multiple links. This is only possible with targets
                   `tab` (with `tabs.background=true`), `tab-bg`,
                   `window`, `run`, `hover`, `userscript` and `spawn`.
            add_history: Whether to add the spawned or yanked link to the
                         browsing history.
            first: Click the first hinted element without prompting.
            group: The element types to hint.

                - `all`: All clickable elements.
                - `links`: Only links.
                - `images`: Only images.
                - `inputs`: Only input fields.

                Custom groups can be added via the `hints.selectors` setting
                and also used here.

            target: What to do with the selected element.

                - `normal`: Open the link.
                - `current`: Open the link in the current tab.
                - `tab`: Open the link in a new tab (honoring the
                         `tabs.background` setting).
                - `tab-fg`: Open the link in a new foreground tab.
                - `tab-bg`: Open the link in a new background tab.
                - `window`: Open the link in a new window.
                - `hover` : Hover over the link.
                - `right-click`: Right-click the element.
                - `yank`: Yank the link to the clipboard.
                - `yank-primary`: Yank the link to the primary selection.
                - `run`: Run the argument as command.
                - `fill`: Fill the commandline with the command given as
                          argument.
                - `download`: Download the link.
                - `userscript`: Call a userscript with `$QUTE_URL` set to the
                                link.
                - `spawn`: Spawn a command.
                - `delete`: Delete the selected element.

            mode: The hinting mode to use.

                - `number`: Use numeric hints.
                - `letter`: Use the chars in the hints.chars setting.
                - `word`: Use hint words based on the html elements and the
                          extra words.

            *args: Arguments for spawn/userscript/run/fill.

                - With `spawn`: The executable and arguments to spawn.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `userscript`: The userscript to execute. Either store
                                     the userscript in
                                     `~/.local/share/qutebrowser/userscripts`
                                     (or `$XDG_DATA_HOME`), or use an absolute
                                     path.
                - With `fill`: The command to fill the statusbar with.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `run`: Same as `fill`.
        """
        tabbed_browser = objreg.get('tabbed-browser',
                                    scope='window',
                                    window=self._win_id)
        tab = tabbed_browser.widget.currentWidget()
        if tab is None:
            raise cmdutils.CommandError("No WebView available yet!")

        mode_manager = modeman.instance(self._win_id)
        if mode_manager.mode == usertypes.KeyMode.hint:
            modeman.leave(self._win_id, usertypes.KeyMode.hint, 're-hinting')

        if rapid:
            if target in [
                    Target.tab_bg, Target.window, Target.run, Target.hover,
                    Target.userscript, Target.spawn, Target.download,
                    Target.normal, Target.current, Target.yank,
                    Target.yank_primary
            ]:
                pass
            elif target == Target.tab and config.val.tabs.background:
                pass
            else:
                name = target.name.replace('_', '-')
                raise cmdutils.CommandError("Rapid hinting makes no sense "
                                            "with target {}!".format(name))

        self._check_args(target, *args)

        try:
            baseurl = tabbed_browser.current_url()
        except qtutils.QtValueError:
            raise cmdutils.CommandError("No URL set for this page yet!")

        self._context = HintContext(
            tab=tab,
            target=target,
            rapid=rapid,
            hint_mode=self._get_hint_mode(mode),
            add_history=add_history,
            first=first,
            baseurl=baseurl,
            args=list(args),
            group=group,
        )

        try:
            selector = webelem.css_selector(self._context.group,
                                            self._context.baseurl)
        except webelem.Error as e:
            raise cmdutils.CommandError(str(e))

        self._context.tab.elements.find_css(
            selector,
            callback=self._start_cb,
            error_cb=lambda err: message.error(str(err)),
            only_visible=True)
Ejemplo n.º 29
0
 def on_cur_load_started(self):
     """Leave insert/hint mode when loading started."""
     modeman.leave(self._win_id, usertypes.KeyMode.insert, 'load started',
                   maybe=True)
     modeman.leave(self._win_id, usertypes.KeyMode.hint, 'load started',
                   maybe=True)
Ejemplo n.º 30
0
def on_mode_entered(mode, win_id):
    """Stop hinting when insert mode was entered."""
    if mode == usertypes.KeyMode.insert:
        modeman.leave(win_id, usertypes.KeyMode.hint, 'insert mode',
                      maybe=True)
Ejemplo n.º 31
0
 def _on_prompt_done(self, key_mode):
     """Leave the prompt mode in this window if a question was answered."""
     modeman.leave(self._win_id, key_mode, ':prompt-accept', maybe=True)
Ejemplo n.º 32
0
 def _on_prompt_done(self, key_mode):
     """Leave the prompt mode in this window if a question was answered."""
     modeman.leave(self._win_id, key_mode, ':prompt-accept', maybe=True)
Ejemplo n.º 33
0
 def on_cur_load_started(self):
     """Leave insert/hint mode when loading started."""
     modeman.leave(self._win_id, usertypes.KeyMode.insert, 'load started',
                   maybe=True)
     modeman.leave(self._win_id, usertypes.KeyMode.hint, 'load started',
                   maybe=True)
Ejemplo n.º 34
0
    def start(self, rapid=False, group=webelem.Group.all, target=Target.normal,
              *args, win_id, mode=None):
        """Start hinting.

        Args:
            rapid: Whether to do rapid hinting. This is only possible with
                   targets `tab` (with background-tabs=true), `tab-bg`,
                   `window`, `run`, `hover`, `userscript` and `spawn`.
            group: The element types to hint.

                - `all`: All clickable elements.
                - `links`: Only links.
                - `images`: Only images.
                - `inputs`: Only input fields.

            target: What to do with the selected element.

                - `normal`: Open the link.
                - `current`: Open the link in the current tab.
                - `tab`: Open the link in a new tab (honoring the
                         background-tabs setting).
                - `tab-fg`: Open the link in a new foreground tab.
                - `tab-bg`: Open the link in a new background tab.
                - `window`: Open the link in a new window.
                - `hover` : Hover over the link.
                - `yank`: Yank the link to the clipboard.
                - `yank-primary`: Yank the link to the primary selection.
                - `run`: Run the argument as command.
                - `fill`: Fill the commandline with the command given as
                          argument.
                - `download`: Download the link.
                - `userscript`: Call a userscript with `$QUTE_URL` set to the
                                link.
                - `spawn`: Spawn a command.

            mode: The hinting mode to use.

                - `number`: Use numeric hints.
                - `letter`: Use the chars in the hints->chars settings.
                - `word`: Use hint words based on the html elements and the
                          extra words.

            *args: Arguments for spawn/userscript/run/fill.

                - With `spawn`: The executable and arguments to spawn.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `userscript`: The userscript to execute. Either store
                                     the userscript in
                                     `~/.local/share/qutebrowser/userscripts`
                                     (or `$XDG_DATA_DIR`), or use an absolute
                                     path.
                - With `fill`: The command to fill the statusbar with.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `run`: Same as `fill`.
        """
        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window=self._win_id)
        tab = tabbed_browser.currentWidget()
        if tab is None:
            raise cmdexc.CommandError("No WebView available yet!")
        if (tab.backend == usertypes.Backend.QtWebEngine and
                target == Target.download):
            message.error(self._win_id, "The download target is not available "
                          "yet with QtWebEngine.", immediately=True)
            return

        mode_manager = objreg.get('mode-manager', scope='window',
                                  window=self._win_id)
        if mode_manager.mode == usertypes.KeyMode.hint:
            modeman.leave(win_id, usertypes.KeyMode.hint, 're-hinting')

        if rapid:
            if target in [Target.tab_bg, Target.window, Target.run,
                          Target.hover, Target.userscript, Target.spawn,
                          Target.download, Target.normal, Target.current]:
                pass
            elif (target == Target.tab and
                  config.get('tabs', 'background-tabs')):
                pass
            else:
                name = target.name.replace('_', '-')
                raise cmdexc.CommandError("Rapid hinting makes no sense with "
                                          "target {}!".format(name))

        if mode is None:
            mode = config.get('hints', 'mode')

        self._check_args(target, *args)
        self._context = HintContext()
        self._context.tab = tab
        self._context.target = target
        self._context.rapid = rapid
        self._context.hint_mode = mode
        try:
            self._context.baseurl = tabbed_browser.current_url()
        except qtutils.QtValueError:
            raise cmdexc.CommandError("No URL set for this page yet!")
        self._context.args = args
        self._context.group = group
        selector = webelem.SELECTORS[self._context.group]
        self._context.tab.elements.find_css(selector, self._start_cb,
                                            only_visible=True)
Ejemplo n.º 35
0
    def start(self,  # pylint: disable=keyword-arg-before-vararg
              group='all', target=Target.normal, *args, mode=None,
              add_history=False, rapid=False, first=False):
        """Start hinting.

        Args:
            rapid: Whether to do rapid hinting. With rapid hinting, the hint
                   mode isn't left after a hint is followed, so you can easily
                   open multiple links. This is only possible with targets
                   `tab` (with `tabs.background=true`), `tab-bg`,
                   `window`, `run`, `hover`, `userscript` and `spawn`.
            add_history: Whether to add the spawned or yanked link to the
                         browsing history.
            first: Click the first hinted element without prompting.
            group: The element types to hint.

                - `all`: All clickable elements.
                - `links`: Only links.
                - `images`: Only images.
                - `inputs`: Only input fields.

                Custom groups can be added via the `hints.selectors` setting
                and also used here.

            target: What to do with the selected element.

                - `normal`: Open the link.
                - `current`: Open the link in the current tab.
                - `tab`: Open the link in a new tab (honoring the
                         `tabs.background` setting).
                - `tab-fg`: Open the link in a new foreground tab.
                - `tab-bg`: Open the link in a new background tab.
                - `window`: Open the link in a new window.
                - `hover` : Hover over the link.
                - `yank`: Yank the link to the clipboard.
                - `yank-primary`: Yank the link to the primary selection.
                - `run`: Run the argument as command.
                - `fill`: Fill the commandline with the command given as
                          argument.
                - `download`: Download the link.
                - `userscript`: Call a userscript with `$QUTE_URL` set to the
                                link.
                - `spawn`: Spawn a command.
                - `delete`: Delete the selected element.

            mode: The hinting mode to use.

                - `number`: Use numeric hints.
                - `letter`: Use the chars in the hints.chars setting.
                - `word`: Use hint words based on the html elements and the
                          extra words.

            *args: Arguments for spawn/userscript/run/fill.

                - With `spawn`: The executable and arguments to spawn.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `userscript`: The userscript to execute. Either store
                                     the userscript in
                                     `~/.local/share/qutebrowser/userscripts`
                                     (or `$XDG_DATA_HOME`), or use an absolute
                                     path.
                - With `fill`: The command to fill the statusbar with.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `run`: Same as `fill`.
        """
        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window=self._win_id)
        tab = tabbed_browser.widget.currentWidget()
        if tab is None:
            raise cmdutils.CommandError("No WebView available yet!")

        mode_manager = objreg.get('mode-manager', scope='window',
                                  window=self._win_id)
        if mode_manager.mode == usertypes.KeyMode.hint:
            modeman.leave(self._win_id, usertypes.KeyMode.hint, 're-hinting')

        if rapid:
            if target in [Target.tab_bg, Target.window, Target.run,
                          Target.hover, Target.userscript, Target.spawn,
                          Target.download, Target.normal, Target.current,
                          Target.yank, Target.yank_primary]:
                pass
            elif target == Target.tab and config.val.tabs.background:
                pass
            else:
                name = target.name.replace('_', '-')
                raise cmdutils.CommandError("Rapid hinting makes no sense "
                                            "with target {}!".format(name))

        self._check_args(target, *args)
        self._context = HintContext()
        self._context.tab = tab
        self._context.target = target
        self._context.rapid = rapid
        self._context.hint_mode = self._get_hint_mode(mode)
        self._context.add_history = add_history
        self._context.first = first
        try:
            self._context.baseurl = tabbed_browser.current_url()
        except qtutils.QtValueError:
            raise cmdutils.CommandError("No URL set for this page yet!")
        self._context.args = list(args)
        self._context.group = group

        try:
            selector = webelem.css_selector(self._context.group,
                                            self._context.baseurl)
        except webelem.Error as e:
            raise cmdutils.CommandError(str(e))

        self._context.tab.elements.find_css(
            selector,
            callback=self._start_cb,
            error_cb=lambda err: message.error(str(err)),
            only_visible=True)
Ejemplo n.º 36
0
def on_mode_entered(mode, win_id):
    """Stop hinting when insert mode was entered."""
    if mode == usertypes.KeyMode.insert:
        modeman.leave(win_id, usertypes.KeyMode.hint, 'insert mode',
                      maybe=True)
Ejemplo n.º 37
0
    def _fire(self, keystr):
        """Fire a completed hint.

        Args:
            keystr: The keychain string to follow.
        """
        # Handlers which take a QWebElement
        elem_handlers = {
            Target.normal: self._actions.click,
            Target.current: self._actions.click,
            Target.tab: self._actions.click,
            Target.tab_fg: self._actions.click,
            Target.tab_bg: self._actions.click,
            Target.window: self._actions.click,
            Target.hover: self._actions.click,
            # _download needs a QWebElement to get the frame.
            Target.download: self._actions.download,
            Target.userscript: self._actions.call_userscript,
        }
        # Handlers which take a QUrl
        url_handlers = {
            Target.yank: self._actions.yank,
            Target.yank_primary: self._actions.yank,
            Target.run: self._actions.run_cmd,
            Target.fill: self._actions.preset_cmd_text,
            Target.spawn: self._actions.spawn,
        }
        elem = self._context.labels[keystr].elem

        if not elem.has_frame():
            message.error("This element has no webframe.")
            return

        if self._context.target in elem_handlers:
            handler = functools.partial(elem_handlers[self._context.target],
                                        elem, self._context)
        elif self._context.target in url_handlers:
            url = elem.resolve_url(self._context.baseurl)
            if url is None:
                message.error("No suitable link found for this element.")
                return
            handler = functools.partial(url_handlers[self._context.target],
                                        url, self._context)
            if self._context.add_history:
                objreg.get('web-history').add_url(url, "")
        else:
            raise ValueError("No suitable handler found!")

        if not self._context.rapid:
            modeman.leave(self._win_id, usertypes.KeyMode.hint, 'followed',
                          maybe=True)
        else:
            # Reset filtering
            self.filter_hints(None)
            # Undo keystring highlighting
            for string, label in self._context.labels.items():
                label.update_text('', string)

        try:
            handler()
        except HintingError as e:
            message.error(str(e))