notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

commit c0d75293dde6fb1eaa47243313af2aed7ec3089e
parent 4467bf09202999078f23c100073ad357dfff6640
Author: William Casarin <jb55@jb55.com>
Date:   Mon, 16 Feb 2026 15:55:44 -0800

add syntax highlighting to code blocks

Use egui_extras::syntax_highlighting for colored code blocks in both
complete and streaming renders. Supports Rust, C/C++, Python, and
TOML with no new dependencies. Results are frame-cached.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Diffstat:
Mcrates/notedeck_dave/src/ui/markdown_ui.rs | 34++++++++++++++++++++++------------
1 file changed, 22 insertions(+), 12 deletions(-)

diff --git a/crates/notedeck_dave/src/ui/markdown_ui.rs b/crates/notedeck_dave/src/ui/markdown_ui.rs @@ -226,20 +226,22 @@ fn render_inlines(inlines: &[InlineElement], theme: &MdTheme, buffer: &str, ui: } fn render_code_block(language: Option<&str>, content: &str, theme: &MdTheme, ui: &mut Ui) { + use egui_extras::syntax_highlighting::{self, CodeTheme}; + egui::Frame::default() .fill(theme.code_bg) .inner_margin(8.0) .corner_radius(4.0) .show(ui, |ui| { - // Language label if present if let Some(lang) = language { ui.label(RichText::new(lang).small().weak()); } - // Code content - ui.add( - egui::Label::new(RichText::new(content).monospace().color(theme.code_text)).wrap(), - ); + let lang = language.unwrap_or("text"); + let code_theme = CodeTheme::from_style(ui.style()); + let layout_job = + syntax_highlighting::highlight(ui.ctx(), ui.style(), &code_theme, content, lang); + ui.add(egui::Label::new(layout_job).wrap()); }); ui.add_space(8.0); } @@ -319,20 +321,28 @@ fn render_partial(partial: &Partial, theme: &MdTheme, buffer: &str, ui: &mut Ui) match &partial.kind { PartialKind::CodeFence { language, .. } => { - // Show incomplete code block + use egui_extras::syntax_highlighting::{self, CodeTheme}; + egui::Frame::default() .fill(theme.code_bg) .inner_margin(8.0) .corner_radius(4.0) .show(ui, |ui| { - if let Some(lang) = language { - ui.label(RichText::new(lang.resolve(buffer)).small().weak()); + let lang_str = language.map(|s| s.resolve(buffer)); + if let Some(lang) = lang_str { + ui.label(RichText::new(lang).small().weak()); } - ui.add( - egui::Label::new(RichText::new(content).monospace().color(theme.code_text)) - .wrap(), + + let lang = lang_str.unwrap_or("text"); + let code_theme = CodeTheme::from_style(ui.style()); + let layout_job = syntax_highlighting::highlight( + ui.ctx(), + ui.style(), + &code_theme, + content, + lang, ); - // Blinking cursor indicator would require animation; just show underscore + ui.add(egui::Label::new(layout_job).wrap()); ui.label(RichText::new("_").weak()); }); }