1
Fork 0

Sketch out lazy.nvim nix interface

This commit is contained in:
Matei Adriel 2023-12-02 06:04:57 +01:00
parent c54f974a8c
commit 91eb12343c
No known key found for this signature in database
5 changed files with 404 additions and 61 deletions

View file

@ -1,7 +1,13 @@
local M = {}
local function importFrom(p)
return { import = p }
end
function M.setup()
require("lazy").setup("my.plugins", {
require("lazy").setup(
{ importFrom("my.plugins"), importFrom("nix.plugins") },
{
defaults = { lazy = true },
install = {
-- install missing plugins on startup. This doesn't increase startup time.
@ -40,7 +46,8 @@ function M.setup()
},
},
},
})
}
)
end
vim.keymap.set("n", "<leader>L", "<cmd>Lazy<cr>", { desc = "[L]azy ui" })

View file

@ -1,20 +0,0 @@
local env = require("my.helpers.env")
local M = {
"kyazdani42/nvim-tree.lua",
cmd = "NvimTreeToggle",
config = true,
cond = env.vscode.not_active() and env.firenvim.not_active(),
}
function M.init()
-- Toggle nerdtree with Control-n
vim.keymap.set(
"n",
"<C-n>",
":NvimTreeToggle<CR>",
{ desc = "Toggle [n]vim-tree" }
)
end
return M

View file

@ -76,10 +76,7 @@ let
];
# }}}
# {{{ extraRuntime
extraRuntime = env: [
# Snippets
(config.satellite.dev.path "home/features/neovim/snippets")
extraRuntimePaths = env: [
# Base16 theme
(pkgs.writeTextDir
"lua/nix/theme.lua"
@ -92,7 +89,21 @@ let
"lua/nix/env.lua"
"return '${env}'"
)
# Experimental nix module generation
config.satellite.neovim.generated.all
];
extraRuntime = env:
let
generated = pkgs.symlinkJoin {
name = "nixified-neovim-lua-modules";
paths = extraRuntimePaths env;
};
snippets = config.satellite.dev.path "home/features/neovim/snippets";
in
lib.concatStringsSep "," [ generated snippets ];
# }}}
# {{{ Client wrapper
# Wraps a neovim client, providing the dependencies
@ -109,7 +120,7 @@ let
postBuild = ''
wrapProgram $out/bin/${binName} \
--prefix PATH : ${lib.makeBinPath extraPackages} \
--set NVIM_EXTRA_RUNTIME ${lib.strings.concatStringsSep "," (extraRuntime name)} \
--set NVIM_EXTRA_RUNTIME ${extraRuntime name} \
${extraArgs}
'';
};
@ -195,4 +206,14 @@ in
};
};
# }}}
# {{{ Custom module testing
satellite.neovim.styluaConfig = ../../../stylua.toml;
satellite.neovim.lazy.nvim-tree = {
setup = true;
package = "kyazdani42/nvim-tree.lua";
keys.mapping = "<C-n>";
keys.desc = "Toggle [n]vim-tree";
keys.action = "<cmd>NvimTreeToggle<cr>";
};
# }}}
}

View file

@ -5,4 +5,5 @@
lua-colorscheme = import ./lua-colorscheme.nix;
theming = import ./theming.nix;
toggles = import ./toggles.nix;
neovim = import ./neovim.nix;
}

334
modules/common/neovim.nix Normal file
View file

@ -0,0 +1,334 @@
# Additional theming primitives not provided by stylix
{ pkgs, lib, config, ... }:
let
inherit (lib) types;
cfg = config.satellite.neovim;
# {{{ Custom types
myTypes = {
luaCode = types.nullOr (types.oneOf [
types.str
types.path
]);
fileTypes = types.nullOr (types.oneOf [
types.str
(types.listOf types.str)
]);
# {{{ Key type
lazyKey = types.oneOf [
types.str
(types.submodule
(_: {
options.mapping = lib.mkOption {
type = types.str;
};
options.action = lib.mkOption {
type = types.str;
};
options.ft = lib.mkOption {
default = null;
type = myTypes.fileTypes;
description = "Filetypes on which this keybind should take effect";
};
options.mode = lib.mkOption {
default = null;
# Only added the types I'm using in my config atm
type = types.nullOr (types.enum [ "n" "v" ]);
};
options.desc = lib.mkOption {
default = null;
type = types.nullOr types.str;
};
}))
];
# }}}
# {{{ Lazy module type
lazyModule = lib.fix (lazyModule: types.submodule (_: {
options = {
package = lib.mkOption {
type = types.oneOf [
types.package
types.str
];
description = "Package to configure the module around";
example = "nvim-telescope/telescope.nvim";
};
version = lib.mkOption {
default = null;
type = types.nullOr types.str;
description = "Pin the package to a certain version (useful for non-nix managed packages)";
};
tag = lib.mkOption {
default = null;
type = types.nullOr types.str;
description = "Pin the package to a certain git tag (useful for non-nix managed packages)";
};
lazy = lib.mkOption {
default = null;
type = types.nullOr types.bool;
description = "Specifies whether this module should be lazy-loaded";
};
dependencies.lua = lib.mkOption {
default = [ ];
type = types.listOf lazyModule;
};
dependencies.nix = lib.mkOption {
default = [ ];
type = types.listOf types.package;
};
cond = lib.mkOption {
default = null;
type = myTypes.luaCode;
description = "Condition based on which to enable/disbale loading the package";
};
setup = lib.mkOption {
default = null;
type = types.oneOf [ myTypes.luaCode types.bool ];
description = ''
Lua function (or module) to use for configuring the package.
Used instead of the canonically named `config` because said property has a special name in nix'';
};
event = lib.mkOption {
default = null;
type = types.nullOr (types.oneOf [
types.str
(types.listOf types.str)
]);
description = "Event on which the module should be lazy loaded";
};
ft = lib.mkOption {
default = null;
type = myTypes.fileTypes;
description = "Filetypes on which the module should be lazy loaded";
};
init = lib.mkOption {
default = null;
type = myTypes.luaCode;
description = "Lua function (or module) to run right away (even if the package is not yet loaded)";
};
passthrough = lib.mkOption {
default = null;
type = myTypes.luaCode;
description = "Attach additional things to the lazy module";
};
keys = lib.mkOption {
default = null;
type =
types.nullOr (types.oneOf [
myTypes.lazyKey
(types.listOf myTypes.lazyKey)
]);
};
opts = { };
};
}));
# }}}
};
# }}}
# {{{ Lua encoders
mkRawLuaObject = chunks:
''
{
${lib.concatStringsSep "," (lib.filter (s: s != "") chunks)}
}
'';
# An encoder is a function from some nix value to a string containing lua code.
# This object provides combinators for writing such encoders.
luaEncoders = {
# {{{ General helpers
identity = given: given;
bind = encoder: given: encoder given given;
conditional = predicate: caseTrue: caseFalse:
luaEncoders.bind (given: if predicate given then caseTrue else caseFalse);
map = f: encoder: given: encoder (f given);
trace = message: luaEncoders.map (f: lib.traceSeq message f);
# }}}
# {{{ Base types
# TODO: figure out escaping and whatnot
string = string: ''"${string}"'';
bool = bool: if bool then "true" else "false";
nil = _: "nil";
stringOr = luaEncoders.conditional lib.isString luaEncoders.string;
boolOr = luaEncoders.conditional lib.isBool luaEncoders.bool;
nullOr = luaEncoders.conditional (e: e == null) luaEncoders.nil;
# }}}
# {{{ Advanced types
luaCode = tag:
luaEncoders.conditional lib.isPath
(path: "require(${path}).${tag}")
luaEncoders.identity;
listOf = encoder: list:
mkRawLuaObject (lib.lists.map encoder list);
tryNonemptyList = encoder: luaEncoders.conditional
(l: l == [ ])
luaEncoders.nil
(luaEncoders.listOf encoder);
oneOrMany = encoder:
luaEncoders.conditional
lib.isList
(luaEncoders.listOf encoder)
encoder;
oneOrManyAsList = encoder: luaEncoders.map
(given: if lib.isList given then given else [ given ])
(luaEncoders.listOf encoder);
attrset = noNils: listOrder: listSpec: spec: attrset:
let
shouldKeep = given:
if noNils then
given != "nil"
else
true;
listChunks = lib.lists.map
(attr:
let result = listSpec.${attr} (attrset.${attr} or null);
in
lib.optionalString (shouldKeep result) result
)
listOrder;
objectChunks = lib.mapAttrsToList
(attr: encoder:
let result = encoder (attrset.${attr} or null);
in
lib.optionalString (shouldKeep result)
"${attr} = ${result}"
)
spec;
in
mkRawLuaObject (listChunks ++ objectChunks);
# }}}
};
e = luaEncoders;
# }}}
# Format and write a lua file to disk
writeLuaFile = path: name: text:
let
directory = "lua/${path}";
destination = "${directory}/${name}.lua";
unformatted = pkgs.writeText "raw-lua-${name}" text;
in
pkgs.runCommand "formatted-lua-${name}" { } ''
mkdir -p $out/${directory}
cp --no-preserve=mode ${unformatted} $out/${destination}
${lib.getExe pkgs.stylua} --config-path ${cfg.styluaConfig} $out/${destination}
'';
in
{
options.satellite.neovim = {
lazy = lib.mkOption {
default = { };
description = "Record of persistent locations (eg: /persist)";
type = types.attrsOf myTypes.lazyModule;
};
generated.lazy = lib.mkOption {
type = types.attrsOf (types.submodule (_: {
options = {
raw = lib.mkOption {
type = types.lines;
description = "The lua script generated using the other options";
};
module = lib.mkOption {
type = types.package;
description = "The lua script generated using the other options";
};
};
}));
description = "Attrset containing every module generated from the lazy configuration";
};
generated.all = lib.mkOption {
default = { };
type = types.package;
description = "Derivation building all the given nix modules";
};
styluaConfig = lib.mkOption {
type = types.path;
description = "Config to use for formatting lua modules";
};
};
config.satellite.neovim.generated.lazy =
let
lazyKeyEncoder =
e.stringOr (e.attrset true [ "mapping" "action" ]
{
mapping = e.string;
action = e.nullOr e.string;
}
{
mode = e.nullOr e.string;
desc = e.nullOr e.string;
ft = e.nullOr (e.oneOrMany e.string);
});
renameKey = from: to: lib.mapAttrs' (name: value:
if name == from then { inherit value; name = to; }
else { inherit name value; });
lazyObjectEncoder = e.map (renameKey "setup" "config")
(e.attrset true [ "package" ]
{
package = e.string;
}
{
tag = e.nullOr e.string;
version = e.nullOr e.string;
dependencies = e.map (d: d.lua) (e.tryNonemptyList lazyObjectEncoder);
lazy = e.nullOr e.bool;
# TODO: add sugar for enabling/disabling under certain envs
cond = e.nullOr (e.luaCode "cond");
config = e.nullOr (e.boolOr (e.luaCode "config"));
init = e.nullOr (e.luaCode "init");
event = e.nullOr (e.oneOrMany e.string);
ft = e.nullOr (e.oneOrMany e.string);
keys = e.nullOr (e.oneOrManyAsList lazyKeyEncoder);
# TODO: passthrough
});
makeLazyScript = opts: ''
-- This file was generated by nix
return ${lazyObjectEncoder opts}
'';
in
lib.attrsets.mapAttrs
(name: opts: rec {
raw = makeLazyScript opts;
module = writeLuaFile "nix/plugins" name raw;
})
cfg.lazy;
config.satellite.neovim.generated.all =
pkgs.symlinkJoin {
name = "lazy-nvim-modules";
paths = lib.attrsets.mapAttrsToList (_: m: m.module) cfg.generated.lazy;
};
}