feat(tui): show running shell jobs in footer#2219
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a new ShellJobs status item to display running background shell commands in the TUI footer, along with a new voice_input module for bridging voice-input commands. The review feedback highlights three key areas for improvement: first, ensuring that with_current_defaults does not append the new status item if the user has explicitly configured an empty footer; second, respecting the user's configured ordering of Agents and ShellJobs rather than hardcoding their rendering order; and third, optimizing the character count check in the stderr summary helper to avoid scanning large strings unnecessarily.
| pub fn with_current_defaults(mut items: Vec<StatusItem>) -> Vec<StatusItem> { | ||
| if !items.contains(&StatusItem::ShellJobs) { | ||
| if let Some(pos) = items.iter().position(|item| *item == StatusItem::Agents) { | ||
| items.insert(pos + 1, StatusItem::ShellJobs); | ||
| } else { | ||
| items.push(StatusItem::ShellJobs); | ||
| } | ||
| } | ||
| items | ||
| } |
There was a problem hiding this comment.
If a user has explicitly configured an empty footer (i.e., status_items = [] in their configuration to hide the footer entirely), with_current_defaults will still append StatusItem::ShellJobs to the empty list, overriding their preference. We should check if items is empty and return early to preserve the user's choice of an empty footer.
#[must_use]
pub fn with_current_defaults(mut items: Vec<StatusItem>) -> Vec<StatusItem> {
if items.is_empty() {
return items;
}
if !items.contains(&StatusItem::ShellJobs) {
if let Some(pos) = items.iter().position(|item| *item == StatusItem::Agents) {
items.insert(pos + 1, StatusItem::ShellJobs);
} else {
items.push(StatusItem::ShellJobs);
}
}
items
}| let mut agents = Vec::new(); | ||
| if has(S::Agents) { | ||
| append_footer_chip( | ||
| &mut agents, | ||
| crate::tui::widgets::footer_agents_chip(running_agent_count(app), app.ui_locale), | ||
| ); | ||
| } | ||
| if has(S::ShellJobs) { | ||
| append_footer_chip(&mut agents, footer_shell_status_spans(app)); | ||
| } |
There was a problem hiding this comment.
The relative ordering of Agents and ShellJobs is currently hardcoded, meaning Agents will always render before ShellJobs even if the user configures them in the opposite order (e.g., status_items = [shell_jobs, agents]). To respect the user's configured order as described in the StatusItem documentation, we can iterate over items and append the chips in the order they appear.
| let mut agents = Vec::new(); | |
| if has(S::Agents) { | |
| append_footer_chip( | |
| &mut agents, | |
| crate::tui::widgets::footer_agents_chip(running_agent_count(app), app.ui_locale), | |
| ); | |
| } | |
| if has(S::ShellJobs) { | |
| append_footer_chip(&mut agents, footer_shell_status_spans(app)); | |
| } | |
| let mut agents = Vec::new(); | |
| for item in items { | |
| match *item { | |
| S::Agents => { | |
| append_footer_chip( | |
| &mut agents, | |
| crate::tui::widgets::footer_agents_chip(running_agent_count(app), app.ui_locale), | |
| ); | |
| } | |
| S::ShellJobs => { | |
| append_footer_chip(&mut agents, footer_shell_status_spans(app)); | |
| } | |
| _ => {} | |
| } | |
| } |
| return String::new(); | ||
| } | ||
| let mut summary: String = trimmed.chars().take(300).collect(); | ||
| if trimmed.chars().count() > 300 { |
There was a problem hiding this comment.
Calling trimmed.chars().count() scans the entire string to count all characters, which is an trimmed.chars().nth(300).is_some() which is much more efficient as it stops scanning after 300 characters.
| if trimmed.chars().count() > 300 { | |
| if trimmed.chars().nth(300).is_some() { |
|
great idea - I love this! will work on getting it released asap @reidliu41 |
| //! Voice-input command bridge for the composer. | ||
| //! | ||
| //! CodeWhale stays out of platform microphone APIs here. A configured command | ||
| //! owns recording and speech-to-text, writes the final transcript to stdout, | ||
| //! and the TUI inserts that transcript into the composer. | ||
|
|
||
| use std::path::Path; | ||
| use std::process::Stdio; | ||
| use std::time::Duration; | ||
|
|
There was a problem hiding this comment.
Orphaned module — not wired into the module tree
voice_input.rs is never declared with mod voice_input (or pub mod voice_input) in crates/tui/src/tui/mod.rs, so the Rust compiler silently ignores the entire file. The 127 lines of logic and the four unit tests it contains will never run. This looks like an accidental commit from a separate feature branch — either it needs a pub mod voice_input; line added to mod.rs, or the file should be removed from this PR.
Add a Shell jobs status item that surfaces active background shell commands in the footer. Show the running command and elapsed time for a single job, or a count for multiple jobs. Also migrate saved legacy status_items at startup so existing users see the new default footer chip without manually editing config.
454a678 to
88f955d
Compare
|
This conflicts with merged footer changes from #2194 (shell-running chip) and #2166 (user feedback). The functionality overlaps — closing as superseded. Thanks @reidliu41! |
Summary
Fixes #2194
Background shell commands started with
task_shell_startwere only visible from the Tasks/sidebar view. When the sidebar was hidden or the user was focused on the composer, the footer could look idle even though a shell command was still running.This adds a
shell_jobsfooter status item so active background shell work is visible in the footer:shell: <command> · <elapsed><n> shells running · <elapsed>Long commands are truncated in the footer to avoid crowding the status line; full details remain available in the Tasks/
sidebar panel.
Saved legacy
tui.status_itemsconfigs are also upgraded in memory so existing users get the new defaultShell jobschip without manually editing config.Testing
cargo fmt --all -- --checkcargo clippy --workspace --all-targets --all-featurescargo test --workspace --all-featuresChecklist
Greptile Summary
This PR surfaces active background shell jobs in the TUI footer so users can see running
task_shell_startwork without opening the sidebar. AShellJobschip renders one running command (truncated to 28 chars) or anN shells runningcount, each with an elapsed-time suffix drawn from the longest-running job.StatusItem::ShellJobsvariant is added with full metadata and wired intorender_footer_fromalongside the existingAgentschip, both feeding intoFooterProps.agents.with_current_defaultsmigrates legacystatus_itemsconfigs by insertingShellJobsafterAgents(or appending it), applied atApp::newwhen a saved config is loaded.render_footer_frompropagation, and the migration path.Confidence Score: 5/5
Safe to merge. All changes are additive UI-layer additions that do not touch data persistence, auth, or any critical path outside footer rendering.
The new shell status chip is purely additive — no existing behavior is altered, and the migration function only adds to saved configs, never removes. The string-prefix convention
shell:used to identify shell tasks is consistent with the existing sidebar code.crates/tui/src/tui/footer_ui.rs — the test-only
footer_auxiliary_spanshelper includes shell spans unconditionally, while the productionrender_footer_fromgates them on config.Important Files Changed
ShellJobsvariant toStatusItemenum with key, description, hint, and awith_current_defaultsmigration function that insertsShellJobsafterAgentsin legacy saved configs. Two unit tests cover both code paths.ShellJobstoStatusItemValueand the two bidirectionalFromimpls. Mechanical, consistent with the existing pattern.status_itemsthroughwith_current_defaultsbefore use, ensuring legacy configs receive theShellJobschip automatically.footer_shell_status_spansandappend_footer_chiphelpers; wiresShellJobsintorender_footer_from(config-gated) andfooter_auxiliary_spans(unconditional). The test-only helper always includes shell spans regardless of the user's config, creating a minor parity gap.render_footer_from, and the legacy-config migration path.Reviews (2): Last reviewed commit: "feat(tui): show running shell jobs in fo..." | Re-trigger Greptile