diff options
Diffstat (limited to 'menubar/model.swift')
| -rw-r--r-- | menubar/model.swift | 44 |
1 files changed, 37 insertions, 7 deletions
diff --git a/menubar/model.swift b/menubar/model.swift index d0bbd7e..4117ba5 100644 --- a/menubar/model.swift +++ b/menubar/model.swift @@ -30,6 +30,9 @@ let mochaText = mocha(205, 214, 244) let mochaSubtext = mocha(166, 173, 200) let mochaOverlay = mocha(108, 112, 134) let mochaBlue = mocha(137, 180, 250) +let mochaRed = mocha(243, 139, 168) +let mochaYellow = mocha(249, 226, 175) +let mochaSurface = mocha(69, 71, 90) // MARK: herdr's status vocabulary @@ -99,6 +102,9 @@ struct Row: Equatable { var attended: Bool = false /// What its session spent today (UTC), in dollars (`@dingger_cost`). var cost: Double = 0 + /// How full its context window is, in percent (`@dingger_context`), as + /// pi's footer shows it; nil when unknown. + var context: Double? = nil var location: String { "\(session) · \(window)" } /// A draft left behind: where the user looks, they may be typing it. @@ -117,17 +123,41 @@ struct Row: Equatable { /// forgotten draft. var markedLabel: String { (importance == .high ? "! " : "") + (forgottenDraft ? "✎ " : "") + label } - /// Dim second line: where it runs, which harness, whether it is low, - /// what it spent today, and how long it waits. + /// The menu's dim second line: where it runs, which harness, whether + /// it is low, how long it waits, what it spent today, and how full its + /// context is. var subtitle: String { + var parts = [place] + if cost >= 0.005 { parts.append(dollars(cost)) } + if let context { parts.append(contextText(context)) } + return parts.joined(separator: " · ") + } + + /// The panel's second line, before its cost and context columns. + var place: String { var parts = [location, agent] if importance == .low { parts.append("low") } - if cost >= 0.005 { parts.append(dollars(cost)) } if waiting, since != Int.max { parts.append("\(status.rawValue) \(elapsed(sinceMs: since))") } return parts.joined(separator: " · ") } + + /// The panel's row as text: its columns, then cost and context. + var panelText: String { + let right = [cost >= 0.005 ? dollars(cost) : nil, context.map(contextText)].compactMap { $0 } + return "\(status.symbol) \(status.rawValue)\t\(markedLabel)\t\(place)" + + (right.isEmpty ? "" : "\t" + right.joined(separator: " ")) + } +} + +/// "10%". +func contextText(_ value: Double) -> String { "\(Int(value.rounded()))%" } + +/// The context meter's color: as pi's footer, yellow above 70% and red +/// above 90%; nil below. +func contextWarning(_ value: Double) -> NSColor? { + value > 90 ? mochaRed : value > 70 ? mochaYellow : nil } /// "$0.42", "$19.85"; whole dollars from $100: "$1,967". @@ -326,19 +356,19 @@ 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}", "#{window_active}", "#{session_attached}", "#{@dingger_draft}", "#{@dingger_cost}", + "#{@dingger_importance}", "#{window_active}", "#{session_attached}", "#{@dingger_draft}", "#{@dingger_cost}", "#{@dingger_context}", ].joined(separator: "\t") guard let out = tmux(["list-panes", "-a", "-F", format]) else { return [] } let lines = out.split(separator: "\n").map { $0.split(separator: "\t", omittingEmptySubsequences: false).map(String.init) } // Looked at in any of its sessions, as the daemon counts it. - let attended = Set(lines.filter { $0.count >= 15 && $0[11] == "1" && $0[12] != "0" }.map { $0[0] }) + let attended = Set(lines.filter { $0.count >= 16 && $0[11] == "1" && $0[12] != "0" }.map { $0[0] }) // A pane in several sessions (a session group, a linked window) is // listed once, under its first session, as the daemon counts it. var listed = Set<String>() let rows: [Row] = lines.compactMap { f in - guard f.count >= 15, !f[1].isEmpty, listed.insert(f[0]).inserted else { return nil } + guard f.count >= 16, !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] @@ -346,7 +376,7 @@ func fetchRows() -> [Row] { session: f[5], window: window, since: Int(f[3]) ?? Int.max, path: f[9].hasPrefix(home) ? "~" + f[9].dropFirst(home.count) : f[9], importance: Importance(option: f[10]), draft: f[13], attended: attended.contains(f[0]), - cost: Double(f[14]) ?? 0) + cost: Double(f[14]) ?? 0, context: Double(f[15])) } return rows.sorted(by: listedBefore) } |
