UI: the code field draws the equation editor's error mark again

The merge of main brought #471's code_editor_marked, whose mark was drawn by the
layouter inside the code editor; on this branch that layouter lives in code_field,
which had no mark, so the merge did not compile. FieldOptions gains mark (None by
default), code_editor_marked passes it, and code_field underlines it as before.

Test: the_marked_editor_underlines_its_mark (fails when the field ignores the mark).
This commit is contained in:
prxnvt
2026-11-02 10:46:17 -05:00
parent e9430daa9a
commit 9c6dbfdfab
2 changed files with 26 additions and 2 deletions
+5 -2
View File
@@ -583,7 +583,7 @@ pub fn code_editor_marked(ui: &mut Ui, id: egui::Id, text: &mut String, lang: La
let max_lines = max_lines.clamp(1, 200);
let mut response = None;
egui::Frame::new().fill(t.input_bg).stroke(egui::Stroke::new(1.0, t.input_border)).corner_radius(4.0).inner_margin(4.0).show(ui, |ui| {
let options = FieldOptions { max_height: row_h * max_lines as f32, ..FieldOptions::new(lang) };
let options = FieldOptions { max_height: row_h * max_lines as f32, mark: mark.clone(), ..FieldOptions::new(lang) };
response = Some(code_field(ui, id, text, &options).response);
});
response.unwrap_or_else(|| ui.allocate_response(egui::Vec2::ZERO, egui::Sense::hover()))
@@ -606,6 +606,8 @@ pub struct FieldOptions<'a> {
pub caret: Option<usize>,
/// The field's name for screen readers.
pub name: &'a str,
/// A byte range underlined in the error colour (see [`underline`]).
pub mark: Option<Range<usize>>,
}
impl FieldOptions<'_> {
@@ -621,6 +623,7 @@ impl FieldOptions<'_> {
// The editor is a generic code field, so the name is not part of the UI's translated
// strings unless the caller gives one.
name: "Code Editor",
mark: None,
}
}
}
@@ -685,7 +688,7 @@ pub fn code_field(ui: &mut Ui, id: egui::Id, text: &mut String, options: &FieldO
let danger = t.danger;
let mut layouter = |ui: &Ui, buf: &dyn egui::TextBuffer, wrap_width: f32| {
let mut job = layout_job(buf.as_str(), lang, &self::font(), plain, &syntax, wrap_width);
if let Some(m) = mark.clone() {
if let Some(m) = options.mark.clone() {
underline(&mut job, m, danger);
}
ui.fonts_mut(|f| f.layout_job(job))
+21
View File
@@ -459,3 +459,24 @@ fn a_repeat_pass_of_the_frame_counts_as_the_next_pass() {
h.run_steps(1);
assert_eq!(h.state().0, " a\n b");
}
/// Whether a frame drew text with an underline.
fn draws_underline(mark: Option<std::ops::Range<usize>>) -> bool {
let ctx = egui::Context::default();
let mut out = ctx.run_ui(egui::RawInput::default(), |ui| {
let mut text = String::from("x^{2");
code_editor_marked(ui, egui::Id::unique("marked"), &mut text, Lang::Latex, 3, mark.clone());
});
out.textures_delta.clear();
out.shapes.iter().any(|s| match &s.shape {
egui::Shape::Text(t) => t.galley.job.sections.iter().any(|sec| sec.format.underline.width > 0.0),
_ => false,
})
}
#[test]
fn the_marked_editor_underlines_its_mark() {
// The equation editor marks an error's position; the code field draws it.
assert!(draws_underline(Some(3..4)));
assert!(!draws_underline(None));
}