예제 #1
0
    def _start_cb(self, elems):
        """Initialize the elements and labels based on the context set."""
        filterfunc = webelem.FILTERS.get(self._context.group, lambda e: True)
        elems = [e for e in elems if filterfunc(e)]
        if not elems:
            message.error(self._win_id, "No elements found.", immediately=True)
            return
        strings = self._hint_strings(elems)
        log.hints.debug("hints: {}".format(', '.join(strings)))

        for elem, string in zip(elems, strings):
            label = HintLabel(elem, self._context)
            label.update_text('', string)
            self._context.all_labels.append(label)
            self._context.labels[string] = label

        keyparsers = objreg.get('keyparsers', scope='window',
                                window=self._win_id)
        keyparser = keyparsers[usertypes.KeyMode.hint]
        keyparser.update_bindings(strings)

        message_bridge = objreg.get('message-bridge', scope='window',
                                    window=self._win_id)
        message_bridge.set_text(self._get_text())
        modeman.enter(self._win_id, usertypes.KeyMode.hint,
                      'HintManager.start')

        # to make auto-follow == 'always' work
        self._handle_auto_follow()
예제 #2
0
파일: app.py 프로젝트: pyrho/qutebrowser
    def _open_startpage(self, win_id=None):
        """Open startpage.

        The startpage is never opened if the given windows are not empty.

        Args:
            win_id: If None, open startpage in all empty windows.
                    If set, open the startpage in the given window.
        """
        if win_id is not None:
            window_ids = [win_id]
        else:
            window_ids = objreg.window_registry
        for cur_win_id in window_ids:
            tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                        window=cur_win_id)
            if tabbed_browser.count() == 0:
                log.init.debug("Opening startpage")
                for urlstr in config.get('general', 'startpage'):
                    try:
                        url = urlutils.fuzzy_url(urlstr)
                    except urlutils.FuzzyUrlError as e:
                        message.error(0, "Error when opening startpage: "
                                         "{}".format(e))
                        tabbed_browser.tabopen(QUrl('about:blank'))
                    else:
                        tabbed_browser.tabopen(url)
예제 #3
0
 def _parse_line(self, line):
     try:
         key, url = line.rsplit(maxsplit=1)
     except ValueError:
         message.error('current', "Invalid quickmark '{}'".format(line))
     else:
         self.marks[key] = url
예제 #4
0
    def on_proc_closed(self, exitcode, exitstatus):
        """Write the editor text into the form field and clean up tempfile.

        Callback for QProcess when the editor was closed.
        """
        log.procs.debug("Editor closed")
        if exitstatus != QProcess.NormalExit:
            # No error/cleanup here, since we already handle this in
            # on_proc_error
            return
        try:
            if exitcode != 0:
                # NOTE: Do not replace this with "raise CommandError" as it's
                # executed async.
                message.error(
                    self._win_id, "Editor did quit abnormally (status "
                                  "{})!".format(exitcode))
                return
            encoding = config.get('general', 'editor-encoding')
            with open(self._filename, 'r', encoding=encoding) as f:
                text = ''.join(f.readlines())
            log.procs.debug("Read back: {}".format(text))
            self.editing_finished.emit(text)
        finally:
            self._cleanup()
예제 #5
0
    def quickmark_add(self, win_id, url, name):
        """Add a new quickmark.

        Args:
            win_id: The window ID to display the errors in.
            url: The url to add as quickmark.
            name: The name for the new quickmark.
        """
        # We don't raise cmdexc.CommandError here as this can be called async
        # via prompt_save.
        if not name:
            message.error(win_id, "Can't set mark with empty name!")
            return
        if not url:
            message.error(win_id, "Can't set mark with empty URL!")
            return

        def set_mark():
            """Really set the quickmark."""
            self.marks[name] = url
            self.changed.emit()
            self.added.emit(name, url)

        if name in self.marks:
            message.confirm_async(
                win_id, "Override existing quickmark?", set_mark, default=True)
        else:
            set_mark()
예제 #6
0
파일: editor.py 프로젝트: shawa/qutebrowser
    def edit(self, text):
        """Edit a given text.

        Args:
            text: The initial text to edit.
        """
        if self._text is not None:
            raise ValueError("Already editing a file!")
        self._text = text
        try:
            self._oshandle, self._filename = tempfile.mkstemp(
                text=True, prefix='qutebrowser-editor-')
            if text:
                encoding = config.get('general', 'editor-encoding')
                with open(self._filename, 'w', encoding=encoding) as f:
                    f.write(text)  # pragma: no branch
        except OSError as e:
            message.error(self._win_id, "Failed to create initial file: "
                                        "{}".format(e))
            return
        self._proc = guiprocess.GUIProcess(self._win_id, what='editor',
                                           parent=self)
        self._proc.finished.connect(self.on_proc_closed)
        self._proc.error.connect(self.on_proc_error)
        editor = config.get('general', 'editor')
        executable = editor[0]
        args = [self._filename if arg == '{}' else arg for arg in editor[1:]]
        log.procs.debug("Calling \"{}\" with args {}".format(executable, args))
        self._proc.start(executable, args)
예제 #7
0
파일: editor.py 프로젝트: shawa/qutebrowser
    def on_proc_closed(self, exitcode, exitstatus):
        """Write the editor text into the form field and clean up tempfile.

        Callback for QProcess when the editor was closed.
        """
        log.procs.debug("Editor closed")
        if exitstatus != QProcess.NormalExit:
            # No error/cleanup here, since we already handle this in
            # on_proc_error.
            return
        try:
            if exitcode != 0:
                return
            encoding = config.get('general', 'editor-encoding')
            try:
                with open(self._filename, 'r', encoding=encoding) as f:
                    text = f.read()  # pragma: no branch
            except OSError as e:
                # NOTE: Do not replace this with "raise CommandError" as it's
                # executed async.
                message.error(self._win_id, "Failed to read back edited file: "
                                            "{}".format(e))
                return
            log.procs.debug("Read back: {}".format(text))
            self.editing_finished.emit(text)
        finally:
            self._cleanup()
예제 #8
0
def _load_session(name):
    """Load the default session.

    Args:
        name: The name of the session to load, or None to read state file.
    """
    state_config = objreg.get('state-config')
    if name is None:
        try:
            name = state_config['general']['session']
        except KeyError:
            # No session given as argument and none in the session file ->
            # start without loading a session
            return
    session_manager = objreg.get('session-manager')
    try:
        session_manager.load(name)
    except sessions.SessionNotFoundError:
        message.error("Session {} not found!".format(name))
    except sessions.SessionError as e:
        message.error("Failed to load session {}: {}".format(name, e))
    try:
        del state_config['general']['session']
    except KeyError:
        pass
    # If this was a _restart session, delete it.
    if name == '_restart':
        session_manager.delete('_restart')
예제 #9
0
def message_error(text):
    """Show an error message in the statusbar.

    Args:
        text: The text to show.
    """
    message.error(text)
예제 #10
0
def qute_help(url):
    """Handler for qute:help."""
    try:
        utils.read_file('html/doc/index.html')
    except OSError:
        html = jinja.render(
            'error.html',
            title="Error while loading documentation",
            url=url.toDisplayString(),
            error="This most likely means the documentation was not generated "
                  "properly. If you are running qutebrowser from the git "
                  "repository, please run scripts/asciidoc2html.py. "
                  "If you're running a released version this is a bug, please "
                  "use :report to report it.",
            icon='',
            qutescheme=True)
        return 'text/html', html
    urlpath = url.path()
    if not urlpath or urlpath == '/':
        urlpath = 'index.html'
    else:
        urlpath = urlpath.lstrip('/')
    if not docutils.docs_up_to_date(urlpath):
        message.error("Your documentation is outdated! Please re-run "
                      "scripts/asciidoc2html.py.")
    path = 'html/doc/{}'.format(urlpath)
    if urlpath.endswith('.png'):
        return 'image/png', utils.read_file(path, binary=True)
    else:
        data = utils.read_file(path)
        return 'text/html', data
예제 #11
0
def _process_args(args):
    """Open startpage etc. and process commandline args."""
    config_obj = objreg.get('config')
    for sect, opt, val in args.temp_settings:
        try:
            config_obj.set('temp', sect, opt, val)
        except (configexc.Error, configparser.Error) as e:
            message.error("set: {} - {}".format(e.__class__.__name__, e))

    if not args.override_restore:
        _load_session(args.session)
    session_manager = objreg.get('session-manager')
    if not session_manager.did_load:
        log.init.debug("Initializing main window...")
        window = mainwindow.MainWindow()
        if not args.nowindow:
            window.show()
        qApp.setActiveWindow(window)

    process_pos_args(args.command)
    _open_startpage()
    _open_quickstart(args)

    delta = datetime.datetime.now() - earlyinit.START_TIME
    log.init.debug("Init finished after {}s".format(delta.total_seconds()))
예제 #12
0
def qute_help(win_id, request):
    """Handler for qute:help. Return HTML content as bytes."""
    try:
        utils.read_file('html/doc/index.html')
    except FileNotFoundError:
        html = jinja.env.get_template('error.html').render(
            title="Error while loading documentation",
            url=request.url().toDisplayString(),
            error="This most likely means the documentation was not generated "
                  "properly. If you are running qutebrowser from the git "
                  "repository, please run scripts/asciidoc2html.py."
                  "If you're running a released version this is a bug, please "
                  "use :report to report it.",
            icon='')
        return html.encode('UTF-8', errors='xmlcharrefreplace')
    urlpath = request.url().path()
    if not urlpath or urlpath == '/':
        urlpath = 'index.html'
    else:
        urlpath = urlpath.lstrip('/')
    if not docutils.docs_up_to_date(urlpath):
        message.error(win_id, "Your documentation is outdated! Please re-run "
                      "scripts/asciidoc2html.py.")
    path = 'html/doc/{}'.format(urlpath)
    return utils.read_file(path).encode('UTF-8', errors='xmlcharrefreplace')
예제 #13
0
    def search(self, text, flags):
        """Search for text in the current page.

        Args:
            text: The text to search for.
            flags: The QWebPage::FindFlags.
        """
        log.webview.debug("Searching with text '{}' and flags "
                          "0x{:04x}.".format(text, int(flags)))
        widget = self.currentWidget()
        old_scroll_pos = widget.scroll_pos
        found = widget.findText(text, flags)
        if not found and not flags & QWebPage.HighlightAllOccurrences and text:
            message.error(self._win_id, "Text '{}' not found on "
                          "page!".format(text), immediately=True)
        else:
            backward = int(flags) & QWebPage.FindBackward

            def check_scroll_pos():
                """Check if the scroll position got smaller and show info."""
                if not backward and widget.scroll_pos < old_scroll_pos:
                    message.info(self._win_id, "Search hit BOTTOM, continuing "
                                 "at TOP", immediately=True)
                elif backward and widget.scroll_pos > old_scroll_pos:
                    message.info(self._win_id, "Search hit TOP, continuing at "
                                 "BOTTOM", immediately=True)
            # We first want QWebPage to refresh.
            QTimer.singleShot(0, check_scroll_pos)
예제 #14
0
    def _hint_strings(self, elems):
        """Calculate the hint strings for elems.

        Inspired by Vimium.

        Args:
            elems: The elements to get hint strings for.

        Return:
            A list of hint strings, in the same order as the elements.
        """
        hint_mode = config.get('hints', 'mode')
        if hint_mode == 'word':
            try:
                return self._word_hinter.hint(elems)
            except WordHintingError as e:
                message.error(self._win_id, str(e), immediately=True)
                # falls back on letter hints
        if hint_mode == 'number':
            chars = '0123456789'
        else:
            chars = config.get('hints', 'chars')
        min_chars = config.get('hints', 'min-chars')
        if config.get('hints', 'scatter') and hint_mode != 'number':
            return self._hint_scattered(min_chars, chars, elems)
        else:
            return self._hint_linear(min_chars, chars, elems)
예제 #15
0
    def fire(self, keystr, force=False):
        """Fire a completed hint.

        Args:
            keystr: The keychain string to follow.
            force: When True, follow even when auto-follow is false.
        """
        if not (force or config.get('hints', 'auto-follow')):
            self.handle_partial_key(keystr)
            self._context.to_follow = keystr
            return
        # Handlers which take a QWebElement
        elem_handlers = {
            Target.normal: self._click,
            Target.current: self._click,
            Target.tab: self._click,
            Target.tab_fg: self._click,
            Target.tab_bg: self._click,
            Target.window: self._click,
            Target.hover: self._click,
            # _download needs a QWebElement to get the frame.
            Target.download: self._download,
            Target.userscript: self._call_userscript,
        }
        # Handlers which take a QUrl
        url_handlers = {
            Target.yank: self._yank,
            Target.yank_primary: self._yank,
            Target.run: self._run_cmd,
            Target.fill: self._preset_cmd_text,
            Target.spawn: self._spawn,
        }
        elem = self._context.elems[keystr].elem
        if elem.webFrame() is None:
            message.error(self._win_id,
                          "This element has no webframe.",
                          immediately=True)
            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 = self._resolve_url(elem, self._context.baseurl)
            if url is None:
                self._show_url_error()
                return
            handler = functools.partial(url_handlers[self._context.target],
                                        url, self._context)
        else:
            raise ValueError("No suitable handler found!")
        if not self._context.rapid:
            modeman.maybe_leave(self._win_id, usertypes.KeyMode.hint,
                                'followed')
        else:
            # Reset filtering
            self.filter_hints(None)
            # Undo keystring highlighting
            for string, elem in self._context.elems.items():
                elem.label.setInnerXml(string)
        handler()
예제 #16
0
    def _on_navigation_request(
            self,
            navigation: usertypes.NavigationRequest
    ) -> None:
        """Handle common acceptNavigationRequest code."""
        url = utils.elide(navigation.url.toDisplayString(), 100)
        log.webview.debug("navigation request: url {}, type {}, is_main_frame "
                          "{}".format(url,
                                      navigation.navigation_type,
                                      navigation.is_main_frame))

        if not navigation.url.isValid():
            # Also a WORKAROUND for missing IDNA 2008 support in QUrl, see
            # https://bugreports.qt.io/browse/QTBUG-60364

            if navigation.navigation_type == navigation.Type.link_clicked:
                msg = urlutils.get_errstring(navigation.url,
                                             "Invalid link clicked")
                message.error(msg)
                self.data.open_target = usertypes.ClickTarget.normal

            log.webview.debug("Ignoring invalid URL {} in "
                              "acceptNavigationRequest: {}".format(
                                  navigation.url.toDisplayString(),
                                  navigation.url.errorString()))
            navigation.accepted = False
예제 #17
0
    def on_ssl_errors(self, reply, errors):
        """Decide if SSL errors should be ignored or not.

        This slot is called on SSL/TLS errors by the self.sslErrors signal.

        Args:
            reply: The QNetworkReply that is encountering the errors.
            errors: A list of errors.
        """
        ssl_strict = config.get('network', 'ssl-strict')
        if ssl_strict == 'ask':
            err_string = '\n'.join('- ' + err.errorString() for err in errors)
            answer = self._ask(self._win_id,
                               'SSL errors - continue?\n{}'.format(err_string),
                               mode=usertypes.PromptMode.yesno,
                               owners=(reply,))
            if answer:
                reply.ignoreSslErrors()
        elif ssl_strict:
            pass
        else:
            for err in errors:
                # FIXME we might want to use warn here (non-fatal error)
                # https://github.com/The-Compiler/qutebrowser/issues/114
                message.error(self._win_id,
                              'SSL error: {}'.format(err.errorString()))
            reply.ignoreSslErrors()
예제 #18
0
 def autosave(self):
     """Slot used when the configs are auto-saved."""
     for (key, saveable) in self.saveables.items():
         try:
             saveable.save(silent=True)
         except OSError as e:
             message.error("Failed to auto-save {}: {}".format(key, e))
예제 #19
0
    def edit(self, text, caret_position=0):
        """Edit a given text.

        Args:
            text: The initial text to edit.
            caret_position: The position of the caret in the text.
        """
        if self._filename is not None:
            raise ValueError("Already editing a file!")
        try:
            # Close while the external process is running, as otherwise systems
            # with exclusive write access (e.g. Windows) may fail to update
            # the file from the external editor, see
            # https://github.com/qutebrowser/qutebrowser/issues/1767
            with tempfile.NamedTemporaryFile(
                    mode='w', prefix='qutebrowser-editor-',
                    encoding=config.val.editor.encoding,
                    delete=False) as fobj:
                if text:
                    fobj.write(text)
                self._filename = fobj.name
        except OSError as e:
            message.error("Failed to create initial file: {}".format(e))
            return

        self._remove_file = True

        line, column = self._calc_line_and_column(text, caret_position)
        self._start_editor(line=line, column=column)
예제 #20
0
    def run(self, win_id, args=None, count=None):
        """Run the command.

        Note we don't catch CommandError here as it might happen async.

        Args:
            win_id: The window ID the command is run in.
            args: Arguments to the command.
            count: Command repetition count.
        """
        dbgout = ["command called:", self.name]
        if args:
            dbgout.append(str(args))
        elif args is None:
            args = []

        if count is not None:
            dbgout.append("(count={})".format(count))
        log.commands.debug(' '.join(dbgout))
        try:
            self.namespace = self.parser.parse_args(args)
        except argparser.ArgumentParserError as e:
            message.error('{}: {}'.format(self.name, e),
                          stack=traceback.format_exc())
            return
        except argparser.ArgumentParserExit as e:
            log.commands.debug("argparser exited with status {}: {}".format(
                e.status, e))
            return
        self._count = count
        self._check_prerequisites(win_id)
        posargs, kwargs = self._get_call_args(win_id)
        log.commands.debug('Calling {}'.format(
            debug_utils.format_call(self.handler, posargs, kwargs)))
        self.handler(*posargs, **kwargs)
예제 #21
0
    def _on_finished(self, code, status):
        """Show a message when the process finished."""
        self._started = False
        log.procs.debug("Process finished with code {}, status {}.".format(
            code, status))

        encoding = locale.getpreferredencoding(do_setlocale=False)
        stderr = bytes(self._proc.readAllStandardError()).decode(
            encoding, 'replace')
        stdout = bytes(self._proc.readAllStandardOutput()).decode(
            encoding, 'replace')

        if status == QProcess.CrashExit:
            exitinfo = "{} crashed!".format(self._what.capitalize())
            message.error(exitinfo)
        elif status == QProcess.NormalExit and code == 0:
            exitinfo = "{} exited successfully.".format(
                self._what.capitalize())
            if self.verbose:
                message.info(exitinfo)
        else:
            assert status == QProcess.NormalExit
            # We call this 'status' here as it makes more sense to the user -
            # it's actually 'code'.
            exitinfo = ("{} exited with status {}, see :messages for "
                        "details.").format(self._what.capitalize(), code)
            message.error(exitinfo)

            if stdout:
                log.procs.error("Process stdout:\n" + stdout.strip())
            if stderr:
                log.procs.error("Process stderr:\n" + stderr.strip())

        qutescheme.spawn_output = self._spawn_format(exitinfo, stdout, stderr)
예제 #22
0
    def _set_download_target(self, download, suggested_filename, target):
        """Set the target for a given download.

        Args:
            download: The download to set the filename for.
            suggested_filename: The suggested filename.
            target: The usertypes.DownloadTarget for this download.
        """
        if isinstance(target, usertypes.FileObjDownloadTarget):
            download.set_fileobj(target.fileobj)
            download.autoclose = False
        elif isinstance(target, usertypes.FileDownloadTarget):
            download.set_filename(target.filename)
        elif isinstance(target, usertypes.OpenFileDownloadTarget):
            tmp_manager = objreg.get('temporary-downloads')
            try:
                fobj = tmp_manager.get_tmpfile(suggested_filename)
            except OSError as exc:
                msg = "Download error: {}".format(exc)
                message.error(self._win_id, msg)
                download.cancel()
                return
            download.finished.connect(
                functools.partial(self._open_download, download))
            download.autoclose = True
            download.set_fileobj(fobj)
        else:
            log.downloads.error("Unknown download target: {}".format(target))
예제 #23
0
def _move_data(old, new):
    """Migrate data from an old to a new directory.

    If the old directory does not exist, the migration is skipped.
    If the new directory already exists, an error is shown.

    Return: True if moving succeeded, False otherwise.
    """
    if not os.path.exists(old):
        return False

    log.init.debug("Migrating data from {} to {}".format(old, new))

    if os.path.exists(new):
        if not os.path.isdir(new) or os.listdir(new):
            message.error("Failed to move data from {} as {} is non-empty!"
                          .format(old, new))
            return False
        os.rmdir(new)

    try:
        shutil.move(old, new)
    except OSError as e:
        message.error("Failed to move data from {} to {}: {}".format(
            old, new, e))
        return False

    return True
예제 #24
0
파일: adblock.py 프로젝트: JIVS/qutebrowser
 def adblock_update(self, win_id: {'special': 'win_id'}):
     """Update the adblock block lists."""
     self.blocked_hosts = set()
     self._done_count = 0
     urls = config.get('content', 'host-block-lists')
     download_manager = objreg.get('download-manager', scope='window',
                                   window='last-focused')
     if urls is None:
         return
     for url in urls:
         if url.scheme() == 'file':
             try:
                 fileobj = open(url.path(), 'rb')
             except OSError as e:
                 message.error(win_id, "adblock: Error while reading {}: "
                               "{}".format(url.path(), e.strerror))
                 continue
             download = FakeDownload(fileobj)
             self._in_progress.append(download)
             self.on_download_finished(download)
         else:
             fobj = io.BytesIO()
             fobj.name = 'adblock: ' + url.host()
             download = download_manager.get(url, fileobj=fobj,
                                             auto_remove=True)
             self._in_progress.append(download)
             download.finished.connect(
                 functools.partial(self.on_download_finished, download))
예제 #25
0
    def quickmark_add(self, url, name):
        """Add a new quickmark.

        You can view all saved quickmarks on the
        link:qute://bookmarks[bookmarks page].

        Args:
            url: The url to add as quickmark.
            name: The name for the new quickmark.
        """
        # We don't raise cmdexc.CommandError here as this can be called async
        # via prompt_save.
        if not name:
            message.error("Can't set mark with empty name!")
            return
        if not url:
            message.error("Can't set mark with empty URL!")
            return

        def set_mark():
            """Really set the quickmark."""
            self.marks[name] = url
            self.changed.emit()
            log.misc.debug("Added quickmark {} for {}".format(name, url))

        if name in self.marks:
            message.confirm_async(
                title="Override existing quickmark?",
                yes_action=set_mark, default=True, url=url)
        else:
            set_mark()
예제 #26
0
    def _prevnext_cb(elems):
        elem = _find_prevnext(prev, elems)
        word = 'prev' if prev else 'forward'

        if elem is None:
            message.error(win_id, "No {} links found!".format(word))
            return
        url = elem.resolve_url(baseurl)
        if url is None:
            message.error(win_id, "No {} links found!".format(word))
            return
        qtutils.ensure_valid(url)

        if window:
            from qutebrowser.mainwindow import mainwindow
            new_window = mainwindow.MainWindow()
            new_window.show()
            tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                        window=new_window.win_id)
            tabbed_browser.tabopen(url, background=False)
        elif tab:
            tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                        window=win_id)
            tabbed_browser.tabopen(url, background=background)
        else:
            browsertab.openurl(url)
예제 #27
0
    def _on_link_clicked(self, url):
        log.webview.debug("link clicked: url {}, hint target {}, "
                          "open_target {}".format(
                              url.toDisplayString(),
                              self.data.hint_target, self.data.open_target))

        if not url.isValid():
            msg = urlutils.get_errstring(url, "Invalid link clicked")
            message.error(self.win_id, msg)
            self.data.open_target = usertypes.ClickTarget.normal
            return False

        target = self.data.combined_target()

        if target == usertypes.ClickTarget.normal:
            return
        elif target == usertypes.ClickTarget.tab:
            win_id = self.win_id
            bg_tab = False
        elif target == usertypes.ClickTarget.tab_bg:
            win_id = self.win_id
            bg_tab = True
        elif target == usertypes.ClickTarget.window:
            from qutebrowser.mainwindow import mainwindow
            window = mainwindow.MainWindow()
            window.show()
            win_id = window.win_id
            bg_tab = False
        else:
            raise ValueError("Invalid ClickTarget {}".format(target))

        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window=win_id)
        tabbed_browser.tabopen(url, background=bg_tab)
        self.data.open_target = usertypes.ClickTarget.normal
예제 #28
0
def _open_startpage(win_id=None):
    """Open startpage.

    The startpage is never opened if the given windows are not empty.

    Args:
        win_id: If None, open startpage in all empty windows.
                If set, open the startpage in the given window.
    """
    if win_id is not None:
        window_ids = [win_id]
    else:
        window_ids = objreg.window_registry
    for cur_win_id in window_ids:
        tabbed_browser = objreg.get("tabbed-browser", scope="window", window=cur_win_id)
        if tabbed_browser.count() == 0:
            log.init.debug("Opening startpage")
            for urlstr in config.get("general", "startpage"):
                try:
                    url = urlutils.fuzzy_url(urlstr, do_search=False)
                except urlutils.InvalidUrlError as e:
                    message.error("current", "Error when opening startpage: " "{}".format(e))
                    tabbed_browser.tabopen(QUrl("about:blank"))
                else:
                    tabbed_browser.tabopen(url)
예제 #29
0
    def edit(self, text):
        """Edit a given text.

        Args:
            text: The initial text to edit.
        """
        if self._text is not None:
            raise ValueError("Already editing a file!")
        self._text = text
        encoding = config.get('general', 'editor-encoding')
        try:
            # Close while the external process is running, as otherwise systems
            # with exclusive write access (e.g. Windows) may fail to update
            # the file from the external editor, see
            # https://github.com/The-Compiler/qutebrowser/issues/1767
            with tempfile.NamedTemporaryFile(
                    mode='w', prefix='qutebrowser-editor-', encoding=encoding,
                    delete=False) as fobj:
                if text:
                    fobj.write(text)
                self._file = fobj
        except OSError as e:
            message.error("Failed to create initial file: {}".format(e))
            return
        self._proc = guiprocess.GUIProcess(what='editor', parent=self)
        self._proc.finished.connect(self.on_proc_closed)
        self._proc.error.connect(self.on_proc_error)
        editor = config.get('general', 'editor')
        executable = editor[0]
        args = [arg.replace('{}', self._file.name) for arg in editor[1:]]
        log.procs.debug("Calling \"{}\" with args {}".format(executable, args))
        self._proc.start(executable, args)
예제 #30
0
    def jump_mark(self, key):
        """Jump to the mark named by `key`.

        Args:
            key: mark identifier; capital indicates a global mark
        """
        # consider urls that differ only in fragment to be identical
        urlkey = self.current_url().adjusted(QUrl.RemoveFragment)
        frame = self.currentWidget().page().currentFrame()

        if key.isupper() and key in self._global_marks:
            point, url = self._global_marks[key]

            @pyqtSlot(bool)
            def callback(ok):
                if ok:
                    self.cur_load_finished.disconnect(callback)
                    frame.setScrollPosition(point)

            self.openurl(url, newtab=False)
            self.cur_load_finished.connect(callback)
        elif urlkey in self._local_marks and key in self._local_marks[urlkey]:
            point = self._local_marks[urlkey][key]

            # save the pre-jump position in the special ' mark
            # this has to happen after we read the mark, otherwise jump_mark
            # "'" would just jump to the current position every time
            self.set_mark("'")

            frame.setScrollPosition(point)
        else:
            message.error(self._win_id, "Mark {} is not set".format(key))
예제 #31
0
    def _set_filename(self,
                      filename,
                      *,
                      force_overwrite=False,
                      remember_directory=True):
        """Set the filename to save the download to.

        Args:
            filename: The full filename to save the download to.
                      None: special value to stop the download.
            force_overwrite: Force overwriting existing files.
            remember_directory: If True, remember the directory for future
                                downloads.
        """
        global last_used_directory
        filename = os.path.expanduser(filename)
        self._ensure_can_set_filename(filename)

        self._filename = create_full_filename(self.basename, filename)
        if self._filename is None:
            # We only got a filename (without directory) or a relative path
            # from the user, so we append that to the default directory and
            # try again.
            self._filename = create_full_filename(
                self.basename, os.path.join(download_dir(), filename))

        # At this point, we have a misconfigured XDG_DOWNLOAD_DIR, as
        # download_dir() + filename is still no absolute path.
        # The config value is checked for "absoluteness", but
        # ~/.config/user-dirs.dirs may be misconfigured and a non-absolute path
        # may be set for XDG_DOWNLOAD_DIR
        if self._filename is None:
            message.error(
                "XDG_DOWNLOAD_DIR points to a relative path - please check"
                " your ~/.config/user-dirs.dirs. The download is saved in"
                " your home directory.", )
            # fall back to $HOME as download_dir
            self._filename = create_full_filename(self.basename,
                                                  os.path.expanduser('~'))

        self.basename = os.path.basename(self._filename)
        if remember_directory:
            last_used_directory = os.path.dirname(self._filename)

        log.downloads.debug("Setting filename to {}".format(filename))
        if force_overwrite:
            self._after_set_filename()
        elif os.path.isfile(self._filename):
            # The file already exists, so ask the user if it should be
            # overwritten.
            txt = "<b>{}</b> already exists. Overwrite?".format(
                html.escape(self._filename))
            self._ask_confirm_question("Overwrite existing file?", txt)
        # FIFO, device node, etc. Make sure we want to do this
        elif (os.path.exists(self._filename)
              and not os.path.isdir(self._filename)):
            txt = ("<b>{}</b> already exists and is a special file. Write to "
                   "it anyways?".format(html.escape(self._filename)))
            self._ask_confirm_question("Overwrite special file?", txt)
        else:
            self._after_set_filename()
예제 #32
0
 def print_callback(ok: bool) -> None:
     """Called when printing finished."""
     if not ok:
         message.error("Printing failed!")
     diag.deleteLater()
예제 #33
0
 def _on_error(self, msg):
     """Display error message on download errors."""
     message.error("Download error: {}".format(msg))
예제 #34
0
 def try_retry(self):
     """Try to retry a download and show an error if it's unsupported."""
     try:
         self.retry()
     except UnsupportedOperationError as e:
         message.error(str(e))
예제 #35
0
파일: hints.py 프로젝트: tckmn/qutebrowser
    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))
예제 #36
0
 def _handle_sql_errors(self):
     try:
         yield
     except sql.KnownError as e:
         message.error("Failed to write history: {}".format(e.text()))
예제 #37
0
 def _on_paste_version_err(text):
     message.error("Failed to pastebin version" " info: {}".format(text))
     pbclient.deleteLater()
예제 #38
0
파일: version.py 프로젝트: spk/qutebrowser
 def _on_paste_version_err(text: str) -> None:
     assert pbclient is not None
     message.error("Failed to pastebin version" " info: {}".format(text))
     pbclient.deleteLater()
예제 #39
0
 def run_safely(self, text, count=None):
     """Run a command and display exceptions in the statusbar."""
     try:
         self.run(text, count)
     except cmdexc.Error as e:
         message.error(str(e), stack=traceback.format_exc())
예제 #40
0
파일: hints.py 프로젝트: ykgmfq/qutebrowser
    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)
예제 #41
0
def _warn_for_pac():
    """Show a warning if PAC is used with QtWebEngine."""
    proxy = config.val.content.proxy
    if (isinstance(proxy, pac.PACFetcher)
            and objects.backend == usertypes.Backend.QtWebEngine):
        message.error("PAC support isn't implemented for QtWebEngine yet!")
예제 #42
0
 def on_error(self, error):
     """Show a message if there was an error while spawning."""
     msg = ERROR_STRINGS[error]
     message.error("Error while spawning {}: {}".format(self._what, msg))
예제 #43
0
    def fire(self, keystr, force=False):
        """Fire a completed hint.

        Args:
            keystr: The keychain string to follow.
            force: When True, follow even when auto-follow is false.
        """
        if not (force or config.get('hints', 'auto-follow')):
            self.handle_partial_key(keystr)
            self._context.to_follow = keystr
            return
        # Handlers which take a QWebElement
        elem_handlers = {
            Target.normal:
            self._click,
            Target.current:
            self._click,
            Target.tab:
            self._click,
            Target.tab_fg:
            self._click,
            Target.tab_bg:
            self._click,
            Target.window:
            self._click,
            Target.hover:
            self._click,
            # _download needs a QWebElement to get the frame.
            Target.download:
            self._download,
            Target.userscript:
            self._call_userscript,
        }
        # Handlers which take a QUrl
        url_handlers = {
            Target.yank: self._yank,
            Target.yank_primary: self._yank,
            Target.run: self._run_cmd,
            Target.fill: self._preset_cmd_text,
            Target.spawn: self._spawn,
        }
        elem = self._context.elems[keystr].elem
        if elem.webFrame() is None:
            message.error(self._win_id,
                          "This element has no webframe.",
                          immediately=True)
            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 = self._resolve_url(elem, self._context.baseurl)
            if url is None:
                self._show_url_error()
                return
            handler = functools.partial(url_handlers[self._context.target],
                                        url, self._context)
        else:
            raise ValueError("No suitable handler found!")
        if not self._context.rapid:
            modeman.maybe_leave(self._win_id, usertypes.KeyMode.hint,
                                'followed')
        else:
            # Reset filtering
            self.filter_hints(None)
            # Undo keystring highlighting
            for string, elem in self._context.elems.items():
                elem.label.setInnerXml(string)
        handler()
예제 #44
0
 def execute(self, cmdstr, count=None):
     try:
         self._commandrunner.run(cmdstr, count)
     except cmdexc.Error as e:
         message.error(str(e), stack=traceback.format_exc())
예제 #45
0
 def run_safely(self, text, count=None):
     """Run a command and display exceptions in the statusbar."""
     try:
         self.run(text, count)
     except (cmdexc.CommandMetaError, cmdexc.CommandError) as e:
         message.error(self._win_id, e, immediately=True)
예제 #46
0
 def _handle_sql_errors(self):
     try:
         yield
     except sql.KnownError as e:
         message.error(f"Failed to write history: {e.text()}")
예제 #47
0
def ignore_certificate_error(
        *,
        request_url: QUrl,
        first_party_url: QUrl,
        error: usertypes.AbstractCertificateErrorWrapper,
        abort_on: Iterable[pyqtBoundSignal],
) -> bool:
    """Display a certificate error question.

    Args:
        request_url: The URL of the request where the errors happened.
        first_party_url: The URL of the page we're visiting. Might be an invalid QUrl.
        error: A single error.
        abort_on: Signals aborting a question.

    Return:
        True if the error should be ignored, False otherwise.
    """
    conf = config.instance.get('content.tls.certificate_errors', url=request_url)
    log.network.debug(f"Certificate error {error!r}, config {conf}")

    assert error.is_overridable(), repr(error)

    # We get the first party URL with a heuristic - with HTTP -> HTTPS redirects, the
    # scheme might not match.
    is_resource = (
        first_party_url.isValid() and
        not request_url.matches(
            first_party_url,
            QUrl.RemoveScheme))  # type: ignore[arg-type]

    if conf == 'ask' or conf == 'ask-block-thirdparty' and not is_resource:
        err_template = jinja.environment.from_string("""
            {% if is_resource %}
            <p>
                Error while loading resource <b>{{request_url.toDisplayString()}}</b><br/>
                on page <b>{{first_party_url.toDisplayString()}}</b>:
            </p>
            {% else %}
            <p>Error while loading page <b>{{request_url.toDisplayString()}}</b>:</p>
            {% endif %}

            {{error.html()|safe}}

            {% if is_resource %}
            <p><i>Consider reporting this to the website operator, or set
            <tt>content.tls.certificate_errors</tt> to <tt>ask-block-thirdparty</tt> to
            always block invalid resource loads.</i></p>
            {% endif %}

            Do you want to ignore these errors and continue loading the page <b>insecurely</b>?
        """.strip())
        msg = err_template.render(
            request_url=request_url,
            first_party_url=first_party_url,
            is_resource=is_resource,
            error=error,
        )

        urlstr = request_url.toString(
            QUrl.RemovePassword | QUrl.FullyEncoded)  # type: ignore[arg-type]
        ignore = message.ask(title="Certificate error", text=msg,
                             mode=usertypes.PromptMode.yesno, default=False,
                             abort_on=abort_on, url=urlstr)
        if ignore is None:
            # prompt aborted
            ignore = False
        return ignore
    elif conf == 'load-insecurely':
        message.error(f'Certificate error: {error}')
        return True
    elif conf == 'block':
        return False
    elif conf == 'ask-block-thirdparty' and is_resource:
        log.network.error(
            f"Certificate error in resource load: {error}\n"
            f"  request URL:     {request_url.toDisplayString()}\n"
            f"  first party URL: {first_party_url.toDisplayString()}")
        return False
    raise utils.Unreachable(conf, is_resource)
예제 #48
0
 def _show_url_error(self):
     """Show an error because no link was found."""
     message.error(self._win_id,
                   "No suitable link found for this element.",
                   immediately=True)
예제 #49
0
 def _on_error(self):
     """Show a message if there was an error while spawning."""
     msg = self._proc.errorString()
     message.error("Error while spawning {}: {}".format(self._what, msg))
예제 #50
0
 def execute(self, cmdstr, _keytype, count=None):
     try:
         self._commandrunner.run(cmdstr, count)
     except (cmdexc.CommandMetaError, cmdexc.CommandError) as e:
         message.error(self._win_id, e, immediately=True)