Files
codex/codex-rs/tui/src/keymap/conflict_tests.rs
T
Eric Traut 516f2780fd Open new sessions directly from the command center (#45255)
## What changed

- Replace the inline task composer with a session list: `n` opens a blank session in the selected checkout without sending an initial turn or interrupting running agents.
- Use single-letter action shortcuts and `Enter` to open a session. `Esc` cancels search or rename without closing the list; `Ctrl+C` quits from the list.
- Load destination settings for new sessions while carrying over explicit permission choices. Retain blank sessions and their drafts across navigation until the first turn.

## Testing

Update tests and snapshots for command center navigation, shortcuts, blank draft restoration, destination defaults, permission carryover, and directory trust.

GitOrigin-RevId: bddd04fdbe6ac2f5b7bd70293fd04f673b97ba02
2026-09-13 16:14:41 +00:00

77 lines
3.1 KiB
Rust

//! Regression coverage for conflict diagnostics and validation pass ordering.
use super::RuntimeKeymap;
use codex_config::types::TuiKeymap;
use pretty_assertions::assert_eq;
use serde_json::Value;
use serde_json::json;
#[test]
fn conflicting_contexts_report_the_first_conflict_in_validation_order() {
let contexts = [
("editor", "insert_newline", "yank"),
("vim_normal", "enter_insert", "cancel_operator"),
("vim_operator", "delete_line", "cancel"),
("vim_text_object", "word", "cancel"),
("pager", "scroll_up", "close_transcript"),
("list", "move_up", "cancel"),
("agents", "search", "toggle_grouping"),
("approval", "open_fullscreen", "cancel"),
];
let mut config = serde_json::Map::new();
for (context, first, second) in contexts {
config.insert(context.to_string(), json!({first: "f12", second: "f12"}));
}
for (context, first, second) in contexts {
let keymap: TuiKeymap = serde_json::from_value(Value::Object(config.clone()))
.expect("valid keymap configuration");
assert_eq!(
RuntimeKeymap::from_config(&keymap).expect_err("expected binding conflict"),
format!(
"Ambiguous `tui.keymap.{context}` bindings: `{first}` and `{second}` use the same key. \
Set unique keys in `~/.codex/config.toml` and retry. \
See the Codex keymap documentation for supported actions and examples."
)
);
config.remove(context);
}
}
#[test]
fn new_agents_defaults_preserve_existing_custom_bindings() {
for (action, alias) in [("archive", "a"), ("delete", "delete"), ("hide", "h")] {
for (context, existing, suffix) in [
("agents", "stop", ""),
("list", "move_down", ""),
("global", "copy", ""),
("agents", "stop", " f12"),
("list", "move_down", " f12"),
] {
// Plain keys are allowed in the dashboard, but global actions and list
// chord prefixes still share text-entry surfaces.
if alias != "delete" && (context == "global" || context == "list" && !suffix.is_empty())
{
continue;
}
let keymap: TuiKeymap = serde_json::from_value(
json!({context: {existing: format!("{alias}{suffix}")}, "approval": {"open_fullscreen": "f12", "approve_for_session": []},
"editor": {"move_line_start": [], "move_line_end": [], "delete_backward_word": [], "delete_forward": []}}),
)
.unwrap();
let runtime =
RuntimeKeymap::from_config(&keymap).expect("existing configuration remains valid");
let bindings = match action {
"archive" => &runtime.agents.archive,
"delete" => &runtime.agents.delete,
"hide" => &runtime.agents.hide,
_ => unreachable!(),
};
assert!(
bindings.is_empty(),
"{action} shadows {context}.{existing} = {alias}{suffix}"
);
}
}
}