mirror of
https://github.com/openai/codex.git
synced 2026-10-29 19:08:43 +00:00
tui: use generic slash parser building blocks
Replace the remaining parse-kind special cases with declarative slash parser primitives so each command spec owns its inline-arg parser as NoArgs, Remainder, or token choices in both tui implementations. Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
co-authored by
Codex
parent
708a95ed4a
commit
c17a609cb2
@@ -271,9 +271,9 @@ use crate::render::renderable::FlexRenderable;
|
||||
use crate::render::renderable::Renderable;
|
||||
use crate::render::renderable::RenderableExt;
|
||||
use crate::render::renderable::RenderableItem;
|
||||
use crate::slash_command::FastSlashCommandArgs;
|
||||
use crate::slash_command::ParsedSlashCommand;
|
||||
use crate::slash_command::SlashCommand;
|
||||
use crate::slash_command_input::FastSlashCommandArgs;
|
||||
use crate::slash_command_input::ParsedSlashCommand;
|
||||
use crate::status::RateLimitSnapshotDisplay;
|
||||
use crate::status_indicator_widget::STATUS_DETAILS_DEFAULT_MAX_LINES;
|
||||
use crate::status_indicator_widget::StatusDetailsCapitalization;
|
||||
|
||||
@@ -73,15 +73,73 @@ pub(crate) enum SlashCommandBareBehavior {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum SlashCommandParseKind {
|
||||
NoArgs,
|
||||
Fast,
|
||||
pub(crate) enum FastSlashCommandArgs {
|
||||
On,
|
||||
Off,
|
||||
Status,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum ParsedSlashCommand {
|
||||
Bare(SlashCommandBareBehavior),
|
||||
Fast(FastSlashCommandArgs),
|
||||
Rename,
|
||||
Plan,
|
||||
Review,
|
||||
SandboxReadRoot,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum SlashCommandUsageErrorKind {
|
||||
UnexpectedInlineArgs,
|
||||
InvalidInlineArgs,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum SlashCommandArgsParser {
|
||||
NoArgs,
|
||||
Remainder(ParsedSlashCommand),
|
||||
Tokens(&'static [SlashCommandTokenChoice]),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) struct SlashCommandTokenChoice {
|
||||
pub(crate) token: &'static str,
|
||||
pub(crate) parsed: ParsedSlashCommand,
|
||||
}
|
||||
|
||||
const FAST_TOKEN_CHOICES: &[SlashCommandTokenChoice] = &[
|
||||
SlashCommandTokenChoice {
|
||||
token: "on",
|
||||
parsed: ParsedSlashCommand::Fast(FastSlashCommandArgs::On),
|
||||
},
|
||||
SlashCommandTokenChoice {
|
||||
token: "off",
|
||||
parsed: ParsedSlashCommand::Fast(FastSlashCommandArgs::Off),
|
||||
},
|
||||
SlashCommandTokenChoice {
|
||||
token: "status",
|
||||
parsed: ParsedSlashCommand::Fast(FastSlashCommandArgs::Status),
|
||||
},
|
||||
];
|
||||
|
||||
impl SlashCommandArgsParser {
|
||||
pub(crate) fn parse(
|
||||
self,
|
||||
args: &str,
|
||||
) -> Result<ParsedSlashCommand, SlashCommandUsageErrorKind> {
|
||||
match self {
|
||||
SlashCommandArgsParser::NoArgs => Err(SlashCommandUsageErrorKind::UnexpectedInlineArgs),
|
||||
SlashCommandArgsParser::Remainder(parsed) => Ok(parsed),
|
||||
SlashCommandArgsParser::Tokens(choices) => choices
|
||||
.iter()
|
||||
.find(|choice| choice.token.eq_ignore_ascii_case(args))
|
||||
.map(|choice| choice.parsed)
|
||||
.ok_or(SlashCommandUsageErrorKind::InvalidInlineArgs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SlashCommand {
|
||||
pub(crate) fn spec(self) -> SlashCommandSpec {
|
||||
match self {
|
||||
@@ -92,7 +150,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/model"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Fast => SlashCommandSpec {
|
||||
description: "toggle Fast mode to enable fastest inference at 2X plan usage",
|
||||
@@ -101,7 +159,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/fast", "/fast [on|off|status]"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::Fast,
|
||||
args_parser: SlashCommandArgsParser::Tokens(FAST_TOKEN_CHOICES),
|
||||
},
|
||||
SlashCommand::Approvals => SlashCommandSpec {
|
||||
description: "choose what Codex is allowed to do",
|
||||
@@ -110,7 +168,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: true,
|
||||
usage_lines: &["/approvals"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Permissions => SlashCommandSpec {
|
||||
description: "choose what Codex is allowed to do",
|
||||
@@ -119,7 +177,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/permissions"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::ElevateSandbox => SlashCommandSpec {
|
||||
description: "set up elevated agent sandbox",
|
||||
@@ -128,7 +186,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/setup-default-sandbox"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::SandboxReadRoot => SlashCommandSpec {
|
||||
description: "let sandbox read a directory: /sandbox-add-read-dir <absolute_path>",
|
||||
@@ -137,7 +195,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/sandbox-add-read-dir <absolute-path>"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::SandboxReadRoot,
|
||||
args_parser: SlashCommandArgsParser::Remainder(ParsedSlashCommand::SandboxReadRoot),
|
||||
},
|
||||
SlashCommand::Experimental => SlashCommandSpec {
|
||||
description: "toggle experimental features",
|
||||
@@ -146,7 +204,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/experimental"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Skills => SlashCommandSpec {
|
||||
description: "use skills to improve how Codex performs specific tasks",
|
||||
@@ -155,7 +213,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/skills"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Review => SlashCommandSpec {
|
||||
description: "review my current changes and find issues",
|
||||
@@ -164,7 +222,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/review", "/review <instructions>"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::Review,
|
||||
args_parser: SlashCommandArgsParser::Remainder(ParsedSlashCommand::Review),
|
||||
},
|
||||
SlashCommand::Rename => SlashCommandSpec {
|
||||
description: "rename the current thread",
|
||||
@@ -173,7 +231,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/rename", "/rename <title>"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::Rename,
|
||||
args_parser: SlashCommandArgsParser::Remainder(ParsedSlashCommand::Rename),
|
||||
},
|
||||
SlashCommand::New => SlashCommandSpec {
|
||||
description: "start a new chat during a conversation",
|
||||
@@ -182,7 +240,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/new"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Resume => SlashCommandSpec {
|
||||
description: "resume a saved chat",
|
||||
@@ -191,7 +249,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/resume"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Fork => SlashCommandSpec {
|
||||
description: "fork the current chat",
|
||||
@@ -200,7 +258,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/fork"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Init => SlashCommandSpec {
|
||||
description: "create an AGENTS.md file with instructions for Codex",
|
||||
@@ -209,7 +267,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/init"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Compact => SlashCommandSpec {
|
||||
description: "summarize conversation to prevent hitting the context limit",
|
||||
@@ -218,7 +276,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/compact"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Plan => SlashCommandSpec {
|
||||
description: "switch to Plan mode",
|
||||
@@ -227,7 +285,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/plan", "/plan <prompt>"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::Plan,
|
||||
args_parser: SlashCommandArgsParser::Remainder(ParsedSlashCommand::Plan),
|
||||
},
|
||||
SlashCommand::Collab => SlashCommandSpec {
|
||||
description: "change collaboration mode (experimental)",
|
||||
@@ -236,7 +294,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/collab"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Agent => SlashCommandSpec {
|
||||
description: "switch the active agent thread",
|
||||
@@ -245,7 +303,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/agent"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Diff => SlashCommandSpec {
|
||||
description: "show git diff (including untracked files)",
|
||||
@@ -254,7 +312,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/diff"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Copy => SlashCommandSpec {
|
||||
description: "copy the latest Codex output to your clipboard",
|
||||
@@ -263,7 +321,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/copy"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Mention => SlashCommandSpec {
|
||||
description: "mention a file",
|
||||
@@ -272,7 +330,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/mention"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Status => SlashCommandSpec {
|
||||
description: "show current session configuration and token usage",
|
||||
@@ -281,7 +339,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/status"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::DebugConfig => SlashCommandSpec {
|
||||
description: "show config layers and requirement sources for debugging",
|
||||
@@ -290,7 +348,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/debug-config"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Title => SlashCommandSpec {
|
||||
description: "configure which items appear in the terminal title",
|
||||
@@ -299,7 +357,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/title"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Statusline => SlashCommandSpec {
|
||||
description: "configure which items appear in the status line",
|
||||
@@ -308,7 +366,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/statusline"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Theme => SlashCommandSpec {
|
||||
description: "choose a syntax highlighting theme",
|
||||
@@ -317,7 +375,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/theme"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Mcp => SlashCommandSpec {
|
||||
description: "list configured MCP tools",
|
||||
@@ -326,7 +384,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/mcp"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Apps => SlashCommandSpec {
|
||||
description: "manage apps",
|
||||
@@ -335,7 +393,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/apps"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Plugins => SlashCommandSpec {
|
||||
description: "browse plugins",
|
||||
@@ -344,7 +402,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/plugins"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Logout => SlashCommandSpec {
|
||||
description: "log out of Codex",
|
||||
@@ -353,7 +411,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/logout"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Quit => SlashCommandSpec {
|
||||
description: "exit Codex",
|
||||
@@ -362,7 +420,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: true,
|
||||
usage_lines: &["/quit"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Exit => SlashCommandSpec {
|
||||
description: "exit Codex",
|
||||
@@ -371,7 +429,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/exit"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Feedback => SlashCommandSpec {
|
||||
description: "send logs to maintainers",
|
||||
@@ -380,7 +438,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/feedback"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Rollout => SlashCommandSpec {
|
||||
description: "print the rollout file path",
|
||||
@@ -389,7 +447,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/rollout"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Ps => SlashCommandSpec {
|
||||
description: "list background terminals",
|
||||
@@ -398,7 +456,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/ps"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Stop => SlashCommandSpec {
|
||||
description: "stop all background terminals",
|
||||
@@ -407,7 +465,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/stop"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Clear => SlashCommandSpec {
|
||||
description: "clear the terminal and start a new chat",
|
||||
@@ -416,7 +474,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/clear"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Personality => SlashCommandSpec {
|
||||
description: "choose a communication style for Codex",
|
||||
@@ -425,7 +483,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/personality"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Realtime => SlashCommandSpec {
|
||||
description: "toggle realtime voice mode (experimental)",
|
||||
@@ -434,7 +492,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/realtime"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Settings => SlashCommandSpec {
|
||||
description: "configure realtime microphone/speaker",
|
||||
@@ -443,7 +501,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/settings"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::TestApproval => SlashCommandSpec {
|
||||
description: "test approval request",
|
||||
@@ -452,7 +510,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/test-approval"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::MultiAgents => SlashCommandSpec {
|
||||
description: "switch the active agent thread",
|
||||
@@ -461,7 +519,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/subagents"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::MemoryDrop => SlashCommandSpec {
|
||||
description: "DO NOT USE",
|
||||
@@ -470,7 +528,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/debug-m-drop"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::MemoryUpdate => SlashCommandSpec {
|
||||
description: "DO NOT USE",
|
||||
@@ -479,7 +537,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/debug-m-update"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -533,7 +591,7 @@ pub(crate) struct SlashCommandSpec {
|
||||
pub(crate) hide_in_command_popup: bool,
|
||||
pub(crate) usage_lines: &'static [&'static str],
|
||||
pub(crate) bare_behavior: SlashCommandBareBehavior,
|
||||
pub(crate) parse_kind: SlashCommandParseKind,
|
||||
pub(crate) args_parser: SlashCommandArgsParser,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,29 +1,6 @@
|
||||
use crate::slash_command::ParsedSlashCommand;
|
||||
use crate::slash_command::SlashCommand;
|
||||
use crate::slash_command::SlashCommandBareBehavior;
|
||||
use crate::slash_command::SlashCommandParseKind;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum FastSlashCommandArgs {
|
||||
On,
|
||||
Off,
|
||||
Status,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum ParsedSlashCommand {
|
||||
Bare(SlashCommandBareBehavior),
|
||||
Fast(FastSlashCommandArgs),
|
||||
Rename,
|
||||
Plan,
|
||||
Review,
|
||||
SandboxReadRoot,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum SlashCommandUsageErrorKind {
|
||||
UnexpectedInlineArgs,
|
||||
InvalidInlineArgs,
|
||||
}
|
||||
use crate::slash_command::SlashCommandUsageErrorKind;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) struct SlashCommandUsageError {
|
||||
@@ -55,25 +32,12 @@ impl SlashCommand {
|
||||
return Ok(ParsedSlashCommand::Bare(spec.bare_behavior));
|
||||
}
|
||||
|
||||
match spec.parse_kind {
|
||||
SlashCommandParseKind::NoArgs => Err(SlashCommandUsageError {
|
||||
spec.args_parser
|
||||
.parse(trimmed)
|
||||
.map_err(|kind| SlashCommandUsageError {
|
||||
command: self,
|
||||
kind: SlashCommandUsageErrorKind::UnexpectedInlineArgs,
|
||||
}),
|
||||
SlashCommandParseKind::Fast => match trimmed.to_ascii_lowercase().as_str() {
|
||||
"on" => Ok(ParsedSlashCommand::Fast(FastSlashCommandArgs::On)),
|
||||
"off" => Ok(ParsedSlashCommand::Fast(FastSlashCommandArgs::Off)),
|
||||
"status" => Ok(ParsedSlashCommand::Fast(FastSlashCommandArgs::Status)),
|
||||
_ => Err(SlashCommandUsageError {
|
||||
command: self,
|
||||
kind: SlashCommandUsageErrorKind::InvalidInlineArgs,
|
||||
}),
|
||||
},
|
||||
SlashCommandParseKind::Rename => Ok(ParsedSlashCommand::Rename),
|
||||
SlashCommandParseKind::Plan => Ok(ParsedSlashCommand::Plan),
|
||||
SlashCommandParseKind::Review => Ok(ParsedSlashCommand::Review),
|
||||
SlashCommandParseKind::SandboxReadRoot => Ok(ParsedSlashCommand::SandboxReadRoot),
|
||||
}
|
||||
kind,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +46,8 @@ mod tests {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
use crate::slash_command::FastSlashCommandArgs;
|
||||
use crate::slash_command::SlashCommandBareBehavior;
|
||||
|
||||
#[test]
|
||||
fn review_bare_form_is_marked_as_ui_driven() {
|
||||
|
||||
@@ -315,9 +315,9 @@ use crate::render::renderable::FlexRenderable;
|
||||
use crate::render::renderable::Renderable;
|
||||
use crate::render::renderable::RenderableExt;
|
||||
use crate::render::renderable::RenderableItem;
|
||||
use crate::slash_command::FastSlashCommandArgs;
|
||||
use crate::slash_command::ParsedSlashCommand;
|
||||
use crate::slash_command::SlashCommand;
|
||||
use crate::slash_command_input::FastSlashCommandArgs;
|
||||
use crate::slash_command_input::ParsedSlashCommand;
|
||||
use crate::status::RateLimitSnapshotDisplay;
|
||||
use crate::status_indicator_widget::STATUS_DETAILS_DEFAULT_MAX_LINES;
|
||||
use crate::status_indicator_widget::StatusDetailsCapitalization;
|
||||
|
||||
@@ -72,15 +72,73 @@ pub(crate) enum SlashCommandBareBehavior {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum SlashCommandParseKind {
|
||||
NoArgs,
|
||||
Fast,
|
||||
pub(crate) enum FastSlashCommandArgs {
|
||||
On,
|
||||
Off,
|
||||
Status,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum ParsedSlashCommand {
|
||||
Bare(SlashCommandBareBehavior),
|
||||
Fast(FastSlashCommandArgs),
|
||||
Rename,
|
||||
Plan,
|
||||
Review,
|
||||
SandboxReadRoot,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum SlashCommandUsageErrorKind {
|
||||
UnexpectedInlineArgs,
|
||||
InvalidInlineArgs,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum SlashCommandArgsParser {
|
||||
NoArgs,
|
||||
Remainder(ParsedSlashCommand),
|
||||
Tokens(&'static [SlashCommandTokenChoice]),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) struct SlashCommandTokenChoice {
|
||||
pub(crate) token: &'static str,
|
||||
pub(crate) parsed: ParsedSlashCommand,
|
||||
}
|
||||
|
||||
const FAST_TOKEN_CHOICES: &[SlashCommandTokenChoice] = &[
|
||||
SlashCommandTokenChoice {
|
||||
token: "on",
|
||||
parsed: ParsedSlashCommand::Fast(FastSlashCommandArgs::On),
|
||||
},
|
||||
SlashCommandTokenChoice {
|
||||
token: "off",
|
||||
parsed: ParsedSlashCommand::Fast(FastSlashCommandArgs::Off),
|
||||
},
|
||||
SlashCommandTokenChoice {
|
||||
token: "status",
|
||||
parsed: ParsedSlashCommand::Fast(FastSlashCommandArgs::Status),
|
||||
},
|
||||
];
|
||||
|
||||
impl SlashCommandArgsParser {
|
||||
pub(crate) fn parse(
|
||||
self,
|
||||
args: &str,
|
||||
) -> Result<ParsedSlashCommand, SlashCommandUsageErrorKind> {
|
||||
match self {
|
||||
SlashCommandArgsParser::NoArgs => Err(SlashCommandUsageErrorKind::UnexpectedInlineArgs),
|
||||
SlashCommandArgsParser::Remainder(parsed) => Ok(parsed),
|
||||
SlashCommandArgsParser::Tokens(choices) => choices
|
||||
.iter()
|
||||
.find(|choice| choice.token.eq_ignore_ascii_case(args))
|
||||
.map(|choice| choice.parsed)
|
||||
.ok_or(SlashCommandUsageErrorKind::InvalidInlineArgs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SlashCommand {
|
||||
pub(crate) fn spec(self) -> SlashCommandSpec {
|
||||
match self {
|
||||
@@ -91,7 +149,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/model"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Fast => SlashCommandSpec {
|
||||
description: "toggle Fast mode to enable fastest inference at 2X plan usage",
|
||||
@@ -100,7 +158,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/fast", "/fast [on|off|status]"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::Fast,
|
||||
args_parser: SlashCommandArgsParser::Tokens(FAST_TOKEN_CHOICES),
|
||||
},
|
||||
SlashCommand::Approvals => SlashCommandSpec {
|
||||
description: "choose what Codex is allowed to do",
|
||||
@@ -109,7 +167,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: true,
|
||||
usage_lines: &["/approvals"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Permissions => SlashCommandSpec {
|
||||
description: "choose what Codex is allowed to do",
|
||||
@@ -118,7 +176,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/permissions"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::ElevateSandbox => SlashCommandSpec {
|
||||
description: "set up elevated agent sandbox",
|
||||
@@ -127,7 +185,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/setup-default-sandbox"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::SandboxReadRoot => SlashCommandSpec {
|
||||
description: "let sandbox read a directory: /sandbox-add-read-dir <absolute_path>",
|
||||
@@ -136,7 +194,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/sandbox-add-read-dir <absolute-path>"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::SandboxReadRoot,
|
||||
args_parser: SlashCommandArgsParser::Remainder(ParsedSlashCommand::SandboxReadRoot),
|
||||
},
|
||||
SlashCommand::Experimental => SlashCommandSpec {
|
||||
description: "toggle experimental features",
|
||||
@@ -145,7 +203,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/experimental"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Skills => SlashCommandSpec {
|
||||
description: "use skills to improve how Codex performs specific tasks",
|
||||
@@ -154,7 +212,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/skills"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Review => SlashCommandSpec {
|
||||
description: "review my current changes and find issues",
|
||||
@@ -163,7 +221,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/review", "/review <instructions>"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::Review,
|
||||
args_parser: SlashCommandArgsParser::Remainder(ParsedSlashCommand::Review),
|
||||
},
|
||||
SlashCommand::Rename => SlashCommandSpec {
|
||||
description: "rename the current thread",
|
||||
@@ -172,7 +230,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/rename", "/rename <title>"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::Rename,
|
||||
args_parser: SlashCommandArgsParser::Remainder(ParsedSlashCommand::Rename),
|
||||
},
|
||||
SlashCommand::New => SlashCommandSpec {
|
||||
description: "start a new chat during a conversation",
|
||||
@@ -181,7 +239,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/new"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Resume => SlashCommandSpec {
|
||||
description: "resume a saved chat",
|
||||
@@ -190,7 +248,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/resume"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Fork => SlashCommandSpec {
|
||||
description: "fork the current chat",
|
||||
@@ -199,7 +257,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/fork"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Init => SlashCommandSpec {
|
||||
description: "create an AGENTS.md file with instructions for Codex",
|
||||
@@ -208,7 +266,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/init"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Compact => SlashCommandSpec {
|
||||
description: "summarize conversation to prevent hitting the context limit",
|
||||
@@ -217,7 +275,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/compact"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Plan => SlashCommandSpec {
|
||||
description: "switch to Plan mode",
|
||||
@@ -226,7 +284,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/plan", "/plan <prompt>"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::Plan,
|
||||
args_parser: SlashCommandArgsParser::Remainder(ParsedSlashCommand::Plan),
|
||||
},
|
||||
SlashCommand::Collab => SlashCommandSpec {
|
||||
description: "change collaboration mode (experimental)",
|
||||
@@ -235,7 +293,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/collab"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Agent => SlashCommandSpec {
|
||||
description: "switch the active agent thread",
|
||||
@@ -244,7 +302,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/agent"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Diff => SlashCommandSpec {
|
||||
description: "show git diff (including untracked files)",
|
||||
@@ -253,7 +311,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/diff"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Copy => SlashCommandSpec {
|
||||
description: "copy the latest Codex output to your clipboard",
|
||||
@@ -262,7 +320,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/copy"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Mention => SlashCommandSpec {
|
||||
description: "mention a file",
|
||||
@@ -271,7 +329,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/mention"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Status => SlashCommandSpec {
|
||||
description: "show current session configuration and token usage",
|
||||
@@ -280,7 +338,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/status"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::DebugConfig => SlashCommandSpec {
|
||||
description: "show config layers and requirement sources for debugging",
|
||||
@@ -289,7 +347,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/debug-config"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Statusline => SlashCommandSpec {
|
||||
description: "configure which items appear in the status line",
|
||||
@@ -298,7 +356,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/statusline"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Theme => SlashCommandSpec {
|
||||
description: "choose a syntax highlighting theme",
|
||||
@@ -307,7 +365,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/theme"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Mcp => SlashCommandSpec {
|
||||
description: "list configured MCP tools",
|
||||
@@ -316,7 +374,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/mcp"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Apps => SlashCommandSpec {
|
||||
description: "manage apps",
|
||||
@@ -325,7 +383,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/apps"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Plugins => SlashCommandSpec {
|
||||
description: "browse plugins",
|
||||
@@ -334,7 +392,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/plugins"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Logout => SlashCommandSpec {
|
||||
description: "log out of Codex",
|
||||
@@ -343,7 +401,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/logout"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Quit => SlashCommandSpec {
|
||||
description: "exit Codex",
|
||||
@@ -352,7 +410,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: true,
|
||||
usage_lines: &["/quit"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Exit => SlashCommandSpec {
|
||||
description: "exit Codex",
|
||||
@@ -361,7 +419,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/exit"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Feedback => SlashCommandSpec {
|
||||
description: "send logs to maintainers",
|
||||
@@ -370,7 +428,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/feedback"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Rollout => SlashCommandSpec {
|
||||
description: "print the rollout file path",
|
||||
@@ -379,7 +437,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/rollout"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Ps => SlashCommandSpec {
|
||||
description: "list background terminals",
|
||||
@@ -388,7 +446,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/ps"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Stop => SlashCommandSpec {
|
||||
description: "stop all background terminals",
|
||||
@@ -397,7 +455,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/stop"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Clear => SlashCommandSpec {
|
||||
description: "clear the terminal and start a new chat",
|
||||
@@ -406,7 +464,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/clear"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Personality => SlashCommandSpec {
|
||||
description: "choose a communication style for Codex",
|
||||
@@ -415,7 +473,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/personality"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Realtime => SlashCommandSpec {
|
||||
description: "toggle realtime voice mode (experimental)",
|
||||
@@ -424,7 +482,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/realtime"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::Settings => SlashCommandSpec {
|
||||
description: "configure realtime microphone/speaker",
|
||||
@@ -433,7 +491,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/settings"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::TestApproval => SlashCommandSpec {
|
||||
description: "test approval request",
|
||||
@@ -442,7 +500,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/test-approval"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::MultiAgents => SlashCommandSpec {
|
||||
description: "switch the active agent thread",
|
||||
@@ -451,7 +509,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/subagents"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::MemoryDrop => SlashCommandSpec {
|
||||
description: "DO NOT USE",
|
||||
@@ -460,7 +518,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/debug-m-drop"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
SlashCommand::MemoryUpdate => SlashCommandSpec {
|
||||
description: "DO NOT USE",
|
||||
@@ -469,7 +527,7 @@ impl SlashCommand {
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/debug-m-update"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
args_parser: SlashCommandArgsParser::NoArgs,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -523,7 +581,7 @@ pub(crate) struct SlashCommandSpec {
|
||||
pub(crate) hide_in_command_popup: bool,
|
||||
pub(crate) usage_lines: &'static [&'static str],
|
||||
pub(crate) bare_behavior: SlashCommandBareBehavior,
|
||||
pub(crate) parse_kind: SlashCommandParseKind,
|
||||
pub(crate) args_parser: SlashCommandArgsParser,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,29 +1,6 @@
|
||||
use crate::slash_command::ParsedSlashCommand;
|
||||
use crate::slash_command::SlashCommand;
|
||||
use crate::slash_command::SlashCommandBareBehavior;
|
||||
use crate::slash_command::SlashCommandParseKind;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum FastSlashCommandArgs {
|
||||
On,
|
||||
Off,
|
||||
Status,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum ParsedSlashCommand {
|
||||
Bare(SlashCommandBareBehavior),
|
||||
Fast(FastSlashCommandArgs),
|
||||
Rename,
|
||||
Plan,
|
||||
Review,
|
||||
SandboxReadRoot,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum SlashCommandUsageErrorKind {
|
||||
UnexpectedInlineArgs,
|
||||
InvalidInlineArgs,
|
||||
}
|
||||
use crate::slash_command::SlashCommandUsageErrorKind;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) struct SlashCommandUsageError {
|
||||
@@ -55,25 +32,12 @@ impl SlashCommand {
|
||||
return Ok(ParsedSlashCommand::Bare(spec.bare_behavior));
|
||||
}
|
||||
|
||||
match spec.parse_kind {
|
||||
SlashCommandParseKind::NoArgs => Err(SlashCommandUsageError {
|
||||
spec.args_parser
|
||||
.parse(trimmed)
|
||||
.map_err(|kind| SlashCommandUsageError {
|
||||
command: self,
|
||||
kind: SlashCommandUsageErrorKind::UnexpectedInlineArgs,
|
||||
}),
|
||||
SlashCommandParseKind::Fast => match trimmed.to_ascii_lowercase().as_str() {
|
||||
"on" => Ok(ParsedSlashCommand::Fast(FastSlashCommandArgs::On)),
|
||||
"off" => Ok(ParsedSlashCommand::Fast(FastSlashCommandArgs::Off)),
|
||||
"status" => Ok(ParsedSlashCommand::Fast(FastSlashCommandArgs::Status)),
|
||||
_ => Err(SlashCommandUsageError {
|
||||
command: self,
|
||||
kind: SlashCommandUsageErrorKind::InvalidInlineArgs,
|
||||
}),
|
||||
},
|
||||
SlashCommandParseKind::Rename => Ok(ParsedSlashCommand::Rename),
|
||||
SlashCommandParseKind::Plan => Ok(ParsedSlashCommand::Plan),
|
||||
SlashCommandParseKind::Review => Ok(ParsedSlashCommand::Review),
|
||||
SlashCommandParseKind::SandboxReadRoot => Ok(ParsedSlashCommand::SandboxReadRoot),
|
||||
}
|
||||
kind,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +46,8 @@ mod tests {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
use crate::slash_command::FastSlashCommandArgs;
|
||||
use crate::slash_command::SlashCommandBareBehavior;
|
||||
|
||||
#[test]
|
||||
fn review_bare_form_is_marked_as_ui_driven() {
|
||||
|
||||
Reference in New Issue
Block a user