Compare commits

..

No commits in common. "main" and "copilot/fix-quarto-functionality-with-r" have entirely different histories.

28 changed files with 592 additions and 867 deletions

View file

@ -1,5 +0,0 @@
if (Sys.getenv("RNVIM_TMPDIR") == "") {
options(defaultPackages = c("utils", "grDevices", "graphics", "stats", "methods"))
} else {
options(defaultPackages = c("utils", "grDevices", "graphics", "stats", "methods", "nvimcom"))
}

3
.gitignore vendored
View file

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

341
README.md
View file

@ -1,341 +0,0 @@
# 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.

61
flake.lock generated
View file

@ -22,11 +22,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1778869304, "lastModified": 1776169885,
"narHash": "sha256-30sZNZoA1cqF5JNO9fVX+wgiQYjB7HJqqJ4ztCDeBZE=", "narHash": "sha256-l/iNYDZ4bGOAFQY2q8y5OAfBBtrDAaPuRQqWaFHVRXM=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "d233902339c02a9c334e7e593de68855ad26c4cb", "rev": "4bd9165a9165d7b5e33ae57f3eecbcb28fb231c9",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -52,35 +52,29 @@
"type": "github" "type": "github"
} }
}, },
"r-nvim-nix": { "plugins-r": {
"inputs": { "flake": false,
"nixpkgs": [
"rixpkgs"
],
"rnvimsrc": "rnvimsrc"
},
"locked": { "locked": {
"lastModified": 1781392459, "lastModified": 1776340770,
"narHash": "sha256-9CMG+trBd9AX7cWiGPrMr0eJwuZaql+pj2WVGyT417I=", "narHash": "sha256-o/8UZIc/Bq9dWTjA+MpSR5uMUpE7KHTErk+TwWID8Ww=",
"owner": "dwinkler1", "owner": "R-nvim",
"repo": "r_nvim_nix", "repo": "R.nvim",
"rev": "03d7872d7702db37ede41f3c6e4d4ce4c129e862", "rev": "b9cfffeb9b4e484aa9e13f01c0eb80230aada455",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "dwinkler1", "owner": "R-nvim",
"ref": "v0.99.5", "repo": "R.nvim",
"repo": "r_nvim_nix",
"type": "github" "type": "github"
} }
}, },
"rixpkgs": { "rixpkgs": {
"locked": { "locked": {
"lastModified": 1782576256, "lastModified": 1771303851,
"narHash": "sha256-KOvpL9DJJmShb64mX9QTjhxHaxE8MizQIqNUAniuJ2E=", "narHash": "sha256-tgveHozOJ2D/mi3LxVy/FcmLFDlM5XKZxsNB2XpvzaM=",
"owner": "dwinkler1", "owner": "dwinkler1",
"repo": "rixpkgs", "repo": "rixpkgs",
"rev": "815afc01bc0cc9a2eba80906645bd08f976a4401", "rev": "af2dd3f7b4b172077747c0869d4e30702fb71b0e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -90,29 +84,12 @@
"type": "github" "type": "github"
} }
}, },
"rnvimsrc": {
"flake": false,
"locked": {
"lastModified": 1780759435,
"narHash": "sha256-VxgKMOP1hseQre3cas2dmMXZu4PVyl05INla2OdHTU4=",
"owner": "R-nvim",
"repo": "R.nvim",
"rev": "6ca306191531c3e3d501ee1609c84a5d29059386",
"type": "github"
},
"original": {
"owner": "R-nvim",
"ref": "v0.99.5",
"repo": "R.nvim",
"type": "github"
}
},
"root": { "root": {
"inputs": { "inputs": {
"fran": "fran", "fran": "fran",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"plugins-cmp-pandoc-references": "plugins-cmp-pandoc-references", "plugins-cmp-pandoc-references": "plugins-cmp-pandoc-references",
"r-nvim-nix": "r-nvim-nix", "plugins-r": "plugins-r",
"rixpkgs": "rixpkgs", "rixpkgs": "rixpkgs",
"wrappers": "wrappers" "wrappers": "wrappers"
} }
@ -124,11 +101,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1779297405, "lastModified": 1776375800,
"narHash": "sha256-VFoBwH7ZjVxCnvZTb5ODRXt70sLtWMxstive0N+RS50=", "narHash": "sha256-/SSAR77Brr9fbapsh1cb2K47JXCbvwS1GjM4yyDxle8=",
"owner": "BirdeeHub", "owner": "BirdeeHub",
"repo": "nix-wrapper-modules", "repo": "nix-wrapper-modules",
"rev": "e7ed7a1205945befdf2e0d73ba7df91d935e5af1", "rev": "f11469ca69068bac13d9e163b2bd268cc06dff57",
"type": "github" "type": "github"
}, },
"original": { "original": {

213
flake.nix
View file

@ -1,23 +1,17 @@
# Copyright (c) 2026 BirdeeHub & Daniel # Copyright (c) 2026 BirdeeHub
# Licensed under the MIT license # Licensed under the MIT license
{ {
description = "Daniel's NixCats"; description = "Daniel's NixCats";
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
#nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
wrappers = { wrappers = {
url = "github:BirdeeHub/nix-wrapper-modules"; url = "github:BirdeeHub/nix-wrapper-modules";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
rixpkgs.url = "github:dwinkler1/rixpkgs/nixpkgs"; rixpkgs.url = "github:dwinkler1/rixpkgs/nixpkgs";
r-nvim-nix = {
url = "github:dwinkler1/r_nvim_nix/v0.99.5";
inputs = {
nixpkgs.follows = "rixpkgs";
};
};
fran = { fran = {
url = "github:dwinkler1/fran"; url = "github:dwinkler1/fran";
inputs = { inputs = {
@ -25,6 +19,11 @@
}; };
}; };
"plugins-r" = {
url = "github:R-nvim/R.nvim";
flake = false;
};
"plugins-cmp-pandoc-references" = { "plugins-cmp-pandoc-references" = {
url = "github:jmbuhr/cmp-pandoc-references"; url = "github:jmbuhr/cmp-pandoc-references";
flake = false; flake = false;
@ -37,42 +36,46 @@
wrappers, wrappers,
... ...
} @ inputs: let } @ inputs: let
devShellCatOrder = [ wrapperSettings = pkgs: let
"always" def = pkgs.lib.mkDefault;
"clickhouse" in
"external" wrapper.config.wrap {
"julia"
"lua"
"markdown"
"nix"
"optional"
"python"
"r"
"treesitterParsers"
];
evalWithPkgs = pkgs: extraModules:
wrappers.lib.evalModules {
specialArgs = {
inherit pkgs; inherit pkgs;
cats = {
clickhouse = def false;
gitPlugins = def true;
julia = def false;
lua = def true;
markdown = def false;
nix = def true;
optional = def false;
python = def false;
r = def false;
}; };
modules =
[ settings = {
module lang_packages = {
] python = with pkgs.python3Packages; [
++ extraModules; duckdb
polars
];
r = with pkgs.rpkgs.rPackages; [
arrow
broom
data_table
janitor
styler
];
julia = ["DataFramesMeta" "QuackIO"];
};
colorscheme = def "cyberdream";
background = def "dark";
wrapRc = def true;
};
binName = def "vv";
}; };
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 = [ systems = [
"aarch64-darwin" "aarch64-darwin"
@ -82,49 +85,54 @@
forAllSystems = nixpkgs.lib.genAttrs systems; forAllSystems = nixpkgs.lib.genAttrs systems;
extra_pkg_config = {
# allowUnfree = true;
};
overlayDefs = import ./overlays inputs; overlayDefs = import ./overlays inputs;
dependencyOverlays = overlayDefs.dependencyOverlays;
dependencyOverlay = overlayDefs.dependencyOverlay;
mkPkgs = system: mkPkgs = system:
import nixpkgs { import nixpkgs {
inherit system; inherit system;
config = {allowUnfree = true;}; config = extra_pkg_config;
overlays = [ overlays = [dependencyOverlay];
overlayDefs.dependencyOverlay
];
}; };
module = (import ./modules/neovim.nix) inputs; module = nixpkgs.lib.modules.importApply ./modules/neovim.nix inputs;
wrapper = wrappers.lib.evalModule module;
in { 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 = { overlays = {
# overlay `vv` wraps the module with default settings only.
# 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 [ default = nixpkgs.lib.composeManyExtensions [
overlayDefs.dependencyOverlay dependencyOverlay
(final: prev: { (final: prev: {
vv = (evalWithPkgs final []).config.wrap {pkgs = final;}; vv = wrapper.config.wrap {pkgs = final;};
}) })
]; ];
dependencies = overlayDefs.dependencyOverlay; dependencies = dependencyOverlay;
vv = self.overlays.default;
}; };
wrapperModules.default = module; wrapperModules = {
wrapperConfigs.default = {pkgs, modules ? []}: (self.lib.eval {inherit pkgs modules;}).config; default = module;
neovim = self.wrapperModules.default;
};
wrappers = {
default = wrapper.config;
neovim = self.wrappers.default;
};
packages = forAllSystems ( packages = forAllSystems (
system: let system: let
pkgs = mkPkgs system; pkgs = mkPkgs system;
nvimPkg = wrapperSettings pkgs;
in { in {
default = self.lib.mkWrapper { default = nvimPkg;
inherit pkgs; vv = nvimPkg;
};
} }
); );
@ -138,13 +146,14 @@
devShells = forAllSystems ( devShells = forAllSystems (
system: let system: let
pkgs = mkPkgs system; pkgs = mkPkgs system;
config = (self.lib.eval {inherit pkgs;}).config; nvimPkg = wrapperSettings pkgs;
nvimPkg = config.wrap {inherit pkgs;};
in { in {
default = pkgs.mkShell { default = pkgs.mkShell {
name = "vShell"; name = "vShell";
packages = [nvimPkg] ++ self.lib.devShellPackages config; packages = [nvimPkg];
shellHook = mkShellHook config; nativeBuildInputs = with pkgs; [] ++ (pkgs.lib.optionals self.wrappers.default.cats.optional [devenv]);
inputsFrom = [];
shellHook = "";
}; };
} }
); );
@ -152,34 +161,20 @@
checks = forAllSystems ( checks = forAllSystems (
system: let system: let
pkgs = mkPkgs system; pkgs = mkPkgs system;
defaultConfig = (self.lib.eval {inherit pkgs;}).config; nvimPkg = wrapperSettings pkgs;
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 { in {
default = pkgs.runCommand "check-vv" {} '' default = nvimPkg;
BINARY_PATH="${defaultNvimPkg}/bin/vv" module-eval = let
_ = wrapper.config;
in
pkgs.runCommand "check-module-eval" {} ''
echo "Module evaluation successful" > $out
'';
package-build = pkgs.runCommand "check-vv" {} ''
BINARY_PATH="${nvimPkg}/bin/vv"
if [ ! -x "$BINARY_PATH" ]; then if [ ! -x "$BINARY_PATH" ]; then
echo "Error: Binary not found or not executable" echo "Error: Binary n not found or not executable"
exit 1 exit 1
fi fi
@ -192,38 +187,6 @@
cat version_output.txt >> $out cat version_output.txt >> $out
fi fi
''; '';
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

@ -1,7 +1,5 @@
-- Add the key mappings only for Markdown files in a zk notebook. -- Add the key mappings only for Markdown files in a zk notebook.
local nix = require("config.nix") if require("zk.util").notebook_root(vim.fn.expand('%:p')) ~= nil then
if nix.get_cat("markdown", false) then
if require("zk.util").notebook_root(vim.fn.expand('%:p')) ~= nil then
local map = vim.keymap.set local map = vim.keymap.set
-- Open the link under the caret. -- Open the link under the caret.
map("n", "<CR>", "<Cmd>lua vim.lsp.buf.definition()<CR>", { noremap = true, silent = false, buffer = true }) map("n", "<CR>", "<Cmd>lua vim.lsp.buf.definition()<CR>", { noremap = true, silent = false, buffer = true })
@ -31,5 +29,4 @@ if nix.get_cat("markdown", false) then
map("v", "<leader>za", ":'<,'>lua vim.lsp.buf.range_code_action()<CR>", map("v", "<leader>za", ":'<,'>lua vim.lsp.buf.range_code_action()<CR>",
{ noremap = true, silent = false, buffer = true, desc = "Code actions" }) { noremap = true, silent = false, buffer = true, desc = "Code actions" })
end
end end

View file

@ -22,11 +22,9 @@ local COMMENT_TYPES = {
} }
function M.get_current_node() function M.get_current_node()
local ts_utils = require('nvim-treesitter.ts_utils')
local cur_win = vim.api.nvim_get_current_win() local cur_win = vim.api.nvim_get_current_win()
return vim.treesitter.get_node({ return ts_utils.get_node_at_cursor(cur_win, true)
winid = cur_win,
ignore_injections = true,
})
end end
function M.detect_global_node() function M.detect_global_node()
@ -52,6 +50,7 @@ function M.detect_global_node()
end end
function M.move_to_next_non_empty_line() function M.move_to_next_non_empty_line()
local ts_utils = require('nvim-treesitter.ts_utils')
-- Search for the next non-empty line -- Search for the next non-empty line
local line_num = vim.fn.search("[^;\\s]", "W") local line_num = vim.fn.search("[^;\\s]", "W")
@ -87,27 +86,25 @@ function M.move_to_next_non_empty_line()
line_content = vim.api.nvim_buf_get_lines(0, line_num - 1, line_num, false)[1] line_content = vim.api.nvim_buf_get_lines(0, line_num - 1, line_num, false)[1]
first_non_ws = line_content:find("%S") or 1 first_non_ws = line_content:find("%S") or 1
vim.api.nvim_win_set_cursor(0, { line_num, first_non_ws - 1 }) vim.api.nvim_win_set_cursor(0, { line_num, first_non_ws - 1 })
node = vim.treesitter.get_node() node = ts_utils.get_node_at_cursor()
end end
return true return true
end end
function M.vselect_node(node) function M.vselect_node(node)
local ts_utils = require('nvim-treesitter.ts_utils')
if not node then if not node then
return false return false
end end
local start_row, _, end_row, _ = node:range() local cur_buf = vim.api.nvim_get_current_buf()
ts_utils.update_selection(cur_buf, node, "V")
vim.api.nvim_win_set_cursor(0, { start_row + 1, 0 })
vim.cmd("normal! V")
vim.api.nvim_win_set_cursor(0, { end_row + 1, 0 })
return true return true
end end
function M.select_until_global(global_nodes) function M.select_until_global(global_nodes)
local ts_utils = require('nvim-treesitter.ts_utils')
local root_node = M.detect_global_node() local root_node = M.detect_global_node()
if not root_node and global_nodes then if not root_node and global_nodes then
root_node = global_nodes[1] root_node = global_nodes[1]
@ -116,7 +113,7 @@ function M.select_until_global(global_nodes)
-- Use empty table if no global nodes provided -- Use empty table if no global nodes provided
global_nodes = global_nodes or {} global_nodes = global_nodes or {}
local node = vim.treesitter.get_node() local node = ts_utils.get_node_at_cursor()
if not node then if not node then
-- print("No syntax node found at cursor position") -- print("No syntax node found at cursor position")
return nil return nil
@ -170,6 +167,7 @@ function M.slime_send_region()
end end
function M.send_repl(global_nodes) function M.send_repl(global_nodes)
local ts_utils = require('nvim-treesitter.ts_utils')
local cur_node = M.get_current_node() local cur_node = M.get_current_node()
if not cur_node then if not cur_node then
@ -191,9 +189,7 @@ function M.send_repl(global_nodes)
M.slime_send_region() M.slime_send_region()
-- Move cursor and continue -- Move cursor and continue
local _, _, er, ec = sel_node:range() ts_utils.goto_node(sel_node, true)
vim.api.nvim_win_set_cursor(0, { er + 1, ec })
M.move_to_next_non_empty_line() M.move_to_next_non_empty_line()
end end

View file

@ -1,111 +0,0 @@
{
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,8 +13,8 @@
Set a category to `false` to skip its dependency/plugin specs. Set a category to `false` to skip its dependency/plugin specs.
Available categories: Available categories:
- always: always-on packages (not gated by a toggle)
- clickhouse: Clickhouse client and tools - clickhouse: Clickhouse client and tools
- customPlugins: local plugin specs
- external: external tools and integrations - external: external tools and integrations
- general: core Neovim plugins/features - general: core Neovim plugins/features
- gitPlugins: git-related plugins - gitPlugins: git-related plugins
@ -25,24 +25,26 @@
- optional: optional tools and utilities - optional: optional tools and utilities
- python: Python tooling and plugins - python: Python tooling and plugins
- r: R tooling and plugins - r: R tooling and plugins
- test: test-only tooling (disabled by default)
- treesitterParsers: Treesitter parsers - treesitterParsers: Treesitter parsers
- utils: general utilities - utils: general utilities
''; '';
}; };
config.cats = { config.cats = {
always = lib.mkDefault true;
clickhouse = lib.mkDefault false; clickhouse = lib.mkDefault false;
customPlugins = lib.mkDefault true;
external = lib.mkDefault true; external = lib.mkDefault true;
general = lib.mkDefault true; general = lib.mkDefault true;
gitPlugins = lib.mkDefault true; gitPlugins = lib.mkDefault true;
julia = lib.mkDefault false; julia = lib.mkDefault false;
lua = lib.mkDefault true; lua = lib.mkDefault true;
markdown = lib.mkDefault true; markdown = lib.mkDefault false;
nix = lib.mkDefault true; nix = lib.mkDefault true;
optional = lib.mkDefault false; optional = lib.mkDefault false;
python = lib.mkDefault false; python = lib.mkDefault false;
r = lib.mkDefault true; r = lib.mkDefault false;
test = lib.mkDefault false;
treesitterParsers = lib.mkDefault true; treesitterParsers = lib.mkDefault true;
utils = lib.mkDefault true; utils = lib.mkDefault true;
}; };

View file

@ -25,17 +25,11 @@
config.settings.block_normal_config = true; config.settings.block_normal_config = true;
# Don't symlink the config (we wrap it instead) # Don't symlink the config (we wrap it instead)
config.settings.dont_link = lib.mkDefault false; config.settings.dont_link = false;
# Create additional aliases for the binary # Create additional aliases for the binary
config.settings.aliases = lib.mkDefault [ "vvim" ]; config.settings.aliases = [ "vvim" ];
# Enable wrapper handling of spec runtimeDeps (template pattern). # Enable wrapper handling of spec runtimeDeps (template pattern).
config.settings.autowrapRuntimeDeps = true; 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

@ -11,12 +11,12 @@
UV_PYTHON_DOWNLOADS = "never"; UV_PYTHON_DOWNLOADS = "never";
UV_PYTHON = pkgs.python.interpreter; UV_PYTHON = pkgs.python.interpreter;
}) })
(lib.mkIf (config.cats.r or false) {
RNVIM_COMPLDIR = "$PWD/.r-compl";
TMPDIR = "$PWD/.r-tmp";
})
]; ];
# Environment variables with defaults (can be overridden by user) # Environment variables with defaults (can be overridden by user)
config.envDefault = lib.mkMerge [ ]; config.envDefault = lib.mkMerge [
(lib.mkIf (config.cats.r or false) {
R_LIBS_USER = "./.Rlibs";
})
];
} }

View file

@ -4,10 +4,6 @@
lib, 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 [ config.hosts = lib.mkMerge [
{ {
@ -19,7 +15,7 @@ in
nvim-host.enable = true; nvim-host.enable = true;
nvim-host.package = "${pkgs.neovide}/bin/neovide"; nvim-host.package = "${pkgs.neovide}/bin/neovide";
nvim-host.argv0 = "neovide"; nvim-host.argv0 = "neovide";
nvim-host.flags."--neovim-bin" = "${builtins.placeholder "out"}/bin/${config.binName}"; nvim-host.flags."--neovim-bin" = "${placeholder "out"}/bin/${config.binName}";
}; };
m = { m = {
@ -33,7 +29,7 @@ in
]; ];
}; };
} }
(lib.mkIf (config.cats.julia or false) { (lib.mkIf (config.cats.julia or true) {
jl = { jl = {
nvim-host.enable = true; nvim-host.enable = true;
nvim-host.package = "${pkgs.julia-bin}/bin/julia"; nvim-host.package = "${pkgs.julia-bin}/bin/julia";
@ -43,13 +39,13 @@ in
]; ];
}; };
}) })
(lib.mkIf (config.cats.python or false) { (lib.mkIf (config.cats.python or true) {
python3.nvim-host.enable = true; python3.nvim-host.enable = true;
}) })
(lib.mkIf (config.cats.r or false) { (lib.mkIf (config.cats.r or true) {
r = { r = {
nvim-host.enable = true; nvim-host.enable = true;
nvim-host.package = "${rWrapperPkg}/bin/R"; nvim-host.package = "${pkgs.rWrapper}/bin/R";
nvim-host.argv0 = "R"; nvim-host.argv0 = "R";
nvim-host.addFlag = [ nvim-host.addFlag = [
"--no-save" "--no-save"

View file

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

View file

@ -0,0 +1,35 @@
{
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.extraPackages or [ ];
in
acc ++ lib.optionals (is_enabled && has_runtime_deps) packages
)
[ ];
prefix_packages = collect_runtime_packages "prefix";
suffix_packages = collect_runtime_packages "suffix";
to_path_specs = packages: [
{
data = [
"PATH"
":"
"${lib.makeBinPath packages}"
];
}
];
in
{
config.prefixVar = lib.optionals (prefix_packages != [ ]) (to_path_specs prefix_packages);
config.suffixVar = lib.optionals (suffix_packages != [ ]) (to_path_specs suffix_packages);
}

View file

@ -0,0 +1,51 @@
{ config, lib, ... }:
{
# This module implements category-based enabling of specs.
# It runs early (order 200) so other specMaps can see the enable flags.
#
# How it works:
# 1. For each spec, extract its name (removing -lazy suffix if present)
# 2. Check if there's a corresponding cats.<name> toggle
# 3. Set spec.value.enable based on the cats toggle (default: true)
# 4. This allows specs to be conditionally included based on config.cats settings
#
# Example: If config.cats.python = false, then specs.python.enable = false
config.specMaps = lib.mkOrder 200 [
{
name = "CATS_ENABLE";
data =
list:
map (
v:
if v.type == "spec" || v.type == "parent" then
let
# Extract spec name, handling lazy specs (remove -lazy suffix)
specName =
if v.name == null then
null
else if lib.hasSuffix "-lazy" v.name then
lib.removeSuffix "-lazy" v.name
else
v.name;
# Check if this spec has a corresponding cat toggle
catEnabled =
if specName != null && builtins.hasAttr specName config.cats then
config.cats.${specName}
else
true; # Default to enabled if no cat toggle exists
in
v
// {
value = v.value // {
# Use explicit enable if set, otherwise use cat toggle
enable = if v.value ? enable then v.value.enable else catEnabled;
};
}
else
v
) list;
}
];
}

View file

@ -5,78 +5,184 @@
wlib, wlib,
... ...
}: { }: {
# ============================================================================
# SPEC MODULE DEFAULTS
# ============================================================================
# Define default options available to all specs
config.specMods = {parentSpec ? null, ...}: { config.specMods = {parentSpec ? null, ...}: {
options.runtimePkgs = lib.mkOption { options.extraPackages = lib.mkOption {
type = lib.types.listOf wlib.types.stringable; type = lib.types.listOf wlib.types.stringable;
default = []; default = [];
description = "a runtimePkgs spec field to put packages to suffix to the PATH"; description = "a extraPackages spec field to put packages to suffix to the PATH";
}; };
}; };
config.specs.always = lib.mkIf (config.cats.always or false) { # ============================================================================
data = lib.mkDefault null; # EXTERNAL TOOLS SPEC
runtimeDeps = "prefix"; # ============================================================================
runtimePkgs = config.catPkgs.always; # Core system tools and utilities
};
config.specs.external = lib.mkIf (config.cats.external or false) { config.specs.external = {
data = lib.mkDefault null; data = lib.mkDefault null;
before = ["INIT_MAIN"]; before = ["INIT_MAIN"];
config = '' config = ''
vim.o.shell = "${pkgs.zsh}/bin/zsh" vim.o.shell = "${pkgs.zsh}/bin/zsh"
''; '';
runtimeDeps = "prefix"; runtimeDeps = "prefix";
runtimePkgs = config.catPkgs.external; extraPackages = with pkgs; [
perl
ruby
shfmt
sqlfluff
tree-sitter
];
}; };
config.specs.optional = lib.mkIf (config.cats.optional or false) { # ============================================================================
# OPTIONAL TOOLS SPEC
# ============================================================================
config.specs.optional = lib.mkIf (config.cats.optional or true) {
data = lib.mkDefault null; data = lib.mkDefault null;
runtimeDeps = "prefix"; runtimeDeps = "prefix";
before = ["INIT_MAIN"]; before = ["INIT_MAIN"];
runtimePkgs = config.catPkgs.optional; extraPackages = 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
];
}; };
config.specs.markdown = lib.mkIf (config.cats.markdown or false) { # ============================================================================
# MARKDOWN SPEC
# ============================================================================
config.specs.markdown = lib.mkIf (config.cats.markdown or true) {
data = lib.mkDefault null; data = lib.mkDefault null;
runtimeDeps = "prefix"; runtimeDeps = "prefix";
runtimePkgs = config.catPkgs.markdown; extraPackages = with pkgs; [
python313Packages.pylatexenc
quarto
zk
];
}; };
config.specs.nix = lib.mkIf (config.cats.nix or false) { # ============================================================================
# NIX SPEC
# ============================================================================
config.specs.nix = lib.mkIf (config.cats.nix or true) {
data = lib.mkDefault null; data = lib.mkDefault null;
runtimeDeps = "prefix"; runtimeDeps = "prefix";
runtimePkgs = config.catPkgs.nix; extraPackages = with pkgs; [
alejandra
nix-doc
nixd
];
}; };
config.specs.lua = lib.mkIf (config.cats.lua or false) { # ============================================================================
# LUA SPEC
# ============================================================================
config.specs.lua = lib.mkIf (config.cats.lua or true) {
data = lib.mkDefault null; data = lib.mkDefault null;
runtimeDeps = "prefix"; runtimeDeps = "prefix";
runtimePkgs = config.catPkgs.lua; extraPackages = with pkgs; [
lua-language-server
];
}; };
config.specs.python = lib.mkIf (config.cats.python or false) { # ============================================================================
# PYTHON SPEC
# ============================================================================
config.specs.python = lib.mkIf (config.cats.python or true) {
data = lib.mkDefault null; data = lib.mkDefault null;
runtimeDeps = "prefix"; runtimeDeps = "prefix";
runtimePkgs = config.catPkgs.python; extraPackages = 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
];
}; };
config.specs.r = lib.mkIf (config.cats.r or false) { # ============================================================================
# R SPEC
# ============================================================================
config.specs.r = lib.mkIf (config.cats.r or true) {
data = lib.mkDefault null; data = lib.mkDefault null;
runtimeDeps = "prefix"; runtimeDeps = "prefix";
runtimePkgs = config.catPkgs.r; extraPackages = 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
];
}; };
config.specs.julia = lib.mkIf (config.cats.julia or false) { # ============================================================================
# JULIA SPEC
# ============================================================================
config.specs.julia = lib.mkIf (config.cats.julia or true) {
data = lib.mkDefault null; data = lib.mkDefault null;
runtimeDeps = "prefix"; runtimeDeps = "prefix";
runtimePkgs = config.catPkgs.julia; extraPackages = let
julia_with_packages =
pkgs.julia-bin.withPackages config.settings.lang_packages.julia;
in [julia_with_packages];
}; };
config.specs.clickhouse = lib.mkIf (config.cats.clickhouse or false) { # ============================================================================
# CLICKHOUSE SPEC
# ============================================================================
config.specs.clickhouse = lib.mkIf (config.cats.clickhouse or true) {
data = lib.mkDefault null; data = lib.mkDefault null;
runtimeDeps = "prefix"; runtimeDeps = "prefix";
runtimePkgs = config.catPkgs.clickhouse; extraPackages = with pkgs; [
clickhouse-lts
];
}; };
config.runtimePkgs = config.specCollect (acc: v: acc ++ (v.runtimePkgs or [])) []; config.extraPackages = config.specCollect (acc: v: acc ++ (v.extraPackages or [])) [];
} }

View file

@ -3,14 +3,15 @@
pkgs, pkgs,
lib, lib,
... ...
}: { }:
config.specs.gitPlugins = lib.mkIf (config.cats.gitPlugins or false) { {
data = []; config.specs.gitPlugins = {
data = [ ];
}; };
config.specs.r = lib.mkIf (config.cats.r or false) { config.specs.r = {
data = with pkgs.vimPlugins; [ data = with pkgs.vimPlugins; [
pkgs.r-nvim config.nvim-lib.neovimPlugins.r
quarto-nvim quarto-nvim
{ {
data = otter-nvim; data = otter-nvim;
@ -19,14 +20,14 @@
]; ];
}; };
config.specs.markdown-lazy = lib.mkIf (config.cats.markdown or false) { config.specs.markdown-lazy = {
lazy = true; lazy = true;
data = [ data = [
config.nvim-lib.neovimPlugins.cmp-pandoc-references config.nvim-lib.neovimPlugins.cmp-pandoc-references
]; ];
}; };
config.specs.general = lib.mkIf (config.cats.general or false) { config.specs.general = {
data = with pkgs.vimPlugins; [ data = with pkgs.vimPlugins; [
lze lze
lzextras lzextras
@ -79,7 +80,7 @@
]; ];
}; };
config.specs.lua = lib.mkIf (config.cats.lua or false) { config.specs.lua = {
data = with pkgs.vimPlugins; [ data = with pkgs.vimPlugins; [
luvit-meta luvit-meta
{ {
@ -89,7 +90,7 @@
]; ];
}; };
config.specs.markdown = lib.mkIf (config.cats.markdown or false) { config.specs.markdown = {
data = with pkgs.vimPlugins; [ data = with pkgs.vimPlugins; [
quarto-nvim quarto-nvim
render-markdown-nvim render-markdown-nvim
@ -104,22 +105,20 @@
]; ];
}; };
config.specs.utils = lib.mkIf (config.cats.utils or false) { config.specs.utils = {
data = with pkgs.vimPlugins; [ data = with pkgs.vimPlugins; [
blink-cmp blink-cmp
nvim-lspconfig nvim-lspconfig
nvim-treesitter-context nvim-treesitter-context
nvim-treesitter-textobjects nvim-treesitter-textobjects
{ {
data = pkgs.codecompanion-nvim.overrideAttrs (old: { data = pkgs.codecompanion-nvim;
doCheck = false;
});
pname = "codecompanion"; pname = "codecompanion";
} }
]; ];
}; };
config.specs.treesitterParsers = lib.mkIf (config.cats.treesitterParsers or false) { config.specs.treesitterParsers = {
data = with pkgs.vimPlugins.nvim-treesitter-parsers; [ data = with pkgs.vimPlugins.nvim-treesitter-parsers; [
bash bash
c c
@ -158,7 +157,7 @@
]; ];
}; };
config.specs.utils-lazy = lib.mkIf (config.cats.utils or false) { config.specs.utils-lazy = {
lazy = true; lazy = true;
data = with pkgs.vimPlugins; [ data = with pkgs.vimPlugins; [
blink-compat blink-compat
@ -175,8 +174,8 @@
]; ];
}; };
config.specs.gitPlugins-lazy = lib.mkIf (config.cats.gitPlugins or false) { config.specs.gitPlugins-lazy = {
lazy = true; lazy = true;
data = []; data = [ ];
}; };
} }

View file

@ -7,18 +7,29 @@ inputs:
... ...
}: }:
{ {
# ============================================================================
# IMPORTS
# ============================================================================
# Import the base neovim wrapper module and all configuration modules
imports = [ imports = [
wlib.wrapperModules.neovim wlib.wrapperModules.neovim
./module/settings/cat-packages.nix
./module/specs/deps.nix ./module/specs/deps.nix
./module/specs/plugins.nix ./module/specs/plugins.nix
./module/specs/cats-enable.nix
./module/settings/core.nix ./module/settings/core.nix
./module/settings/cats.nix ./module/settings/cats.nix
./module/settings/env.nix ./module/settings/env.nix
./module/settings/hosts.nix ./module/settings/hosts.nix
./module/settings/lang-packages.nix ./module/settings/lang-packages.nix
./module/settings/runtime-path.nix
]; ];
# ============================================================================
# HELPER FUNCTIONS
# ============================================================================
# Utilities for working with plugin inputs
options.nvim-lib.neovimPlugins = lib.mkOption { options.nvim-lib.neovimPlugins = lib.mkOption {
readOnly = true; readOnly = true;
type = lib.types.attrsOf wlib.types.stringable; type = lib.types.attrsOf wlib.types.stringable;
@ -47,6 +58,11 @@ inputs:
]; ];
}; };
# ============================================================================
# CONFIGURATION
# ============================================================================
# Pass cats configuration to neovim and expose metadata
config.settings.cats = config.cats; config.settings.cats = config.cats;
config.info.cats = config.cats; config.info.cats = config.cats;
config.info.nixCats_config_location = config.settings.config_directory; config.info.nixCats_config_location = config.settings.config_directory;

View file

@ -3,33 +3,39 @@ let
lib = nixpkgs.lib; lib = nixpkgs.lib;
rOverlay = import ./r.nix {inherit inputs;}; rOverlay = import ./r.nix {inherit inputs;};
rNvimNixOverlay = inputs.r-nvim-nix.overlays.default; franOverlay = inputs.fran.overlays.default;
pythonOverlay = import ./python.nix {inherit inputs;}; pythonOverlay = import ./python.nix inputs;
pluginsOverlay = import ./plugins.nix {inherit inputs;}; pluginsOverlay = import ./plugins.nix inputs;
dependencyOverlays = [ dependencyOverlays = [
rOverlay rOverlay
rNvimNixOverlay
pythonOverlay pythonOverlay
pluginsOverlay pluginsOverlay
]; ];
dependencyOverlay = lib.composeManyExtensions dependencyOverlays; dependencyOverlay = lib.composeManyExtensions dependencyOverlays;
# franOverlay provides R-specific tooling (radianWrapper, air-formatter).
# It is scoped to rixpkgs (via overlays/r.nix) rather than the global
# package set, since it only applies to R package derivations.
franOverlay = inputs.fran.overlays.default;
in in
{ {
inherit inherit
rOverlay rOverlay
rNvimNixOverlay
franOverlay franOverlay
pythonOverlay pythonOverlay
pluginsOverlay pluginsOverlay
dependencyOverlays dependencyOverlays
dependencyOverlay; dependencyOverlay;
# Named exports for downstream composition.
default = dependencyOverlay; default = dependencyOverlay;
dependencies = dependencyOverlays; dependencies = dependencyOverlays;
overlays = {
inherit
rOverlay
franOverlay
pythonOverlay
pluginsOverlay
dependencyOverlays
dependencyOverlay;
default = dependencyOverlay;
dependencies = dependencyOverlays;
};
} }

View file

@ -1,11 +1,52 @@
{inputs, ...}: final: prev: let # R packages overlay (rix)
#
# This overlay provides access to R packages from rstats-on-nix.
#
# rstats-on-nix maintains snapshots of CRAN packages built with Nix:
# - Provides reproducible R package versions
# - Ensures binary cache availability for faster builds
# - Maintained by the rstats-on-nix community
#
# Available attributes after applying this overlay:
# - pkgs.rpkgs: R packages from rstats-on-nix
# - pkgs.rpkgs.rPackages: All CRAN packages
# - pkgs.rpkgs.quarto: Quarto publishing system
# - pkgs.rpkgs.rWrapper: R with package management
# - pkgs.rWrapper: R wrapper with standard packages pre-configured
# - pkgs.quarto: Quarto with R integration and standard packages
#
# Custom R packages and tools (radianWrapper, air-formatter) come from
# the fran overlay which should be applied separately.
#
# To use specific R packages, reference them via:
# with pkgs.rpkgs.rPackages; [ package1 package2 ]
#
# Update the R snapshot date in flake.nix inputs section:
# rixpkgs.url = "github:rstats-on-nix/nixpkgs/YYYY-MM-DD"
{
inputs,
...
}: final: prev: let
# R packages from rstats-on-nix for the current system
rpkgs = import inputs.rixpkgs { rpkgs = import inputs.rixpkgs {
system = prev.stdenv.hostPlatform.system; system = prev.stdenv.hostPlatform.system;
overlays = [inputs.fran.overlays.default inputs.r-nvim-nix.overlays.default]; overlays = [inputs.fran.overlays.default];
}; }; # rixpkgs.legacyPackages.${prev.stdenv.hostPlatform.system};
# Standard R packages used by default in rWrapper and quarto
reqPkgs = with rpkgs.rPackages; [
# languageserver
];
in { in {
inherit rpkgs; inherit rpkgs;
baseRPackages = [rpkgs.nvimcom]; baseRPackages = reqPkgs;
rWrapper = rpkgs.rWrapper.override {packages = [];};
quarto = rpkgs.quarto.override {extraRPackages = [];}; # R wrapper with standard packages
rWrapper = rpkgs.rWrapper.override {packages = reqPkgs;};
# Quarto with R integration
quarto = rpkgs.quarto.override {extraRPackages = reqPkgs;};
# Update helper for rix
updateR = import ../scripts/updater.nix {pkgs = final;};
} }

View file

@ -176,7 +176,7 @@ if vim.g.neovide then
vim.g.neovide_cursor_short_animation_length = 0 vim.g.neovide_cursor_short_animation_length = 0
vim.g.neovide_font_hinting = 'none' vim.g.neovide_font_hinting = 'none'
vim.g.neovide_font_edging = 'subpixelantialias' vim.g.neovide_font_edging = 'subpixelantialias'
vim.o.guifont = 'JetBrainsMono Nerd Font,Symbols Nerd Font:h14:#e-subpixelantialias:#h-none' vim.o.guifont = 'Iosevka Nerd Font,Symbols Nerd Font:h14:#e-subpixelantialias:#h-none'
vim.g.neovide_floating_corner_radius = 0.35 vim.g.neovide_floating_corner_radius = 0.35
vim.keymap.set("n", "<leader>nf", "<cmd>NeovideFullscreen<CR>", { desc = "Toggle Neovide Fullscreen" }) vim.keymap.set("n", "<leader>nf", "<cmd>NeovideFullscreen<CR>", { desc = "Toggle Neovide Fullscreen" })
end end

View file

@ -144,7 +144,7 @@ nmap_leader('gc', '<Cmd>Git commit<CR>', 'Commit')
nmap_leader('gC', '<Cmd>Git commit --amend<CR>', 'Commit amend') 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')
nmap_leader('gD', '<Cmd>Git diff -- %<CR>', 'Diff buffer') nmap_leader('gD', '<Cmd>Git diff -- %<CR>', 'Diff buffer')
nmap_leader("gg", "<cmd>Neogit<cr>", "Open Neogit UI") nmap_leader('gg', '<Cmd>lua require("neogit").open()<CR>', 'Git tab')
nmap_leader('gl', '<Cmd>' .. git_log_cmd .. '<CR>', 'Log') nmap_leader('gl', '<Cmd>' .. git_log_cmd .. '<CR>', 'Log')
nmap_leader('gL', '<Cmd>' .. git_log_cmd .. ' --follow -- %<CR>', 'Log buffer') nmap_leader('gL', '<Cmd>' .. git_log_cmd .. ' --follow -- %<CR>', 'Log buffer')
nmap_leader('go', '<Cmd>lua MiniDiff.toggle_overlay()<CR>', 'Toggle overlay') nmap_leader('go', '<Cmd>lua MiniDiff.toggle_overlay()<CR>', 'Toggle overlay')

View file

@ -390,7 +390,6 @@ end)
-- zk -- zk
now_if_args(function() now_if_args(function()
if nix.get_cat("markdown", false) then
require("zk").setup({ require("zk").setup({
picker = "minipick", picker = "minipick",
lsp = { lsp = {
@ -410,5 +409,4 @@ now_if_args(function()
}, },
}) })
end
end) end)

View file

@ -44,12 +44,6 @@ end)
-- r -- r
now(function() now(function()
if nix.get_cat("r", false) then if nix.get_cat("r", false) then
local cwd = vim.fn.getcwd(-1)
vim.env.RNVIM_COMPLDIR = cwd .. "/.r-compl"
vim.env.R_LIBS_USER = (vim.env.R_LIBS_USER or ""):gsub("%$PWD", cwd)
vim.env.TMPDIR = cwd .. "/.r-tmp"
vim.fn.mkdir(vim.env.RNVIM_COMPLDIR, "p")
vim.fn.mkdir(vim.env.TMPDIR, "p")
vim.g.rout_follow_colorscheme = true vim.g.rout_follow_colorscheme = true
require("r").setup({ require("r").setup({
-- Create a table with the options to be passed to setup() -- Create a table with the options to be passed to setup()
@ -61,7 +55,7 @@ now(function()
min_editor_width = 80, min_editor_width = 80,
rconsole_height = 20, rconsole_height = 20,
nvimpager = "split_h", nvimpager = "split_h",
pdfviewer = "", pdfviewer = "zathura",
}) })
end end
end) end)
@ -71,7 +65,6 @@ end)
now(function() now(function()
vim.treesitter.language.register("markdown", { "quarto", "rmd" }) vim.treesitter.language.register("markdown", { "quarto", "rmd" })
if nix.get_cat({ "r", "markdown" }, false) then
vim.api.nvim_create_autocmd("FileType", { vim.api.nvim_create_autocmd("FileType", {
pattern = { "quarto" }, pattern = { "quarto" },
callback = function() callback = function()
@ -88,11 +81,9 @@ now(function()
write_to_disk = true, write_to_disk = true,
}, },
}) })
end
end) end)
later(function() later(function()
if nix.get_cat({ "r", "markdown" }, false) then
require("quarto").setup({ require("quarto").setup({
lspFeatures = { lspFeatures = {
enabled = true, enabled = true,
@ -111,5 +102,4 @@ later(function()
default_method = "slime", default_method = "slime",
}, },
}) })
end
end) end)

View file

@ -1,7 +1,6 @@
local add = Config.add local add = Config.add
local now_if_args = Config.now_if_args local now_if_args = Config.now_if_args
local later = MiniDeps.later local later = MiniDeps.later
local nix = require('config.nix')
if not Config.isNixCats then if not Config.isNixCats then
local m_add = MiniDeps.add local m_add = MiniDeps.add
@ -13,7 +12,6 @@ end
-- lua -- lua
later(function() later(function()
if nix.get_cat("lua", false) then
add("luvit-meta") add("luvit-meta")
add("lazydev") add("lazydev")
require("lazydev").setup({ require("lazydev").setup({
@ -27,7 +25,6 @@ later(function()
{ path = "${3rd}/luv/library", words = { "vim%.uv" } }, { path = "${3rd}/luv/library", words = { "vim%.uv" } },
}, },
}) })
end
end) end)
-- Markdown -- Markdown

View file

@ -15,17 +15,17 @@ now_if_args(function()
marksman = { marksman = {
filetypes = { "markdown", "markdown_inline", "codecompanion" }, filetypes = { "markdown", "markdown_inline", "codecompanion" },
}, },
r_ls = { -- r_language_server = {
filetypes = { 'r', 'rmd', 'rmarkdown' }, -- filetypes = { 'r', 'rmd', 'rmarkdown' },
settings = { -- settings = {
['r_ls'] = { -- ['r_language_server'] = {
lsp = { -- lsp = {
rich_documentation = true, -- rich_documentation = true,
enable = true, -- enable = true,
}, -- },
}, -- },
} -- }
}, -- },
julials = { julials = {
settings = { settings = {
julia = { julia = {

14
scripts/updater.nix Normal file
View file

@ -0,0 +1,14 @@
{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;
}

22
scripts/updater.sh Normal file
View file

@ -0,0 +1,22 @@
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