Files
menologion/quickshell/services/Typikon.qml
T
funkpower 7beb53fc94 the documented way to use this did not work
`import qs.horologion.modules` was the README's headline instruction and it
fails outright: Quickshell resolves `qs` against the host config root, not
the subtree, so in an empty shell the type is unavailable and in a populated
one the widget would have silently bound to the host's Config and Theme
instead of its own. The imports inside are now relative and each directory
carries a qmldir, so `import "horologion/modules"` works in any host and the
three pieces really are usable on their own.

  - refresh() dropped a request made while a run was in flight, so a
    jurisdiction or date set a moment after startup never took effect until
    midnight. It queues now.
  - The waybar script exited non-zero on its error paths, and waybar hides a
    module whose script does that -- so a missing typikon made the module
    vanish rather than say so, and the .error CSS was dead. An unrecognised
    --format field raised instead of rendering empty, and the tooltip
    interpolated unescaped text into Pango markup, which matters because
    --update-menaion fetches commemorations from a page nobody here controls.
  - The installer aborted the whole run at the point where it printed
    'leaving it alone', and a wholly successful run exited 1 because the last
    statement was a failed [ -d ] test under set -e. --help demanded typikon,
    which is what --help would have told you to install.
  - eww painted every day with the feast colour and printed a dangling
    separator, because it compares against "" and eww renders a JSON null as
    the string "null". The parenthesised ?: form two lines away was already
    right. The week list also repeated today.

pip install typikon installed nothing; there is no such package, and that was
the first line of every install path. Pascha now carries its label instead of
being a bare ISO date in a corner.

tests/smoke.sh covers the scripts, which is where all of this lived and where
nothing was covered. It caught two of these while being written.
2026-09-18 10:29:37 -04:00

104 lines
4.0 KiB
QML

pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
// The liturgical day, from the `typikon` command.
//
// Computed locally, so this needs no network and cannot go stale. It only has
// to be re-read when the date changes, which a clock at minute precision
// notices without polling a subprocess every few seconds.
Singleton {
id: root
// Set this to a jurisdiction key — "rocor", "antiochian", "oca" — or leave
// it empty to use whatever `typikon --set-default` wrote.
property string jurisdiction: ""
// Today plus the next six, so the week ahead is visible at a glance.
property int days: 7
// Empty means today. Set it to an ISO date to look at a different one --
// useful for seeing what Great Week will ask of you before it arrives.
property string forDate: ""
property bool available: false
property string error: ""
property var week: []
property var today: ({})
readonly property string date: today.date ?? ""
readonly property string weekday: today.weekday ?? ""
readonly property string churchDate: today.churchDate ?? ""
readonly property string season: today.season ?? ""
readonly property string cycle: today.cycle ?? ""
readonly property string feast: today.feast ?? ""
readonly property string title: today.title ?? ""
readonly property string rank: today.rank ?? ""
readonly property string fast: today.fast ?? "none"
readonly property string fastLabel: today.fastLabel ?? ""
readonly property string emoji: today.emoji ?? ""
readonly property string reason: today.reason ?? ""
readonly property string obligation: today.obligation ?? ""
readonly property string pascha: today.pascha ?? ""
readonly property int daysToPascha: today.daysToPascha ?? 0
readonly property var commemorations: today.commemorations ?? []
readonly property bool obligatory: obligation === "obligatory"
// A request made while a run is in flight is queued, not dropped. Dropping
// it meant a jurisdiction or date set a moment after startup never took
// effect at all -- the answer stayed yesterday's until midnight.
property bool _queued: false
function refresh() {
if (proc.running) { root._queued = true; return; }
proc.running = true;
}
SystemClock { id: clock; precision: SystemClock.Minutes }
// Re-read when the day rolls over, not on a timer. The answer changes at
// midnight and at no other moment.
readonly property string _day: Qt.formatDateTime(clock.date, "yyyy-MM-dd")
on_DayChanged: root.refresh()
onJurisdictionChanged: root.refresh()
onForDateChanged: root.refresh()
Component.onCompleted: root.refresh()
Process {
id: proc
onExited: if (root._queued) { root._queued = false; root.refresh(); }
command: {
const c = ["typikon", "--json", "--days", String(root.days)];
if (root.jurisdiction !== "")
c.push("--jurisdiction", root.jurisdiction);
if (root.forDate !== "")
c.push("--date", root.forDate);
return c;
}
stdout: StdioCollector {
onStreamFinished: {
try {
const parsed = JSON.parse(this.text);
root.week = parsed.days ?? [parsed];
root.today = root.week.length ? root.week[0] : {};
root.available = true;
root.error = "";
} catch (e) {
root.available = false;
root.error = "could not read typikon";
}
}
}
stderr: StdioCollector {
onStreamFinished: {
if (this.text.trim() !== "") {
root.available = false;
root.error = this.text.trim();
}
}
}
}
}