aboutsummaryrefslogtreecommitdiff
path: root/crates/dinggerd/src/tmux.rs
diff options
context:
space:
mode:
authorIgor Soarez <igor@soarez.org>2026-10-19 16:55:30 +0300
committerIgor Soarez <igor@soarez.org>2026-10-19 16:55:30 +0300
commitea1dda2f056fdfd56bffe8b978c0b0786b82aa7d (patch)
tree2a6451f2a956cdd2345d6a77a2db00e0fff1d376 /crates/dinggerd/src/tmux.rs
parent9c6b10426bd897afe6cf6f0c022f45310c5ab3d3 (diff)
ready-queue fifo with click-to-focus; redesign presentation per design panel
daemon tracks when each agent became ready (idle/blocked, unacked) and publishes fifo queue + numeric counts as server-global options; unknown to idle transitions stay out of the queue (restart spam). new dingger focus subcommand jumps to the longest-waiting pane and acks it, bound to status-right clicks in tmux. menu bar redesigned per two-model design panel: monochrome sf-symbol bell + queue depth, queue-ordered rows with state glyphs and right-aligned targets, row clicks ack like focus does. tmux segment renders glyph+count with a single red accent for blocked; fixes unescaped comma in the conditional format that truncated the segment entirely.
Diffstat (limited to 'crates/dinggerd/src/tmux.rs')
-rw-r--r--crates/dinggerd/src/tmux.rs46
1 files changed, 43 insertions, 3 deletions
diff --git a/crates/dinggerd/src/tmux.rs b/crates/dinggerd/src/tmux.rs
index edd44aa..cba1ca6 100644
--- a/crates/dinggerd/src/tmux.rs
+++ b/crates/dinggerd/src/tmux.rs
@@ -26,6 +26,9 @@ pub struct Pane {
pub written_state: String,
/// The `@agent` user option (agent label) previously written, if any.
pub written_agent: String,
+ /// The `@dingger_ack` user option: "1" when the user already jumped to
+ /// this pane in its current ready episode.
+ pub written_ack: String,
}
impl Pane {
@@ -70,7 +73,8 @@ pub fn list_panes() -> Result<Vec<Pane>, String> {
"#{pane_start_command}\t",
"#{pane_pid}\t",
"#{@agent_state}\t",
- "#{@agent}"
+ "#{@agent}\t",
+ "#{@dingger_ack}"
);
let out = run_tmux(&["list-panes", "-a", "-F", format])?;
let mut panes = Vec::new();
@@ -104,6 +108,7 @@ pub fn list_panes() -> Result<Vec<Pane>, String> {
agent,
written_state: fields[9].to_string(),
written_agent: fields[10].to_string(),
+ written_ack: fields.get(11).copied().unwrap_or("").to_string(),
});
}
Ok(panes)
@@ -166,6 +171,19 @@ fn fetch_process_tree() -> ProcessTree {
(children, comm)
}
+/// Run a tmux command whose effect is an action (e.g. switch-client), not
+/// output to parse.
+pub fn run_tmux_client(args: &[&str]) -> Result<(), String> {
+ run_tmux(args).map(|_| ())
+}
+
+/// Read a format expansion for one pane.
+pub fn show_pane_format(pane_id: &str, format: &str) -> Option<String> {
+ run_tmux(&["display-message", "-p", "-t", pane_id, format])
+ .ok()
+ .map(|value| value.trim().to_string())
+}
+
/// Capture the pane's visible screen as plain text — the exact input shape
/// the detection manifests expect.
pub fn capture_pane(pane_id: &str) -> Result<String, String> {
@@ -187,6 +205,28 @@ pub fn set_agent_state(pane_id: &str, state: AgentState) -> Result<(), String> {
/// Label the pane with the agent running in it, for tmux status-line and
/// menu-bar rendering; clears the label when the pane stops running one.
pub fn set_agent(pane_id: &str, agent: Option<Agent>) -> Result<(), String> {
- let label = agent.map(detect_core::agent_label).unwrap_or("");
- run_tmux(&["set-option", "-p", "-t", pane_id, "@agent", label]).map(|_| ())
+ let label = agent.map(detect_core::agent_label).unwrap_or("");
+ run_tmux(&["set-option", "-p", "-t", pane_id, "@agent", label]).map(|_| ())
+}
+
+/// Write a server-global option (readable from any client and from formats).
+pub fn set_global(name: &str, value: &str) -> Result<(), String> {
+ run_tmux(&["set-option", "-g", name, value]).map(|_| ())
+}
+
+pub fn show_global(name: &str) -> Option<String> {
+ run_tmux(&["show-option", "-gv", name])
+ .ok()
+ .map(|value| value.trim().to_string())
+ .filter(|value| !value.is_empty())
+}
+
+/// Mark a pane as seen by the user after `dingger focus`: taken out of the
+/// ready queue until its next state transition.
+pub fn ack(pane_id: &str) -> Result<(), String> {
+ run_tmux(&["set-option", "-p", "-t", pane_id, "@dingger_ack", "1"]).map(|_| ())
+}
+
+pub fn clear_ack(pane_id: &str) -> Result<(), String> {
+ run_tmux(&["set-option", "-p", "-t", pane_id, "-u", "@dingger_ack"]).map(|_| ())
}