#lang scheme/base ;; Build the node structure for a ramblings.txt file. (require "entry.ss" ;; Ramblings syntax (meta + body) "entry-format.ss" "tools.ss" "ramblings-registry.ss" "latex.ss" "facade.ss" "entry-tex.ss" ;; tex -> html+png / pdf compiler web-server/http/response-structs (planet zwizwa/lib/x/graph)) (provide make-node->offset ramblings-file->nodes) ;; convert ramblings.txt to list of articles ;; (ramblings-file->nodes "/home/tom/sweb/doc/sweb.txt") (define (ramblings-file->nodes filename) (map parse-article (file->entries filename))) (define (symbol-nodes! node lst) (for ((sym lst)) (let ((val (n@ node sym false))) (when (and val (string? val)) (n! node sym (string->symbol val)))))) ;; Interpret a query. (define (query-match q) (let ((hash (make-immutable-hash q))) (lambda (tag) (let ((ref (hash-ref hash tag void))) (if (void? ref) #f ;; no ref (or ref #t)))))) (define (make-node->offset n) (lambda (offst) (with-handlers ((void (lambda _ #f))) (let ((toc (n@ n 'toc))) (n@ (toc-ref toc (n@ n 'ID) offst) 'ID))))) ;; Page numbers start at 1. (define (tex! n lines) ;; A rendered tex doc contains multiple pages, and each page ;; contains an HTML wrapper and a PNG file for the rendered page. ;; The `query' method of the article node provides the functionality ;; to retreive the data, while the `link' function defined below ;; constructs HTTP links to embed in the HTML. (define (link tag i) (node-query->link (lambda (key) (n@ n key)) `((,tag . ,i)))) (let* ;; Cached, lazy intermediates ((dvi-file (% (texblog->dvi (n@ n 'str)))) (pdf-file (% (dvi->pdf (n@ n 'dvi-file)))) (png-files (% (dvi->pngs (! dvi-file)))) (npng (lambda () (length (! png-files)))) (xhtml (lambda (i) (tex-xhtml link npng lines i)))) (begin (n! n 'pdf (%% ;; don't cache binary data (just reload mfile) (mime #"application/pdf" (mfile->bytes (! pdf-file))))) (n! n 'query (lambda (q) (define q? (query-match q)) (cond ((q? 'page) => (lambda (str) (render-decoration (lambda (key) (n@ n key (lambda () #f))) (make-node->offset n) (xhtml (string->number str))))) ((q? 'png) => (lambda (str) (let ((i (string->number str))) (mime #"image/png" (mfile->bytes (list-ref (! png-files) (sub1 i)))))))))) ;; Main page has same content as page 1. (n! n 'xhtml (% `(pre ,@(xhtml 1))))))) (define (parse-article lines) (let-values (((dict lines) (article->dict+lines lines))) (let ((n (dict->node dict))) (symbol-nodes! n '(MD5 ID Type)) (let ((date (n@ n 'Date false)) (MD5 (n@ n 'MD5 false)) (ID (n@ n 'ID false)) (Type (n@ n 'Type false))) ;; Posts are identified by an explicitly specified ID, an MD5 ;; hash of the data it is associated to, or the Index derived ;; from the date. Note that these IDs should be specific ;; enough to be googlable. (n! n 'ID (cond (ID ID) (MD5 MD5) (else (n@ n 'Index)))) ;; Will be filled in once the parse is forced. (n! n 'links '()) (n! n 'words '()) ;; Store a couple of lazy objects in the node. (n! n 'str (% (lines->string lines))) (n! n 'raw (% (mime #"text/plain" (n@ n 'str)))) ;; Rendering (case Type ((tex) (tex! n lines)) (else (n! n 'xhtml (% ;; (*) (let ((id (n@ n 'ID (lambda () "")))) (printf "parsing ~a\n" id) (lines->xhtml lines #:tx-word (lambda (w) (n-push! n 'words w) w) #:tx-link (lambda (w) (n-push! n 'links w) w) )))))) n)))) ;; (*) The body parsing is delayed until it is actually acessed. ;; TEST