mirror of
https://github.com/openai/codex.git
synced 2026-05-04 19:36:45 +00:00
feat(tui2): copy tui crate and normalize snapshots (#7833)
Introduce a full codex-tui source snapshot under the new codex-tui2 crate so viewport work can be replayed in isolation. This change copies the entire codex-rs/tui/src tree into codex-rs/tui2/src in one atomic step, rather than piecemeal, to keep future diffs vs the original viewport bookmark easy to reason about. The goal is for codex-tui2 to render identically to the existing TUI behind the `features.tui2` flag while we gradually port the viewport/history commits from the joshka/viewport bookmark onto this forked tree. While on this baseline change, we also ran the codex-tui2 snapshot test suite and accepted all insta snapshots for the new crate, so the snapshot files now use the codex-tui2 naming scheme and encode the unmodified legacy TUI behavior. This keeps later viewport commits focused on intentional behavior changes (and their snapshots) rather than on mechanical snapshot renames.
This commit is contained in:
128
codex-rs/tui2/src/public_widgets/composer_input.rs
Normal file
128
codex-rs/tui2/src/public_widgets/composer_input.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
//! Public wrapper around the internal ChatComposer for simple, reusable text input.
|
||||
//!
|
||||
//! This exposes a minimal interface suitable for other crates (e.g.,
|
||||
//! codex-cloud-tasks) to reuse the mature composer behavior: multi-line input,
|
||||
//! paste heuristics, Enter-to-submit, and Shift+Enter for newline.
|
||||
|
||||
use crossterm::event::KeyEvent;
|
||||
use ratatui::buffer::Buffer;
|
||||
use ratatui::layout::Rect;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::app_event::AppEvent;
|
||||
use crate::app_event_sender::AppEventSender;
|
||||
use crate::bottom_pane::ChatComposer;
|
||||
use crate::bottom_pane::InputResult;
|
||||
use crate::render::renderable::Renderable;
|
||||
|
||||
/// Action returned from feeding a key event into the ComposerInput.
|
||||
pub enum ComposerAction {
|
||||
/// The user submitted the current text (typically via Enter). Contains the submitted text.
|
||||
Submitted(String),
|
||||
/// No submission occurred; UI may need to redraw if `needs_redraw()` returned true.
|
||||
None,
|
||||
}
|
||||
|
||||
/// A minimal, public wrapper for the internal `ChatComposer` that behaves as a
|
||||
/// reusable text input field with submit semantics.
|
||||
pub struct ComposerInput {
|
||||
inner: ChatComposer,
|
||||
_tx: tokio::sync::mpsc::UnboundedSender<AppEvent>,
|
||||
rx: tokio::sync::mpsc::UnboundedReceiver<AppEvent>,
|
||||
}
|
||||
|
||||
impl ComposerInput {
|
||||
/// Create a new composer input with a neutral placeholder.
|
||||
pub fn new() -> Self {
|
||||
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
let sender = AppEventSender::new(tx.clone());
|
||||
// `enhanced_keys_supported=true` enables Shift+Enter newline hint/behavior.
|
||||
let inner = ChatComposer::new(true, sender, true, "Compose new task".to_string(), false);
|
||||
Self { inner, _tx: tx, rx }
|
||||
}
|
||||
|
||||
/// Returns true if the input is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.inner.is_empty()
|
||||
}
|
||||
|
||||
/// Clear the input text.
|
||||
pub fn clear(&mut self) {
|
||||
self.inner.set_text_content(String::new());
|
||||
}
|
||||
|
||||
/// Feed a key event into the composer and return a high-level action.
|
||||
pub fn input(&mut self, key: KeyEvent) -> ComposerAction {
|
||||
let action = match self.inner.handle_key_event(key).0 {
|
||||
InputResult::Submitted(text) => ComposerAction::Submitted(text),
|
||||
_ => ComposerAction::None,
|
||||
};
|
||||
self.drain_app_events();
|
||||
action
|
||||
}
|
||||
|
||||
pub fn handle_paste(&mut self, pasted: String) -> bool {
|
||||
let handled = self.inner.handle_paste(pasted);
|
||||
self.drain_app_events();
|
||||
handled
|
||||
}
|
||||
|
||||
/// Override the footer hint items displayed under the composer.
|
||||
/// Each tuple is rendered as "<key> <label>", with keys styled.
|
||||
pub fn set_hint_items(&mut self, items: Vec<(impl Into<String>, impl Into<String>)>) {
|
||||
let mapped: Vec<(String, String)> = items
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.into(), v.into()))
|
||||
.collect();
|
||||
self.inner.set_footer_hint_override(Some(mapped));
|
||||
}
|
||||
|
||||
/// Clear any previously set custom hint items and restore the default hints.
|
||||
pub fn clear_hint_items(&mut self) {
|
||||
self.inner.set_footer_hint_override(None);
|
||||
}
|
||||
|
||||
/// Desired height (in rows) for a given width.
|
||||
pub fn desired_height(&self, width: u16) -> u16 {
|
||||
self.inner.desired_height(width)
|
||||
}
|
||||
|
||||
/// Compute the on-screen cursor position for the given area.
|
||||
pub fn cursor_pos(&self, area: Rect) -> Option<(u16, u16)> {
|
||||
self.inner.cursor_pos(area)
|
||||
}
|
||||
|
||||
/// Render the input into the provided buffer at `area`.
|
||||
pub fn render_ref(&self, area: Rect, buf: &mut Buffer) {
|
||||
self.inner.render(area, buf);
|
||||
}
|
||||
|
||||
/// Return true if a paste-burst detection is currently active.
|
||||
pub fn is_in_paste_burst(&self) -> bool {
|
||||
self.inner.is_in_paste_burst()
|
||||
}
|
||||
|
||||
/// Flush a pending paste-burst if the inter-key timeout has elapsed.
|
||||
/// Returns true if text changed and a redraw is warranted.
|
||||
pub fn flush_paste_burst_if_due(&mut self) -> bool {
|
||||
let flushed = self.inner.flush_paste_burst_if_due();
|
||||
self.drain_app_events();
|
||||
flushed
|
||||
}
|
||||
|
||||
/// Recommended delay to schedule the next micro-flush frame while a
|
||||
/// paste-burst is active.
|
||||
pub fn recommended_flush_delay() -> Duration {
|
||||
crate::bottom_pane::ChatComposer::recommended_paste_flush_delay()
|
||||
}
|
||||
|
||||
fn drain_app_events(&mut self) {
|
||||
while self.rx.try_recv().is_ok() {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ComposerInput {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
1
codex-rs/tui2/src/public_widgets/mod.rs
Normal file
1
codex-rs/tui2/src/public_widgets/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod composer_input;
|
||||
Reference in New Issue
Block a user