Files
llmx/codex-rs/tui/src/slash_command.rs
Ahmed Ibrahim e761924dc2 feat: add exit slash command alias for quit (#6002)
## Summary
- add the `/exit` slash command alongside `/quit` and reuse shared exit
handling
- refactor the chat widget to funnel quit, exit, logout, and shutdown
flows through a common `request_exit` helper
- add focused unit tests that confirm both `/quit` and `/exit` send an
`ExitRequest`

## Testing
- `just fmt`
- `just fix -p codex-tui`
- `cargo test -p codex-tui`


------
https://chatgpt.com/codex/tasks/task_i_6903d5a8f47c8321bf180f031f2fa330
2025-10-30 17:29:40 -07:00

101 lines
3.5 KiB
Rust

use strum::IntoEnumIterator;
use strum_macros::AsRefStr;
use strum_macros::EnumIter;
use strum_macros::EnumString;
use strum_macros::IntoStaticStr;
/// Commands that can be invoked by starting a message with a leading slash.
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, EnumString, EnumIter, AsRefStr, IntoStaticStr,
)]
#[strum(serialize_all = "kebab-case")]
pub enum SlashCommand {
// DO NOT ALPHA-SORT! Enum order is presentation order in the popup, so
// more frequently used commands should be listed first.
Model,
Approvals,
Review,
New,
Init,
Compact,
Undo,
Diff,
Mention,
Status,
Mcp,
Logout,
Quit,
Exit,
Feedback,
Rollout,
TestApproval,
}
impl SlashCommand {
/// User-visible description shown in the popup.
pub fn description(self) -> &'static str {
match self {
SlashCommand::Feedback => "send logs to maintainers",
SlashCommand::New => "start a new chat during a conversation",
SlashCommand::Init => "create an AGENTS.md file with instructions for Codex",
SlashCommand::Compact => "summarize conversation to prevent hitting the context limit",
SlashCommand::Review => "review my current changes and find issues",
SlashCommand::Undo => "ask Codex to undo a turn",
SlashCommand::Quit | SlashCommand::Exit => "exit Codex",
SlashCommand::Diff => "show git diff (including untracked files)",
SlashCommand::Mention => "mention a file",
SlashCommand::Status => "show current session configuration and token usage",
SlashCommand::Model => "choose what model and reasoning effort to use",
SlashCommand::Approvals => "choose what Codex can do without approval",
SlashCommand::Mcp => "list configured MCP tools",
SlashCommand::Logout => "log out of Codex",
SlashCommand::Rollout => "print the rollout file path",
SlashCommand::TestApproval => "test approval request",
}
}
/// Command string without the leading '/'. Provided for compatibility with
/// existing code that expects a method named `command()`.
pub fn command(self) -> &'static str {
self.into()
}
/// Whether this command can be run while a task is in progress.
pub fn available_during_task(self) -> bool {
match self {
SlashCommand::New
| SlashCommand::Init
| SlashCommand::Compact
| SlashCommand::Undo
| SlashCommand::Model
| SlashCommand::Approvals
| SlashCommand::Review
| SlashCommand::Logout => false,
SlashCommand::Diff
| SlashCommand::Mention
| SlashCommand::Status
| SlashCommand::Mcp
| SlashCommand::Feedback
| SlashCommand::Quit
| SlashCommand::Exit => true,
SlashCommand::Rollout => true,
SlashCommand::TestApproval => true,
}
}
fn is_visible(self) -> bool {
match self {
SlashCommand::Rollout | SlashCommand::TestApproval => cfg!(debug_assertions),
_ => true,
}
}
}
/// Return all built-in commands in a Vec paired with their command string.
pub fn built_in_slash_commands() -> Vec<(&'static str, SlashCommand)> {
SlashCommand::iter()
.filter(|command| command.is_visible())
.map(|c| (c.command(), c))
.collect()
}