feat: toggle wrapping in shell output windows

This commit is contained in:
2026-10-18 01:23:19 +02:00
parent 00207b5526
commit 074df97c02
4 changed files with 125 additions and 23 deletions
+53 -18
View File
@@ -2906,7 +2906,7 @@ fn draw_overlays(
draw_startup_diagnostic(frame, diagnostic, area);
}
if let Some(output) = editor.command_output() {
draw_diagnostic_panel(frame, &output.content, area, &output.title, false);
draw_diagnostic_panel(frame, &output.content, area, &output.title, Some(output));
}
}
@@ -4631,7 +4631,7 @@ fn floating_panel(area: Rect) -> Rect {
}
fn draw_startup_diagnostic(frame: &mut Frame, diagnostic: &StartupDiagnostic, area: Rect) {
draw_diagnostic_panel(frame, diagnostic, area, "Configuration error", true);
draw_diagnostic_panel(frame, diagnostic, area, "Configuration error", None);
}
fn draw_diagnostic_panel(
@@ -4639,8 +4639,9 @@ fn draw_diagnostic_panel(
diagnostic: &StartupDiagnostic,
area: Rect,
title: &str,
startup: bool,
output: Option<&crate::editor::ShellOutput>,
) {
let startup = output.is_none();
let panel = floating_panel(area);
frame.render_widget(Clear, panel);
let bordered = panel.width >= 4 && panel.height >= 4;
@@ -4661,26 +4662,60 @@ fn draw_diagnostic_panel(
Constraint::Length(u16::from(content.height >= 3)),
])
.areas(content);
let lines: Vec<Line> = diagnostic
.lines
.iter()
.skip(diagnostic.top)
.take(usize::from(text_area.height))
.map(|line| {
let line = display_text(line);
Line::from(visible_line(
&line,
display_column(&line, diagnostic.left),
usize::from(text_area.width),
))
})
.collect();
let lines: Vec<Line> = if let Some(output) = output.filter(|output| output.wrapping) {
let width = usize::from(text_area.width).max(1);
let mut cached = output.wrapped_lines.borrow_mut();
if cached.0 != width {
let mut cache = crate::wrap::WrapCache::default();
cache.prepare((0, 0), width);
cached.1.clear();
for (row, line) in diagnostic.lines.iter().enumerate() {
let segments = cache.segments(row, line);
for (index, segment) in segments.iter().enumerate() {
// Output has no insertion caret: omit its extra empty continuation.
if index == 0 || segment.start != segment.end {
cached.1.push((row, *segment));
}
}
}
cached.0 = width;
}
output.wrapped_rows.set(cached.1.len());
cached
.1
.iter()
.skip(diagnostic.top.min(cached.1.len().saturating_sub(1)))
.take(usize::from(text_area.height))
.map(|(row, segment)| {
Line::from(visible_line(
&diagnostic.lines[*row],
segment.start,
(segment.end - segment.start).min(width),
))
})
.collect()
} else {
diagnostic
.lines
.iter()
.skip(diagnostic.top)
.take(usize::from(text_area.height))
.map(|line| {
let line = display_text(line);
Line::from(visible_line(
&line,
display_column(&line, diagnostic.left),
usize::from(text_area.width),
))
})
.collect()
};
frame.render_widget(Paragraph::new(lines), text_area);
frame.render_widget(
Paragraph::new(if startup {
"Arrows scroll · Home reset · Enter/Esc continue"
} else {
"Arrows scroll · Home reset · Enter/Esc close"
"w wrap · Arrows scroll · Home reset · Enter/Esc close"
})
.style(Style::default().fg(Color::DarkGray)),
help_area,