-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathindex.htmel
98 lines (94 loc) · 5.03 KB
/
index.htmel
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
90
91
92
93
94
95
96
97
98
;; -*- lexical-binding: t; -*-
(require 'mel)
(defun +mel-print-md (node)
"Print NODE as markdown."
(if (stringp node) node
(pcase (car-safe node)
((or 'html 'body) (mapconcat #'+mel-print-md (nthcdr 2 node)))
((or 'p 'md) (concat (mapconcat #'+mel-print-md (nthcdr 2 node) "\n") "\n"))
((and 'div (guard (equal (alist-get 'class (nth 1 node)) "md")))
(car (last (car (last (nthcdr 2 node))))))
('img (format "<p align=\"center\">%s</p>\n\n" (let ((mel-print-functions))
(with-temp-buffer
(dom-print node)
(buffer-string)))))
('span (mapconcat #'+mel-print-md (nthcdr 2 node) " "))
('pre (concat "\n```" (car (split-string (alist-get 'class (nth 1 node)) " "))
(format "\n%s\n"
(with-temp-buffer
(insert (mapconcat (lambda (el) (format "%s" el))
(nthcdr 2 node) "\n"))
(indent-region (point-min) (point-max))
(buffer-substring-no-properties (point-min) (point-max))))
"```\n"))
('q (concat (mapconcat (lambda (el) (format "> %s" el)) (nthcdr 2 node) "\n") "\n"))
((and heading (pred symbolp)
(guard (string-match-p "h[[:digit:]]" (symbol-name heading))))
(format "\n%s %s\n\n"
(make-string (string-to-number (substring (symbol-name heading) 1)) ?#)
(mapconcat #'+mel-print-md (nthcdr 2 node) " ")))
(_ ""))))
(defun +mel-write-docs ()
(let ((name (buffer-file-name))
(mel-spec-functions
(list (mel-deftag md (.md ,(apply #'mel-markdown body)))
(mel-deftag example
(.example (pre.emacs-lisp ,(format "%S" (macroexp-progn body)))
(p "Returns:")
(pre.html ,(format "%s" (eval `(progn ,@body) t))))))))
(mel-write-html name "index.html"))
(let ((mel-print-functions '(+mel-print-md))
(mel-spec-functions '(+mel-example)))
(with-temp-buffer
(insert (mel (mel-read "index.htmel")))
(write-file "README.md"))))
(add-hook 'after-save-hook #'+mel-write-docs nil t)
`( html [:lang "en"]
(head
(meta[:charset UTF-8])
(link [:rel "stylesheet" :href "https://cdn.simplecss.org/simple.min.css"])
(style "pre { white-space: pre-line; } .center { margin: auto; }")
(title "MEL: Elisp HTML Templating"))
(body
(h1 "MEL: Elisp HTML Templating")
(img.center [ :src "./logo.png"
:alt "A honeycomb with the word 'mel' written in honey in the center."])
(q.center "Short and sweet HTML.")
(h2 "Usage")
(md "The `mel` function accepts any number of nodes and returns an HTML string."
"Each node is a list of the following form:")
(pre.emacs-lisp "(TAG [attribute val...] CHILDREN...)")
(h3 "Tags")
(md "`TAG` must be a symbol staring with the name of an HTML tag.")
(example (mel '(h1 "heading")))
(h3 "Classes")
(md "The `.` separator can be used in a tag symbol name to indicate a class.")
(example (mel '(h1.class "heading")))
(p "It may be used multiple times.")
(example (mel '(h1.one.two "heading")))
(md "As a special case, if a tag symbol begins with a `.`, a div tag is implied.")
(example (mel '(.class "content")))
(h3 "IDs")
(md "A single `#` separator can be used to associate an ID with a tag."
"Note that the separator must be escaped with a `\\` in elisp."
"The `@` separator is an alias for `#` which does not need to be escaped.")
(example (mel '(h1\#one "heading") '(h2@two "heading")))
(h3 "Attributes")
(p "An optional attribute vector may be added as the second element of a node list."
"Each attribute must be a symbol (optionally a keyword) followed by its value."
"The value will be coerced to its string representation.")
(example (mel '(h1 [:one "true" :two false] "heading")))
(h3 "Children")
(p "Any elements of a node specified after the tag and optional attribute vector are the node's children."
"They may be either strings or nodes.")
(example (mel '(p "example " (span "text"))))
(h2 "Tempalte Files")
(md "An `htmel` file must contain an emacs-lisp program."
"When evaluated, the return value of the last expression must be a mel spec for a document."
"For example, the source for this page is stored in [./index.htmel](./index.htmel).")
(md "A `mel` file is similar to an htmel file, but the return value of each top-level sexp is collected into a list."
"This is useful for including partial templates within other templates (see below).")
(h2 "File Inclusion")
(md "Content stored in other files can be included via the `mel-read` function.")
(md "The `mel-read` function can be used to parse and load files into a template.")
(example (mel-read "./include.mel"))))