if latex fails to render in bulk, show the user the problem

This commit is contained in:
Damien Elmes 2020-02-11 15:36:05 +10:00
parent 9df2a08cb0
commit 2d0499580f
3 changed files with 41 additions and 10 deletions

View file

@ -7,7 +7,7 @@ import html
import os import os
import re import re
import shutil import shutil
from typing import Any, Optional from typing import Any, List, Optional, Tuple
import anki import anki
from anki import hooks 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: def render_latex(html: str, model: NoteType, col: anki.storage._Collection,) -> str:
"Convert TEXT with embedded latex tags to image links." "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) svg = model.get("latexsvg", False)
header = model["latexPre"] header = model["latexPre"]
footer = model["latexPost"] footer = model["latexPost"]
out = col.backend.extract_latex(html, svg) out = col.backend.extract_latex(html, svg)
errors = []
html = out.html html = out.html
for latex in out.latex: 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) err = _save_latex_image(col, latex, header, footer, svg)
if err is not None: if err is not None:
html += err errors.append(err)
return html return html, errors
def _save_latex_image( def _save_latex_image(

View file

@ -13,7 +13,7 @@ from typing import Any, Callable, List, Optional, Tuple, Union
import anki import anki
from anki.consts import * 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.rsbackend import MediaCheckOutput
from anki.utils import intTime 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 # fixme: look into whether we can drop chdir() below
# - need to check aa89d06304fecd3597da4565330a3e55bdbb91fe # - need to check aa89d06304fecd3597da4565330a3e55bdbb91fe
# - and audio handling code # - and audio handling code
class MediaManager: class MediaManager:
soundRegexps = [r"(?i)(\[sound:(?P<fname>[^]]+)\])"] soundRegexps = [r"(?i)(\[sound:(?P<fname>[^]]+)\])"]
@ -164,11 +166,15 @@ class MediaManager:
"This should be called while the collection is closed." "This should be called while the collection is closed."
return self.col.backend.check_media() 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. """Render any LaTeX that is missing.
If a progress callback is provided and it returns false, the operation If a progress callback is provided and it returns false, the operation
will be aborted. will be aborted.
If an error is encountered, returns (note_id, error_message)
""" """
last_progress = intTime() last_progress = intTime()
for c, (nid, mid, flds) in enumerate( for c, (nid, mid, flds) in enumerate(
@ -178,14 +184,18 @@ class MediaManager:
continue continue
model = self.col.models.get(mid) 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: if c % 10 == 0:
elap = last_progress - intTime() elap = last_progress - intTime()
if elap >= 1 and progress_cb is not None: if elap >= 1 and progress_cb is not None:
last_progress = intTime() last_progress = intTime()
if not progress_cb(c + 1): if not progress_cb(c + 1):
return return None
return None
# Legacy # Legacy
########################################################################## ##########################################################################

View file

@ -14,7 +14,7 @@ from anki import hooks
from anki.lang import _, ngettext from anki.lang import _, ngettext
from anki.rsbackend import Interrupted, MediaCheckOutput, Progress, ProgressKind from anki.rsbackend import Interrupted, MediaCheckOutput, Progress, ProgressKind
from aqt.qt import * 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: def check_media_db(mw: aqt.AnkiQt) -> None:
@ -97,10 +97,18 @@ class MediaChecker:
def _on_render_latex(self): def _on_render_latex(self):
self.progress_dialog = self.mw.progress.start() self.progress_dialog = self.mw.progress.start()
try: 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: finally:
self.mw.progress.finish() 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: def _on_render_latex_progress(self, count: int) -> bool:
if self.progress_dialog.wantCancel: if self.progress_dialog.wantCancel: