diff --git a/.commandcode/taste/taste.md b/.commandcode/taste/taste.md new file mode 100644 index 0000000..54e4488 --- /dev/null +++ b/.commandcode/taste/taste.md @@ -0,0 +1,9 @@ +# 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/ + diff --git a/.gitignore b/.gitignore index e402ff0..8474af7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,3 @@ *.R .Rlibs .nvimcom -.commandcode -.commandcode/ diff --git a/README.md b/README.md deleted file mode 100644 index 068d704..0000000 --- a/README.md +++ /dev/null @@ -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. - │ │ - ├──────────────┐ │ - ▼ ▼ ▼ - 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. diff --git a/flake.lock b/flake.lock index 45f57c3..2976ff4 100644 --- a/flake.lock +++ b/flake.lock @@ -22,11 +22,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1779508470, - "narHash": "sha256-Ap9KJX+5xHIn3bPIpfNgT6MEXdAECECwo4/rmlQD74M=", + "lastModified": 1779357205, + "narHash": "sha256-cCO8aTqss5x9Ky8GWkpY0Hy5fyTZEbtifSUV8QjSzic=", "owner": "nixos", "repo": "nixpkgs", - "rev": "29916453413845e54a65b8a1cf996842300cd299", + "rev": "f83fc3c307e74bc5fd5adb7eb6b8b13ffd2a36e1", "type": "github" }, "original": { @@ -52,24 +52,42 @@ "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": "rnvimsrc" + "rnvimsrc": [ + "plugins-r" + ] }, "locked": { - "lastModified": 1779438909, - "narHash": "sha256-1lvv0bdvSVyeCIgeZ7Ws7ffbDFurA5LJscS9dRLHzC8=", + "lastModified": 1779439280, + "narHash": "sha256-OX3/QTVOq5o3DD6dNzNY8X2v/7ZtbQOM01Z8bVf5tHc=", "owner": "dwinkler1", "repo": "r_nvim_nix", - "rev": "ec17e22ab362a0ddfd6c2e9c5e95d43897a143be", + "rev": "a012c98b5cc6a8ce59d461825c71b4877f934056", "type": "github" }, "original": { "owner": "dwinkler1", - "ref": "v0.99.4", "repo": "r_nvim_nix", "type": "github" } @@ -90,28 +108,12 @@ "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" diff --git a/flake.nix b/flake.nix index ee9c05c..2780328 100644 --- a/flake.nix +++ b/flake.nix @@ -1,4 +1,4 @@ -# Copyright (c) 2026 BirdeeHub & Daniel +# Copyright (c) 2026 Daniel # Licensed under the MIT license { description = "Daniel's NixCats"; @@ -11,12 +11,9 @@ }; rixpkgs.url = "github:dwinkler1/rixpkgs/af2dd3f7b4b172077747c0869d4e30702fb71b0e"; - r-nvim-nix = { - url = "github:dwinkler1/r_nvim_nix/v0.99.4"; - inputs = { - nixpkgs.follows = "rixpkgs"; - }; - }; + r-nvim-nix.url = "github:dwinkler1/r_nvim_nix"; + r-nvim-nix.inputs.rnvimsrc.follows = "plugins-r"; + r-nvim-nix.inputs.nixpkgs.follows = "rixpkgs"; fran = { url = "github:dwinkler1/fran"; @@ -25,6 +22,11 @@ }; }; + "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; @@ -37,42 +39,35 @@ wrappers, ... } @ inputs: let - devShellCatOrder = [ - "always" - "clickhouse" - "external" - "julia" - "lua" - "markdown" - "nix" - "optional" - "python" - "r" - "treesitterParsers" - ]; - evalWithPkgs = pkgs: extraModules: - wrappers.lib.evalModules { - specialArgs = { - inherit pkgs; + 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 = []; }; - 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" @@ -87,44 +82,34 @@ 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. - # It is evaluated against the final package set so module defaults can - # depend on overlays such as rixpkgs-backed `pkgs.rpkgs`. + # For the fully-configured binary (including mkWrapperConfig overrides), + # use `packages..default` instead. default = nixpkgs.lib.composeManyExtensions [ overlayDefs.dependencyOverlay (final: prev: { - vv = (evalWithPkgs final []).config.wrap {pkgs = final;}; + vv = wrapper.config.wrap {pkgs = final;}; }) ]; dependencies = overlayDefs.dependencyOverlay; }; wrapperModules.default = module; - wrapperConfigs.default = {pkgs, modules ? []}: (self.lib.eval {inherit pkgs modules;}).config; + wrapperConfigs.default = wrapper.config; packages = forAllSystems ( system: let pkgs = mkPkgs system; in { - default = self.lib.mkWrapper { - inherit pkgs; - }; + default = wrapperSettings pkgs; } ); @@ -138,13 +123,80 @@ devShells = forAllSystems ( system: let pkgs = mkPkgs system; - config = (self.lib.eval {inherit pkgs;}).config; - nvimPkg = config.wrap {inherit pkgs;}; + 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; in { default = pkgs.mkShell { name = "vShell"; - packages = [nvimPkg] ++ self.lib.devShellPackages config; - shellHook = mkShellHook config; + 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" + ''; }; } ); @@ -152,31 +204,10 @@ checks = forAllSystems ( system: let pkgs = mkPkgs system; - 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; + nvimPkg = wrapperSettings pkgs; in { default = pkgs.runCommand "check-vv" {} '' - BINARY_PATH="${defaultNvimPkg}/bin/vv" + BINARY_PATH="${nvimPkg}/bin/vv" if [ ! -x "$BINARY_PATH" ]; then echo "Error: Binary not found or not executable" @@ -192,38 +223,11 @@ cat version_output.txt >> $out fi ''; - module-eval = let - _ = (self.lib.eval {inherit pkgs;}).config; - in - pkgs.runCommand "check-module-eval" {} '' + module-eval = + let _ = wrapper.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 - ''; } ); diff --git a/modules/module/settings/cat-packages.nix b/modules/module/settings/cat-packages.nix deleted file mode 100644 index b92c331..0000000 --- a/modules/module/settings/cat-packages.nix +++ /dev/null @@ -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 = [ ]; - }; -} diff --git a/modules/module/settings/cats.nix b/modules/module/settings/cats.nix index e1895f7..13758d4 100644 --- a/modules/module/settings/cats.nix +++ b/modules/module/settings/cats.nix @@ -13,7 +13,6 @@ 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 @@ -31,7 +30,6 @@ }; config.cats = { - always = lib.mkDefault true; clickhouse = lib.mkDefault false; external = lib.mkDefault true; general = lib.mkDefault true; diff --git a/modules/module/settings/core.nix b/modules/module/settings/core.nix index 822fc53..ec9bb5c 100644 --- a/modules/module/settings/core.nix +++ b/modules/module/settings/core.nix @@ -16,7 +16,7 @@ # Lua packages available to neovim (for :lua require()) config.settings.nvim_lua_env = lp: - lib.optionals (config.cats.general or false) [ lp.tiktoken_core ]; + lib.optionals (config.cats.general or true) [ lp.tiktoken_core ]; # Binary name for the wrapper config.binName = lib.mkDefault "vv"; @@ -32,10 +32,4 @@ # 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; } diff --git a/modules/module/settings/env.nix b/modules/module/settings/env.nix index c7a1a8b..2fcab8a 100644 --- a/modules/module/settings/env.nix +++ b/modules/module/settings/env.nix @@ -7,16 +7,21 @@ # Environment variables set for the wrapper. # These are available when running neovim. config.env = lib.mkMerge [ - (lib.mkIf (config.cats.python or false) { + (lib.mkIf (config.cats.python or true) { UV_PYTHON_DOWNLOADS = "never"; UV_PYTHON = pkgs.python.interpreter; }) - (lib.mkIf (config.cats.r or false) { + (lib.mkIf (config.cats.r or true) { 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 [ ]; + config.envDefault = lib.mkMerge [ + (lib.mkIf (config.cats.r or true) { + R_LIBS_USER = "${pkgs.nvimcom}/library:$PWD/.Rlibs"; + }) + ]; } diff --git a/modules/module/settings/hosts.nix b/modules/module/settings/hosts.nix index aadd70f..f248a00 100644 --- a/modules/module/settings/hosts.nix +++ b/modules/module/settings/hosts.nix @@ -4,10 +4,6 @@ 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 [ { @@ -33,7 +29,7 @@ in ]; }; } - (lib.mkIf (config.cats.julia or false) { + (lib.mkIf (config.cats.julia or true) { jl = { nvim-host.enable = true; 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; }) - (lib.mkIf (config.cats.r or false) { + (lib.mkIf (config.cats.r or true) { r = { nvim-host.enable = true; - nvim-host.package = "${rWrapperPkg}/bin/R"; + nvim-host.package = "${pkgs.rWrapper}/bin/R"; nvim-host.argv0 = "R"; nvim-host.addFlag = [ "--no-save" diff --git a/modules/module/settings/lang-packages.nix b/modules/module/settings/lang-packages.nix index a91d9a5..531b811 100644 --- a/modules/module/settings/lang-packages.nix +++ b/modules/module/settings/lang-packages.nix @@ -1,6 +1,5 @@ { config, - pkgs, lib, ... }: @@ -27,28 +26,14 @@ }; default = { }; description = '' - Language-specific package defaults and downstream overrides appended to each - language spec's runtime packages. + Language-specific package overrides appended to each language spec's runtimePackages. + Intended for flake.nix overrides via wrapper.config.wrap. ''; }; config.settings.lang_packages = { - 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" - ]; + python = lib.mkDefault [ ]; + r = lib.mkDefault [ ]; + julia = lib.mkDefault [ ]; }; } diff --git a/modules/module/settings/runtime-path.nix b/modules/module/settings/runtime-path.nix new file mode 100644 index 0000000..b321019 --- /dev/null +++ b/modules/module/settings/runtime-path.nix @@ -0,0 +1,33 @@ +{ + 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); +} diff --git a/modules/module/specs/deps.nix b/modules/module/specs/deps.nix index 5cbfe63..c3a40ea 100644 --- a/modules/module/specs/deps.nix +++ b/modules/module/specs/deps.nix @@ -13,69 +13,133 @@ }; }; - 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) { + config.specs.external = { data = lib.mkDefault null; before = ["INIT_MAIN"]; config = '' vim.o.shell = "${pkgs.zsh}/bin/zsh" ''; runtimeDeps = "prefix"; - runtimePkgs = config.catPkgs.external; + runtimePkgs = with pkgs; [ + perl + ruby + shfmt + sqlfluff + tree-sitter + ]; }; - config.specs.optional = lib.mkIf (config.cats.optional or false) { + config.specs.optional = lib.mkIf (config.cats.optional or true) { data = lib.mkDefault null; runtimeDeps = "prefix"; before = ["INIT_MAIN"]; - runtimePkgs = config.catPkgs.optional; + 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 + ]; }; - config.specs.markdown = lib.mkIf (config.cats.markdown or false) { + config.specs.markdown = lib.mkIf (config.cats.markdown or true) { data = lib.mkDefault null; runtimeDeps = "prefix"; - runtimePkgs = config.catPkgs.markdown; + runtimePkgs = with pkgs; [ + python313Packages.pylatexenc + quarto + zk + ]; }; - config.specs.nix = lib.mkIf (config.cats.nix or false) { + config.specs.nix = lib.mkIf (config.cats.nix or true) { data = lib.mkDefault null; runtimeDeps = "prefix"; - runtimePkgs = config.catPkgs.nix; + runtimePkgs = with pkgs; [ + alejandra + nix-doc + nixd + ]; }; - config.specs.lua = lib.mkIf (config.cats.lua or false) { + config.specs.lua = lib.mkIf (config.cats.lua or true) { data = lib.mkDefault null; runtimeDeps = "prefix"; - runtimePkgs = config.catPkgs.lua; + runtimePkgs = with pkgs; [ + lua-language-server + ]; }; - config.specs.python = lib.mkIf (config.cats.python or false) { + config.specs.python = lib.mkIf (config.cats.python or true) { data = lib.mkDefault null; runtimeDeps = "prefix"; - runtimePkgs = config.catPkgs.python; + 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 + ]; }; - config.specs.r = lib.mkIf (config.cats.r or false) { + config.specs.r = lib.mkIf (config.cats.r or true) { data = lib.mkDefault null; runtimeDeps = "prefix"; - runtimePkgs = config.catPkgs.r; + 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 + ]; }; - config.specs.julia = lib.mkIf (config.cats.julia or false) { + config.specs.julia = lib.mkIf (config.cats.julia or true) { data = lib.mkDefault null; runtimeDeps = "prefix"; - runtimePkgs = config.catPkgs.julia; + runtimePkgs = 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) { + config.specs.clickhouse = lib.mkIf (config.cats.clickhouse or true) { data = lib.mkDefault null; runtimeDeps = "prefix"; - runtimePkgs = config.catPkgs.clickhouse; + runtimePkgs = with pkgs; [ + clickhouse-lts + ]; }; config.runtimePkgs = config.specCollect (acc: v: acc ++ (v.runtimePkgs or [])) []; diff --git a/modules/module/specs/plugins.nix b/modules/module/specs/plugins.nix index ad464b8..ff00a72 100644 --- a/modules/module/specs/plugins.nix +++ b/modules/module/specs/plugins.nix @@ -4,11 +4,11 @@ lib, ... }: { - config.specs.gitPlugins = lib.mkIf (config.cats.gitPlugins or false) { + config.specs.gitPlugins = lib.mkIf (config.cats.gitPlugins or true) { data = []; }; - config.specs.r = lib.mkIf (config.cats.r or false) { + config.specs.r = lib.mkIf (config.cats.r or true) { data = with pkgs.vimPlugins; [ pkgs.r-nvim quarto-nvim @@ -19,14 +19,14 @@ ]; }; - config.specs.markdown-lazy = lib.mkIf (config.cats.markdown or false) { + config.specs.markdown-lazy = lib.mkIf (config.cats.markdown or true) { lazy = true; data = [ config.nvim-lib.neovimPlugins.cmp-pandoc-references ]; }; - config.specs.general = lib.mkIf (config.cats.general or false) { + config.specs.general = lib.mkIf (config.cats.general or true) { data = with pkgs.vimPlugins; [ lze lzextras @@ -79,7 +79,7 @@ ]; }; - config.specs.lua = lib.mkIf (config.cats.lua or false) { + config.specs.lua = lib.mkIf (config.cats.lua or true) { data = with pkgs.vimPlugins; [ luvit-meta { @@ -89,7 +89,7 @@ ]; }; - config.specs.markdown = lib.mkIf (config.cats.markdown or false) { + config.specs.markdown = lib.mkIf (config.cats.markdown or true) { data = with pkgs.vimPlugins; [ quarto-nvim render-markdown-nvim @@ -104,7 +104,7 @@ ]; }; - config.specs.utils = lib.mkIf (config.cats.utils or false) { + config.specs.utils = lib.mkIf (config.cats.utils or true) { data = with pkgs.vimPlugins; [ blink-cmp nvim-lspconfig @@ -119,7 +119,7 @@ ]; }; - config.specs.treesitterParsers = lib.mkIf (config.cats.treesitterParsers or false) { + config.specs.treesitterParsers = lib.mkIf (config.cats.treesitterParsers or true) { data = with pkgs.vimPlugins.nvim-treesitter-parsers; [ bash c @@ -158,7 +158,7 @@ ]; }; - config.specs.utils-lazy = lib.mkIf (config.cats.utils or false) { + config.specs.utils-lazy = lib.mkIf (config.cats.utils or true) { lazy = true; data = with pkgs.vimPlugins; [ blink-compat @@ -175,7 +175,7 @@ ]; }; - config.specs.gitPlugins-lazy = lib.mkIf (config.cats.gitPlugins or false) { + config.specs.gitPlugins-lazy = lib.mkIf (config.cats.gitPlugins or true) { lazy = true; data = []; }; diff --git a/modules/neovim.nix b/modules/neovim.nix index f4ca40f..64d2cda 100644 --- a/modules/neovim.nix +++ b/modules/neovim.nix @@ -9,7 +9,6 @@ inputs: { imports = [ wlib.wrapperModules.neovim - ./module/settings/cat-packages.nix ./module/specs/deps.nix ./module/specs/plugins.nix ./module/settings/core.nix @@ -17,6 +16,7 @@ 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 { diff --git a/overlays/r.nix b/overlays/r.nix index 18f01dd..14c02eb 100644 --- a/overlays/r.nix +++ b/overlays/r.nix @@ -11,4 +11,5 @@ in { baseRPackages = [ ]; rWrapper = rpkgs.rWrapper.override {packages = [ ];}; quarto = rpkgs.quarto.override {extraRPackages = [ ];}; + updateR = import ../scripts/updater.nix {pkgs = final;}; } diff --git a/plugin/10_keymap.lua b/plugin/10_keymap.lua index 5682b93..ebbebf0 100644 --- a/plugin/10_keymap.lua +++ b/plugin/10_keymap.lua @@ -37,7 +37,7 @@ _G.Config.leader_group_clues = { { mode = 'x', keys = 'l', desc = '+LSP' }, { mode = 'x', keys = 'r', desc = '+R' }, { mode = 'n', keys = 'z', desc = '+ZK' }, - { mode = 'n', keys = 'zr', desc = '+Reviews' }, + { mode = 'n', keys = 'zr', desc = '+Reviews' }, { mode = 'x', keys = 'a', desc = '+AI' }, } @@ -144,7 +144,7 @@ nmap_leader('gc', 'Git commit', 'Commit') nmap_leader('gC', 'Git commit --amend', 'Commit amend') nmap_leader('gd', 'Git diff', 'Diff') nmap_leader('gD', 'Git diff -- %', 'Diff buffer') -nmap_leader("gg", "Neogit", "Open Neogit UI") +nmap_leader('gg', 'lua require("neogit").open()', 'Git tab') nmap_leader('gl', '' .. git_log_cmd .. '', 'Log') nmap_leader('gL', '' .. git_log_cmd .. ' --follow -- %', 'Log buffer') nmap_leader('go', 'lua MiniDiff.toggle_overlay()', 'Toggle overlay') diff --git a/plugin/21_datascience.lua b/plugin/21_datascience.lua index aeab360..2e9f86c 100644 --- a/plugin/21_datascience.lua +++ b/plugin/21_datascience.lua @@ -61,7 +61,7 @@ now(function() min_editor_width = 80, rconsole_height = 20, nvimpager = "split_h", - pdfviewer = "", + pdfviewer = "zathura", }) end end) diff --git a/scripts/updater.nix b/scripts/updater.nix new file mode 100644 index 0000000..063ec8d --- /dev/null +++ b/scripts/updater.nix @@ -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; +} diff --git a/scripts/updater.sh b/scripts/updater.sh new file mode 100644 index 0000000..ccf5e2e --- /dev/null +++ b/scripts/updater.sh @@ -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