Compare commits

..

62 Commits

Author SHA1 Message Date
Tom Alexander
b06798f23f Prepare for publishing to crates.io. 2023-12-21 19:40:28 -05:00
Tom Alexander
35dff5cdaf Rename to natter. 2023-12-21 19:28:31 -05:00
Tom Alexander
d641c8d638 Merge branch 'pretty' 2023-12-21 18:36:23 -05:00
Tom Alexander
7e2fd70212 Style the homepage. 2023-12-21 18:34:42 -05:00
Tom Alexander
4fb08bc7d0 Wrap inline footnote definitions in a paragraph tag.
This is to match the behavior of the upstream org html exporter.
2023-12-21 18:09:43 -05:00
Tom Alexander
01b55b7256 Make paragraphs under footnote definitions display inline.
This seems to be the behavior of the upstream org html exporter.
2023-12-21 17:44:40 -05:00
Tom Alexander
bd68681e44 Increase the size of headlines.
This is to make them stand out more from the regular text.
2023-12-21 17:31:19 -05:00
Tom Alexander
27ff13e675 Also special-case plain list items containing only paragraphs and sublists.
This seems to be the behavior of the upstream org html exporter.
2023-12-21 17:27:19 -05:00
Tom Alexander
2914e42ba1 For plain list items with a single child that is a paragraph, do not wrap in paragraph html tags.
This is mimicking the behavior from org-mode's HTML exporter.
2023-12-21 17:18:51 -05:00
Tom Alexander
a8969f141d Style code and verbatim. 2023-12-21 16:49:44 -05:00
Tom Alexander
6f049e00d4 Style inline source blocks. 2023-12-21 16:42:22 -05:00
Tom Alexander
45a1076d18 Style descriptive plain lists. 2023-12-21 16:39:26 -05:00
Tom Alexander
775c88d67a Style footnotes. 2023-12-21 15:44:56 -05:00
Tom Alexander
efbf6cfc0c Style ordered and unordered plain lists. 2023-12-21 15:31:13 -05:00
Tom Alexander
5af4a372ae Make object trailing space dependent on post_blank. 2023-12-21 15:13:07 -05:00
Tom Alexander
72952adb6b Add post_blank to the rust types. 2023-12-21 15:09:13 -05:00
Tom Alexander
8b85c02ef1 Wrap the intermediate Registry in an IntermediateContext.
This is currently just to maintain consistency with the render phase's RenderContext but in the future it should allow us to include immutable data that is not locked behind the ArcMutex.
2023-12-21 13:53:56 -05:00
Tom Alexander
2ae4839ce0 Remove common whitespace prefix from src block lines. 2023-12-21 13:16:05 -05:00
Tom Alexander
5654c40d03 Get the real language for src blocks from the org source. 2023-12-21 12:07:36 -05:00
Tom Alexander
b538750287 Preserve whitespace in src blocks. 2023-12-21 12:04:29 -05:00
Tom Alexander
65ed754bfe Space out some elements. 2023-12-19 21:57:33 -05:00
Tom Alexander
80cdf5166b Style quote blocks, h2, and h3. 2023-12-19 21:41:41 -05:00
Tom Alexander
3968121d54 Style src blocks. 2023-12-19 21:30:59 -05:00
Tom Alexander
a29b625631 Apply a dark background. 2023-12-19 20:33:21 -05:00
Tom Alexander
e193fcc2ba Start applying styles to blog posts. 2023-12-19 19:23:56 -05:00
Tom Alexander
050b426f6f Merge branch 'homepage' 2023-12-19 18:08:50 -05:00
Tom Alexander
da81f93e4a Re-enable the CSS reset sheet. 2023-12-19 18:06:52 -05:00
Tom Alexander
1581e5c401 Rename the output root directory in the render context. 2023-12-19 18:03:59 -05:00
Tom Alexander
2e1c979127 Add a prefix to footnote IDs.
This avoids a conflict with multiple blog posts rendering in the same stream.
2023-12-19 18:01:54 -05:00
Tom Alexander
d4b290ebe6 Remove unnecessary let statements from render macro. 2023-12-19 17:31:50 -05:00
Tom Alexander
4bb1f9983a Standardize the construction of intermediate BlogPostPage. 2023-12-19 17:31:16 -05:00
Tom Alexander
261fe8a1a2 Fix the links to the blog posts. 2023-12-19 16:49:46 -05:00
Tom Alexander
add267d616 Switch over to using the render context in render calls. 2023-12-19 16:20:12 -05:00
Tom Alexander
cb3278aba5 Create a struct that will combine all the context for converting intermediate objects into the dust render context. 2023-12-19 14:54:12 -05:00
Tom Alexander
94d9a95967 Add a basic template for the blog stream page. 2023-12-19 14:13:29 -05:00
Tom Alexander
6511115b95 Implement a flawed version of RenderBlogStreamEntry::new.
There are some shortcomings in this implementation listed in the comments, but this is the general structure.
2023-12-19 10:59:34 -05:00
Tom Alexander
53cd55932b Implement RenderBlogStream::new.
I still need to implement RenderBlogStreamEntry::new.
2023-12-19 10:47:03 -05:00
Tom Alexander
cbe2010407 Invoke dust to render the stream pages.
At this point the render_blog_stream function is done, but RenderBlogStream::new needs to be implemented to actually generate the render context. The body of this function should be similar to convert_blog_post_page_to_render_context.
2023-12-17 17:26:15 -05:00
Tom Alexander
2ba4a5e3d7 Generate newer and older links. 2023-12-17 17:16:26 -05:00
Tom Alexander
c3482cf1e4 Chunking the blog posts for the stream. 2023-12-17 16:57:37 -05:00
Tom Alexander
fdf84e3d0b Finding the index page. 2023-12-17 15:45:50 -05:00
Tom Alexander
0a4376dfb8 Rename intermediate blog post source file. 2023-12-17 15:32:07 -05:00
Tom Alexander
e8ed4a4f4a Initial structure for rendering a blog post stream. 2023-12-17 15:32:07 -05:00
Tom Alexander
60555999db TEMP: Disable the css reset.
This is so I can develop the header without having any CSS written yet since the page is a mess without CSS.
2023-12-17 14:56:23 -05:00
Tom Alexander
6968a5b02c Merge branch 'header' 2023-12-17 14:47:45 -05:00
Tom Alexander
c84cfdc02b Basic template for a page header. 2023-12-17 14:45:42 -05:00
Tom Alexander
c98489cacb Add the page header to the render context. 2023-12-17 14:45:42 -05:00
Tom Alexander
35dbab0ceb Create a page header struct. 2023-12-17 14:45:42 -05:00
Tom Alexander
1ff41940a5 Merge branch 'css' 2023-12-17 14:02:20 -05:00
Tom Alexander
884215a7e1 Writing the stylesheets to the output folder. 2023-12-17 13:46:47 -05:00
Tom Alexander
20c55f0708 Loading stylesheets from the default environment. 2023-12-17 12:43:47 -05:00
Tom Alexander
9e3d72972c Add a CSS reset file. 2023-12-17 11:55:38 -05:00
Tom Alexander
806c45a453 Switch back to the published version of organic. 2023-12-17 11:54:59 -05:00
Tom Alexander
270c42a509 Update to use get_value from the latest organic code. 2023-10-31 22:03:22 -04:00
Tom Alexander
e8963e107b Merge branch 'table' 2023-10-31 20:38:36 -04:00
Tom Alexander
0b64551a23 Add templates for tables. 2023-10-31 20:31:36 -04:00
Tom Alexander
b654ca4859 Add render phase to tables. 2023-10-31 20:29:37 -04:00
Tom Alexander
386af57ce6 Add intermediate stage for tables. 2023-10-31 20:26:34 -04:00
Tom Alexander
ef4d315bf2 Run cargo fix. 2023-10-31 20:02:46 -04:00
Tom Alexander
2142b01967 Merge branch 'text_markup' 2023-10-31 20:02:13 -04:00
Tom Alexander
159d8fb72a Add render stage for text markup. 2023-10-31 20:02:04 -04:00
Tom Alexander
0fae417610 Add intermediate stage for text markup. 2023-10-31 19:57:04 -04:00
170 changed files with 2807 additions and 1598 deletions

124
Cargo.lock generated
View File

@@ -17,15 +17,6 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
[[package]]
name = "anstream"
version = "0.6.4"
@@ -188,7 +179,8 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "duster"
version = "0.1.1"
source = "git+https://code.fizz.buzz/talexander/duster.git?branch=master#3428a3f5097c7d2cc252d1bfd9aae7771553ab69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17d19cdf8e1ae4aead0978a30e99817af1c36abaf22f81901952b1310abb6989"
dependencies = [
"nom 6.1.2",
"serde",
@@ -355,12 +347,6 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lexical-core"
version = "0.7.6"
@@ -401,6 +387,22 @@ dependencies = [
"adler",
]
[[package]]
name = "natter"
version = "0.0.1"
dependencies = [
"clap",
"duster",
"futures",
"include_dir",
"organic",
"serde",
"serde_json",
"tokio",
"toml",
"walkdir",
]
[[package]]
name = "nom"
version = "6.1.2"
@@ -445,7 +447,9 @@ dependencies = [
[[package]]
name = "organic"
version = "0.1.12"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61b01691695303b42f9a2ff318bec83853fbeb65c96569f2fb391e7636801c6"
dependencies = [
"nom 7.1.3",
"walkdir",
@@ -487,35 +491,6 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
[[package]]
name = "regex"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "rustc-demangle"
version = "0.1.23"
@@ -609,26 +584,6 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "thiserror"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tokio"
version = "1.33.0"
@@ -675,26 +630,6 @@ dependencies = [
"winnow",
]
[[package]]
name = "tree-sitter"
version = "0.20.10"
source = "git+https://github.com/tree-sitter/tree-sitter.git?rev=52f7eaff3182a726eb064a91d4e49dfbaecd4ee3#52f7eaff3182a726eb064a91d4e49dfbaecd4ee3"
dependencies = [
"cc",
"regex",
]
[[package]]
name = "tree-sitter-highlight"
version = "0.20.2"
source = "git+https://github.com/tree-sitter/tree-sitter.git?rev=52f7eaff3182a726eb064a91d4e49dfbaecd4ee3#52f7eaff3182a726eb064a91d4e49dfbaecd4ee3"
dependencies = [
"lazy_static",
"regex",
"thiserror",
"tree-sitter",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
@@ -829,23 +764,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "writer"
version = "0.0.1"
dependencies = [
"clap",
"duster",
"futures",
"include_dir",
"organic",
"serde",
"serde_json",
"tokio",
"toml",
"tree-sitter-highlight",
"walkdir",
]
[[package]]
name = "wyz"
version = "0.2.0"

View File

@@ -1,19 +1,32 @@
[package]
name = "writer"
name = "natter"
version = "0.0.1"
edition = "2021"
authors = ["Tom Alexander <tom@fizz.buzz>"]
description = "A static site generator using org source files."
license = "0BSD"
repository = "https://code.fizz.buzz/talexander/natter"
readme = "README.md"
keywords = ["static", "site", "generator"]
categories = ["command-line-utilities"]
resolver = "2"
include = [
"LICENSE",
"**/*.rs",
"Cargo.toml",
"Cargo.lock",
"default_environment/"
]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "4.4.6", default-features = false, features = ["std", "color", "help", "derive"] }
duster = { git = "https://code.fizz.buzz/talexander/duster.git", branch = "master" }
tree-sitter-highlight = { git = "https://github.com/tree-sitter/tree-sitter.git", rev = "52f7eaff3182a726eb064a91d4e49dfbaecd4ee3" }
duster = "0.1.1"
futures = "0.3.29"
include_dir = "0.7.3"
# TODO: This is temporary to work on the latest organic code. Eventually switch back to using the published crate.
organic = { path = "../organic" }
# organic = "0.1.12"
# organic = { path = "../organic" }
organic = "0.1.13"
serde = { version = "1.0.189", default-features = false, features = ["std", "derive"] }
serde_json = "1.0.107"
tokio = { version = "1.30.0", default-features = false, features = ["rt", "rt-multi-thread", "fs", "io-util"] }

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# Natter
Natter is a static site generator for blogs using org as an input format. It is at a very early stage, and will have deep sweeping changes.

View File

@@ -0,0 +1,187 @@
:root {
--main-max-width: 800px;
--site-background-color: #0a0a0a;
--site-text-color: #fffffc;
--header-divider-color: #6a687a;
--stream-divider-color: #6ccff6;
--src-font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;
--src-block-background-color: #141414;
--src-block-border-color: #84828f;
--src-block-language-color: #0a0a0a;
--src-block-language-background: #84828f;
--quote-block-border-color: #84828f;
}
body {
color: var(--site-text-color);
background-color: var(--site-background-color);
font-family: source-sans-pro, Seravek, 'Gill Sans Nova', Ubuntu, Calibri, 'DejaVu Sans', sans-serif;
a:link, a:visited {
/* TODO: Should I use a different color for links? */
color: var(--site-text-color);
}
}
.page_centering {
display: flex;
flex-direction: column;
align-items: center;
}
.page_header {
width: 100%;
max-width: var(--main-max-width);
border-bottom: 0.1rem solid var(--header-divider-color);
.home_link {
font-size: 1.2rem;
font-weight: 600;
text-decoration: none;
&:link, &:visited {
color: var(--site-text-color);
}
}
}
.main_content {
width: 100%;
max-width: var(--main-max-width);
font-size: 1.2rem;
line-height: 1.2;
/* A stand-alone blog post (not in a blog stream). */
.blog_post {
padding: 1rem 0 3rem 0;
}
.blog_stream {
.stream_divider {
color: var(--stream-divider-color);
}
}
/* A blog post in a blog stream (for example, the homepage). */
.blog_stream_post {
background: #1F1F1F;
padding: 1rem 0.2rem;
}
.blog_post_title {
font-size: 2.5rem;
font-weight: 700;
padding-bottom: 1rem;
}
p {
margin: 1rem 0;
}
.src_block {
background: var(--src-block-background-color);
border-radius: 3px;
border: 1px solid var(--src-block-border-color);
font-size: 1rem;
font-family: var(--src-font-family);
margin: 1rem 0;
.src_language {
display: inline-block;
color: var(--src-block-language-color);
background: var(--src-block-language-background);
border-radius: 0 0 3px 0;
padding: 0.1rem 0.5rem;
font-size: 0.8rem;
vertical-align: top;
}
.src_body {
margin: 0.5rem;
.src_line {
white-space: pre-wrap;
}
}
}
.inline_source_block {
font-family: var(--src-font-family);
font-size: 1rem;
}
.code, .verbatim {
font-family: var(--src-font-family);
font-size: 1rem;
}
.quote_block {
border-left: 1px solid var(--quote-block-border-color);
padding: 0 0 0 1rem;
margin: 1rem 0 1rem 2rem;
}
h2, h3 {
margin: 1rem 0;
padding-bottom: 0.5rem;
}
h2 {
font-size: 2.3rem;
font-weight: 600;
}
h3 {
font-size: 2.1rem;
font-weight: 600;
}
.plain_list {
&.unordered {
list-style-type: disc;
padding-left: 2.5rem;
}
&.ordered {
list-style-type: decimal;
padding-left: 2.5rem;
}
&.descriptive {
font-size: 1rem;
> dt {
font-weight: 600;
}
> dd {
padding-left: 2.5rem;
}
}
}
.footnote_reference {
vertical-align: super;
font-size: 80%;
> a {
text-decoration: none;
}
}
.footnote_definition {
.label {
text-decoration: none;
}
.definition {
display: inline;
> p {
display: inline;
}
}
}
}

View File

@@ -0,0 +1,48 @@
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}

View File

@@ -1,8 +1,6 @@
<div class="blog_post">
<div class="blog_post_intro">
{?.title}{?.self_link}<a class="blog_post_title" href="{.link}">{.title}</a>{:else}<div class="blog_post_title">{.title}</div>{/.self_link}{/.title}
<article class="blog_post">
{?.title}<h1 class="blog_post_title"><span>{.title}</span></h1>{/.title}
{! TODO: date? !}
</div>
{! TODO: Table of contents? !}
@@ -18,4 +16,4 @@
{/.footnotes}
{/.footnotes}
</div>
</div>
</article>

View File

@@ -0,0 +1,32 @@
<div class="blog_stream">
{#.children}
{@gt key=$idx value=0}<hr class="stream_divider" />{/gt}
<div class="blog_stream_post">
<div class="blog_post_intro">
{?.title}{?.self_link}<a class="blog_post_title" href="{.self_link}">{.title}</a>{:else}<div class="blog_post_title">{.title}</div>{/.self_link}{/.title}
{! TODO: date? !}
</div>
{! TODO: Table of contents? !}
<div class="blog_post_body">
{#.children}
{>document_element/}
{/.children}
{?.footnotes}
<h2>Footnotes:</h2>
{#.footnotes}
{>real_footnote_definition/}
{/.footnotes}
{/.footnotes}
</div>
</div>
{/.children}
{#.stream_pagination}
<div class="stream_nav">
{?.older_link}<a href="{.older_link}">Older</a>{/.older_link}
{?.newer_link}<a href="{.newer_link}">Newer</a>{/.newer_link}
</div>
{/.stream_pagination}
</div>

View File

@@ -1 +1 @@
<code>{.source}</code>
<code class="code">{.contents}</code>

View File

@@ -1,6 +1,7 @@
{@select key=.type}
{@eq value="paragraph"}{>paragraph/}{/eq}
{@eq value="plain_list"}{>plain_list/}{/eq}
{@eq value="plain_list_simple_item"}{>plain_list_simple_item/}{/eq}
{@eq value="center_block"}{>center_block/}{/eq}
{@eq value="quote_block"}{>quote_block/}{/eq}
{@eq value="special_block"}{>special_block/}{/eq}

View File

@@ -1 +1 @@
<sup><a id="{.reference_id}" href="{.definition_link}">{.label}</a></sup>
<sup class="footnote_reference"><a id="{.reference_id}" href="{.definition_link}">{.label}</a></sup>

View File

@@ -1 +1 @@
<code>{.value}</code>
<code class="inline_source_block">{.value}</code>

View File

@@ -6,13 +6,14 @@
{#global_settings.js_files}<script type="text/javascript" src="{.}"></script>{/global_settings.js_files}
{?global_settings.page_title}<title>{global_settings.page_title}</title>{/global_settings.page_title}
</head>
<body>
{! TODO: Header bar with links? !}
<div class="main_content">
<body class="page_centering">
{#.page_header}{>page_header/}{/.page_header}
<main class="main_content">
{@select key=.type}
{@eq value="blog_post_page"}{>blog_post_page/}{/eq}
{@eq value="blog_stream"}{>blog_stream/}{/eq}
{@none}{!TODO: make this panic!}ERROR: Unrecognized page content type{/none}
{/select}
</div>
</main>
</body>
</html>

View File

@@ -27,5 +27,4 @@
{@eq value="superscript"}{>superscript/}{/eq}
{@eq value="timestamp"}{>timestamp/}{/eq}
{@none}{!TODO: make this panic!}ERROR: Unrecognized type {.type}.{/none}
{/select}{~s}
{! TODO: Maybe the final space should be conditional on end blank in the org source !}
{/select}{@gt key=.post_blank value=0}{~s}{/gt}

View File

@@ -0,0 +1,4 @@
<header class="page_header">
<a class="home_link" href="{.home_link}">{.website_title}</a>
{! TODO: Additional links? Probably using the nav semantic element. !}
</header>

View File

@@ -1,6 +1,6 @@
{@select key=.list_type}
{@eq value="unordered"}<ul>{#.children}{>plain_list_item/}{/.children}</ul>{/eq}
{@eq value="ordered"}<ol>{#.children}{>plain_list_item/}{/.children}</ol>{/eq}
{@eq value="descriptive"}<dl>{#.children}{>plain_list_item/}{/.children}</dl>{/eq}
{@eq value="unordered"}<ul class="plain_list unordered">{#.children}{>plain_list_item/}{/.children}</ul>{/eq}
{@eq value="ordered"}<ol class="plain_list ordered">{#.children}{>plain_list_item/}{/.children}</ol>{/eq}
{@eq value="descriptive"}<dl class="plain_list descriptive">{#.children}{>plain_list_item/}{/.children}</dl>{/eq}
{@none}{!TODO: make this panic!}ERROR: Unrecognized list type {.list_type}.{/none}
{/select}

View File

@@ -0,0 +1,3 @@
{#.children}
{>object/}
{/.children}

View File

@@ -1,3 +1,3 @@
<blockquote>{#.children}
<blockquote class="quote_block">{#.children}
{>element/}
{/.children}</blockquote>

View File

@@ -1 +1 @@
<div><sup><a id="{.definition_id}" href="{.reference_link}">{.label}</a></sup><div>{#.contents}{>ast_node/}{/.contents}</div></div>
<div class="footnote_definition"><a id="{.definition_id}" href="{.reference_link}" class="label">{.label}.</a> <div class="definition">{#.contents}{>ast_node/}{/.contents}</div></div>

View File

@@ -1,9 +1,12 @@
<table>
<div class="src_block">
{?.language}<div class="src_language">{.language}</div>{/.language}
<table class="src_body">
<tbody>
{#.lines}
<tr>
<td><code>{.}</code></td>
<td><code class="src_line">{.}</code></td>
</tr>
{/.lines}
</tbody>
</table>
</div>

View File

@@ -1 +1 @@
!!!!!!!! table
<table>{#.children}{>table_row/}{/.children}</table>

View File

@@ -0,0 +1 @@
<td>{#.children}{>object/}{/.children}</td>

View File

@@ -0,0 +1 @@
<tr>{#.children}{>table_cell/}{/.children}</tr>

View File

@@ -1 +1 @@
<code>{.source}</code>
<code class="verbatim">{.contents}</code>

View File

@@ -4,7 +4,7 @@ use clap::Subcommand;
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[command(name = "Writer")]
#[command(name = "Natter")]
#[command(version = env!("CARGO_PKG_VERSION"))]
#[command(about = "Generate a static site.", long_about = None)]
#[command(propagate_version = true)]
@@ -24,14 +24,14 @@ pub(crate) enum Commands {
#[derive(Args, Debug)]
pub(crate) struct InitArgs {
/// Path where you want the initial writer structure to be located.
/// Path where you want the initial natter structure to be located.
#[arg(short, long)]
pub(crate) path: PathBuf,
}
#[derive(Args, Debug)]
pub(crate) struct BuildArgs {
/// Path to the writer config file.
/// Path to the natter config file.
#[arg(short, long)]
pub(crate) config: PathBuf,
}

View File

@@ -1,4 +1,5 @@
mod render;
mod runner;
mod stylesheet;
pub(crate) use runner::build_site;

View File

@@ -5,30 +5,41 @@ use include_dir::include_dir;
use include_dir::Dir;
use crate::config::Config;
use crate::context::RenderBlogPostPage;
use crate::context::RenderBlogPostPageInput;
use crate::context::RenderBlogStream;
use crate::context::RenderBlogStreamInput;
use crate::context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::convert_blog_post_page_to_render_context;
use crate::intermediate::get_web_path;
use crate::intermediate::BlogPost;
use crate::render::DusterRenderer;
use crate::render::RendererIntegration;
use super::stylesheet::Stylesheet;
static MAIN_TEMPLATES: Dir = include_dir!("$CARGO_MANIFEST_DIR/default_environment/templates/html");
pub(crate) struct SiteRenderer {
output_directory: PathBuf,
blog_posts: Vec<BlogPost>,
stylesheets: Vec<Stylesheet>,
}
impl SiteRenderer {
pub(crate) fn new<P: Into<PathBuf>>(
output_directory: P,
blog_posts: Vec<BlogPost>,
stylesheets: Vec<Stylesheet>,
) -> SiteRenderer {
SiteRenderer {
output_directory: output_directory.into(),
blog_posts,
stylesheets,
}
}
pub(crate) async fn render_blog_posts(&self, config: &Config) -> Result<(), CustomError> {
fn init_renderer_integration(&self) -> Result<DusterRenderer<'_>, CustomError> {
let mut renderer_integration = DusterRenderer::new();
let sources: Vec<_> = MAIN_TEMPLATES
@@ -56,21 +67,27 @@ impl SiteRenderer {
renderer_integration.load_template(name, contents)?;
}
Ok(renderer_integration)
}
pub(crate) async fn render_blog_posts(&self, config: &Config) -> Result<(), CustomError> {
let renderer_integration = self.init_renderer_integration()?;
for blog_post in &self.blog_posts {
for blog_post_page in &blog_post.pages {
let output_path = self
.output_directory
.join("posts")
.join(&blog_post.id)
.join(config.get_relative_path_to_post(&blog_post.id))
.join(blog_post_page.get_output_path());
let render_context = convert_blog_post_page_to_render_context(
let convert_input = RenderBlogPostPageInput::new(blog_post, blog_post_page);
let render_context = RenderContext::new(
config,
&self.output_directory,
&output_path,
blog_post,
blog_post_page,
self.output_directory.as_path(),
output_path.as_path(),
None,
)?;
let render_context = RenderBlogPostPage::new(render_context, &convert_input)?;
let rendered_output = renderer_integration.render(render_context)?;
let parent_directory = output_path
.parent()
@@ -82,6 +99,103 @@ impl SiteRenderer {
Ok(())
}
pub(crate) async fn render_blog_stream(&self, config: &Config) -> Result<(), CustomError> {
let renderer_integration = self.init_renderer_integration()?;
// Sort blog posts by date, newest first.
let sorted_blog_posts = {
let mut sorted_blog_posts: Vec<_> = self.blog_posts.iter().collect();
sorted_blog_posts
.sort_by_key(|blog_post| (blog_post.get_date(), blog_post.id.as_str()));
sorted_blog_posts.reverse();
sorted_blog_posts
};
for blog_post in &sorted_blog_posts {
if blog_post.get_date().is_none() {
return Err(format!("Blog post {} does not have a date.", blog_post.id).into());
}
}
// Group blog posts based on # of posts per page.
let stream_chunks: Vec<_> = sorted_blog_posts
.chunks(config.get_stream_entries_per_page())
.collect();
// For each group, create a RenderBlogStream.
let num_stream_pages = stream_chunks.len();
for (page_num, chunk) in stream_chunks.into_iter().enumerate() {
let output_file = if page_num == 0 {
self.output_directory.join("index.html")
} else {
self.output_directory
.join("stream")
.join(format!("{}.html", page_num))
};
let newer_link = if page_num == 0 {
None
} else if page_num == 1 {
Some(get_web_path(
config,
&self.output_directory,
&output_file,
"index.html",
)?)
} else {
Some(get_web_path(
config,
&self.output_directory,
&output_file,
format!("stream/{}.html", page_num - 1),
)?)
};
let older_link = if page_num == (num_stream_pages - 1) {
None
} else {
Some(get_web_path(
config,
&self.output_directory,
&output_file,
format!("stream/{}.html", page_num + 1),
)?)
};
let convert_input = RenderBlogStreamInput::new(chunk, older_link, newer_link);
let render_context = RenderContext::new(
config,
self.output_directory.as_path(),
output_file.as_path(),
None,
)?;
let blog_stream = RenderBlogStream::new(render_context, &convert_input)?;
// Pass each RenderBlogStream to dust as the context to render index.html and any additional stream pages.
let rendered_output = renderer_integration.render(blog_stream)?;
let parent_directory = output_file
.parent()
.ok_or("Output file should have a containing directory.")?;
tokio::fs::create_dir_all(parent_directory).await?;
tokio::fs::write(output_file, rendered_output).await?;
}
Ok(())
}
pub(crate) async fn render_stylesheets(&self) -> Result<(), CustomError> {
let stylesheet_output_directory = self.output_directory.join("stylesheet");
if !stylesheet_output_directory.exists() {
tokio::fs::create_dir(&stylesheet_output_directory).await?;
}
for stylesheet in &self.stylesheets {
let file_output_path = stylesheet_output_directory.join(&stylesheet.path);
let parent_directory = file_output_path
.parent()
.ok_or("Output file should have a containing directory.")?;
tokio::fs::create_dir_all(parent_directory).await?;
tokio::fs::write(file_output_path, stylesheet.contents.as_bytes()).await?;
}
Ok(())
}
}
fn build_name_contents_pairs<'a>(

View File

@@ -1,16 +1,30 @@
use std::ffi::OsStr;
use std::path::PathBuf;
use super::stylesheet::Stylesheet;
use crate::cli::parameters::BuildArgs;
use crate::command::build::render::SiteRenderer;
use crate::config::Config;
use crate::error::CustomError;
use crate::intermediate::BlogPost;
use include_dir::include_dir;
use include_dir::Dir;
static DEFAULT_STYLESHEETS: Dir =
include_dir!("$CARGO_MANIFEST_DIR/default_environment/stylesheet");
pub(crate) async fn build_site(args: BuildArgs) -> Result<(), CustomError> {
let config = Config::load_from_file(args.config).await?;
let blog_posts = load_blog_posts(&config).await?;
let renderer = SiteRenderer::new(get_output_directory(&config).await?, blog_posts);
let stylesheets = load_stylesheets().await?;
let renderer = SiteRenderer::new(
get_output_directory(&config).await?,
blog_posts,
stylesheets,
);
renderer.render_blog_posts(&config).await?;
renderer.render_blog_stream(&config).await?;
renderer.render_stylesheets().await?;
Ok(())
}
@@ -58,3 +72,18 @@ async fn load_blog_posts(config: &Config) -> Result<Vec<BlogPost>, CustomError>
}
Ok(blog_posts)
}
async fn load_stylesheets() -> Result<Vec<Stylesheet>, CustomError> {
let sources: Vec<_> = DEFAULT_STYLESHEETS
.files()
.filter(|f| f.path().extension() == Some(OsStr::new("css")))
.collect();
let mut ret = Vec::with_capacity(sources.len());
for entry in sources {
let path = entry.path().to_path_buf();
let contents = String::from_utf8(entry.contents().to_vec())?;
let stylesheet = Stylesheet::new(path, contents).await?;
ret.push(stylesheet);
}
Ok(ret)
}

View File

@@ -0,0 +1,15 @@
use std::path::PathBuf;
use crate::error::CustomError;
#[derive(Debug)]
pub(crate) struct Stylesheet {
pub(crate) path: PathBuf,
pub(crate) contents: String,
}
impl Stylesheet {
pub(crate) async fn new(path: PathBuf, contents: String) -> Result<Stylesheet, CustomError> {
Ok(Stylesheet { path, contents })
}
}

View File

@@ -1,3 +1,3 @@
mod runner;
pub(crate) use runner::init_writer_folder;
pub(crate) use runner::init_natter_folder;

View File

@@ -2,7 +2,7 @@ use crate::cli::parameters::InitArgs;
use crate::config::Config;
use crate::error::CustomError;
pub(crate) async fn init_writer_folder(args: InitArgs) -> Result<(), CustomError> {
pub(crate) async fn init_natter_folder(args: InitArgs) -> Result<(), CustomError> {
if args.path.exists() && !args.path.is_dir() {
return Err("The supplied path exists but is not a directory. Aborting.".into());
}

View File

@@ -8,6 +8,7 @@ use crate::error::CustomError;
use super::raw::RawConfig;
/// This is the config struct used by most of the code, which is an interpreted version of the RawConfig struct which is the raw disk-representation of the config.
#[derive(Debug)]
pub(crate) struct Config {
raw: RawConfig,
config_path: PathBuf,
@@ -16,7 +17,7 @@ pub(crate) struct Config {
impl Config {
pub(crate) fn new<P: AsRef<Path>>(root_dir: P) -> Result<Config, CustomError> {
fn inner(root_dir: &Path) -> Result<Config, CustomError> {
let file_path = root_dir.join("writer.toml");
let file_path = root_dir.join("natter.toml");
Ok(Config {
raw: RawConfig::default(),
config_path: file_path,
@@ -56,6 +57,15 @@ impl Config {
self.get_root_directory().join("posts")
}
/// Get the relative path to the folder containing a blog post.
///
/// This could be appended to the output root directory to get the
/// blog post output folder or it could be used to generate a link
/// to the blog post.
pub(crate) fn get_relative_path_to_post<P: AsRef<Path>>(&self, post_id: P) -> PathBuf {
Path::new("posts").join(post_id)
}
pub(crate) fn get_output_directory(&self) -> PathBuf {
self.get_root_directory().join("output")
}
@@ -67,4 +77,17 @@ impl Config {
pub(crate) fn get_web_root(&self) -> Option<&str> {
self.raw.web_root.as_deref()
}
pub(crate) fn get_site_title(&self) -> Option<&str> {
self.raw.site_title.as_deref()
}
pub(crate) fn get_stream_entries_per_page(&self) -> usize {
self.raw
.stream
.as_ref()
.map(|stream| stream.entries_per_page)
.flatten()
.unwrap_or(5)
}
}

View File

@@ -1,24 +1,39 @@
use serde::Deserialize;
use serde::Serialize;
/// This is the struct for the writer.toml config file that ends up in each site's root directory.
#[derive(Deserialize, Serialize)]
/// This is the struct for the natter.toml config file that ends up in each site's root directory.
#[derive(Debug, Deserialize, Serialize)]
pub(crate) struct RawConfig {
site_title: String,
pub(super) site_title: Option<String>,
author: Option<String>,
email: Option<String>,
pub(super) use_relative_paths: Option<bool>,
pub(super) web_root: Option<String>,
pub(super) stream: Option<RawConfigStream>,
}
impl Default for RawConfig {
fn default() -> Self {
RawConfig {
site_title: "My super awesome website".to_owned(),
site_title: None,
author: None,
email: None,
use_relative_paths: None,
web_root: None,
stream: None,
}
}
}
#[derive(Debug, Deserialize, Serialize)]
pub(crate) struct RawConfigStream {
pub(super) entries_per_page: Option<usize>,
}
impl Default for RawConfigStream {
fn default() -> Self {
RawConfigStream {
entries_per_page: None,
}
}
}

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IAngleLink;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "angle_link")]
pub(crate) struct RenderAngleLink {}
pub(crate) struct RenderAngleLink {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderAngleLink, IAngleLink);

View File

@@ -1,8 +1,5 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use crate::error::CustomError;
use crate::intermediate::IAstNode;
@@ -45,6 +42,7 @@ use super::quote_block::RenderQuoteBlock;
use super::radio_link::RenderRadioLink;
use super::radio_target::RenderRadioTarget;
use super::regular_link::RenderRegularLink;
use super::render_context::RenderContext;
use super::special_block::RenderSpecialBlock;
use super::src_block::RenderSrcBlock;
use super::statistics_cookie::RenderStatisticsCookie;
@@ -121,285 +119,207 @@ pub(crate) enum RenderAstNode {
pub(crate) trait IntoRenderAstNode {
fn into_render_ast_node(
&self,
config: &Config,
output_directory: &Path,
output_file: &Path,
render_context: RenderContext<'_>,
) -> Result<RenderAstNode, CustomError>;
}
impl IntoRenderAstNode for IAstNode {
fn into_render_ast_node(
&self,
config: &Config,
output_directory: &Path,
output_file: &Path,
render_context: RenderContext<'_>,
) -> Result<RenderAstNode, CustomError> {
match self {
IAstNode::Heading(inner) => Ok(RenderAstNode::Heading(RenderHeading::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::Section(inner) => Ok(RenderAstNode::Section(RenderSection::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::Paragraph(inner) => Ok(RenderAstNode::Paragraph(RenderParagraph::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::PlainList(inner) => Ok(RenderAstNode::PlainList(RenderPlainList::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::CenterBlock(inner) => Ok(RenderAstNode::CenterBlock(RenderCenterBlock::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::QuoteBlock(inner) => Ok(RenderAstNode::QuoteBlock(RenderQuoteBlock::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::SpecialBlock(inner) => Ok(RenderAstNode::SpecialBlock(
RenderSpecialBlock::new(config, output_directory, output_file, inner)?,
RenderSpecialBlock::new(render_context, inner)?,
)),
IAstNode::DynamicBlock(inner) => Ok(RenderAstNode::DynamicBlock(
RenderDynamicBlock::new(config, output_directory, output_file, inner)?,
RenderDynamicBlock::new(render_context, inner)?,
)),
IAstNode::FootnoteDefinition(inner) => Ok(RenderAstNode::FootnoteDefinition(
RenderFootnoteDefinition::new(config, output_directory, output_file, inner)?,
RenderFootnoteDefinition::new(render_context, inner)?,
)),
IAstNode::Comment(inner) => Ok(RenderAstNode::Comment(RenderComment::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::Drawer(inner) => Ok(RenderAstNode::Drawer(RenderDrawer::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::PropertyDrawer(inner) => Ok(RenderAstNode::PropertyDrawer(
RenderPropertyDrawer::new(config, output_directory, output_file, inner)?,
RenderPropertyDrawer::new(render_context, inner)?,
)),
IAstNode::Table(inner) => Ok(RenderAstNode::Table(RenderTable::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::VerseBlock(inner) => Ok(RenderAstNode::VerseBlock(RenderVerseBlock::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::CommentBlock(inner) => Ok(RenderAstNode::CommentBlock(
RenderCommentBlock::new(config, output_directory, output_file, inner)?,
RenderCommentBlock::new(render_context, inner)?,
)),
IAstNode::ExampleBlock(inner) => Ok(RenderAstNode::ExampleBlock(
RenderExampleBlock::new(config, output_directory, output_file, inner)?,
RenderExampleBlock::new(render_context, inner)?,
)),
IAstNode::ExportBlock(inner) => Ok(RenderAstNode::ExportBlock(RenderExportBlock::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::SrcBlock(inner) => Ok(RenderAstNode::SrcBlock(RenderSrcBlock::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::Clock(inner) => Ok(RenderAstNode::Clock(RenderClock::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::DiarySexp(inner) => Ok(RenderAstNode::DiarySexp(RenderDiarySexp::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::Planning(inner) => Ok(RenderAstNode::Planning(RenderPlanning::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::FixedWidthArea(inner) => Ok(RenderAstNode::FixedWidthArea(
RenderFixedWidthArea::new(config, output_directory, output_file, inner)?,
RenderFixedWidthArea::new(render_context, inner)?,
)),
IAstNode::HorizontalRule(inner) => Ok(RenderAstNode::HorizontalRule(
RenderHorizontalRule::new(config, output_directory, output_file, inner)?,
RenderHorizontalRule::new(render_context, inner)?,
)),
IAstNode::Keyword(inner) => Ok(RenderAstNode::Keyword(RenderKeyword::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::BabelCall(inner) => Ok(RenderAstNode::BabelCall(RenderBabelCall::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::LatexEnvironment(inner) => Ok(RenderAstNode::LatexEnvironment(
RenderLatexEnvironment::new(config, output_directory, output_file, inner)?,
RenderLatexEnvironment::new(render_context, inner)?,
)),
IAstNode::Bold(inner) => Ok(RenderAstNode::Bold(RenderBold::new(
config,
output_directory,
output_file,
inner,
)?)),
IAstNode::Bold(inner) => {
Ok(RenderAstNode::Bold(RenderBold::new(render_context, inner)?))
}
IAstNode::Italic(inner) => Ok(RenderAstNode::Italic(RenderItalic::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::Underline(inner) => Ok(RenderAstNode::Underline(RenderUnderline::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::StrikeThrough(inner) => Ok(RenderAstNode::StrikeThrough(
RenderStrikeThrough::new(config, output_directory, output_file, inner)?,
RenderStrikeThrough::new(render_context, inner)?,
)),
IAstNode::Code(inner) => Ok(RenderAstNode::Code(RenderCode::new(
config,
output_directory,
output_file,
inner,
)?)),
IAstNode::Code(inner) => {
Ok(RenderAstNode::Code(RenderCode::new(render_context, inner)?))
}
IAstNode::Verbatim(inner) => Ok(RenderAstNode::Verbatim(RenderVerbatim::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::PlainText(inner) => Ok(RenderAstNode::PlainText(RenderPlainText::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::RegularLink(inner) => Ok(RenderAstNode::RegularLink(RenderRegularLink::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::RadioLink(inner) => Ok(RenderAstNode::RadioLink(RenderRadioLink::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::RadioTarget(inner) => Ok(RenderAstNode::RadioTarget(RenderRadioTarget::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::PlainLink(inner) => Ok(RenderAstNode::PlainLink(RenderPlainLink::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::AngleLink(inner) => Ok(RenderAstNode::AngleLink(RenderAngleLink::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::OrgMacro(inner) => Ok(RenderAstNode::OrgMacro(RenderOrgMacro::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::Entity(inner) => Ok(RenderAstNode::Entity(RenderEntity::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::LatexFragment(inner) => Ok(RenderAstNode::LatexFragment(
RenderLatexFragment::new(config, output_directory, output_file, inner)?,
RenderLatexFragment::new(render_context, inner)?,
)),
IAstNode::ExportSnippet(inner) => Ok(RenderAstNode::ExportSnippet(
RenderExportSnippet::new(config, output_directory, output_file, inner)?,
RenderExportSnippet::new(render_context, inner)?,
)),
IAstNode::FootnoteReference(inner) => Ok(RenderAstNode::FootnoteReference(
RenderFootnoteReference::new(config, output_directory, output_file, inner)?,
RenderFootnoteReference::new(render_context, inner)?,
)),
IAstNode::Citation(inner) => Ok(RenderAstNode::Citation(RenderCitation::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::CitationReference(inner) => Ok(RenderAstNode::CitationReference(
RenderCitationReference::new(config, output_directory, output_file, inner)?,
RenderCitationReference::new(render_context, inner)?,
)),
IAstNode::InlineBabelCall(inner) => Ok(RenderAstNode::InlineBabelCall(
RenderInlineBabelCall::new(config, output_directory, output_file, inner)?,
RenderInlineBabelCall::new(render_context, inner)?,
)),
IAstNode::InlineSourceBlock(inner) => Ok(RenderAstNode::InlineSourceBlock(
RenderInlineSourceBlock::new(config, output_directory, output_file, inner)?,
RenderInlineSourceBlock::new(render_context, inner)?,
)),
IAstNode::LineBreak(inner) => Ok(RenderAstNode::LineBreak(RenderLineBreak::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::Target(inner) => Ok(RenderAstNode::Target(RenderTarget::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::StatisticsCookie(inner) => Ok(RenderAstNode::StatisticsCookie(
RenderStatisticsCookie::new(config, output_directory, output_file, inner)?,
RenderStatisticsCookie::new(render_context, inner)?,
)),
IAstNode::Subscript(inner) => Ok(RenderAstNode::Subscript(RenderSubscript::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::Superscript(inner) => Ok(RenderAstNode::Superscript(RenderSuperscript::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
IAstNode::Timestamp(inner) => Ok(RenderAstNode::Timestamp(RenderTimestamp::new(
config,
output_directory,
output_file,
render_context,
inner,
)?)),
}

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IBabelCall;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "babel_call")]
pub(crate) struct RenderBabelCall {}
pub(crate) struct RenderBabelCall {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderBabelCall, IBabelCall);

View File

@@ -1,15 +1,37 @@
use serde::Serialize;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::get_web_path;
use crate::intermediate::BlogPost;
use crate::intermediate::BlogPostPage;
use super::footnote_definition::RenderRealFootnoteDefinition;
use super::macros::render;
use super::GlobalSettings;
use super::PageHeader;
use super::RenderDocumentElement;
#[derive(Debug)]
pub(crate) struct RenderBlogPostPageInput<'a> {
post: &'a BlogPost,
page: &'a BlogPostPage,
}
impl<'a> RenderBlogPostPageInput<'a> {
pub(crate) fn new(post: &'a BlogPost, page: &'a BlogPostPage) -> RenderBlogPostPageInput<'a> {
RenderBlogPostPageInput { post, page }
}
}
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "blog_post_page")]
pub(crate) struct RenderBlogPostPage {
global_settings: GlobalSettings,
page_header: Option<PageHeader>,
/// The title that will be shown visibly on the page.
title: Option<String>,
@@ -20,21 +42,82 @@ pub(crate) struct RenderBlogPostPage {
footnotes: Vec<RenderRealFootnoteDefinition>,
}
impl RenderBlogPostPage {
// TODO: Maybe these settings should be moved into a common struct so this can have the same type signature as the others.
pub(crate) fn new(
global_settings: GlobalSettings,
title: Option<String>,
self_link: Option<String>,
children: Vec<RenderDocumentElement>,
footnotes: Vec<RenderRealFootnoteDefinition>,
) -> RenderBlogPostPage {
RenderBlogPostPage {
render!(
RenderBlogPostPage,
RenderBlogPostPageInput,
original,
render_context,
{
let css_files = vec![
get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
"stylesheet/reset.css",
)?,
get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
"stylesheet/main.css",
)?,
];
let js_files = vec![get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
"blog_post.js",
)?];
let global_settings = GlobalSettings::new(original.page.title.clone(), css_files, js_files);
let page_header = PageHeader::new(
render_context.config.get_site_title().map(str::to_string),
Some(get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
"",
)?),
);
let link_to_blog_post = get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
render_context
.output_file
.strip_prefix(render_context.output_root_directory)?,
)?;
let children = {
let mut children = Vec::new();
for child in original.page.children.iter() {
children.push(RenderDocumentElement::new(render_context.clone(), child)?);
}
children
};
let footnotes = {
let mut ret = Vec::new();
for footnote in original.page.footnotes.iter() {
ret.push(RenderRealFootnoteDefinition::new(
render_context.clone(),
footnote,
)?);
}
ret
};
let ret = RenderBlogPostPage {
global_settings,
title,
self_link,
page_header: Some(page_header),
title: original.page.title.clone(),
self_link: Some(link_to_blog_post),
children,
footnotes,
};
Ok(ret)
}
}
}
);

213
src/context/blog_stream.rs Normal file
View File

@@ -0,0 +1,213 @@
use serde::Serialize;
use super::macros::render;
use super::render_context::RenderContext;
use crate::context::RenderDocumentElement;
use crate::context::RenderRealFootnoteDefinition;
use crate::error::CustomError;
use crate::intermediate::get_web_path;
use crate::intermediate::BlogPost;
use super::GlobalSettings;
use super::PageHeader;
#[derive(Debug)]
pub(crate) struct RenderBlogStreamInput<'a, 'b> {
original: &'a [&'b BlogPost],
older_link: Option<String>,
newer_link: Option<String>,
}
impl<'a, 'b> RenderBlogStreamInput<'a, 'b> {
pub(crate) fn new(
original: &'a [&'b BlogPost],
older_link: Option<String>,
newer_link: Option<String>,
) -> RenderBlogStreamInput<'a, 'b> {
RenderBlogStreamInput {
original,
older_link,
newer_link,
}
}
}
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "blog_stream")]
pub(crate) struct RenderBlogStream {
global_settings: GlobalSettings,
page_header: Option<PageHeader>,
children: Vec<RenderBlogStreamEntry>,
stream_pagination: Option<RenderBlogStreamPagination>,
}
render!(
RenderBlogStream,
RenderBlogStreamInput,
original,
render_context,
{
let css_files = vec![
get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
"stylesheet/reset.css",
)?,
get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
"stylesheet/main.css",
)?,
];
let js_files = vec![get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
"blog_post.js",
)?];
let global_settings = GlobalSettings::new(
render_context.config.get_site_title().map(str::to_string),
css_files,
js_files,
);
let page_header = PageHeader::new(
render_context.config.get_site_title().map(str::to_string),
Some(get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
"",
)?),
);
let children = original
.original
.into_iter()
.enumerate()
.map(|(i, blog_post)| {
RenderBlogStreamEntry::new(
render_context.clone(),
&RenderBlogStreamEntryInput::new(blog_post, i),
)
})
.collect::<Result<Vec<_>, _>>()?;
let stream_pagination = if original.older_link.is_some() || original.newer_link.is_some() {
Some(RenderBlogStreamPagination::new(
original.older_link.clone(),
original.newer_link.clone(),
)?)
} else {
None
};
Ok(RenderBlogStream {
global_settings,
page_header: Some(page_header),
children,
stream_pagination,
})
}
);
#[derive(Debug)]
pub(crate) struct RenderBlogStreamEntryInput<'a> {
original: &'a BlogPost,
offset: usize,
}
impl<'a> RenderBlogStreamEntryInput<'a> {
fn new(original: &'a BlogPost, offset: usize) -> RenderBlogStreamEntryInput<'a> {
RenderBlogStreamEntryInput { original, offset }
}
}
#[derive(Debug, Serialize)]
pub(crate) struct RenderBlogStreamEntry {
/// The title that will be shown visibly on the page.
title: Option<String>,
self_link: Option<String>,
children: Vec<RenderDocumentElement>,
footnotes: Vec<RenderRealFootnoteDefinition>,
}
render!(
RenderBlogStreamEntry,
RenderBlogStreamEntryInput,
original,
render_context,
{
let offset_string = original.offset.to_string();
let render_context = {
let mut render_context = render_context.clone();
render_context.id_addition = Some(offset_string.as_str());
render_context
};
let link_to_blog_post = get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
render_context
.config
.get_relative_path_to_post(&original.original.id),
)?;
// TODO: Should I guess an index page instead of erroring out?
let index_page = original
.original
.get_index_page()
.ok_or_else(|| format!("Blog post {} needs an index page.", original.original.id))?;
let title = index_page.title.clone();
let children = index_page
.children
.iter()
.map(|child| RenderDocumentElement::new(render_context.clone(), child))
.collect::<Result<Vec<_>, _>>()?;
let footnotes = {
let mut ret = Vec::new();
for footnote in index_page.footnotes.iter() {
ret.push(RenderRealFootnoteDefinition::new(
render_context.clone(),
footnote,
)?);
}
ret
};
Ok(RenderBlogStreamEntry {
title,
self_link: Some(link_to_blog_post),
children,
footnotes,
})
}
);
#[derive(Debug, Serialize)]
pub(crate) struct RenderBlogStreamPagination {
older_link: Option<String>,
newer_link: Option<String>,
}
impl RenderBlogStreamPagination {
fn new(
older_link: Option<String>,
newer_link: Option<String>,
) -> Result<RenderBlogStreamPagination, CustomError> {
Ok(RenderBlogStreamPagination {
older_link,
newer_link,
})
}
}

View File

@@ -1,16 +1,31 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use crate::error::CustomError;
use crate::intermediate::IBold;
use super::macros::rnoop;
use super::macros::render;
use super::render_context::RenderContext;
use super::RenderObject;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "bold")]
pub(crate) struct RenderBold {}
pub(crate) struct RenderBold {
children: Vec<RenderObject>,
post_blank: organic::types::PostBlank,
}
rnoop!(RenderBold, IBold);
render!(RenderBold, IBold, original, render_context, {
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderObject::new(render_context.clone(), obj)?);
}
ret
};
Ok(RenderBold {
children,
post_blank: original.post_blank,
})
});

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ICenterBlock;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "center_block")]
pub(crate) struct RenderCenterBlock {}
pub(crate) struct RenderCenterBlock {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderCenterBlock, ICenterBlock);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ICitation;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "citation")]
pub(crate) struct RenderCitation {}
pub(crate) struct RenderCitation {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderCitation, ICitation);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ICitationReference;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "citation_reference")]
pub(crate) struct RenderCitationReference {}
pub(crate) struct RenderCitationReference {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderCitationReference, ICitationReference);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IClock;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "clock")]
pub(crate) struct RenderClock {}
pub(crate) struct RenderClock {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderClock, IClock);

View File

@@ -1,16 +1,22 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ICode;
use super::macros::rnoop;
use super::macros::render;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "code")]
pub(crate) struct RenderCode {}
pub(crate) struct RenderCode {
contents: String,
post_blank: organic::types::PostBlank,
}
rnoop!(RenderCode, ICode);
render!(RenderCode, ICode, original, _render_context, {
Ok(RenderCode {
contents: original.contents.clone(),
post_blank: original.post_blank,
})
});

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IComment;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "comment")]
pub(crate) struct RenderComment {}
pub(crate) struct RenderComment {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderComment, IComment);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ICommentBlock;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "comment_block")]
pub(crate) struct RenderCommentBlock {}
pub(crate) struct RenderCommentBlock {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderCommentBlock, ICommentBlock);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IDiarySexp;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "diary_sexp")]
pub(crate) struct RenderDiarySexp {}
pub(crate) struct RenderDiarySexp {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderDiarySexp, IDiarySexp);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IDocumentElement;
@@ -21,16 +19,14 @@ render!(
RenderDocumentElement,
IDocumentElement,
original,
config,
output_directory,
output_file,
render_context,
{
match original {
IDocumentElement::Heading(inner) => Ok(RenderDocumentElement::Heading(
RenderHeading::new(config, output_directory, output_file, inner)?,
RenderHeading::new(render_context.clone(), inner)?,
)),
IDocumentElement::Section(inner) => Ok(RenderDocumentElement::Section(
RenderSection::new(config, output_directory, output_file, inner)?,
RenderSection::new(render_context.clone(), inner)?,
)),
}
}

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IDrawer;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "drawer")]
pub(crate) struct RenderDrawer {}
pub(crate) struct RenderDrawer {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderDrawer, IDrawer);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IDynamicBlock;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "dynamic_block")]
pub(crate) struct RenderDynamicBlock {}
pub(crate) struct RenderDynamicBlock {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderDynamicBlock, IDynamicBlock);

View File

@@ -1,8 +1,7 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::plain_list_simple_item::RenderPlainListSimpleItem;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IElement;
@@ -37,6 +36,7 @@ use super::verse_block::RenderVerseBlock;
pub(crate) enum RenderElement {
Paragraph(RenderParagraph),
PlainList(RenderPlainList),
PlainListSimpleItem(RenderPlainListSimpleItem),
CenterBlock(RenderCenterBlock),
QuoteBlock(RenderQuoteBlock),
SpecialBlock(RenderSpecialBlock),
@@ -61,132 +61,101 @@ pub(crate) enum RenderElement {
LatexEnvironment(RenderLatexEnvironment),
}
render!(
RenderElement,
IElement,
original,
config,
output_directory,
output_file,
{
render!(RenderElement, IElement, original, render_context, {
match original {
IElement::Paragraph(inner) => Ok(RenderElement::Paragraph(RenderParagraph::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IElement::PlainList(inner) => Ok(RenderElement::PlainList(RenderPlainList::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IElement::PlainListSimpleItem(inner) => Ok(RenderElement::PlainListSimpleItem(
RenderPlainListSimpleItem::new(render_context.clone(), inner)?,
)),
IElement::CenterBlock(inner) => Ok(RenderElement::CenterBlock(RenderCenterBlock::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IElement::QuoteBlock(inner) => Ok(RenderElement::QuoteBlock(RenderQuoteBlock::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IElement::SpecialBlock(inner) => Ok(RenderElement::SpecialBlock(RenderSpecialBlock::new(
render_context.clone(),
inner,
)?)),
IElement::DynamicBlock(inner) => Ok(RenderElement::DynamicBlock(RenderDynamicBlock::new(
render_context.clone(),
inner,
)?)),
IElement::SpecialBlock(inner) => Ok(RenderElement::SpecialBlock(
RenderSpecialBlock::new(config, output_directory, output_file, inner)?,
)),
IElement::DynamicBlock(inner) => Ok(RenderElement::DynamicBlock(
RenderDynamicBlock::new(config, output_directory, output_file, inner)?,
)),
IElement::FootnoteDefinition(inner) => Ok(RenderElement::FootnoteDefinition(
RenderFootnoteDefinition::new(config, output_directory, output_file, inner)?,
RenderFootnoteDefinition::new(render_context.clone(), inner)?,
)),
IElement::Comment(inner) => Ok(RenderElement::Comment(RenderComment::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IElement::Drawer(inner) => Ok(RenderElement::Drawer(RenderDrawer::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IElement::PropertyDrawer(inner) => Ok(RenderElement::PropertyDrawer(
RenderPropertyDrawer::new(config, output_directory, output_file, inner)?,
RenderPropertyDrawer::new(render_context.clone(), inner)?,
)),
IElement::Table(inner) => Ok(RenderElement::Table(RenderTable::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IElement::VerseBlock(inner) => Ok(RenderElement::VerseBlock(RenderVerseBlock::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IElement::CommentBlock(inner) => Ok(RenderElement::CommentBlock(RenderCommentBlock::new(
render_context.clone(),
inner,
)?)),
IElement::ExampleBlock(inner) => Ok(RenderElement::ExampleBlock(RenderExampleBlock::new(
render_context.clone(),
inner,
)?)),
IElement::CommentBlock(inner) => Ok(RenderElement::CommentBlock(
RenderCommentBlock::new(config, output_directory, output_file, inner)?,
)),
IElement::ExampleBlock(inner) => Ok(RenderElement::ExampleBlock(
RenderExampleBlock::new(config, output_directory, output_file, inner)?,
)),
IElement::ExportBlock(inner) => Ok(RenderElement::ExportBlock(RenderExportBlock::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IElement::SrcBlock(inner) => Ok(RenderElement::SrcBlock(RenderSrcBlock::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IElement::Clock(inner) => Ok(RenderElement::Clock(RenderClock::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IElement::DiarySexp(inner) => Ok(RenderElement::DiarySexp(RenderDiarySexp::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IElement::Planning(inner) => Ok(RenderElement::Planning(RenderPlanning::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IElement::FixedWidthArea(inner) => Ok(RenderElement::FixedWidthArea(
RenderFixedWidthArea::new(config, output_directory, output_file, inner)?,
RenderFixedWidthArea::new(render_context.clone(), inner)?,
)),
IElement::HorizontalRule(inner) => Ok(RenderElement::HorizontalRule(
RenderHorizontalRule::new(config, output_directory, output_file, inner)?,
RenderHorizontalRule::new(render_context.clone(), inner)?,
)),
IElement::Keyword(inner) => Ok(RenderElement::Keyword(RenderKeyword::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IElement::BabelCall(inner) => Ok(RenderElement::BabelCall(RenderBabelCall::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IElement::LatexEnvironment(inner) => Ok(RenderElement::LatexEnvironment(
RenderLatexEnvironment::new(config, output_directory, output_file, inner)?,
RenderLatexEnvironment::new(render_context.clone(), inner)?,
)),
}
}
);
});

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IEntity;
@@ -13,18 +11,12 @@ use super::macros::render;
#[serde(rename = "entity")]
pub(crate) struct RenderEntity {
html: String,
post_blank: organic::types::PostBlank,
}
render!(
RenderEntity,
IEntity,
original,
config,
output_directory,
output_file,
{
render!(RenderEntity, IEntity, original, _render_context, {
Ok(RenderEntity {
html: original.html.clone(),
post_blank: original.post_blank,
})
}
);
});

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IExampleBlock;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "example_block")]
pub(crate) struct RenderExampleBlock {}
pub(crate) struct RenderExampleBlock {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderExampleBlock, IExampleBlock);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IExportBlock;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "export_block")]
pub(crate) struct RenderExportBlock {}
pub(crate) struct RenderExportBlock {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderExportBlock, IExportBlock);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IExportSnippet;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "export_snippet")]
pub(crate) struct RenderExportSnippet {}
pub(crate) struct RenderExportSnippet {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderExportSnippet, IExportSnippet);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IFixedWidthArea;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "fixed_width_area")]
pub(crate) struct RenderFixedWidthArea {}
pub(crate) struct RenderFixedWidthArea {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderFixedWidthArea, IFixedWidthArea);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IFootnoteDefinition;
use crate::intermediate::IRealFootnoteDefinition;
@@ -15,39 +13,40 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "footnote_definition")]
pub(crate) struct RenderFootnoteDefinition {}
pub(crate) struct RenderFootnoteDefinition {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderFootnoteDefinition, IFootnoteDefinition);
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "footnote_reference")]
#[serde(rename = "real_footnote_definition")]
pub(crate) struct RenderRealFootnoteDefinition {
definition_id: String,
reference_link: String,
label: String,
contents: Vec<RenderAstNode>,
// TODO: Do I need post_blank for real footnote definitions?
}
render!(
RenderRealFootnoteDefinition,
IRealFootnoteDefinition,
original,
config,
output_directory,
output_file,
render_context,
{
let contents = {
let mut ret = Vec::new();
for obj in original.contents.iter() {
ret.push(obj.into_render_ast_node(config, output_directory, output_file)?);
ret.push(obj.into_render_ast_node(render_context.clone())?);
}
ret
};
Ok(RenderRealFootnoteDefinition {
definition_id: original.get_definition_id(),
reference_link: format!("#{}", original.get_reference_id()),
definition_id: original.get_definition_id(render_context.id_addition),
reference_link: format!("#{}", original.get_reference_id(render_context.id_addition)),
label: original.get_display_label(),
contents,
})

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IFootnoteReference;
@@ -15,20 +13,23 @@ pub(crate) struct RenderFootnoteReference {
reference_id: String,
definition_link: String,
label: String,
post_blank: organic::types::PostBlank,
}
render!(
RenderFootnoteReference,
IFootnoteReference,
original,
config,
output_directory,
output_file,
render_context,
{
Ok(RenderFootnoteReference {
reference_id: original.get_reference_id(),
definition_link: format!("#{}", original.get_definition_id()),
reference_id: original.get_reference_id(render_context.id_addition),
definition_link: format!(
"#{}",
original.get_definition_id(render_context.id_addition)
),
label: original.get_display_label(),
post_blank: original.post_blank,
})
}
);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IHeading;
@@ -17,25 +15,14 @@ pub(crate) struct RenderHeading {
level: organic::types::HeadlineLevel,
title: Vec<RenderObject>,
children: Vec<RenderDocumentElement>,
post_blank: organic::types::PostBlank,
}
render!(
RenderHeading,
IHeading,
original,
config,
output_directory,
output_file,
{
render!(RenderHeading, IHeading, original, render_context, {
let title = {
let mut ret = Vec::new();
for obj in original.title.iter() {
ret.push(RenderObject::new(
config,
output_directory,
output_file,
obj,
)?);
ret.push(RenderObject::new(render_context.clone(), obj)?);
}
ret
};
@@ -43,12 +30,7 @@ render!(
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderDocumentElement::new(
config,
output_directory,
output_file,
obj,
)?);
ret.push(RenderDocumentElement::new(render_context.clone(), obj)?);
}
ret
};
@@ -57,6 +39,6 @@ render!(
level: original.level + 1, // Adding 1 because the page title is going to be h1.
title,
children,
post_blank: original.post_blank,
})
}
);
});

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IHorizontalRule;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "horizontal_rule")]
pub(crate) struct RenderHorizontalRule {}
pub(crate) struct RenderHorizontalRule {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderHorizontalRule, IHorizontalRule);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IInlineBabelCall;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "inline_babel_call")]
pub(crate) struct RenderInlineBabelCall {}
pub(crate) struct RenderInlineBabelCall {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderInlineBabelCall, IInlineBabelCall);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IInlineSourceBlock;
@@ -13,18 +11,18 @@ use super::macros::render;
#[serde(rename = "inline_source_block")]
pub(crate) struct RenderInlineSourceBlock {
value: String,
post_blank: organic::types::PostBlank,
}
render!(
RenderInlineSourceBlock,
IInlineSourceBlock,
original,
config,
output_directory,
output_file,
_render_context,
{
Ok(RenderInlineSourceBlock {
value: original.value.clone(),
post_blank: original.post_blank,
})
}
);

View File

@@ -1,16 +1,31 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IItalic;
use super::macros::rnoop;
use super::macros::render;
use super::RenderObject;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "italic")]
pub(crate) struct RenderItalic {}
pub(crate) struct RenderItalic {
children: Vec<RenderObject>,
post_blank: organic::types::PostBlank,
}
rnoop!(RenderItalic, IItalic);
render!(RenderItalic, IItalic, original, render_context, {
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderObject::new(render_context.clone(), obj)?);
}
ret
};
Ok(RenderItalic {
children,
post_blank: original.post_blank,
})
});

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IKeyword;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "keyword")]
pub(crate) struct RenderKeyword {}
pub(crate) struct RenderKeyword {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderKeyword, IKeyword);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ILatexEnvironment;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "latex_environment")]
pub(crate) struct RenderLatexEnvironment {}
pub(crate) struct RenderLatexEnvironment {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderLatexEnvironment, ILatexEnvironment);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ILatexFragment;
@@ -13,18 +11,18 @@ use super::macros::render;
#[serde(rename = "latex_fragment")]
pub(crate) struct RenderLatexFragment {
value: String,
post_blank: organic::types::PostBlank,
}
render!(
RenderLatexFragment,
ILatexFragment,
original,
_config,
_output_directory,
_output_file,
_render_context,
{
Ok(RenderLatexFragment {
value: original.value.clone(),
post_blank: original.post_blank,
})
}
);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ILineBreak;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "line_break")]
pub(crate) struct RenderLineBreak {}
pub(crate) struct RenderLineBreak {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderLineBreak, ILineBreak);

View File

@@ -2,18 +2,12 @@
///
/// This exists to make changing the type signature easier.
macro_rules! render {
($rstruct:ident, $istruct:ident, $original:ident, $config:ident, $output_directory:ident, $output_file:ident, $fnbody:tt) => {
($rstruct:ident, $istruct:ident, $original:ident, $render_context:ident, $fnbody:tt) => {
impl $rstruct {
pub(crate) fn new(
config: &Config,
output_directory: &Path,
output_file: &Path,
original: &$istruct,
$render_context: RenderContext<'_>,
$original: &$istruct,
) -> Result<$rstruct, CustomError> {
let $original = original;
let $config = config;
let $output_directory = output_directory;
let $output_file = output_file;
$fnbody
}
}
@@ -29,12 +23,12 @@ macro_rules! rnoop {
($rstruct:ident, $istruct:ident) => {
impl $rstruct {
pub(crate) fn new(
_config: &Config,
_output_directory: &Path,
_output_file: &Path,
_original: &$istruct,
_render_context: RenderContext<'_>,
original: &$istruct,
) -> Result<$rstruct, CustomError> {
Ok($rstruct {})
Ok($rstruct {
post_blank: original.post_blank,
})
}
}
};

View File

@@ -2,6 +2,7 @@ mod angle_link;
mod ast_node;
mod babel_call;
mod blog_post_page;
mod blog_stream;
mod bold;
mod center_block;
mod citation;
@@ -35,10 +36,12 @@ mod line_break;
mod macros;
mod object;
mod org_macro;
mod page_header;
mod paragraph;
mod plain_link;
mod plain_list;
mod plain_list_item;
mod plain_list_simple_item;
mod plain_text;
mod planning;
mod property_drawer;
@@ -46,6 +49,7 @@ mod quote_block;
mod radio_link;
mod radio_target;
mod regular_link;
mod render_context;
mod section;
mod special_block;
mod src_block;
@@ -54,6 +58,8 @@ mod strike_through;
mod subscript;
mod superscript;
mod table;
mod table_cell;
mod table_row;
mod target;
mod timestamp;
mod underline;
@@ -61,10 +67,15 @@ mod verbatim;
mod verse_block;
pub(crate) use blog_post_page::RenderBlogPostPage;
pub(crate) use blog_post_page::RenderBlogPostPageInput;
pub(crate) use blog_stream::RenderBlogStream;
pub(crate) use blog_stream::RenderBlogStreamInput;
pub(crate) use document_element::RenderDocumentElement;
pub(crate) use element::RenderElement;
pub(crate) use footnote_definition::RenderRealFootnoteDefinition;
pub(crate) use global_settings::GlobalSettings;
pub(crate) use heading::RenderHeading;
pub(crate) use object::RenderObject;
pub(crate) use page_header::PageHeader;
pub(crate) use render_context::RenderContext;
pub(crate) use section::RenderSection;

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IObject;
@@ -67,153 +65,110 @@ pub(crate) enum RenderObject {
Timestamp(RenderTimestamp),
}
render!(
RenderObject,
IObject,
original,
config,
output_directory,
output_file,
{
render!(RenderObject, IObject, original, render_context, {
match original {
IObject::Bold(inner) => Ok(RenderObject::Bold(RenderBold::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::Italic(inner) => Ok(RenderObject::Italic(RenderItalic::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::Underline(inner) => Ok(RenderObject::Underline(RenderUnderline::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::StrikeThrough(inner) => Ok(RenderObject::StrikeThrough(RenderStrikeThrough::new(
render_context.clone(),
inner,
)?)),
IObject::StrikeThrough(inner) => Ok(RenderObject::StrikeThrough(
RenderStrikeThrough::new(config, output_directory, output_file, inner)?,
)),
IObject::Code(inner) => Ok(RenderObject::Code(RenderCode::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::Verbatim(inner) => Ok(RenderObject::Verbatim(RenderVerbatim::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::PlainText(inner) => Ok(RenderObject::PlainText(RenderPlainText::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::RegularLink(inner) => Ok(RenderObject::RegularLink(RenderRegularLink::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::RadioLink(inner) => Ok(RenderObject::RadioLink(RenderRadioLink::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::RadioTarget(inner) => Ok(RenderObject::RadioTarget(RenderRadioTarget::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::PlainLink(inner) => Ok(RenderObject::PlainLink(RenderPlainLink::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::AngleLink(inner) => Ok(RenderObject::AngleLink(RenderAngleLink::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::OrgMacro(inner) => Ok(RenderObject::OrgMacro(RenderOrgMacro::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::Entity(inner) => Ok(RenderObject::Entity(RenderEntity::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::LatexFragment(inner) => Ok(RenderObject::LatexFragment(RenderLatexFragment::new(
render_context.clone(),
inner,
)?)),
IObject::ExportSnippet(inner) => Ok(RenderObject::ExportSnippet(RenderExportSnippet::new(
render_context.clone(),
inner,
)?)),
IObject::LatexFragment(inner) => Ok(RenderObject::LatexFragment(
RenderLatexFragment::new(config, output_directory, output_file, inner)?,
)),
IObject::ExportSnippet(inner) => Ok(RenderObject::ExportSnippet(
RenderExportSnippet::new(config, output_directory, output_file, inner)?,
)),
IObject::FootnoteReference(inner) => Ok(RenderObject::FootnoteReference(
RenderFootnoteReference::new(config, output_directory, output_file, inner)?,
RenderFootnoteReference::new(render_context.clone(), inner)?,
)),
IObject::Citation(inner) => Ok(RenderObject::Citation(RenderCitation::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::CitationReference(inner) => Ok(RenderObject::CitationReference(
RenderCitationReference::new(config, output_directory, output_file, inner)?,
RenderCitationReference::new(render_context.clone(), inner)?,
)),
IObject::InlineBabelCall(inner) => Ok(RenderObject::InlineBabelCall(
RenderInlineBabelCall::new(config, output_directory, output_file, inner)?,
RenderInlineBabelCall::new(render_context.clone(), inner)?,
)),
IObject::InlineSourceBlock(inner) => Ok(RenderObject::InlineSourceBlock(
RenderInlineSourceBlock::new(config, output_directory, output_file, inner)?,
RenderInlineSourceBlock::new(render_context.clone(), inner)?,
)),
IObject::LineBreak(inner) => Ok(RenderObject::LineBreak(RenderLineBreak::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::Target(inner) => Ok(RenderObject::Target(RenderTarget::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::StatisticsCookie(inner) => Ok(RenderObject::StatisticsCookie(
RenderStatisticsCookie::new(config, output_directory, output_file, inner)?,
RenderStatisticsCookie::new(render_context.clone(), inner)?,
)),
IObject::Subscript(inner) => Ok(RenderObject::Subscript(RenderSubscript::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::Superscript(inner) => Ok(RenderObject::Superscript(RenderSuperscript::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
IObject::Timestamp(inner) => Ok(RenderObject::Timestamp(RenderTimestamp::new(
config,
output_directory,
output_file,
render_context.clone(),
inner,
)?)),
}
}
);
});

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IOrgMacro;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "org_macro")]
pub(crate) struct RenderOrgMacro {}
pub(crate) struct RenderOrgMacro {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderOrgMacro, IOrgMacro);

View File

@@ -0,0 +1,19 @@
use serde::Serialize;
/// The header that goes above the content of the page.
///
/// This header will be mostly the same on every page.
#[derive(Debug, Serialize)]
pub(crate) struct PageHeader {
website_title: Option<String>,
home_link: Option<String>,
}
impl PageHeader {
pub(crate) fn new(website_title: Option<String>, home_link: Option<String>) -> PageHeader {
PageHeader {
website_title,
home_link,
}
}
}

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IParagraph;
@@ -14,29 +12,20 @@ use super::RenderObject;
#[serde(rename = "paragraph")]
pub(crate) struct RenderParagraph {
children: Vec<RenderObject>,
post_blank: organic::types::PostBlank,
}
render!(
RenderParagraph,
IParagraph,
original,
config,
output_directory,
output_file,
{
render!(RenderParagraph, IParagraph, original, render_context, {
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderObject::new(
config,
output_directory,
output_file,
obj,
)?);
ret.push(RenderObject::new(render_context.clone(), obj)?);
}
ret
};
Ok(RenderParagraph { children })
}
);
Ok(RenderParagraph {
children,
post_blank: original.post_blank,
})
});

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IPlainLink;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "plain_link")]
pub(crate) struct RenderPlainLink {}
pub(crate) struct RenderPlainLink {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderPlainLink, IPlainLink);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IPlainList;
@@ -15,16 +13,10 @@ use super::plain_list_item::RenderPlainListItem;
pub(crate) struct RenderPlainList {
list_type: String,
children: Vec<RenderPlainListItem>,
post_blank: organic::types::PostBlank,
}
render!(
RenderPlainList,
IPlainList,
original,
config,
output_directory,
output_file,
{
render!(RenderPlainList, IPlainList, original, render_context, {
let list_type = match original.list_type {
organic::types::PlainListType::Unordered => "unordered".to_owned(),
organic::types::PlainListType::Ordered => "ordered".to_owned(),
@@ -33,12 +25,7 @@ render!(
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderPlainListItem::new(
config,
output_directory,
output_file,
obj,
)?);
ret.push(RenderPlainListItem::new(render_context.clone(), obj)?);
}
ret
};
@@ -46,6 +33,6 @@ render!(
Ok(RenderPlainList {
list_type,
children,
post_blank: original.post_blank,
})
}
);
});

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IPlainListItem;
@@ -22,19 +20,12 @@ render!(
RenderPlainListItem,
IPlainListItem,
original,
config,
output_directory,
output_file,
render_context,
{
let tag = {
let mut ret = Vec::new();
for obj in original.tag.iter() {
ret.push(RenderObject::new(
config,
output_directory,
output_file,
obj,
)?);
ret.push(RenderObject::new(render_context.clone(), obj)?);
}
ret
};
@@ -42,12 +33,7 @@ render!(
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderElement::new(
config,
output_directory,
output_file,
obj,
)?);
ret.push(RenderElement::new(render_context.clone(), obj)?);
}
ret
};

View File

@@ -0,0 +1,38 @@
use serde::Serialize;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IPlainListSimpleItem;
use super::macros::render;
use super::RenderObject;
/// Special case for list items with only paragraphs and sublists as their children. In those cases, the paragraph tags are omitted. This is equivalent to a Paragraph but in a different struct to have a different type tag.
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "plain_list_simple_item")]
pub(crate) struct RenderPlainListSimpleItem {
children: Vec<RenderObject>,
post_blank: organic::types::PostBlank,
}
render!(
RenderPlainListSimpleItem,
IPlainListSimpleItem,
original,
render_context,
{
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderObject::new(render_context.clone(), obj)?);
}
ret
};
Ok(RenderPlainListSimpleItem {
children,
post_blank: original.post_blank,
})
}
);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IPlainText;
@@ -13,18 +11,12 @@ use super::macros::render;
#[serde(rename = "plain_text")]
pub(crate) struct RenderPlainText {
source: String,
post_blank: organic::types::PostBlank,
}
render!(
RenderPlainText,
IPlainText,
original,
config,
output_directory,
output_file,
{
render!(RenderPlainText, IPlainText, original, _render_context, {
Ok(RenderPlainText {
source: original.source.clone(),
post_blank: original.post_blank,
})
}
);
});

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IPlanning;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "planning")]
pub(crate) struct RenderPlanning {}
pub(crate) struct RenderPlanning {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderPlanning, IPlanning);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IPropertyDrawer;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "property_drawer")]
pub(crate) struct RenderPropertyDrawer {}
pub(crate) struct RenderPropertyDrawer {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderPropertyDrawer, IPropertyDrawer);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IQuoteBlock;
@@ -14,29 +12,20 @@ use super::RenderElement;
#[serde(rename = "quote_block")]
pub(crate) struct RenderQuoteBlock {
children: Vec<RenderElement>,
post_blank: organic::types::PostBlank,
}
render!(
RenderQuoteBlock,
IQuoteBlock,
original,
config,
output_directory,
output_file,
{
render!(RenderQuoteBlock, IQuoteBlock, original, render_context, {
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderElement::new(
config,
output_directory,
output_file,
obj,
)?);
ret.push(RenderElement::new(render_context.clone(), obj)?);
}
ret
};
Ok(RenderQuoteBlock { children })
}
);
Ok(RenderQuoteBlock {
children,
post_blank: original.post_blank,
})
});

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IRadioLink;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "radio_link")]
pub(crate) struct RenderRadioLink {}
pub(crate) struct RenderRadioLink {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderRadioLink, IRadioLink);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IRadioTarget;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "radio_target")]
pub(crate) struct RenderRadioTarget {}
pub(crate) struct RenderRadioTarget {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderRadioTarget, IRadioTarget);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IRegularLink;
@@ -15,25 +13,14 @@ use super::RenderObject;
pub(crate) struct RenderRegularLink {
raw_link: String,
children: Vec<RenderObject>,
post_blank: organic::types::PostBlank,
}
render!(
RenderRegularLink,
IRegularLink,
original,
config,
output_directory,
output_file,
{
render!(RenderRegularLink, IRegularLink, original, render_context, {
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderObject::new(
config,
output_directory,
output_file,
obj,
)?);
ret.push(RenderObject::new(render_context.clone(), obj)?);
}
ret
};
@@ -41,6 +28,6 @@ render!(
Ok(RenderRegularLink {
raw_link: original.raw_link.clone(),
children,
post_blank: original.post_blank,
})
}
);
});

View File

@@ -0,0 +1,36 @@
use std::path::Path;
use crate::config::Config;
use crate::error::CustomError;
/// The supporting information used for converting the intermediate representation into the dust context for rendering.
#[derive(Debug, Clone)]
pub(crate) struct RenderContext<'intermediate> {
pub(crate) config: &'intermediate Config,
// TODO: Perhaps rename to output_root_directory.
pub(crate) output_root_directory: &'intermediate Path,
pub(crate) output_file: &'intermediate Path,
/// An optional string that gets added to IDs in HTML.
///
/// This is useful for cases where you may have conflicting HTML
/// IDs, for example, multiple blog posts with footnotes in a blog
/// stream.
pub(crate) id_addition: Option<&'intermediate str>,
}
impl<'intermediate> RenderContext<'intermediate> {
pub(crate) fn new(
config: &'intermediate Config,
output_directory: &'intermediate Path,
output_file: &'intermediate Path,
id_addition: Option<&'intermediate str>,
) -> Result<RenderContext<'intermediate>, CustomError> {
Ok(RenderContext {
config,
output_root_directory: output_directory,
output_file,
id_addition,
})
}
}

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ISection;
@@ -14,29 +12,20 @@ use super::RenderElement;
#[serde(rename = "section")]
pub(crate) struct RenderSection {
children: Vec<RenderElement>,
post_blank: organic::types::PostBlank,
}
render!(
RenderSection,
ISection,
original,
config,
output_directory,
output_file,
{
render!(RenderSection, ISection, original, render_context, {
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderElement::new(
config,
output_directory,
output_file,
obj,
)?);
ret.push(RenderElement::new(render_context.clone(), obj)?);
}
ret
};
Ok(RenderSection { children })
}
);
Ok(RenderSection {
children,
post_blank: original.post_blank,
})
});

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ISpecialBlock;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "special_block")]
pub(crate) struct RenderSpecialBlock {}
pub(crate) struct RenderSpecialBlock {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderSpecialBlock, ISpecialBlock);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ISrcBlock;
@@ -13,18 +11,14 @@ use super::macros::render;
#[serde(rename = "src_block")]
pub(crate) struct RenderSrcBlock {
lines: Vec<String>,
language: Option<String>,
post_blank: organic::types::PostBlank,
}
render!(
RenderSrcBlock,
ISrcBlock,
original,
config,
output_directory,
output_file,
{
render!(RenderSrcBlock, ISrcBlock, original, _render_context, {
Ok(RenderSrcBlock {
lines: original.lines.clone(),
language: original.language.clone(),
post_blank: original.post_blank,
})
}
);
});

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IStatisticsCookie;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "statistics_cookie")]
pub(crate) struct RenderStatisticsCookie {}
pub(crate) struct RenderStatisticsCookie {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderStatisticsCookie, IStatisticsCookie);

View File

@@ -1,16 +1,37 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IStrikeThrough;
use super::macros::rnoop;
use super::macros::render;
use super::RenderObject;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "strike_through")]
pub(crate) struct RenderStrikeThrough {}
pub(crate) struct RenderStrikeThrough {
children: Vec<RenderObject>,
post_blank: organic::types::PostBlank,
}
rnoop!(RenderStrikeThrough, IStrikeThrough);
render!(
RenderStrikeThrough,
IStrikeThrough,
original,
render_context,
{
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderObject::new(render_context.clone(), obj)?);
}
ret
};
Ok(RenderStrikeThrough {
children,
post_blank: original.post_blank,
})
}
);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ISubscript;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "subscript")]
pub(crate) struct RenderSubscript {}
pub(crate) struct RenderSubscript {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderSubscript, ISubscript);

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ISuperscript;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "superscript")]
pub(crate) struct RenderSuperscript {}
pub(crate) struct RenderSuperscript {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderSuperscript, ISuperscript);

View File

@@ -1,16 +1,31 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ITable;
use super::macros::rnoop;
use super::macros::render;
use super::table_row::RenderTableRow;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "table")]
pub(crate) struct RenderTable {}
pub(crate) struct RenderTable {
children: Vec<RenderTableRow>,
post_blank: organic::types::PostBlank,
}
rnoop!(RenderTable, ITable);
render!(RenderTable, ITable, original, render_context, {
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderTableRow::new(render_context.clone(), obj)?);
}
ret
};
Ok(RenderTable {
children,
post_blank: original.post_blank,
})
});

27
src/context/table_cell.rs Normal file
View File

@@ -0,0 +1,27 @@
use serde::Serialize;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ITableCell;
use super::macros::render;
use super::RenderObject;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "table_cell")]
pub(crate) struct RenderTableCell {
children: Vec<RenderObject>,
}
render!(RenderTableCell, ITableCell, original, render_context, {
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderObject::new(render_context.clone(), obj)?);
}
ret
};
Ok(RenderTableCell { children })
});

27
src/context/table_row.rs Normal file
View File

@@ -0,0 +1,27 @@
use serde::Serialize;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ITableRow;
use super::macros::render;
use super::table_cell::RenderTableCell;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "table_row")]
pub(crate) struct RenderTableRow {
children: Vec<RenderTableCell>,
}
render!(RenderTableRow, ITableRow, original, render_context, {
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderTableCell::new(render_context.clone(), obj)?);
}
ret
};
Ok(RenderTableRow { children })
});

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ITarget;
@@ -13,18 +11,12 @@ use super::macros::render;
#[serde(rename = "target")]
pub(crate) struct RenderTarget {
id: String,
post_blank: organic::types::PostBlank,
}
render!(
RenderTarget,
ITarget,
original,
config,
output_directory,
output_file,
{
render!(RenderTarget, ITarget, original, _render_context, {
Ok(RenderTarget {
id: original.id.clone(),
post_blank: original.post_blank,
})
}
);
});

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::ITimestamp;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "timestamp")]
pub(crate) struct RenderTimestamp {}
pub(crate) struct RenderTimestamp {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderTimestamp, ITimestamp);

View File

@@ -1,16 +1,31 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IUnderline;
use super::macros::rnoop;
use super::macros::render;
use super::RenderObject;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "underline")]
pub(crate) struct RenderUnderline {}
pub(crate) struct RenderUnderline {
children: Vec<RenderObject>,
post_blank: organic::types::PostBlank,
}
rnoop!(RenderUnderline, IUnderline);
render!(RenderUnderline, IUnderline, original, render_context, {
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderObject::new(render_context.clone(), obj)?);
}
ret
};
Ok(RenderUnderline {
children,
post_blank: original.post_blank,
})
});

View File

@@ -1,16 +1,22 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IVerbatim;
use super::macros::rnoop;
use super::macros::render;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "verbatim")]
pub(crate) struct RenderVerbatim {}
pub(crate) struct RenderVerbatim {
contents: String,
post_blank: organic::types::PostBlank,
}
rnoop!(RenderVerbatim, IVerbatim);
render!(RenderVerbatim, IVerbatim, original, _render_context, {
Ok(RenderVerbatim {
contents: original.contents.clone(),
post_blank: original.post_blank,
})
});

View File

@@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize;
use crate::config::Config;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::IVerseBlock;
@@ -11,6 +9,8 @@ use super::macros::rnoop;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "verse_block")]
pub(crate) struct RenderVerseBlock {}
pub(crate) struct RenderVerseBlock {
post_blank: organic::types::PostBlank,
}
rnoop!(RenderVerseBlock, IVerseBlock);

View File

@@ -4,6 +4,7 @@ use std::string::FromUtf8Error;
#[derive(Debug)]
pub(crate) enum CustomError {
Static(&'static str),
String(String),
IO(std::io::Error),
TomlSerialize(toml::ser::Error),
TomlDeserialize(toml::de::Error),
@@ -29,6 +30,12 @@ impl From<&'static str> for CustomError {
}
}
impl From<String> for CustomError {
fn from(value: String) -> Self {
CustomError::String(value)
}
}
impl From<toml::ser::Error> for CustomError {
fn from(value: toml::ser::Error) -> Self {
CustomError::TomlSerialize(value)

Some files were not shown because too many files have changed in this diff Show More