From 9d852d120ef0f69695b1751387609b5f65b6acca Mon Sep 17 00:00:00 2001
From: Thiago Sposito
Date: Sat, 10 Jan 2026 19:39:34 -0300
Subject: [PATCH] feat: nvim: add Fennel config support via nfnl, treesitter,
plugins
---
home-manager/nvim/default.nix | 48 +++++++++++++++-
home-manager/nvim/extraconfig.fnl | 96 +++++++++++++++++++++++++++++++
2 files changed, 143 insertions(+), 1 deletion(-)
create mode 100644 home-manager/nvim/extraconfig.fnl
diff --git a/home-manager/nvim/default.nix b/home-manager/nvim/default.nix
index 438e593..112fc78 100644
--- a/home-manager/nvim/default.nix
+++ b/home-manager/nvim/default.nix
@@ -6,7 +6,24 @@
];
home.packages = with pkgs; [
ripgrep
+ gcc
];
+ home.file.".config/nvim/extraconfig.fnl" = {
+ source = ./extraconfig.fnl;
+ };
+ home.file.".config/nvim/.nfnl.fnl" = {
+ source = ./.nfnl.fnl;
+ };
+ # Compile Fennel to Lua at build time
+ home.file.".config/nvim/extraconfig.lua" = {
+ text = builtins.readFile (
+ pkgs.runCommand "extraconfig-compiled.lua" {
+ buildInputs = [ pkgs.luajitPackages.fennel ];
+ } ''
+ ${pkgs.luajitPackages.fennel}/bin/fennel --compile ${./extraconfig.fnl} > $out
+ ''
+ );
+ };
programs.nixvim = {
enable = true;
colorschemes.nord.enable = true;
@@ -21,6 +38,7 @@
};
plugins = {
+ conjure.enable = true;
avante = {
enable = true;
};
@@ -47,6 +65,10 @@
lspkind.enable = true;
lsp-lines.enable = true;
+ treesitter = {
+ enable = true;
+ };
+
none-ls = {
enable = true;
sources = {
@@ -65,6 +87,30 @@
conform-nvim.enable = true;
};
- extraConfigLua = builtins.readFile ./extraconfig.lua;
+ extraPlugins = with pkgs.vimPlugins; [
+ nvim-web-devicons
+ (pkgs.vimUtils.buildVimPlugin {
+ name = "nfnl";
+ src = pkgs.fetchFromGitHub {
+ owner = "Olical";
+ repo = "nfnl";
+ rev = "v1.3.0";
+ hash = "sha256-ug2vAVI3C99TZxFpXw/+AJLRAc+3FLq92bFVhkZUL7A=";
+ };
+ })
+ (pkgs.vimUtils.buildVimPlugin {
+ name = "vim-fennel-syntax";
+ src = pkgs.fetchFromGitHub {
+ owner = "m15a";
+ repo = "vim-fennel-syntax";
+ rev = "e7299d5"; #v1.3.0
+ hash = "sha256-CL3ooywWpGicmzine9qteHTGajAZ2qnIcK9CByaONvc=";
+ };
+ })
+ ];
+ extraConfigLua = ''
+ -- Load compiled Fennel config
+ dofile(vim.fn.expand("~/.config/nvim/extraconfig.lua"))
+ '';
};
}
diff --git a/home-manager/nvim/extraconfig.fnl b/home-manager/nvim/extraconfig.fnl
new file mode 100644
index 0000000..a56bb40
--- /dev/null
+++ b/home-manager/nvim/extraconfig.fnl
@@ -0,0 +1,96 @@
+(do
+ (local cmp (require :cmp))
+ (local avante (require :avante))
+ (local cmp-nvim-lsp (require :cmp_nvim_lsp))
+ (local treesitter (require :nvim-treesitter.configs))
+
+ ;; Configure fennel-ls LSP server using new vim.lsp API
+ ;; Note: vim-fennel-syntax plugin handles filetype detection automatically
+ (local base-capabilities (vim.lsp.protocol.make_client_capabilities))
+ (local capabilities (cmp-nvim-lsp.default_capabilities base-capabilities))
+
+ ;; Find fennel-ls in PATH
+ (local fennel-ls-path (vim.fn.exepath "fennel-ls"))
+ (local fennel-ls-cmd (if (= fennel-ls-path "") ["fennel-ls"] [fennel-ls-path]))
+
+ ;; Setup fennel-ls using autocmd to start on Fennel files
+ (vim.api.nvim_create_autocmd "FileType" {
+ :pattern [:fennel]
+ :callback (fn []
+ (local root (vim.fs.find [".nfnl.fnl" ".git" "fnl"] {:upward true}))
+ (local root-dir (if root (vim.fs.dirname (. root 1)) (vim.fn.getcwd)))
+ (vim.lsp.start {
+ :name :fennel_ls
+ :cmd fennel-ls-cmd
+ :root_dir root-dir
+ :settings {
+ :fennel {
+ :extra-globals "vim"
+ }
+ }
+ :capabilities capabilities
+ }))
+ })
+
+ ;; Enable inlay hints for better documentation
+ (vim.lsp.inlay_hint.enable true {:buftype [""]})
+
+ ;; Configure Treesitter to ensure Fennel grammar is installed
+ ;; Use writable directory for parsers (not the read-only nix store)
+ (local parser_install_dir (.. (vim.fn.stdpath :data) "/treesitter"))
+ (vim.opt.runtimepath:prepend parser_install_dir)
+
+ (treesitter.setup {
+ :ensure_installed [:fennel :lua]
+ :highlight {:enable true}
+ :indent {:enable true}
+ :parser_install_dir parser_install_dir
+ })
+
+ (cmp.setup {
+ :mapping {
+ : (cmp.mapping.complete)
+ : (cmp.mapping.confirm {:select true})
+ : (cmp.mapping.select_next_item)
+ : (cmp.mapping.select_prev_item)
+ }
+ :sources [
+ {:name :nvim_lsp}
+ {:name :buffer}
+ {:name :path}
+ ]
+ })
+
+ (vim.api.nvim_create_autocmd "LspAttach" {
+ :callback (fn [args]
+ (local buf args.buf)
+ (local opts {:buffer buf})
+
+ (vim.keymap.set "n" "gd" vim.lsp.buf.definition opts)
+ (vim.keymap.set "n" "gr" vim.lsp.buf.references opts)
+ (vim.keymap.set "n" "K" vim.lsp.buf.hover opts)
+ (vim.keymap.set "n" "rn" vim.lsp.buf.rename opts)
+ (vim.keymap.set "n" "ca" vim.lsp.buf.code_action opts)
+ (vim.keymap.set "n" "f" (fn []
+ (vim.lsp.buf.format {:async true}))
+ opts)
+
+ (vim.keymap.set "n" "" ":m .+1==")
+ (vim.keymap.set "n" "" ":m .-2=="))
+ })
+
+ (avante.setup {
+ :provider "ollama"
+ :providers {
+ :ollama {
+ :endpoint "http://127.0.0.1:11434"
+ :model "gpt-oss:20b"
+ :extra_request_body {
+ :temperature 0
+ :num_ctx 8192
+ }
+ }
+ }
+ })
+ )
+