scripts/generate-numeric-index
#!/usr/bin/env lua
-- Numeric Similarity Index Generator
-- Generates a dense, CTRL+F-searchable block of numbered links (0001-7791)
-- pointing to similar/XXX.html pages. Output is an HTML fragment for insertion
-- into index.html. Each row contains LINKS_PER_ROW links in monospace format.
-- Also generates a full test page in tmp/ for browser preview.
-- {{{ setup_dir_path
local function setup_dir_path(provided_dir)
if provided_dir and provided_dir ~= "" then
return provided_dir
end
return "/mnt/mtwo/programming/ai-stuff/neocities-modernization"
end
-- }}}
local DIR = setup_dir_path(arg[1])
-- Configuration
local LINKS_PER_ROW = 15
-- Bugfix: was "/temp/" which never exists, so every run printed "Could not
-- write Test page" (swallowed under the success banner). Ephemeral previews
-- belong in the project's tmp/ RAM symlink, which the run scripts ensure exists.
local TEST_PAGE_PATH = DIR .. "/tmp/numeric-index-test.html"
local BUILD_OUTPUT_PATH = DIR .. "/output/numeric-index.html"
-- Add libs to package path
package.path = DIR .. "/libs/?.lua;" .. package.path
local dkjson = require("dkjson")
-- {{{ read_poem_count
local function read_poem_count()
local poems_path = DIR .. "/assets/poems.json"
local file = io.open(poems_path, "r")
if not file then
io.stderr:write("Error: Could not open " .. poems_path .. "\n")
os.exit(1)
end
local content = file:read("*a")
file:close()
local data = dkjson.decode(content)
if not data or not data.metadata or not data.metadata.total_poems then
io.stderr:write("Error: Could not parse poem count from poems.json\n")
os.exit(1)
end
return data.metadata.total_poems
end
-- }}}
-- {{{ format_link
local function format_link(num)
-- Zero-pad to 4 digits for alignment (handles up to 9999 poems)
local padded = string.format("%04d", num)
return string.format('<a href="similar/%s.html">%s</a>', padded, padded)
end
-- }}}
-- {{{ generate_index
local function generate_index(total_poems)
local lines = {}
local current_row = {}
for i = 1, total_poems do
table.insert(current_row, format_link(i))
if #current_row >= LINKS_PER_ROW then
table.insert(lines, table.concat(current_row, " "))
current_row = {}
end
end
-- Handle remaining links in last row
if #current_row > 0 then
table.insert(lines, table.concat(current_row, " "))
end
return lines
end
-- }}}
-- {{{ generate_test_page
local function generate_test_page(fragment, total_poems)
-- Wrap fragment in a complete HTML document for browser testing
local template = [[<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Numeric Index Test - %d poems</title>
</head>
<body>
<center>
<h1>Numeric Similarity Index</h1>
<p>%d poems - CTRL+F to find a number</p>
</center>
%s
<center>
<p><small>Test page generated by scripts/generate-numeric-index</small></p>
</center>
</body>
</html>]]
return string.format(template, total_poems, total_poems, fragment)
end
-- }}}
-- {{{ write_file
local function write_file(path, content, label)
local file = io.open(path, "w")
if file then
file:write(content)
file:close()
io.stderr:write(string.format("%s: %s\n", label, path))
return true
else
io.stderr:write(string.format("Error: Could not write %s to %s\n", label, path))
return false
end
end
-- }}}
-- {{{ main
local function main()
local total_poems = read_poem_count()
io.stderr:write(string.format("Generating index for %d poems...\n", total_poems))
local lines = generate_index(total_poems)
-- Build fragment output
local output = {}
table.insert(output, "<pre>")
for _, line in ipairs(lines) do
table.insert(output, line)
end
table.insert(output, "</pre>")
local fragment = table.concat(output, "\n")
-- Generate full page from fragment
local full_page = generate_test_page(fragment, total_poems)
-- Write build output to output/ (main build product)
write_file(BUILD_OUTPUT_PATH, full_page, "Build output")
-- Write test page to temp/ (for local preview)
write_file(TEST_PAGE_PATH, full_page, "Test page")
-- Output fragment to stdout (for piping/insertion)
print(fragment)
io.stderr:write(string.format("Generated %d links in %d rows\n", total_poems, #lines))
end
-- }}}
main()