Compare commits

...

10 commits

Author SHA1 Message Date
aec9110e70 hopefully R fix 2026-05-24 00:01:12 +10:00
62f456ed46 hopefully R fix 2026-05-23 23:54:07 +10:00
458332a141 hopefully R fix 2026-05-23 23:44:56 +10:00
740f86ad7b hopefully R fix 2026-05-23 23:41:48 +10:00
d218b05d48 hopefully R fix 2026-05-23 23:38:18 +10:00
1c5619312d simplified 2026-05-23 23:07:54 +10:00
ed7abad63c Expose shellhooks via API 2026-05-23 22:53:52 +10:00
db610620b3 large refactor 2026-05-23 21:59:54 +10:00
a0ba90c4d2 refactor package installation 2026-05-23 20:15:23 +10:00
10254b11c7 Corrected langpackage installation 2026-05-23 18:41:22 +10:00
20 changed files with 670 additions and 343 deletions

View file

@ -1,9 +0,0 @@
# nix
- For R.nvim in the Nix wrapper, both RNVIM_COMPLDIR (C server compilation) and a writable R_LIBS_USER directory (nvimcom R package installation) must be configured — fixing only one leaves permission errors in the other. Confidence: 0.65
- For R.nvim writable directories (RNVIM_COMPLDIR, R_LIBS_USER, TMPDIR), prefer project-local paths (e.g., $PWD/.Rlibs) over global cache paths — the cache approach may let the build succeed but still fail at runtime. Confidence: 0.70
- Do not use lib.mkDefault on values consumed by lib.optionals or other boolean-checking functions — mkDefault wraps values in a priority set that fails "expected a Boolean" at evaluation time. Use plain booleans for inline conditionals, reserving mkDefault for module options resolved by the merge system. Confidence: 0.70
# Taste (Continuously Learned by [CommandCode][cmd])
[cmd]: https://commandcode.ai/

2
.gitignore vendored
View file

@ -3,3 +3,5 @@
*.R
.Rlibs
.nvimcom
.commandcode
.commandcode/

341
README.md Normal file
View file

@ -0,0 +1,341 @@
# nvimConfig
Modular Neovim wrapper config. Defines a wrapped `vv` binary with per-category packages, plugins, and environment variables. Available as NixOS module, Home Manager module, or single-starflake import.
## Quick start (imported into another flake)
```nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
rixpkgs.url = "github:dwinkler1/rixpkgs/af2dd3f7b4b172077747c0869d4e30702fb71b0e";
fran = {
url = "github:dwinkler1/fran";
inputs.nixpkgs.follows = "rixpkgs";
};
nvimConfig = {
url = "github:dwinkler1/nvimConfig";
inputs = {
nixpkgs.follows = "nixpkgs";
rixpkgs.follows = "rixpkgs";
fran.follows = "fran";
};
};
};
outputs = { self, nixpkgs, nvimConfig, ... } @ inputs: let
systems = ["aarch64-darwin" "x86_64-linux" "aarch64-linux"];
forAllSystems = nixpkgs.lib.genAttrs systems;
in {
packages = forAllSystems (system: let
pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true;
overlays = [ nvimConfig.overlays.dependencies ];
};
evalResult = nvimConfig.lib.eval {
inherit pkgs;
modules = [ projectSettings ]; # see below
};
in {
default = evalResult.config.wrap { inherit pkgs; };
});
devShells = forAllSystems (system: let
pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true;
overlays = [ nvimConfig.overlays.dependencies ];
};
evalResult = nvimConfig.lib.eval {
inherit pkgs;
modules = [ projectSettings ];
};
nv = evalResult.config.wrap { inherit pkgs; };
in {
default = pkgs.mkShell {
packages = [ nv ] ++ nvimConfig.lib.devShellPackages evalResult.config;
shellHook = nvimConfig.lib.shellHook evalResult.config;
};
});
};
}
```
## Home Manager module
```nix
{ inputs, ... }: {
home.packages = [
(inputs.nvimConfig.homeModules.default { inherit pkgs; })
# Or via the overlay:
# pkgs.vv
];
}
```
## NixOS module
```nix
{ inputs, ... }: {
environment.systemPackages = [
(inputs.nvimConfig.nixosModules.default { inherit pkgs; })
];
}
```
## Overriding settings
Define a `projectSettings` attrset and pass it to `nvimConfig.lib.eval` or `nvimConfig.lib.mkWrapper`. The helper injects your overlaid `pkgs` automatically, so downstream consumers do not need to wire `specialArgs` themselves. Every option in `nvimConfig.wrapperConfigs.default` can be overridden here. Local `packages.default`, local `devShells.default`, downstream helper usage, and `pkgs.vv` all resolve the same module defaults unless you override them.
### Basic downstream flake example
This example enables a few cats, adds runtime tools to the shared wrapper/devShell package set, and appends language libraries to the default Python and R environments.
```nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
rixpkgs.url = "github:dwinkler1/rixpkgs/af2dd3f7b4b172077747c0869d4e30702fb71b0e";
fran = {
url = "github:dwinkler1/fran";
inputs.nixpkgs.follows = "rixpkgs";
};
nvimConfig = {
url = "github:dwinkler1/nvimConfig";
inputs = {
nixpkgs.follows = "nixpkgs";
rixpkgs.follows = "rixpkgs";
fran.follows = "fran";
};
};
};
outputs = { nixpkgs, nvimConfig, ... }: let
system = "aarch64-darwin";
pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true;
overlays = [ nvimConfig.overlays.dependencies ];
};
projectSettings = {
cats = {
python = true;
r = true;
nix = true;
markdown = true;
optional = true;
};
settings.lang_packages = {
python = with pkgs.python3Packages; [
pandas
pyarrow
];
r = with pkgs.rpkgs.rPackages; [
fixest
modelsummary
];
};
catPkgs = {
python = [
(pkgs.python3.withPackages (ps:
ps
++ (with ps; [
pandas
pyarrow
])))
pkgs.ruff
pkgs.basedpyright
pkgs.uv
pkgs.nodejs
];
nix = [
pkgs.alejandra
pkgs.nil
];
optional = [
pkgs.git
pkgs.fd
pkgs.ripgrep
];
};
};
evalResult = nvimConfig.lib.eval {
inherit pkgs;
modules = [ projectSettings ];
};
nv = evalResult.config.wrap { inherit pkgs; };
in {
packages.${system}.default = nv;
devShells.${system}.default = pkgs.mkShell {
packages = [ nv ] ++ nvimConfig.lib.devShellPackages evalResult.config;
shellHook = nvimConfig.lib.shellHook evalResult.config;
};
};
}
```
### Categories
Enable only the cats you need. Defaults are listed in `modules/module/settings/cats.nix`.
```nix
projectSettings = {
cats = {
python = true; # enable Python tooling
r = false; # disable R
nix = true;
lua = false;
markdown = false;
optional = false;
gitPlugins = false;
};
};
```
### Language packages (module defaults)
Add Python/R/Julia libraries that get appended to the module defaults. The built-in defaults are:
- Python: `duckdb`, `polars`
- R: `arrow`, `broom`, `data_table`, `janitor`, `styler`
- Julia: `DataFramesMeta`, `QuackIO`
```nix
projectSettings = {
settings.lang_packages = {
python = with pkgs.python3Packages; [ pandas numpy ];
r = with pkgs.rpkgs.rPackages; [ fixest data_table ];
julia = [ "StatsBase" "Plots" ];
};
};
```
Use `lib.mkForce` to replace rather than append:
```nix
projectSettings = {
settings.lang_packages = {
python = pkgs.lib.mkForce (with pkgs.python3Packages; [ polars duckdb ]);
};
};
```
### Runtime dependencies (per-cat packages)
Override `catPkgs` to change the full runtime tool lists that appear in both the wrapper PATH and the devShell. Use normal assignments to merge list values, or `lib.mkForce` to replace them.
```nix
projectSettings = {
catPkgs = {
nix = [ pkgs.nil pkgs.nixfmt ];
python = [
(pkgs.python3.withPackages (ps: [ ps.pandas ps.duckdb ]))
pkgs.ruff
];
};
};
```
### Direct runtimePkgs override (always-on)
Add packages to `catPkgs.always` for tools that should always be available regardless of other cat toggles.
```nix
projectSettings = {
catPkgs = {
always = [ pkgs.git pkgs.curl pkgs.pre-commit ];
};
};
```
### Runtime env vars
```nix
projectSettings = {
env = {
MY_PROJECT_VAR = "some-value";
};
envDefault = {
EDITOR = "vv";
};
};
```
`env` values are forced; `envDefault` values can be overridden by the user's shell.
### Choosing the right override surface
- Use `cats` to enable or disable a whole language or tooling category.
- Use `settings.lang_packages` to add or replace Python, R, or Julia libraries within a language environment.
- Use `catPkgs` to change the full runtime tool list for a category. `config.runtimePkgs` drives wrapper PATH composition, while `nvimConfig.lib.devShellPackages config` returns the package-only list suitable for `mkShell`.
- Use `env` or `envDefault` for wrapper environment variables.
- Use `specs` for plugin additions or custom runtime behavior.
### Neovim settings
```nix
projectSettings = {
settings = {
colorscheme = "kanagawa";
background = "dark";
wrapRc = true;
config_directory = ./nvim; # path to init.lua + lua/ dir
aliases = [ "v" "nvim" ]; # extra binary names (default: [ "vvim" ])
};
binName = "nv"; # binary name (default: vv)
};
```
## Adding plugins
```nix
projectSettings = {
specs = {
extraPlugins = {
data = with pkgs.vimPlugins; [
telescope-nvim
which-key-nvim
];
};
extraLazy = {
lazy = true;
data = with pkgs.vimPlugins; [ dashboard-nvim ];
};
# Inject Lua config at startup
extraLua = {
data = pkgs.writeText "extra.lua" ''
vim.opt.number = true
vim.opt.relativenumber = true
'';
before = ["INIT_MAIN"];
};
};
};
```
## Architecture
```
settings/lang-packages.nix ──► settings.lang_packages
cats.nix ───────────────► config.cats │
│ │
▼ ▼
cat-packages.nix ───────► config.catPkgs.<cat>
│ │
├──────────────┐ │
▼ ▼ ▼
deps.nix PATH wrapper.config.wrap devShells.default
```
- **Overlays** (`overlays/`) inject dependency package sets into nixpkgs (`rpkgs`, `baseRPackages`, `basePythonPackages`, plugins). Top-level `rWrapper` and `quarto` are compatibility conveniences, but `pkgs.rpkgs` is the canonical R surface for downstream configuration.
- **cat-packages.nix** is the single source of truth for per-category packages. Each list is gated by its cat toggle.
- **deps.nix** wires `catPkgs` into the wrapper's runtime PATH.
- **settings.lang_packages** holds the shared defaults used by local outputs and downstream module consumers.
- **flake.nix** exports `lib.eval`, `lib.mkWrapper`, `lib.devShellPackages`, and `lib.shellHook` as the canonical downstream helpers, and builds `packages.default` and `devShells.default` from the same module config.

46
flake.lock generated
View file

@ -52,42 +52,24 @@
"type": "github"
}
},
"plugins-r": {
"flake": false,
"locked": {
"lastModified": 1776905071,
"narHash": "sha256-dXox6qEs1VDE7vPNDoN8bY4g06uj1IEs6uki72w8lpA=",
"owner": "R-nvim",
"repo": "R.nvim",
"rev": "582f2af11290ac067e49018db38e12a511325556",
"type": "github"
},
"original": {
"owner": "R-nvim",
"ref": "v0.99.4",
"repo": "R.nvim",
"type": "github"
}
},
"r-nvim-nix": {
"inputs": {
"nixpkgs": [
"rixpkgs"
],
"rnvimsrc": [
"plugins-r"
]
"rnvimsrc": "rnvimsrc"
},
"locked": {
"lastModified": 1778684156,
"narHash": "sha256-Z4y1tQfkIsPK4NRxGn668HMDfWxnxNxSJ0CAOOXiIfY=",
"lastModified": 1779438909,
"narHash": "sha256-1lvv0bdvSVyeCIgeZ7Ws7ffbDFurA5LJscS9dRLHzC8=",
"owner": "dwinkler1",
"repo": "r_nvim_nix",
"rev": "2f49dfee27886068e2f49cbd54558ce4cc424c82",
"rev": "ec17e22ab362a0ddfd6c2e9c5e95d43897a143be",
"type": "github"
},
"original": {
"owner": "dwinkler1",
"ref": "v0.99.4",
"repo": "r_nvim_nix",
"type": "github"
}
@ -108,12 +90,28 @@
"type": "github"
}
},
"rnvimsrc": {
"flake": false,
"locked": {
"lastModified": 1776905071,
"narHash": "sha256-dXox6qEs1VDE7vPNDoN8bY4g06uj1IEs6uki72w8lpA=",
"owner": "R-nvim",
"repo": "R.nvim",
"rev": "582f2af11290ac067e49018db38e12a511325556",
"type": "github"
},
"original": {
"owner": "R-nvim",
"ref": "v0.99.4",
"repo": "R.nvim",
"type": "github"
}
},
"root": {
"inputs": {
"fran": "fran",
"nixpkgs": "nixpkgs",
"plugins-cmp-pandoc-references": "plugins-cmp-pandoc-references",
"plugins-r": "plugins-r",
"r-nvim-nix": "r-nvim-nix",
"rixpkgs": "rixpkgs",
"wrappers": "wrappers"

236
flake.nix
View file

@ -1,4 +1,4 @@
# Copyright (c) 2026 Daniel
# Copyright (c) 2026 BirdeeHub & Daniel
# Licensed under the MIT license
{
description = "Daniel's NixCats";
@ -11,9 +11,12 @@
};
rixpkgs.url = "github:dwinkler1/rixpkgs/af2dd3f7b4b172077747c0869d4e30702fb71b0e";
r-nvim-nix.url = "github:dwinkler1/r_nvim_nix";
r-nvim-nix.inputs.rnvimsrc.follows = "plugins-r";
r-nvim-nix.inputs.nixpkgs.follows = "rixpkgs";
r-nvim-nix = {
url = "github:dwinkler1/r_nvim_nix/v0.99.4";
inputs = {
nixpkgs.follows = "rixpkgs";
};
};
fran = {
url = "github:dwinkler1/fran";
@ -22,11 +25,6 @@
};
};
"plugins-r" = {
url = "github:R-nvim/R.nvim/v0.99.4";
flake = false;
};
"plugins-cmp-pandoc-references" = {
url = "github:jmbuhr/cmp-pandoc-references";
flake = false;
@ -39,35 +37,42 @@
wrappers,
...
} @ inputs: let
mkWrapperConfig = pkgs: {
cats = {
clickhouse = false;
gitPlugins = true;
julia = false;
lua = true;
markdown = true;
nix = true;
optional = false;
python = false;
r = true;
};
settings = {
lang_packages = {
python = [];
r = [];
julia = [];
devShellCatOrder = [
"always"
"clickhouse"
"external"
"julia"
"lua"
"markdown"
"nix"
"optional"
"python"
"r"
"treesitterParsers"
];
evalWithPkgs = pkgs: extraModules:
wrappers.lib.evalModules {
specialArgs = {
inherit pkgs;
};
modules =
[
module
]
++ extraModules;
};
binName = "vv";
};
wrapperSettings = pkgs: let
cfg = mkWrapperConfig pkgs;
in
wrapper.config.wrap {
inherit pkgs;
inherit (cfg) settings binName;
};
mkDevShellPackages = config:
builtins.concatLists (map (name: config.catPkgs.${name} or []) devShellCatOrder);
mkShellHook = config:
''
echo 'I am a NixShell'
''
+ nixpkgs.lib.optionalString (config.cats.r or false) ''
export R_HOME=$(R RHOME)
export R_LIBS_SITE=$(strings "$(command -v R)" | grep -oP '/nix/store/[^:]+/library' | sort -u | paste -sd: -)
export R_LIBS_USER="$PWD/.r-libs"
mkdir -p "$R_LIBS_USER"
'';
systems = [
"aarch64-darwin"
@ -82,34 +87,44 @@
mkPkgs = system:
import nixpkgs {
inherit system;
config = { allowUnfree = true; };
overlays = [ overlayDefs.dependencyOverlay ];
config = {allowUnfree = true;};
overlays = [
overlayDefs.dependencyOverlay
];
};
module = (import ./modules/neovim.nix) inputs;
wrapper = wrappers.lib.evalModule module;
in {
lib = {
eval = {pkgs, modules ? []}: evalWithPkgs pkgs modules;
mkWrapper = {pkgs, modules ? []}: (evalWithPkgs pkgs modules).config.wrap {inherit pkgs;};
devShellPackages = config: mkDevShellPackages config;
shellHook = config: mkShellHook config;
};
overlays = {
# overlay `vv` wraps the module with default settings only.
# For the fully-configured binary (including mkWrapperConfig overrides),
# use `packages.<system>.default` instead.
# It is evaluated against the final package set so module defaults can
# depend on overlays such as rixpkgs-backed `pkgs.rpkgs`.
default = nixpkgs.lib.composeManyExtensions [
overlayDefs.dependencyOverlay
(final: prev: {
vv = wrapper.config.wrap {pkgs = final;};
vv = (evalWithPkgs final []).config.wrap {pkgs = final;};
})
];
dependencies = overlayDefs.dependencyOverlay;
};
wrapperModules.default = module;
wrapperConfigs.default = wrapper.config;
wrapperConfigs.default = {pkgs, modules ? []}: (self.lib.eval {inherit pkgs modules;}).config;
packages = forAllSystems (
system: let
pkgs = mkPkgs system;
in {
default = wrapperSettings pkgs;
default = self.lib.mkWrapper {
inherit pkgs;
};
}
);
@ -123,80 +138,13 @@
devShells = forAllSystems (
system: let
pkgs = mkPkgs system;
nvimPkg = wrapperSettings pkgs;
pythonPkgs = with pkgs.python3Packages; [
duckdb
polars
];
rPkgs = (with pkgs.rpkgs.rPackages; [
arrow
broom
data_table
janitor
languageserver
styler
]) ++ [ pkgs.nvimcom ];
juliaPkgs = ["DataFramesMeta" "QuackIO"];
pythonPackages = let
python_packages_fn =
if pkgs ? basePythonPackages
then ps: pkgs.basePythonPackages ps ++ pythonPkgs
else _: pythonPkgs;
in
with pkgs; [
(python3.withPackages python_packages_fn)
nodejs
ruff
basedpyright
uv
];
rPackages = let
r_packages = (pkgs.baseRPackages or []) ++ rPkgs;
in
with pkgs; [
(rWrapper.override {packages = r_packages;})
radianWrapper
(quarto.override {extraRPackages = r_packages;})
air-formatter
yaml-language-server
updateR
nvimcom
rnvimserver
];
juliaPackages = let
julia_with_packages = pkgs.julia-bin.withPackages juliaPkgs;
in [julia_with_packages];
markdownPackages = with pkgs; [
python313Packages.pylatexenc
quarto
zk
];
shellPackages =
[nvimPkg]
++ pkgs.lib.optionals wrapper.config.cats.python pythonPackages
++ pkgs.lib.optionals wrapper.config.cats.r rPackages
++ pkgs.lib.optionals wrapper.config.cats.julia juliaPackages
++ pkgs.lib.optionals wrapper.config.cats.markdown markdownPackages;
config = (self.lib.eval {inherit pkgs;}).config;
nvimPkg = config.wrap {inherit pkgs;};
in {
default = pkgs.mkShell {
name = "vShell";
packages = shellPackages;
nativeBuildInputs = pkgs.lib.optionals wrapper.config.cats.optional [ pkgs.devenv ];
shellHook = ''
echo 'I am a NixShell'
export R_HOME=$(R RHOME)
export R_LIBS_SITE=$(strings "$(command -v R)" | grep -oP '/nix/store/[^:]+/library' | sort -u | paste -sd: -)
export R_LIBS_USER="$PWD/.r-libs"
mkdir -p "$R_LIBS_USER"
'';
packages = [nvimPkg] ++ self.lib.devShellPackages config;
shellHook = mkShellHook config;
};
}
);
@ -204,10 +152,31 @@
checks = forAllSystems (
system: let
pkgs = mkPkgs system;
nvimPkg = wrapperSettings pkgs;
defaultConfig = (self.lib.eval {inherit pkgs;}).config;
defaultNvimPkg = defaultConfig.wrap {inherit pkgs;};
defaultShellHook = mkShellHook defaultConfig;
overrideConfig =
(self.lib.eval {
inherit pkgs;
modules = [
{
cats = {
r = false;
python = true;
};
settings.lang_packages.python = nixpkgs.lib.mkForce (with pkgs.python3Packages; [
pandas
]);
catPkgs.nix = nixpkgs.lib.mkForce [
pkgs.alejandra
];
}
];
}).config;
overrideShellHook = mkShellHook overrideConfig;
in {
default = pkgs.runCommand "check-vv" {} ''
BINARY_PATH="${nvimPkg}/bin/vv"
BINARY_PATH="${defaultNvimPkg}/bin/vv"
if [ ! -x "$BINARY_PATH" ]; then
echo "Error: Binary not found or not executable"
@ -223,11 +192,38 @@
cat version_output.txt >> $out
fi
'';
module-eval =
let _ = wrapper.config;
in pkgs.runCommand "check-module-eval" {} ''
module-eval = let
_ = (self.lib.eval {inherit pkgs;}).config;
in
pkgs.runCommand "check-module-eval" {} ''
echo "Module evaluation successful" > $out
'';
downstream-overrides = let
overrideNix = builtins.map (p: p.pname or p.name) overrideConfig.catPkgs.nix;
defaultAssertions = [
(defaultConfig.cats.r or false)
(builtins.match ".*R RHOME.*" defaultShellHook != null)
(builtins.length (self.lib.devShellPackages defaultConfig) > 0)
];
overrideAssertions = [
(!(overrideConfig.cats.r or false))
(builtins.length overrideNix == 1)
((builtins.head overrideNix) == "alejandra")
(builtins.match ".*R RHOME.*" overrideShellHook == null)
];
in
pkgs.runCommand "check-downstream-overrides" {
pass =
if builtins.all (x: x) (defaultAssertions ++ overrideAssertions)
then "1"
else "";
} ''
if [ -z "$pass" ]; then
echo "Downstream override assertions failed" >&2
exit 1
fi
echo "Downstream override assertions passed" > $out
'';
}
);

View file

@ -0,0 +1,111 @@
{
config,
pkgs,
lib,
...
}:
let
maybe = cat: pkgsList:
lib.optionals (config.cats.${cat} or false) pkgsList;
rPackages = (pkgs.baseRPackages or [ ]) ++ config.settings.lang_packages.r;
rWrapperPackages = rPackages;
quartoPkg =
if config.cats.r or false
then pkgs.rpkgs.quarto.override { extraRPackages = rPackages; }
else pkgs.quarto;
in
{
options.catPkgs = lib.mkOption {
type = lib.types.attrsOf (lib.types.listOf lib.types.package);
description = "Per-cat package lists, gated by cat toggles. Single source of truth for runtimeDeps and devShells.";
};
config.catPkgs = {
always = maybe "always" (with pkgs; [ ]);
clickhouse = maybe "clickhouse" (with pkgs; [ clickhouse-lts ]);
external = maybe "external" (with pkgs; [
perl
ruby
shfmt
sqlfluff
tree-sitter
]);
julia = maybe "julia" [
(pkgs.julia-bin.withPackages config.settings.lang_packages.julia)
];
lua = maybe "lua" (with pkgs; [ lua-language-server ]);
markdown = maybe "markdown" (with pkgs; [
python313Packages.pylatexenc
quartoPkg
zk
]);
nix = maybe "nix" (with pkgs; [
alejandra
nix-doc
nixd
]);
optional = maybe "optional" (with pkgs; [
bat
broot
devenv
dust
fd
fzf
gawk
gh
git
hunspell
hunspellDicts.de-at
hunspellDicts.en-us
ispell
jq
just
lazygit
man
ncdu
pigz
poppler
ripgrep
tokei
wget
yq
]);
python = maybe "python" (let
python_packages_fn =
if pkgs ? basePythonPackages
then ps: pkgs.basePythonPackages ps ++ config.settings.lang_packages.python
else _: config.settings.lang_packages.python;
python_with_packages = pkgs.python3.withPackages python_packages_fn;
in
with pkgs; [
python_with_packages
nodejs
ruff
basedpyright
uv
]);
r = maybe "r" [
(pkgs.rpkgs.rWrapper.override { packages = rWrapperPackages; })
pkgs.rpkgs.radianWrapper
quartoPkg
pkgs.air-formatter
pkgs.yaml-language-server
pkgs.rnvimserver
];
# cats without packages get empty lists
general = [ ];
gitPlugins = [ ];
treesitterParsers = [ pkgs.tree-sitter ];
utils = [ ];
};
}

View file

@ -13,6 +13,7 @@
Set a category to `false` to skip its dependency/plugin specs.
Available categories:
- always: always-on packages (not gated by a toggle)
- clickhouse: Clickhouse client and tools
- external: external tools and integrations
- general: core Neovim plugins/features
@ -30,6 +31,7 @@
};
config.cats = {
always = lib.mkDefault true;
clickhouse = lib.mkDefault false;
external = lib.mkDefault true;
general = lib.mkDefault true;

View file

@ -16,7 +16,7 @@
# Lua packages available to neovim (for :lua require())
config.settings.nvim_lua_env = lp:
lib.optionals (config.cats.general or true) [ lp.tiktoken_core ];
lib.optionals (config.cats.general or false) [ lp.tiktoken_core ];
# Binary name for the wrapper
config.binName = lib.mkDefault "vv";
@ -32,4 +32,10 @@
# Enable wrapper handling of spec runtimeDeps (template pattern).
config.settings.autowrapRuntimeDeps = true;
# The wrapper library currently emits runtime PATH additions via `suffixVar`,
# which lets host-level tools in `/usr/local/bin` win inside `nix run`.
# Mirror those additions into `prefixVar` so wrapped Neovim resolves the
# Nix-provided toolchain first while preserving existing wrapper behavior.
config.prefixVar = lib.mkAfter config.suffixVar;
}

View file

@ -7,21 +7,16 @@
# Environment variables set for the wrapper.
# These are available when running neovim.
config.env = lib.mkMerge [
(lib.mkIf (config.cats.python or true) {
(lib.mkIf (config.cats.python or false) {
UV_PYTHON_DOWNLOADS = "never";
UV_PYTHON = pkgs.python.interpreter;
})
(lib.mkIf (config.cats.r or true) {
(lib.mkIf (config.cats.r or false) {
RNVIM_COMPLDIR = "$PWD/.r-compl";
R_LIBS_USER = "${pkgs.nvimcom}/library:$PWD/.Rlibs";
TMPDIR = "$PWD/.r-tmp";
})
];
# Environment variables with defaults (can be overridden by user)
config.envDefault = lib.mkMerge [
(lib.mkIf (config.cats.r or true) {
R_LIBS_USER = "${pkgs.nvimcom}/library:$PWD/.Rlibs";
})
];
config.envDefault = lib.mkMerge [ ];
}

View file

@ -4,6 +4,10 @@
lib,
...
}:
let
rPackages = (pkgs.baseRPackages or [ ]) ++ config.settings.lang_packages.r;
rWrapperPkg = pkgs.rpkgs.rWrapper.override { packages = rPackages ++ [pkgs.nvimcom]; };
in
{
config.hosts = lib.mkMerge [
{
@ -29,7 +33,7 @@
];
};
}
(lib.mkIf (config.cats.julia or true) {
(lib.mkIf (config.cats.julia or false) {
jl = {
nvim-host.enable = true;
nvim-host.package = "${pkgs.julia-bin}/bin/julia";
@ -39,13 +43,13 @@
];
};
})
(lib.mkIf (config.cats.python or true) {
(lib.mkIf (config.cats.python or false) {
python3.nvim-host.enable = true;
})
(lib.mkIf (config.cats.r or true) {
(lib.mkIf (config.cats.r or false) {
r = {
nvim-host.enable = true;
nvim-host.package = "${pkgs.rWrapper}/bin/R";
nvim-host.package = "${rWrapperPkg}/bin/R";
nvim-host.argv0 = "R";
nvim-host.addFlag = [
"--no-save"

View file

@ -1,5 +1,6 @@
{
config,
pkgs,
lib,
...
}:
@ -26,14 +27,28 @@
};
default = { };
description = ''
Language-specific package overrides appended to each language spec's runtimePackages.
Intended for flake.nix overrides via wrapper.config.wrap.
Language-specific package defaults and downstream overrides appended to each
language spec's runtime packages.
'';
};
config.settings.lang_packages = {
python = lib.mkDefault [ ];
r = lib.mkDefault [ ];
julia = lib.mkDefault [ ];
python = lib.mkDefault (with pkgs.python3Packages; [
duckdb
polars
]);
r = lib.mkDefault (
(with pkgs.rpkgs.rPackages; [
arrow
broom
data_table
janitor
styler
])
);
julia = lib.mkDefault [
"DataFramesMeta"
"QuackIO"
];
};
}

View file

@ -1,33 +0,0 @@
{
config,
lib,
...
}:
let
collect_runtime_packages = runtime_deps_type:
config.specCollect
(acc: spec:
let
is_enabled = if spec ? enable then spec.enable else true;
has_runtime_deps = (spec.runtimeDeps or false) == runtime_deps_type;
packages = spec.runtimePackages or [ ];
in
acc ++ lib.optionals (is_enabled && has_runtime_deps) packages
)
[ ];
prefix_packages = collect_runtime_packages "prefix";
to_path_specs = packages: [
{
data = [
"PATH"
":"
"${lib.makeBinPath packages}"
];
}
];
in
{
config.prefixVar = lib.optionals (prefix_packages != [ ]) (to_path_specs prefix_packages);
}

View file

@ -13,133 +13,69 @@
};
};
config.specs.external = {
config.specs.always = lib.mkIf (config.cats.always or false) {
data = lib.mkDefault null;
runtimeDeps = "prefix";
runtimePkgs = config.catPkgs.always;
};
config.specs.external = lib.mkIf (config.cats.external or false) {
data = lib.mkDefault null;
before = ["INIT_MAIN"];
config = ''
vim.o.shell = "${pkgs.zsh}/bin/zsh"
'';
runtimeDeps = "prefix";
runtimePkgs = with pkgs; [
perl
ruby
shfmt
sqlfluff
tree-sitter
];
runtimePkgs = config.catPkgs.external;
};
config.specs.optional = lib.mkIf (config.cats.optional or true) {
config.specs.optional = lib.mkIf (config.cats.optional or false) {
data = lib.mkDefault null;
runtimeDeps = "prefix";
before = ["INIT_MAIN"];
runtimePkgs = with pkgs; [
bat
broot
devenv
dust
fd
fzf
gawk
gh
git
hunspell
hunspellDicts.de-at
hunspellDicts.en-us
ispell
jq
just
lazygit
man
ncdu
pigz
poppler
ripgrep
tokei
wget
yq
zathura
];
runtimePkgs = config.catPkgs.optional;
};
config.specs.markdown = lib.mkIf (config.cats.markdown or true) {
config.specs.markdown = lib.mkIf (config.cats.markdown or false) {
data = lib.mkDefault null;
runtimeDeps = "prefix";
runtimePkgs = with pkgs; [
python313Packages.pylatexenc
quarto
zk
];
runtimePkgs = config.catPkgs.markdown;
};
config.specs.nix = lib.mkIf (config.cats.nix or true) {
config.specs.nix = lib.mkIf (config.cats.nix or false) {
data = lib.mkDefault null;
runtimeDeps = "prefix";
runtimePkgs = with pkgs; [
alejandra
nix-doc
nixd
];
runtimePkgs = config.catPkgs.nix;
};
config.specs.lua = lib.mkIf (config.cats.lua or true) {
config.specs.lua = lib.mkIf (config.cats.lua or false) {
data = lib.mkDefault null;
runtimeDeps = "prefix";
runtimePkgs = with pkgs; [
lua-language-server
];
runtimePkgs = config.catPkgs.lua;
};
config.specs.python = lib.mkIf (config.cats.python or true) {
config.specs.python = lib.mkIf (config.cats.python or false) {
data = lib.mkDefault null;
runtimeDeps = "prefix";
runtimePkgs = let
python_packages_fn =
if pkgs ? basePythonPackages
then ps: pkgs.basePythonPackages ps ++ config.settings.lang_packages.python
else _: config.settings.lang_packages.python;
python_with_packages = pkgs.python3.withPackages python_packages_fn;
in
with pkgs; [
python_with_packages
nodejs
ruff
basedpyright
uv
];
runtimePkgs = config.catPkgs.python;
};
config.specs.r = lib.mkIf (config.cats.r or true) {
config.specs.r = lib.mkIf (config.cats.r or false) {
data = lib.mkDefault null;
runtimeDeps = "prefix";
runtimePkgs = let
r_packages = (pkgs.baseRPackages or []) ++ config.settings.lang_packages.r;
in
with pkgs; [
(rWrapper.override {packages = r_packages;})
radianWrapper
(quarto.override {extraRPackages = r_packages;})
air-formatter
yaml-language-server
updateR
];
runtimePkgs = config.catPkgs.r;
};
config.specs.julia = lib.mkIf (config.cats.julia or true) {
config.specs.julia = lib.mkIf (config.cats.julia or false) {
data = lib.mkDefault null;
runtimeDeps = "prefix";
runtimePkgs = let
julia_with_packages =
pkgs.julia-bin.withPackages config.settings.lang_packages.julia;
in [julia_with_packages];
runtimePkgs = config.catPkgs.julia;
};
config.specs.clickhouse = lib.mkIf (config.cats.clickhouse or true) {
config.specs.clickhouse = lib.mkIf (config.cats.clickhouse or false) {
data = lib.mkDefault null;
runtimeDeps = "prefix";
runtimePkgs = with pkgs; [
clickhouse-lts
];
runtimePkgs = config.catPkgs.clickhouse;
};
config.runtimePkgs = config.specCollect (acc: v: acc ++ (v.runtimePkgs or [])) [];

View file

@ -4,11 +4,11 @@
lib,
...
}: {
config.specs.gitPlugins = lib.mkIf (config.cats.gitPlugins or true) {
config.specs.gitPlugins = lib.mkIf (config.cats.gitPlugins or false) {
data = [];
};
config.specs.r = lib.mkIf (config.cats.r or true) {
config.specs.r = lib.mkIf (config.cats.r or false) {
data = with pkgs.vimPlugins; [
pkgs.r-nvim
quarto-nvim
@ -19,14 +19,14 @@
];
};
config.specs.markdown-lazy = lib.mkIf (config.cats.markdown or true) {
config.specs.markdown-lazy = lib.mkIf (config.cats.markdown or false) {
lazy = true;
data = [
config.nvim-lib.neovimPlugins.cmp-pandoc-references
];
};
config.specs.general = lib.mkIf (config.cats.general or true) {
config.specs.general = lib.mkIf (config.cats.general or false) {
data = with pkgs.vimPlugins; [
lze
lzextras
@ -79,7 +79,7 @@
];
};
config.specs.lua = lib.mkIf (config.cats.lua or true) {
config.specs.lua = lib.mkIf (config.cats.lua or false) {
data = with pkgs.vimPlugins; [
luvit-meta
{
@ -89,7 +89,7 @@
];
};
config.specs.markdown = lib.mkIf (config.cats.markdown or true) {
config.specs.markdown = lib.mkIf (config.cats.markdown or false) {
data = with pkgs.vimPlugins; [
quarto-nvim
render-markdown-nvim
@ -104,7 +104,7 @@
];
};
config.specs.utils = lib.mkIf (config.cats.utils or true) {
config.specs.utils = lib.mkIf (config.cats.utils or false) {
data = with pkgs.vimPlugins; [
blink-cmp
nvim-lspconfig
@ -119,7 +119,7 @@
];
};
config.specs.treesitterParsers = lib.mkIf (config.cats.treesitterParsers or true) {
config.specs.treesitterParsers = lib.mkIf (config.cats.treesitterParsers or false) {
data = with pkgs.vimPlugins.nvim-treesitter-parsers; [
bash
c
@ -158,7 +158,7 @@
];
};
config.specs.utils-lazy = lib.mkIf (config.cats.utils or true) {
config.specs.utils-lazy = lib.mkIf (config.cats.utils or false) {
lazy = true;
data = with pkgs.vimPlugins; [
blink-compat
@ -175,7 +175,7 @@
];
};
config.specs.gitPlugins-lazy = lib.mkIf (config.cats.gitPlugins or true) {
config.specs.gitPlugins-lazy = lib.mkIf (config.cats.gitPlugins or false) {
lazy = true;
data = [];
};

View file

@ -9,6 +9,7 @@ inputs:
{
imports = [
wlib.wrapperModules.neovim
./module/settings/cat-packages.nix
./module/specs/deps.nix
./module/specs/plugins.nix
./module/settings/core.nix
@ -16,7 +17,6 @@ inputs:
./module/settings/env.nix
./module/settings/hosts.nix
./module/settings/lang-packages.nix
./module/settings/runtime-path.nix
];
options.nvim-lib.neovimPlugins = lib.mkOption {

View file

@ -11,5 +11,4 @@ in {
baseRPackages = [ ];
rWrapper = rpkgs.rWrapper.override {packages = [ ];};
quarto = rpkgs.quarto.override {extraRPackages = [ ];};
updateR = import ../scripts/updater.nix {pkgs = final;};
}

View file

@ -37,7 +37,7 @@ _G.Config.leader_group_clues = {
{ mode = 'x', keys = '<Leader>l', desc = '+LSP' },
{ mode = 'x', keys = '<Leader>r', desc = '+R' },
{ mode = 'n', keys = '<Leader>z', desc = '+ZK' },
{ mode = 'n', keys = '<Leader>zr', desc = '+Reviews' },
{ mode = 'n', keys = '<Leader>zr', desc = '+Reviews' },
{ mode = 'x', keys = '<leader>a', desc = '+AI' },
}
@ -144,7 +144,7 @@ nmap_leader('gc', '<Cmd>Git commit<CR>', 'Commit')
nmap_leader('gC', '<Cmd>Git commit --amend<CR>', 'Commit amend')
nmap_leader('gd', '<Cmd>Git diff<CR>', 'Diff')
nmap_leader('gD', '<Cmd>Git diff -- %<CR>', 'Diff buffer')
nmap_leader('gg', '<Cmd>lua require("neogit").open()<CR>', 'Git tab')
nmap_leader("gg", "<cmd>Neogit<cr>", "Open Neogit UI")
nmap_leader('gl', '<Cmd>' .. git_log_cmd .. '<CR>', 'Log')
nmap_leader('gL', '<Cmd>' .. git_log_cmd .. ' --follow -- %<CR>', 'Log buffer')
nmap_leader('go', '<Cmd>lua MiniDiff.toggle_overlay()<CR>', 'Toggle overlay')

View file

@ -61,7 +61,7 @@ now(function()
min_editor_width = 80,
rconsole_height = 20,
nvimpager = "split_h",
pdfviewer = "zathura",
pdfviewer = "",
})
end
end)

View file

@ -1,14 +0,0 @@
{pkgs}:
pkgs.writeShellApplication {
name = "updateR";
# Tools your script needs at runtime
runtimeInputs = [
pkgs.wget
pkgs.gnused
pkgs.coreutils
];
# Keep script in separate file, but embed contents
text = builtins.readFile ./updater.sh;
}

View file

@ -1,22 +0,0 @@
echo "📡 Fetching latest R version from rstats-on-nix..."
RVER=$( wget -qO- 'https://raw.githubusercontent.com/ropensci/rix/refs/heads/main/inst/extdata/available_df.csv' | tail -n 1 | head -n 1 | cut -d',' -f4 | tr -d '"' )
# Validate RVER matches YYYY-MM-DD format
if [[ ! "$RVER" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then
echo "❌ Error: Failed to fetch valid R version date. Got: '$RVER'"
exit 1
fi
echo "✅ R date is $RVER"
# Create backup of flake.nix before modifying
cp flake.nix flake.nix.backup
# Update rixpkgs date in flake.nix
if sed -i "s|rixpkgs.url = \"github:rstats-on-nix/nixpkgs/[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}\";|rixpkgs.url = \"github:rstats-on-nix/nixpkgs/$RVER\";|" flake.nix; then
echo "✅ Updated rixpkgs date in flake.nix"
rm flake.nix.backup
else
echo "⚠️ Warning: Failed to update flake.nix, restoring backup"
mv flake.nix.backup flake.nix
fi