diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-07 11:39:31 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-07 11:39:31 +0200 |
| commit | 0a9ef3c77c7c593f3568f25761aad5d1f55e0e33 (patch) | |
| tree | 714f2a5f622a43477af50393007fd892434a7a65 /src/mailsync.h | |
| parent | 1a6007b4cdaacb22d013daeb58deb6ae72afda07 (diff) | |
| download | qtmaildir-0a9ef3c77c7c593f3568f25761aad5d1f55e0e33.tar.gz qtmaildir-0a9ef3c77c7c593f3568f25761aad5d1f55e0e33.zip | |
feat(sync): the status bar says which account is syncing
"Syncing..." was set once and never updated, so a run that takes over a
minute reported nothing about what it was doing.
The original diagnosis in the backlog was half wrong, and two further
wrong ones were made and discarded before the real cause: plain
"mbsync -a" prints NOTHING until it exits, then a single summary line.
Measured on a real run, one line at 11:11:08 then 73 within the second
11:11:33, at the end of a 46-second run. So there was no stream to read
for the part of a sync that takes time. It is not buffering, so stdbuf
changes nothing, and the account name is not unavailable either, which
was the second wrong conclusion.
mbsync -V is what changes both: it announces each channel as it reaches
it, which is at once the progress and the account name originally
asked for. The shipped script now passes it.
SyncPhaseTracker derives a short status from the output as it streams:
the channel being synced, the summary counts when mbsync ends, then the
notmuch reindex. It lives beside MailSync rather than in the window so
the matching rules are one testable thing, and it holds no widget.
Matching is loose and case-insensitive, since the wording varies by
version, and nothing in it decides success or failure: the exit status
remains the only authority on that.
Lines are reassembled in MainWindow before being fed, because
QProcess::readAll() splits wherever it happens to and a half-line would
match nothing. Every status is sanitised and truncated: the channel
name comes from a config file this app does not own, and a long one
must not stretch the status bar.
Two defects in existing code, fixed with it. setSyncBusy(true) ran
after start(), so a fast run's output arrived before the per-run reset
and wiped its own phase. And a first draft deferred phases while a
transient message showed, which let a "Background sync completed"
message armed before the sync began suppress the whole run: a running
sync's state outranks an expiring event message.
Verified by replaying real captured mbsync -V output through the
tracker, not only against fixtures. The MainWindow test paces its
script with sleeps, since a script that prints everything at once
arrives in one readyRead and makes every intermediate phase
unobservable.
Closes item 42.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'src/mailsync.h')
| -rw-r--r-- | src/mailsync.h | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/src/mailsync.h b/src/mailsync.h index 8123ea9..3c0d616 100644 --- a/src/mailsync.h +++ b/src/mailsync.h @@ -22,6 +22,48 @@ #include <QProcess> #include <QString> +/// Which half of the sync script is running. +/// +/// The script runs mbsync and then `notmuch new`, so the phase is derived from +/// the output rather than announced: there is no side channel, and adding one +/// would mean the script and the app had to agree on a protocol. +enum class SyncPhase { + Starting, ///< Launched, nothing recognised yet. + Mbsync, ///< Fetching mail. + Notmuch, ///< Reindexing. +}; + +/// Derives a short status line from the sync script's output as it streams. +/// +/// Kept separate from MailSync so it can be tested against captured output +/// without running a process, and free of any widget so the matching rules stay +/// one thing rather than being spread through a UI handler. +/// +/// **Matching is deliberately loose.** mbsync's and notmuch's exact wording +/// varies by version, and a status line that goes blank because a string moved +/// is worse than the fixed "Syncing..." this replaces. Nothing here decides +/// whether the run succeeded: the exit status is the only authority on that, and +/// a second opinion derived from text would eventually disagree with it. +class SyncPhaseTracker +{ +public: + /// Feeds one line. Returns true when the status text changed as a result, + /// so the caller can avoid rewriting the label for every line of noise. + bool feed(const QString &line); + + /// Clears back to Starting for a new run. + void reset(); + + SyncPhase phase() const { return m_phase; } + + /// Plain text, already truncated, safe to put straight into a label. + QString statusText() const { return m_status; } + +private: + SyncPhase m_phase = SyncPhase::Starting; + QString m_status; +}; + /// Runs the configured external sync command. /// /// qtmaildir deliberately does not implement sync itself. The existing script |
