182 lines
No EOL
6.6 KiB
HTML
182 lines
No EOL
6.6 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<title>CLiki: cl-markup</title>
|
|
<link rel="alternate" type="application/atom+xml" title="ATOM feed of edits to current article"
|
|
href="https://www.cliki.net/site/feed/article.atom?title=cl-markup">
|
|
<link rel="stylesheet" href="static/css/style.css">
|
|
<link rel="stylesheet" href="static/css/colorize.css">
|
|
</head>
|
|
|
|
<body>
|
|
<span class="hidden">CLiki - cl-markup</span>
|
|
<div id="content"><div id="content-area"><div id="article-title">cl-markup</div><div id="article">CL-MARKUP - Modern <a href="HTML generator.html" class="category">HTML generator</a> library for Common Lisp.<p><ul>
|
|
<li>Fast (even faster if you compile it)
|
|
</li>
|
|
<li>Safety
|
|
</li>
|
|
<li>Support multiple document types (markup, xml, html, xhtml)
|
|
</li>
|
|
<li>Output with doctype
|
|
</li>
|
|
<li>Direct output to stream
|
|
</li>
|
|
</ul><p>Homepage: <a href="https://github.com/arielnetworks/cl-markup">https://github.com/arielnetworks/cl-markup</a><p>License: <a href="LLGPL.html" class="category">LLGPL</a><p><h2>Some experiments:</h2><p><pre>(defpackage :cl-markup-test (use :cl))
|
|
|
|
(in-package :cl-markup-test)
|
|
|
|
;; central feature is MARKUP:
|
|
|
|
(markup (:p 123))
|
|
=> "<p>123</p>"
|
|
|
|
;; MARKUP expects list arguments, atoms are being rejected
|
|
|
|
(markup "abc")
|
|
=> The value "abc" is not of type LIST.
|
|
[Condition of type TYPE-ERROR]
|
|
|
|
;; arguments can be multiple lists
|
|
|
|
(markup (:p 123) (:p 234))
|
|
=> "<p>123</p><p>234</p>"
|
|
|
|
;; first element of list is used as tag, not bothering what type it is
|
|
;; and wether it smells like HTML
|
|
|
|
(markup ("p" 123))
|
|
=> "<p>123</p>"
|
|
|
|
(markup (p 123))
|
|
=> "<p>123</p>"
|
|
|
|
(markup ('p 123))
|
|
=> "<'p>123</'p>" ; oops
|
|
|
|
(markup (123 p))
|
|
=> error: The variable P is unbound.
|
|
[Condition of type UNBOUND-VARIABLE]
|
|
|
|
(markup (123 "p"))
|
|
=> "<123>p</123>" ; !!
|
|
|
|
;; whole HTML pages can be produced with cl-markup macros HTML, HTML5,
|
|
;; XHTML and XML.
|
|
|
|
(html5 (:p 42))
|
|
=> "<!DOCTYPE html><html><p>42</p></html>"
|
|
|
|
;; lisp expressions can be inserted everywhere except first position of list
|
|
|
|
(markup (:p (concatenate 'string "1" "2" "3")))
|
|
=> "<p>123</p>"
|
|
|
|
;; these expressions are considered good citizens when they produce
|
|
;; string results, else:
|
|
|
|
(markup (:p (+ 100 20 3)))
|
|
=> The value 123 is not of type STRING.
|
|
[Condition of type TYPE-ERROR]
|
|
|
|
;; weird things seem to happen when combining snippets
|
|
|
|
(let ((snip (markup (:p "abc"))))
|
|
(markup (:div snip)))
|
|
=> "<div>&lt;p&gt;abc&lt;/p&gt;</div>" ; !!
|
|
|
|
;; This is a feature called auto-escape and it provides correct
|
|
;; solutions for these kind of tasks:
|
|
|
|
(markup (:p "1<3"))
|
|
=> "<p>1&lt;3</p>"
|
|
|
|
(markup (:p "R&B"))
|
|
=> "<p>R&amp;B</p>"
|
|
|
|
;; auto-escaping can be turned off like this
|
|
|
|
(let* ((*auto-escape* nil)
|
|
(snip (markup (:p "abc"))))
|
|
(markup (:div snip)))
|
|
=> "<div><p>abc</p></div>"
|
|
|
|
;; another way to shelter strings against greedy auto-escape
|
|
;; is wrapping them in a list
|
|
|
|
(let ((snip (markup (:p "abc"))))
|
|
(markup (:div (list snip))))
|
|
=> "<div><p>abc</p></div>"
|
|
|
|
;; same result using backquote syntax
|
|
|
|
(let ((snip (markup (:p "abc"))))
|
|
(markup (:div `(,snip))))
|
|
=> "<div><p>abc</p></div>"
|
|
|
|
;; and this can also be done with CL-MARKUPs RAW macro. RAW sounds
|
|
;; like a kind of strange name for a list-wrapping feature. Maybe the
|
|
;; name tries to express that this procedure treats the string
|
|
;; like the raw markup from which it evolved.
|
|
|
|
(let ((snip (markup (:p "abc"))))
|
|
(markup (:div (raw snip))))
|
|
=> "<div><p>abc</p></div>"
|
|
|
|
;; and now for the best of all: it is possible to write cl macros
|
|
;; producing HTML snippets.
|
|
|
|
(defmacro snip (name)
|
|
`(markup (:p ,name)))
|
|
|
|
(snip "foo")
|
|
=> "<p>foo</p>"
|
|
|
|
;; It is save to handle string results.
|
|
|
|
;; Trying to pass markup asks for trouble
|
|
|
|
(defmacro snip-markup (name)
|
|
`(:p ,name))
|
|
|
|
(markup (snip-markup "foo"))
|
|
=> "<snip-markup>foo</snip-markup>" ;; oops
|
|
|
|
;; MARKUP is a macro, it does not evaluate its arguments</pre></div></div>
|
|
<div id="footer" class="buttonbar"><ul><li><a href="cl-markup.html">Current version</a></li>
|
|
<li><a href="https://www.cliki.net/site/history?article=cl-markup">History</a></li>
|
|
<li><a href="https://www.cliki.net/site/backlinks?article=cl-markup">Backlinks</a></li><li><a href="https://www.cliki.net/site/edit-article?title=cl-markup&from-revision=3655983279">Edit</a></li><li><a href="https://www.cliki.net/site/edit-article?create=t">Create</a></li></ul></div>
|
|
</div>
|
|
<div id="header-buttons" class="buttonbar">
|
|
<ul>
|
|
<li><a href="https://www.cliki.net/">Home</a></li>
|
|
<li><a href="https://www.cliki.net/site/recent-changes">Recent Changes</a></li>
|
|
<li><a href="CLiki.html">About</a></li>
|
|
<li><a href="Text Formatting.html">Text Formatting</a></li>
|
|
<li><a href="https://www.cliki.net/site/tools">Tools</a></li>
|
|
</ul>
|
|
<div id="search">
|
|
<form action="https://www.cliki.net/site/search">
|
|
<label for="search_query" class="hidden">Search CLiki</label>
|
|
<input type="text" name="query" id="search_query" value="" />
|
|
<input type="submit" value="search" />
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<div id="pageheader">
|
|
<div id="header">
|
|
<span id="logo">CLiki</span>
|
|
<span id="slogan">the common lisp wiki</span>
|
|
<div id="login"><form method="post" action="https://www.cliki.net/site/login">
|
|
<label for="login_name" class="hidden">Account name</label>
|
|
<input type="text" name="name" id="login_name" class="login_input" />
|
|
<label for= "login_password" class="hidden">Password</label>
|
|
<input type="password" name="password" id="login_password" class="login_input" />
|
|
<input type="submit" name="login" value="login" id="login_submit" /><br />
|
|
<div id="register"><a href="https://www.cliki.net/site/register">register</a></div>
|
|
<input type="submit" name="reset-pw" value="reset password" id="reset_pw" />
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body></html> |