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
2 changes: 1 addition & 1 deletion peri-tui/locales/en/main.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ statusbar-permission-accept-edit = Accept Edit
statusbar-permission-auto = Auto Mode
statusbar-permission-bypass = Bypass
statusbar-permission-cycle-hint = (Shift+Tab to cycle)
statusbar-copied = { $count } chars copied
statusbar-copied = Copied { $count } chars to clipboard
statusbar-no-agent = None
statusbar-bg-indicator = [BG: { $count }]
statusbar-retrying = Retry { $attempt }/{ $max } ({ $delay }s): { $error }
Expand Down
31 changes: 24 additions & 7 deletions peri-tui/src/event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -718,14 +718,31 @@ async fn handle_event(app: &mut App, ev: Event) -> Result<Option<Action>> {
}
if app.session_mgr.current_mut().ui.text_selection.dragging {
if let Some(area) = app.session_mgr.current_mut().ui.messages_area {
let visual_row = usize::from(mouse.row.saturating_sub(area.y))
+ app.session_mgr.current_mut().ui.scroll_offset;
// Auto-scroll when dragging past viewport boundary
// Speed scales with distance from viewport edge (1-5 lines per event)
let ui = &mut app.session_mgr.current_mut().ui;
let area_bottom = area.y + area.height;
if mouse.row >= area_bottom {
let distance = (mouse.row - area_bottom) as u32;
let step = (1 + distance / 2).min(5) as usize;
let max_scroll = ui.scrollbar_max_offset;
let min_scroll = ui.scrollbar_min_offset.min(max_scroll);
let next = ui.scroll_offset.saturating_add(step).min(max_scroll);
ui.scroll_offset = next.max(min_scroll);
ui.scroll_follow = next >= max_scroll;
} else if mouse.row < area.y {
let distance = (area.y - mouse.row) as u32;
let step = (1 + distance / 2).min(5) as usize;
let max_scroll = ui.scrollbar_max_offset;
let min_scroll = ui.scrollbar_min_offset.min(max_scroll);
ui.scroll_offset = ui.scroll_offset.saturating_sub(step).max(min_scroll);
ui.scroll_follow = false;
}
let scroll_offset = ui.scroll_offset;
let visual_row =
usize::from(mouse.row.saturating_sub(area.y)) + scroll_offset;
let visual_col = mouse.column.saturating_sub(area.x);
app.session_mgr
.current_mut()
.ui
.text_selection
.update_drag(visual_row, visual_col);
ui.text_selection.update_drag(visual_row, visual_col);
}
}
// Textarea area: extend textarea selection
Expand Down
36 changes: 36 additions & 0 deletions peri-tui/src/ui/main_ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,42 @@ fn render_session_column(f: &mut Frame, app: &mut App, area: Rect) {
.split(area);

message_area::render_messages(f, app, chunks[0], chunks[1]);

// 复制成功浮动提示:消息区右下角,紧贴输入框上方(对齐 Claude Code)
if let Some(until) = app.session_mgr.current().ui.copy_message_until {
if std::time::Instant::now() < until {
let lc = &app.services.lc;
let count = app.session_mgr.current().ui.copy_char_count;
let text = format!(
" {} ",
lc.tr_args("statusbar-copied", &[("count".into(), (count as i64).into())])
);
let text_width = unicode_width::UnicodeWidthStr::width(text.as_str());
let msg_area = chunks[1];
if msg_area.height > 0 && text_width > 0 {
// scrollbar 占据最右 1 列,toast 需左移避让
let has_scrollbar = {
let cache = app.session_mgr.current().messages.render_cache.read();
cache.total_lines > msg_area.height as usize && msg_area.width > 1
};
let scrollbar_col: u16 = if has_scrollbar { 1 } else { 0 };
let y = msg_area.y + msg_area.height - 1;
let avail_width = msg_area.width.saturating_sub(scrollbar_col);
let x = (msg_area.x + avail_width).saturating_sub(text_width as u16);
let label_area = Rect {
x,
y,
width: text_width.min(avail_width as usize) as u16,
height: 1,
};
f.render_widget(
Paragraph::new(text).style(Style::default().fg(Color::Rgb(182, 186, 233))),
label_area,
);
}
}
}

attachment::render_attachment_bar(f, app, chunks[2]);

// 底部展开区
Expand Down
21 changes: 1 addition & 20 deletions peri-tui/src/ui/main_ui/status_bar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,26 +268,7 @@ fn render_third_row(f: &mut Frame, app: &App, area: Rect) {
left_spans.push(Span::styled(hint, Style::default().fg(theme::DIM)));
}

// 瞬时状态
// 复制成功提示
if let Some(until) = app.session_mgr.current().ui.copy_message_until {
if std::time::Instant::now() < until {
if has_content {
left_spans.push(Span::styled(" · ", Style::default().fg(theme::MUTED)));
}
let count = app.session_mgr.current().ui.copy_char_count;
left_spans.push(Span::styled(
format!(
" {}",
lc.tr_args(
"statusbar-copied",
&[("count".into(), (count as i64).into()),]
)
),
Style::default().fg(theme::MUTED),
));
}
}
// 瞬时状态(复制提示已移至消息区右下角浮动显示)

// 后台任务指示器
if !app.session_mgr.current().background_agents.is_empty() {
Expand Down
Loading