diff --git a/lua/config/templates.lua b/lua/config/templates.lua new file mode 100644 index 0000000..15839fb --- /dev/null +++ b/lua/config/templates.lua @@ -0,0 +1,75 @@ +--- Snacks picker frontend for template.nvim (t). +--- +--- : insert the template at the cursor when the current buffer is a +--- named file whose filetype matches the template's; otherwise fall through +--- to the new-file flow. : always prompt (snacks.input) for a new file +--- to create in the cwd and fill with the template. +--- +--- template.nvim resolves templates by filetype + basename-without-extension +--- using Lua-pattern substring matching, so template file names must use +--- underscores only and never be substrings of one another. +--- @module config.templates + +local M = {} + +local function temp_dir() return vim.fs.normalize(require("template").temp_dir) end + +local function tpl_name(item) return vim.fn.fnamemodify(item.file, ":t:r") end + +--- Insert the template at the cursor of the current buffer. +local function insert(item) require("template"):generate_template { tpl_name(item) } end + +--- Prompt for a filename, create it under cwd, and fill it with the template. +local function create(item) + local ext = vim.fn.fnamemodify(item.file, ":e") + require("snacks").input({ + prompt = ("New .%s file (created in %s)"):format(ext, vim.fn.fnamemodify(vim.fn.getcwd(), ":~")), + }, function(value) + if not value or value == "" then return end + -- template.nvim detects the file argument by its extension + if not value:find("%.%w+$") then value = value .. "." .. ext end + -- template.nvim opens the file with bare uv.fs_open; make parents first + local parent = vim.fn.fnamemodify(vim.fn.getcwd() .. "/" .. value, ":h") + if vim.fn.isdirectory(parent) == 0 then vim.fn.mkdir(parent, "p") end + require("template"):generate_template { value, tpl_name(item) } + end) +end + +--- Open the template picker. +function M.pick() + require "template" -- lazy-loads the plugin so temp_dir is configured + require("snacks").picker.files { + title = "Templates", + cwd = temp_dir(), + actions = { + template_new_file = function(picker, item) + picker:close() + if item then vim.schedule(function() create(item) end) end + end, + }, + win = { + input = { + keys = { [""] = { "template_new_file", mode = { "n", "i" } } }, + }, + }, + confirm = function(picker, item) + picker:close() + if not item then return end + -- defer past the picker teardown so the target window is current again + vim.schedule(function() + local buf = vim.api.nvim_get_current_buf() + local named = vim.api.nvim_buf_get_name(buf) ~= "" and vim.bo[buf].buftype == "" + local tpl_ft = vim.filetype.match { filename = vim.fs.joinpath(temp_dir(), item.file) } + -- template.nvim silently no-ops on filetype mismatch, so route + -- non-matching buffers to the new-file flow instead + if named and vim.bo[buf].filetype == tpl_ft then + insert(item) + else + create(item) + end + end) + end, + } +end + +return M diff --git a/lua/plugins/astrocore.lua b/lua/plugins/astrocore.lua index 9580009..a218432 100644 --- a/lua/plugins/astrocore.lua +++ b/lua/plugins/astrocore.lua @@ -282,8 +282,8 @@ return { desc = "Find in line", }, ["t"] = { - function() require("snacks").picker.lines() end, - desc = "Find in line", + function() require("config.templates").pick() end, + desc = "Find templates", }, ["w"] = { function() require("snacks").picker.grep() end, diff --git a/lua/plugins/template.lua b/lua/plugins/template.lua new file mode 100644 index 0000000..a8185d3 --- /dev/null +++ b/lua/plugins/template.lua @@ -0,0 +1,14 @@ +--- template.nvim: insert file templates with {{_expr_}} grammar +--- Templates live in /templates//*.ext and are matched to the +--- buffer by filetype. Picker frontend lives in config.templates (t). +--- @module plugins.template + +return { + "nvimdev/template.nvim", + cmd = "Template", + opts = { + temp_dir = vim.fn.stdpath "config" .. "/templates", + author = "Prad Nukala", + email = "prad@sonr.io", + }, +}