aboutsummaryrefslogtreecommitdiff
path: root/menubar
diff options
context:
space:
mode:
Diffstat (limited to 'menubar')
-rw-r--r--menubar/main.swift24
-rw-r--r--menubar/model.swift31
2 files changed, 55 insertions, 0 deletions
diff --git a/menubar/main.swift b/menubar/main.swift
index 2230817..82931ab 100644
--- a/menubar/main.swift
+++ b/menubar/main.swift
@@ -236,6 +236,16 @@ final class Menubar: NSObject, NSApplicationDelegate, NSMenuDelegate {
refresh()
}
+ /// Reload the agents on an old extension: those that can now, the
+ /// others as they become idle and leave the screen (the daemon's job).
+ @objc private func reloadOutdated() {
+ log("reload agents: requested")
+ DispatchQueue.global().async {
+ let result = runReporting(dinggerBinary, ["reload-agents"])
+ log("reload agents: \(result.ok ? "" : "failed: ")\(result.output.replacingOccurrences(of: "\n", with: "; "))")
+ }
+ }
+
@objc private func restoreFromMenu(_ sender: NSMenuItem) {
restore(sessions: (sender.representedObject as? String).map { [$0] } ?? [])
}
@@ -304,6 +314,16 @@ final class Menubar: NSObject, NSApplicationDelegate, NSMenuDelegate {
menu.addItem(item)
menu.addItem(.separator())
}
+ let outdated = fetchOutdated()
+ if !outdated.isEmpty {
+ let item = NSMenuItem(title: "⟳ \(outdated.title)", action: outdated.canReload ? #selector(reloadOutdated) : nil,
+ keyEquivalent: "")
+ item.target = self
+ item.isEnabled = outdated.canReload
+ item.subtitle = outdated.detail
+ menu.addItem(item)
+ menu.addItem(.separator())
+ }
if rows.isEmpty {
let none = NSMenuItem(title: "No agents", action: nil, keyEquivalent: "")
none.isEnabled = false
@@ -443,6 +463,10 @@ if arguments.contains("--selftest") {
if arguments.contains("--print") {
let rows = fetchRows()
print("title: \(plainTitle(for: rows))")
+ let outdated = fetchOutdated()
+ if !outdated.isEmpty {
+ print("⟳ \(outdated.title)\t\(outdated.detail)\(outdated.canReload ? "" : "\t(disabled)")")
+ }
for row in rows {
print("\(row.status.symbol) \(row.status.rawValue)\t\(row.markedLabel)\t\(row.subtitle)")
}
diff --git a/menubar/model.swift b/menubar/model.swift
index f0f977e..e4d179c 100644
--- a/menubar/model.swift
+++ b/menubar/model.swift
@@ -230,6 +230,37 @@ func fetchRestoreOffer() -> RestoreOffer? {
return try? JSONDecoder().decode(RestoreOffer.self, from: data)
}
+// MARK: agents on an old extension
+
+/// pi agents on an old dingger extension, as the daemon counts them:
+/// `@dingger_outdated` it can reload, `@dingger_outdated_by_hand` it cannot
+/// (an extension from before reloads).
+struct OutdatedAgents: Equatable {
+ let reloadable: Int
+ let byHand: Int
+
+ var isEmpty: Bool { reloadable == 0 && byHand == 0 }
+ var canReload: Bool { reloadable > 0 }
+
+ private func agents(_ n: Int) -> String { "\(n) \(n == 1 ? "Agent" : "Agents")" }
+
+ /// "Reload 3 Agents on an Old Extension", or "2 Agents Need /reload".
+ var title: String {
+ canReload ? "Reload \(agents(reloadable)) on an Old Extension" : "\(agents(byHand)) \(byHand == 1 ? "Needs" : "Need") /reload"
+ }
+
+ var detail: String {
+ guard canReload else { return "their dingger extension is too old to reload them" }
+ let when = "each when idle and off screen"
+ return byHand > 0 ? "\(when) · \(byHand) more need /reload" : when
+ }
+}
+
+func fetchOutdated() -> OutdatedAgents {
+ let count = { (name: String) in Int(tmux(["show-options", "-gv", name])?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "") ?? 0 }
+ return OutdatedAgents(reloadable: count("@dingger_outdated"), byHand: count("@dingger_outdated_by_hand"))
+}
+
/// Run `dingger <args>` through the user's login shell, the way a terminal
/// starts tmux: restored panes inherit this environment (PATH, LANG), and
/// launchd's is bare. DINGGER_RESTORE_DIRECT runs it directly (tests).