From ed4e86f47935994fb424c977e4123bde625ddff1 Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Mon, 3 Jun 2024 16:56:30 -0500 Subject: Fix html/other sourcing; re-scramble Makefile --- Makefile | 93 +++++++++++++++------------------- jimmy.egg | 15 +++++- src/emit.scm | 69 +++++++++++++------------ src/html.scm | 58 +++++++++++++++++++++ src/read.scm | 29 ++++++++--- src/util.scm | 12 ++++- src/wrap.scm | 2 +- tests/run.scm | 160 +++++++++++++++++++++++++++++++++++++--------------------- 8 files changed, 283 insertions(+), 155 deletions(-) diff --git a/Makefile b/Makefile index b4f54b6..8eead3a 100644 --- a/Makefile +++ b/Makefile @@ -1,64 +1,51 @@ -NAME = jimmy - -LIBS = read emit util - -BUILD = $(PWD)/build -SRC = $(PWD)/src -TESTS = $(PWD)/tests +# Automatically generated by scramble +NAME = jimmy CSC = /usr/bin/csc +CSC_OPTIONS = -setup-mode -host -I $(PWD) -C -I$(PWD) +CSC_LIB_OPTIONS = -D compiling-extension -emit-all-import-libraries -dynamic -regenerate-import-libraries +CSC_OPTIONS_EXTRA = -X utf8 -X module-declarations CSI = /usr/bin/csi -CSC_OPTIONS = \ - -setup-mode \ - -host \ - -D compiling-extension \ - -emit-all-import-libraries \ - -dynamic \ - -regenerate-import-libraries \ - -I $(SRC) \ - -C -I$(SRC) - -CSC_OPTIONS_EXTRA = \ - -X utf8 \ - -X module-declarations - -## Library dependency graph -# here's a convenience macro -lib = $(BUILD)/$(NAME).$(1).so -# and another -src = $(SRC)/$(1).scm - -LIBS_ = $(foreach l,$(LIBS),$(call lib,$(l))) - -## Phonies - -.PHONY: build test clean -build: $(LIBS_) - -mv *.import.scm build/ - -test: build - cd $(BUILD) && \ - $(CSI) -setup-mode -s $(TESTS)/run.scm $(NAME) +BUILD = $(PWD)/build +TESTS = $(PWD)/tests +TEST_ENV = env BUILD=$(BUILD) TESTS=$(TESTS) +TEST_ENV_EXTRA = TEST_USE_ANSI=0 +.PHONY: all test clean install uninstall +all: build/jimmy.util.so build/jimmy.read.so build/jimmy.emit.so build/jimmy.html.so build/jimmy.wrap.so +test: all + cd $(BUILD) && $(TEST_ENV) $(TEST_ENV_EXTRA) $(CSI) -setup-mode -s $(TESTS)/run.scm $(NAME) clean: - -rm -rf $(BUILD) - + -rm -rf $(BUILD) *.build.sh *.install.sh $(NAME) *.import.scm *.so *.link *.static.o install: chicken-install -s - uninstall: chicken-uninstall -s -# Scm -> So - -$(BUILD)/$(NAME).%.so: src/%.scm - mkdir -p "$(dir $@)" - $(CSC) $(CSC_OPTIONS) $(CSC_OPTIONS_EXTRA) $< -o $@ - -# Libraries! -$(call lib,util): $(call src,util) +# jimmy -$(call lib,read): $(call src,read) $(call lib,util) -$(call lib,emit): $(call src,emit) $(call lib,util) - -# Program! +build/jimmy.util.so: src/util.scm + @mkdir -p $(BUILD) + cd $(BUILD) && \ + $(CSC) $(CSC_OPTIONS) $(CSC_LIB_OPTIONS) $(CSC_OPTIONS_EXTRA) ../$< -o $(@F) + @test -f jimmy.util.import.scm &&mv jimmy.util.import.scm $(BUILD)/||true +build/jimmy.read.so: src/read.scm src/util.scm + @mkdir -p $(BUILD) + cd $(BUILD) && \ + $(CSC) $(CSC_OPTIONS) $(CSC_LIB_OPTIONS) $(CSC_OPTIONS_EXTRA) ../$< -o $(@F) + @test -f jimmy.read.import.scm &&mv jimmy.read.import.scm $(BUILD)/||true +build/jimmy.emit.so: src/emit.scm src/util.scm + @mkdir -p $(BUILD) + cd $(BUILD) && \ + $(CSC) $(CSC_OPTIONS) $(CSC_LIB_OPTIONS) $(CSC_OPTIONS_EXTRA) ../$< -o $(@F) + @test -f jimmy.emit.import.scm &&mv jimmy.emit.import.scm $(BUILD)/||true +build/jimmy.html.so: src/html.scm src/util.scm src/emit.scm + @mkdir -p $(BUILD) + cd $(BUILD) && \ + $(CSC) $(CSC_OPTIONS) $(CSC_LIB_OPTIONS) $(CSC_OPTIONS_EXTRA) ../$< -o $(@F) + @test -f jimmy.html.import.scm &&mv jimmy.html.import.scm $(BUILD)/||true +build/jimmy.wrap.so: src/wrap.scm src/util.scm src/emit.scm + @mkdir -p $(BUILD) + cd $(BUILD) && \ + $(CSC) $(CSC_OPTIONS) $(CSC_LIB_OPTIONS) $(CSC_OPTIONS_EXTRA) ../$< -o $(@F) + @test -f jimmy.wrap.import.scm &&mv jimmy.wrap.import.scm $(BUILD)/||true diff --git a/jimmy.egg b/jimmy.egg index 108cf7d..84fe949 100644 --- a/jimmy.egg +++ b/jimmy.egg @@ -7,11 +7,24 @@ (component-options (csc-options -X utf8 -X module-declarations)) (components + ;; Utility library (extension jimmy.util (source src/util.scm)) + ;; Read gemini files into internal format (extension jimmy.read (source src/read.scm) (component-dependencies jimmy.util)) + ;; Emit the output format (includes gemini) (extension jimmy.emit (source src/emit.scm) - (component-dependencies jimmy.util)))) + (component-dependencies jimmy.util)) + ;; Emit HTML -- import this *after* emit (is this the best way?) + (extension jimmy.html + (source src/html.scm) + (component-dependencies jimmy.util + jimmy.emit)) + ;; Wrap output in templates + (extension jimmy.wrap + (source src/wrap.scm) + (component-dependencies jimmy.util + jimmy.emit)))) diff --git a/src/emit.scm b/src/emit.scm index e57e437..4c3581f 100644 --- a/src/emit.scm +++ b/src/emit.scm @@ -1,3 +1,5 @@ +(declare (module (jimmy emit))) + (import scheme (chicken base) (chicken format) (chicken irregex) @@ -9,41 +11,36 @@ (for-each display (map format-stanza doc))) (define-public formats - ;;; (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~%")) - (meta (line . "") - (stanza . "")) - (default - (line . "~A") - (stanza . "~A~%~%")))) + (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 - ;;; (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 . ,(lambda (lines) (apply string-append lines)))) - (default - (line . ,identity) - (stanza . ,(lambda (lines) - (irregex-replace/all '(: bol (* space)) - (string-join lines) "")))))) + (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 @@ -72,8 +69,10 @@ (and (eq? scope 'inline) (alist-walk alist 'default 'line)))) -(define (get-format el scope) (get-from formats el scope)) -(define (get-filter el scope) (get-from filters el scope)) +(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))) diff --git a/src/html.scm b/src/html.scm index 371d407..07cd921 100644 --- a/src/html.scm +++ b/src/html.scm @@ -1,3 +1,61 @@ (declare (module (jimmy html))) +(import scheme (chicken base) + (chicken irregex) + (jimmy emit) + (jimmy util)) +(define (escape-entities s) + (irregex-replace/all "[&<>]" s + (lambda (m) + (let ((c (irregex-match-substring m))) + (cond + ((equal? c "&") "&") + ((equal? c "<") "<") + ((equal? c ">") ">")))))) + +(define (add-inline-markup s) + (define (char->tag ch tag) + (lambda (s) + (irregex-replace/all `(: ,ch ($ (* (~ ,ch))) ,ch) s + "<" tag ">" 1 ""))) + + ((o (char->tag "*" "b") + (char->tag "_" "i") + (char->tag "`" "code")) s)) + +(formats + '((para (line . "~a~%") + (stanza . "

~% ~a

~%")) + (verb (line . "~a~%") + (stanza . "
~a
~%")) + (link (line . "
  • ~a
  • ~%") + (stanza . "~%") + (inline . "~a~%")) + (list (line . "
  • ~a
  • ~%") + (stanza . "~%")) + (quot (line . "~a~%") + (stanza . "
    ~% ~a
    ~%")) + (hdr1 (line . "~a") + (stanza . "

    ~a

    ~%")) + (hdr2 (line . "~a") + (stanza . "

    ~a

    ~%")) + (hdr3 (line . "~a") + (stanza . "

    ~a

    ~%")))) + +(filters + `((verb (line . ,identity) + (stanza . ,join-lines)) + (link (line . ,(lambda (ln) + (cons (car ln) + ((o list + add-inline-markup + escape-entities + string-join) + (cdr ln)))))) + (default + (line . ,(o list + add-inline-markup + escape-entities + string-join)) + (stanza . ,string-join)))) diff --git a/src/read.scm b/src/read.scm index 94708ef..1b611bb 100644 --- a/src/read.scm +++ b/src/read.scm @@ -36,19 +36,34 @@ ((null? words) ; empty line (parse-lines (cdr lines) doc)) ((equal? (car words) "```") ; verbatim - (parse-verbatim (cdr lines) doc '())) + ;; Format for verbatim header: + ;; ``` ?html | command ... + ;; -- only run command on block with html output. + ;; other outputs process the block normally + ;; ``` ?!html | command ... + ;; -- only run command on block when *not* outputting html. + ;; html processes the block normally + ;; ``` ?:html | command ... + ;; -- like ?html, but ignore the block in non-html outputs. + ;;;; FIXME: I think this necessitates a special emit-verbatim + ;;;; function. + (parse-verbatim (cdr lines) doc '() + #; (if (< 1 (length words)) + (cons 'verb (cdr words)) + 'verb) + 'verb)) (else ; another line type (apply parse-stanza lines doc '() (line-type words))))))) -(define (parse-verbatim lines doc block) - (define (close-verbatim) (cons (cons 'verb (reverse block)) doc)) +(define (parse-verbatim lines doc block bhead) + (define (close-verbatim) (cons (cons bhead (reverse block)) doc)) (cond - ((null? lines) ; end of document + ((null? lines) ; end of document (parse-lines lines (close-verbatim))) - ((equal? (car lines) "```") ; end of verbatim block + ((equal? (car lines) "```") ; end of verbatim block (parse-lines (cdr lines) (close-verbatim))) - (else ; verbatim block continues - (parse-verbatim (cdr lines) doc (cons (list (car lines)) block))))) + (else ; verbatim block continues + (parse-verbatim (cdr lines) doc (cons (list (car lines)) block) bhead)))) (define (parse-stanza lines doc stanza st-type #!optional (st-inlines '()) (st-words cdr)) diff --git a/src/util.scm b/src/util.scm index 41da769..c71c600 100644 --- a/src/util.scm +++ b/src/util.scm @@ -2,6 +2,7 @@ (import scheme (chicken base) (chicken condition) + (only (chicken irregex) irregex-replace/all) (chicken string)) (define-syntax define-public @@ -34,6 +35,15 @@ (apply alist-walk (cdr kv) (cdr keys))))))) (define (string-join ss #!optional (sep " ")) - (string-intersperse ss sep))) + (string-intersperse ss sep)) + + (define (flush-lines-left lines) + (irregex-replace/all '(: bol (* space)) + (string-join lines) "")) + + (define (join-lines lines) + (apply string-append lines)) + + ) diff --git a/src/wrap.scm b/src/wrap.scm index 0ed8868..aa077d8 100644 --- a/src/wrap.scm +++ b/src/wrap.scm @@ -5,7 +5,7 @@ (jimmy util) (only (chicken io) read-string) (only (chicken port) with-output-to-string) - (only (chicken string) string-translate*)) + (only (chicken string) string-translate* string-intersperse)) ;; templates are strings with variables interpolated with "{{variables}}" diff --git a/tests/run.scm b/tests/run.scm index 1ec4ffe..49da815 100644 --- a/tests/run.scm +++ b/tests/run.scm @@ -1,80 +1,126 @@ (import scheme (chicken base) (chicken load) + (chicken pathname) (chicken port) (chicken process-context) test) +(define test-dir (or (get-environment-variable "TESTS") + "tests")) + ;;; Setup (import (jimmy emit) (jimmy read) #;(jimmy wrap)) -(define test-doc #< example.com with links! -and other things. +;;; Reading -## a code example -``` -for (a=1;a<=4;a++) { - printf("%d\n", a); -} -``` +(define test-file (make-pathname (list test-dir) "test" "gmi")) +(define expected-doc + '((meta ("title" "a" "test" "document") + ("date" "2024-05-13T03:02:45Z") + ("uuid" "b3daebf1-440b-4828-a4d9-9089c7bd7c61")) + (hdr1 ("a" "test" "document" "of" "some" "kind")) + (para ("here" "is" "a" "test" "document.") + ("it" "has" "paragraphs") + (link "example.com" "with" "links!") + ("and" "other" "things.")) + (hdr2 ("a" "code" "example")) + (verb ("for (a=1;a<=4;a++) {") ("\tprintf(\"%d\\n\", a);") ("}")) + (hdr3 ("other" "examples")) + (quot ("a" "blockquote" "is" "a" "quote") ("that" "is" "blocky.")) + (list ("list" "1") ("list" "2") ("list" "3")) + (link ("example.com" "link" "list" "1") + ("example.com" "link" "list" "2") + ("example.com" "link" "list" "3")) + (para ("ok," "now" "for" "another" "test:") + ("will" "*strong*" "in-line" "text" "be" "converted?") + ("as" "well" "as" "`code`," "_emph_" "and" "such?") + ("what" "if" "*i" "_nest_" "them*") + ("what" "if" "*i" "_nest" "them*" "wrong_" "?") + ("what" "about" "*breaking" "them") + ("over" "two" "lines?*")))) +(define actual-doc (with-input-from-file test-file parse)) -### other examples +(test "read" expected-doc actual-doc) -> a blockquote is a quote -> that is blocky. +(define doc expected-doc) -* list 1 -* list 2 -* list 3 -=> example.com link list 1 -=> example.com link list 2 -=> example.com link list 3 +;;; Emitting -ok, now for another test: -will *strong* in-line text be converted? -as well as `code`, _emph_ and such? -what if *i _nest_ them* -what if *i _nest them* wrong_ ? -what about *breaking them -over two lines?* -end-document -) +(test-group "gemini" + (define expected-gmi + (string-append "# a test document of some kind\n\n" + "here is a test document. it has paragraphs \n" + "=> example.com with links!\n" + "and other things.\n\n" + "## a code example\n\n" + "```\nfor (a=1;a<=4;a++) {\n" + "\tprintf(\"%d\\n\", a);" + "\n}\n```\n\n" + "### other examples\n\n" + "> a blockquote is a quote that is blocky.\n\n" + "* list 1\n" + "* list 2\n" + "* list 3\n\n" + "=> example.com link list 1\n" + "=> example.com link list 2\n" + "=> example.com link list 3\n\n" + "ok, now for another test: " + "will *strong* in-line text be converted? " + "as well as `code`, _emph_ and such? " + "what if *i _nest_ them* what if *i _nest them* wrong_ ? " + "what about *breaking them over two lines?*\n\n")) + (define actual-gmi (with-output-to-string (lambda () (emit doc)))) + (test "emit" expected-gmi actual-gmi)) -;;; Tests +;;; HTML -(test "read" - '((meta ("title" "a" "test" "document") - ("date" "2024-05-13T03:02:45Z") - ("uuid" "b3daebf1-440b-4828-a4d9-9089c7bd7c61")) - (hdr1 ("a" "test" "document" "of" "some" "kind")) - (para "here is a test document." "it has paragraphs" (link "example.com" - "with" - "links!") - "and other things.") - (hdr2 ("a" "code" "example")) - (verb "for (a=1;a<=4;a++) {" "\tprintf(\"%d\\n\", a);" "}") - (hdr3 ("other" "examples")) - (quot ("a" "blockquote" "is" "a" "quote") ("that" "is" "blocky.")) - (list ("list" "1") ("list" "2") ("list" "3")) - (link ("example.com" "link" "list" "1") ("example.com" "link" "list" - "2") ("example.com" "link" - "list" "3")) - (para "ok, now for another test:" "will *strong* in-line text be -converted?" "as well as `code`, _emph_ and such?" "what if *i _nest_ them*" -"what if *i _nest them* wrong_ ?" "what about *breaking them" "over two -lines?*")) - (call-with-input-string test-doc parse)) +(test-group "html" + (import (jimmy html)) + (define expected-html + (string-append "

    a test document of some kind

    \n" + "

    \n" + " here is a test document.\n" + " it has paragraphs\n" + " with links!\n" + " and other things.\n" + "

    \n" + "

    a code example

    \n" + "
    for (a=1;a<=4;a++) {\n"
    +                   "\tprintf(\"%d\\n\", a);\n"
    +                   "}\n"
    +                   "
    \n" + "

    other examples

    \n" + "
    \n" + " a blockquote is a quote\n" + " that is blocky.\n" + "
    \n" + "\n" + "\n" + "

    \n" + " ok, now for another test:\n" + " will strong in-line text be converted?\n" + " as well as code, emph and such?\n" + " what if i nest them\n" + " what if i nest them wrong ?\n" + " what about *breaking them\n" + " over two lines?*\n" + "

    \n")) + (define actual-html (with-output-to-string (lambda () (emit doc)))) + (test "emit html" expected-html actual-html)) +(test-end) (test-exit) -- cgit 1.4.1-21-gabe81