diff options
| author | Christian Cleberg <[email protected]> | 2026-08-07 02:45:31 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-08-07 02:45:31 -0500 |
| commit | b410fd16b76146f4116538c5b82330818dd47da9 (patch) | |
| tree | 649488b2e5d3d901db8c792c0dc215c835fa9d38 /HutchTests | |
| parent | 0a3e55c15cfb9ce1bd3df0c7b352760bc2ee33c3 (diff) | |
| download | hutch-b410fd16b76146f4116538c5b82330818dd47da9.tar.gz hutch-b410fd16b76146f4116538c5b82330818dd47da9.tar.bz2 hutch-b410fd16b76146f4116538c5b82330818dd47da9.zip | |
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.
Diffstat (limited to 'HutchTests')
| -rw-r--r-- | HutchTests/SyntaxHighlighterTests.swift | 48 |
1 files changed, 48 insertions, 0 deletions
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("<span style=\"color:") == true) + #expect(unwrapped?.contains("answer") == true) + } + + @Test + func fallsBackToNilForUnsupportedLanguage() { + let highlighter = SyntaxHighlighter(theme: .dark) + #expect(highlighter.highlightedHTML(for: "plain text", language: nil) == nil) + #expect(highlighter.highlightedHTML(for: "plain text", language: "totally-not-a-language") == nil) + } + + @Test + func producesAttributedTextForNativeViewer() { + let highlighter = SyntaxHighlighter(theme: .light) + let font = UIFont.monospacedSystemFont(ofSize: 12, weight: .regular) + let attributed = highlighter.attributedText(for: "print(\"hi\")", language: "python", font: font) + + let unwrapped = try? #require(attributed) + #expect(unwrapped?.string.contains("print") == true) + } +} |
