From 727995a409632d4c143ba4b6b088c7df40f074e7 Mon Sep 17 00:00:00 2001
From: Case Duckworth
Date: Sat, 18 May 2024 21:15:54 -0500
Subject: Scheme bit!
---
src/emit.scm | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/html.scm | 3 ++
src/read.scm | 74 ++++++++++++++++++++++++++++++++++++++++
src/util.scm | 37 ++++++++++++++++++++
src/wrap.scm | 13 +++++++
5 files changed, 236 insertions(+)
create mode 100644 src/emit.scm
create mode 100644 src/html.scm
create mode 100644 src/read.scm
create mode 100644 src/util.scm
create mode 100644 src/wrap.scm
(limited to 'src')
diff --git a/src/emit.scm b/src/emit.scm
new file mode 100644
index 0000000..aa36eb5
--- /dev/null
+++ b/src/emit.scm
@@ -0,0 +1,109 @@
+(declare (module (jimmy emit)))
+
+(import scheme (chicken base)
+ (jimmy util)
+ (chicken format)
+ (chicken irregex)
+ (chicken string))
+
+(define-public (emit document)
+ (for-each display
+ (map format-block document)))
+
+(define-public formats
+ ;;; (type line-format block-format [line-in-block-format])
+ ;; these default to gemtext
+ '((para (line . "~A ")
+ (block . "~A~%~%"))
+ (verb (line . "~A~%")
+ (block . "```~%~A```~%~%"))
+ (link (line . "=> ~A ~A~%")
+ (block . "~A~%")
+ (inline . "~%=> ~A ~A~%")) ;TODO: have 2 args to format
+ (list (line . "* ~A~%")
+ (block . "~A~%"))
+ (quot (line . "~A ")
+ (block . "> ~A~%~%"))
+ (hdr1 (line . "# ~A~%")
+ (block . "~A~%"))
+ (hdr2 (line . "## ~A~%")
+ (block . "~A~%"))
+ (hdr3 (line . "### ~A~%")
+ (block . "~A~%"))
+ (default
+ (line . "~A")
+ (block . "~A~%~%"))))
+
+(define (string-join ss #!optional sep)
+ (if (string? ss) ss
+ (string-intersperse ss (or sep " "))))
+
+(define (char->tag char beg end)
+ (lambda (str)
+ (irregex-replace/all `(: ($ (or bos space))
+ ,char ($ (+ (~ ,char))) ,char
+ ($ (or space eos)))
+ str
+ 1 beg 2 end 3)))
+
+(define-public filters
+ `((para
+ (line . ,(o (char->tag "*" "" "")
+ (char->tag "_" "" "")
+ (char->tag "`" "" "
")
+ string-join))
+ (block . ,(lambda (ln)
+ (irregex-replace/all '(: bol (* " ")) ln ""))))
+ (link
+ (line . ,(lambda (ln)
+ (let ((ws (cond ((list? ln) ln)
+ ((string? ln) (string-split ln)))))
+ (list (car ws) (string-join (cdr ws)))))))
+ (default
+ (line . ,list)
+ (block . ,identity))))
+
+(define (get-from from type subtype)
+ (or (alist-walk from type subtype)
+ (if (eq? subtype 'inline)
+ (alist-walk from type 'list)
+ (lambda _ '("")))))
+
+(define (get-format type subtype) (get-from formats type subtype))
+(define (get-filter type subtype) (get-from filters type subtype))
+
+(define (format-line fmt line type)
+ (cond
+ ;; if LINE is a string, wrap it in a list
+ ((string? line)
+ (set! line (list line)))
+ ;; if it's a list of strings, join them together and filter them
+ ((and (list? line)
+ (string? (car line)))
+ (set! line ((get-filter type 'line) line)))
+ ;; if the car of LINE is a symbol, it's an inline thing.
+ ((and (list? line)
+ (symbol? (car line)))
+ (set! line (format-line (get-format (car line) 'inline)
+ ((get-filter (car line) 'line) (cdr line))
+ type)))
+ (else (error "Malformed line" line)))
+ (apply sprintf fmt line))
+
+(define (format-block block)
+ (if (assq (car block) formats)
+ (let* ((type (car block))
+ (data (cdr block))
+ (text (cond
+ ((string? data) data)
+ ((list? data)
+ (apply string-append
+ (map (lambda (ln)
+ (format-line (get-format type 'line)
+ ln
+ type))
+ data)))
+ (else (error "Malformed block" block)))))
+ (sprintf (get-format type 'block)
+ ((get-filter type 'block) text)))
+ ""))
diff --git a/src/html.scm b/src/html.scm
new file mode 100644
index 0000000..371d407
--- /dev/null
+++ b/src/html.scm
@@ -0,0 +1,3 @@
+(declare (module (jimmy html)))
+
+
diff --git a/src/read.scm b/src/read.scm
new file mode 100644
index 0000000..00ffad4
--- /dev/null
+++ b/src/read.scm
@@ -0,0 +1,74 @@
+(declare (module (jimmy read)))
+
+(import scheme (chicken base)
+ (jimmy util)
+ (only (chicken condition) handle-exceptions)
+ (only (chicken io) read-lines)
+ (only (chicken string) string-split))
+
+(define-public line-types
+ ;; (sigil type inlines preproc)
+ '(("=>" link)
+ (">" quot)
+ ("#" hdr1)
+ ("##" hdr2)
+ ("###" hdr3)
+ ("*" list)
+ ("```" verb)
+ ;; extra!
+ (":" meta)))
+
+(define-public (parse inport)
+ (parse-lines (read-lines inport) '()))
+
+(define (line-type line)
+ (let ((it (assoc (car (string-split line)) line-types)))
+ (if it (cadr it)
+ 'para)))
+
+(define (parse-lines lines document)
+ (if (null? lines) (reverse document)
+ (let ((words (string-split (car lines))))
+ (cond
+ ((null? words)
+ (parse-lines (cdr lines) document))
+ ((equal? (car words) "```")
+ (parse-verbatim (cdr lines) document '()))
+ ((assoc (car words) line-types)
+ => (lambda (it)
+ (apply parse-block lines document '() (cdr it))))
+ (else
+ (parse-block lines document '() 'para '(link) identity))))))
+
+(define (parse-verbatim lines document verb)
+ (cond
+ ((null? lines)
+ (parse-lines lines (cons (cons 'verb (reverse verb)) document)))
+ ((equal? (car lines) "```")
+ (parse-lines (cdr lines) (cons (cons 'verb (reverse verb)) document)))
+ (else
+ (parse-verbatim (cdr lines) document (cons (car lines) verb)))))
+
+(define (parse-block lines document block type #!optional inlines preproc)
+ (let ((inlines (or inlines '()))
+ (preproc (or preproc (lambda (ln) (cdr (string-split ln))))))
+ (cond
+ ((null? lines)
+ (parse-lines lines (cons (cons type (reverse block)) document)))
+ ((equal? (car lines) "")
+ (parse-lines (cdr lines) (cons (cons type (reverse block)) document)))
+ ((and (not (eq? type (line-type (car lines))))
+ (not (memq (line-type (car lines)) inlines)))
+ (parse-lines lines (cons (cons type (reverse block)) document)))
+ ((memq (line-type (car lines)) inlines)
+ (let* ((ln (car lines))
+ (ws (string-split ln))
+ (lt (cdr (assoc (car ws) line-types))))
+ (parse-block (cdr lines) document
+ (cons (cons (car lt)
+ ((or (ignore-errors (caddr lt)) cdr) ws))
+ block)
+ type inlines preproc)))
+ (else
+ (parse-block (cdr lines) document (cons (preproc (car lines)) block)
+ type inlines preproc)))))
diff --git a/src/util.scm b/src/util.scm
new file mode 100644
index 0000000..7bf89ac
--- /dev/null
+++ b/src/util.scm
@@ -0,0 +1,37 @@
+(module (jimmy util) *
+
+ (import scheme (chicken base)
+ (chicken condition))
+
+ (define-syntax define-public
+ (syntax-rules ()
+ ((define-public (name . arg) forms ...)
+ (begin (export name)
+ (define (name . arg) forms ...)))
+ ((define-public (name args ...) forms ...)
+ (begin (export name)
+ (define (name args ...) forms ...)))
+ ((define-public name value)
+ (begin (export name)
+ (define name value)))))
+
+ (define-syntax ignore-errors
+ (syntax-rules ()
+ ((ignore-errors x)
+ (handle-exceptions e #f x))))
+
+ (define (alist-walk lis . keys)
+ (if (null? keys)
+ lis
+ (let ((kv (assoc (car keys) lis)))
+ (cond
+ ((not kv) #f)
+ ((atom? (cdr kv))
+ (and (null? (cdr keys)) ; this shouldn't error...
+ (cdr kv)))
+ ((list? (cdr kv))
+ (apply alist-walk (cdr kv) (cdr keys)))))))
+
+ )
+
+
diff --git a/src/wrap.scm b/src/wrap.scm
new file mode 100644
index 0000000..3537dea
--- /dev/null
+++ b/src/wrap.scm
@@ -0,0 +1,13 @@
+(declare (module (jimmy wrap)))
+
+(import scheme (chicken base)
+ (jimmy util)
+ (chicken format))
+
+;;; open question: how to do templating?
+
+(define-public (wrap document template)
+ #f)
+
+(define (meta-get key document)
+ (alist-walk document 'meta key))
--
cgit 1.4.1-21-gabe81