about summary refs log tree commit diff stats
path: root/src/emit.scm
blob: 4c3581f9af75dea3c561bc9d64c5f9363e1dd6b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
(declare (module (jimmy emit)))

(import scheme (chicken base)
        (chicken format)
        (chicken irregex)
        (chicken string)
        (only utf8-srfi-13 string-join)
        (jimmy util))

(define-public (emit doc)
  (for-each display (map format-stanza doc)))

(define-public formats
  (make-parameter
   ;; (TYPE (line . LINE-FMT) (stanza . STANZA-FMT) (inline . INLINE-FMT))
   '((para (line . "~A")
           (stanza . "~A~%~%"))
     (verb (line . "~A~%")
           (stanza . "```~%~A```~%~%"))
     (link (line . "=> ~A ~A~%")         ; Note: link has 2 format arguments
           (stanza . "~A~%")
           (inline . "~%=> ~A ~A~%"))
     (list (line . "* ~A~%")
           (stanza . "~A~%"))
     (quot (line . "~A")
           (stanza . "> ~A~%~%"))
     (hdr1 (line . "# ~A~%")
           (stanza . "~A~%"))
     (hdr2 (line . "## ~A~%")
           (stanza . "~A~%"))
     (hdr3 (line . "### ~A~%")
           (stanza . "~A~%")))))

(define-public filters
  (make-parameter
   ;; (TYPE (line . LINE-FILTER) (stanza . STANZA-FILTER))
   ;; line-filter : (lambda (list-of-strs) ...) -> list-of-strs (for format)
   ;; stanza-filter : (lambda (list-of-strs) ...) -> str
   `((verb (line . ,identity)
           (stanza . ,join-lines))
     (default
       (line . ,identity)
       (stanza . ,flush-lines-left)))))

(define (format-line line el)
  (cond
   ((string? (car line))                ; regular stanza line
    (sprintf* (get-format el 'line)
              ((get-filter el 'line) line)))
   ((symbol? (car line))                ; inline element
    (sprintf* (get-format (car line) 'inline)
              ((get-filter (car line) 'line) (cdr line))))
   (else (error "Malformed line" line))))

(define (format-stanza stanza)
  (let* ((type (car stanza))
         (data (cdr stanza))
         (text (map (lambda (ln)
                      (format-line ln type))
                    data)))
    (sprintf (get-format type 'stanza)
             ((get-filter type 'stanza) text))))

;;; Utilities

(define (get-from alist el scope)
  (or (alist-walk alist el scope)
      (alist-walk alist 'default scope)
      (and (eq? scope 'inline)
           (alist-walk alist 'default 'line))))

(define (get-format el scope)
  (or (get-from (formats) el scope)
      ""))
(define (get-filter el scope) (get-from (filters) el scope))

(define (sprintf* fmt lis)
  (let loop ((num (length (irregex-extract "~[aA]" fmt)))
             (lis lis)
             (out '()))
    (cond
     ((null? lis)
      (apply sprintf fmt (reverse out)))
     ((= 1 num)
      (loop 0 '() (cons (string-join lis) out)))
     (else
      (loop (- num 1)
            (cdr lis)
            (cons (car lis) out))))))