| Crates.io | seam |
| lib.rs | seam |
| version | 0.4.3 |
| created_at | 2020-10-10 19:22:48.261707+00 |
| updated_at | 2024-12-28 18:10:58.498849+00 |
| description | Symbolic Expressions As Markup. |
| homepage | https://git.knutsen.co/seam |
| repository | |
| max_upload_size | |
| id | 298141 |
| size | 270,548 |
Symbolic Expressions As Markup.
Because all markup is terrible, especially XML/SGML and derivatives.
But mainly, for easier static markup code generation, such as by macros and code includes and such.
This may be used as a Rust library, such as from within a server,
generating HTML (or any other supported markup) before it is served to the
client. Personally, I just use the seam binary to statically
generate my personal websites through a Makefile.
Read the USAGE.md file for code examples and documentation.
--xml; including: SVG, MathML)--html; SGML)--css)--sexp; S-expression, basically a macro expansion utility)--text; renders escaped strings to text)You may clone the repo, then build and install by
git clone git://git.knutsen.co/seam
cd seam
cargo build --release
cargo install --path .
Or install it from crates.io
cargo install seam
Either way, you'll need the Rust (nightly) compiler and along
with it, comes cargo.
You may use it by passing in a file and piping from STDOUT.
seam test.sex --html > test.html
test.sex contains your symbolic-expressions, which is used to generate
HTML, saved in test.html.
Likewise, you may read from STDIN
seam --html < example.sex > example.html
# ... same as
cat example.sex | seam --html > example.html
You may also use here-strings or here-docs, if your shell supports it.
seam --html <<< "(p Hello World)"
#stdout:
# <!DOCTYPE html>
# <html>
# <head></head>
# <body>
# <p>Hello World</p>
# </body>
# </html>
seam --html --nodocument <<< "(p Hello World)"
#stdout:
# <p>Hello World</p>
seam --xml <<< '(para Today is a day in (%date "%B, year %Y").)'
#stdout:
# <?xml version="1.0" encoding="UTF-8" ?>
# <para>Today is a day in November, year 2020.</para>
seam --sexp <<< '(hello (%define subject world) %subject)'
#stdout:
# (hello world)
(% and ) pair, i.e. when calling a macro.
So hello world (earth) (%do (p letter "\x61")) "\x61" turns in to (in HTML mode)
hello world <earth></earth> <p>hi a</p> a normally, but in literate (HTML) mode turns into
hello world (earth) <p>letter a</p> "\x61". Parentheses and quotes have been preserved.
Markdown source in (%markdown ...) should be parsed as literate files by default.
Provide command line --literate option; %include and %embed should also have options for enabling literate mode.(%define dict (:a 1 :b 2 :c 3)):
- (%for (kw val) in (%items %dict) (%log %kw = %val))
- (%for kw in (%keys %dict) (%log %kw = (%get %kw %dict)))
- (%for val in (%values %dict) (%log ___ = %val))%get to work with slicing (%get (1 3) (a b c d e)) becomes b c d; negative indices (%get -1 (a b c)) becomes c.${var:...} string manipulation.%while, %take, %drop, %split on symbols in lists, %intercalate.(%basename :suffix "txt" /path/file.txt) (-> file), (%dirname /path/file.txt) (-> /path) and (%extension /path/file.txt) (-> txt), macros for paths.+, -, *, /, mod, pow, exp, sqrt, log, ln, hypot.(%error msg) macro for aborting compilation.(%reverse (...)).(%symbol lit), (%number lit), (%string lit), (%raw lit).(%sort (...)) which sorts alphanumerically on literals.
Allow providing a :key to sort "by field": e.g. sort by title name (%sort :key (%lambda ((:title _ &&_)) %title) %posts)(%date) to be able to read UNIX numeric timestamps and display relative to timezones.
Add complementary strptime-style utility (%timestamp) to convert date-strings to timestamps (relative to a timezone).(%match expr (pat1 ...) (pat2 ...)) macro.
Pattern matching is already implemented for %define internally.&&rest matches excess keyword.
Extracting a value from a map (:a 1 :b 2 :c 3) is done with:
(%match %h ((:b default &&_) %b)).%get macro: (%get b (:a 1 :b 2)) becomes 2; (%get 0 (a b c)) becomes a.(%yaml "..."), (%toml "...") and (%json "...") converts
whichever config-lang definition into a seam %define-definition.(%do ...) which just expands to the ...; the identity function.(%try :catch index-error (%do code-to-try) :error the-error (%do caught-error %the-error)).(%strip ...) which evaluates to the ... without any of the leading whitespace.(%splat (a b c)) becomes a b c.(%define x %body) evaluates %body eagerly (at definition),
while (%define (y) %body) only evaluates %body per call-site (%y).(%namespace ns (%include "file.sex")) will prefix all definitions in its body with ns/, e.g. %ns/defn.
Allows for a customizable separator, e.g. (%namespace ns :separator "-" ...) will allow for writing %ns-defn.
Otherwise, the macro leaves the content produced by the body completely unchanged.-I include directory.(%os/env ENV_VAR) environment variable macro.ifdef) with use of new (%eval ...) macro.(%apply name x y z) macro which is equivalent to (%name x y z).(%lambda (x y) ...) macro which just evaluates to an secret symbol, e.g. __lambda0.
used by applying %apply, e.g. (%apply (%lambda (a b) b a) x y) becomes y x(%string ...), (%join ...), (%map ...), (%filter ...) macros.(%concat ...) which is just (%join "" ...).%glob for sorting by type, date(s), name, etc.(%format "{}") macro with Rust's format syntax. e.g. (%format "Hello {}, age {age:0>2}" "Sam" :age 9)(%raw ...) macro which takes a string and leaves it unchanged in the final output.(%formatter/text ...) can take any seam (sexp) source code, for which it just embeds the expanded code (plain-text formatter).(%formatter/html ...) etc. which call the respective available formatters.(%embed "/path") macro, like %include, but just returns the file contents as a string.&rest syntax.%list macro which expands from (%list %a %b %c) to ( %a %b %c ) but without calling %a as a macro with %b and %c as argument.%for-loop macro, iterating over %lists.%glob which returns a list of files/directories matching a glob.%markdown renders Markdown given to it as %raw html-string.style="..." object should handle s-expressions well, (e.g. (p :style (:color red :border none) Hello World))JSON, JS, TOML, &c.).(%chez (+ 1 2)) executes
(+ 1 2) with Chez-Scheme LISP, and places the result in the source (i.e. 3).