fix: modified snippets pipeline to actually work properly with luasnip

This commit is contained in:
Ceferino Patino 2025-10-20 14:03:12 -05:00
commit 8d2c1d921e
Signed by: c4patino
SSH key fingerprint: SHA256:9fQ9TsujGrdNNi76mnsu63v7dS5JOmHRZEqBOl49OR8
8 changed files with 204 additions and 366 deletions

View file

View file

@ -33,150 +33,91 @@
];
# Core snippet configuration and definitions
extraConfigLua = ''
local ls = require("luasnip")
local types = require("luasnip.util.types")
# Uses unified snippets config from ../snippets/default.nix for all LuaSnip setup.
# Use the unified snippets config for LuaSnip
extraConfigLua = let
snippetDir = ../languages/snippets;
snippetFiles =
builtins.filter
(name: builtins.match ".*\\.nix$" name != null)
(builtins.attrNames (builtins.readDir snippetDir));
snippetConfigs = map (file: (import (snippetDir + "/${file}")).extraConfigLua) snippetFiles;
allSnippets = builtins.concatStringsSep "\n" snippetConfigs;
in ''
-- Get comment string for current filetype
local function get_comment_string()
local comment_string = vim.bo.commentstring
if not comment_string or comment_string == "" then
return "-- %s" -- Default to Lua style comments
end
return comment_string
end
-- Add visual indicators for snippet nodes
ls.config.set_config({
ext_opts = {
[types.choiceNode] = {
active = {
virt_text = {{"", "GruvboxOrange"}}
}
},
[types.insertNode] = {
active = {
virt_text = {{"", "GruvboxBlue"}}
}
}
}
})
-- Get visual selection
local function get_visual_selection()
local visual_modes = {
v = true,
V = true,
["\22"] = true -- CTRL+V
}
-- Common snippet creation utilities
local s = ls.snippet
local t = ls.text_node
local i = ls.insert_node
local f = ls.function_node
local c = ls.choice_node
local d = ls.dynamic_node
local r = ls.restore_node
local fmt = require("luasnip.extras.fmt").fmt
local rep = require("luasnip.extras").rep
local parse = require("luasnip.util.parser").parse_snippet
if not visual_modes[vim.api.nvim_get_mode().mode] then
return ""
end
-- Function to generate namespace interpolation at runtime
local function namespace_interp(suffix)
-- Uses string.char to generate the namespace interpolation
return string.char(36) .. string.char(123) .. "namespace" .. string.char(125) .. suffix
end
local _, ls, cs = unpack(vim.fn.getpos("v"))
local _, le, ce = unpack(vim.fn.getpos("."))
-- Nix snippets
local nix_snippets = {
-- Module snippet
module = s("module", {
-- Opening
t({
"{",
" config,",
" lib,",
" namespace,",
" pkgs,",
" ...",
"}: let",
" inherit (lib) mkIf mkEnableOption;",
" inherit (lib."
}),
f(function() return namespace_interp("") end),
t(") getAttrByNamespace mkOptionsWithNamespace;"),
t({"", " base = \""}),
f(function() return namespace_interp(".") end),
i(1, "category"),
t("."),
i(2, "module"),
t({
"\";",
" cfg = getAttrByNamespace config base;",
"in {",
" options = mkOptionsWithNamespace base {",
" enable = mkEnableOption \""
}),
i(3, "description"),
t({
"\";",
" };",
"",
" config = mkIf cfg.enable {",
" "
}),
i(4, "# configuration"),
t({"", " };", "}"}),
}),
-- Normalize positions
if ls > le or (ls == le and cs > ce) then
ls, le = le, ls
cs, ce = ce, cs
end
-- Bundle module
bundle = s("bundle", {
t({
"{",
" config,",
" lib,",
" namespace,",
" ...",
"}: let",
" inherit (lib) mkIf mkEnableOption;",
" inherit (lib."
}),
f(function() return namespace_interp("") end),
t(") getAttrByNamespace mkOptionsWithNamespace enabled;"),
t({"", " base = \""}),
f(function() return namespace_interp(".bundles.") end),
i(1, "name"),
t({
"\";",
" cfg = getAttrByNamespace config base;",
"in {",
" options = mkOptionsWithNamespace base {",
" enable = mkEnableOption \""
}),
i(2, "name"),
t({
" bundle\";",
" };",
"",
" config = mkIf cfg.enable {",
" "
}),
f(function() return namespace_interp("") end),
t(" = {"),
t({"", " "}),
i(3, "# enabled modules"),
t({"", " };", " };", "}"})
}),
local lines = vim.api.nvim_buf_get_lines(0, ls - 1, le, false)
if #lines == 0 then
return ""
end
-- Simple patterns using formatted strings
enable = s("enable", fmt([[
{} = {{
enable = true;
{}
}};]], {
i(1, "module.path"),
i(2, "# configuration"),
})),
-- Adjust for partial lines
lines[1] = string.sub(lines[1], cs, -1)
if #lines > 1 then
lines[#lines] = string.sub(lines[#lines], 1, ce)
else
lines[1] = string.sub(lines[1], 1, ce - cs + 1)
end
enabled = s("enabled", fmt("{} = enabled;", {
i(1, "module.path"),
})),
return table.concat(lines, "\n")
end
home = s("home", fmt([[
home = {{
packages = with pkgs; [ {} ];
{}
}};]], {
i(1, "# packages"),
i(2, "# other home attributes"),
})),
}
-- Format date in various ways
local function date_format(format)
return os.date(format)
end
-- Add snippets to filetypes
ls.add_snippets("nix", nix_snippets)
-- Capture groups from regex matches
local function capture_match(match, group)
if match and #match > group then
return match[group + 1]
end
return ""
end
-- Check if the current buffer is a test file
local function is_test_file()
local filename = vim.fn.expand("%:t")
return string.match(filename, "[tT]est") ~= nil or string.match(filename, "_test") ~= nil or string.match(filename, "spec") ~= nil
end
-- Make these functions available to snippets
_G.snippet_utils = {
get_comment_string = get_comment_string,
get_visual_selection = get_visual_selection,
date_format = date_format,
capture_match = capture_match,
is_test_file = is_test_file
}
${allSnippets}
'';
}

View file

@ -17,9 +17,10 @@
" ...",
"}: let",
" inherit (lib) mkIf mkEnableOption;",
" inherit (lib.${namespace}) getAttrByNamespace mkOptionsWithNamespace;", -- literal ${namespace}
" ${"inherit (lib.\${namespace}) getAttrByNamespace mkOptionsWithNamespace;"}",
" base = \""
}),
t("${"\${namespace}"}"),
i(1, "namespace"),
t("."),
i(2, "category"),
@ -56,10 +57,10 @@
" ...",
"}: let",
" inherit (lib) mkIf mkEnableOption;",
" inherit (lib.${namespace}) getAttrByNamespace mkOptionsWithNamespace enabled;",
" ${"inherit (lib.\${namespace}) getAttrByNamespace mkOptionsWithNamespace enabled;"}",
" base = \""
}),
i(1, "namespace"),
t("${"\${namespace}"}"),
t(".bundles."),
i(2, "name"),
t({"\";",

View file

@ -0,0 +1,123 @@
{
# Python-specific snippets
extraConfigLua = ''
local ls = require("luasnip")
local s = ls.snippet
local t = ls.text_node
local i = ls.insert_node
local f = ls.function_node
local c = ls.choice_node
local fmt = require("luasnip.extras.fmt").fmt
local python_snippets = {
-- Import statement
s("imp", {
t("import "),
i(1, "module")
}),
-- From import statement
s("fimp", fmt("from {} import {}", {
i(1, "module"),
i(2, "name")
})),
-- Class definition
s("class", fmt([[
class {}:
"""{}"""
def __init__(self{}):
{}
]], {
i(1, "ClassName"),
i(2, "Class docstring"),
i(3, ""),
i(4, "# Implementation"),
})),
-- Function definition
s("def", fmt([[
def {}({}):
"""{}
{}
{}
"""
{}
]], {
i(1, "function_name"),
i(2, ""),
i(3, "Function docstring"),
c(4, {
t("Args:"),
t("Parameters:"),
}),
i(5, " arg: Description"),
i(6, " # Implementation"),
})),
-- Main function
s("main", fmt([[
def main():
{}
if __name__ == "__main__":
main()
]], {
i(1, "# Implementation"),
})),
-- Try/except block
s("try", fmt([[
try:
{}
except {}:
{}
]], {
i(1, "# Try block"),
i(2, "Exception"),
i(3, "# Exception handling"),
})),
-- Context manager (with statement)
s("with", fmt([[
with {} as {}:
{}
]], {
i(1, "context_manager"),
i(2, "variable"),
i(3, "# Implementation"),
})),
-- List comprehension
s("lc", fmt("[{} for {} in {}]", {
i(1, "expression"),
i(2, "item"),
i(3, "iterable"),
})),
-- Dictionary comprehension
s("dc", fmt("{{{}: {} for {} in {}}}", {
i(1, "key"),
i(2, "value"),
i(3, "item"),
i(4, "iterable"),
})),
-- Test function (pytest)
s("test", fmt([[
def test_{}():
"""{}"""
{}
]], {
i(1, "name"),
i(2, "Test docstring"),
i(3, "# Test implementation"),
}))
}
-- Add these snippets to Python files
ls.add_snippets("python", python_snippets)
'';
}

View file

@ -1,25 +0,0 @@
{
# Import all snippet files here
imports = [
./utils.nix
./languages/common.nix
./languages/rust.nix
./languages/python.nix
./languages/nix.nix
];
# This extra config will load all our snippets
extraConfigLua = ''
-- Ensure LuaSnip loads all snippet definitions
require("luasnip.loaders.from_lua").lazy_load()
-- This function lets us load snippets defined in Nix string
function load_nix_snippets(snippets, filetypes)
local ls = require("luasnip")
for _, ft in ipairs(filetypes) do
ls.add_snippets(ft, snippets)
end
end
'';
}

View file

@ -1,123 +0,0 @@
{
# Python-specific snippets
extraConfigLua = ''
local ls = require("luasnip")
local s = ls.snippet
local t = ls.text_node
local i = ls.insert_node
local f = ls.function_node
local c = ls.choice_node
local fmt = require("luasnip.extras.fmt").fmt
local python_snippets = {
-- Import statement
s("imp", {
t("import "),
i(1, "module")
}),
-- From import statement
s("fimp", fmt("from {} import {}", {
i(1, "module"),
i(2, "name")
})),
-- Class definition
s("class", fmt([[
class {}:
"""{}"""
def __init__(self{}):
{}
]], {
i(1, "ClassName"),
i(2, "Class docstring"),
i(3, ""),
i(4, "# Implementation"),
})),
-- Function definition
s("def", fmt([[
def {}({}):
"""{}
{}
{}
"""
{}
]], {
i(1, "function_name"),
i(2, ""),
i(3, "Function docstring"),
c(4, {
t("Args:"),
t("Parameters:"),
}),
i(5, " arg: Description"),
i(6, " # Implementation"),
})),
-- Main function
s("main", fmt([[
def main():
{}
if __name__ == "__main__":
main()
]], {
i(1, "# Implementation"),
})),
-- Try/except block
s("try", fmt([[
try:
{}
except {}:
{}
]], {
i(1, "# Try block"),
i(2, "Exception"),
i(3, "# Exception handling"),
})),
-- Context manager (with statement)
s("with", fmt([[
with {} as {}:
{}
]], {
i(1, "context_manager"),
i(2, "variable"),
i(3, "# Implementation"),
})),
-- List comprehension
s("lc", fmt("[{} for {} in {}]", {
i(1, "expression"),
i(2, "item"),
i(3, "iterable"),
})),
-- Dictionary comprehension
s("dc", fmt("{{{}: {} for {} in {}}}", {
i(1, "key"),
i(2, "value"),
i(3, "item"),
i(4, "iterable"),
})),
-- Test function (pytest)
s("test", fmt([[
def test_{}():
"""{}"""
{}
]], {
i(1, "name"),
i(2, "Test docstring"),
i(3, "# Test implementation"),
}))
}
-- Add these snippets to Python files
ls.add_snippets("python", python_snippets)
'';
}

View file

@ -1,79 +0,0 @@
{
extraConfigLua = ''
-- Common utility functions for snippets
-- Get comment string for current filetype
local function get_comment_string()
local comment_string = vim.bo.commentstring
if not comment_string or comment_string == "" then
return "-- %s" -- Default to Lua style comments
end
return comment_string
end
-- Get visual selection
local function get_visual_selection()
local visual_modes = {
v = true,
V = true,
["\22"] = true -- CTRL+V
}
if not visual_modes[vim.api.nvim_get_mode().mode] then
return ""
end
local _, ls, cs = unpack(vim.fn.getpos("v"))
local _, le, ce = unpack(vim.fn.getpos("."))
-- Normalize positions
if ls > le or (ls == le and cs > ce) then
ls, le = le, ls
cs, ce = ce, cs
end
local lines = vim.api.nvim_buf_get_lines(0, ls - 1, le, false)
if #lines == 0 then
return ""
end
-- Adjust for partial lines
lines[1] = string.sub(lines[1], cs, -1)
if #lines > 1 then
lines[#lines] = string.sub(lines[#lines], 1, ce)
else
lines[1] = string.sub(lines[1], 1, ce - cs + 1)
end
return table.concat(lines, "\n")
end
-- Format date in various ways
local function date_format(format)
return os.date(format)
end
-- Capture groups from regex matches
local function capture_match(match, group)
if match and #match > group then
return match[group + 1]
end
return ""
end
-- Check if the current buffer is a test file
local function is_test_file()
local filename = vim.fn.expand("%:t")
return string.match(filename, "[tT]est") ~= nil or string.match(filename, "_test") ~= nil or string.match(filename, "spec") ~= nil
end
-- Make these functions available to snippets
_G.snippet_utils = {
get_comment_string = get_comment_string,
get_visual_selection = get_visual_selection,
date_format = date_format,
capture_match = capture_match,
is_test_file = is_test_file
}
'';
}