From b410fd16b76146f4116538c5b82330818dd47da9 Mon Sep 17 00:00:00 2001 From: Christian Cleberg Date: Fri, 7 Aug 2026 02:45:31 -0500 Subject: Add multi-language syntax highlighting (#16) Splash (Swift-only, since removed) left code rendering unhighlighted everywhere. Add Highlightr (highlight.js) behind a small SyntaxHighlighter service and use it on both surfaces: - Native file viewer: highlight NSAttributedString by language inferred from the filename, picking a light/dark theme from the trait style and re-highlighting on style changes. Falls back to plain text for unknown languages or very large files. - Markdown/org code blocks in the WKWebView (READMEs, tickets, comments): the web view disables JavaScript, so highlight server-side into inline color-styled spans. The color scheme is now part of the render/cache key since colors are baked into the HTML. Covered by unit tests for language mapping and highlighted output. --- HutchTests/SyntaxHighlighterTests.swift | 48 +++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 HutchTests/SyntaxHighlighterTests.swift (limited to 'HutchTests') diff --git a/HutchTests/SyntaxHighlighterTests.swift b/HutchTests/SyntaxHighlighterTests.swift new file mode 100644 index 0000000..258e81e --- /dev/null +++ b/HutchTests/SyntaxHighlighterTests.swift @@ -0,0 +1,48 @@ +import Foundation +import Testing +import UIKit +@testable import Hutch + +struct SyntaxHighlighterTests { + @Test + func mapsFileNamesToLanguages() { + #expect(SyntaxHighlighter.language(forFileName: "Sources/App/Main.swift") == "swift") + #expect(SyntaxHighlighter.language(forFileName: "server.py") == "python") + #expect(SyntaxHighlighter.language(forFileName: "index.tsx") == "typescript") + #expect(SyntaxHighlighter.language(forFileName: "Dockerfile") == "dockerfile") + #expect(SyntaxHighlighter.language(forFileName: "Makefile") == "makefile") + } + + @Test + func returnsNilForUnknownExtensions() { + #expect(SyntaxHighlighter.language(forFileName: "notes.unknownext") == nil) + #expect(SyntaxHighlighter.language(forFileName: "LICENSE") == nil) + } + + @Test + func highlightsKnownLanguageAsColoredSpans() { + let highlighter = SyntaxHighlighter(theme: .light) + let html = highlighter.highlightedHTML(for: "let answer = 42", language: "swift") + + let unwrapped = try? #require(html) + #expect(unwrapped?.contains("