aboutsummaryrefslogtreecommitdiff
path: root/menubar/model.swift
diff options
context:
space:
mode:
Diffstat (limited to 'menubar/model.swift')
-rw-r--r--menubar/model.swift44
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)
}