Skip to content

Latest commit

 

History

History
254 lines (182 loc) · 4.79 KB

File metadata and controls

254 lines (182 loc) · 4.79 KB

LuaTemplate

Demo

Dynamic template system for Neovim. Create new buffers from templates with support for Lua logic, support nested templates, and asynchronous UI selection.

Features

  • Templates as Lua functions or plain text files.
  • Shared context for passing data between templates
  • Nested templates supported.
  • Async selection with vim.ui.select.
  • Recursive template lookup in subdirectories.
  • Apply template to an existing buffer or create a new one.

Setup

Install

  • With your preferred plugin manager

lazy:

{
  "splyashka/LuaTemplate",
  opts = {},
  -- example keymaps
  keys = {
    {
      "<leader>n",
      function()
        require("luatemplate").pick_template()
      end,
      desc = "New from template"
    }
  }
}

Configuration

require("luatemplate").setup({
  -- default options
  templates_dir = vim.fn.stdpath("config") .. "/templates", -- path to templates
})

Add template

Template organization

Templates can be organized in subdirectories. The picker will show them as subdir/template.lua in the selection list.

Directories and files prefixed with _ are hidden from the picker.

Static text file

All non *.lua files

example.md in templates_dir:

# Example Template
Hello from LuaTemplate!

Lua template (basic)

return function(ctx)
  ctx.filename = "example.md"

  return {
    "Line 1",
    "Line 2",
    "CWD:" .. ctx.cwd,
    "TIME: " .. os.date()
  }
end

or:

return function(ctx)
  ctx.filename = "multiline_strings.md"

  return [[Line 1
Line 2
Line 3]]
end

Lua template with user choice

local lt = require("luatemplate")

return function(ctx)
  local options = { "Option A", "Option B", "Option C" }

  local choice = lt.ui_select(options, {
    prompt = "Select option:",
  })

  ctx.filename = "note_" .. choice

  return "You selected: " .. choice
end

Nested templates

Templates can call other templates — even in a recursive manner. This allows building complex dynamic structures (e.g. trees, repeated sections, generators).

Just be careful to avoid infinite recursion.

Files and directories prefixed with _ are hidden from the picker.

_child.lua:

return function(ctx)
  ctx.value = "from child"

  return {
    "Child line 1",
    "Child line 2",
  }
end

parent.lua:

local lt = require("luatemplate")

return function(ctx)
  local child = lt.load_template("_child.lua")

  local lines = {
    "Parent line 1",
  }

  local child_lines = child(ctx)

  vim.list_extend(lines, child_lines)

  vim.list_extend(lines, {
    "Parent line 2",
    "Value: " .. ctx.value,
  })

  return lines
end

Result:

Parent line 1
Child line 1
Child line 2
Parent line 2
Value: from child

Cursor positioning

Set ctx.cursor to move the cursor after the template is applied:

return function(ctx)
  local lines = {
    "Line 1",
    "Line 2",
    "Line 3",
  }

  ctx.cursor = { #lines, 0 }

  return lines
end

Apply template to an existing buffer

Use apply_template to replace contents of the current buffer (or a specific one) with a template result:

-- Replace current buffer with template output
lt.apply_template("my_template.lua")

-- Or target a specific buffer
lt.apply_template("my_template.lua", 5)

The template receives the current buffer's content in ctx.buffer_content:

return function(ctx)
  local date = os.date()

  return {
    "-- Generated at " .. date,
    "-- Original " .. #ctx.buffer_content .. " lines",
    unpack(ctx.buffer_content),
  }
end

API

local lt = require("luatemplate")

-- Pick a template and create a buffer
lt.pick_template()

-- Create a buffer from a specific template (skip picker)
lt.create_buffer_from_template("my_template.lua")

-- Apply a template to an existing buffer
lt.apply_template("my_template.lua")
lt.apply_template("my_template.lua", bufnr)

-- Load template function (can be Lua or static file)
local fn = lt.load_template("my_template.lua")
local lines = fn(ctx)

-- Get list of visible templates (without _ prefix)
local list = lt.get_templates()

-- Async select helper
local choice = lt.ui_select({"A", "B", "C"}, { prompt = "Choose:" })

UI (vim.ui.select)

LuaTemplate uses Neovim’s built-in vim.ui.select for user interaction.

This means you can change the UI globally by installing another plugin.

Examples:

These plugins override vim.ui.select, so LuaTemplate will automatically use them.

License

This plugin is released under the MIT License. See LICENSE for details.