neovim: swap out a filetype plugin in place of tree-sitter-nix-shell for handling #!nix-shell scripts
This commit is contained in:
@@ -4,7 +4,9 @@ moduleArgs@{ lib, pkgs, ... }:
|
|||||||
|
|
||||||
let
|
let
|
||||||
plugins = import ./plugins.nix moduleArgs;
|
plugins = import ./plugins.nix moduleArgs;
|
||||||
plugin-packages = builtins.map (p: p.plugin) plugins;
|
plugin-packages = builtins.filter (x: x != null) (
|
||||||
|
builtins.map (p: p.plugin or null) plugins
|
||||||
|
);
|
||||||
plugin-configs = lib.concatMapStrings (p:
|
plugin-configs = lib.concatMapStrings (p:
|
||||||
lib.optionalString
|
lib.optionalString
|
||||||
(p ? config) (
|
(p ? config) (
|
||||||
|
78
hosts/common/programs/neovim/nix_shell.lua
Normal file
78
hosts/common/programs/neovim/nix_shell.lua
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
-- add to ~/.vimrc to enable file-type detection for `nix-shell` scripts,
|
||||||
|
-- e.g. files with `#!nix-shell -i python3 -p python3 -p ...` are recognized as `python` files
|
||||||
|
|
||||||
|
-- see <https://neovim.io/doc/user/lua.html#vim.filetype.add()>
|
||||||
|
vim.filetype.add {
|
||||||
|
pattern = {
|
||||||
|
['.*'] = {
|
||||||
|
function(path, bufnr)
|
||||||
|
function test_for_nix_shell_shebang(maybe_hashbang)
|
||||||
|
local bang_payload = string.match(maybe_hashbang, '^#!(.*)$')
|
||||||
|
if not bang_payload then
|
||||||
|
return false -- not a shebang
|
||||||
|
end
|
||||||
|
-- look for `nix-shell` _as its own word_ anywhere in the shebang line
|
||||||
|
for word in string.gmatch(bang_payload, "[^ ]+") do
|
||||||
|
if word == "nix-shell" then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- extract `$interpreter` from some `#!nix-shell -i $interpreter ...` line
|
||||||
|
function parse_nix_shell(maybe_nix_shell)
|
||||||
|
local shell_payload = string.match(maybe_nix_shell, "^#!nix%-shell(.*)$")
|
||||||
|
|
||||||
|
if not shell_payload then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local interpreters = {}
|
||||||
|
local context = nil
|
||||||
|
for word in string.gmatch(shell_payload, "[^ ]+") do
|
||||||
|
if context == "-i" then
|
||||||
|
table.insert(interpreters, word)
|
||||||
|
context = nil
|
||||||
|
elseif word == "-i" then
|
||||||
|
context = "-i"
|
||||||
|
end
|
||||||
|
-- this parser doesn't consider _all_ nix flags, and especially things like quotes, etc.
|
||||||
|
-- just keep your nix-shell lines simple...
|
||||||
|
end
|
||||||
|
|
||||||
|
return interpreters[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
function filetype_from_interpreter(i)
|
||||||
|
if string.match(i, "^python") then
|
||||||
|
-- python3, python2.7, etc
|
||||||
|
return "python"
|
||||||
|
else
|
||||||
|
-- very common for interpreter name to be the same as filetype
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- docs: <https://neovim.io/doc/user/api.html#nvim_buf_get_lines()>
|
||||||
|
-- nvim_buf_get_lines({buffer}, {start}, {end}, {strict_indexing})
|
||||||
|
-- `start` and `end` are inclusive
|
||||||
|
local first_few_lines = vim.api.nvim_buf_get_lines(bufnr, 0, 5, false)
|
||||||
|
local maybe_hashbang = first_few_lines[1] or ''
|
||||||
|
|
||||||
|
if not test_for_nix_shell_shebang(maybe_hashbang) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- search for `#!nix-shell -i $interpreter ...` anywhere in the first few lines of the file
|
||||||
|
for _, line in ipairs(first_few_lines) do
|
||||||
|
local interpreter = parse_nix_shell(line)
|
||||||
|
if interpreter then
|
||||||
|
return filetype_from_interpreter(interpreter)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
-- high priority, to overrule vim's native detection (which gives ft=nix to all nix-shell files)
|
||||||
|
{ priority = math.huge },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
@@ -194,7 +194,18 @@ with pkgs.vimPlugins;
|
|||||||
# nvim-treesitter ships its own queries which may be distinct from e.g. helix.
|
# nvim-treesitter ships its own queries which may be distinct from e.g. helix.
|
||||||
# the queries aren't included when i ship the grammar in this manner.
|
# the queries aren't included when i ship the grammar in this manner.
|
||||||
# maybe check: <https://github.com/nvim-treesitter/nvim-treesitter/wiki/Extra-modules-and-plugins> ?
|
# maybe check: <https://github.com/nvim-treesitter/nvim-treesitter/wiki/Extra-modules-and-plugins> ?
|
||||||
pkgs.tree-sitter-nix-shell
|
#
|
||||||
|
# however: tree-sitter for `#!nix-shell` is the WRONG APPROACH.
|
||||||
|
# - because it works via "injection"s, i don't get proper LSP integration.
|
||||||
|
# i.e. no undefined variable checks, or language-aware function completions
|
||||||
|
# upstream vim showed interest in a similar approach as mine, but w/o the tree-sitter integration:
|
||||||
|
# - <https://groups.google.com/g/vim_dev/c/c-VXsJu-EKA>
|
||||||
|
# this likely still has the same problem w.r.t. LSP integration.
|
||||||
|
# vim-nix project also has a solution:
|
||||||
|
# - <https://github.com/LnL7/vim-nix/pull/51>
|
||||||
|
# this overrides the active filetype, so likely *is* what i want.
|
||||||
|
# and i've implemented my own pure-lua .vimrc integration further below
|
||||||
|
# pkgs.tree-sitter-nix-shell
|
||||||
]);
|
]);
|
||||||
type = "lua";
|
type = "lua";
|
||||||
config = ''
|
config = ''
|
||||||
@@ -228,6 +239,11 @@ with pkgs.vimPlugins;
|
|||||||
vim.o.foldexpr = 'nvim_treesitter#foldexpr()'
|
vim.o.foldexpr = 'nvim_treesitter#foldexpr()'
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
# detect `#!nix-shell -i $interpreter ...` files as filetype=$interpreter
|
||||||
|
type = "lua";
|
||||||
|
config = builtins.readFile ./nix_shell.lua;
|
||||||
|
}
|
||||||
{
|
{
|
||||||
# show commit which last modified text under the cursor.
|
# show commit which last modified text under the cursor.
|
||||||
# trigger with `:GitMessenger` or `<Leader>gm` (i.e. `\gm`)
|
# trigger with `:GitMessenger` or `<Leader>gm` (i.e. `\gm`)
|
||||||
|
Reference in New Issue
Block a user