From 662fa69912c22dc520a861c27b04ea2c23a5da37 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 12 Aug 2022 11:54:57 +0200 Subject: Surface internal/userscript JS errors as messages Configurable via a new content.javascript.log_message setting. Closes #7173, driven by #7335. --- doc/changelog.asciidoc | 5 +++++ doc/help/settings.asciidoc | 18 ++++++++++++++++++ qutebrowser/browser/shared.py | 24 ++++++++++++++++++++++-- qutebrowser/config/configdata.yml | 23 +++++++++++++++++++++++ qutebrowser/javascript/greasemonkey_wrapper.js | 4 ++-- 5 files changed, 70 insertions(+), 4 deletions(-) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index 1a7800dd8..3b5eb2b1d 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -29,6 +29,9 @@ Added prompts (bound to `` by default). - New `clock` value for `statusbar.widgets`, displaying the current time. - New `qute://start` built-in start page (not set as the default start page yet). +- New `content.javascript.log_message` setting, allowing to surface JS log + messages as qutebrowser messages (rather than only logging them). By default, + errors in internal `qute:` pages and userscripts are shown to the user. - New `qute-1pass` userscript using the 1password commandline to fill passwords. - New features in userscripts: @@ -87,6 +90,8 @@ Changed - Improved output when loading Greasemonkey scripts. - The macOS `.app` now is registered as a handler for `.mhtml` files, such as the ones produced by `:download --mhtml`. +- The "... called unimplemented GM_..." messages are now logged as info JS + messages instead of errors. Fixed ~~~~~ diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index b16fe2a06..e4eb594b5 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -172,6 +172,7 @@ |<>|Allow JavaScript to read from or write to the clipboard. |<>|Enable JavaScript. |<>|Log levels to use for JavaScript console logging messages. +|<>|Javascript message sources/levels to show in the qutebrowser UI. |<>|Use the standard JavaScript modal dialog for `alert()` and `confirm()`. |<>|Show javascript prompts. |<>|Allow locally loaded documents to access other local URLs. @@ -2400,6 +2401,23 @@ Default: - +pass:[unknown]+: +pass:[debug]+ - +pass:[warning]+: +pass:[debug]+ +[[content.javascript.log_message]] +=== content.javascript.log_message +Javascript message sources/levels to show in the qutebrowser UI. +When a JavaScript message is logged from a location matching the glob pattern given in the key, and is from one of the levels listed as value, it's surfaced as a message in the qutebrowser UI. +By default, errors happening in qutebrowser internally or in userscripts are shown to the user. + +Type: <> + +Default: + +- +pass:[qute:*]+: + +* +pass:[error]+ +- +pass:[userscript:*]+: + +* +pass:[error]+ + [[content.javascript.modal_dialog]] === content.javascript.modal_dialog Use the standard JavaScript modal dialog for `alert()` and `confirm()`. diff --git a/qutebrowser/browser/shared.py b/qutebrowser/browser/shared.py index 54c466415..b75f7dab0 100644 --- a/qutebrowser/browser/shared.py +++ b/qutebrowser/browser/shared.py @@ -25,6 +25,7 @@ import html import enum import netrc import tempfile +import fnmatch from typing import Callable, Mapping, List, Optional, Iterable, Iterator from PyQt5.QtCore import QUrl, pyqtBoundSignal @@ -149,11 +150,30 @@ _JS_LOGMAP: Mapping[str, Callable[[str], None]] = { 'warning': log.js.warning, 'error': log.js.error, } +# Callables to use for content.javascript.log_message. +# Note that the keys are JS log levels here, not config settings! +_JS_LOGMAP_MESSAGE: Mapping[usertypes.JsLogLevel, Callable[[str], None]] = { + usertypes.JsLogLevel.info: message.info, + usertypes.JsLogLevel.warning: message.warning, + usertypes.JsLogLevel.error: message.error, +} -def javascript_log_message(level, source, line, msg): +def javascript_log_message( + level: usertypes.JsLogLevel, + source: str, + line: int, + msg: str, +): """Display a JavaScript log message.""" - logstring = "[{}:{}] {}".format(source, line, msg) + logstring = f"[{source}:{line}] {msg}" + + for pattern, levels in config.cache['content.javascript.log_message'].items(): + if level.name in levels and fnmatch.fnmatchcase(source, pattern): + func = _JS_LOGMAP_MESSAGE[level] + func(f"JS: {logstring}") + return + logger = _JS_LOGMAP[config.cache['content.javascript.log'][level.name]] logger(logstring) diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 4da003b37..220712e2d 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -940,6 +940,29 @@ content.javascript.log: The following levels are valid: `none`, `debug`, `info`, `warning`, `error`. +content.javascript.log_message: + type: + name: Dict + keytype: String + valtype: + name: FlagList + valid_values: + - info: Show JS info as messages. + - warning: Show JS warnings as messages. + - error: Show JS errors as messages. + default: + "qute:*": ["error"] + "userscript:*": ["error"] + desc: >- + Javascript message sources/levels to show in the qutebrowser UI. + + When a JavaScript message is logged from a location matching the glob + pattern given in the key, and is from one of the levels listed as value, + it's surfaced as a message in the qutebrowser UI. + + By default, errors happening in qutebrowser internally or in userscripts are + shown to the user. + content.javascript.modal_dialog: type: Bool default: false diff --git a/qutebrowser/javascript/greasemonkey_wrapper.js b/qutebrowser/javascript/greasemonkey_wrapper.js index ced4e1063..d36328282 100644 --- a/qutebrowser/javascript/greasemonkey_wrapper.js +++ b/qutebrowser/javascript/greasemonkey_wrapper.js @@ -129,11 +129,11 @@ // Stub these two so that the gm4 polyfill script doesn't try to // create broken versions as attributes of window. function GM_getResourceText(caption, commandFunc, accessKey) { - console.error(`${GM_info.script.name} called unimplemented GM_getResourceText`); + console.info(`${GM_info.script.name} called unimplemented GM_getResourceText`); } function GM_registerMenuCommand(caption, commandFunc, accessKey) { - console.error(`${GM_info.script.name} called unimplemented GM_registerMenuCommand`); + console.info(`${GM_info.script.name} called unimplemented GM_registerMenuCommand`); } // Mock the greasemonkey 4.0 async API. -- cgit v1.2.3-54-g00ecf