Well, 95% test coverage is okay I guess

This commit is contained in:
Miguel Jacq 2025-11-13 11:52:21 +11:00
parent ab5ec2bfae
commit db0476f9ad
Signed by: mig5
GPG key ID: 59B3F0C24135C6A9
15 changed files with 1851 additions and 78 deletions

View file

@ -122,8 +122,6 @@ class FindBar(QWidget):
return flags
def find_next(self):
if not self.editor:
return
txt = self.edit.text()
if not txt:
return
@ -149,8 +147,6 @@ class FindBar(QWidget):
self._update_highlight()
def find_prev(self):
if not self.editor:
return
txt = self.edit.text()
if not txt:
return

View file

@ -163,8 +163,6 @@ class HistoryDialog(QDialog):
@Slot()
def _revert(self):
item = self.list.currentItem()
if not item:
return
sel_id = item.data(Qt.UserRole)
if sel_id == self._current_id:
return

View file

@ -111,4 +111,3 @@
"toolbar_heading": "Titre",
"toolbar_toggle_checkboxes": "Cocher/Décocher les cases"
}

View file

@ -18,8 +18,6 @@ class LockOverlay(QWidget):
self.setFocusPolicy(Qt.StrongFocus)
self.setGeometry(parent.rect())
self._last_dark: bool | None = None
lay = QVBoxLayout(self)
lay.addStretch(1)

View file

@ -675,6 +675,9 @@ class MainWindow(QMainWindow):
def _save_editor_content(self, editor: MarkdownEditor):
"""Save a specific editor's content to its associated date."""
# Skip if DB is missing or not connected somehow.
if not getattr(self, "db", None) or getattr(self.db, "conn", None) is None:
return
if not hasattr(editor, "current_date"):
return
date_iso = editor.current_date.toString("yyyy-MM-dd")
@ -773,9 +776,13 @@ class MainWindow(QMainWindow):
Save editor contents into the given date. Shows status on success.
explicit=True means user invoked Save: show feedback even if nothing changed.
"""
# Bail out if there is no DB connection (can happen during construction/teardown)
if not getattr(self.db, "conn", None):
return
if not self._dirty and not explicit:
return
text = self.editor.to_markdown()
text = self.editor.to_markdown() if hasattr(self, "editor") else ""
self.db.save_new_version(date_iso, text, note)
self._dirty = False
self._refresh_calendar_marks()
@ -867,13 +874,14 @@ class MainWindow(QMainWindow):
fmt.setFontWeight(QFont.Weight.Normal) # remove bold only
self.calendar.setDateTextFormat(d, fmt)
self._marked_dates = set()
for date_iso in self.db.dates_with_content():
qd = QDate.fromString(date_iso, "yyyy-MM-dd")
if qd.isValid():
fmt = self.calendar.dateTextFormat(qd)
fmt.setFontWeight(QFont.Weight.Bold) # add bold only
self.calendar.setDateTextFormat(qd, fmt)
self._marked_dates.add(qd)
if self.db.conn is not None:
for date_iso in self.db.dates_with_content():
qd = QDate.fromString(date_iso, "yyyy-MM-dd")
if qd.isValid():
fmt = self.calendar.dateTextFormat(qd)
fmt.setFontWeight(QFont.Weight.Bold) # add bold only
self.calendar.setDateTextFormat(qd, fmt)
self._marked_dates.add(qd)
# -------------------- UI handlers ------------------- #
@ -1248,17 +1256,39 @@ class MainWindow(QMainWindow):
# ----------------- Close handlers ----------------- #
def closeEvent(self, event):
# Save window position
self.settings.setValue("main/geometry", self.saveGeometry())
self.settings.setValue("main/windowState", self.saveState())
self.settings.setValue("main/maximized", self.isMaximized())
# Persist geometry if settings exist (window might be half-initialized).
if getattr(self, "settings", None) is not None:
try:
self.settings.setValue("main/geometry", self.saveGeometry())
self.settings.setValue("main/windowState", self.saveState())
self.settings.setValue("main/maximized", self.isMaximized())
except Exception:
pass
# Stop timers if present to avoid late autosaves firing during teardown.
for _t in ("_autosave_timer", "_idle_timer"):
t = getattr(self, _t, None)
if t:
t.stop()
# Save content from tabs if the database is still connected
db = getattr(self, "db", None)
conn = getattr(db, "conn", None)
tw = getattr(self, "tab_widget", None)
if db is not None and conn is not None and tw is not None:
try:
for i in range(tw.count()):
editor = tw.widget(i)
if editor is not None:
self._save_editor_content(editor)
except Exception:
# Don't let teardown crash if one tab fails to save.
pass
try:
db.close()
except Exception:
pass
# Ensure we save all tabs before closing
for i in range(self.tab_widget.count()):
editor = self.tab_widget.widget(i)
if editor:
self._save_editor_content(editor)
self.db.close()
super().closeEvent(event)
# ----------------- Below logic helps focus the editor ----------------- #

View file

@ -41,15 +41,15 @@ class MarkdownHighlighter(QSyntaxHighlighter):
self.italic_format = QTextCharFormat()
self.italic_format.setFontItalic(True)
# Strikethrough: ~~text~~
self.strike_format = QTextCharFormat()
self.strike_format.setFontStrikeOut(True)
# Allow combination of bold/italic
self.bold_italic_format = QTextCharFormat()
self.bold_italic_format.setFontWeight(QFont.Weight.Bold)
self.bold_italic_format.setFontItalic(True)
# Strikethrough: ~~text~~
self.strike_format = QTextCharFormat()
self.strike_format.setFontStrikeOut(True)
# Inline code: `code`
mono = QFontDatabase.systemFont(QFontDatabase.FixedFont)
self.code_format = QTextCharFormat()
@ -163,25 +163,30 @@ class MarkdownHighlighter(QSyntaxHighlighter):
self.setFormat(marker_len, len(text) - marker_len, heading_fmt)
return
# Bold+Italic: ***text*** or ___text___
# Do these first and remember their spans so later passes don't override them.
occupied = []
# Bold+Italic (*** or ___): do these first and record occupied spans.
# --- Triple emphasis: detect first, hide markers now, but DEFER applying content style
triple_contents: list[tuple[int, int]] = [] # (start, length) for content only
occupied: list[tuple[int, int]] = (
[]
) # full spans including markers, for overlap checks
for m in re.finditer(
r"(?<!\*)\*\*\*(.+?)(?<!\*)\*\*\*|(?<!_)___(.+?)(?<!_)___", text
):
start, end = m.span()
content_start, content_end = start + 3, end - 3
self.setFormat(start, 3, self.syntax_format) # hide leading ***
self.setFormat(end - 3, 3, self.syntax_format) # hide trailing ***
self.setFormat(
content_start, content_end - content_start, self.bold_italic_format
)
occupied.append((start, end))
# hide the *** / ___ markers now
self.setFormat(start, 3, self.syntax_format)
self.setFormat(end - 3, 3, self.syntax_format)
def _overlaps(a, b):
# remember the full occupied span and the content span
occupied.append((start, end))
triple_contents.append((content_start, content_end - content_start))
def _overlaps(a, b): # a, b are (start, end)
return not (a[1] <= b[0] or b[1] <= a[0])
# Bold: **text** or __text__ (but not part of *** or ___)
# --- Bold (**) or (__): skip if it overlaps any triple
for m in re.finditer(
r"(?<!\*)\*\*(?!\*)(.+?)(?<!\*)\*\*(?!\*)|(?<!_)__(?!_)(.+?)(?<!_)__(?!_)",
text,
@ -194,14 +199,14 @@ class MarkdownHighlighter(QSyntaxHighlighter):
self.setFormat(end - 2, 2, self.syntax_format)
self.setFormat(content_start, content_end - content_start, self.bold_format)
# Italic: *text* or _text_ (but not part of bold/** and not inside *** or ___)
# --- Italic (*) or (_): skip if it overlaps any triple, keep your guards
for m in re.finditer(
r"(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)|(?<!_)_(?!_)(.+?)(?<!_)_(?!_)", text
):
start, end = m.span()
if any(_overlaps((start, end), occ) for occ in occupied):
continue
# Keep your existing guards that avoid grabbing * from **:
# avoid stealing a single marker that is part of a double
if start > 0 and text[start - 1 : start + 1] in ("**", "__"):
continue
if end < len(text) and text[end : end + 1] in ("*", "_"):
@ -213,6 +218,10 @@ class MarkdownHighlighter(QSyntaxHighlighter):
content_start, content_end - content_start, self.italic_format
)
# --- NOW overlay bold+italic for triple contents LAST (so nothing clobbers it)
for cs, length in triple_contents:
self._overlay_range(cs, length, self.bold_italic_format)
# Strikethrough: ~~text~~
for m in re.finditer(r"~~(.+?)~~", text):
start, end = m.span()

View file

@ -303,7 +303,7 @@ class SettingsDialog(QDialog):
self, strings._("key_changed"), strings._("key_changed_explanation")
)
except Exception as e:
QMessageBox.critical(self, strings._("error"), e)
QMessageBox.critical(self, strings._("error"), str(e))
@Slot(bool)
def _save_key_btn_clicked(self, checked: bool):
@ -330,7 +330,7 @@ class SettingsDialog(QDialog):
self, strings._("success"), strings._("database_compacted_successfully")
)
except Exception as e:
QMessageBox.critical(self, strings._("error"), e)
QMessageBox.critical(self, strings._("error"), str(e))
@property
def config(self) -> DBConfig: