implement intermediate doc format
This commit is contained in:
parent
45407af83b
commit
6d24b2fbd8
|
@ -0,0 +1,21 @@
|
||||||
|
#lang racket/base
|
||||||
|
|
||||||
|
(require racket/contract racket/list racket/match)
|
||||||
|
|
||||||
|
(provide metadata? metadata-ref metadata-ref+)
|
||||||
|
|
||||||
|
(define metadata?
|
||||||
|
(listof (or/c
|
||||||
|
(list/c 'date integer? integer? integer?)
|
||||||
|
(list/c 'title string?)
|
||||||
|
(list/c 'slug string?)
|
||||||
|
(list/c 'summary string?)
|
||||||
|
(cons/c 'authors (listof string?)))))
|
||||||
|
|
||||||
|
(define (metadata-ref md key [default (λ () (error "no such key"))])
|
||||||
|
(match (assoc key md)
|
||||||
|
[#f (if (procedure? default) (default) default)]
|
||||||
|
[(cons _ rst) rst]))
|
||||||
|
|
||||||
|
(define (metadata-ref+ md key [default (λ () (error "no such key"))])
|
||||||
|
(first (metadata-ref md key default)))
|
129
render.rkt
129
render.rkt
|
@ -1,64 +1,119 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
|
|
||||||
(require racket/contract racket/list racket/match racket/port racket/string
|
(require racket/list racket/match racket/port racket/set racket/string
|
||||||
markdown markdown/display-xexpr markdown/toc
|
markdown markdown/display-xexpr markdown/toc
|
||||||
"compiler.rkt"
|
"compiler.rkt" "defs.rkt"
|
||||||
|
threading
|
||||||
(prefix-in sass: sass)
|
(prefix-in sass: sass)
|
||||||
(prefix-in mathml: "ext-mathml/main.rkt")
|
(prefix-in mathml: "ext-mathml/main.rkt")
|
||||||
(prefix-in syntax: "ext-syntax/main.rkt")
|
(prefix-in syntax: "ext-syntax/main.rkt")
|
||||||
(prefix-in article: "templates/article.html.rkt"))
|
(prefix-in article: "templates/article.html.rkt"))
|
||||||
|
|
||||||
(define metadata?
|
(struct input-doc [metadata text] #:transparent)
|
||||||
(listof (or/c
|
(struct ir-doc [metadata hashtags html] #:transparent)
|
||||||
(list/c 'date integer? integer? integer?)
|
|
||||||
(list/c 'title string?)
|
|
||||||
(list/c 'slug string?)
|
|
||||||
(list/c 'summary string?)
|
|
||||||
(cons/c 'authors (listof string?)))))
|
|
||||||
|
|
||||||
(define (metadata-ref md key [default (λ () (error "no such key"))])
|
(define (read-input-doc [port (current-input-port)])
|
||||||
(match (assoc key md)
|
|
||||||
[#f (if (procedure? default) (default) default)]
|
|
||||||
[(cons _ rst) rst]))
|
|
||||||
|
|
||||||
(define (metadata-ref+ md key [default (λ () (error "no such key"))])
|
|
||||||
(first (metadata-ref md key default)))
|
|
||||||
|
|
||||||
(struct input-document [metadata text] #:transparent)
|
|
||||||
|
|
||||||
(define (read-doc [port (current-input-port)])
|
|
||||||
(define metadata (read port))
|
(define metadata (read port))
|
||||||
(unless (metadata? metadata)
|
(unless (metadata? metadata)
|
||||||
(error "post front matter is not valid metadata!"))
|
(error "post front matter is not valid metadata!"))
|
||||||
(define text (port->string port))
|
(define text (port->string port))
|
||||||
(input-document metadata text))
|
(input-doc metadata text))
|
||||||
|
|
||||||
(define (markdown->html input)
|
;; transforms the xexpr into an xexpr that includes links to hashtags
|
||||||
(match-define (input-document md text) input)
|
(define (extract-hashtags xexpr)
|
||||||
|
(define hashtags (mutable-set))
|
||||||
|
(define (process+ xexpr)
|
||||||
|
(match xexpr
|
||||||
|
;; do not descend into code or math
|
||||||
|
[(list (or 'code 'math) attrs children ...) (list xexpr)]
|
||||||
|
;; recursive
|
||||||
|
[(list tag attrs children ...)
|
||||||
|
(list (cons tag (cons attrs
|
||||||
|
(apply append
|
||||||
|
(map (lambda (child) (process+ child)) children)))))]
|
||||||
|
;; extract and transform hashtags
|
||||||
|
[(? string? str)
|
||||||
|
(define posns (regexp-match-positions* #px"#(\\p{L}|\\p{N})+" str))
|
||||||
|
(define-values [items last-pos]
|
||||||
|
(for/fold ([items '()] [last-pos 0]) ([pos (in-list posns)])
|
||||||
|
(define hashtag (substring str (car pos) (cdr pos)))
|
||||||
|
(set-add! hashtags hashtag)
|
||||||
|
(values (cons `(hashtag () ,hashtag)
|
||||||
|
(cons (substring str last-pos (car pos)) items))
|
||||||
|
(cdr pos))))
|
||||||
|
(reverse (cons (substring str last-pos) items))]))
|
||||||
|
(values (first (process+ xexpr)) hashtags))
|
||||||
|
|
||||||
|
;; xref links start with ^
|
||||||
|
(define (xref-link? x)
|
||||||
|
(and (string? x) (> (string-length x) 1) (char=? (string-ref x 0) #\^)))
|
||||||
|
|
||||||
|
;; extracts xref-prefixed links and converts them into the <xref> pseudo-tag
|
||||||
|
(define (extract-xrefs xexpr)
|
||||||
|
(match xexpr
|
||||||
|
[(list 'a attrs body ...)
|
||||||
|
(match (assoc 'href attrs)
|
||||||
|
[(list _ (? xref-link? xref))
|
||||||
|
(define target (substring xref 1))
|
||||||
|
`(xref ([target ,target]) ,@(map extract-xrefs body))]
|
||||||
|
[_ (apply list 'a attrs (map extract-xrefs body))])]
|
||||||
|
[(list tag attrs children ...)
|
||||||
|
(apply list tag attrs (map extract-xrefs children))]
|
||||||
|
[(? string? str) str]))
|
||||||
|
|
||||||
|
(define (input-doc->ir-doc doc)
|
||||||
|
(match-define (input-doc md text) doc)
|
||||||
(define output-raw (parse-markdown text))
|
(define output-raw (parse-markdown text))
|
||||||
(define output-cooked (mathml:transform-xexprs (syntax:transform-xexprs output-raw)))
|
(define output-cooked (mathml:transform-xexprs (syntax:transform-xexprs output-raw)))
|
||||||
(define output-toc (toc output-cooked))
|
(let-values ([(output-cooked hashtags) (extract-hashtags output-cooked)])
|
||||||
|
(let ([output-cooked (extract-xrefs output-cooked)])
|
||||||
|
(ir-doc md hashtags output-cooked))))
|
||||||
|
|
||||||
|
;; lowers pseudo-tags into their final form
|
||||||
|
(define (lower-specials xexpr base-url)
|
||||||
|
(define (lower-specials* xexpr)
|
||||||
|
(match xexpr
|
||||||
|
;; hashtags
|
||||||
|
[(list 'hashtag _ hashtag)
|
||||||
|
`(a ([class "hashtag"]
|
||||||
|
[href ,(string-append base-url "/tag/" (substring hashtag 1))])
|
||||||
|
,hashtag)]
|
||||||
|
;; xrefs
|
||||||
|
[(list 'xref (list (list 'target target)) body ...)
|
||||||
|
`(a ([class "xref"] [href ,(string-append base-url "/xref/" target)])
|
||||||
|
,@(map lower-specials* body))]
|
||||||
|
;; everything else
|
||||||
|
[(list tag attrs children ...)
|
||||||
|
(apply list tag attrs (map lower-specials* children))]
|
||||||
|
[(? string? str) str]))
|
||||||
|
(lower-specials* xexpr))
|
||||||
|
|
||||||
|
(define (ir-doc->page doc)
|
||||||
|
(match-define (ir-doc md hashtags content) doc)
|
||||||
|
(let ([content (lower-specials content "https://awoo.systems")])
|
||||||
|
(define content-toc (toc content))
|
||||||
|
|
||||||
|
(define document
|
||||||
|
(article:execute
|
||||||
|
(hash 'metadata md
|
||||||
|
'content-toc content-toc
|
||||||
|
'content content)))
|
||||||
|
|
||||||
|
(with-output-to-string (λ () (display "<!doctype html>") (display-xexpr document)))))
|
||||||
|
|
||||||
|
(define (compile-index-scss)
|
||||||
(define scss-files (append mathml:scss-files syntax:scss-files))
|
(define scss-files (append mathml:scss-files syntax:scss-files))
|
||||||
(define top-level-style
|
(define top-level-style
|
||||||
(string-join (map (λ (x) (format "@import \"~a\";" (path->string x))) scss-files) "\n"))
|
(string-join (map (λ (x) (format "@import \"~a\";" (path->string x))) scss-files) "\n"))
|
||||||
(define styles (sass:compile/string top-level-style #t))
|
(sass:compile/string top-level-style #t))
|
||||||
|
|
||||||
(define document
|
|
||||||
(article:execute (hash 'metadata-ref metadata-ref
|
|
||||||
'metadata-ref+ metadata-ref+
|
|
||||||
'metadata md
|
|
||||||
'page-styles styles
|
|
||||||
'content-toc output-toc
|
|
||||||
'content output-cooked)))
|
|
||||||
|
|
||||||
(with-output-to-string (λ () (display "<!doctype html>") (display-xexpr document))))
|
|
||||||
|
|
||||||
(module+ main
|
(module+ main
|
||||||
(require racket/cmdline)
|
(require racket/cmdline)
|
||||||
(command-line
|
(command-line
|
||||||
#:program "meow"
|
#:program "meow"
|
||||||
#:args (infile outfile)
|
#:args (infile outfile)
|
||||||
|
(define-rule (scss [out "index.css"])
|
||||||
|
(~> (compile-index-scss) (write-string out)))
|
||||||
(define-rule (render [out outfile] [in infile])
|
(define-rule (render [out outfile] [in infile])
|
||||||
(write-string (markdown->html (read-doc in)) out))
|
(~> (read-input-doc in) input-doc->ir-doc ir-doc->page (write-string out)))
|
||||||
(generate/execute (list render))))
|
(generate/execute (list render scss))))
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
(~r dn #:min-width 2 #:pad-string "0"))])))])
|
(~r dn #:min-width 2 #:pad-string "0"))])))])
|
||||||
(meta ([name "generator"] [content "meow meow meow meow"]))
|
(meta ([name "generator"] [content "meow meow meow meow"]))
|
||||||
;<link rel="shortcut icon" type="image/png" href="haskal.png"/>
|
;<link rel="shortcut icon" type="image/png" href="haskal.png"/>
|
||||||
(style ([type "text/css"]) ,page-styles))
|
(link ([rel "stylesheet"] [type "text/css"] [href "index.css"])))
|
||||||
(body
|
(body
|
||||||
()
|
()
|
||||||
(nav
|
(nav
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
|
|
||||||
(require racket/base racket/format racket/list racket/match racket/string
|
(require racket/base racket/format racket/list racket/match racket/string
|
||||||
|
"defs.rkt"
|
||||||
syntax/parse syntax/parse/define racket/stxparam
|
syntax/parse syntax/parse/define racket/stxparam
|
||||||
(for-syntax racket/base racket/match racket/set))
|
(for-syntax racket/base racket/match racket/set))
|
||||||
|
|
||||||
(provide (rename-out [x:#%module-begin #%module-begin]
|
(provide (rename-out [x:#%module-begin #%module-begin]
|
||||||
[x:#%top #%top])
|
[x:#%top #%top])
|
||||||
(except-out (all-from-out racket/base racket/format racket/list racket/match racket/string)
|
(except-out (all-from-out racket/base racket/format racket/list racket/match racket/string
|
||||||
|
"defs.rkt")
|
||||||
#%module-begin #%top))
|
#%module-begin #%top))
|
||||||
|
|
||||||
(define-syntax-parameter template-id #f)
|
(define-syntax-parameter template-id #f)
|
||||||
|
|
Loading…
Reference in New Issue