This commit is contained in:
Hassan Abedi 2026-03-23 10:13:10 +01:00
parent 638bb6db8e
commit 7b2bfa77cf
2 changed files with 79 additions and 36 deletions

View File

@ -19,7 +19,7 @@ Priorities, in order:
3. Focused, maintainable changes with good regression coverage. 3. Focused, maintainable changes with good regression coverage.
4. Performance only after correctness and testability are preserved. 4. Performance only after correctness and testability are preserved.
## Core Rules ## Core Rucargo run --features gui --bin geolog-guiles
- Use English for code, comments, docs, tests, and commit-facing text. - Use English for code, comments, docs, tests, and commit-facing text.
- Prefer small, targeted changes over broad rewrites. - Prefer small, targeted changes over broad rewrites.

View File

@ -53,12 +53,18 @@ impl EditorPanel {
fn show_editor_content(&mut self, ui: &mut egui::Ui, state: &mut GuiState) { fn show_editor_content(&mut self, ui: &mut egui::Ui, state: &mut GuiState) {
// Use a monospace font for code // Use a monospace font for code
let font_id = egui::FontId::monospace(14.0); let font_id = egui::FontId::monospace(14.0);
let mut layouter = |ui: &egui::Ui, text: &dyn egui::TextBuffer, wrap_width: f32| {
let mut layout_job = geolog_highlighter(ui, text.as_str(), wrap_width);
layout_job.wrap.max_width = wrap_width;
ui.fonts_mut(|fonts| fonts.layout_job(layout_job))
};
// Main editor area - simplified layout without line numbers column // Main editor area - simplified layout without line numbers column
// to avoid layout instability from horizontal split calculations // to avoid layout instability from horizontal split calculations
let text_edit = egui::TextEdit::multiline(&mut state.editor_content) let text_edit = egui::TextEdit::multiline(&mut state.editor_content)
.font(font_id) .font(font_id)
.code_editor() .code_editor()
.layouter(&mut layouter)
.desired_width(f32::INFINITY) .desired_width(f32::INFINITY)
.desired_rows(20) .desired_rows(20)
.lock_focus(true); .lock_focus(true);
@ -84,24 +90,42 @@ impl Default for EditorPanel {
} }
/// Simple syntax highlighting for Geolog code /// Simple syntax highlighting for Geolog code
/// Returns a layouter function for egui's code_editor fn geolog_highlighter(ui: &egui::Ui, text: &str, wrap_width: f32) -> egui::text::LayoutJob {
#[allow(dead_code)]
fn geolog_highlighter(
_ui: &egui::Ui,
text: &str,
_wrap_width: f32,
) -> egui::text::LayoutJob {
let mut job = egui::text::LayoutJob::default(); let mut job = egui::text::LayoutJob::default();
job.wrap.max_width = wrap_width;
let keywords = [ let keywords = [
"theory", "instance", "query", "forall", "exists", "Sort", "Prop", "true", "false", "namespace",
"theory",
"instance",
"query",
"forall",
"exists",
"chase",
"Sort",
"Prop",
"true",
"false",
]; ];
let font_id = egui::FontId::monospace(14.0); let font_id = egui::FontId::monospace(14.0);
let default_color = egui::Color32::WHITE; let default_format = egui::TextFormat::simple(font_id.clone(), ui.visuals().text_color());
let keyword_color = egui::Color32::from_rgb(86, 156, 214); // Blue let keyword_format = egui::TextFormat {
let comment_color = egui::Color32::from_rgb(106, 153, 85); // Green font_id: font_id.clone(),
let string_color = egui::Color32::from_rgb(206, 145, 120); // Orange color: egui::Color32::from_rgb(0, 92, 197),
..Default::default()
};
let comment_format = egui::TextFormat {
font_id: font_id.clone(),
color: egui::Color32::from_rgb(35, 110, 55),
italics: true,
..Default::default()
};
let string_format = egui::TextFormat {
font_id: font_id.clone(),
color: egui::Color32::from_rgb(145, 70, 15),
..Default::default()
};
let mut chars = text.char_indices().peekable(); let mut chars = text.char_indices().peekable();
@ -116,11 +140,7 @@ fn geolog_highlighter(
} }
} }
let end = chars.peek().map(|(i, _)| *i).unwrap_or(text.len()); let end = chars.peek().map(|(i, _)| *i).unwrap_or(text.len());
job.append( job.append(&text[start..end], 0.0, comment_format.clone());
&text[start..end],
0.0,
egui::TextFormat::simple(font_id.clone(), comment_color),
);
continue; continue;
} }
@ -136,11 +156,7 @@ fn geolog_highlighter(
} }
} }
let end = chars.peek().map(|(i, _)| *i).unwrap_or(text.len()); let end = chars.peek().map(|(i, _)| *i).unwrap_or(text.len());
job.append( job.append(&text[start..end], 0.0, string_format.clone());
&text[start..end],
0.0,
egui::TextFormat::simple(font_id.clone(), string_color),
);
continue; continue;
} }
@ -153,27 +169,54 @@ fn geolog_highlighter(
let end = chars.peek().map(|(i, _)| *i).unwrap_or(text.len()); let end = chars.peek().map(|(i, _)| *i).unwrap_or(text.len());
let word = &text[start..end]; let word = &text[start..end];
let color = if keywords.contains(&word) { let format = if keywords.contains(&word) {
keyword_color keyword_format.clone()
} else { } else {
default_color default_format.clone()
}; };
job.append( job.append(word, 0.0, format);
word,
0.0,
egui::TextFormat::simple(font_id.clone(), color),
);
continue; continue;
} }
// Default: single character // Default: single character
job.append( job.append(&text[i..i + c.len_utf8()], 0.0, default_format.clone());
&text[i..i + c.len_utf8()],
0.0,
egui::TextFormat::simple(font_id.clone(), default_color),
);
} }
job job
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn highlighter_marks_keywords_comments_and_strings() {
egui::__run_test_ui(|ui| {
let job = geolog_highlighter(
ui,
"theory Demo { // note\n label = \"hi\";\n}",
f32::INFINITY,
);
assert!(!job.sections.is_empty());
let has_keyword = job
.sections
.iter()
.any(|section| section.format.color == egui::Color32::from_rgb(0, 92, 197));
let has_comment = job
.sections
.iter()
.any(|section| section.format.color == egui::Color32::from_rgb(35, 110, 55));
let has_string = job
.sections
.iter()
.any(|section| section.format.color == egui::Color32::from_rgb(145, 70, 15));
assert!(has_keyword);
assert!(has_comment);
assert!(has_string);
});
}
}