โ– humdrum codex / glint v1.0.2
license AGPL-3.0

โ† issues

TASK-018 Minimal Alabaster syntax highlighting for code files

๐Ÿ Done feature priority: medium release-1

created 2026-06-29 16:44 ยท updated 2026-06-30 00:28

Description

Makes glint usable as a quick-edit editor for code (not just markdown) so it can reasonably be set as $EDITOR. Alabaster philosophy: color only a few token types, leave the rest base.

Three pieces:

  1. File-type routing: the editor selects a scanner by the file's extension โ€” .md/.markdown/.txt/none -> the existing markdown scanner; known code extensions (.go .py .js .ts .rs .c .h .java .rb .sh .lua .toml .yaml .json โ€ฆ) -> a code scanner. Add editor.SetLanguage/SetScanner; app sets it in Load() from filepath.Ext.
  2. Code scanner via chroma (already a transitive dep through glamour โ€” promote to direct). Use chroma's lexer-by-filename to tokenize, then map ONLY: String* -> string color (reuse Code, or a new String role); Comment* -> Comment (visible); Number/Literal -> Accent; Keyword/Name/Operator -> base Text; Punctuation -> Muted. Everything else base. Split the chroma token stream into per-line []Span; the concatenated span text must equal the raw line (markup-visible / display-only invariant, same as the markdown scanner). Handle multi-line tokens (block comments, multi-line strings).
  3. Theme: reuse Code/Comment/Accent/Muted; optionally add a dedicated String role if strings should differ from inline-code green.

Keep it minimal and calm (Alabaster), not a full IDE theme. Not the main code editor โ€” just 'open, read okay, small change, save'. Verify cursor/selection/wrap still work over code (tabs/CJK width is TASK-005).

Acceptance Criteria

Implementation Plan

  1. ScanCode(lines, filename, th) in internal/editor/code.go: chroma lexers.Match(filename) (fallback lexers.Fallback), Coalesce, Tokenise joined source; split token stream on newlines into per-line []Span; map String*->Code, Comment*->Comment, Number/Literal->Accent, Punctuation->Muted, rest->Text; preserve markup-visible invariant.
  2. Editor routing: codeFile field + SetLanguage(path) โ€” md/markdown/mdx/txt/none keep markdown scanner, other extensions use code scanner; buildVisual picks scanner.
  3. app Load() calls editor.SetLanguage(path).
  4. Promote chroma to direct dep (go mod tidy).
  5. TDD: code_test.go (strings/comments/numbers colored, identifiers/keywords base, invariant, multi-line block comment) + routing test (.go colors strings, .md still colors headings).

Implementation Notes

Done. internal/editor/code.go: ScanCode(lines, filename, th) via chroma lexers.Match (Fallback if unknown), Coalesce, Tokenise on joined source, split token stream on '\n' into per-line []Span. codeStyle maps String*->Code, Comment*->Comment, Number/Literal->Accent, Punctuation->Muted, rest base Text. Markup-visible invariant preserved (span text == raw line). Editor.codeFile + SetLanguage(path): md/markdown/mdx/txt/text/no-ext keep prose scanner, other exts use code scanner (base filename -> chroma). wrap.go buildVisual routes. app Load() calls SetLanguage. chroma/v2 promoted to direct dep. 8 TDD tests (strings/comments/numbers/identifiers/invariant/multiline-comment + buildVisual routing both ways + SetLanguage). Full suite + vet green.