diff --git a/.github/workflows/issue-code.yml b/.github/workflows/issue-code.yml index e4f8b28e139..11bb2cf484d 100644 --- a/.github/workflows/issue-code.yml +++ b/.github/workflows/issue-code.yml @@ -148,10 +148,10 @@ jobs: install -m 0755 "$HOME/.local/tools/jq-1.7.1/jq" "$HOME/.local/bin/jq" jq --version - - name: Setup Rust toolchain (1.89) + - name: Setup Rust toolchain (1.90) uses: dtolnay/rust-toolchain@master with: - toolchain: 1.89.0 + toolchain: 1.90.0 - name: Cache Rust build (cargo + target) uses: Swatinem/rust-cache@v2 diff --git a/.github/workflows/preview-build.yml b/.github/workflows/preview-build.yml index 378983c1c53..c2756008f6c 100644 --- a/.github/workflows/preview-build.yml +++ b/.github/workflows/preview-build.yml @@ -64,14 +64,15 @@ jobs: shell: bash run: | rustup set profile minimal - rustup toolchain install 1.89.0 --profile minimal --target ${{ matrix.target }} - rustup default 1.89.0 + rustup toolchain install 1.90.0 --profile minimal + rustup default 1.90.0 + rustup target add ${{ matrix.target }} - name: Rust cache (target + registries) uses: Swatinem/rust-cache@v2 with: prefix-key: v1-preview - shared-key: preview-${{ matrix.target }}-rust-1.89 + shared-key: preview-${{ matrix.target }}-rust-1.90 workspaces: | code-rs -> target codex-rs -> target diff --git a/.github/workflows/upstream-merge.yml b/.github/workflows/upstream-merge.yml index 0c99c908f2e..54f563c6b68 100644 --- a/.github/workflows/upstream-merge.yml +++ b/.github/workflows/upstream-merge.yml @@ -254,7 +254,7 @@ jobs: if: steps.check_upstream.outputs.skip != 'true' uses: dtolnay/rust-toolchain@master with: - toolchain: 1.89.0 + toolchain: 1.90.0 - name: Add local bin to PATH if: steps.check_upstream.outputs.skip != 'true' diff --git a/code-rs/Cargo.lock b/code-rs/Cargo.lock index d15926efcd1..939c4b27c4b 100644 --- a/code-rs/Cargo.lock +++ b/code-rs/Cargo.lock @@ -1240,6 +1240,7 @@ dependencies = [ "tokio-stream", "tracing", "tracing-subscriber", + "unicode-segmentation", "unicode-width 0.1.14", ] diff --git a/code-rs/cloud-tasks/Cargo.toml b/code-rs/cloud-tasks/Cargo.toml index 773c1e7ed4a..11d9c3aaf35 100644 --- a/code-rs/cloud-tasks/Cargo.toml +++ b/code-rs/cloud-tasks/Cargo.toml @@ -30,6 +30,7 @@ serde_json = "1" reqwest = { version = "0.12", features = ["json"] } serde = { version = "1", features = ["derive"] } unicode-width = "0.1" +unicode-segmentation = "1.12" code-tui = { path = "../tui" } [dev-dependencies] diff --git a/code-rs/cloud-tasks/src/lib.rs b/code-rs/cloud-tasks/src/lib.rs index 15d244137a7..ed1c5476a0e 100644 --- a/code-rs/cloud-tasks/src/lib.rs +++ b/code-rs/cloud-tasks/src/lib.rs @@ -12,6 +12,7 @@ use std::path::PathBuf; use std::sync::Arc; use std::time::Duration; use std::time::Instant; +use unicode_segmentation::UnicodeSegmentation; use tokio::sync::mpsc::UnboundedSender; use tracing::info; use tracing_subscriber::EnvFilter; @@ -1202,7 +1203,16 @@ pub async fn run_main(cli: Cli, _code_linux_sandbox_exe: Option) -> any if let Some(m) = app.env_modal.as_mut() { m.query.push(ch); } needs_redraw = true; } - KeyCode::Backspace => { if let Some(m) = app.env_modal.as_mut() { m.query.pop(); } needs_redraw = true; } + KeyCode::Backspace => { + if let Some(m) = app.env_modal.as_mut() { + if let Some((idx, _)) = m.query.grapheme_indices(true).last() { + m.query.truncate(idx); + } else { + m.query.clear(); + } + } + needs_redraw = true; + } KeyCode::Down | KeyCode::Char('j') => { if let Some(m) = app.env_modal.as_mut() { m.selected = m.selected.saturating_add(1); } needs_redraw = true; } KeyCode::Up | KeyCode::Char('k') => { if let Some(m) = app.env_modal.as_mut() { m.selected = m.selected.saturating_sub(1); } needs_redraw = true; } KeyCode::Home => { if let Some(m) = app.env_modal.as_mut() { m.selected = 0; } needs_redraw = true; } diff --git a/code-rs/tui/src/app.rs b/code-rs/tui/src/app.rs index 83a1c9be81b..0d30a8f706a 100644 --- a/code-rs/tui/src/app.rs +++ b/code-rs/tui/src/app.rs @@ -1222,6 +1222,24 @@ impl App<'_> { } AppEvent::KeyEvent(mut key_event) => { if self.timing_enabled { self.timing.on_key(); } + #[cfg(windows)] + { + use crossterm::event::KeyCode; + use crossterm::event::KeyEventKind; + if matches!(key_event.kind, KeyEventKind::Repeat) { + match key_event.code { + KeyCode::Left + | KeyCode::Right + | KeyCode::Up + | KeyCode::Down + | KeyCode::Home + | KeyCode::End + | KeyCode::Backspace + | KeyCode::Delete => {} + _ => continue, + } + } + } // On terminals without keyboard enhancement flags (notably some Windows // Git Bash/mintty setups), crossterm may emit duplicate key-up events or // only report releases. Track which keys were seen as pressed so matching diff --git a/code-rs/tui/src/bottom_pane/theme_selection_view.rs b/code-rs/tui/src/bottom_pane/theme_selection_view.rs index 21b3f34a7ae..cb659060715 100644 --- a/code-rs/tui/src/bottom_pane/theme_selection_view.rs +++ b/code-rs/tui/src/bottom_pane/theme_selection_view.rs @@ -4,6 +4,7 @@ use code_core::config_types::ThemeName; use crossterm::event::KeyCode; use crossterm::event::KeyEvent; use crossterm::event::KeyModifiers; +use unicode_segmentation::UnicodeSegmentation; use ratatui::buffer::Buffer; use ratatui::layout::Alignment; use ratatui::layout::Rect; @@ -1484,7 +1485,11 @@ impl ThemeSelectionView { } match s.step.get() { CreateStep::Prompt => { - s.prompt.pop(); + if let Some((idx, _)) = s.prompt.grapheme_indices(true).last() { + s.prompt.truncate(idx); + } else { + s.prompt.clear(); + } } CreateStep::Action | CreateStep::Review => { return; @@ -1496,7 +1501,11 @@ impl ThemeSelectionView { } match s.step.get() { CreateStep::Prompt => { - s.prompt.pop(); + if let Some((idx, _)) = s.prompt.grapheme_indices(true).last() { + s.prompt.truncate(idx); + } else { + s.prompt.clear(); + } } CreateStep::Action | CreateStep::Review => { return;