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
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
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)
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)
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()
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()
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)
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:])
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]))
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)
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()
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:])
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
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]))
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)
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.")
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)
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
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
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
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)
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!")
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()
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)
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))
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')
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)
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)
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)
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)
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)
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)