Skip to content

Instantly share code, notes, and snippets.

@eduardoarandah
Created August 27, 2026 23:41
Show Gist options
  • Select an option

  • Save eduardoarandah/4dbf33da3fe60042ee0e21695ef64b10 to your computer and use it in GitHub Desktop.

Select an option

Save eduardoarandah/4dbf33da3fe60042ee0e21695ef64b10 to your computer and use it in GitHub Desktop.
luasnip snippets to create forms in markdown, useful for agents
-- https://github.com/L3MON4D3/LuaSnip/blob/master/Examples/snippets.lua
-- extract functions from luasnips
local ls = require("luasnip")
local snippet = ls.snippet
local text_node = ls.text_node
local insert_node = ls.insert_node
local function_node = ls.function_node
local fmt = require("luasnip.extras.fmt").fmt
--------------------------------------------------------------------------------
-- helpers
--------------------------------------------------------------------------------
local PANEL_WIDTH = 72
local function dw(s)
return vim.fn.strdisplaywidth(s or "")
end
local function pad_right(s, width)
return s .. string.rep(" ", math.max(0, width - dw(s)))
end
--- Cola del borde superior: rellena con ─ hasta PANEL_WIDTH según el título.
local function top_border_tail(args)
local title_width = dw(args[1][1])
return " " .. string.rep("─", math.max(1, PANEL_WIDTH - 5 - title_width)) .. "┐"
end
return {
--------------------------------------------------------------------------------
--- Forms
--------------------------------------------------------------------------------
-- Panel de una sola línea, editable en vivo (el borde se reajusta al escribir).
snippet("panel_line", {
text_node("┌─ "),
insert_node(1, "Título"),
function_node(top_border_tail, { 1 }),
text_node({ "", "│ " }),
insert_node(2, "contenido"),
function_node(function(args)
return pad_right("", PANEL_WIDTH - 4 - dw(args[1][1])) .. " │"
end, { 2 }),
text_node({ "", "└" .. string.rep("─", PANEL_WIDTH - 2) .. "┘" }),
}, {
desc = "Panel con título de una sola línea de contenido",
}),
-- Panel vacío de N líneas para rellenar a mano.
snippet("panel_blank", {
text_node("┌─ "),
insert_node(1, "Título"),
function_node(top_border_tail, { 1 }),
text_node({
"",
"│ " .. string.rep(" ", PANEL_WIDTH - 4) .. " │",
"│ " .. string.rep(" ", PANEL_WIDTH - 4) .. " │",
"│ " .. string.rep(" ", PANEL_WIDTH - 4) .. " │",
"└" .. string.rep("─", PANEL_WIDTH - 2) .. "┘",
}),
}, {
desc = "Panel vacío con título",
}),
-- Leyenda de notación: ponla una vez arriba del wireframe.
snippet("form_legend", {
text_node({
"Notación:",
" [ ] / [x] checkbox ( ) / (•) radio (●—) toggle activo",
" [__________] texto [ 0 ] número (rango) [ 2026-01-29 📅 ] fecha",
" [ Opción ▾ ] select ┌─┐ textarea [ 📎 Adjuntar… ] archivo",
" 【 Primario 】 ( Secundario ) « solo lectura / calculado » 🔒 deshabilitado",
" * requerido ↳ ayuda o validación ⟳ fila repetible",
"",
}),
}, {
desc = "Leyenda de la notación de controles",
}),
-- Andamio completo de pantalla.
snippet(
"form_screen",
fmt(
[================================================[
## <1>
<2>* [__________]
<3> [ <4> ▾ ]
↳ opciones: <5>
【 Guardar 】 ( Cancelar )
]================================================],
{
insert_node(1, "TÍTULO DE LA PANTALLA"),
insert_node(2, "Campo"),
insert_node(3, "Otro campo"),
insert_node(4, "Opción por defecto"),
insert_node(5, "A / B / C"),
},
{ delimiters = "<>" }
),
{ desc = "Andamio de pantalla de formulario" }
),
-- Controles sueltos
snippet("form_text", fmt("<1>* [__________]", { insert_node(1, "Etiqueta") }, { delimiters = "<>" }), { desc = "Input de texto" }),
snippet("form_number", fmt("<1>* [ <2> ] (<3>)", { insert_node(1, "Etiqueta"), insert_node(2, "0"), insert_node(3, "0–100, entero") }, { delimiters = "<>" }), { desc = "Input numérico con rango" }),
snippet(
"form_checkbox",
fmt(
[================================================[
<1>
[x] <2>
[ ] <3>
[ ] <4>
↳ <5>
]================================================],
{
insert_node(1, "Etiqueta del grupo"),
insert_node(2, "Opción A"),
insert_node(3, "Opción B"),
insert_node(4, "Opción C"),
insert_node(5, "al menos una"),
},
{ delimiters = "<>" }
),
{ desc = "Grupo de checkboxes" }
),
snippet(
"form_radio",
fmt("<1>* (•) <2> ( ) <3> ( ) <4>", {
insert_node(1, "Etiqueta"),
insert_node(2, "Opción A"),
insert_node(3, "Opción B"),
insert_node(4, "Opción C"),
}, { delimiters = "<>" }),
{ desc = "Grupo de radios en línea" }
),
snippet(
"form_select",
fmt(
[================================================[
<1>* [ <2> ▾ ]
↳ opciones: <3>
]================================================],
{
insert_node(1, "Etiqueta"),
insert_node(2, "Valor por defecto"),
insert_node(3, "A / B / C"),
},
{ delimiters = "<>" }
),
{ desc = "Select con lista de opciones" }
),
snippet(
"form_textarea",
fmt(
[================================================[
<1>
┌──────────────────────────────────────────────────┐
│ │
│ │
└──────────────────────────────────────────────────┘
↳ <2>
]================================================],
{ insert_node(1, "Etiqueta"), insert_node(2, "máx. 500 caracteres") },
{ delimiters = "<>" }
),
{ desc = "Textarea" }
),
snippet(
"form_toggle",
fmt("<1> (●—) <2> / (—●) <3>", {
insert_node(1, "Etiqueta"),
insert_node(2, "activo"),
insert_node(3, "inactivo"),
}, { delimiters = "<>" }),
{ desc = "Toggle" }
),
snippet(
"form_date",
fmt("<1>* [ <2> 📅 ]", {
insert_node(1, "Fecha"),
function_node(function()
return os.date("%Y-%m-%d")
end),
}, { delimiters = "<>" }),
{ desc = "Input de fecha" }
),
snippet(
"form_file",
fmt("<1> [ 📎 <2> ] ↳ <3>", {
insert_node(1, "Adjuntos"),
insert_node(2, "Seleccionar archivo…"),
insert_node(3, "pdf, jpg — máx. 5 MB"),
}, { delimiters = "<>" }),
{ desc = "Input de archivo" }
),
snippet("form_readonly", fmt("<1> « <2> »", { insert_node(1, "Etiqueta"), insert_node(2, "valor calculado") }, { delimiters = "<>" }), { desc = "Campo de solo lectura / calculado" }),
snippet("form_actions", fmt("【 <1> 】 ( <2> )", { insert_node(1, "Guardar"), insert_node(2, "Cancelar") }, { delimiters = "<>" }), { desc = "Botones primario y secundario" }),
snippet("form_rule", fmt("↳ <1>", { insert_node(1, "regla de validación") }, { delimiters = "<>" }), { desc = "Línea de ayuda / validación" }),
-- Tabla de filas repetibles.
snippet(
"form_table",
fmt(
[================================================[
⟳ una fila por <1>
| <2> | <3> | <4> |
| ----- | -------- | ----- |
| valor | [ 0 ] | [ ▾ ] |
| valor | [ 0 ] | [ ▾ ] |
]================================================],
{
insert_node(1, "partida"),
insert_node(2, "Columna A"),
insert_node(3, "Columna B"),
insert_node(4, "Columna C"),
},
{ delimiters = "<>" }
),
{ desc = "Tabla markdown de filas repetibles" }
),
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment