fix: surface rejected configuration in a floating startup diagnostic
This commit is contained in:
+111
-81
@@ -29,7 +29,7 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use crate::{
|
||||
editor::{Editor, Hover, Input, Mode, Palette},
|
||||
editor::{Editor, Hover, Input, Mode, Palette, StartupDiagnostic},
|
||||
files::{DockSide, FilePicker, FilePresentation, FileView},
|
||||
plugin::{Diagnostic, DiagnosticSeverity},
|
||||
session::EditorSession,
|
||||
@@ -605,18 +605,7 @@ fn draw(
|
||||
}
|
||||
if let Some(picker) = editor.file_picker() {
|
||||
if picker.presentation == FilePresentation::Floating {
|
||||
let [_, column, _] = Layout::horizontal([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(area.width.min(100)),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.areas(area);
|
||||
let [_, panel, _] = Layout::vertical([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(area.height.min(24)),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.areas(column);
|
||||
let panel = floating_panel(area);
|
||||
frame.render_widget(Clear, panel);
|
||||
draw_file_list(frame, picker, panel, editor.file_navigation_hint());
|
||||
} else if let Some(panel) = dock {
|
||||
@@ -634,6 +623,71 @@ fn draw(
|
||||
if let Some(hover) = editor.hover() {
|
||||
draw_hover(frame, hover, viewport);
|
||||
}
|
||||
if let Some(diagnostic) = editor.startup_diagnostic() {
|
||||
draw_startup_diagnostic(frame, diagnostic, area);
|
||||
}
|
||||
}
|
||||
|
||||
fn floating_panel(area: Rect) -> Rect {
|
||||
let [_, column, _] = Layout::horizontal([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(area.width.min(100)),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.areas(area);
|
||||
let [_, panel, _] = Layout::vertical([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(area.height.min(24)),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.areas(column);
|
||||
panel
|
||||
}
|
||||
|
||||
fn draw_startup_diagnostic(frame: &mut Frame, diagnostic: &StartupDiagnostic, area: Rect) {
|
||||
let panel = floating_panel(area);
|
||||
frame.render_widget(Clear, panel);
|
||||
let bordered = panel.width >= 4 && panel.height >= 4;
|
||||
let block = Block::default()
|
||||
.borders(if bordered {
|
||||
Borders::ALL
|
||||
} else {
|
||||
Borders::NONE
|
||||
})
|
||||
.border_style(Style::default().fg(Color::Red))
|
||||
.title(" Configuration error ");
|
||||
let content = if bordered { block.inner(panel) } else { panel };
|
||||
if bordered {
|
||||
frame.render_widget(block, panel);
|
||||
}
|
||||
let [text_area, help_area] = Layout::vertical([
|
||||
Constraint::Fill(1),
|
||||
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();
|
||||
frame.render_widget(Paragraph::new(lines), text_area);
|
||||
frame.render_widget(
|
||||
Paragraph::new("Arrows scroll · Home reset · Enter/Esc continue")
|
||||
.style(Style::default().fg(Color::DarkGray)),
|
||||
help_area,
|
||||
);
|
||||
if text_area.width > 0 && text_area.height > 0 {
|
||||
frame.set_cursor_position((text_area.x, text_area.y));
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_hover(frame: &mut Frame, hover: &Hover, area: Rect) {
|
||||
@@ -1746,74 +1800,6 @@ end
|
||||
assert_eq!(viewports.syntax.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn highlighted_editor_text_stays_out_of_docked_and_floating_picker_surfaces() {
|
||||
let directory = Directory::new();
|
||||
let path = directory.file("panels.rs", &vec!["// note"; 30].join("\n"));
|
||||
let area = Rect::new(3, 2, 100, 24);
|
||||
for (name, side) in [
|
||||
("left", Some(DockSide::Left)),
|
||||
("right", Some(DockSide::Right)),
|
||||
("top", Some(DockSide::Top)),
|
||||
("bottom", Some(DockSide::Bottom)),
|
||||
("floating", None),
|
||||
] {
|
||||
let mut editor = Editor::open(Some(path.clone()), vec![]).unwrap();
|
||||
if side.is_some() {
|
||||
editor.set_file_explorer_side(name).unwrap();
|
||||
}
|
||||
editor.handle(Input::Char(' '));
|
||||
editor.handle(Input::Char(if side.is_some() { 'e' } else { 'o' }));
|
||||
let mut terminal = Terminal::with_options(
|
||||
ratatui::backend::TestBackend::new(110, 30),
|
||||
ratatui::TerminalOptions {
|
||||
viewport: ratatui::Viewport::Fixed(area),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let mut viewports = BufferViewports::default();
|
||||
terminal
|
||||
.draw(|frame| viewports.draw(frame, &editor))
|
||||
.unwrap();
|
||||
let workspace = Rect::new(area.x, area.y, area.width, area.height - 2);
|
||||
let (text, panel) = if let Some(side) = side {
|
||||
let (text, panel) = dock_layout(workspace, side, true);
|
||||
(text, panel.unwrap())
|
||||
} else {
|
||||
(workspace, Rect::new(area.x + 8, area.y + 3, 84, 18))
|
||||
};
|
||||
let mut expected = Terminal::with_options(
|
||||
ratatui::backend::TestBackend::new(110, 30),
|
||||
ratatui::TerminalOptions {
|
||||
viewport: ratatui::Viewport::Fixed(panel),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
expected
|
||||
.draw(|frame| {
|
||||
draw_file_list(
|
||||
frame,
|
||||
editor.file_picker().unwrap(),
|
||||
panel,
|
||||
editor.file_navigation_hint(),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
let buffer = terminal.backend().buffer();
|
||||
let expected = expected.backend().buffer();
|
||||
for y in panel.y..panel.bottom() {
|
||||
for x in panel.x..panel.right() {
|
||||
assert_eq!(buffer[(x, y)], expected[(x, y)], "{name}: {x},{y}");
|
||||
}
|
||||
}
|
||||
assert_eq!(buffer[(text.x + 3, text.y)].symbol(), "/");
|
||||
assert_eq!(buffer[(text.x + 3, text.y)].fg, Color::DarkGray);
|
||||
assert_eq!(buffer[(text.x, text.y)].fg, Color::Cyan);
|
||||
assert_eq!(buffer[(area.x, area.bottom() - 2)].bg, Color::Cyan);
|
||||
assert_eq!(buffer[(0, 0)].fg, Color::Reset);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn translate_distinguishes_control_j_from_enter_and_normalizes_control_letters() {
|
||||
for (code, modifiers, expected) in [
|
||||
@@ -2784,6 +2770,50 @@ end
|
||||
assert_eq!(buffer[(0, 0)].symbol(), " ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn startup_diagnostic_scrolls_long_unicode_reasons_and_dismisses_without_editing() {
|
||||
let directory = Directory::new();
|
||||
let source = directory.file("buffer.txt", "keep");
|
||||
let config = directory.file("config.rb", "raise \"#{'x' * 160}界END\\nlast reason\"");
|
||||
let mut session =
|
||||
EditorSession::open(Some(source), vec!["text".into()], Some(&config)).unwrap();
|
||||
let mut terminal = Terminal::new(ratatui::backend::TestBackend::new(110, 26)).unwrap();
|
||||
let mut viewports = BufferViewports::default();
|
||||
terminal
|
||||
.draw(|frame| viewports.draw(frame, session.editor()))
|
||||
.unwrap();
|
||||
let text = screen_text(&terminal);
|
||||
assert!(text.contains("Configuration error"));
|
||||
assert!(text.contains("config.rb"));
|
||||
assert!(text.contains("default settings and bindings"));
|
||||
assert!(text.contains("last reason"));
|
||||
assert!(!text.contains("界END"));
|
||||
for _ in 0..100 {
|
||||
session.handle(Input::Right);
|
||||
}
|
||||
terminal
|
||||
.draw(|frame| viewports.draw(frame, session.editor()))
|
||||
.unwrap();
|
||||
let scrolled = screen_text(&terminal);
|
||||
assert!(
|
||||
scrolled.contains("界") && scrolled.contains("END"),
|
||||
"{scrolled}"
|
||||
);
|
||||
for (width, height) in [(4, 4), (1, 1)] {
|
||||
let mut tiny =
|
||||
Terminal::new(ratatui::backend::TestBackend::new(width, height)).unwrap();
|
||||
tiny.draw(|frame| viewports.draw(frame, session.editor()))
|
||||
.unwrap();
|
||||
}
|
||||
session.handle(Input::Enter);
|
||||
terminal
|
||||
.draw(|frame| viewports.draw(frame, session.editor()))
|
||||
.unwrap();
|
||||
assert!(!screen_text(&terminal).contains("Configuration error"));
|
||||
assert_eq!(session.editor().lines(), &["keep"]);
|
||||
assert_eq!(session.editor().cursor(), crate::editor::Cursor::default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn picker_conversion_focus_palette_and_closure_preserve_buffer_viewport_cache() {
|
||||
let directory = Directory::new();
|
||||
|
||||
Reference in New Issue
Block a user