aboutsummaryrefslogtreecommitdiff
path: root/menubar/model.swift
diff options
context:
space:
mode:
Diffstat (limited to 'menubar/model.swift')
-rw-r--r--menubar/model.swift53
1 files changed, 44 insertions, 9 deletions
diff --git a/menubar/model.swift b/menubar/model.swift
index 8bed858..760ff31 100644
--- a/menubar/model.swift
+++ b/menubar/model.swift
@@ -65,6 +65,20 @@ enum Status: String {
}
}
+/// The agent's importance (`@dingger_importance`, unset for normal): it
+/// orders agents within a status, and a low agent makes no sound.
+enum Importance: Int {
+ case low = 0, normal = 1, high = 2
+
+ init(option: String) {
+ switch option {
+ case "high": self = .high
+ case "low": self = .low
+ default: self = .normal
+ }
+ }
+}
+
struct Row: Equatable {
let paneId: String
let agent: String
@@ -76,6 +90,7 @@ struct Row: Equatable {
let since: Int
/// The pane's working directory, home as "~".
var path: String = ""
+ var importance: Importance = .normal
var location: String { "\(session) · \(window)" }
var waiting: Bool { status == .blocked || status == .done }
@@ -86,9 +101,14 @@ struct Row: Equatable {
return name.count > 80 ? String(name.prefix(79)) + "…" : name
}
- /// Dim second line: where it runs, which harness, and how long it waits.
+ /// The title's text as plain text: `! ` marks a high agent.
+ var markedLabel: String { (importance == .high ? "! " : "") + label }
+
+ /// Dim second line: where it runs, which harness, whether it is low,
+ /// and how long it waits.
var subtitle: String {
var parts = [location, agent]
+ if importance == .low { parts.append("low") }
if waiting, since != Int.max {
parts.append("\(status.rawValue) \(elapsed(sinceMs: since))")
}
@@ -219,13 +239,15 @@ func runDinggerInLoginShell(_ args: [String]) -> (ok: Bool, output: String) {
private let home = NSHomeDirectory()
-/// Every agent pane: herdr's status priority; within a status, done and
-/// blocked oldest first (the queue), working and idle most recent first
-/// (`@dingger_since`: when the pane entered its status); then by place.
+/// Every agent pane: herdr's status priority; within a status, the more
+/// important first, then done and blocked oldest first (the queue),
+/// working and idle most recent first (`@dingger_since`: when the pane
+/// entered its status); then by place.
func fetchRows() -> [Row] {
let format = [
"#{pane_id}", "#{@agent}", "#{@agent_state}", "#{@dingger_since}", "#{@agent_name}",
"#{session_name}", "#{window_name}", "#{window_panes}", "#{pane_index}", "#{pane_current_path}",
+ "#{@dingger_importance}",
].joined(separator: "\t")
guard let out = tmux(["list-panes", "-a", "-F", format]) else { return [] }
// A pane in several sessions (a session group, a linked window) is
@@ -233,13 +255,14 @@ func fetchRows() -> [Row] {
var listed = Set<String>()
let rows: [Row] = out.split(separator: "\n").compactMap { line in
let f = line.split(separator: "\t", omittingEmptySubsequences: false).map(String.init)
- guard f.count >= 10, !f[1].isEmpty, listed.insert(f[0]).inserted else { return nil }
+ guard f.count >= 11, !f[1].isEmpty, listed.insert(f[0]).inserted else { return nil }
let status = Status(rawValue: f[2]) ?? .unknown
guard status != .unknown else { return nil }
let window = (Int(f[7]) ?? 1) > 1 ? "\(f[6]).\(f[8])" : f[6]
return Row(paneId: f[0], agent: f[1], name: f[4], status: status,
session: f[5], window: window, since: Int(f[3]) ?? Int.max,
- path: f[9].hasPrefix(home) ? "~" + f[9].dropFirst(home.count) : f[9])
+ path: f[9].hasPrefix(home) ? "~" + f[9].dropFirst(home.count) : f[9],
+ importance: Importance(option: f[10]))
}
return rows.sorted(by: listedBefore)
}
@@ -247,6 +270,7 @@ func fetchRows() -> [Row] {
/// The list order (see `fetchRows`).
func listedBefore(_ a: Row, _ b: Row) -> Bool {
if a.status.priority != b.status.priority { return a.status.priority > b.status.priority }
+ if a.importance != b.importance { return a.importance.rawValue > b.importance.rawValue }
if a.since != b.since {
// Int.max: never stamped; last either way.
if a.since == Int.max || b.since == Int.max { return a.since < b.since }
@@ -291,8 +315,15 @@ func plainTitle(for rows: [Row]) -> String {
title(for: rows).string
}
-/// Row title: the colored status symbol, then the agent's name. Unnamed
-/// agents show their harness, dimmed, so it never competes with real names.
+/// The title's characters before the name: the status symbol, and `!` for a
+/// high agent.
+func rowTitlePrefix(_ row: Row) -> String {
+ "\(row.status.symbol) " + (row.importance == .high ? "! " : "")
+}
+
+/// Row title: the colored status symbol, a bold `!` for a high agent, then
+/// the agent's name. Unnamed agents show their harness, dimmed, so it never
+/// competes with real names; a low agent's name is lightly dimmed.
func rowTitle(_ row: Row, primary: NSColor = .labelColor,
secondary: NSColor = .secondaryLabelColor) -> NSAttributedString {
let font = NSFont.menuFont(ofSize: 0)
@@ -300,7 +331,11 @@ func rowTitle(_ row: Row, primary: NSColor = .labelColor,
let text = NSMutableAttributedString()
text.append(NSAttributedString(
string: "\(row.status.symbol) ", attributes: [.font: mono, .foregroundColor: row.status.color]))
- let labelColor = row.name.isEmpty ? secondary : primary
+ if row.importance == .high {
+ text.append(NSAttributedString(
+ string: "! ", attributes: [.font: NSFont.boldSystemFont(ofSize: font.pointSize), .foregroundColor: primary]))
+ }
+ let labelColor = row.name.isEmpty ? secondary : row.importance == .low ? primary.withAlphaComponent(0.7) : primary
text.append(NSAttributedString(
string: row.label, attributes: [.font: font, .foregroundColor: labelColor]))
return text