diff --git a/src/main.rs b/src/main.rs index 3a12b70..fb4bd38 100644 --- a/src/main.rs +++ b/src/main.rs @@ -348,12 +348,18 @@ impl eframe::App for CompilerApp { }, AppTab::Trace => { let mut combined = self.trace_logs.join("\n"); + let mut layouter = |ui: &egui::Ui, buffer: &dyn egui::TextBuffer, _wrap_width: f32| { + let layout_job = highlight_myc(ui.ctx(), buffer.as_str()); + ui.painter().layout_job(layout_job) + }; + ui.add_sized( ui.available_size(), egui::TextEdit::multiline(&mut combined) .font(egui::TextStyle::Monospace) .desired_width(f32::INFINITY) .interactive(false) + .layouter(&mut layouter) ); } } @@ -387,15 +393,110 @@ impl eframe::App for CompilerApp { egui::ScrollArea::vertical() .id_salt("source_code_scroll") .show(ui, |ui| { + let mut layouter = |ui: &egui::Ui, buffer: &dyn egui::TextBuffer, _wrap_width: f32| { + let layout_job = highlight_myc(ui.ctx(), buffer.as_str()); + ui.painter().layout_job(layout_job) + }; + ui.add_sized( ui.available_size(), egui::TextEdit::multiline(&mut self.source_code) .id(editor_id) .font(egui::TextStyle::Monospace) .desired_width(f32::INFINITY) - .lock_focus(true), + .lock_focus(true) + .layouter(&mut layouter), ); }); }); } } + +fn highlight_myc(ctx: &egui::Context, code: &str) -> egui::text::LayoutJob { + let mut job = egui::text::LayoutJob::default(); + let theme = &ctx.style().visuals; + + let color_kw = egui::Color32::from_rgb(86, 156, 214); // Blue + let color_str = egui::Color32::from_rgb(206, 145, 120); // Orange/Brown + let color_num = egui::Color32::from_rgb(181, 206, 168); // Greenish + let color_comment = egui::Color32::from_rgb(106, 153, 85); // Green + let color_bracket = [ + egui::Color32::from_rgb(255, 215, 0), // Gold + egui::Color32::from_rgb(218, 112, 214), // Orchid + egui::Color32::from_rgb(24, 131, 215), // Blue + ]; + + let mut chars = code.chars().peekable(); + let mut bracket_depth = 0; + + while let Some(c) = chars.next() { + let mut text = String::from(c); + let mut color = theme.widgets.noninteractive.text_color(); + + match c { + ';' => { + while let Some(&next) = chars.peek() { + if next == '\n' { break; } + text.push(chars.next().unwrap()); + } + color = color_comment; + } + '"' => { + while let Some(next) = chars.next() { + text.push(next); + if next == '"' { break; } + if next == '\\' { + if let Some(escaped) = chars.next() { text.push(escaped); } + } + } + color = color_str; + } + ':' => { + while let Some(&next) = chars.peek() { + if next.is_whitespace() || "()[]{}".contains(next) { break; } + text.push(chars.next().unwrap()); + } + color = color_kw; + } + '(' | '[' | '{' => { + color = color_bracket[bracket_depth % 3]; + bracket_depth += 1; + } + ')' | ']' | '}' => { + if bracket_depth > 0 { bracket_depth -= 1; } + color = color_bracket[bracket_depth % 3]; + } + '0'..='9' => { + while let Some(&next) = chars.peek() { + if next.is_ascii_digit() || next == '.' { + text.push(chars.next().unwrap()); + } else { break; } + } + color = color_num; + } + _ if c.is_alphabetic() || "+-*/<=>!$%&_?.".contains(c) => { + while let Some(&next) = chars.peek() { + if next.is_alphanumeric() || "+-*/<=>!$%&_?.".contains(next) { + text.push(chars.next().unwrap()); + } else { break; } + } + if ["fn", "def", "do", "if", "assign", "recur", "cond"].contains(&text.as_str()) { + color = color_kw; + } + } + _ => {} + } + + job.append( + &text, + 0.0, + egui::TextFormat { + font_id: egui::FontId::monospace(14.0), + color, + ..Default::default() + }, + ); + } + + job +}