From 18e0407666ee9b7fb1b7b01b80b5107d1c571e3f Mon Sep 17 00:00:00 2001
From: Jesper Wendel Devantier
Date: Mon, 20 Jan 2025 22:05:12 +0100
Subject: [PATCH] new release
* nested components supported
* syntax change
* empty Lua lines (`%`) now permitted, can use to format code
* docs: fix cross-referencing links bug
* docs: update to reflect new syntax
* docs: remove concept of directives, now there are components and Lua
code blocks
* add LICENSE file
* add README.md file
* api: htt.Component.is -- check if value is a component
* api: all components now have a .name attribute containing the name
they were defined with
Defining components, before:
```
% @component foo
...
% @end
```
Defining components, now:
```
%
...
%
```
Lua code blocks, before:
```
% @code
...
% @end
```
Lua code blocks, now:
```
%%%
...
%%%
```
---
LICENSE | 9 +
README.md | 20 +++
api/api_desc.lua | 67 +++++---
api/typestub.htt | 58 ++++---
docs/api_module.htt | 68 ++++----
docs/common.htt | 116 +++++++------
docs/common.htt.lua | 30 ++--
docs/debug.htt | 27 ++-
docs/ex-go-ast.htt | 36 ++--
docs/examples/ast/ast1.htt | 4 +-
docs/examples/ast/ast2.htt | 12 +-
docs/examples/ast/ast3.htt | 16 +-
docs/examples/ast/ast4.htt | 16 +-
docs/examples/ast/ast5.htt | 24 +--
docs/examples/debug/err-compile.htt | 4 +-
docs/examples/debug/err-exec.htt | 8 +-
docs/examples/debug/err-stx.htt | 4 +-
docs/examples/quick-start/components.htt | 88 +++++++---
docs/examples/syntax/def-component.txt | 4 +-
docs/examples/syntax/examples.htt | 26 +--
docs/examples/syntax/grammar.txt | 15 +-
docs/htt-intro.htt | 8 +-
docs/htt.tmLanguage.json | 51 +++---
docs/model.lua | 2 +-
docs/modules-and-files.htt | 32 ++--
docs/quick-start.htt | 92 ++++++----
docs/setup.htt | 16 +-
docs/syntax-recap.htt | 72 ++++----
src/engine/tpl.zig | 20 ++-
src/htt_typestubs.lua | 14 ++
src/prelude.lua | 18 ++
src/tpl/compiler.zig | 127 +++++++-------
src/tpl/lexer.zig | 160 ++++++++----------
src/tpl/test_lexer.zig | 120 ++++++++++---
src/tpl/token.zig | 8 +-
.../03_render/test_nested_components/outer1 | 5 +
.../03_render/test_nested_components/outer2 | 5 +
.../03_render/test_nested_components/outer3 | 5 +
.../03_render/test_nested_components/outer4 | 5 +
.../06_component_api/test_component_is/out | 6 +
.../06_component_api/test_component_name/out | 5 +
tests/tpl/inputs/01_render/hello.htt | 8 +-
tests/tpl/inputs/02_basics/context.htt | 8 +-
tests/tpl/inputs/02_basics/exprs.htt | 4 +-
.../inputs/02_basics/line_continuation.htt | 8 +-
tests/tpl/inputs/02_basics/lua_blocks.htt | 12 +-
tests/tpl/inputs/02_basics/lua_lines.htt | 12 +-
tests/tpl/inputs/02_basics/render_expr.htt | 8 +-
.../tpl/inputs/02_basics/tpl_with_luafile.htt | 4 +-
tests/tpl/inputs/03_render/ctx.htt | 16 +-
tests/tpl/inputs/03_render/hoc.htt | 8 +-
.../inputs/03_render/nested_components.htt | 47 +++++
.../03_render/test_nested_components.lua | 7 +
.../tpl/inputs/04_formatting/indentation.htt | 40 ++---
.../04_formatting/inline_components.htt | 32 ++--
tests/tpl/inputs/04_formatting/nl_tests.htt | 36 ++--
.../tpl/inputs/05_require/foo/bar/nested.htt | 4 +-
tests/tpl/inputs/05_require/same_dir.htt | 4 +-
.../inputs/05_require/test_htt_require.lua | 2 -
.../inputs/06_component_api/component_is.htt | 28 +++
.../06_component_api/component_name.htt | 25 +++
.../06_component_api/test_component_is.lua | 1 +
.../06_component_api/test_component_name.lua | 1 +
63 files changed, 1042 insertions(+), 696 deletions(-)
create mode 100644 LICENSE
create mode 100644 README.md
create mode 100644 tests/tpl/expected/03_render/test_nested_components/outer1
create mode 100644 tests/tpl/expected/03_render/test_nested_components/outer2
create mode 100644 tests/tpl/expected/03_render/test_nested_components/outer3
create mode 100644 tests/tpl/expected/03_render/test_nested_components/outer4
create mode 100644 tests/tpl/expected/06_component_api/test_component_is/out
create mode 100644 tests/tpl/expected/06_component_api/test_component_name/out
create mode 100644 tests/tpl/inputs/03_render/nested_components.htt
create mode 100644 tests/tpl/inputs/03_render/test_nested_components.lua
create mode 100644 tests/tpl/inputs/06_component_api/component_is.htt
create mode 100644 tests/tpl/inputs/06_component_api/component_name.htt
create mode 100644 tests/tpl/inputs/06_component_api/test_component_is.lua
create mode 100644 tests/tpl/inputs/06_component_api/test_component_name.lua
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f35498c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,9 @@
+Copyright 2025 Jesper Wendel Devantier
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..47f2832
--- /dev/null
+++ b/README.md
@@ -0,0 +1,20 @@
+# HTT - HTML/Text Templating
+
+[](https://github.com/jwdevantier/htt/actions/workflows/ci.yml)
+
+HTT is a templating language built around Lua that excels at generating code and configuration files. It combines the readability of traditional templating with the full power of Lua.
+
+## Key Features
+
+- **Component-Based**: Build complex templates by composing smaller, reusable components
+- **Full Lua Integration**: Use Lua for logic, data transformation, and external module integration
+- **Smart Indentation**: Maintains correct indentation across component nesting levels
+- **Efficient**: Templates are compiled to Lua modules and loaded lazily
+
+## Documentation
+
+Visit [https://jwdevantier.github.io/htt/](https://jwdevantier.github.io/htt/) for:
+- Getting started guide
+- Syntax reference
+- Examples and best practices
+- Detailed explanations of components, modules, and debugging
diff --git a/api/api_desc.lua b/api/api_desc.lua
index ce9456b..0818d32 100644
--- a/api/api_desc.lua
+++ b/api/api_desc.lua
@@ -165,7 +165,7 @@ local tcp_stream = {
content = {
{
name = "recv",
- type = "function",
+ type = "method",
params = {
{ name = "buf", type = t_tcp_buffer, summary = "Buffer of data to send" },
{ name = "n", type = "integer", summary = "if provided, read exactly `n` bytes" },
@@ -180,7 +180,7 @@ local tcp_stream = {
},
{
name = "recv_at_least",
- type = "function",
+ type = "method",
params = {
{ name = "buf", type = t_tcp_buffer, summary = "Buffer of data to send" },
{ name = "n", type = "integer", summary = "read at least this many bytes" },
@@ -195,7 +195,7 @@ local tcp_stream = {
},
{
name = "send",
- type = "function",
+ type = "method",
params = {
{ name = "buffer", type = t_tcp_buffer, summary = "Buffer" },
{ name = "n", type = "integer?", summary = "if set, send the first n bytes, not entire buffer" },
@@ -216,7 +216,7 @@ local tcp_buffer = {
content = {
{
name = "remaining",
- type = "function",
+ type = "method",
params = {
},
desc = {
@@ -230,7 +230,7 @@ local tcp_buffer = {
},
{
name = "size",
- type = "function",
+ type = "method",
params = {
},
desc = {
@@ -244,7 +244,7 @@ local tcp_buffer = {
},
{
name = "set_size",
- type = "function",
+ type = "method",
params = {
{ name = "N", type = "integer", "Desired size of the buffer, in bytes" }
},
@@ -259,7 +259,7 @@ local tcp_buffer = {
},
{
name = "seek",
- type = "function",
+ type = "method",
params = {
{ name = "N", type = "integer", summary = "The byte offset to seek to" }
},
@@ -271,7 +271,7 @@ local tcp_buffer = {
},
{
name = "tell",
- type = "function",
+ type = "method",
params = {
},
desc = {
@@ -283,7 +283,7 @@ local tcp_buffer = {
},
{
name = "write_string",
- type = "function",
+ type = "method",
params = {
{ name = "str", type = "string", summary = "the string to write" }
},
@@ -297,7 +297,7 @@ local tcp_buffer = {
},
{
name = "write_bool",
- type = "function",
+ type = "method",
params = {
{ name = "val", type = "boolean", summary = "the value to write" }
},
@@ -311,7 +311,7 @@ local tcp_buffer = {
},
{
name = "read_string",
- type = "function",
+ type = "method",
params = {
{ name = "len", type = "integer", summary = "length, in bytes, of string" }
},
@@ -326,7 +326,7 @@ local tcp_buffer = {
},
{
name = "read_bool",
- type = "function",
+ type = "method",
params = {
},
desc = {
@@ -354,7 +354,7 @@ for _, signedness in ipairs({ "i", "u" }) do
end
table.insert(tcp_buffer.content, {
name = string.format("write_%s%s%s", signedness, bits, order),
- type = "function",
+ type = "method",
params = {
{ name = "val", type = "integer", summary = "value to write" },
},
@@ -386,7 +386,7 @@ for _, signedness in ipairs({ "i", "u" }) do
end
table.insert(tcp_buffer.content, {
name = string.format("read_%s%s%s", signedness, bits, order),
- type = "function",
+ type = "method",
params = {
},
desc = {
@@ -690,7 +690,7 @@ m_fs.content = {
content = {
{
name = "path",
- type = "function",
+ type = "method",
params = {
},
desc = {
@@ -702,7 +702,7 @@ m_fs.content = {
},
{
name = "make_path",
- type = "function",
+ type = "method",
params = {
{ name = "subpath", type = "path", summary = "path of dirs, relative to dir, to create" },
},
@@ -718,7 +718,7 @@ m_fs.content = {
},
{
name = "open_dir",
- type = "function",
+ type = "method",
params = {
{ name = "subpath", type = "string", summary = "path relative to dir of directory to open" },
},
@@ -732,7 +732,7 @@ m_fs.content = {
},
{
name = "parent",
- type = "function",
+ type = "method",
params = {
},
desc = {
@@ -745,7 +745,7 @@ m_fs.content = {
},
{
name = "list",
- type = "function",
+ type = "method",
params = {},
desc = {
"Return iterator to loop over all items in directory.",
@@ -757,7 +757,7 @@ m_fs.content = {
},
{
name = "walk",
- type = "function",
+ type = "method",
params = {},
desc = {
"Return iterator for recursively iterating through all contents nested under dir.",
@@ -769,7 +769,7 @@ m_fs.content = {
},
{
name = "remove",
- type = "function",
+ type = "method",
params = {
{ name = "subpath", type = "string?", summary = "(optional) a path relative to this directory. Otherwise this directory." }
},
@@ -785,7 +785,7 @@ m_fs.content = {
},
{
name = "exists",
- type = "function",
+ type = "method",
params = {
{ name = "subpath", type = "string?", summary = "(optional) either check subpath relative to directory, or directory itself" },
},
@@ -799,7 +799,7 @@ m_fs.content = {
},
{
name = "touch",
- type = "function",
+ type = "method",
params = {
{ name = "subpath", type = "string", summary = "path of file to create, relative to directory" },
},
@@ -1102,10 +1102,31 @@ local m_json = {
}
}
+local htt_component = {
+ name = "Component",
+ type = "type",
+ content = {
+ {
+ name = "is",
+ type = "function",
+ params = {
+ { name = "value", type = "any", summary = "some value to check" },
+ },
+ desc = {
+ "Check whether value is a HTT template component"
+ },
+ returns = {
+ { type = "boolean", summary = "true if a ComponentInstance, false otherwise" },
+ }
+ },
+ },
+}
+
htt.name = "htt"
htt.summary = "HTT utility API"
htt.class = "htt"
htt.content = {
+ htt_component,
m_str,
m_env,
m_tcp,
diff --git a/api/typestub.htt b/api/typestub.htt
index 88cef60..874e032 100644
--- a/api/typestub.htt
+++ b/api/typestub.htt
@@ -1,6 +1,6 @@
% -- see typestub.htt.lua for helper functions
-% @component Description
+%
% if type(ctx.val) == "string" then
---{{ctx.val}}
% elseif type(ctx.val) == "table" then
@@ -8,26 +8,26 @@
---{{line}}
% end
% end
-% @end
+%
-% @component Alias
+%
{{@ M.Description {val = ctx.alias.desc or ctx.alias.summary} }}
---@alias {{ctx.alias.name}} {{ctx.alias.def}}
-% @end
+%
-% @component FnArgs
+%
% if #ctx > 0 then
{{ctx[1].name}}
% for i = 2, #ctx do
~>, {{ctx[i].name}}
% end
% end
-% @end
+%
-% @component Function
+%
{{@ M.Description {val = ctx.fn.desc or ctx.fn.summary} }}
% for _, param in ipairs(ctx.fn.params) do
---@param {{param.name}} {{param.type}} {{param.summary}}
@@ -40,10 +40,10 @@
% end
% end
function {{htt.str.join('.', ctx.parent)}}{{ctx.sep or '.'}}{{ctx.fn.name}}({{@ M.FnArgs ctx.fn.params }}) end
-% @end
+%
-% @component Type
+%
% local parent = concat(ctx.parent, ctx.type.name)
---@class {{htt.str.join('.', ctx.parent)}}.{{ctx.type.name}}
% for _, field in ipairs(ctx.type.fields or {}) do
@@ -56,26 +56,29 @@ function {{htt.str.join('.', ctx.parent)}}{{ctx.sep or '.'}}{{ctx.fn.name}}({{@
{{htt.str.join('.', ctx.parent)}}.{{ctx.type.name}} = {}
% end
% for _, item in ipairs(ctx.type.content or {}) do
-% if item.type == "function" then
+% if item.type == "method" then
{{@ M.Function {fn = item, parent = parent, sep = ":"} }}
+% elseif item.type == "function" then
+
+{{@ M.Function {fn = item, parent = parent, sep = "."} }}
% else
% error(string.format("expects .content elems of type to be 'function', got '%s'", item.type))
% end -- if
% end -- for
-% @end
+%
-% @component Constant
+%
% if ctx.val.desc then
{{@ Description {val = ctx.val.desc} }}
% end
---@type {{ctx.val.luatype}}
{{htt.str.join('.', ctx.parent)}}.{{ctx.val.name}} = nil
-% @end
+%
-% @component ModuleContent
+%
% for _, item in ipairs(ctx.mod.content) do
% if item.type == "module" then
@@ -95,10 +98,10 @@ function {{htt.str.join('.', ctx.parent)}}{{ctx.sep or '.'}}{{ctx.fn.name}}({{@
{{@ M.Constant {val = item, parent = ctx.parent} }}
% end -- if
% end -- for
-% @end
+%
-% @component Module
+%
% local parent = concat(ctx.parent, ctx.mod.name)
% local mod_name = pascalCase("htt", ctx.mod.name, "module")
% if ctx.mod.desc then
@@ -107,25 +110,34 @@ function {{htt.str.join('.', ctx.parent)}}{{ctx.sep or '.'}}{{ctx.fn.name}}({{@
---@class {{mod_name}}
{{htt.str.join('.', ctx.parent)}}.{{ctx.mod.name}} = {}
{{@ ModuleContent { mod = ctx.mod, parent = parent } }}
-% @end
+%
-% @component TopLevel
+%
---@meta
+---Render component to file at `fpath`.
+---@param component function the component to render
+---@param fpath string relative path to file
+---@param ctx table? context (arguments) to pass to the component
+function render(component, fpath, ctx) end
+
---{{ctx.mod.summary}}
---@class {{ctx.mod.class}}
% for _, item in ipairs(ctx.mod.content) do
-% if item.type == "module" then
+ % if item.type == "module" then
---@field {{item.name}} {{pascalCase(ctx.mod.class, item.name, "module")}} {{item.summary}}
-% end
+ % end
% end
{{ctx.mod.class}} = {}
% for _, item in ipairs(ctx.mod.content) do
-% if item.type == "module" then
+ % if item.type == "module" then
{{@ Module { mod = item, parent = {"htt"} } }}
+ % elseif item.type == "type" then
+
+{{@ M.Type {type = item, parent = {"htt"}} }}
+ % end
% end
-% end
-% @end
+%
diff --git a/docs/api_module.htt b/docs/api_module.htt
index 010c4c8..c8fe7eb 100644
--- a/docs/api_module.htt
+++ b/docs/api_module.htt
@@ -1,6 +1,6 @@
-% @code
+%%%
local T = require "tags"
-% @end
+%%%
% -- function
% -- {
@@ -49,7 +49,7 @@ local T = require "tags"
% -- written as a NO-OP in case description is nil
-% @component Description
+%
% if type(ctx.val) == "string" then
{{ctx.val}}
@@ -65,38 +65,38 @@ local T = require "tags"
% end
% end
-% @end
+%
-% @component EntrySubHdr
+%
{{ctx.text}}
-% @end
+%
-% @component Tag
+%
{{ctx.text}}
-% @end
+%
-% @component Alias
+%
{{@ Description {val = ctx.item.desc}}}
{{@ EntrySubHdr {text="Definition"}}}
-% @end
+%
-% @component AliasPreview
+%
-% @end
+%
-% @component ParamType
+%
{{ctx.param.type}}
-% @end
+%
-% @component FunctionSignature
+%
% local param_renderer = ctx.param_renderer
{{ctx.fn.name}}(
% if #ctx.fn.params > 0 then
@@ -114,10 +114,10 @@ local T = require "tags"
% else
~>nil
% end
-% @end
+%
-% @component Function
+%
{{@ Description {val = ctx.item.desc}}}
% if #ctx.item.params > 0 then
{{@ EntrySubHdr {text="Parameters"}}}
@@ -149,29 +149,29 @@ local T = require "tags"
% else
No return value
% end
-% @end
+%
-% @component FunctionPreview
+%
-% @end
+%
-% @component Constant
+%
{{@ Description {val = ctx.item.desc}}}
{{@ EntrySubHdr {text="Type"}}}
-% @end
+%
-% @component ConstantPreview
+%
-% @end
+%
-% @component Type
+%
% if ctx.item.fields ~= nil and #ctx.item.fields > 0 then
{{@ EntrySubHdr {text="Fields"}}}
@@ -194,16 +194,16 @@ local T = require "tags"
% end
% end -- / method
-% @end
+%
-% @component TypePreview
+%
-% @end
+%
-% @component Element
-% @code
+%
+%%%
local component
local preview = nil
local tag_color = "green"
@@ -231,7 +231,7 @@ elseif ctx.item.type == "constant" then
else
error(string.format("API, Element: cannot render elements of type '%s'", ctx.item.type))
end
-% @end
+%%%
% -- assign unique ID for show/hide functionality
% local ndx = open_api_defs
% open_api_defs = open_api_defs + 1
@@ -255,10 +255,10 @@ end
~>
% end
-% @end
+%
-% @component main
+%
% -- ctx.module --- module
% -- ctx.lookup(str)
% if ctx.module.desc then
@@ -284,4 +284,4 @@ function initApiModuleState() {
}
}
-% @end
+%
diff --git a/docs/common.htt b/docs/common.htt
index 41a4555..590a0fb 100644
--- a/docs/common.htt
+++ b/docs/common.htt
@@ -1,13 +1,13 @@
%local sitename = "HTT Documentation"
%local model = require("model")
-% @component code
+%
~>{{ctx.text}}
~>
-% @end
+%
-% @component xref
+%
% local page = model.ref2page[ctx.ref]
% if page then
% local url = page.slug .. (ctx.bookmark and ("#" .. ctx.bookmark) or "")
@@ -15,28 +15,28 @@
% else
{{ ctx.txt or ctx.ref or "invalid link"}}
% end
-% @end
+%
-% @component url
-% @code
+%
+%%%
if ctx.ref == nil then
error("ctx.ref is nil - it must be set")
end
if ctx.label == nil then
error("ctx.label is nil, it must be set")
end
-% @end
+%%%
{{ctx.label}}
-% @end
+%
-% @component list
-% @code
+%
+%%%
local lst = ctx
local indent = ctx._indent or 0
local class = htt.str.join(' ', lst.attrs.class)
-% @end
+%%%
<{{lst.tag}} class="{{class}}
% if indent ~= 0 then
~> ml-{{indent}}
@@ -56,11 +56,11 @@ local class = htt.str.join(' ', lst.attrs.class)
~>
% end -- /for
{{lst.tag}}>
-% @end
+%
-% @component codebox
-% @code
+%
+%%%
local style = ""
if ctx.highlight then
-- background here must match style chosen in docs/highlighter.js
@@ -74,7 +74,7 @@ else
style = [[class="bg-stone-100 ]]
end
style = style .. [[p-4 rounded-md"]]
-% @end
+%%%
% -- render a nice box for the code
@@ -83,16 +83,16 @@ style = style .. [[p-4 rounded-md"]]
-% @end
+%
-% @component text
+%
{{ ctx.text }}
-% @end
+%
-% @component run_htt
-% @code
+%
+%%%
-- Validate input
if not ctx.script then
error("must provide script to run")
@@ -117,14 +117,14 @@ f:close()
-- Clean up
os.remove(tmp_output)
-% @end
+%%%
{{@ codebox {c = text, c_args = {text = output} } }}
-% @end
+%
% -- include contents of a file as a text/code box
-% @component include
-% @code
+%
+%%%
local content
local use_highlighter = false
local file = io.open(ctx.file, "r")
@@ -135,48 +135,48 @@ if file then
content = highlighter.highlight_code(content, ctx.lang)
use_highlighter = true
end
-% @end
+%%%
{{@ codebox {c = text, c_args = {text = content}, highlight = use_highlighter } }}
-% @code
+%%%
file:close()
end
-% @end
-% @end
+%%%
+%
% -- produce a code box listing the contents of a particular component
-% @component compSrc
-% @code
+%
+%%%
local fpath = ctx.file:sub(1,2) == "//" and ctx.file:sub(3) or ctx.file
-local include_directives
-if ctx.include_directives ~= nil then
- include_directives = ctx.include_directives ~= false
+local include_tags
+if ctx.include_tags ~= nil then
+ include_tags = ctx.include_tags ~= false
else
- include_directives = false
+ include_tags = false
end
-local content = extract_component_source(fpath, ctx.component, include_directives)
+local content = extract_component_source(fpath, ctx.component, include_tags)
content = require('highlight').highlight_code(content, "htt")
-% @end
+%%%
% -- this actually circumvents the indentation provided by htt
% -- this is a rare case of actually wanting that
{{@ codebox {c = text, c_args = {text = content}, highlight = true } }}
-% @end
+%
% -- evaluate component with args, show output as text/code box
-% @component eval
+%
% local m = require(ctx.file)
% local component_name = ctx.component or "main"
{{@ codebox {c = m[component_name], c_args = ctx.ctx or {} } }}
-% @end
+%
-% @component textbox
+%
{{@ codebox {c = text, c_args = {text = ctx.text} } }}
-% @end
+%
-% @component bNote
+%
{{ctx.icon}}
@@ -188,11 +188,11 @@ content = require('highlight').highlight_code(content, "htt")
-% @end
+%
-% @component note
-% @code
+%
+%%%
local args = {
-- circle with an 'i'
icon = [[ ]],
@@ -200,13 +200,13 @@ local args = {
c = ctx.c,
ctx = ctx.ctx
}
-% @end
+%%%
{{@ bNote args }}
-% @end
+%
-% @component warn
-% @code
+%
+%%%
local args = {
-- circle with an 'i'
icon = [[ ]],
@@ -214,12 +214,12 @@ local args = {
c = ctx.c,
ctx = ctx.ctx
}
-% @end
+%%%
{{@ bNote args }}
-% @end
+%
-% @component menuSection
+%
% local section = ctx.section
i !== '{{ section.title }}') : openSections.push('{{ section.title }}')"
@@ -235,28 +235,26 @@ local args = {
% for _, page in ipairs(section.pages) do
% local x = page.refid == ctx.page.refid and " font-bold" or ""
- % print("page(" .. page.refid .. "), ctx.page(".. ctx.page.refid .. ") ->" .. tostring(x))
{{ page.title }}
% end
-% @end
+%
-% @component menu
+%
% for _, entry in pairs(model.site) do
% if model.is_section(entry) then
{{@ menuSection { section = entry, page = ctx.page } }}
% elseif model.is_page(entry) then
% local x = entry.refid == ctx.page.refid and " font-bold" or ""
- % print("entry(" .. entry.refid .. "), ctx.page(".. ctx.page.refid .. ") ->" .. tostring(x))
{{ entry.title }}
% end -- if
% end -- for
-% @end
+%
-% @component base
+%
% local section = model.ref2section[ctx.page.refid]
@@ -345,4 +343,4 @@ document.addEventListener('DOMContentLoaded', function() {