home/nvim: add my to-be-upstreamed neovim hm module

This commit is contained in:
Gabriel Fontes
2022-09-25 22:10:51 -03:00
parent fa4769a4ed
commit ef4a306ab5
4 changed files with 574 additions and 24 deletions
+10 -3
View File
@@ -11,9 +11,17 @@
programs.neovim = {
enable = true;
extraConfig = /* vim */ ''
extraRuntime = {
"colors/nix-${config.colorscheme.slug}.vim" = {
text = import ./theme.nix config.colorscheme;
};
};
extraConfig.viml = /* vim */ ''
"Use truecolor
set termguicolors
"Set colorscheme
colorscheme nix-${config.colorscheme.slug}
"Set fold level to highest in file
"so everything starts out unfolded at just the right level
@@ -140,13 +148,12 @@
plugin = pkgs.writeTextDir "colors/nix-${config.colorscheme.slug}.vim"
(import ./theme.nix config.colorscheme);
config = /* vim */ ''
colorscheme nix-${config.colorscheme.slug}
'';
}
];
};
xdg.configFile."nvim/init-home-manager.vim".onChange =
xdg.configFile."nvim/init.lua".onChange =
let
nvr = "${pkgs.neovim-remote}/bin/nvr";
in
+16 -18
View File
@@ -3,36 +3,34 @@
home.packages = with pkgs; [ rnix-lsp ];
programs.neovim = {
extraConfig = /* lua */ ''
'';
extraConfig.lua = /* lua */ ''
vim.keymap.set("n", "gD", vim.lsp.buf.declaration, { desc = "Go to declaration" })
vim.keymap.set("n", "gd", vim.lsp.buf.definition, { desc = "Go to definition" })
vim.keymap.set("n", "gi", vim.lsp.buf.implementation, { desc = "Go to implementation" })
vim.keymap.set("n", "<space>f", vim.lsp.buf.formatting, { desc = "Format code" })
vim.keymap.set("n", "K", vim.lsp.buf.hover, { desc = "Hover Documentation" })
function add_sign(name, text)
vim.fn.sign_define(name, { text = text, texthl = name, numhl = name})
end
add_sign("DiagnosticSignError", " ")
add_sign("DiagnosticSignWarn", " ")
add_sign("DiagnosticSignHint", " ")
add_sign("DiagnosticSignInfo", " ")
'';
plugins = with pkgs.vimPlugins; [
# LSP
{
plugin = nvim-lspconfig;
type = "lua";
config = /* lua */ ''
vim.keymap.set("n", "gD", vim.lsp.buf.declaration, { desc = "Go to declaration" })
vim.keymap.set("n", "gd", vim.lsp.buf.definition, { desc = "Go to definition" })
vim.keymap.set("n", "gi", vim.lsp.buf.implementation, { desc = "Go to implementation" })
vim.keymap.set("n", "<space>f", vim.lsp.buf.formatting, { desc = "Format code" })
vim.keymap.set("n", "K", vim.lsp.buf.hover, { desc = "Hover Documentation" })
function add_sign(name, text)
vim.fn.sign_define(name, { text = text, texthl = name, numhl = name})
end
add_sign("DiagnosticSignError", " ")
add_sign("DiagnosticSignWarn", " ")
add_sign("DiagnosticSignHint", " ")
add_sign("DiagnosticSignInfo", " ")
local lspconfig = require('lspconfig')
function add_lsp(binary, server, options)
if vim.fn.executable(binary) == 1 then server.setup{options} end
end
add_lsp("docker-langserver", lspconfig.dockerls, {})
add_lsp("docker-langserver", lspconfig.dockerls, {})
add_lsp("bash-language-server", lspconfig.bashls, {})
add_lsp("clangd", lspconfig.clangd, {})
+4 -3
View File
@@ -1,10 +1,11 @@
{
afuse = import ./afuse.nix;
rgbdaemon = import ./rgbdaemon.nix;
wallpaper = import ./wallpaper.nix;
shellcolor = import ./shellcolor.nix;
fonts = import ./fonts.nix;
neovim = import ./neovim.nix;
preferred-apps = import ./preferred-apps.nix;
rgbdaemon = import ./rgbdaemon.nix;
shellcolor = import ./shellcolor.nix;
swaylock = import ./swaylock.nix;
wallpaper = import ./wallpaper.nix;
xpo = import ./xpo.nix;
}
+544
View File
@@ -0,0 +1,544 @@
/*
Neovim module language support refactor
Adds support to use any lua compatible language with `cfg.extraConfig` and `cfg.plugins.*.config`
ATM upstream only supports vimscript on extraConfig and vimscript+lua on plugin config
Will test it for a few days before upstreaming
https://github.com/Misterio77/home-manager/blob/neovim-multilang/modules/programs/neovim.nix
*/
{ config, lib, pkgs, inputs, ... }: # TODO remove `inputs`
with lib;
let
cfg = config.programs.neovim;
# TODO change back to `../lib` before upstreaming
fileType = (import "${inputs.home-manager}/modules/lib/file-type.nix" {
inherit (config.home) homeDirectory;
inherit lib pkgs;
}).fileType;
jsonFormat = pkgs.formats.json { };
extraPython3PackageType = mkOptionType {
name = "extra-python3-packages";
description = "python3 packages in python.withPackages format";
check = with types;
(x: if isFunction x then isList (x pkgs.python3Packages) else false);
merge = mergeOneOption;
};
# Currently, upstream Neovim is pinned on Lua 5.1 for LuaJIT support.
# This will need to be updated if Neovim ever migrates to a newer
# version of Lua.
extraLua51PackageType = mkOptionType {
name = "extra-lua51-packages";
description = "lua5.1 packages in lua5_1.withPackages format";
check = with types;
(x: if isFunction x then isList (x pkgs.lua51Packages) else false);
merge = mergeOneOption;
};
pluginWithConfigType = types.submodule {
options = {
config = mkOption {
type = with types; nullOr str;
default = null;
description =
"Script to configure this plugin. The scripting language should match type.";
};
type = mkOption {
type = types.str;
description =
"Language used in config. Configurations are aggregated per-language.";
default = "viml";
};
optional = mkEnableOption "optional" // {
description = "Don't load by default (load with :packadd)";
};
plugin = mkOption {
type = types.package;
description =
"Package providing the plugin";
};
runtime = mkOption {
default = { };
# passing actual "${xdg.configHome}/nvim" as basePath was a bit tricky
# due to how fileType.target is implemented
type = fileType "<varname>xdg.configHome/nvim</varname>" "nvim";
example = literalExpression ''
{ "ftplugin/c.vim".text = "setlocal omnifunc=v:lua.vim.lsp.omnifunc"; }
'';
description = ''
Set of files that have to be linked in nvim config folder.
'';
};
};
};
languageType = types.submodule {
options = {
extension = mkOption {
type = types.str;
description = "File extension this language uses.";
};
luaPackages = mkOption {
type = with types; either extraLua51PackageType (listOf package);
default = [ ];
example = literalExpression ''
with pkgs.lua51Packages [ fennel ];
'';
description = "Lua packages required to support this language.";
};
vimPlugins = mkOption {
type = with types; listOf (coercedTo package (v: { plugin = v; }) pluginWithConfigType);
default = [ ];
description = "Vim plugins required to support this language.";
example = literalExpression ''
with pkgs.vimPlugins; [ nvim-moonwalk ];
'';
};
enableScript = mkOption {
type = with types; nullOr str;
default = null;
description = "Lua script required to enable support for this language.";
example = literalExpression ''
require("moonwalk").add_loader("fnl", function(src, path)
return require("fennel").compileString(src, { filename = path })
end)
'';
};
importScript = mkOption {
type = with types; functionTo str;
default = n: ''
require('${n}')
'';
# Only I could get a `require('${fileName}')` literal into the manual
defaultText = literalExpression ''
fileName: "require(${"'"}''${fileName}')"
'';
description = ''
Function returning the statement which lua will use to import
this language's config.
The provided variable does not include file extension.
'';
};
};
};
langVimPlugins = flatten (mapAttrsToList (_: lang: lang.vimPlugins) cfg.configLanguages);
allPlugins = cfg.plugins ++ langVimPlugins ++ optional cfg.coc.enable {
type = "viml";
plugin = cfg.coc.package;
config = cfg.coc.pluginConfig;
optional = false;
runtime = { };
};
langLuaPackages = flatten (mapAttrsToList (_: lang: lang.luaPackages) cfg.configLanguages);
allLuaPackages = cfg.extraLuaPackages ++ langLuaPackages;
extraMakeWrapperArgs = optionalString (cfg.extraPackages != [ ])
''--suffix PATH : "${makeBinPath cfg.extraPackages}"'';
extraMakeWrapperLuaCArgs = optionalString (allLuaPackages != [ ]) ''
--suffix LUA_CPATH ";" "${
concatMapStringsSep ";" pkgs.lua51Packages.getLuaCPath
allLuaPackages
}"'';
extraMakeWrapperLuaArgs = optionalString (allLuaPackages != [ ]) ''
--suffix LUA_PATH ";" "${
concatMapStringsSep ";" pkgs.lua51Packages.getLuaPath
allLuaPackages
}"'';
in {
disabledModules = [ "programs/neovim.nix" ];
imports = [
/* TODO
(mkRenamedOptionModule [ "programs" "neovim" "generatedConfigViml" ]
[ "programs" "neovim" "generatedConfigs" "viml" ])
*/
(mkRemovedOptionModule [ "programs" "neovim" "withPython" ]
"Python2 support has been removed from neovim.")
(mkRemovedOptionModule [ "programs" "neovim" "extraPythonPackages" ]
"Python2 support has been removed from neovim.")
(mkRemovedOptionModule [ "programs" "neovim" "configure" ] ''
programs.neovim.configure is deprecated.
Other programs.neovim options can override its settings or ignore them.
Please use the other options at your disposal:
configure.packages.*.opt -> programs.neovim.plugins = [ { plugin = ...; optional = true; }]
configure.packages.*.start -> programs.neovim.plugins = [ { plugin = ...; }]
configure.customRC -> programs.neovim.extraConfig
'')
];
options = {
programs.neovim = {
enable = mkEnableOption "Neovim";
viAlias = mkOption {
type = types.bool;
default = false;
description = ''
Symlink <command>vi</command> to <command>nvim</command> binary.
'';
};
vimAlias = mkOption {
type = types.bool;
default = false;
description = ''
Symlink <command>vim</command> to <command>nvim</command> binary.
'';
};
vimdiffAlias = mkOption {
type = types.bool;
default = false;
description = ''
Alias <command>vimdiff</command> to <command>nvim -d</command>.
'';
};
withNodeJs = mkOption {
type = types.bool;
default = false;
description = ''
Enable node provider. Set to <literal>true</literal> to
use Node plugins.
'';
};
withRuby = mkOption {
type = types.bool;
default = true;
description = ''
Enable ruby provider.
'';
};
withPython3 = mkOption {
type = types.bool;
default = true;
description = ''
Enable Python 3 provider. Set to <literal>true</literal> to
use Python 3 plugins.
'';
};
extraPython3Packages = mkOption {
type = with types; either extraPython3PackageType (listOf package);
default = (_: [ ]);
defaultText = literalExpression "ps: [ ]";
example = literalExpression "(ps: with ps; [ python-language-server ])";
description = ''
A function in python.withPackages format, which returns a
list of Python 3 packages required for your plugins to work.
'';
};
extraLuaPackages = mkOption {
type = with types; either extraLua51PackageType (listOf package);
default = [ ];
defaultText = literalExpression "[ ]";
example = literalExpression "(ps: with ps; [ luautf8 ])";
description = ''
A function in lua5_1.withPackages format, which returns a
list of Lua packages required for your plugins to work.
'';
};
generatedConfigs = mkOption {
type = types.attrsOf types.str;
visible = true;
readOnly = true;
example = literalExpression ''
{
viml = '''
" Generated by home-manager
map <leader> ,
''';
lua = '''
-- Generated by home-manager
vim.opt.background = "dark"
''';
}'';
description = ''
Generated configurations with as key their language.
From plugins configurations (using "type") and extraConfig.
'';
};
package = mkOption {
type = types.package;
default = pkgs.neovim-unwrapped;
defaultText = literalExpression "pkgs.neovim-unwrapped";
description = "The package to use for the neovim binary.";
};
finalPackage = mkOption {
type = types.package;
visible = false;
readOnly = true;
description = "Resulting customized neovim package.";
};
extraConfig = mkOption {
type = with types; coercedTo lines (x: { viml = x; }) (attrsOf lines);
default = {};
example = literalExpression ''
{
viml = "set nobackup";
lua = "vim.keymap.set("n", "gd", vim.lsp.buf.definition)";
}
'';
description = ''
Custom configuration lines for each supported language.
If provided as a string, viml is assumed.
'';
};
configLanguages = mkOption {
description = ''
Configuration languages supported by neovim.
</para><para>
Supports viml (vimscript) and lua by default. The example shows
how to enable support for fennel using moonwalk.
</para><para>
Consider using lib.mkOptionDefault to extend or override default
languages instead of specifying all of them from scratch.
'';
type = with types; attrsOf languageType;
defaultText = literalExpression ''
{
viml = {
extension = "vim";
importScript = file: '''
vim.cmd 'runtime vim/''${file}.vim'
''';
};
lua = {
extension = "lua";
};
}
'';
default = {
viml = {
extension = "vim";
importScript = file: ''
vim.cmd 'runtime vim/${file}.vim'
'';
};
lua = {
extension = "lua";
};
};
example = literalExpression ''
lib.mkOptionDefault {
fennel = {
extension = "fnl";
luaPackages = with pkgs.lua51Packages; [ fennel ];
vimPlugins = with pkgs.vimPlugins; [ nvim-moonwalk ];
enableScript = '''
require("moonwalk").add_loader("fnl", function(src, path)
return require("fennel").compileString(src, { filename = path })
end)
''';
};
}
'';
};
extraPackages = mkOption {
type = with types; listOf package;
default = [ ];
example = literalExpression "[ pkgs.shfmt ]";
description = "Extra packages available to nvim.";
};
extraRuntime = mkOption {
default = { };
# passing actual "${xdg.configHome}/nvim" as basePath was a bit tricky
# due to how fileType.target is implemented
type = fileType "<varname>xdg.configHome/nvim</varname>" "nvim";
example = literalExpression ''
{ "ftplugin/c.vim".text = "setlocal omnifunc=v:lua.vim.lsp.omnifunc"; }
'';
description = ''
Set of files that have to be linked in nvim config folder.
'';
};
plugins = mkOption {
type = with types; listOf (coercedTo package (v: { plugin = v; }) pluginWithConfigType);
default = [ ];
example = literalExpression ''
with pkgs.vimPlugins; [
yankring
vim-nix
{
plugin = vim-startify;
config = "let g:startify_change_to_vcs_root = 0";
}
{
plugin = nvim-lspconfig;
type = "lua";
config = '''
local lspconfig = require("lspconfig")
lspconfig.rnix.setup{}
lspconfig.pylsp.setup{}
''';
}
]
'';
description = ''
List of vim plugins to install optionally associated with
configuration to be placed in the respective language file.
'';
};
coc = {
enable = mkEnableOption "Coc";
package = mkOption {
type = types.package;
default = pkgs.vimPlugins.coc-nvim;
defaultText = literalExpression "pkgs.vimPlugins.coc-nvim";
description = "The package to use for the CoC plugin.";
};
settings = mkOption {
type = jsonFormat.type;
default = { };
example = literalExpression ''
{
"suggest.noselect" = true;
"suggest.enablePreview" = true;
"suggest.enablePreselect" = false;
"suggest.disableKind" = true;
languageserver = {
haskell = {
command = "haskell-language-server-wrapper";
args = [ "--lsp" ];
rootPatterns = [
"*.cabal"
"stack.yaml"
"cabal.project"
"package.yaml"
"hie.yaml"
];
filetypes = [ "haskell" "lhaskell" ];
};
};
};
'';
description = ''
Extra configuration lines to add to
<filename>$XDG_CONFIG_HOME/nvim/coc-settings.json</filename>
See
<link xlink:href="https://github.com/neoclide/coc.nvim/wiki/Using-the-configuration-file" />
for options.
'';
};
pluginConfig = mkOption {
type = types.lines;
default = "";
description = "Script to configure CoC. Must be viml.";
};
};
};
};
config = let
suppressNotVimlConfig = plugin:
if plugin.type != "viml"
then plugin // { config = null; }
else plugin;
neovimConfig = pkgs.neovimUtils.makeNeovimConfig {
inherit (cfg) extraPython3Packages withPython3 withRuby viAlias vimAlias;
withNodeJs = cfg.withNodeJs || cfg.coc.enable;
plugins = map suppressNotVimlConfig allPlugins;
customRC = cfg.generatedConfigs.viml;
};
in mkIf cfg.enable {
assertions = let
undefinedLangs = subtractLists (attrNames cfg.configLanguages) (attrNames cfg.generatedConfigs);
in [{
assertion = undefinedLangs == [ ];
message =
if (any (l: l == "lua" || l == "viml") undefinedLangs)
then ''
The neovim configuration is using vimscript or lua, but they are not present in `programs.neovim.configLanguages`.
You probably meant to use lib.mkOptionDefault when setting it.
''
else ''
Languages [${concatStringsSep "," undefinedLangs}] found in neovim configuration, but not defined in `programs.neovim.configLanguages`.
'';
}];
# Generate config for each supported config language
programs.neovim.generatedConfigs = let
concatLines = concatStringsSep "\n";
getCfgs = plugins: filter (c: c != null) (map (p: p.config) plugins);
groupedPlugins = lists.groupBy (p: p.type) allPlugins;
pluginConfigs = mapAttrs (_: plugins: concatLines (getCfgs plugins)) groupedPlugins;
in
zipAttrsWith (_: concatLines) [ pluginConfigs cfg.extraConfig ];
home.packages = [ cfg.finalPackage ];
xdg.configFile = mkMerge
(
(map (plugin: plugin.runtime) allPlugins) ++ [(cfg.extraRuntime)] ++
# Make a config file for each configLang (if it's not empty) and import it on init.lua
(mapAttrsToList
(langName: langConfig: let
langExtension = cfg.configLanguages.${langName}.extension;
langImportScript = cfg.configLanguages.${langName}.importScript;
langFilePath = "nvim/${langExtension}/home-manager-${langName}.${langExtension}";
in
mkIf (langConfig != "") {
${langFilePath}.text = langConfig;
"nvim/init.lua".text = ''
-- ${config.xdg.configFile.${langFilePath}.source}
${langImportScript "home-manager-${langName}"}
'';
}) cfg.generatedConfigs
) ++
# Add support for all configLanguages
(mapAttrsToList
(langName: langOpts: mkIf (langOpts.enableScript != null) {
"nvim/init.lua".text = langOpts.enableScript;
}) cfg.configLanguages
) ++
[{
"nvim/coc-settings.json" = mkIf cfg.coc.enable {
source = jsonFormat.generate "coc-settings.json" cfg.coc.settings;
};
}]);
programs.neovim.finalPackage = pkgs.wrapNeovimUnstable cfg.package
(neovimConfig // {
wrapperArgs = (escapeShellArgs neovimConfig.wrapperArgs) + " "
+ extraMakeWrapperArgs + " " + extraMakeWrapperLuaCArgs + " "
+ extraMakeWrapperLuaArgs;
wrapRc = false;
});
programs.bash.shellAliases = mkIf cfg.vimdiffAlias { vimdiff = "nvim -d"; };
programs.fish.shellAliases = mkIf cfg.vimdiffAlias { vimdiff = "nvim -d"; };
programs.zsh.shellAliases = mkIf cfg.vimdiffAlias { vimdiff = "nvim -d"; };
};
}