Support gitignore highlighting
Makefile.am
11 | 11 | gitile/handler.scm \ | |
12 | 12 | gitile/pages.scm \ | |
13 | 13 | gitile/repo.scm \ | |
14 | - | gitile/highlight/css.scm | |
14 | + | gitile/highlight/utils.scm \ | |
15 | + | gitile/highlight/gitignore.scm | |
15 | 16 | ||
16 | 17 | clean-go: | |
17 | 18 | find . -name '*.go' -delete |
assets/css/highlight.css
26 | 26 | font-weight: bold; | |
27 | 27 | } | |
28 | 28 | ||
29 | + | /* language-specific */ | |
30 | + | ||
31 | + | /*** | |
32 | + | * SCHEME * | |
33 | + | * ***/ | |
34 | + | ||
29 | 35 | .language-scheme .syntax-special { | |
30 | 36 | color: var(--keyword); | |
31 | 37 | font-weight: bold; | |
… | |||
38 | 44 | .language-scheme .syntax-open, .language-scheme .syntax-close { | |
39 | 45 | color: var(--comment); | |
40 | 46 | } | |
47 | + | ||
48 | + | /*** | |
49 | + | * GITIGNORE * | |
50 | + | * ***/ | |
51 | + | .language-gitignore .syntax-special { | |
52 | + | color: var(--keyword); | |
53 | + | } |
gitile/code.scm
20 | 20 | #:use-module (ice-9 match) | |
21 | 21 | #:use-module (syntax-highlight) | |
22 | 22 | #:use-module (syntax-highlight scheme) | |
23 | - | #:use-module (gitile highlight css) | |
23 | + | #:use-module (gitile highlight gitignore) | |
24 | + | #:use-module ((gitile highlight utils) #:prefix gitile:) | |
24 | 25 | #:export (display-code | |
25 | 26 | display-formatted-code)) | |
26 | 27 | ||
… | |||
28 | 29 | (let* ((extension (car (reverse (string-split (basename path) #\.)))) | |
29 | 30 | (language (match extension | |
30 | 31 | ("scm" "scheme") | |
31 | - | ("css" "css") | |
32 | + | ("gitignore" "gitignore") | |
32 | 33 | (_ "unknown")))) | |
33 | 34 | `(table (@ (class ,(string-append "file-content language-" language))) | |
34 | - | ,@(split-tr (highlights->sxml (highlight-code content language)))))) | |
35 | + | ,@(split-tr (gitile:highlights->sxml (highlight-code content language)))))) | |
35 | 36 | ||
36 | 37 | (define (display-formatted-code content language) | |
37 | - | (highlights->sxml (highlight-code content language))) | |
38 | + | (gitile:highlights->sxml (highlight-code content language))) | |
38 | 39 | ||
39 | 40 | (define (highlight-code content language) | |
40 | 41 | (match language | |
41 | 42 | ("scheme" (highlight lex-scheme content)) | |
42 | - | ("css" (highlight lex-css content)) | |
43 | + | ("gitignore" (highlight lex-gitignore content)) | |
43 | 44 | (_ (list content)))) | |
44 | 45 | ||
45 | 46 | (define (split-lines content) | |
46 | 47 | (let loop ((content content) (result '()) (line '())) | |
47 | - | (match content | |
48 | + | (match (pk 'split-lines-content content) | |
48 | 49 | ((? string? s) (string-split s #\newline)) | |
49 | 50 | (() (append result (list line))) | |
50 | 51 | (((? string? s) content ...) | |
… | |||
77 | 78 | '())))))))) | |
78 | 79 | ||
79 | 80 | (define (split-tr content) | |
81 | + | (pk 'split-tr content) | |
80 | 82 | (let loop ((result '()) (lines (split-lines content)) (line-num 1)) | |
81 | 83 | (match lines | |
82 | 84 | (() result) |
gitile/highlight/gitignore.scm unknown status 1
1 | + | (define-module (gitile highlight gitignore) | |
2 | + | #:use-module (ice-9 match) | |
3 | + | #:use-module (srfi srfi-1) | |
4 | + | #:use-module (srfi srfi-11) | |
5 | + | #:use-module (srfi srfi-26) | |
6 | + | #:use-module (syntax-highlight lexers) | |
7 | + | #:use-module (gitile highlight utils) | |
8 | + | #:export (lex-gitignore)) | |
9 | + | ||
10 | + | (define lex-line | |
11 | + | (lex-consume-until | |
12 | + | (lex-string "\n") | |
13 | + | (lex-any | |
14 | + | (lex-tag 'special (apply lex-any (map lex-string '("*" "**" "?")))) | |
15 | + | (lex-tag 'range (lex-delimited "[" #:until "]")) | |
16 | + | (apply lex-any (map lex-string '("\\!" "\\*" "\\\\" "\\?"))) | |
17 | + | (lex-char-set (char-set-complement (char-set #\newline #\\ #\* #\?)))) | |
18 | + | #:tag 'line)) | |
19 | + | ||
20 | + | (define lex-gitignore | |
21 | + | (lex-consume | |
22 | + | (lex-any (lex-tag 'comment (lex-delimited "#" #:until "\n")) | |
23 | + | (lex-tag 'special (lex-string "!")) | |
24 | + | lex-line))) |
gitile/highlight/utils.scm unknown status 1
1 | + | (define-module (gitile highlight utils) | |
2 | + | #:use-module (ice-9 match) | |
3 | + | #:use-module (srfi srfi-1) | |
4 | + | #:use-module (srfi srfi-11) | |
5 | + | #:use-module (syntax-highlight lexers) | |
6 | + | #:export (highlights->sxml | |
7 | + | lex-consume-until)) | |
8 | + | ||
9 | + | (define (flatten-highlights highlights) | |
10 | + | (define (flatten-highlights-aux content tokens) | |
11 | + | (pk 'content content 'tokens tokens) | |
12 | + | (match content | |
13 | + | ((? string? s) (if (null? tokens) | |
14 | + | s | |
15 | + | `((,@tokens ,s)))) | |
16 | + | (((? symbol? token) content ...) | |
17 | + | (flatten-highlights-aux content (cons token tokens))) | |
18 | + | ((? list? content) | |
19 | + | (append-map (lambda (c) (flatten-highlights-aux c tokens)) content)))) | |
20 | + | ||
21 | + | (pk 'content highlights) | |
22 | + | (flatten-highlights-aux highlights '())) | |
23 | + | ||
24 | + | (define (highlights->sxml highlights) | |
25 | + | (define flat-highlights (flatten-highlights highlights)) | |
26 | + | ||
27 | + | (define (tag->class tag) | |
28 | + | (string-append "syntax-" (symbol->string tag))) | |
29 | + | ||
30 | + | (pk 'highlights flat-highlights) | |
31 | + | ||
32 | + | (map (match-lambda | |
33 | + | ((? string? str) str) | |
34 | + | ((content ...) | |
35 | + | (let loop ((tags '()) (text "") (content content)) | |
36 | + | (match content | |
37 | + | (() `(span (@ (class ,(string-join (map tag->class tags) " "))) ,text)) | |
38 | + | (((? symbol? tag) content ...) | |
39 | + | (loop (cons tag tags) text content)) | |
40 | + | (((? string? s) content ...) | |
41 | + | (loop tags (string-append text s) content)))))) | |
42 | + | flat-highlights)) | |
43 | + | ||
44 | + | (define* (lex-consume-until until lexer #:key (tag #f)) | |
45 | + | "Return a lexer that always succeeds with a list of as many consecutive | |
46 | + | successful applications of LEXER as possible, consuming the entire input text, | |
47 | + | or until a successful match of UNTIL, whichever comes first. Sections of text | |
48 | + | that could not be lexed are returned as plain strings." | |
49 | + | (define (substring* cursor start) | |
50 | + | (substring (cursor-text cursor) start (cursor-position cursor))) | |
51 | + | ||
52 | + | (define (consume-until tokens cursor) | |
53 | + | (if (cursor-end? cursor) | |
54 | + | (values tokens cursor) | |
55 | + | (let-values (((result remainder) (until tokens cursor))) | |
56 | + | (if result | |
57 | + | (values result remainder) | |
58 | + | (let-values (((result remainder) (lexer tokens cursor))) | |
59 | + | (if result | |
60 | + | (consume-until result remainder) | |
61 | + | (values (token-add tokens (cursor->string cursor)) | |
62 | + | (move-cursor-to-end cursor)))))))) | |
63 | + | ||
64 | + | (if tag | |
65 | + | (lambda (tokens cursor) | |
66 | + | (let-values (((result remainder) (consume-until empty-tokens cursor))) | |
67 | + | (values (pk (token-add tokens (list tag (tokens->list result)))) remainder))) | |
68 | + | consume-until)) |