WIP
This commit is contained in:
parent
638bb6db8e
commit
7b2bfa77cf
@ -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.
|
||||||
|
|||||||
@ -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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user