From 2d0499580f49abb52e739aff32f743f11fb4790d Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 11 Feb 2020 15:36:05 +1000 Subject: [PATCH] if latex fails to render in bulk, show the user the problem --- pylib/anki/latex.py | 19 ++++++++++++++++--- pylib/anki/media.py | 18 ++++++++++++++---- qt/aqt/media.py | 14 +++++++++++--- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/pylib/anki/latex.py b/pylib/anki/latex.py index aff030b5a..5742da792 100644 --- a/pylib/anki/latex.py +++ b/pylib/anki/latex.py @@ -7,7 +7,7 @@ import html import os import re import shutil -from typing import Any, Optional +from typing import Any, List, Optional, Tuple import anki from anki import hooks @@ -48,11 +48,24 @@ def on_card_did_render(output: TemplateRenderOutput, ctx: TemplateRenderContext) def render_latex(html: str, model: NoteType, col: anki.storage._Collection,) -> str: "Convert TEXT with embedded latex tags to image links." + html, err = render_latex_returning_errors(html, model, col) + if err: + html += "\n".join(err) + return html + + +def render_latex_returning_errors( + html: str, model: NoteType, col: anki.storage._Collection +) -> Tuple[str, List[str]]: + """Returns (text, errors). + + error_message will be non-empty is LaTeX failed to render.""" svg = model.get("latexsvg", False) header = model["latexPre"] footer = model["latexPost"] out = col.backend.extract_latex(html, svg) + errors = [] html = out.html for latex in out.latex: @@ -62,9 +75,9 @@ def render_latex(html: str, model: NoteType, col: anki.storage._Collection,) -> err = _save_latex_image(col, latex, header, footer, svg) if err is not None: - html += err + errors.append(err) - return html + return html, errors def _save_latex_image( diff --git a/pylib/anki/media.py b/pylib/anki/media.py index 1c02586c6..091b477e1 100644 --- a/pylib/anki/media.py +++ b/pylib/anki/media.py @@ -13,7 +13,7 @@ from typing import Any, Callable, List, Optional, Tuple, Union import anki from anki.consts import * -from anki.latex import render_latex +from anki.latex import render_latex, render_latex_returning_errors from anki.rsbackend import MediaCheckOutput from anki.utils import intTime @@ -27,6 +27,8 @@ def media_paths_from_col_path(col_path: str) -> Tuple[str, str]: # fixme: look into whether we can drop chdir() below # - need to check aa89d06304fecd3597da4565330a3e55bdbb91fe # - and audio handling code + + class MediaManager: soundRegexps = [r"(?i)(\[sound:(?P[^]]+)\])"] @@ -164,11 +166,15 @@ class MediaManager: "This should be called while the collection is closed." return self.col.backend.check_media() - def render_all_latex(self, progress_cb: Optional[Callable[[int], bool]] = None): + def render_all_latex( + self, progress_cb: Optional[Callable[[int], bool]] = None + ) -> Optional[Tuple[int, str]]: """Render any LaTeX that is missing. If a progress callback is provided and it returns false, the operation will be aborted. + + If an error is encountered, returns (note_id, error_message) """ last_progress = intTime() for c, (nid, mid, flds) in enumerate( @@ -178,14 +184,18 @@ class MediaManager: continue model = self.col.models.get(mid) - render_latex(flds, model, self.col) + _html, errors = render_latex_returning_errors(flds, model, self.col) + if errors: + return (nid, "\n".join(errors)) if c % 10 == 0: elap = last_progress - intTime() if elap >= 1 and progress_cb is not None: last_progress = intTime() if not progress_cb(c + 1): - return + return None + + return None # Legacy ########################################################################## diff --git a/qt/aqt/media.py b/qt/aqt/media.py index a86992ab2..5b6ef4c6b 100644 --- a/qt/aqt/media.py +++ b/qt/aqt/media.py @@ -14,7 +14,7 @@ from anki import hooks from anki.lang import _, ngettext from anki.rsbackend import Interrupted, MediaCheckOutput, Progress, ProgressKind from aqt.qt import * -from aqt.utils import askUser, restoreGeom, saveGeom, tooltip +from aqt.utils import askUser, restoreGeom, saveGeom, showText, tooltip def check_media_db(mw: aqt.AnkiQt) -> None: @@ -97,10 +97,18 @@ class MediaChecker: def _on_render_latex(self): self.progress_dialog = self.mw.progress.start() try: - self.mw.col.media.render_all_latex(self._on_render_latex_progress) + out = self.mw.col.media.render_all_latex(self._on_render_latex_progress) finally: self.mw.progress.finish() - tooltip(_("LaTeX rendered.")) + + if out is not None: + nid, err = out + browser = aqt.dialogs.open("Browser", self.mw) + browser.form.searchEdit.lineEdit().setText("nid:%d" % nid) + browser.onSearchActivated() + showText(err, type="html") + else: + tooltip(_("All LaTeX rendered.")) def _on_render_latex_progress(self, count: int) -> bool: if self.progress_dialog.wantCancel: