diff options
Diffstat (limited to 'crates/dinggerd/src/tmux.rs')
| -rw-r--r-- | crates/dinggerd/src/tmux.rs | 67 |
1 files changed, 38 insertions, 29 deletions
diff --git a/crates/dinggerd/src/tmux.rs b/crates/dinggerd/src/tmux.rs index cba1ca6..f6c2f17 100644 --- a/crates/dinggerd/src/tmux.rs +++ b/crates/dinggerd/src/tmux.rs @@ -2,15 +2,14 @@ use std::process::Command; -use detect_core::manifest::agent_state_label; use detect_core::{identify_agent, Agent, AgentState}; #[derive(Debug, Clone)] pub struct Pane { /// Unique tmux pane id, e.g. `%3`. Stable for the pane's lifetime. pub pane_id: String, - /// User-facing target, e.g. `main:1.0`. - pub target: String, + /// Human-readable target, e.g. `main:work` (`.pane` suffix when split). + pub display_target: String, /// Foreground command name in the pane, from `#{pane_current_command}`. pub current_command: String, /// Last OSC title the pane's application set, from `#{pane_title}`. @@ -29,14 +28,21 @@ pub struct Pane { /// The `@dingger_ack` user option: "1" when the user already jumped to /// this pane in its current ready episode. pub written_ack: String, + /// The pane is the active pane of the active window. + pub pane_active: bool, } impl Pane { - /// Panes the user is actively looking at suppress notifications, mirroring - /// herdr's active-tab suppression. + /// Panes the user is actively looking at suppress finished notifications, + /// mirroring herdr's active-tab suppression. pub fn suppresses_notifications(&self) -> bool { self.window_active && self.session_attached } + + /// The pane is fully focused: the user is looking at this exact pane. + pub fn attended(&self) -> bool { + self.pane_active && self.suppresses_notifications() + } } fn run_tmux(args: &[&str]) -> Result<String, String> { @@ -64,7 +70,6 @@ fn run_tmux(args: &[&str]) -> Result<String, String> { pub fn list_panes() -> Result<Vec<Pane>, String> { let format = concat!( "#{pane_id}\t", - "#{session_name}:#{window_index}.#{pane_index}\t", "#{pane_current_command}\t", "#{pane_title}\t", "#{pane_dead}\t", @@ -74,18 +79,22 @@ pub fn list_panes() -> Result<Vec<Pane>, String> { "#{pane_pid}\t", "#{@agent_state}\t", "#{@agent}\t", - "#{@dingger_ack}" + "#{@dingger_ack}\t", + "#{pane_active}\t", + "#{session_name}:#{window_name}\t", + "#{window_panes}\t", + "#{pane_index}", ); let out = run_tmux(&["list-panes", "-a", "-F", format])?; let mut panes = Vec::new(); for line in out.lines() { let fields: Vec<&str> = line.split('\t').collect(); - if fields.len() < 11 { + if fields.len() < 15 { continue; } - let current_command = fields[2].to_string(); - let start_command = fields[7].to_string(); - let pane_pid: Option<u32> = fields[8].trim().parse().ok(); + let current_command = fields[1].to_string(); + let start_command = fields[6].to_string(); + let pane_pid: Option<u32> = fields[7].trim().parse().ok(); // An agent may be started via a wrapper or still be initializing // behind the shell; `pane_start_command` covers launch-command cases. let mut agent = @@ -97,18 +106,25 @@ pub fn list_panes() -> Result<Vec<Pane>, String> { let tree = process_tree.get_or_insert_with(fetch_process_tree); agent = resolve_agent_in_process_tree(pane_pid, tree); } + // Display target: session:window-name, pane index only when split. + let mut display_target = fields[12].to_string(); + if fields[13].parse::<u32>().map(|n| n > 1).unwrap_or(false) { + display_target.push('.'); + display_target.push_str(fields[14]); + } panes.push(Pane { pane_id: fields[0].to_string(), - target: fields[1].to_string(), + display_target, current_command, - pane_title: fields[3].to_string(), - dead: fields[4] == "1", - window_active: fields[5] == "1", - session_attached: fields[6] != "0", + pane_title: fields[2].to_string(), + dead: fields[3] == "1", + window_active: fields[4] == "1", + session_attached: fields[5] != "0", agent, - written_state: fields[9].to_string(), - written_agent: fields[10].to_string(), - written_ack: fields.get(11).copied().unwrap_or("").to_string(), + written_state: fields[8].to_string(), + written_agent: fields[9].to_string(), + written_ack: fields[10].to_string(), + pane_active: fields[11] == "1", }); } Ok(panes) @@ -190,16 +206,9 @@ pub fn capture_pane(pane_id: &str) -> Result<String, String> { run_tmux(&["capture-pane", "-p", "-q", "-t", pane_id]) } -pub fn set_agent_state(pane_id: &str, state: AgentState) -> Result<(), String> { - run_tmux(&[ - "set-option", - "-p", - "-t", - pane_id, - "@agent_state", - agent_state_label(state), - ]) - .map(|_| ()) +/// Write the pane's display status (herdr's vocabulary: done/idle/...). +pub fn set_agent_state(pane_id: &str, label: &str) -> Result<(), String> { + run_tmux(&["set-option", "-p", "-t", pane_id, "@agent_state", label]).map(|_| ()) } /// Label the pane with the agent running in it, for tmux status-line and |
