# luasmith Tutorial In this tutorial, we'll start with a trivial pipeline and build it up into a simple blog theme. See [../README.md](../README.md) for an overview of luasmith. For an example of input content, look at the `sample/content/` directory. ### Trivial/Identity Pipeline Here's a pipeline that essentially just copies from `content/` to `out/`: ```lua -- Pipeline that copies from content/ to out/ return { readFromSource("content"), writeToDestination("out"), } ``` Note that no Markdown processing is done whatsoever. You can try this trivial example out by compiling luasmith, going into the `sample` directory, and running `../luasmith tutorial1.lua`. ### Process Markdown To actually convert Markdown to HTML, just add the `processMarkdown()` node (as in `sample/tutorial2.lua`): ```lua return { readFromSource("content"), -- Convert Markdown files to HTML fragments processMarkdown(), writeToDestination("out"), } ``` ### Templates Markdown produces an HTML fragment, so you can apply a template to build the rest of the document: ```lua -- Put generated HTML fragment into a complete document -- The template is internally passed to etlua.compile() -- See etlua docs for an explanation of <%= %>, etc. -- The item schema is roughly: -- { -- path = "relative path of the item", -- pathToRoot = "path TO the root FROM the item", -- content = "contents of the item/file", -- ... -- Any additional properties added by the pipeline -- } local template = [[ <%= title %> <%- content %> ]] return { readFromSource("content"), processMarkdown(), applyTemplates({ -- The first item in each pair is a pattern to match item paths -- The second item in each pair is the etlua template string itself -- If an item's path matches multiple entries, the last match wins -- The Lua pattern below means "ends with '.html'" { "%.html$", template }, }), writeToDestination("out"), } ``` What does `%.html$` mean? Lua does not use POSIX regular expressions (regexp) for reasons outlined [here](https://www.lua.org/pil/20.1.html). In this case, `%.` means the literal `.` character; in other words, `%` is the escape character. The `$` (**only** at the end of a pattern) anchors the match to the end of the string in question. The manual outlines this in greater detail [here](https://www.lua.org/manual/5.4/manual.html#6.4.1). A tutorial [here](http://lua-users.org/wiki/PatternsTutorial) explains some of the limitations of Lua's pattern matching. ### Adding CSS Injecting a CSS file is trivial, but remember to reference it using the correct relative path (see `pathToRoot` in the contained HTML template): ```lua -- Add and reference CSS local css = [[ body { max-width: 40em; margin: auto; } ]] -- Note CSS is referenced using `pathToRoot` local template = [[ <%= title %> <%- content %> ]] return { readFromSource("content"), -- Inject arbitrary files: key is the path and value is the content injectFiles({ ["style.css"] = css }), processMarkdown(), applyTemplates({ { "%.html$", template } }), writeToDestination("out"), } ``` ### Root/Index Page Using `aggregate()`, you can create a root/index/home page that displays information about all posts, in reverse chronological order. Note that you can add multiple `applyTemplates()` steps, e.g. to format the content in the first pass and then insert the content into a document in a second pass. ```lua -- Add a root/index/home page, listing blog posts local index = [[ ]] local outer = [[ <%= title %> <%- content %> ]] local css = [[ body { max-width: 40em; margin: auto; } ]] return { readFromSource("content"), injectFiles({ ["style.css"] = css }), processMarkdown(), -- Aggregate into an item of path, including a new property -- named `items` of all items matching the pattern aggregate("index.html", "%.html$"), -- Apply a template to list the blog posts applyTemplates({ { "^index%.html$", index } }), -- Finally, wrap each HTML fragment in a document applyTemplates({ { "%.html$", outer } }), writeToDestination("out"), } ``` There you go! Now you've got a barebones blog. ### Bonus: syntax highlighting and link checking * Add `highlightSyntax()` after `processMarkdown()` to apply CSS classes to code blocks * Add `checkLinks()` to check that relative links are not broken ```lua return { ... processMarkdown(), highlightSyntax(), -- Add ".hl-*" CSS classes to code blocks ... checkLinks(), -- Check for broken links writeToDestination("out"), } ``` ### Beyond the Tutorial Poke around the included themes in `themes/` for further inspiration.