Merge branch 'master' into more_precise_config_error_message
This commit is contained in:
commit
b1d0945d10
10
.github/scripts/trailing-newlines.sh
vendored
Executable file
10
.github/scripts/trailing-newlines.sh
vendored
Executable file
@ -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
|
1
.github/workflows/checks.yml
vendored
1
.github/workflows/checks.yml
vendored
@ -21,6 +21,7 @@ jobs:
|
||||
run: |
|
||||
# add requirements
|
||||
sudo apt update; sudo apt install portaudio19-dev gettext rename
|
||||
sudo snap install ripgrep --classic
|
||||
export CARGO_TARGET_DIR=~/target
|
||||
export RSPY_TARGET_DIR=~/target
|
||||
make check build BUILDFLAGS=""
|
||||
|
3
Makefile
3
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 && \
|
||||
|
@ -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.
|
||||
|
@ -10,7 +10,7 @@ import os
|
||||
import sys
|
||||
import tempfile
|
||||
import traceback
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Callable, Dict, Optional, Union
|
||||
|
||||
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():
|
||||
@ -126,6 +126,34 @@ 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, 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
|
||||
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()
|
||||
|
||||
|
@ -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,61 @@ 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."""
|
||||
|
||||
_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."""
|
||||
|
||||
|
@ -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):
|
||||
@ -1403,9 +1404,17 @@ will be lost. Continue?"""
|
||||
else:
|
||||
buf += "... %s\n" % line
|
||||
try:
|
||||
frm.log.appendPlainText(buf + (self._output or "<no output>"))
|
||||
to_append = buf + (self._output or "<no output>")
|
||||
to_append = gui_hooks.debug_console_did_evaluate_python(
|
||||
to_append, text, frm
|
||||
)
|
||||
frm.log.appendPlainText(to_append)
|
||||
except UnicodeDecodeError:
|
||||
frm.log.appendPlainText(_("<non-unicode text>"))
|
||||
to_append = _("<non-unicode text>")
|
||||
to_append = gui_hooks.debug_console_did_evaluate_python(
|
||||
to_append, text, frm
|
||||
)
|
||||
frm.log.appendPlainText(to_append)
|
||||
frm.log.ensureCursorVisible()
|
||||
|
||||
# System specific code
|
||||
|
@ -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,21 @@ 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.""",
|
||||
),
|
||||
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(
|
||||
|
Loading…
Reference in New Issue
Block a user