Let the history be pruned, and keep the settings window open on save

The History tab was read-only, so the only way to get rid of a dictation
was to edit history.jsonl by hand. Entries can now be removed: right-click
or Delete drops the selection, "Clear history" empties the file, and the
Ctrl/Shift selection lets several go at once. Deleting more than one asks
first, since there is no undo.

The cap on the file has existed since the first commit but was never
reachable from the interface. It is now a spinbox in the same tab, applied
the moment you save rather than on the next dictation, and 0 turns it off.
Trimming rewrites the file only when it is actually over the cap, instead
of on every single dictation, and does it through a temporary file so a
crash cannot leave a half-written history behind.

Deletion matches an entry on its whole content, not on its line number: the
worker may well have appended a new dictation while the window sat open.

Save no longer closes the window. It confirms and stays put, so you can
settle several things in one sitting; the cross closes it. Cancel is gone
with it, because it would be a lie next to a Save that already wrote.
This commit is contained in:
yusufipk
2026-07-25 20:07:36 +07:00
parent 60c8006725
commit 2cbc369132
4 changed files with 175 additions and 26 deletions
+43 -7
View File
@@ -210,12 +210,15 @@ def append_history(entry):
fh.write(json.dumps(entry, ensure_ascii=False) + "\n")
def read_history(limit=200):
def read_history(limit=None):
"""Newest last. A limit of None (or 0) reads the whole file."""
try:
with open(HISTORY_FILE, encoding="utf-8") as fh:
lines = fh.readlines()[-limit:]
lines = fh.readlines()
except OSError:
return []
if limit:
lines = lines[-limit:]
out = []
for line in lines:
try:
@@ -225,10 +228,43 @@ def read_history(limit=200):
return out
def _write_history(lines):
"""Replace the file in one go, so a crash cannot leave it half written."""
DATA_DIR.mkdir(parents=True, exist_ok=True)
tmp = HISTORY_FILE.with_suffix(".jsonl.tmp")
with open(tmp, "w", encoding="utf-8") as fh:
fh.writelines(lines)
tmp.replace(HISTORY_FILE)
def trim_history(limit):
rows = read_history(limit)
if not rows:
"""Drop the oldest entries once the file passes `limit` rows. 0 means keep all."""
if not limit or limit < 0:
return
with open(HISTORY_FILE, "w", encoding="utf-8") as fh:
for row in rows:
fh.write(json.dumps(row, ensure_ascii=False) + "\n")
try:
with open(HISTORY_FILE, encoding="utf-8") as fh:
lines = fh.readlines()
except OSError:
return
if len(lines) <= limit:
return
_write_history(lines[-limit:])
def _row_key(row):
return json.dumps(row, ensure_ascii=False, sort_keys=True)
def delete_history(rows):
"""Remove the given entries, matched on their whole content rather than on a
line number: the worker may have appended a new one since the list was read."""
doomed = {_row_key(row) for row in rows}
if not doomed:
return
kept = [json.dumps(row, ensure_ascii=False) + "\n"
for row in read_history() if _row_key(row) not in doomed]
_write_history(kept)
def clear_history():
HISTORY_FILE.unlink(missing_ok=True)