From 3319b114deb909c876dd1ecc00ea946071c36393 Mon Sep 17 00:00:00 2001 From: Arthur Milchior Date: Wed, 4 Mar 2020 18:11:13 +0100 Subject: [PATCH 01/12] hook debug_will_show_hook --- qt/aqt/gui_hooks.py | 29 ++++++++++++++++++++++++++++- qt/aqt/main.py | 1 + qt/tools/genhooks_gui.py | 9 +++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/qt/aqt/gui_hooks.py b/qt/aqt/gui_hooks.py index fded1c1c8..ff8721ed9 100644 --- a/qt/aqt/gui_hooks.py +++ b/qt/aqt/gui_hooks.py @@ -13,7 +13,7 @@ import anki import aqt from anki.cards import Card from anki.hooks import runFilter, runHook -from aqt.qt import QMenu +from aqt.qt import QDialog, QMenu # New hook/filter handling ############################################################################## @@ -520,6 +520,33 @@ class _CurrentNoteTypeDidChangeHook: current_note_type_did_change = _CurrentNoteTypeDidChangeHook() +class _DebugConsoleWillShowHook: + """Allows editing the debug window. E.g. setting a default code, or + previous code.""" + + _hooks: List[Callable[[QDialog], None]] = [] + + def append(self, cb: Callable[[QDialog], None]) -> None: + """(debug_window: QDialog)""" + self._hooks.append(cb) + + def remove(self, cb: Callable[[QDialog], None]) -> None: + if cb in self._hooks: + self._hooks.remove(cb) + + def __call__(self, debug_window: QDialog) -> None: + for hook in self._hooks: + try: + hook(debug_window) + except: + # if the hook fails, remove it + self._hooks.remove(hook) + raise + + +debug_console_will_show = _DebugConsoleWillShowHook() + + class _DeckBrowserDidRenderHook: """Allow to update the deck browser window. E.g. change its title.""" diff --git a/qt/aqt/main.py b/qt/aqt/main.py index 79ef51bf2..38e434dbf 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -1342,6 +1342,7 @@ will be lost. Continue?""" s.activated.connect(frm.log.clear) s = self.debugDiagShort = QShortcut(QKeySequence("ctrl+shift+l"), d) s.activated.connect(frm.text.clear) + gui_hooks.debug_console_will_show(d) d.show() def _captureOutput(self, on): diff --git a/qt/tools/genhooks_gui.py b/qt/tools/genhooks_gui.py index 1147c0653..be60a24b6 100644 --- a/qt/tools/genhooks_gui.py +++ b/qt/tools/genhooks_gui.py @@ -11,6 +11,7 @@ import sys pylib = os.path.join(os.path.dirname(__file__), "..", "..", "pylib") sys.path.append(pylib) + from tools.hookslib import Hook, update_file # Hook list @@ -89,6 +90,14 @@ hooks = [ legacy_hook="reviewCleanup", doc="Called before Anki transitions from the review screen to another screen.", ), + # Debug + ################### + Hook( + name="debug_console_will_show", + args=["debug_window: QDialog"], + doc="""Allows editing the debug window. E.g. setting a default code, or + previous code.""", + ), # Card layout ################### Hook( From 5adbc33d4c0fa726ef10c17e04a6561a960e838b Mon Sep 17 00:00:00 2001 From: Arthur Milchior Date: Wed, 4 Mar 2020 18:20:02 +0100 Subject: [PATCH 02/12] hook debug_ran_hook --- qt/aqt/gui_hooks.py | 28 ++++++++++++++++++++++++++++ qt/aqt/main.py | 12 ++++++++++-- qt/tools/genhooks_gui.py | 7 +++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/qt/aqt/gui_hooks.py b/qt/aqt/gui_hooks.py index ff8721ed9..86fa5bdb3 100644 --- a/qt/aqt/gui_hooks.py +++ b/qt/aqt/gui_hooks.py @@ -520,6 +520,34 @@ class _CurrentNoteTypeDidChangeHook: current_note_type_did_change = _CurrentNoteTypeDidChangeHook() +class _DebugConsoleDidEvaluatePythonFilter: + """Allows processing the debug result. E.g. logging queries and + result, saving last query to display it later...""" + + _hooks: List[Callable[[str, str, QDialog], str]] = [] + + def append(self, cb: Callable[[str, str, QDialog], str]) -> None: + """(output: str, query: str, debug_window: QDialog)""" + self._hooks.append(cb) + + def remove(self, cb: Callable[[str, str, QDialog], str]) -> None: + if cb in self._hooks: + self._hooks.remove(cb) + + def __call__(self, output: str, query: str, debug_window: QDialog) -> str: + for filter in self._hooks: + try: + output = filter(output, query, debug_window) + except: + # if the hook fails, remove it + self._hooks.remove(filter) + raise + return output + + +debug_console_did_evaluate_python = _DebugConsoleDidEvaluatePythonFilter() + + class _DebugConsoleWillShowHook: """Allows editing the debug window. E.g. setting a default code, or previous code.""" diff --git a/qt/aqt/main.py b/qt/aqt/main.py index 38e434dbf..3f3034bb5 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -1404,9 +1404,17 @@ will be lost. Continue?""" else: buf += "... %s\n" % line try: - frm.log.appendPlainText(buf + (self._output or "")) + to_append = buf + (self._output or "") + to_append = gui_hooks.debug_console_did_evaluate_python( + to_append, text, frm + ) + frm.log.appendPlainText(to_append) except UnicodeDecodeError: - frm.log.appendPlainText(_("")) + to_append = _("") + to_append = gui_hooks.debug_console_did_evaluate_python( + to_append, text, frm + ) + frm.log.appendPlainText(to_append) frm.log.ensureCursorVisible() # System specific code diff --git a/qt/tools/genhooks_gui.py b/qt/tools/genhooks_gui.py index be60a24b6..e3049cd00 100644 --- a/qt/tools/genhooks_gui.py +++ b/qt/tools/genhooks_gui.py @@ -98,6 +98,13 @@ hooks = [ doc="""Allows editing the debug window. E.g. setting a default code, or previous code.""", ), + Hook( + name="debug_console_did_evaluate_python", + args=["output: str", "query: str", "debug_window: QDialog"], + return_type="str", + doc="""Allows processing the debug result. E.g. logging queries and + result, saving last query to display it later...""", + ), # Card layout ################### Hook( From 0f9683a8506637cfdff68c48dcc8aebe8e0aa87a Mon Sep 17 00:00:00 2001 From: Glutanimate Date: Sat, 7 Mar 2020 17:29:37 +0100 Subject: [PATCH 03/12] Add cursory type annotations for aqt.DialogManager Typing DialogManager._dialogs properly would require more extensive changes which could break a number of add-ons --- qt/aqt/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/qt/aqt/__init__.py b/qt/aqt/__init__.py index 7a368979a..2740f808d 100644 --- a/qt/aqt/__init__.py +++ b/qt/aqt/__init__.py @@ -10,7 +10,7 @@ import os import sys import tempfile import traceback -from typing import Any, Optional +from typing import Any, Dict, Optional import anki.buildinfo import anki.lang @@ -69,7 +69,7 @@ from aqt import stats, about, preferences, mediasync # isort:skip class DialogManager: - _dialogs = { + _dialogs: Dict[str, list] = { "AddCards": [addcards.AddCards, None], "Browser": [browser.Browser, None], "EditCurrent": [editcurrent.EditCurrent, None], @@ -79,7 +79,7 @@ class DialogManager: "sync_log": [mediasync.MediaSyncDialog, None], } - def open(self, name, *args): + def open(self, name: str, *args: Any) -> Any: (creator, instance) = self._dialogs[name] if instance: if instance.windowState() & Qt.WindowMinimized: @@ -94,17 +94,17 @@ class DialogManager: self._dialogs[name][1] = instance return instance - def markClosed(self, name): + def markClosed(self, name: str): self._dialogs[name] = [self._dialogs[name][0], None] def allClosed(self): return not any(x[1] for x in self._dialogs.values()) - def closeAll(self, onsuccess): + def closeAll(self, onsuccess: Callable[[], None]) -> Optional[bool]: # can we close immediately? if self.allClosed(): onsuccess() - return + return None # ask all windows to close and await a reply for (name, (creator, instance)) in self._dialogs.items(): From 1ed2ba8983c334ad8c4d1b5bba419c57283e3675 Mon Sep 17 00:00:00 2001 From: Glutanimate Date: Sat, 7 Mar 2020 17:35:09 +0100 Subject: [PATCH 04/12] Allow add-ons to register custom dialogs with the dialog manager --- qt/aqt/__init__.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/qt/aqt/__init__.py b/qt/aqt/__init__.py index 2740f808d..d61e073af 100644 --- a/qt/aqt/__init__.py +++ b/qt/aqt/__init__.py @@ -10,7 +10,7 @@ import os import sys import tempfile import traceback -from typing import Any, Dict, Optional +from typing import Any, Callable, Dict, Optional, Union import anki.buildinfo import anki.lang @@ -126,6 +126,23 @@ class DialogManager: return True + def register_dialog( + self, name: str, creator: Union[Callable, type], instance: Optional[Any] = None + ): + """Allows add-ons to register a custom dialog to be managed by Anki's dialog + manager + + Arguments: + name {str} -- Name/identifier of the dialog in question + creator {Union[Callable, type]} -- A class or function to create new + dialog instances with + + Keyword Arguments: + instance {Optional[Any]} -- An optional existing instance of the dialog + (default: {None}) + """ + self._dialogs[name] = [creator, instance] + dialogs = DialogManager() From 05f69272d074c5e00c8b04cb90c93489aa2ea713 Mon Sep 17 00:00:00 2001 From: Glutanimate Date: Sat, 7 Mar 2020 17:43:21 +0100 Subject: [PATCH 05/12] Elaborate more on the use case and requirements for dialog registration --- qt/aqt/__init__.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/qt/aqt/__init__.py b/qt/aqt/__init__.py index d61e073af..925250405 100644 --- a/qt/aqt/__init__.py +++ b/qt/aqt/__init__.py @@ -130,7 +130,18 @@ class DialogManager: self, name: str, creator: Union[Callable, type], instance: Optional[Any] = None ): """Allows add-ons to register a custom dialog to be managed by Anki's dialog - manager + manager, which ensures that only one copy of the window is open at once, + and that the dialog cleans up asynchronously when the collection closes + + Please note that dialogs added in this manner need to define a close behavior + by either: + + - setting `dialog.silentlyClose = True` to have it close immediately + - define a `dialog.closeWithCallback()` method that is called when closed + by the dialog manager + + TODO?: Implement more restrictive type check to ensure these requirements + are met Arguments: name {str} -- Name/identifier of the dialog in question From 1bde8d72bb494acccdf013eca73f6015ac346871 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 9 Mar 2020 18:57:55 +1000 Subject: [PATCH 06/12] check for files without a final newline --- .github/scripts/trailing-newlines.sh | 10 ++++++++++ Makefile | 3 ++- README.development | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100755 .github/scripts/trailing-newlines.sh diff --git a/.github/scripts/trailing-newlines.sh b/.github/scripts/trailing-newlines.sh new file mode 100755 index 000000000..7d77afefa --- /dev/null +++ b/.github/scripts/trailing-newlines.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -e + +files=$(rg -l '[^\n]\z' -g '!*.{svg,scss}' || true) +if [ "$files" != "" ]; then + echo "the following files are missing a newline on the last line:" + echo $files + exit 1 +fi diff --git a/Makefile b/Makefile index fb8fe5d41..98e83c664 100644 --- a/Makefile +++ b/Makefile @@ -120,9 +120,10 @@ clean-dist: .PHONY: check check: pyenv buildhash prepare @set -eo pipefail && \ + .github/scripts/trailing-newlines.sh && \ for dir in $(CHECKABLE_RS); do \ $(SUBMAKE) -C $$dir check; \ - done; \ + done && \ . "${ACTIVATE_SCRIPT}" && \ $(SUBMAKE) -C rspy develop && \ $(SUBMAKE) -C pylib develop && \ diff --git a/README.development b/README.development index 7bbe38db0..ac82b6b5a 100644 --- a/README.development +++ b/README.development @@ -22,6 +22,7 @@ To start, make sure you have the following installed: - rename - rsync - perl + - ripgrep (cargo install rigrep) The build scripts assume a UNIX-like environment, so on Windows you will need to use WSL or Cygwin to use them. From 93bb5a0bf60bc80c86cc3eb8f3ffc4cb19c6eefd Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 9 Mar 2020 18:58:41 +1000 Subject: [PATCH 07/12] fix missing newline in ftl files https://anki.tenderapp.com/discussions/beta-testing/1836-problem-with-new-translations --- qt/ftl/addons.ftl | 2 +- rslib/tests/support/ftl/templates/test.ftl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qt/ftl/addons.ftl b/qt/ftl/addons.ftl index 4ba2ddb93..134ae8532 100644 --- a/qt/ftl/addons.ftl +++ b/qt/ftl/addons.ftl @@ -6,4 +6,4 @@ addons-failed-to-load = {$traceback} # Shown in the add-on configuration screen (Tools>Add-ons>Config), in the title bar addons-config-window-title = Configure '{$name}' -addons-config-validation-error = There was a problem with the provided configuration: {$problem} \ No newline at end of file +addons-config-validation-error = There was a problem with the provided configuration: {$problem} diff --git a/rslib/tests/support/ftl/templates/test.ftl b/rslib/tests/support/ftl/templates/test.ftl index eb1867ab1..e654f414e 100644 --- a/rslib/tests/support/ftl/templates/test.ftl +++ b/rslib/tests/support/ftl/templates/test.ftl @@ -4,4 +4,4 @@ two-args-key = two args: {$one} and {$two} plural = You have {$hats -> [one] 1 hat *[other] {$hats} hats - }. \ No newline at end of file + }. From 3d3fe1713260851448d85608b175dce1329edfea Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 9 Mar 2020 18:58:49 +1000 Subject: [PATCH 08/12] add missing newline to .proto --- proto/backend.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto/backend.proto b/proto/backend.proto index c830225c7..ac6acd6bc 100644 --- a/proto/backend.proto +++ b/proto/backend.proto @@ -318,4 +318,4 @@ message StudiedTodayIn { message CongratsLearnMsgIn { float next_due = 1; uint32 remaining = 2; -} \ No newline at end of file +} From 5724c18ec1077c17d1b7bbac8b93131f175696e5 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 9 Mar 2020 19:02:36 +1000 Subject: [PATCH 09/12] install ripgrep in CI --- .github/workflows/checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 43e04e6cf..eea26fc9d 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -20,7 +20,7 @@ jobs: - name: Run checks run: | # add requirements - sudo apt update; sudo apt install portaudio19-dev gettext rename + sudo apt update; sudo apt install portaudio19-dev gettext rename ripgrep export CARGO_TARGET_DIR=~/target export RSPY_TARGET_DIR=~/target make check build BUILDFLAGS="" From aedb2d0d4a71b926a82c2ec93ebd67b60d690a07 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 9 Mar 2020 19:09:13 +1000 Subject: [PATCH 10/12] try the ripgrep snap --- .github/workflows/checks.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index eea26fc9d..acf8f7b69 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -20,7 +20,8 @@ jobs: - name: Run checks run: | # add requirements - sudo apt update; sudo apt install portaudio19-dev gettext rename ripgrep + sudo apt update; sudo apt install portaudio19-dev gettext rename + snap install ripgrep export CARGO_TARGET_DIR=~/target export RSPY_TARGET_DIR=~/target make check build BUILDFLAGS="" From c428541e0674fd523fe4c6d7d237564970ebfc14 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 9 Mar 2020 19:22:15 +1000 Subject: [PATCH 11/12] sudo required --- .github/workflows/checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index acf8f7b69..6d8db0403 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -21,7 +21,7 @@ jobs: run: | # add requirements sudo apt update; sudo apt install portaudio19-dev gettext rename - snap install ripgrep + sudo snap install ripgrep export CARGO_TARGET_DIR=~/target export RSPY_TARGET_DIR=~/target make check build BUILDFLAGS="" From 4465d65bd5b1f810cf5c16c000471c56d923b289 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 9 Mar 2020 19:25:03 +1000 Subject: [PATCH 12/12] add required --classic --- .github/workflows/checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 6d8db0403..4871a7c18 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -21,7 +21,7 @@ jobs: run: | # add requirements sudo apt update; sudo apt install portaudio19-dev gettext rename - sudo snap install ripgrep + sudo snap install ripgrep --classic export CARGO_TARGET_DIR=~/target export RSPY_TARGET_DIR=~/target make check build BUILDFLAGS=""