tl;dr
texts.html table.
I wanted to keep my personal website completely under my own control. I did not want to depend on a static site generator to handle the structure and content for me. After creating only five pages manually, however, I started noticing how useful some automation could be. That is why I decided to build a small system of my own.
My current setup is based around a texts.html file, which
contains a table listing all the texts I have written. Each entry links to
a separate page stored inside the pages/ directory.
The idea is simple: since I already use Neovim to edit all my files, I
wanted to create a custom command that would handle the repetitive parts
of creating a new article. Running :NewText should ask me for
a title, create a new HTML file, fill it with the required boilerplate,
and automatically add it to my texts table.
To make this work, I first created a
template HTML file. I created a new
directory called templates/ and added the basic structure of
a text page as text.html.
After that, I created a new blog.lua file inside my Neovim
configuration directory (lua/config/) and loaded it from
lua/config/lazy.lua:
require("config.blog")
The next step was creating the new_text() function. It gets
the current date, asks for the title, creates the new file, replaces the
placeholders in the template, and inserts a new entry into the text table.
function M.new_text() vim.ui.input({ prompt = "Title: ", }, function(title) if not title or title == "" then return end local slug = slugify(title) local filename = slug .. ".html" local filepath = pages .. "/" .. filename local date = os.date("%Y-%m-%d") if vim.fn.filereadable(filepath) == 1 then print("File already exists.") return end local lines = vim.fn.readfile(template) for i, line in ipairs(lines) do line = line:gsub("{{TITLE}}", title) lines[i] = line end vim.fn.writefile(lines, filepath) local html = vim.fn.readfile(texts) local row = { " <tr>", " <td>", ' <a href="./pages/' .. filename .. '">', " " .. title, " </a>", " </td>", ' <td class="shrink">' .. date .. "</td>", ' <td class="shrink">' .. date .. "</td>", " </tr>", } for i, line in ipairs(html) do if line:find("<tbody>") then for j = #row, 1, -1 do table.insert(html, i + 1, row[j]) end break end end vim.fn.writefile(html, texts) vim.cmd("edit " .. filepath) print("Created " .. filename) end) end
After creating this function, I restarted Neovim and created my first page using the new command. It worked, but there was still one thing missing.
My text table stores both the creation date and the last edited date. While the creation date is added automatically when creating a page, I also wanted the edited date to update whenever I changed an existing article.
So I created another function for that:
function M.update_edited() local filepath = vim.fn.expand("%:p") if not filepath:find("/pages/") then return end local filename = vim.fn.expand("%:t") local date = os.date("%Y-%m-%d") local html = vim.fn.readfile(texts) local found = false for i, line in ipairs(html) do if line:find("./pages/" .. filename, 1, true) then found = true for j = i, math.min(i + 10, #html) do if html[j]:find('<td class="shrink">') then if html[j + 1] and html[j + 1]:find('<td class="shrink">') then html[j + 1] = ' <td class="shrink">' .. date .. "</td>" break end end end break end end if found then vim.fn.writefile(html, texts) print("Updated edited date") end end
The function checks whether the current file is inside the
pages/ directory. If it is, it searches for the matching
entry in texts.html and replaces the old edited date with the
current date.
The complete code can be found in my dotfiles repository if you want to take a look or suggest improvements.
That is it for now. I hope this little system continues to work well as I write more pages. If it breaks or I find a better approach, I will probably write a follow-up.
For transparency: I wrote this post myself and then used ChatGPT to correct grammatical mistakes and improve the overall reading experience, since English is not my first language. The source code, however, was almost entirely written with the help of ChatGPT.
Further reading: