mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Probe Windows terminal colors without risking startup input (#40598)
## Why Windows Terminal and xterm.js can render a theme that differs from the underlying console color table. Querying that visible theme through OSC shares the console input queue with keystrokes, including input for security-sensitive startup prompts. ## What changed - Defer the Windows OSC color probe until protected startup decisions and the world-writable workspace scan have completed. - Preserve and replay unrelated console input records around the probe, while removing only valid OSC 10 and 11 replies and retaining the console palette as a fallback. - Require an explicit confirmation key after shortcuts select trust, sandbox, or world-writable warning choices, so a fragmented terminal reply cannot accept them. - Accept one- through four-digit OSC RGB components so the visible terminal palette is applied across supported response formats. ## Testing Added coverage for delayed startup scans, protected prompt confirmation, console-record replay, bracketed paste and malformed OSC preservation, RGB response parsing, and light-theme composer rendering. GitOrigin-RevId: b8ae456fe32c701ba3af31e9cc452fc4e8bffa22
This commit is contained in:
1 parent
1f5c9ba183
commit
70b5cfc73b
19 files changed
+1162
-149
No files matched your search
@@ -5090,6 +5090,29 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn light_terminal_palette_renders_light_composer_snapshot() {
|
||||
let colors = crate::terminal_probe::DefaultColors {
|
||||
fg: (0x55, 0x57, 0x53),
|
||||
bg: (0xff, 0xff, 0xff),
|
||||
};
|
||||
|
||||
crate::terminal_palette::with_test_default_colors(colors, || {
|
||||
let (composer, _rx) = new_test_composer();
|
||||
let area = Rect::new(
|
||||
/*x*/ 0, /*y*/ 0, /*width*/ 48, /*height*/ 6,
|
||||
);
|
||||
let mut buffer = Buffer::empty(area);
|
||||
composer.render(area, &mut buffer);
|
||||
|
||||
assert_eq!(
|
||||
buffer[(0, 1)].bg,
|
||||
crate::terminal_palette::rgb_color((244, 244, 244))
|
||||
);
|
||||
insta::assert_snapshot!("light_terminal_palette_composer", format!("{buffer:?}"));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn footer_hint_row_is_separated_from_composer() {
|
||||
let (tx, _rx) = unbounded_channel::<AppEvent>();
|
||||
|
||||
@@ -143,6 +143,8 @@ pub(crate) struct SelectionItem {
|
||||
pub is_disabled: bool,
|
||||
pub actions: Vec<SelectionAction>,
|
||||
pub dismiss_on_select: bool,
|
||||
/// Require an explicit accept key after a direct shortcut highlights this sensitive item.
|
||||
pub require_explicit_confirmation: bool,
|
||||
pub dismiss_parent_on_child_accept: bool,
|
||||
pub search_value: Option<String>,
|
||||
pub disabled_reason: Option<String>,
|
||||
@@ -807,6 +809,22 @@ impl ListSelectionView {
|
||||
}
|
||||
}
|
||||
|
||||
fn select_shortcut(&mut self, actual_idx: usize) {
|
||||
let previously_selected = self.selected_actual_idx();
|
||||
self.state.selected_idx = Some(actual_idx);
|
||||
if self
|
||||
.active_items()
|
||||
.get(actual_idx)
|
||||
.is_some_and(|item| item.require_explicit_confirmation)
|
||||
{
|
||||
if self.selected_actual_idx() != previously_selected {
|
||||
self.fire_selection_changed();
|
||||
}
|
||||
} else {
|
||||
self.accept();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn set_search_query(&mut self, query: String) {
|
||||
self.search_query = query;
|
||||
@@ -1047,8 +1065,7 @@ impl BottomPaneView for ListSelectionView {
|
||||
.is_some_and(|shortcut| shortcut.is_press(key_event))
|
||||
&& Self::item_is_enabled(item)
|
||||
}) {
|
||||
self.state.selected_idx = Some(idx);
|
||||
self.accept();
|
||||
self.select_shortcut(idx);
|
||||
return;
|
||||
}
|
||||
if let Some(idx) = c
|
||||
@@ -1056,8 +1073,7 @@ impl BottomPaneView for ListSelectionView {
|
||||
.map(|d| d as usize)
|
||||
.and_then(|number| self.actual_idx_for_enabled_number(number))
|
||||
{
|
||||
self.state.selected_idx = Some(idx);
|
||||
self.accept();
|
||||
self.select_shortcut(idx);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
---
|
||||
source: tui/src/bottom_pane/chat_composer.rs
|
||||
expression: "format!(\"{buffer:?}\")"
|
||||
---
|
||||
Buffer {
|
||||
area: Rect { x: 0, y: 0, width: 48, height: 6 },
|
||||
content: [
|
||||
" ",
|
||||
"› Ask Codex to do anything ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ? for shortcuts 100% context left ",
|
||||
],
|
||||
styles: [
|
||||
x: 0, y: 0, fg: Reset, bg: Rgb(244, 244, 244), underline: Reset, modifier: NONE,
|
||||
x: 0, y: 1, fg: Reset, bg: Rgb(244, 244, 244), underline: Reset, modifier: BOLD,
|
||||
x: 1, y: 1, fg: Reset, bg: Rgb(244, 244, 244), underline: Reset, modifier: NONE,
|
||||
x: 2, y: 1, fg: Reset, bg: Rgb(244, 244, 244), underline: Reset, modifier: DIM,
|
||||
x: 26, y: 1, fg: Reset, bg: Rgb(244, 244, 244), underline: Reset, modifier: NONE,
|
||||
x: 0, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
|
||||
x: 2, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
|
||||
x: 17, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
|
||||
x: 29, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
|
||||
x: 46, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user