Skip to content
Merged
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
1 change: 1 addition & 0 deletions .github/AUTHOR_MAP
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Duducoco = Duducoco <69681789+Duducoco@users.noreply.github.com>
cyq1017 = cyq1017 <61975706+cyq1017@users.noreply.github.com>
cyq = cyq1017 <61975706+cyq1017@users.noreply.github.com>
15000851237@163.com = cyq1017 <61975706+cyq1017@users.noreply.github.com>
cy2311 = CY <29836092+cy2311@users.noreply.github.com>
zlh124 = zlh124 <56312993+zlh124@users.noreply.github.com>
LeoLin990405 = LeoLin990405 <101193087+LeoLin990405@users.noreply.github.com>
THINKER-ONLY = THINKER-ONLY <181556007+THINKER-ONLY@users.noreply.github.com>
Expand Down
443 changes: 443 additions & 0 deletions crates/tui/locales/zh-Hans.json

Large diffs are not rendered by default.

585 changes: 37 additions & 548 deletions crates/tui/src/localization.rs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions crates/tui/src/tui/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3511,7 +3511,7 @@ impl App {
.find(|detail| self.tool_cells.get(&detail.tool_id).copied() == Some(index))
}

/// Whether a virtual transcript cell can open a meaningful Alt+V detail
/// Whether a virtual transcript cell can open a meaningful `v` detail
/// view. Thinking cells render their own raw text inline so there is no
/// separate "raw" target — only tool / sub-agent cells get the hint.
#[must_use]
Expand All @@ -3524,7 +3524,7 @@ impl App {
}

/// Pick the detail target for the current viewport. This is used by the
/// transcript highlight and footer hint so they agree with Alt+V.
/// transcript highlight and footer hint so they agree with `v`.
#[must_use]
pub fn detail_cell_index_for_viewport(
&self,
Expand Down
2 changes: 1 addition & 1 deletion crates/tui/src/tui/context_inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ fn push_tools(out: &mut String, app: &App, locale: Locale) {
if rendered == 0 {
let _ = writeln!(out, "- {}", tr(locale, MessageId::CtxInspNoToolActivity));
} else {
let _ = writeln!(out, "- {}", tr(locale, MessageId::CtxInspAltVHint));
let _ = writeln!(out, "- {}", tr(locale, MessageId::CtxInspVHint));
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/tui/src/tui/history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1416,7 +1416,7 @@ impl GenericToolCell {
// `checklist_update` always do on a successful match — render
// only the changed item plus a `M/N · pct%` summary instead of
// dumping the full list every time. The full list is still
// reachable via Alt+V on the tool detail record. This keeps the
// reachable via `v` on the tool detail record. This keeps the
// transcript scannable in long sessions.
if matches!(mode, RenderMode::Live)
&& let Some(change) = parse_update_prefix(output)
Expand Down
2 changes: 1 addition & 1 deletion crates/tui/src/tui/history/tool_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl ToolRunActivitySummary {
///
/// Failed, running, patch, review, diff, and plan-update cells split runs so
/// important state never disappears into a summary row. Successful command
/// cells can join dense runs; Alt+V / expansion keeps their raw details
/// cells can join dense runs; `v` / expansion keeps their raw details
/// available without making routine verifier/shell work dominate the default
/// transcript.
pub fn detect_tool_runs(history: &[HistoryCell], min_size: usize) -> Vec<ToolRun> {
Expand Down
12 changes: 4 additions & 8 deletions crates/tui/src/tui/key_shortcuts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
//!
//! These helpers normalise the cross-platform variations between
//! `Ctrl+…` (Linux/Windows) and `Cmd+…` (macOS), legacy `Ctrl+H`-as-
//! backspace handling, and the macOS Option-Latin-character escapes
//! (`Option+V` produces `\u{221A}` instead of `v`). Centralising them
//! backspace handling, and the macOS Option-Latin-character escapes.
//! Centralising them
//! keeps the composer / transcript event loops in `ui.rs` short and
//! lets us add a new platform without touching the call sites.

Expand Down Expand Up @@ -57,11 +57,7 @@ pub(super) fn is_file_tree_toggle_shortcut(key: &KeyEvent) -> bool {
}

pub(super) fn tool_details_shortcut_label() -> &'static str {
if cfg!(target_os = "macos") {
"Option+V"
} else {
"Alt+V"
}
"v"
}

pub(super) fn tool_details_shortcut_action_hint(noun: &str) -> String {
Expand All @@ -73,7 +69,7 @@ pub(super) fn activity_shortcut_label() -> &'static str {
}

/// Modifier predicate for the v0.8.30 family of `Alt+<key>` transcript-
/// nav shortcuts (`Alt+G` / `Alt+[` / `Alt+]` / `Alt+?` / `Alt+L` / `Alt+V`). Requires
/// nav shortcuts (`Alt+G` / `Alt+[` / `Alt+]` / `Alt+?` / `Alt+L`). Requires
/// `Alt` and disallows `Ctrl` / `Super` so the
/// bindings don't collide with platform clipboard / window-management
/// shortcuts. `Shift` is permitted so the capital-letter forms work on
Expand Down
19 changes: 13 additions & 6 deletions crates/tui/src/tui/keybindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,8 @@ pub const KEYBINDINGS: &[KeybindingEntry] = &[
section: KeybindingSection::Submission,
},
KeybindingEntry {
chord: "Alt+V",
description_id: crate::localization::MessageId::KbToolDetailsPager,
chord: "v",
description_id: crate::localization::MessageId::KbSelectedDetails,
section: KeybindingSection::Submission,
},
KeybindingEntry {
Expand Down Expand Up @@ -365,16 +365,23 @@ mod tests {
}

#[test]
fn tool_details_help_documents_alt_v_without_bare_v() {
let details = KEYBINDINGS
fn tool_details_help_documents_bare_v_without_alt_v() {
let selected_details = KEYBINDINGS
.iter()
.filter(|entry| {
entry.description_id == crate::localization::MessageId::KbToolDetailsPager
entry.description_id == crate::localization::MessageId::KbSelectedDetails
})
.map(|entry| entry.chord)
.collect::<Vec<_>>();

assert_eq!(details, vec!["Alt+V"]);
assert_eq!(selected_details, vec!["v"]);
let legacy_modified_details_chord = ["Alt", "V"].join("+");
assert!(
KEYBINDINGS
.iter()
.all(|entry| entry.chord != legacy_modified_details_chord),
"help should advertise the bare v details shortcut"
);
}

#[test]
Expand Down
32 changes: 19 additions & 13 deletions crates/tui/src/tui/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3964,11 +3964,17 @@ async fn run_event_loop(
{
continue;
}
// Bare `v` / `V` no longer opens the tool-details pager — that
// path is owned exclusively by `Alt+V` at the lower arm, so
// the letter `v` is freely usable as the first character of
// a message. `details_shortcut_modifiers` previously allowed
// empty/Shift here, eating the keystroke on empty composers.
// This detail shortcut intentionally precedes vim-normal-mode
// handling: visual selection has no useful empty-composer
// target, while selected tool cards do.
KeyCode::Char('v')
if key.modifiers == KeyModifiers::NONE
&& app.input.is_empty()
&& detail_target_cell_index(app).is_some() =>
{
open_tool_details_pager(app);
continue;
}
KeyCode::Char('o')
if key.modifiers.contains(KeyModifiers::CONTROL)
&& app.input.is_empty()
Expand Down Expand Up @@ -4407,12 +4413,12 @@ async fn run_event_loop(
KeyCode::BackTab => {
app.cycle_effort();
}
// Transcript-nav shortcuts now require Alt, leaving the bare
// Transcript-nav shortcuts now require Alt, leaving most bare
// letters free to insert as text. Before v0.8.30, bare `g`,
// `G`, `[`, `]`, `?`, `l`, and `v` on an empty composer were
// `G`, `[`, `]`, `?`, and `l` on an empty composer were
// hijacked for navigation — typing "good" yielded "ood" with
// no whale and no warning. The Alt-prefixed shortcuts mirror
// the Alt+R / Alt+V / Alt+C pattern already in use. Shift is
// the Alt+R / Alt+C pattern already in use. Shift is
// permitted for most capital-letter forms.
KeyCode::Char('g')
if key_shortcuts::alt_nav_modifiers(key.modifiers)
Expand Down Expand Up @@ -10493,7 +10499,7 @@ fn open_thinking_pager(app: &mut App) -> bool {
/// then a live activity in the current turn, then the most recent meaningful
/// activity across history + active cells. Tool activity is intentionally
/// rendered through the compact live view so Activity Detail does not become
/// an accidental raw-output dump; Alt+V remains the direct full tool-detail
/// an accidental raw-output dump; `v` remains the direct full tool-detail
/// surface.
fn open_activity_detail_pager(app: &mut App) -> bool {
let Some(idx) = activity_target_cell_index(app) else {
Expand Down Expand Up @@ -10924,19 +10930,19 @@ fn activity_detail_handle_line(app: &App, cell_index: usize, cell: &HistoryCell)
.find(|artifact| artifact.tool_call_id == detail.tool_id)
{
return Some(format!(
"Detail handle: {} (retrieve_tool_result ref={}; Alt+V raw details)",
"Detail handle: {} (retrieve_tool_result ref={}; v raw details)",
artifact.id, artifact.id
));
}
return Some(format!(
"Detail handle: tool:{} (Alt+V raw details)",
"Detail handle: tool:{} (v raw details)",
detail.tool_id
));
}

match cell {
HistoryCell::Tool(_) => Some("Detail handle: Alt+V details".to_string()),
HistoryCell::SubAgent(_) => Some("Detail handle: Alt+V details".to_string()),
HistoryCell::Tool(_) => Some("Detail handle: v details".to_string()),
HistoryCell::SubAgent(_) => Some("Detail handle: v details".to_string()),
_ => None,
}
}
Expand Down
8 changes: 4 additions & 4 deletions crates/tui/src/tui/ui/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8719,8 +8719,8 @@ fn activity_detail_includes_tool_handle_and_neighbor_context() {
body.contains("retrieve_tool_result ref=art_call-read"),
"{body}"
);
assert!(body.contains("Alt+V"), "{body}");
assert!(body.contains("raw details"), "{body}");
assert!(body.contains("v raw"), "{body}");
assert!(body.contains("details)"), "{body}");
}

#[test]
Expand Down Expand Up @@ -8777,9 +8777,9 @@ fn activity_detail_fallback_uses_recent_meaningful_activity_without_full_tool_du

assert!(body.contains("Activity: read"));
assert!(body.contains("Status: done"));
assert!(body.contains("Detail handle: Alt+V details"), "{body}");
assert!(body.contains("Detail handle: v details"), "{body}");
assert!(
!body.contains("Detail handle: Alt+V raw details"),
!body.contains("Detail handle: v raw details"),
"fallback tool details should not be labeled raw: {body}"
);
assert!(
Expand Down
Loading