Well, 95% test coverage is okay I guess
This commit is contained in:
parent
ab5ec2bfae
commit
db0476f9ad
15 changed files with 1851 additions and 78 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -111,4 +111,3 @@
|
|||
"toolbar_heading": "Titre",
|
||||
"toolbar_toggle_checkboxes": "Cocher/Décocher les cases"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ----------------- #
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue