From 19a804e0be889750d799ddc8c365eec122afba1c Mon Sep 17 00:00:00 2001 From: "Dhanji R. Prasanna" Date: Thu, 8 Jan 2026 20:35:34 +1100 Subject: [PATCH] Add syntax highlighting for Racket, Elisp, and Scheme Add language alias mapping in highlight_code() to map: - racket, rkt -> lisp - elisp, emacs-lisp -> lisp - scheme -> lisp - common-lisp, cl -> lisp - shell, sh, zsh, dockerfile -> bash Syntect's built-in Lisp syntax handles all Lisp-family languages well. Added test to verify the aliases work correctly. --- crates/g3-cli/src/streaming_markdown.rs | 16 +++++- .../g3-cli/tests/streaming_markdown_test.rs | 50 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/crates/g3-cli/src/streaming_markdown.rs b/crates/g3-cli/src/streaming_markdown.rs index 4cd2943..3f97fff 100644 --- a/crates/g3-cli/src/streaming_markdown.rs +++ b/crates/g3-cli/src/streaming_markdown.rs @@ -799,8 +799,22 @@ fn is_potential_delimiter_start(ch: char) -> bool { /// Highlight code with syntect. fn highlight_code(code: &str, lang: Option<&str>) -> String { + // Map language aliases to syntect-recognized names + let normalized_lang = lang.map(|l| match l.to_lowercase().as_str() { + // Lisp family - syntect's "Lisp" syntax handles these well + "racket" | "rkt" => "lisp", + "elisp" | "emacs-lisp" => "lisp", + "scheme" => "lisp", + "common-lisp" | "cl" => "lisp", + // Other common aliases + "shell" | "sh" => "bash", + "zsh" => "bash", + "dockerfile" => "bash", + _ => l, + }); + let syntax = lang - .and_then(|l| SYNTAX_SET.find_syntax_by_token(l)) + .and_then(|_| normalized_lang.and_then(|l| SYNTAX_SET.find_syntax_by_token(l))) .unwrap_or_else(|| SYNTAX_SET.find_syntax_plain_text()); let theme = &THEME_SET.themes["base16-ocean.dark"]; diff --git a/crates/g3-cli/tests/streaming_markdown_test.rs b/crates/g3-cli/tests/streaming_markdown_test.rs index e1f4e1c..cf73b84 100644 --- a/crates/g3-cli/tests/streaming_markdown_test.rs +++ b/crates/g3-cli/tests/streaming_markdown_test.rs @@ -1536,3 +1536,53 @@ fn stress_test_pathological() { fmt = make_formatter(); } } + +#[test] +fn test_language_aliases() { + let mut fmt = make_formatter(); + + // Test Racket code block + let racket_code = r#"```racket +(define (factorial n) + (if (<= n 1) + 1 + (* n (factorial (- n 1))))) +``` +"#; + let output = fmt.process(racket_code); + let remaining = fmt.finish(); + let full = format!("{}{}", output, remaining); + // Should have ANSI codes (syntax highlighting applied) + assert!(full.contains("\x1b["), "Racket should be syntax highlighted"); + assert!(full.contains("factorial")); + + // Test elisp code block + let mut fmt = make_formatter(); + let elisp_code = r#"```elisp +(defun hello-world () + "Print hello world." + (interactive) + (message "Hello, World!")) +``` +"#; + let output = fmt.process(elisp_code); + let remaining = fmt.finish(); + let full = format!("{}{}", output, remaining); + assert!(full.contains("\x1b["), "Elisp should be syntax highlighted"); + assert!(full.contains("hello-world")); + + // Test scheme code block + let mut fmt = make_formatter(); + let scheme_code = r#"```scheme +(define (map f lst) + (if (null? lst) + '() + (cons (f (car lst)) + (map f (cdr lst))))) +``` +"#; + let output = fmt.process(scheme_code); + let remaining = fmt.finish(); + let full = format!("{}{}", output, remaining); + assert!(full.contains("\x1b["), "Scheme should be syntax highlighted"); +}