Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions codex-rs/config/src/tui_keymap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ pub struct TuiVimNormalKeymap {
pub delete_char: Option<KeybindingsSpec>,
/// Delete from cursor to end of line (`D`).
pub delete_to_line_end: Option<KeybindingsSpec>,
/// Change from cursor to end of line and enter insert mode (`C`).
pub change_to_line_end: Option<KeybindingsSpec>,
/// Yank the entire line (`Y`).
pub yank_line: Option<KeybindingsSpec>,
/// Paste after cursor (`p`).
Expand All @@ -231,6 +233,8 @@ pub struct TuiVimNormalKeymap {
pub start_delete_operator: Option<KeybindingsSpec>,
/// Begin yank operator; next key selects motion (`y`).
pub start_yank_operator: Option<KeybindingsSpec>,
/// Begin change operator; next keys select a text object.
pub start_change_operator: Option<KeybindingsSpec>,
/// Cancel a pending operator and return to normal mode.
pub cancel_operator: Option<KeybindingsSpec>,
}
Expand Down Expand Up @@ -266,10 +270,39 @@ pub struct TuiVimOperatorKeymap {
pub motion_line_start: Option<KeybindingsSpec>,
/// Motion: to end of line (`$`).
pub motion_line_end: Option<KeybindingsSpec>,
/// Select an inner text object after an operator.
pub select_inner_text_object: Option<KeybindingsSpec>,
/// Select an around text object after an operator.
pub select_around_text_object: Option<KeybindingsSpec>,
/// Cancel the pending operator and return to normal mode.
pub cancel: Option<KeybindingsSpec>,
}

/// Vim text-object keybindings for modal editing inside text areas.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default, JsonSchema)]
#[serde(deny_unknown_fields)]
#[schemars(deny_unknown_fields)]
pub struct TuiVimTextObjectKeymap {
/// Text object: word.
pub word: Option<KeybindingsSpec>,
/// Text object: whitespace-delimited WORD.
pub big_word: Option<KeybindingsSpec>,
/// Text object: parentheses.
pub parentheses: Option<KeybindingsSpec>,
/// Text object: brackets.
pub brackets: Option<KeybindingsSpec>,
/// Text object: braces.
pub braces: Option<KeybindingsSpec>,
/// Text object: double quotes.
pub double_quote: Option<KeybindingsSpec>,
/// Text object: single quotes.
pub single_quote: Option<KeybindingsSpec>,
/// Text object: backticks.
pub backtick: Option<KeybindingsSpec>,
/// Cancel the pending text-object command.
pub cancel: Option<KeybindingsSpec>,
}

/// Pager context keybindings for transcript and static overlays.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default, JsonSchema)]
#[serde(deny_unknown_fields)]
Expand Down Expand Up @@ -374,6 +407,8 @@ pub struct TuiKeymap {
#[serde(default)]
pub vim_operator: TuiVimOperatorKeymap,
#[serde(default)]
pub vim_text_object: TuiVimTextObjectKeymap,
#[serde(default)]
pub pager: TuiPagerKeymap,
#[serde(default)]
pub list: TuiListKeymap,
Expand Down Expand Up @@ -560,6 +595,20 @@ mod tests {
);
}

#[test]
fn misspelled_vim_text_object_action_is_rejected() {
let toml_input = r#"
[vim_text_object]
double_quotes = "shift-quote"
"#;
let err = toml::from_str::<TuiKeymap>(toml_input)
.expect_err("expected unknown vim text object action");
assert!(
err.to_string().contains("double_quotes"),
"expected error to mention misspelled field, got: {err}"
);
}

#[test]
fn removed_backtrack_actions_are_rejected() {
for (context, action) in [
Expand Down
148 changes: 148 additions & 0 deletions codex-rs/core/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2824,6 +2824,7 @@
"append_after_cursor": null,
"append_line_end": null,
"cancel_operator": null,
"change_to_line_end": null,
"delete_char": null,
"delete_to_line_end": null,
"enter_insert": null,
Expand All @@ -2840,6 +2841,7 @@
"open_line_above": null,
"open_line_below": null,
"paste_after": null,
"start_change_operator": null,
"start_delete_operator": null,
"start_yank_operator": null,
"yank_line": null
Expand All @@ -2856,7 +2858,20 @@
"motion_word_backward": null,
"motion_word_end": null,
"motion_word_forward": null,
"select_around_text_object": null,
"select_inner_text_object": null,
"yank_line": null
},
"vim_text_object": {
"backtick": null,
"big_word": null,
"braces": null,
"brackets": null,
"cancel": null,
"double_quote": null,
"parentheses": null,
"single_quote": null,
"word": null
}
},
"description": "Keybinding overrides for the TUI.\n\nThis supports rebinding selected actions globally and by context. Context bindings take precedence over `global` bindings."
Expand Down Expand Up @@ -3490,6 +3505,7 @@
"append_after_cursor": null,
"append_line_end": null,
"cancel_operator": null,
"change_to_line_end": null,
"delete_char": null,
"delete_to_line_end": null,
"enter_insert": null,
Expand All @@ -3506,6 +3522,7 @@
"open_line_above": null,
"open_line_below": null,
"paste_after": null,
"start_change_operator": null,
"start_delete_operator": null,
"start_yank_operator": null,
"yank_line": null
Expand All @@ -3529,8 +3546,28 @@
"motion_word_backward": null,
"motion_word_end": null,
"motion_word_forward": null,
"select_around_text_object": null,
"select_inner_text_object": null,
"yank_line": null
}
},
"vim_text_object": {
"allOf": [
{
"$ref": "#/definitions/TuiVimTextObjectKeymap"
}
],
"default": {
"backtick": null,
"big_word": null,
"braces": null,
"brackets": null,
"cancel": null,
"double_quote": null,
"parentheses": null,
"single_quote": null,
"word": null
}
}
},
"type": "object"
Expand Down Expand Up @@ -3755,6 +3792,14 @@
],
"description": "Cancel a pending operator and return to normal mode."
},
"change_to_line_end": {
"allOf": [
{
"$ref": "#/definitions/KeybindingsSpec"
}
],
"description": "Change from cursor to end of line and enter insert mode (`C`)."
},
"delete_char": {
"allOf": [
{
Expand Down Expand Up @@ -3883,6 +3928,14 @@
],
"description": "Paste after cursor (`p`)."
},
"start_change_operator": {
"allOf": [
{
"$ref": "#/definitions/KeybindingsSpec"
}
],
"description": "Begin change operator; next keys select a text object."
},
"start_delete_operator": {
"allOf": [
{
Expand Down Expand Up @@ -4002,6 +4055,22 @@
],
"description": "Motion: to start of next word (`w`)."
},
"select_around_text_object": {
"allOf": [
{
"$ref": "#/definitions/KeybindingsSpec"
}
],
"description": "Select an around text object after an operator."
},
"select_inner_text_object": {
"allOf": [
{
"$ref": "#/definitions/KeybindingsSpec"
}
],
"description": "Select an inner text object after an operator."
},
"yank_line": {
"allOf": [
{
Expand All @@ -4013,6 +4082,85 @@
},
"type": "object"
},
"TuiVimTextObjectKeymap": {
"additionalProperties": false,
"description": "Vim text-object keybindings for modal editing inside text areas.",
"properties": {
"backtick": {
"allOf": [
{
"$ref": "#/definitions/KeybindingsSpec"
}
],
"description": "Text object: backticks."
},
"big_word": {
"allOf": [
{
"$ref": "#/definitions/KeybindingsSpec"
}
],
"description": "Text object: whitespace-delimited WORD."
},
"braces": {
"allOf": [
{
"$ref": "#/definitions/KeybindingsSpec"
}
],
"description": "Text object: braces."
},
"brackets": {
"allOf": [
{
"$ref": "#/definitions/KeybindingsSpec"
}
],
"description": "Text object: brackets."
},
"cancel": {
"allOf": [
{
"$ref": "#/definitions/KeybindingsSpec"
}
],
"description": "Cancel the pending text-object command."
},
"double_quote": {
"allOf": [
{
"$ref": "#/definitions/KeybindingsSpec"
}
],
"description": "Text object: double quotes."
},
"parentheses": {
"allOf": [
{
"$ref": "#/definitions/KeybindingsSpec"
}
],
"description": "Text object: parentheses."
},
"single_quote": {
"allOf": [
{
"$ref": "#/definitions/KeybindingsSpec"
}
],
"description": "Text object: single quotes."
},
"word": {
"allOf": [
{
"$ref": "#/definitions/KeybindingsSpec"
}
],
"description": "Text object: word."
}
},
"type": "object"
},
"UriBasedFileOpener": {
"oneOf": [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
source: tui/src/bottom_pane/textarea.rs
expression: "states.join(\"\\n\\n\")"
---
alpha beta gamma
^

alpha beta gamma
^

alpha beta gamma
^
Loading
Loading