diff --git a/Brewfile b/Brewfile
deleted file mode 100644
index 85826cd..0000000
--- a/Brewfile
+++ /dev/null
@@ -1,2 +0,0 @@
-# build deps
-brew "go@1.25"
diff --git a/Makefile b/Makefile
index 0bd2067..1284076 100644
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ deps:
$(GO) mod download
build: deps
- CGO_ENABLED=0 $(GO) build -a -v -x -trimpath -ldflags "-X fes/modules/version.gitCommit=$(shell git rev-parse --short HEAD) -s -w -buildid=" -o fes
+ CGO_ENABLED=0 $(GO) build -trimpath -ldflags "-X fes/modules/version.gitCommit=$(shell git rev-parse --short HEAD) -s -w -buildid=" -o fes
@echo "Fes is now built to ./fes"
lint:
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..8896b4e
--- /dev/null
+++ b/TODO
@@ -0,0 +1,4 @@
+ * Fix Gemini rendering
+ * Add Gemini command-line options
+ * Better gemini errors
+ * Fix build steps newlines
diff --git a/lib/fes.lua b/lib/fes.lua
index 968c037..fd5c549 100644
--- a/lib/fes.lua
+++ b/lib/fes.lua
@@ -105,9 +105,8 @@ local default_gemini_footer = [[
{{COPYRIGHT}}
]]
-function M.fes(proto, header, footer)
- proto = proto or "http"
- std.proto = proto
+function M.fes(header, footer)
+ local proto = std.proto
local config = {}
local site_config = {}
@@ -179,6 +178,14 @@ function M:build()
)
return header .. table.concat(self.parts, "\n") .. footer
+ elseif self.proto == "gemini" then
+ local footer = self.footer:gsub(
+ "{{COPYRIGHT}}",
+ self.copyright or "(c) The Copyright Holder"
+ )
+ local header = self.header
+
+ return header .. table.concat(self.parts, "\n") .. "\n\n" .. footer
end
return table.concat(self.parts, "\n")
diff --git a/lib/std.lua b/lib/std.lua
index 8418d60..fa3409c 100644
--- a/lib/std.lua
+++ b/lib/std.lua
@@ -1,6 +1,7 @@
local M = {}
M.proto = "http"
+M.__fes_banner_set = false
local function isHttp()
return M.proto == "http"
@@ -10,18 +11,10 @@ local function isGemini()
return M.proto == "gemini"
end
-local function esc(s)
- s = s or ""
- s = s:gsub("&", "&")
- s = s:gsub("<", "<")
- s = s:gsub(">", ">")
- return s
-end
-
M.p = function(s)
s = s or ""
if isHttp() then
- return "
" .. esc(s) .. "
"
+ return "" .. s .. "
"
elseif isGemini() then
return s
end
@@ -33,7 +26,7 @@ M.h = function(level, s)
if level > 6 then level = 6 end
s = s or ""
if isHttp() then
- return "" .. esc(s) .. ""
+ return "" .. s .. ""
elseif isGemini() then
return string.rep("#", level) .. " " .. s
end
@@ -42,7 +35,7 @@ end
M.codeblock = function(s)
s = s or ""
if isHttp() then
- return "" .. esc(s) .. "
"
+ return "" .. s .. "
"
elseif isGemini() then
return "```\n" .. s .. "\n```"
end
@@ -51,17 +44,17 @@ end
M.inline = function(s)
s = s or ""
if isHttp() then
- return "" .. esc(s) .. ""
+ return "" .. s .. ""
elseif isGemini() then
return "`" .. s .. "`"
end
end
-M.link = function(text, url)
- text = text or ""
+M.link = function(url, text)
url = url or ""
+ text = text or url
if isHttp() then
- return "" .. esc(text) .. ""
+ return "" .. text .. ""
elseif isGemini() then
return "=> " .. url .. " " .. text
end
@@ -73,7 +66,7 @@ M.list = function(items, ordered)
local tag = ordered and "ol" or "ul"
local out = "<" .. tag .. ">"
for _, v in ipairs(items) do
- out = out .. "" .. esc(v) .. ""
+ out = out .. "" .. v .. ""
end
out = out .. "" .. tag .. ">"
return out
@@ -93,7 +86,7 @@ end
M.blockquote = function(s)
s = s or ""
if isHttp() then
- return "" .. esc(s) .. "
"
+ return "" .. s .. "
"
elseif isGemini() then
return "> " .. s
end
@@ -111,7 +104,7 @@ M.image = function(alt, src)
alt = alt or ""
src = src or ""
if isHttp() then
- return "
"
+ return "
"
elseif isGemini() then
return "=> " .. src .. " " .. alt
end
@@ -121,7 +114,7 @@ M.file = function(text, url)
text = text or ""
url = url or ""
if isHttp() then
- return "" .. esc(text) .. ""
+ return "" .. text .. ""
elseif isGemini() then
return "=> " .. url .. " " .. text
end
@@ -130,53 +123,25 @@ end
M.note = function(text)
text = text or ""
if isHttp() then
- return "" .. esc(text) .. "
"
+ return "" .. text .. "
"
elseif isGemini() then
- local width = 31
+ return "\n\n" .. text .. "\n\n"
+ end
+end
- local function wrap_line(line)
- local out = {}
- local i = 1
- local len = #line
+M.banner = function (text)
+ text = text or ""
- if len == 0 then
- out[#out + 1] = ""
- return out
- end
+ if M.__fes_banner_set then
+ error("Page already contains header")
+ return ""
+ end
- while i <= len do
- out[#out + 1] = line:sub(i, i + width - 1)
- i = i + width
- end
-
- return out
- end
-
- local lines = {}
-
- for line in (text .. "\n"):gmatch("(.-)\n") do
- local wrapped = wrap_line(line)
- for _, w in ipairs(wrapped) do
- lines[#lines + 1] = w
- end
- end
-
- local border = "+" .. string.rep("=", width + 2) .. "+"
- local empty = "|" .. string.rep(" ", width + 2) .. "|"
-
- local out = {}
- out[#out + 1] = border
- out[#out + 1] = empty
-
- for _, line in ipairs(lines) do
- local padding = width - #line
- out[#out + 1] = "| " .. line .. string.rep(" ", padding) .. " |"
- end
-
- out[#out + 1] = empty
- out[#out + 1] = border
-
- return table.concat(out, "\n")
+ M.__fes_banner_set = true
+ if isHttp() then
+ return "" .. text .. "
"
+ elseif isGemini() then
+ return text .. "\n"
end
end
diff --git a/modules/new/new.go b/modules/new/new.go
index 2ae216c..b82dddd 100644
--- a/modules/new/new.go
+++ b/modules/new/new.go
@@ -105,11 +105,112 @@ All commands are run from the root of the project, from a terminal:
| Command | Action |
| :------------------------ | :----------------------------------------------- |
-| $$fes run .$$ | Runs the project at $$.$$ |
+| $$fes run .$$ | Runs the project at $$.$$ |
+
+## Gemini
+
+Fes supports many different protocols. One of which is the Gemini protocol; this
+protocol has specific encryption standards which makes the providing $$key.pem$$
+and a $$cert.pem$$ files. *Please* regenerate these files by running this command.
+$$$$$$
+openssl req -x509 -nodes -days 365 \
+ -newkey rsa:2048 \
+ -keyout key.pem \
+ -out cert.pem \
+ -subj "/C=US/ST=State/L=City/O=Local Development/OU=Localhost/CN=localhost" \
+ -addext "subjectAltName=DNS:localhost,IP:127.0.0.1,IP:::1" \
+ -addext "basicConstraints=CA:FALSE" \
+ -addext "keyUsage=digitalSignature,keyEncipherment" \
+ -addext "extendedKeyUsage=serverAuth"
+$$$$$$
## What to learn more?
Check out [Fes's docs](https://docs.vxserver.dev/static/fes.html).`, "$$", "`"), dir, dir)
+ write("key.pem", `-----BEGIN PRIVATE KEY-----
+MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCfl+m81U9+WLBn
+PiJ1ZADnZC+BecXArguAdnbkgDlmfqe1eU6M0PBmXXFHEvJYOh2oYQZ7DMbuLLvo
+DdjomXM4yb9Axu2KDHfflTcw3wHD3850ganf9rwVG460gkVfUGaRiokyCvEJKd05
+BxKmx8Zh6G2tpetaDKm72ONYQFyaBCelYMzaBRpJ2kcPqk/gEhUSvQKVF4oDREm+
+sTEkCTWsjUesiG0393t3psFa/SlZKsNXNrb+N6y9SElKVlQOT28r9YGiDfy5PiAQ
+iFtQse2gqC4IhG2MGi0b4mu4Qa3+d2u3jsmn6Gqt92hKrbFOpz+Ci5GQ+zKXnE+j
+/h40l1J3h/aTM5/qS7malAtXySMVzLQnJzai6IL+nBKbIOMCzP1Bns64Oo7YuuhV
+Cx/sovrvgFF+8j4nLXOBgrx8llYB5cvgVYkNmccXtPzd7hZI6PHgZRGOd0uBKlZ+
+OHeKhgdnz/a+pCUBwJe8JAzX7fzoZ+HLy26ADx2Uywh0Rjfj4gVOSZXaGS0ne0p5
+PciN0xsWQdaAWPcVe6+YYRKS6l6qaWuGaPwVsZSvNgIMMPOgUn7+s2Bxh51DhqZT
+4MDFUJWXFmTnyhHg3Cq7pWJR7pv2erv5q32b8iah5o+CP4W3FeZX1CcBuiIsrimh
+vZZIa5W2vzpkLHbWgI2XGbx8yKRXowIDAQABAoICAENZb5lyB5cRRHh9XztdFYiQ
+3f9s7UhP6qiu1aO+fPrFDm9mHwEMF7eLTYep9j3HYMazE3IQRU8z76SRW21lfJuF
+gEGM8aeldV0UcnMcWXlY1J6ULaVHUb4yn/mLVE1R98cJyLYmqeutEB/F3VgmzJB6
+7vYuI/EfkO2mLOMMXkfc4wJGpIyJRLvP8tcoj4bG+r+qphFXGrYgNmLUEiHcBRup
+j4q/FCBfP2qSI90LI0zu3/rJK1aDFlHW1J8baWOUoBzUAX3rGzDth8iSUr7uJ5L6
+Blsvz68lSM4QslbS2OOfcATJrE5Apex+kTOas023BPVJgwfFCmey3mUdk4+sIG+I
+YpvrfUHBAbhRt1itGjjx/BH3HVtkwKsm3nNNgE8qS0qmziGVa60amLng0OgD4SOH
+QKWrotcojYlWHywdHNAmiaWP+ZV9U0u4T59dkHhjqBoPuY64kNddRCLYItszqOmC
+tamnflcoFPThdBnDpnXhLX+MnvQKIO2K2QTKjdYrkSMvEC/m96H49Vf4w+Fe3coc
+SLsyMqHmYSG3+QtFN3JSmqDdBLQ+bFK0KZOk3IE2UK+lvabmtHuGLkYguur/fOnG
+FvxcC+MIHHFrtSfqfvIrXeGFqe2Fb6DIKdMJFPV8iP5Px91A0GAGeabyktyya1n5
+kk5nMJY3A7rTmnDO2PUBAoIBAQDSd+pvNGDf/We74+NODKQBcleCfF0NNzvRIuYH
+9vel5jhyD28Y30XQS7+YBo3Y5Yo5pVlJ425Z5CveZOmr4VImuYG8LTbbGYY8ns3c
+R/IdP1ByAcIa1eRGQNcKHid7RW4aEoFdvW3jZNj6/ukbJwd9ZHOt4HEUv5MOObn7
+VXiXiwHjVy3X4uD5j0bHS4owd7S3Ygg0OneUzX3XJ+8qUgfU9B+lD3SbtsI4baoU
+qUKcQc/0yXKvJvoz9oX2tjQOHqGrGwHdootc2CLnr0PMI7fKBwT3k63B+24xEGcx
+OAPc5tUuiqIewiCn1oZbeCxmNnnimkAjDfG2KXMXj1R1G96BAoIBAQDCHnTNQhXH
+tcfwnxj86E+Zd7ORS7iH/5eWvnspt2pnNCpufLFQlbdiL3d9ysSN9nw3+y15/o83
+R79s7fLdC0+blc6q/ZQEdB1C+8YQa0nTlqqlZWVbRPjQUV+SfGssaZFEO4W7QWh3
+hJL14HbWUFC3XSdMAeKTNOcgvfVvQ9M8HlJI1ZPo4Pe4rGNFIEsKUz/6HVE7HFgQ
+OwcLSxZlSQSQ6/YErP/XJoyQUPjHldAjphV/rn28cvh2quoI35fbBuZu5pyKLXTg
+RKbdWbeoIZTthRojpqnfqnIR+rPXIIiaMYhStdPshNUxLL7DX+/3yI05qq8R+yqa
+2gLb2mJltuwjAoIBAF0WQI/ywK4Q7CKEBnLs0FT7d4z06EsCFOjI4KjBKIMtseVw
+whhkGAKqnhDlRTObQmmAol81wgbsDiMMyvUEcUtDXQgXj12UinShYDd/cqxQ5omm
+EW3BEHeqEfIdqCSzbqEFckY9lC6w2e8Zc4xY1M028psC28DrgmUWTxXEldOg3bLp
+ShNj+1Eld46J8JLDPyCksTA4c89Sm8ffl75GDcS4PI7KqS59xKUki8cbnaRyz0Fb
+H+gr+xmkfVfC+n8MOUDubwLR84Wa6sVCFWBio9UtCZteq8lSJUh6EsoIFl1LkxpE
+orOr9LmG/mHSYwDKM1pwEtHuRuvkpUzUTeyF6QECggEAbm/vWZtgUsdbocyR5cix
+CImuUlo2+MBz2KIz5c7grShjf4pXQpZ6x1Rj8d/7JRz3HM482Cv4BKZABNP3GMTH
+nKeE9YjgvgvlXedpjovLa6JLIV/nYx6BQ9sXuXopaxIAQEZw1dDngx+ckGAMm+8D
+jN5lbfugkMlHOTx5Nrzqn0hM3f0McjATHzCMJZayuoQUYNJvFWcRvuImJsmoSyVY
+gK6Nv6lAwIHA9JXsg3f6+10Q3BxEkoMCUlj4XuX+OfDaBnwS0RX9aV4FZOcW8oNw
+fBT+gwvdl08cKJht2lU7AiZt/UhO8j+8HobrXLHnDxw9JHKzuVIgsgqYF8ZNtrpz
+6wKCAQEAqJc9xfNYL2jyJTVBvqX34Uct9xV1fq7z45B3gpPHj4tc0dBOIwPKSsu8
+rGyefPuMDvbecJoaXqRZGQEcv03ecLVtHHDCsJcWavth9sCQJW9mnOxjOnLHdGnl
+h2yIV4iVzNEx5XA1+0JRAAwFMXrC9LUZDTT61opjohMJSEySo/HVekoWG9A0bQGn
+Ui+JbtLeuuCwwAGSgdAhVkjr27ANyFtjR63KVrDvSLbYFyZXKxrRYnZWs92Ho/g6
+oTLnUSmkbLlhsUDjknAaNfp+enETSoPHcpkd7MeqVw2oYrLw6MCo4h2tBsIgtZEd
+h6CgX4Gc3+bhvKx36XYxVwScPJUWsQ==
+-----END PRIVATE KEY-----`)
+ write("cert.pem", `-----BEGIN CERTIFICATE-----
+MIIFmzCCA4OgAwIBAgIUZGaMDLeCAQplfhhjXb2HaL6xpFYwDQYJKoZIhvcNAQEL
+BQAwXTELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5
+MQwwCgYDVQQKDANPcmcxDTALBgNVBAsMBFVuaXQxEjAQBgNVBAMMCWxvY2FsaG9z
+dDAeFw0yNjAyMjQwMjUwMzVaFw0yNzAyMjQwMjUwMzVaMF0xCzAJBgNVBAYTAlVT
+MQ4wDAYDVQQIDAVTdGF0ZTENMAsGA1UEBwwEQ2l0eTEMMAoGA1UECgwDT3JnMQ0w
+CwYDVQQLDARVbml0MRIwEAYDVQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQCfl+m81U9+WLBnPiJ1ZADnZC+BecXArguAdnbkgDlm
+fqe1eU6M0PBmXXFHEvJYOh2oYQZ7DMbuLLvoDdjomXM4yb9Axu2KDHfflTcw3wHD
+3850ganf9rwVG460gkVfUGaRiokyCvEJKd05BxKmx8Zh6G2tpetaDKm72ONYQFya
+BCelYMzaBRpJ2kcPqk/gEhUSvQKVF4oDREm+sTEkCTWsjUesiG0393t3psFa/SlZ
+KsNXNrb+N6y9SElKVlQOT28r9YGiDfy5PiAQiFtQse2gqC4IhG2MGi0b4mu4Qa3+
+d2u3jsmn6Gqt92hKrbFOpz+Ci5GQ+zKXnE+j/h40l1J3h/aTM5/qS7malAtXySMV
+zLQnJzai6IL+nBKbIOMCzP1Bns64Oo7YuuhVCx/sovrvgFF+8j4nLXOBgrx8llYB
+5cvgVYkNmccXtPzd7hZI6PHgZRGOd0uBKlZ+OHeKhgdnz/a+pCUBwJe8JAzX7fzo
+Z+HLy26ADx2Uywh0Rjfj4gVOSZXaGS0ne0p5PciN0xsWQdaAWPcVe6+YYRKS6l6q
+aWuGaPwVsZSvNgIMMPOgUn7+s2Bxh51DhqZT4MDFUJWXFmTnyhHg3Cq7pWJR7pv2
+erv5q32b8iah5o+CP4W3FeZX1CcBuiIsrimhvZZIa5W2vzpkLHbWgI2XGbx8yKRX
+owIDAQABo1MwUTAdBgNVHQ4EFgQUcyq+ZZWmAUejOPEQpHpl4hOllHswHwYDVR0j
+BBgwFoAUcyq+ZZWmAUejOPEQpHpl4hOllHswDwYDVR0TAQH/BAUwAwEB/zANBgkq
+hkiG9w0BAQsFAAOCAgEANwdjxlPHqvOOyNTFJcFhcNff3862/74CyCiglrstk/ea
+txjyHxXFwXOtyAtm0tqaQPpzHWFM5MDqVD7Qip4aZrPcRvvfJ8zxXuakrgy7oI6i
+Wl4/BXzvIoxh8MyFVC7VdGmuv11fq091RaNPlnz5lH9Qxhb6QCGbk73PjTXxD/7A
+yusNiXuJvx3oRhLLGuksotFKEnngOq21Jla3ZPUmJTLAZdk/joXITk5Q64ZBp5uD
+rpxFZDtdHTBuL3nmNPUHixsxQRFzCSloufRlatdI2ldDc+d2WLLFhkpdM35Oedf3
+Hib0VXPgJ8j/w6RK+oYKMP27RojMFXALolzRBSQu3Zbd1bD1qVhh/dO5Uyn4E3mb
+2LW5+a9zuabD9wt8smSU9V5ZYw5hcR0ANN7xYmaMvGFKrNPNkI3m0c2dyj22vgg0
+zQqeMze4KxZqDf/gFifJ4UIybBAgc/p1uOIceFTSYplVXJQIgFACn9l6c4Zo0GZD
+H48iKQLwlxDdUSM8aHtItWxRddLCL7lYNKtu2/qu8I9NKkjx4/Kn3I9Is/f37EIn
+rF3ygUg3ee5zo3fvMjlhCNs6djm+ANx2KzdZkS7UU/jb0o+OSEvoMIgZh5NNgUlC
+aVR3opS3PTqwu4plN0Evh5kr3nEOx0vcIK726DwnpgNRhcG9cNcSi2UB4NYCWaw=
+-----END CERTIFICATE-----`)
ui.Hint("you can run this with `fes run %s`", dir)
diff --git a/modules/server/archive.go b/modules/server/archive.go
index 4d48fc0..f006e3c 100644
--- a/modules/server/archive.go
+++ b/modules/server/archive.go
@@ -1,8 +1,9 @@
package server
import (
+ "errors"
"fmt"
- "net/http"
+ "io"
"os"
"path"
"path/filepath"
@@ -95,15 +96,22 @@ func generateArchiveIndex(fsPath string, urlPath string) (string, error) {
}
/* helper to read the archive files */
-func readArchive(w http.ResponseWriter, route string) error {
- fsPath := "." + route
- if info, err := os.Stat(fsPath); err == nil && info.IsDir() {
- if page, err := generateArchiveIndex(fsPath, route); err == nil {
- w.Write([]byte(page))
- return nil
- } else {
- return err
+func readArchive(w io.Writer, route string, protcol Protocols) error {
+ switch protcol {
+ case HTTP:
+ fsPath := "." + route
+ if info, err := os.Stat(fsPath); err == nil && info.IsDir() {
+ if page, err := generateArchiveIndex(fsPath, route); err == nil {
+ w.Write([]byte(page))
+ return nil
+ } else {
+ return err
+ }
}
+ case GEMINI:
+ panic(errors.New("TODO"))
+ default:
+ panic(errors.New("Invalid Protocol"))
}
return nil
}
diff --git a/modules/server/gemini.go b/modules/server/gemini.go
index f668781..0e94ec6 100644
--- a/modules/server/gemini.go
+++ b/modules/server/gemini.go
@@ -25,17 +25,9 @@ func geminiHandler(w gemini.ResponseWriter, r *gemini.Request) {
route = r.URL.Path
if strings.HasPrefix(route, "/archive") {
- w.Write([]byte("# error: not implemented"))
- // err = readArchive(w, route)
+ err = readArchive(w, route, GEMINI)
} else {
w.WriteHeader(gemini.StatusNotFound, "StatusNotFound")
- w.Write([]byte(`
-404 Not Found
-
-404 Not Found
-
fes
-
-`))
}
return
}
@@ -49,7 +41,7 @@ func geminiHandler(w gemini.ResponseWriter, r *gemini.Request) {
var data []byte
if strings.HasSuffix(route, ".lua") {
- data, err = render(route, reqData{path: r.URL.Path, params: params}, &Sets)
+ data, err = render(route, reqData{path: r.URL.Path, params: params}, GEMINI)
} else if strings.HasSuffix(route, ".md") {
data, err = os.ReadFile(route)
data = []byte(markdownToHTML(string(data)))
diff --git a/modules/server/http.go b/modules/server/http.go
index 6577e95..7b370b1 100644
--- a/modules/server/http.go
+++ b/modules/server/http.go
@@ -26,7 +26,7 @@ func httpHandler(w http.ResponseWriter, r *http.Request) {
route = r.URL.Path
if strings.HasPrefix(route, "/archive") {
- err = readArchive(w, route)
+ err = readArchive(w, route, HTTP)
} else {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(`
@@ -49,7 +49,7 @@ func httpHandler(w http.ResponseWriter, r *http.Request) {
var data []byte
if strings.HasSuffix(route, ".lua") {
- data, err = render(route, reqData{path: r.URL.Path, params: params}, &Sets)
+ data, err = render(route, reqData{path: r.URL.Path, params: params}, HTTP)
} else if strings.HasSuffix(route, ".md") {
data, err = os.ReadFile(route)
data = []byte(markdownToHTML(string(data)))
diff --git a/modules/server/render.go b/modules/server/render.go
index f41e205..95422cc 100644
--- a/modules/server/render.go
+++ b/modules/server/render.go
@@ -14,14 +14,7 @@ type reqData struct {
params map[string]string
}
-type DeclarativeSets struct {
- protos struct {
- http bool
- gemini bool
- }
-}
-
-func render(luapath string, requestData reqData, setBuffer *DeclarativeSets) ([]byte, error) {
+func render(luapath string, requestData reqData, protocol Protocols) ([]byte, error) {
L := lua.NewState()
defer L.Close()
@@ -74,6 +67,36 @@ func render(luapath string, requestData reqData, setBuffer *DeclarativeSets) ([]
panic("fes module did not return table")
}
+ if err := L.CallByParam(lua.P{
+ Fn: L.GetGlobal("require"),
+ NRet: 1,
+ Protect: true,
+ }, lua.LString("lib.std")); err != nil {
+ panic(err)
+ }
+
+ stdMod := L.Get(-1)
+ L.Pop(1)
+
+ stdTbl, ok := stdMod.(*lua.LTable)
+ if !ok {
+ panic("lib.std did not return table")
+ }
+
+ proto := func() string {
+ switch protocol {
+ case HTTP:
+ return "http"
+ case GEMINI:
+ return "gemini"
+ default:
+ return "http"
+ }
+ }()
+
+ stdTbl.RawSetString("proto", lua.LString(proto))
+ tbl.RawSetString("std", stdTbl)
+
bus := L.NewTable()
bus.RawSetString("url", lua.LString(requestData.path))
diff --git a/modules/server/server.go b/modules/server/server.go
index b98b1e8..8b7a787 100644
--- a/modules/server/server.go
+++ b/modules/server/server.go
@@ -11,8 +11,14 @@ import (
"sync"
)
+type Protocols int
+
+const (
+ HTTP Protocols = iota
+ GEMINI
+)
+
var Routes map[string]string
-var Sets DeclarativeSets
func Start(dir string) {
if err := os.Chdir(dir); err != nil {
diff --git a/test/default/README.md b/test/README.md
similarity index 96%
rename from test/default/README.md
rename to test/README.md
index 7e8b977..748b9e4 100644
--- a/test/default/README.md
+++ b/test/README.md
@@ -1,7 +1,7 @@
-# default
+# test
```
-fes new default
+fes new test
```
> **Know what you are doing?** Delete this file. Have fun!
diff --git a/test/cert.pem b/test/cert.pem
new file mode 100644
index 0000000..8b87bde
--- /dev/null
+++ b/test/cert.pem
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFmzCCA4OgAwIBAgIUZGaMDLeCAQplfhhjXb2HaL6xpFYwDQYJKoZIhvcNAQEL
+BQAwXTELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5
+MQwwCgYDVQQKDANPcmcxDTALBgNVBAsMBFVuaXQxEjAQBgNVBAMMCWxvY2FsaG9z
+dDAeFw0yNjAyMjQwMjUwMzVaFw0yNzAyMjQwMjUwMzVaMF0xCzAJBgNVBAYTAlVT
+MQ4wDAYDVQQIDAVTdGF0ZTENMAsGA1UEBwwEQ2l0eTEMMAoGA1UECgwDT3JnMQ0w
+CwYDVQQLDARVbml0MRIwEAYDVQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQCfl+m81U9+WLBnPiJ1ZADnZC+BecXArguAdnbkgDlm
+fqe1eU6M0PBmXXFHEvJYOh2oYQZ7DMbuLLvoDdjomXM4yb9Axu2KDHfflTcw3wHD
+3850ganf9rwVG460gkVfUGaRiokyCvEJKd05BxKmx8Zh6G2tpetaDKm72ONYQFya
+BCelYMzaBRpJ2kcPqk/gEhUSvQKVF4oDREm+sTEkCTWsjUesiG0393t3psFa/SlZ
+KsNXNrb+N6y9SElKVlQOT28r9YGiDfy5PiAQiFtQse2gqC4IhG2MGi0b4mu4Qa3+
+d2u3jsmn6Gqt92hKrbFOpz+Ci5GQ+zKXnE+j/h40l1J3h/aTM5/qS7malAtXySMV
+zLQnJzai6IL+nBKbIOMCzP1Bns64Oo7YuuhVCx/sovrvgFF+8j4nLXOBgrx8llYB
+5cvgVYkNmccXtPzd7hZI6PHgZRGOd0uBKlZ+OHeKhgdnz/a+pCUBwJe8JAzX7fzo
+Z+HLy26ADx2Uywh0Rjfj4gVOSZXaGS0ne0p5PciN0xsWQdaAWPcVe6+YYRKS6l6q
+aWuGaPwVsZSvNgIMMPOgUn7+s2Bxh51DhqZT4MDFUJWXFmTnyhHg3Cq7pWJR7pv2
+erv5q32b8iah5o+CP4W3FeZX1CcBuiIsrimhvZZIa5W2vzpkLHbWgI2XGbx8yKRX
+owIDAQABo1MwUTAdBgNVHQ4EFgQUcyq+ZZWmAUejOPEQpHpl4hOllHswHwYDVR0j
+BBgwFoAUcyq+ZZWmAUejOPEQpHpl4hOllHswDwYDVR0TAQH/BAUwAwEB/zANBgkq
+hkiG9w0BAQsFAAOCAgEANwdjxlPHqvOOyNTFJcFhcNff3862/74CyCiglrstk/ea
+txjyHxXFwXOtyAtm0tqaQPpzHWFM5MDqVD7Qip4aZrPcRvvfJ8zxXuakrgy7oI6i
+Wl4/BXzvIoxh8MyFVC7VdGmuv11fq091RaNPlnz5lH9Qxhb6QCGbk73PjTXxD/7A
+yusNiXuJvx3oRhLLGuksotFKEnngOq21Jla3ZPUmJTLAZdk/joXITk5Q64ZBp5uD
+rpxFZDtdHTBuL3nmNPUHixsxQRFzCSloufRlatdI2ldDc+d2WLLFhkpdM35Oedf3
+Hib0VXPgJ8j/w6RK+oYKMP27RojMFXALolzRBSQu3Zbd1bD1qVhh/dO5Uyn4E3mb
+2LW5+a9zuabD9wt8smSU9V5ZYw5hcR0ANN7xYmaMvGFKrNPNkI3m0c2dyj22vgg0
+zQqeMze4KxZqDf/gFifJ4UIybBAgc/p1uOIceFTSYplVXJQIgFACn9l6c4Zo0GZD
+H48iKQLwlxDdUSM8aHtItWxRddLCL7lYNKtu2/qu8I9NKkjx4/Kn3I9Is/f37EIn
+rF3ygUg3ee5zo3fvMjlhCNs6djm+ANx2KzdZkS7UU/jb0o+OSEvoMIgZh5NNgUlC
+aVR3opS3PTqwu4plN0Evh5kr3nEOx0vcIK726DwnpgNRhcG9cNcSi2UB4NYCWaw=
+-----END CERTIFICATE-----
diff --git a/test/default/www/index.lua b/test/default/www/index.lua
deleted file mode 100644
index e828f38..0000000
--- a/test/default/www/index.lua
+++ /dev/null
@@ -1,8 +0,0 @@
-local fes = require("fes")
-local site = fes.fes()
-
--- site.copyright = fes.util.copyright("https://example.com", "vx-clutch")
-
-site:h(1, "Hello, World!")
-
-return site
\ No newline at end of file
diff --git a/test/default_gmi/README.md b/test/default_gmi/README.md
deleted file mode 100644
index 7e8b977..0000000
--- a/test/default_gmi/README.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# default
-
-```
-fes new default
-```
-
-> **Know what you are doing?** Delete this file. Have fun!
-
-## Project Structure
-
-Inside your Fes project, you'll see the following directories and files:
-
-```
-.
-├── Fes.toml
-├── README.md
-└── www
- └── index.lua
-```
-
-Fes looks for `.lua` files in the `www/` directory. Each file is exposed as a route based on its file name.
-
-## Commands
-
-All commands are run from the root of the project, from a terminal:
-
-| Command | Action |
-| :------------------------ | :----------------------------------------------- |
-| `fes run .` | Runs the project at `.` |
-
-## What to learn more?
-
-Check out [Fes's docs](https://docs.vxserver.dev/static/fes.html).
\ No newline at end of file
diff --git a/test/default_gmi/cert.pem b/test/default_gmi/cert.pem
deleted file mode 100644
index 7034838..0000000
--- a/test/default_gmi/cert.pem
+++ /dev/null
@@ -1,18 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIC8zCCAdugAwIBAgIUWobZlV5Gp72Z4LUD/hjRb2aa+GgwDQYJKoZIhvcNAQEL
-BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI2MDIxNTAzMDgxOVoXDTI3MDIx
-NTAzMDgxOVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEAxvNs7/1cJ/6kdlo7CAwIUc+d8L5cbqw3KKYMl/9JSnqp
-HutIcl23LrF0ylClnAkTbuuDmzED73Z8788eaoIsjmwNA5yapkmDkjh/y8CRg1+2
-8iEuneHAeKZosHGdfjBcOzLVPo713Mw2m3yXeeVLfn/FLUql3l/Au0xu+oVT4XB/
-aZ//j3spgT4xIFggXMYchs9EW1pJpD4pnKDo+ZBATuAJjDy4OstGKzFiEiNSWfiI
-K8VLM6V74xdEiojcyy2TCHDSYOIozsB5iQRV9PcXyyIEGw7wTx/o9wrkShff+pyn
-seLJ644FnGRvEkZpTWg18NTC18JNLVGqmuSqbwzGZQIDAQABoz0wOzAaBgNVHREE
-EzARgglsb2NhbGhvc3SHBH8AAAEwHQYDVR0OBBYEFI/tgi60jQUeMqILEeZf7m80
-MWB1MA0GCSqGSIb3DQEBCwUAA4IBAQATIwsWSuPBFb/n4q60QgScVIGjTIHTJGUT
-di6ButyVug4zCltsMIw+VwfigRk77eyqZjbdm9Tmn/1cUTxLnNMBNyUPabojmf32
-ItWGCLmI9QBW2/d8oK1rxLiDDQ5FwzWloeavwJC2E3xKy5xmcQicv1iTvpJnLRFJ
-amyrY9dDVo0qAsLnnOmwc0OEnzpcYclegTOD9jUgEMJ00oLrYsWqXC8KvPaWcIu7
-MiCj9j+U9ncU0fWE0WCOZr8VOgjtJeiHN1CLPOWbsSaZRWLBWlgF4AJGI2VXVM7d
-BAb5y4cDIqmDnrTl3DUk8BlCnMdHopvl1ZrZWKgQJbfhvOagUv91
------END CERTIFICATE-----
diff --git a/test/default_gmi/key.pem b/test/default_gmi/key.pem
deleted file mode 100644
index f71e8a9..0000000
--- a/test/default_gmi/key.pem
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDG82zv/Vwn/qR2
-WjsIDAhRz53wvlxurDcopgyX/0lKeqke60hyXbcusXTKUKWcCRNu64ObMQPvdnzv
-zx5qgiyObA0DnJqmSYOSOH/LwJGDX7byIS6d4cB4pmiwcZ1+MFw7MtU+jvXczDab
-fJd55Ut+f8UtSqXeX8C7TG76hVPhcH9pn/+PeymBPjEgWCBcxhyGz0RbWkmkPimc
-oOj5kEBO4AmMPLg6y0YrMWISI1JZ+IgrxUszpXvjF0SKiNzLLZMIcNJg4ijOwHmJ
-BFX09xfLIgQbDvBPH+j3CuRKF9/6nKex4snrjgWcZG8SRmlNaDXw1MLXwk0tUaqa
-5KpvDMZlAgMBAAECggEAFR1lvOzDWJ1OgB8gb8CzK1ehGBlj/vz5F6/T21flQ+nT
-xCvNcxHeLK75ybUYdoCCFv4Y6CIiHEqThPIS9NPe/bibAvyebzKTK7QiYBIOf4Zr
-iLQb2fbJMiTbLIrKX8erKj9BYZPTpTzpOMRW4UGEKydNWnq3MuwvrNE2YBFBb0YM
-3RcSxs+nEkYs0sbZGtkqy2gYGbr0WcWHi3tNRWTT5FXM5VY84XY8QCPqDTj5fXys
-DwDFQDBJc0l/IYRcaen+4UNliVaJRto/ZZaqhwnPra1d16PLYhWmfAkYKgWCEIhw
-+b/+mV+6oUnORGbmq1TiSzZ9U9WqNwSo/8ZoNC8WywKBgQDm7SK2zFyXx4SdnVfL
-XikJCYLdnsLaaP/Z7iCZgt7oaHUDg6Eb/SAqdEB/YPcCHXox6ChUOqHe7ee7ROCk
-1wD3xI+kV4E9yZqs2zeRJrv8W8Q0JjJXdVrXy6vFQ0z/132QNXLJpr7KXGctE9zX
-XheT+yisgJQSd6O7HX1Ow67EKwKBgQDcjX7tThSw+dloyEywbi3dA8VmGVuH3UPk
-3zgD6dEA/xt/OpD3LgDgHOLIL+lbR4LAfxjS8RTHGOON8iVcCAi6k7gAf+0WU2Uh
-6GkA4gUM6mx1zSl7k4/vmJa1WpxG11bCdWPvNt3X0cvYMGNPfhTITqz4F81M6+9p
-ZEmaCGaHrwKBgGGmSzSjbFAeZXzE6TgtJAsXQ4h1tw3msrI0GQLxLVN3wGtxAPK1
-8iEhsZhrp2f0kRSDiHI9rO95CLHO6XOrG1SqgNdMzXEUTFzmAjRV/c4z+97VfBox
-nO19ybALyoaxV/5gK58L7MfjlRmhuZQ0zKGd5lAzuumoP8tDKBbjdoarAoGAcNJ9
-DH21vfaBjcVw3YvvMDE+qITuOqkokwrRB8dzIBRgB4x5HcjNr9d29zrzH7uMGlap
-5zZmD5ceyL0G+XYuqOrp5G+MY7BTeq3+EPKN7NZ6lyRVRR7uMX2YEruAWAjOG/mb
-HoKtpzpuEXBnTQHNNc5xUxQx9Fh5ByvDLuV/NYcCgYEAy/An+fPP6Lkl4nwbcnbP
-npAimzB6z25ftFeNMfggJYOukQomAeuwS5QYdLvqtPdqjtrqRQJrXFW9q0Nmt5HM
-h0WuMCrKDWfYdZbZ8E6y3zqUXb5J66M2mcu+8ED6zUvktOBHXgIS7YnXYf46illx
-3+8QDk1ufotloNSokoM/BTw=
------END PRIVATE KEY-----
diff --git a/test/default_gmi/localhost.cnf b/test/default_gmi/localhost.cnf
deleted file mode 100644
index 9f88d19..0000000
--- a/test/default_gmi/localhost.cnf
+++ /dev/null
@@ -1,16 +0,0 @@
-[req]
-default_bits = 2048
-prompt = no
-default_md = sha256
-x509_extensions = v3_req
-distinguished_name = dn
-
-[dn]
-CN = localhost
-
-[v3_req]
-subjectAltName = @alt_names
-
-[alt_names]
-DNS.1 = localhost
-IP.1 = 127.0.0.1
diff --git a/test/default_gmi/www/index.lua b/test/default_gmi/www/index.lua
deleted file mode 100644
index f1fe9b1..0000000
--- a/test/default_gmi/www/index.lua
+++ /dev/null
@@ -1,10 +0,0 @@
-local fes = require("fes")
-local site = fes.fes("gemini")
-
--- site.copyright = fes.util.copyright("https://example.com", "vx-clutch")
-
-site:h(1, "Hello, World!")
-
-site:note("Hello, World!. djsaklllllll\nlllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll")
-
-return site
diff --git a/test/error/README.md b/test/error/README.md
deleted file mode 100644
index 8acd1c3..0000000
--- a/test/error/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# error
-
-This is expected to return the following error:
-
-```
-Error loading page: www/index.lua line:6(column:6) near 'return': syntax error
-```
diff --git a/test/error/www/index.lua b/test/error/www/index.lua
deleted file mode 100644
index 68a918e..0000000
--- a/test/error/www/index.lua
+++ /dev/null
@@ -1,6 +0,0 @@
-local fes = require("fes")
-local site = fes.fes()
-
-site.
-
-return site
diff --git a/test/key.pem b/test/key.pem
new file mode 100644
index 0000000..9aafa51
--- /dev/null
+++ b/test/key.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCfl+m81U9+WLBn
+PiJ1ZADnZC+BecXArguAdnbkgDlmfqe1eU6M0PBmXXFHEvJYOh2oYQZ7DMbuLLvo
+DdjomXM4yb9Axu2KDHfflTcw3wHD3850ganf9rwVG460gkVfUGaRiokyCvEJKd05
+BxKmx8Zh6G2tpetaDKm72ONYQFyaBCelYMzaBRpJ2kcPqk/gEhUSvQKVF4oDREm+
+sTEkCTWsjUesiG0393t3psFa/SlZKsNXNrb+N6y9SElKVlQOT28r9YGiDfy5PiAQ
+iFtQse2gqC4IhG2MGi0b4mu4Qa3+d2u3jsmn6Gqt92hKrbFOpz+Ci5GQ+zKXnE+j
+/h40l1J3h/aTM5/qS7malAtXySMVzLQnJzai6IL+nBKbIOMCzP1Bns64Oo7YuuhV
+Cx/sovrvgFF+8j4nLXOBgrx8llYB5cvgVYkNmccXtPzd7hZI6PHgZRGOd0uBKlZ+
+OHeKhgdnz/a+pCUBwJe8JAzX7fzoZ+HLy26ADx2Uywh0Rjfj4gVOSZXaGS0ne0p5
+PciN0xsWQdaAWPcVe6+YYRKS6l6qaWuGaPwVsZSvNgIMMPOgUn7+s2Bxh51DhqZT
+4MDFUJWXFmTnyhHg3Cq7pWJR7pv2erv5q32b8iah5o+CP4W3FeZX1CcBuiIsrimh
+vZZIa5W2vzpkLHbWgI2XGbx8yKRXowIDAQABAoICAENZb5lyB5cRRHh9XztdFYiQ
+3f9s7UhP6qiu1aO+fPrFDm9mHwEMF7eLTYep9j3HYMazE3IQRU8z76SRW21lfJuF
+gEGM8aeldV0UcnMcWXlY1J6ULaVHUb4yn/mLVE1R98cJyLYmqeutEB/F3VgmzJB6
+7vYuI/EfkO2mLOMMXkfc4wJGpIyJRLvP8tcoj4bG+r+qphFXGrYgNmLUEiHcBRup
+j4q/FCBfP2qSI90LI0zu3/rJK1aDFlHW1J8baWOUoBzUAX3rGzDth8iSUr7uJ5L6
+Blsvz68lSM4QslbS2OOfcATJrE5Apex+kTOas023BPVJgwfFCmey3mUdk4+sIG+I
+YpvrfUHBAbhRt1itGjjx/BH3HVtkwKsm3nNNgE8qS0qmziGVa60amLng0OgD4SOH
+QKWrotcojYlWHywdHNAmiaWP+ZV9U0u4T59dkHhjqBoPuY64kNddRCLYItszqOmC
+tamnflcoFPThdBnDpnXhLX+MnvQKIO2K2QTKjdYrkSMvEC/m96H49Vf4w+Fe3coc
+SLsyMqHmYSG3+QtFN3JSmqDdBLQ+bFK0KZOk3IE2UK+lvabmtHuGLkYguur/fOnG
+FvxcC+MIHHFrtSfqfvIrXeGFqe2Fb6DIKdMJFPV8iP5Px91A0GAGeabyktyya1n5
+kk5nMJY3A7rTmnDO2PUBAoIBAQDSd+pvNGDf/We74+NODKQBcleCfF0NNzvRIuYH
+9vel5jhyD28Y30XQS7+YBo3Y5Yo5pVlJ425Z5CveZOmr4VImuYG8LTbbGYY8ns3c
+R/IdP1ByAcIa1eRGQNcKHid7RW4aEoFdvW3jZNj6/ukbJwd9ZHOt4HEUv5MOObn7
+VXiXiwHjVy3X4uD5j0bHS4owd7S3Ygg0OneUzX3XJ+8qUgfU9B+lD3SbtsI4baoU
+qUKcQc/0yXKvJvoz9oX2tjQOHqGrGwHdootc2CLnr0PMI7fKBwT3k63B+24xEGcx
+OAPc5tUuiqIewiCn1oZbeCxmNnnimkAjDfG2KXMXj1R1G96BAoIBAQDCHnTNQhXH
+tcfwnxj86E+Zd7ORS7iH/5eWvnspt2pnNCpufLFQlbdiL3d9ysSN9nw3+y15/o83
+R79s7fLdC0+blc6q/ZQEdB1C+8YQa0nTlqqlZWVbRPjQUV+SfGssaZFEO4W7QWh3
+hJL14HbWUFC3XSdMAeKTNOcgvfVvQ9M8HlJI1ZPo4Pe4rGNFIEsKUz/6HVE7HFgQ
+OwcLSxZlSQSQ6/YErP/XJoyQUPjHldAjphV/rn28cvh2quoI35fbBuZu5pyKLXTg
+RKbdWbeoIZTthRojpqnfqnIR+rPXIIiaMYhStdPshNUxLL7DX+/3yI05qq8R+yqa
+2gLb2mJltuwjAoIBAF0WQI/ywK4Q7CKEBnLs0FT7d4z06EsCFOjI4KjBKIMtseVw
+whhkGAKqnhDlRTObQmmAol81wgbsDiMMyvUEcUtDXQgXj12UinShYDd/cqxQ5omm
+EW3BEHeqEfIdqCSzbqEFckY9lC6w2e8Zc4xY1M028psC28DrgmUWTxXEldOg3bLp
+ShNj+1Eld46J8JLDPyCksTA4c89Sm8ffl75GDcS4PI7KqS59xKUki8cbnaRyz0Fb
+H+gr+xmkfVfC+n8MOUDubwLR84Wa6sVCFWBio9UtCZteq8lSJUh6EsoIFl1LkxpE
+orOr9LmG/mHSYwDKM1pwEtHuRuvkpUzUTeyF6QECggEAbm/vWZtgUsdbocyR5cix
+CImuUlo2+MBz2KIz5c7grShjf4pXQpZ6x1Rj8d/7JRz3HM482Cv4BKZABNP3GMTH
+nKeE9YjgvgvlXedpjovLa6JLIV/nYx6BQ9sXuXopaxIAQEZw1dDngx+ckGAMm+8D
+jN5lbfugkMlHOTx5Nrzqn0hM3f0McjATHzCMJZayuoQUYNJvFWcRvuImJsmoSyVY
+gK6Nv6lAwIHA9JXsg3f6+10Q3BxEkoMCUlj4XuX+OfDaBnwS0RX9aV4FZOcW8oNw
+fBT+gwvdl08cKJht2lU7AiZt/UhO8j+8HobrXLHnDxw9JHKzuVIgsgqYF8ZNtrpz
+6wKCAQEAqJc9xfNYL2jyJTVBvqX34Uct9xV1fq7z45B3gpPHj4tc0dBOIwPKSsu8
+rGyefPuMDvbecJoaXqRZGQEcv03ecLVtHHDCsJcWavth9sCQJW9mnOxjOnLHdGnl
+h2yIV4iVzNEx5XA1+0JRAAwFMXrC9LUZDTT61opjohMJSEySo/HVekoWG9A0bQGn
+Ui+JbtLeuuCwwAGSgdAhVkjr27ANyFtjR63KVrDvSLbYFyZXKxrRYnZWs92Ho/g6
+oTLnUSmkbLlhsUDjknAaNfp+enETSoPHcpkd7MeqVw2oYrLw6MCo4h2tBsIgtZEd
+h6CgX4Gc3+bhvKx36XYxVwScPJUWsQ==
+-----END PRIVATE KEY-----
diff --git a/test/static/seal.png b/test/static/seal.png
new file mode 100644
index 0000000..bb47029
Binary files /dev/null and b/test/static/seal.png differ
diff --git a/test/www/index.lua b/test/www/index.lua
new file mode 100644
index 0000000..0e17c10
--- /dev/null
+++ b/test/www/index.lua
@@ -0,0 +1,49 @@
+local fes = require("fes")
+local site = fes.fes()
+
+local std = fes.std
+local u = fes.util
+
+site.copyright = std.link("https://fsdproject.org/", "fSD")
+
+site:banner(table.concat {
+ std.h(1, "Testing Page"),
+})
+
+site:note(table.concat {
+ std.h(1, "Example syntax features"),
+ std.h(2, "Paragraphs"),
+ std.p("This is a paragraph."),
+ std.h(2, "Codeblocks"),
+ std.codeblock([[
+#include
+
+int main() {
+ puts("Hello, World!");
+ return 0;
+}]]),
+ std.h(2, "Inline Codeblocks"),
+ std.inline([[puts("Hello, World!");]]),
+ std.h(2, "Links"),
+ std.link("geminiprotocol.net/"),
+ std.h(2, "Lists"),
+ std.list {
+ "Item 1",
+ "Item 2",
+ "Item 3",
+ },
+ std.h(2, "Blockquotes"),
+ std.blockquote([[
+"UNIX is very simple" - Dennis Ritchie
+
+"GNU's Not UNIX" - Richard Stallman
+]]),
+ std.h(2, "Rules"),
+ std.rule(),
+ std.h(2, "Images"),
+ std.image("fluffy baby seal", "/static/seal.png"),
+ std.h(2, "Files"),
+ std.file("seal.png", "/static/seal.png"),
+})
+
+return site