diff --git a/verso-web-components/VersoWeb/Components/Card/Learn.lean b/verso-web-components/VersoWeb/Components/Card/Learn.lean
index 9de43986c..6959c9e10 100644
--- a/verso-web-components/VersoWeb/Components/Card/Learn.lean
+++ b/verso-web-components/VersoWeb/Components/Card/Learn.lean
@@ -45,7 +45,7 @@ def learnCard [MonadStateOf Component.State m] [Monad m] (card : Card) : m Html
{{
if card.tags.isEmpty then .empty else
{{
}}
}}
diff --git a/verso-web-components/VersoWeb/Components/Title.lean b/verso-web-components/VersoWeb/Components/Title.lean
index d2c2c0bc5..d3f50f359 100644
--- a/verso-web-components/VersoWeb/Components/Title.lean
+++ b/verso-web-components/VersoWeb/Components/Title.lean
@@ -10,6 +10,7 @@ import VersoWeb.Components.Icon
namespace Verso.Web.Components
open Verso.Output Html
+open Lean (Html)
open Verso.Genre.Blog Template
def badge (content : String) (variant : String := "primary") : Html :=
@@ -33,12 +34,12 @@ block_component +directive pageTitle (level : Nat) (title : String) where
toHtml _ _ _ _ _ := do
saveCss (include_str "../../static/style/title.css")
- return Html.tag s!"h{level}" #[("class", "page-title")] (.text true title)
+ return Html.element s!"h{level}" #[("class", "page-title")] (.text title)
block_component +directive header (level : Nat) (title : String) where
toHtml _ _ _ _ _ := do
saveCss (include_str "../../static/style/title.css")
- return Html.tag s!"h{level}" #[("id", defaultPostName.slugify title)] (.text true title)
+ return Html.element s!"h{level}" #[("id", defaultPostName.slugify title)] (.text title)
end Verso.Web.Components
diff --git a/verso-web-components/VersoWeb/Features.lean b/verso-web-components/VersoWeb/Features.lean
index 37c4fede0..57fab1fef 100644
--- a/verso-web-components/VersoWeb/Features.lean
+++ b/verso-web-components/VersoWeb/Features.lean
@@ -13,7 +13,7 @@ open Verso Doc Elab
open Lean Elab
open Lean.Doc (CodeBlockView CodeView TextView)
open Verso.ArgParse
-open Verso.Output (Html)
+open Lean (Html)
private def codeblockContents (stx : TSyntax ``Lean.Doc.Parser.block) : Option String :=
match CodeBlockView.of stx with
@@ -117,7 +117,7 @@ partial def toml : CodeBlockExpander
where
infoHtml : SourceInfo → Html → Html
| .original leading _ trailing _, html =>
- .text false leading.toString ++ html ++ .text false trailing.toString
+ .raw leading.toString ++ html ++ .raw trailing.toString
| _, html => html
hl (cls : String) (html : Html) : Html := {{
}}
@@ -157,7 +157,7 @@ where
| .node info ``Lake.Toml.decInt elts => infoHtml info <| hl "num" <| elts.map highlightToml
| .node info ``Lake.Toml.array elts => infoHtml info <| elts.map highlightToml
| .node info ``Lake.Toml.inlineTable elts => infoHtml info <| elts.map highlightToml
- | .atom info str => infoHtml info (.text true str)
+ | .atom info str => infoHtml info (.text str)
| other => {{ "Failed to highlight TOML (probably highlightToml in Lang.Features needs another pattern case): " {{toString other}} }}
@@ -169,14 +169,14 @@ def collapsedDetails : DirectiveExpander
| args, contents => do
let summary ← ArgParse.run (.positional `summary .string) args
let blocks ← contents.mapM elabBlock
- let summary ← ``(Block.other (BlockExt.blob (Html.tag "summary" #[] #[Html.text true $(quote summary)])) #[])
+ let summary ← ``(Block.other (BlockExt.blob (Html.element "summary" #[] #[Html.text $(quote summary)])) #[])
pure #[← ``(Block.other (BlockExt.htmlWrapper "details" #[]) #[$summary, $blocks,*])]
@[directive_expander TODO]
def TODO : DirectiveExpander
| _, contents => do
let blocks ← contents.mapM elabBlock
- let header ← ``(Block.other (BlockExt.blob (Html.tag "h3" #[] #[Html.text true "TODO"])) #[])
+ let header ← ``(Block.other (BlockExt.blob (Html.element "h3" #[] #[Html.text "TODO"])) #[])
pure #[← ``(Block.other (BlockExt.htmlWrapper "div" #[("class", "TODO")]) #[$header, $blocks,*])]
@[role_expander TODO]
diff --git a/verso-web-components/VersoWeb/Theme/Head.lean b/verso-web-components/VersoWeb/Theme/Head.lean
index 9a5e3eef5..00f949679 100644
--- a/verso-web-components/VersoWeb/Theme/Head.lean
+++ b/verso-web-components/VersoWeb/Theme/Head.lean
@@ -140,7 +140,7 @@ def head (siteName : String) (rootTitle : String) (config : HeadConfig) (variabl
diff --git a/verso-web-components/VersoWeb/Theme/Post.lean b/verso-web-components/VersoWeb/Theme/Post.lean
index ea749d002..ce5798639 100644
--- a/verso-web-components/VersoWeb/Theme/Post.lean
+++ b/verso-web-components/VersoWeb/Theme/Post.lean
@@ -9,6 +9,7 @@ import VersoWeb.Components.ArchiveEntry
import VersoWeb.Components.Aside
open Verso Genre Blog Template Output Html
+open Lean (Html)
open Verso.Web Components Util Multi
namespace Verso.Web.Theme
@@ -31,7 +32,7 @@ def articleContent (title : Html) (content : Html) (metadata : Option Post.PartM
| none => Html.empty
| some md => {{
- {{(md : Post.PartMetadata).authors.map ({{
{{Html.text true ·}}
}}) |>.toArray}}
+ {{(md : Post.PartMetadata).authors.map ({{
{{Html.text ·}}
}}) |>.toArray}}
{{md.date.toIso8601String}}
diff --git a/verso-web-components/VersoWeb/Util.lean b/verso-web-components/VersoWeb/Util.lean
index 358f2bedb..826e4e0a1 100644
--- a/verso-web-components/VersoWeb/Util.lean
+++ b/verso-web-components/VersoWeb/Util.lean
@@ -11,7 +11,8 @@ import Std.Data.HashSet
namespace Verso.Web.Util
-open Verso.Output Html
+open Verso
+open Lean (Html)
open Verso Genre Blog Template ArgParse
/--
@@ -70,7 +71,7 @@ Sets an attribute on an HTML element only if the value is defined.
-/
def setAttributeOption (attr : String) (value : Option String) (html : Html) : Html :=
if let some value := value
- then setAttribute attr value html
+ then Html.setAttribute attr value html
else html
/--
@@ -85,8 +86,8 @@ Extract text content from HTML, removing all tags.
-/
def extractText (html : Html) : String :=
match html with
- | Html.text _ content => content
- | Html.tag _ _ contents => extractText contents
+ | Html.text content | Html.raw content => content
+ | Html.element _ _ contents => extractText contents
| Html.seq contents =>
contents.foldl (fun acc h => acc ++ extractText h) ""
@@ -116,14 +117,14 @@ Truncate HTML text content to a maximum length, adding "..." if truncated.
else acc ++ "..."
else buildResult newAcc rest
let truncatedText := buildResult "" words
- Html.text false truncatedText
+ Html.raw truncatedText
/--
Remove HTML wrapper and extract text content.
-/
partial def removeWrapper : Html → String
- | .text _ s => s
- | .tag _ _ h => removeWrapper h
+ | .text s | .raw s => s
+ | .element _ _ h => removeWrapper h
| .seq hs => String.intercalate " " (hs.toList.map removeWrapper)
/--
@@ -140,8 +141,9 @@ no leading slash) so that the permalink href resolves correctly against the Vers
-/
partial def addSlug (page : String) : Html → Html
| .seq h => .seq (h.map (addSlug page))
- | .text s e => .text s e
- | .tag t a h =>
+ | .text s => .text s
+ | .raw s => .raw s
+ | .element t a h =>
let findId (attrs : Array (String × String)) := (attrs.find? (·.1 == "id")).map (·.2)
let theresId (attrs : Array (String × String)) := attrs.any (·.1 == "id")
@@ -149,19 +151,19 @@ partial def addSlug (page : String) : Html → Html
| "h1" =>
let slug := findId a |>.getD (createSlug (removeWrapper h))
let finalAttrs := if theresId a then a else a.push ("id", slug)
- .tag "h1" finalAttrs h
+ .element "h1" finalAttrs h
| "h2" | "h3" | "h4" =>
let slug := findId a |>.getD (createSlug (removeWrapper h))
let finalAttrs := if theresId a then a else a.push ("id", slug)
let hasNoPermalink := a.any (fun (k, v) => k == "class" && v.splitOn.any (· == "no-permalink"))
if hasNoPermalink then
- .tag t finalAttrs h
+ .element t finalAttrs h
else
- let anchor := Html.tag "a" #[("href", s!"{page}#{slug}"), ("title", "Permalink")] #[Html.text false "🔗"]
- let widget := Html.tag "span" #[("class", "permalink-widget inline")] #[anchor]
- .tag t finalAttrs (.seq #[h, widget])
+ let anchor := Html.element "a" #[("href", s!"{page}#{slug}"), ("title", "Permalink")] #[Html.raw "🔗"]
+ let widget := Html.element "span" #[("class", "permalink-widget inline")] #[anchor]
+ .element t finalAttrs (.seq #[h, widget])
| _ =>
- .tag t a (addSlug page h)
+ .element t a (addSlug page h)
/--
Collect H1-H4 headings and build a table of contents.
@@ -170,7 +172,7 @@ partial def collectH1 (html : Html) (page : String) : Option Html :=
let res := (collect [] html |>.reverse)
if ¬ res.isEmpty then
let (html, _) := compact 2 res
- Html.tag "ol" #[] #[Html.seq (html.toArray |>.map (Html.tag "li" #[]))]
+ Html.element "ol" #[] #[Html.seq (html.toArray |>.map (Html.element "li" #[]))]
else
none
where
@@ -182,8 +184,8 @@ partial def collectH1 (html : Html) (page : String) : Option Html :=
| _ => 0
collect (col : List (Nat × String)) : Html → List (Nat × String)
- | .text _ _ => col
- | .tag t _ h =>
+ | .text _ | .raw _ => col
+ | .element t _ h =>
match t with
| "h1" | "h2" | "h3" | "h4" => (getLevel t, removeWrapper h) :: col
| _ => collect col h
@@ -193,10 +195,10 @@ partial def collectH1 (html : Html) (page : String) : Option Html :=
| (level, str) :: xs =>
if level = current then
let slug := createSlug str
- let headingLink := Html.tag "a" #[("href", s!"{page}#{slug}")] #[Html.text false str]
+ let headingLink := Html.element "a" #[("href", s!"{page}#{slug}")] #[Html.raw str]
let (children, remaining) := compactChildren (level + 1) xs
- let item := if children.isEmpty then headingLink else Html.seq #[headingLink, Html.tag "ol" #[] (Html.seq children.toArray)]
+ let item := if children.isEmpty then headingLink else Html.seq #[headingLink, Html.element "ol" #[] (Html.seq children.toArray)]
let (siblings, final) := compact level remaining
(item :: siblings, final)
@@ -211,7 +213,7 @@ partial def collectH1 (html : Html) (page : String) : Option Html :=
if level >= minLevel then
let (item, remaining) := compact level ((level, str) :: xs)
let (siblings, final) := compactChildren minLevel remaining
- (item.map (Html.tag "li" #[]) ++ siblings, final)
+ (item.map (Html.element "li" #[]) ++ siblings, final)
else
([], (level, str) :: xs)
| [] => ([], [])
@@ -219,8 +221,8 @@ partial def collectH1 (html : Html) (page : String) : Option Html :=
defmethod Html.classNames (html : Html) : Array String :=
let rec go (h : Html) (acc : Std.HashSet String) : Std.HashSet String :=
match h with
- | .text _ _ => acc
- | .tag _ attrs contents =>
+ | .text _ | .raw _ => acc
+ | .element _ attrs contents =>
let classAcc := attrs.foldl (fun acc (k, v) =>
if k == "class" then
-- Split class string by whitespace and add each class
diff --git a/verso/doc/UsersGuide/Output/HTML.lean b/verso/doc/UsersGuide/Output/HTML.lean
index adb7d31ec..dcf7fa994 100644
--- a/verso/doc/UsersGuide/Output/HTML.lean
+++ b/verso/doc/UsersGuide/Output/HTML.lean
@@ -15,6 +15,7 @@ open InlineLean
open Verso.Doc
open Verso.Output
+open Lean (Html)
open Verso.Code
@@ -26,24 +27,22 @@ tag := "output-html"
While most users of Verso don't need to worry about the specific details of the HTML that it produces, authors of new {tech}[genres] or of substantial extensions to existing genres may need to produce custom HTML.
Verso's HTML output follows a number of conventions and uses built-in libraries and features.
-Verso's {name}`Html` type represents HTML documents.
-They are typically produced using an embedded DSL that is available when the namespace `Verso.Output.Html` is opened.
+Lean's {name}`Html` type represents HTML documents.
+In Verso, they are typically produced using an embedded DSL that is available when the namespace `Verso.Output.Html` is opened.
{docstring Html}
{docstring Html.empty}
-{docstring Html.fromArray}
+{docstring Html.ofArray}
-{docstring Html.fromList}
+{docstring Html.ofList}
{docstring Html.append}
-{docstring Html.visitM}
+{docstring Html.rewritePostM}
-{docstring Html.format}
-
-{docstring Html.asString}
+{docstring Html.render}
HTML documents are written in double curly braces, in a syntax very much like HTML itself.
The differences are:
@@ -59,19 +58,12 @@ def mkList (xs : List Html) : Html :=
{{
}}
#eval mkList ["A", {{
"B"}}, "C"]
- |>.asString
+ |>.render
|> IO.println
```
```leanOutput htmllist
-
+
```
# Conventions
diff --git a/verso/doc/UsersGuide/Websites.lean b/verso/doc/UsersGuide/Websites.lean
index 116214076..57e48a79a 100644
--- a/verso/doc/UsersGuide/Websites.lean
+++ b/verso/doc/UsersGuide/Websites.lean
@@ -63,7 +63,7 @@ The URL layout of a site is specified via a {name Blog.Site}`Site`:
These are usually constructed using a small embedded configuration language.
A blog is rendered using a theme, which is a collection of templates.
-Templates are monadic functions that construct {name Verso.Output.Html}`Html` from a set of dynamically-typed parameters.
+Templates are monadic functions that construct {name Lean.Html}`Html` from a set of dynamically-typed parameters.
{docstring Blog.Theme}
diff --git a/verso/src/tests/VersoTests/GenericCode.lean b/verso/src/tests/VersoTests/GenericCode.lean
index 44f395989..c502e7707 100644
--- a/verso/src/tests/VersoTests/GenericCode.lean
+++ b/verso/src/tests/VersoTests/GenericCode.lean
@@ -42,21 +42,21 @@ info: Verso.Doc.Part.mk
#test_msgs in
#eval code1.toPart
/--
-info: Verso.Output.Html.tag
+info: Lean.Html.element
"section"
#[]
- (Verso.Output.Html.seq
- #[Verso.Output.Html.tag "h1" #[] (Verso.Output.Html.seq #[Verso.Output.Html.text true "More writing"]),
- Verso.Output.Html.tag
+ (Lean.Html.seq
+ #[Lean.Html.element "h1" #[] (Lean.Html.seq #[Lean.Html.text "More writing"]),
+ Lean.Html.element
"section"
#[]
- (Verso.Output.Html.seq
- #[Verso.Output.Html.tag "h2" #[] (Verso.Output.Html.seq #[Verso.Output.Html.text true "Section 1"]),
- Verso.Output.Html.tag "p" #[] (Verso.Output.Html.seq #[Verso.Output.Html.text true "Here's some code"]),
- Verso.Output.Html.tag
+ (Lean.Html.seq
+ #[Lean.Html.element "h2" #[] (Lean.Html.seq #[Lean.Html.text "Section 1"]),
+ Lean.Html.element "p" #[] (Lean.Html.text "Here's some code"),
+ Lean.Html.element
"pre"
#[]
- (Verso.Output.Html.text true "(define (zero f z) z)\n(define (succ n) (lambda (f x) (f (n f z))))\n")])])
+ (Lean.Html.text "(define (zero f z) z)\n(define (succ n) (lambda (f x) (f (n f z))))\n")])])
-/
#test_msgs in
#eval Doc.Genre.none.toHtml (m := Id) {} () () {} {} {} code1.toPart |>.run .empty |>.fst
diff --git a/verso/src/tests/VersoTests/HoverMerge.lean b/verso/src/tests/VersoTests/HoverMerge.lean
index 542871abf..5b075e8d7 100644
--- a/verso/src/tests/VersoTests/HoverMerge.lean
+++ b/verso/src/tests/VersoTests/HoverMerge.lean
@@ -11,7 +11,8 @@ meta import SubVerso.Highlighting
open SubVerso.Highlighting (Highlighted)
open Verso.Code (takeAttrs)
-open Verso.Output (Html)
+open Verso.Output
+open Lean (Html)
namespace Verso.HoverMergeTest
@@ -21,64 +22,64 @@ shares the token's extent: `Highlighted.normalize` makes the sole-token shape re
and `takeAttrs` moves the token's hover attributes up to the span.
-/
-def tok : Html := .tag "span" #[("class", "token"), ("data-verso-hover", "5")] (.text true "x")
-def tokNoHover : Html := .tag "span" #[("class", "token")] (.text true "x")
+def tok : Html := .element "span" #[("class", "token"), ("data-verso-hover", "5")] (.text "x")
+def tokNoHover : Html := .element "span" #[("class", "token")] (.text "x")
-- The attribute is taken from a bare element.
#test_guard takeAttrs #["data-verso-hover"] tok == (#[("data-verso-hover", "5")], tokNoHover)
-- The attribute is found through a wrapping element, such as a link.
-#test_guard takeAttrs #["data-verso-hover"] (.tag "a" #[("href", "x.html")] tok) ==
- (#[("data-verso-hover", "5")], .tag "a" #[("href", "x.html")] tokNoHover)
+#test_guard takeAttrs #["data-verso-hover"] (.element "a" #[("href", "x.html")] tok) ==
+ (#[("data-verso-hover", "5")], .element "a" #[("href", "x.html")] tokNoHover)
-- Attributes are gathered across the wrappers of a sole element: the hover from the token
-- and the extra links from the link element around it.
#test_guard takeAttrs #["data-verso-hover", "data-verso-links"]
- (.tag "a" #[("data-verso-links", "[]")] tok) ==
- (#[("data-verso-links", "[]"), ("data-verso-hover", "5")], .tag "a" #[] tokNoHover)
+ (.element "a" #[("data-verso-links", "[]")] tok) ==
+ (#[("data-verso-links", "[]"), ("data-verso-hover", "5")], .element "a" #[] tokNoHover)
-- Only the attributes that are present appear in the result.
#test_guard takeAttrs #["data-verso-hover", "data-verso-links"]
- (.tag "a" #[("data-verso-links", "[]")] tokNoHover) ==
- (#[("data-verso-links", "[]")], .tag "a" #[] tokNoHover)
+ (.element "a" #[("data-verso-links", "[]")] tokNoHover) ==
+ (#[("data-verso-links", "[]")], .element "a" #[] tokNoHover)
def tokLinked : Html :=
- .tag "span" #[("class", "token"), ("data-verso-hover", "5"), ("data-verso-links", "[2]")]
- (.text true "x")
+ .element "span" #[("class", "token"), ("data-verso-hover", "5"), ("data-verso-links", "[2]")]
+ (.text "x")
-- Each attribute is taken from the outermost element that carries it, and repeats on
-- elements nested inside stay in place.
#test_guard takeAttrs #["data-verso-hover", "data-verso-links"]
- (.tag "a" #[("data-verso-hover", "9")] tokLinked) ==
+ (.element "a" #[("data-verso-hover", "9")] tokLinked) ==
(#[("data-verso-hover", "9"), ("data-verso-links", "[2]")],
- .tag "a" #[] (.tag "span" #[("class", "token"), ("data-verso-hover", "5")] (.text true "x")))
+ .element "a" #[] (.element "span" #[("class", "token"), ("data-verso-hover", "5")] (.text "x")))
#test_guard takeAttrs #["data-verso-hover", "data-verso-links"]
- (.tag "a" #[("data-verso-links", "[1]")] tokLinked) ==
+ (.element "a" #[("data-verso-links", "[1]")] tokLinked) ==
(#[("data-verso-links", "[1]"), ("data-verso-hover", "5")],
- .tag "a" #[] (.tag "span" #[("class", "token"), ("data-verso-links", "[2]")] (.text true "x")))
+ .element "a" #[] (.element "span" #[("class", "token"), ("data-verso-links", "[2]")] (.text "x")))
-- The outermost attribute wins, and inner ones are left in place.
-#test_guard takeAttrs #["data-verso-hover"] (.tag "a" #[("data-verso-hover", "9")] tok) ==
- (#[("data-verso-hover", "9")], .tag "a" #[] tok)
+#test_guard takeAttrs #["data-verso-hover"] (.element "a" #[("data-verso-hover", "9")] tok) ==
+ (#[("data-verso-hover", "9")], .element "a" #[] tok)
-- Empty content around a sole element does not block the search.
-#test_guard takeAttrs #["data-verso-hover"] (.seq #[.text true "", tok, .seq #[]]) ==
+#test_guard takeAttrs #["data-verso-hover"] (.seq #[.text "", tok, .seq #[]]) ==
(#[("data-verso-hover", "5")], tokNoHover)
-- Adjacent content blocks the search, including whitespace.
-#test_guard takeAttrs #["data-verso-hover"] (.seq #[tok, .text true "y"]) ==
- (#[], .seq #[tok, .text true "y"])
+#test_guard takeAttrs #["data-verso-hover"] (.seq #[tok, .text "y"]) ==
+ (#[], .seq #[tok, .text "y"])
#test_guard takeAttrs #["data-verso-hover"] (.seq #[tok, tokNoHover]) == (#[], .seq #[tok, tokNoHover])
-#test_guard takeAttrs #["data-verso-hover"] (.seq #[.text true " ", tok]) ==
- (#[], .seq #[.text true " ", tok])
+#test_guard takeAttrs #["data-verso-hover"] (.seq #[.text " ", tok]) ==
+ (#[], .seq #[.text " ", tok])
-- Adjacent content inside a wrapper blocks the search.
-#test_guard takeAttrs #["data-verso-hover"] (.tag "a" #[] (.seq #[tok, tokNoHover])) ==
- (#[], .tag "a" #[] (.seq #[tok, tokNoHover]))
+#test_guard takeAttrs #["data-verso-hover"] (.element "a" #[] (.seq #[tok, tokNoHover])) ==
+ (#[], .element "a" #[] (.seq #[tok, tokNoHover]))
-- Content without the attributes is unchanged.
#test_guard takeAttrs #["data-verso-hover"] tokNoHover == (#[], tokNoHover)
-#test_guard takeAttrs #["data-verso-hover"] (.text true "x") == (#[], .text true "x")
+#test_guard takeAttrs #["data-verso-hover"] (.text "x") == (#[], .text "x")
#test_guard takeAttrs #["data-verso-hover"] (.seq #[]) == (#[], .seq #[])
def hlTok : Highlighted := .token ⟨.keyword none none none, "rfl"⟩
diff --git a/verso/src/tests/VersoTests/Html.lean b/verso/src/tests/VersoTests/Html.lean
index f8293079c..c99b22eb9 100644
--- a/verso/src/tests/VersoTests/Html.lean
+++ b/verso/src/tests/VersoTests/Html.lean
@@ -9,7 +9,7 @@ meta import all Verso.Output.Html
namespace Verso.Tests.Html
-open Verso.Output
+open Lean (Html)
open Verso.Output.Html
/-! ## Tests for HTML syntax macros -/
@@ -17,10 +17,10 @@ open Verso.Output.Html
private def testAttrs := {{
}}
/--
-info: Verso.Output.Html.tag
+info: Lean.Html.element
"html"
#[("charset", "UTF-8"), ("charset", "UTF-8"), ("a", "b"), ("a-b-c", "44"), ("x", "y")]
- (Verso.Output.Html.seq #[])
+ (Lean.Html.seq #[])
-/
#test_msgs in
#eval testAttrs
@@ -29,10 +29,10 @@ private def testAttrsAntiquotes :=
{{