diff --git a/.Rprofile b/.Rprofile deleted file mode 100644 index 7617f61..0000000 --- a/.Rprofile +++ /dev/null @@ -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")) -} diff --git a/.gitignore b/.gitignore index 6e33f00..8474af7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,3 @@ *.R .Rlibs .nvimcom -.commandcode -.commandcode/ -.r-* 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 21dc5ef..78a5bd8 100644 --- a/flake.lock +++ b/flake.lock @@ -22,11 +22,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1778869304, - "narHash": "sha256-30sZNZoA1cqF5JNO9fVX+wgiQYjB7HJqqJ4ztCDeBZE=", + "lastModified": 1776169885, + "narHash": "sha256-l/iNYDZ4bGOAFQY2q8y5OAfBBtrDAaPuRQqWaFHVRXM=", "owner": "nixos", "repo": "nixpkgs", - "rev": "d233902339c02a9c334e7e593de68855ad26c4cb", + "rev": "4bd9165a9165d7b5e33ae57f3eecbcb28fb231c9", "type": "github" }, "original": { @@ -52,35 +52,29 @@ "type": "github" } }, - "r-nvim-nix": { - "inputs": { - "nixpkgs": [ - "rixpkgs" - ], - "rnvimsrc": "rnvimsrc" - }, + "plugins-r": { + "flake": false, "locked": { - "lastModified": 1781392459, - "narHash": "sha256-9CMG+trBd9AX7cWiGPrMr0eJwuZaql+pj2WVGyT417I=", - "owner": "dwinkler1", - "repo": "r_nvim_nix", - "rev": "03d7872d7702db37ede41f3c6e4d4ce4c129e862", + "lastModified": 1776340770, + "narHash": "sha256-o/8UZIc/Bq9dWTjA+MpSR5uMUpE7KHTErk+TwWID8Ww=", + "owner": "R-nvim", + "repo": "R.nvim", + "rev": "b9cfffeb9b4e484aa9e13f01c0eb80230aada455", "type": "github" }, "original": { - "owner": "dwinkler1", - "ref": "v0.99.5", - "repo": "r_nvim_nix", + "owner": "R-nvim", + "repo": "R.nvim", "type": "github" } }, "rixpkgs": { "locked": { - "lastModified": 1782576256, - "narHash": "sha256-KOvpL9DJJmShb64mX9QTjhxHaxE8MizQIqNUAniuJ2E=", + "lastModified": 1771303851, + "narHash": "sha256-tgveHozOJ2D/mi3LxVy/FcmLFDlM5XKZxsNB2XpvzaM=", "owner": "dwinkler1", "repo": "rixpkgs", - "rev": "815afc01bc0cc9a2eba80906645bd08f976a4401", + "rev": "af2dd3f7b4b172077747c0869d4e30702fb71b0e", "type": "github" }, "original": { @@ -90,29 +84,12 @@ "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": { "inputs": { "fran": "fran", "nixpkgs": "nixpkgs", "plugins-cmp-pandoc-references": "plugins-cmp-pandoc-references", - "r-nvim-nix": "r-nvim-nix", + "plugins-r": "plugins-r", "rixpkgs": "rixpkgs", "wrappers": "wrappers" } @@ -124,11 +101,11 @@ ] }, "locked": { - "lastModified": 1779297405, - "narHash": "sha256-VFoBwH7ZjVxCnvZTb5ODRXt70sLtWMxstive0N+RS50=", + "lastModified": 1776375800, + "narHash": "sha256-/SSAR77Brr9fbapsh1cb2K47JXCbvwS1GjM4yyDxle8=", "owner": "BirdeeHub", "repo": "nix-wrapper-modules", - "rev": "e7ed7a1205945befdf2e0d73ba7df91d935e5af1", + "rev": "f11469ca69068bac13d9e163b2bd268cc06dff57", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index d8c0018..cce0107 100644 --- a/flake.nix +++ b/flake.nix @@ -1,23 +1,17 @@ -# Copyright (c) 2026 BirdeeHub & Daniel +# Copyright (c) 2026 BirdeeHub # Licensed under the MIT license { description = "Daniel's NixCats"; inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + #nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11"; wrappers = { url = "github:BirdeeHub/nix-wrapper-modules"; inputs.nixpkgs.follows = "nixpkgs"; }; rixpkgs.url = "github:dwinkler1/rixpkgs/nixpkgs"; - r-nvim-nix = { - url = "github:dwinkler1/r_nvim_nix/v0.99.5"; - inputs = { - nixpkgs.follows = "rixpkgs"; - }; - }; - fran = { url = "github:dwinkler1/fran"; inputs = { @@ -25,6 +19,11 @@ }; }; + "plugins-r" = { + url = "github:R-nvim/R.nvim"; + flake = false; + }; + "plugins-cmp-pandoc-references" = { url = "github:jmbuhr/cmp-pandoc-references"; flake = false; @@ -37,42 +36,46 @@ wrappers, ... } @ inputs: let - devShellCatOrder = [ - "always" - "clickhouse" - "external" - "julia" - "lua" - "markdown" - "nix" - "optional" - "python" - "r" - "treesitterParsers" - ]; - evalWithPkgs = pkgs: extraModules: - wrappers.lib.evalModules { - specialArgs = { - inherit pkgs; + wrapperSettings = pkgs: let + def = pkgs.lib.mkDefault; + in + wrapper.config.wrap { + 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 = - [ - module - ] - ++ extraModules; + + settings = { + lang_packages = { + python = with pkgs.python3Packages; [ + 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 = [ "aarch64-darwin" @@ -82,49 +85,54 @@ forAllSystems = nixpkgs.lib.genAttrs systems; + extra_pkg_config = { + # allowUnfree = true; + }; + overlayDefs = import ./overlays inputs; + dependencyOverlays = overlayDefs.dependencyOverlays; + + dependencyOverlay = overlayDefs.dependencyOverlay; + mkPkgs = system: import nixpkgs { inherit system; - config = {allowUnfree = true;}; - overlays = [ - overlayDefs.dependencyOverlay - ]; + config = extra_pkg_config; + overlays = [dependencyOverlay]; }; - module = (import ./modules/neovim.nix) inputs; + module = nixpkgs.lib.modules.importApply ./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`. default = nixpkgs.lib.composeManyExtensions [ - overlayDefs.dependencyOverlay + dependencyOverlay (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; - wrapperConfigs.default = {pkgs, modules ? []}: (self.lib.eval {inherit pkgs modules;}).config; + wrapperModules = { + default = module; + neovim = self.wrapperModules.default; + }; + + wrappers = { + default = wrapper.config; + neovim = self.wrappers.default; + }; packages = forAllSystems ( system: let pkgs = mkPkgs system; + nvimPkg = wrapperSettings pkgs; in { - default = self.lib.mkWrapper { - inherit pkgs; - }; + default = nvimPkg; + vv = nvimPkg; } ); @@ -138,13 +146,14 @@ devShells = forAllSystems ( system: let pkgs = mkPkgs system; - config = (self.lib.eval {inherit pkgs;}).config; - nvimPkg = config.wrap {inherit pkgs;}; + nvimPkg = wrapperSettings pkgs; in { default = pkgs.mkShell { name = "vShell"; - packages = [nvimPkg] ++ self.lib.devShellPackages config; - shellHook = mkShellHook config; + packages = [nvimPkg]; + nativeBuildInputs = with pkgs; [] ++ (pkgs.lib.optionals self.wrappers.default.cats.optional [devenv]); + inputsFrom = []; + shellHook = ""; }; } ); @@ -152,34 +161,20 @@ 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" + default = nvimPkg; + 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 - echo "Error: Binary not found or not executable" + echo "Error: Binary n not found or not executable" exit 1 fi @@ -192,38 +187,6 @@ cat version_output.txt >> $out 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 - ''; } ); diff --git a/ftplugin/markdown.lua b/ftplugin/markdown.lua index db316fc..b673b60 100644 --- a/ftplugin/markdown.lua +++ b/ftplugin/markdown.lua @@ -1,35 +1,32 @@ -- Add the key mappings only for Markdown files in a zk notebook. -local nix = require("config.nix") -if nix.get_cat("markdown", false) then - if require("zk.util").notebook_root(vim.fn.expand('%:p')) ~= nil then - local map = vim.keymap.set - -- Open the link under the caret. - map("n", "", "lua vim.lsp.buf.definition()", { noremap = true, silent = false, buffer = true }) +if require("zk.util").notebook_root(vim.fn.expand('%:p')) ~= nil then + local map = vim.keymap.set + -- Open the link under the caret. + map("n", "", "lua vim.lsp.buf.definition()", { noremap = true, silent = false, buffer = true }) - -- Create a new note after asking for its title. - -- This overrides the global `zn` mapping to create the note in the same directory as the current buffer. - map("n", "zhn", "ZkNew { dir = vim.fn.expand('%:p:h'), title = vim.fn.input('Title: ') }", - { noremap = true, silent = false, buffer = true, desc = "Note (here)" }) - -- Create a new note in the same directory as the current buffer, using the current selection for title. - map("v", "zhnt", ":'<,'>ZkNewFromTitleSelection { dir = vim.fn.expand('%:p:h') }", - { noremap = true, silent = false, buffer = true, desc = "Note from selection (title)" }) - -- Create a new note in the same directory as the current buffer, using the current selection for note content and asking for its title. - map("v", "zhnc", - ":'<,'>ZkNewFromContentSelection { dir = vim.fn.expand('%:p:h'), title = vim.fn.input('Title: ') }", - { noremap = true, silent = false, buffer = true, desc = "Note from selection (content)" }) + -- Create a new note after asking for its title. + -- This overrides the global `zn` mapping to create the note in the same directory as the current buffer. + map("n", "zhn", "ZkNew { dir = vim.fn.expand('%:p:h'), title = vim.fn.input('Title: ') }", + { noremap = true, silent = false, buffer = true, desc = "Note (here)" }) + -- Create a new note in the same directory as the current buffer, using the current selection for title. + map("v", "zhnt", ":'<,'>ZkNewFromTitleSelection { dir = vim.fn.expand('%:p:h') }", + { noremap = true, silent = false, buffer = true, desc = "Note from selection (title)" }) + -- Create a new note in the same directory as the current buffer, using the current selection for note content and asking for its title. + map("v", "zhnc", + ":'<,'>ZkNewFromContentSelection { dir = vim.fn.expand('%:p:h'), title = vim.fn.input('Title: ') }", + { noremap = true, silent = false, buffer = true, desc = "Note from selection (content)" }) - -- Open notes linking to the current buffer. - map("n", "zb", "ZkBacklinks", { noremap = true, silent = false, buffer = true, desc = "Backlinks" }) - -- Alternative for backlinks using pure LSP and showing the source context. - --map('n', 'zb', 'lua vim.lsp.buf.references()', opts) - -- Open notes linked by the current buffer. - map("n", "zL", "ZkLinks", { noremap = true, silent = false, buffer = true, desc = "Links" }) - map("n", "zi", "ZkInsertLink", { noremap = true, silent = false, buffer = true, desc = "Insert link" }) + -- Open notes linking to the current buffer. + map("n", "zb", "ZkBacklinks", { noremap = true, silent = false, buffer = true, desc = "Backlinks" }) + -- Alternative for backlinks using pure LSP and showing the source context. + --map('n', 'zb', 'lua vim.lsp.buf.references()', opts) + -- Open notes linked by the current buffer. + map("n", "zL", "ZkLinks", { noremap = true, silent = false, buffer = true, desc = "Links" }) + map("n", "zi", "ZkInsertLink", { noremap = true, silent = false, buffer = true, desc = "Insert link" }) - -- Preview a linked note. - -- Open the code actions for a visual selection. - map("v", "za", ":'<,'>lua vim.lsp.buf.range_code_action()", - { noremap = true, silent = false, buffer = true, desc = "Code actions" }) + -- Preview a linked note. + -- Open the code actions for a visual selection. + map("v", "za", ":'<,'>lua vim.lsp.buf.range_code_action()", + { noremap = true, silent = false, buffer = true, desc = "Code actions" }) - end end diff --git a/lua/nix_smart_send.lua b/lua/nix_smart_send.lua index 1f82383..c03af4c 100644 --- a/lua/nix_smart_send.lua +++ b/lua/nix_smart_send.lua @@ -22,11 +22,9 @@ local COMMENT_TYPES = { } function M.get_current_node() + local ts_utils = require('nvim-treesitter.ts_utils') local cur_win = vim.api.nvim_get_current_win() - return vim.treesitter.get_node({ - winid = cur_win, - ignore_injections = true, - }) + return ts_utils.get_node_at_cursor(cur_win, true) end function M.detect_global_node() @@ -52,6 +50,7 @@ function M.detect_global_node() end function M.move_to_next_non_empty_line() + local ts_utils = require('nvim-treesitter.ts_utils') -- Search for the next non-empty line 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] first_non_ws = line_content:find("%S") or 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 return true end function M.vselect_node(node) + local ts_utils = require('nvim-treesitter.ts_utils') if not node then return false end - local start_row, _, end_row, _ = node:range() - - 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 }) - + local cur_buf = vim.api.nvim_get_current_buf() + ts_utils.update_selection(cur_buf, node, "V") return true end function M.select_until_global(global_nodes) + local ts_utils = require('nvim-treesitter.ts_utils') local root_node = M.detect_global_node() if not root_node and global_nodes then root_node = global_nodes[1] @@ -116,7 +113,7 @@ function M.select_until_global(global_nodes) -- Use empty table if no global nodes provided global_nodes = global_nodes or {} - local node = vim.treesitter.get_node() + local node = ts_utils.get_node_at_cursor() if not node then -- print("No syntax node found at cursor position") return nil @@ -170,6 +167,7 @@ function M.slime_send_region() end function M.send_repl(global_nodes) + local ts_utils = require('nvim-treesitter.ts_utils') local cur_node = M.get_current_node() if not cur_node then @@ -191,9 +189,7 @@ function M.send_repl(global_nodes) M.slime_send_region() -- Move cursor and continue - local _, _, er, ec = sel_node:range() - vim.api.nvim_win_set_cursor(0, { er + 1, ec }) - + ts_utils.goto_node(sel_node, true) M.move_to_next_non_empty_line() end 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..22b3638 100644 --- a/modules/module/settings/cats.nix +++ b/modules/module/settings/cats.nix @@ -13,8 +13,8 @@ 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 + - customPlugins: local plugin specs - external: external tools and integrations - general: core Neovim plugins/features - gitPlugins: git-related plugins @@ -25,24 +25,26 @@ - optional: optional tools and utilities - python: Python tooling and plugins - r: R tooling and plugins + - test: test-only tooling (disabled by default) - treesitterParsers: Treesitter parsers - utils: general utilities ''; }; config.cats = { - always = lib.mkDefault true; clickhouse = lib.mkDefault false; + customPlugins = lib.mkDefault true; external = lib.mkDefault true; general = lib.mkDefault true; gitPlugins = lib.mkDefault true; julia = lib.mkDefault false; lua = lib.mkDefault true; - markdown = lib.mkDefault true; + markdown = lib.mkDefault false; nix = lib.mkDefault true; optional = lib.mkDefault false; python = lib.mkDefault false; - r = lib.mkDefault true; + r = lib.mkDefault false; + test = lib.mkDefault false; treesitterParsers = lib.mkDefault true; utils = lib.mkDefault true; }; diff --git a/modules/module/settings/core.nix b/modules/module/settings/core.nix index 822fc53..42e9e11 100644 --- a/modules/module/settings/core.nix +++ b/modules/module/settings/core.nix @@ -25,17 +25,11 @@ config.settings.block_normal_config = true; # 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 - config.settings.aliases = lib.mkDefault [ "vvim" ]; + config.settings.aliases = [ "vvim" ]; # 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..2ae4b9c 100644 --- a/modules/module/settings/env.nix +++ b/modules/module/settings/env.nix @@ -11,12 +11,12 @@ UV_PYTHON_DOWNLOADS = "never"; 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) - config.envDefault = lib.mkMerge [ ]; + config.envDefault = lib.mkMerge [ + (lib.mkIf (config.cats.r or false) { + R_LIBS_USER = "./.Rlibs"; + }) + ]; } diff --git a/modules/module/settings/hosts.nix b/modules/module/settings/hosts.nix index aadd70f..0743979 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 [ { @@ -19,7 +15,7 @@ in nvim-host.enable = true; nvim-host.package = "${pkgs.neovide}/bin/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 = { @@ -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..3315363 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 extraPackages. + 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..96c5d0f --- /dev/null +++ b/modules/module/settings/runtime-path.nix @@ -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); +} diff --git a/modules/module/specs/cats-enable.nix b/modules/module/specs/cats-enable.nix new file mode 100644 index 0000000..f5a9826 --- /dev/null +++ b/modules/module/specs/cats-enable.nix @@ -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. 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; + } + ]; +} diff --git a/modules/module/specs/deps.nix b/modules/module/specs/deps.nix index 5cbfe63..a8bfaf6 100644 --- a/modules/module/specs/deps.nix +++ b/modules/module/specs/deps.nix @@ -5,78 +5,184 @@ wlib, ... }: { + # ============================================================================ + # SPEC MODULE DEFAULTS + # ============================================================================ + # Define default options available to all specs + config.specMods = {parentSpec ? null, ...}: { - options.runtimePkgs = lib.mkOption { + options.extraPackages = lib.mkOption { type = lib.types.listOf wlib.types.stringable; 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; - runtimeDeps = "prefix"; - runtimePkgs = config.catPkgs.always; - }; + # ============================================================================ + # EXTERNAL TOOLS SPEC + # ============================================================================ + # Core system tools and utilities - 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; + 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; runtimeDeps = "prefix"; 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; 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; 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; 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; 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; 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; 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; 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 [])) []; } diff --git a/modules/module/specs/plugins.nix b/modules/module/specs/plugins.nix index ad464b8..ded8195 100644 --- a/modules/module/specs/plugins.nix +++ b/modules/module/specs/plugins.nix @@ -3,14 +3,15 @@ pkgs, 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; [ - pkgs.r-nvim + config.nvim-lib.neovimPlugins.r quarto-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; data = [ config.nvim-lib.neovimPlugins.cmp-pandoc-references ]; }; - config.specs.general = lib.mkIf (config.cats.general or false) { + config.specs.general = { data = with pkgs.vimPlugins; [ lze lzextras @@ -79,7 +80,7 @@ ]; }; - config.specs.lua = lib.mkIf (config.cats.lua or false) { + config.specs.lua = { data = with pkgs.vimPlugins; [ luvit-meta { @@ -89,7 +90,7 @@ ]; }; - config.specs.markdown = lib.mkIf (config.cats.markdown or false) { + config.specs.markdown = { data = with pkgs.vimPlugins; [ quarto-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; [ blink-cmp nvim-lspconfig nvim-treesitter-context nvim-treesitter-textobjects { - data = pkgs.codecompanion-nvim.overrideAttrs (old: { - doCheck = false; - }); + data = pkgs.codecompanion-nvim; pname = "codecompanion"; } ]; }; - config.specs.treesitterParsers = lib.mkIf (config.cats.treesitterParsers or false) { + config.specs.treesitterParsers = { data = with pkgs.vimPlugins.nvim-treesitter-parsers; [ bash c @@ -158,7 +157,7 @@ ]; }; - config.specs.utils-lazy = lib.mkIf (config.cats.utils or false) { + config.specs.utils-lazy = { lazy = true; data = with pkgs.vimPlugins; [ blink-compat @@ -175,8 +174,8 @@ ]; }; - config.specs.gitPlugins-lazy = lib.mkIf (config.cats.gitPlugins or false) { + config.specs.gitPlugins-lazy = { lazy = true; - data = []; + data = [ ]; }; } diff --git a/modules/neovim.nix b/modules/neovim.nix index f4ca40f..ba0361c 100644 --- a/modules/neovim.nix +++ b/modules/neovim.nix @@ -7,18 +7,29 @@ inputs: ... }: { + # ============================================================================ + # IMPORTS + # ============================================================================ + # Import the base neovim wrapper module and all configuration modules + imports = [ wlib.wrapperModules.neovim - ./module/settings/cat-packages.nix ./module/specs/deps.nix ./module/specs/plugins.nix + ./module/specs/cats-enable.nix ./module/settings/core.nix ./module/settings/cats.nix ./module/settings/env.nix ./module/settings/hosts.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 { readOnly = true; 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.info.cats = config.cats; config.info.nixCats_config_location = config.settings.config_directory; diff --git a/overlays/default.nix b/overlays/default.nix index 5a4cc6c..821ff88 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -3,33 +3,39 @@ let lib = nixpkgs.lib; rOverlay = import ./r.nix {inherit inputs;}; - rNvimNixOverlay = inputs.r-nvim-nix.overlays.default; - pythonOverlay = import ./python.nix {inherit inputs;}; - pluginsOverlay = import ./plugins.nix {inherit inputs;}; + franOverlay = inputs.fran.overlays.default; + pythonOverlay = import ./python.nix inputs; + pluginsOverlay = import ./plugins.nix inputs; dependencyOverlays = [ rOverlay - rNvimNixOverlay pythonOverlay pluginsOverlay ]; 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 { inherit rOverlay - rNvimNixOverlay franOverlay pythonOverlay pluginsOverlay dependencyOverlays dependencyOverlay; + # Named exports for downstream composition. default = dependencyOverlay; dependencies = dependencyOverlays; + + overlays = { + inherit + rOverlay + franOverlay + pythonOverlay + pluginsOverlay + dependencyOverlays + dependencyOverlay; + default = dependencyOverlay; + dependencies = dependencyOverlays; + }; } diff --git a/overlays/r.nix b/overlays/r.nix index e736b77..2fb71c8 100644 --- a/overlays/r.nix +++ b/overlays/r.nix @@ -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 { 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 { inherit rpkgs; - baseRPackages = [rpkgs.nvimcom]; - rWrapper = rpkgs.rWrapper.override {packages = [];}; - quarto = rpkgs.quarto.override {extraRPackages = [];}; + baseRPackages = reqPkgs; + + # 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;}; } diff --git a/plugin/00_options.lua b/plugin/00_options.lua index e824333..2b4485b 100644 --- a/plugin/00_options.lua +++ b/plugin/00_options.lua @@ -176,7 +176,7 @@ if vim.g.neovide then vim.g.neovide_cursor_short_animation_length = 0 vim.g.neovide_font_hinting = 'none' 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.keymap.set("n", "nf", "NeovideFullscreen", { desc = "Toggle Neovide Fullscreen" }) end 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/20_startup.lua b/plugin/20_startup.lua index 0404b2c..ca18bd8 100644 --- a/plugin/20_startup.lua +++ b/plugin/20_startup.lua @@ -390,25 +390,23 @@ end) -- zk now_if_args(function() - if nix.get_cat("markdown", false) then - require("zk").setup({ - picker = "minipick", - lsp = { - -- `config` is passed to `vim.lsp.start_client(config)` - config = { - cmd = { "zk", "lsp" }, - name = "zk", - -- on_attach = ... - -- etc, see `:h vim.lsp.start_client()` - }, - - -- automatically attach buffers in a zk notebook that match the given filetypes - auto_attach = { - enabled = true, - filetypes = { "markdown" }, - }, - + require("zk").setup({ + picker = "minipick", + lsp = { + -- `config` is passed to `vim.lsp.start_client(config)` + config = { + cmd = { "zk", "lsp" }, + name = "zk", + -- on_attach = ... + -- etc, see `:h vim.lsp.start_client()` }, - }) - end + + -- automatically attach buffers in a zk notebook that match the given filetypes + auto_attach = { + enabled = true, + filetypes = { "markdown" }, + }, + + }, + }) end) diff --git a/plugin/21_datascience.lua b/plugin/21_datascience.lua index aeab360..118ee20 100644 --- a/plugin/21_datascience.lua +++ b/plugin/21_datascience.lua @@ -44,12 +44,6 @@ end) -- r now(function() 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 require("r").setup({ -- Create a table with the options to be passed to setup() @@ -61,7 +55,7 @@ now(function() min_editor_width = 80, rconsole_height = 20, nvimpager = "split_h", - pdfviewer = "", + pdfviewer = "zathura", }) end end) @@ -71,45 +65,41 @@ end) now(function() vim.treesitter.language.register("markdown", { "quarto", "rmd" }) - if nix.get_cat({ "r", "markdown" }, false) then - vim.api.nvim_create_autocmd("FileType", { - pattern = { "quarto" }, - callback = function() - require("otter").activate() - end, - }) + vim.api.nvim_create_autocmd("FileType", { + pattern = { "quarto" }, + callback = function() + require("otter").activate() + end, + }) - require("otter").setup({ - lsp = { - diagnostic_update_events = { "BufWritePost", "InsertLeave" }, - }, - buffers = { - set_filetype = true, - write_to_disk = true, - }, - }) - end + require("otter").setup({ + lsp = { + diagnostic_update_events = { "BufWritePost", "InsertLeave" }, + }, + buffers = { + set_filetype = true, + write_to_disk = true, + }, + }) end) later(function() - if nix.get_cat({ "r", "markdown" }, false) then - require("quarto").setup({ - lspFeatures = { + require("quarto").setup({ + lspFeatures = { + enabled = true, + chunks = "curly", + languages = { "r", "python", "julia" }, + diagnostics = { enabled = true, - chunks = "curly", - languages = { "r", "python", "julia" }, - diagnostics = { - enabled = true, - triggers = { "BufWritePost" }, - }, - completion = { - enabled = true, - }, + triggers = { "BufWritePost" }, }, - codeRunner = { + completion = { enabled = true, - default_method = "slime", }, - }) - end + }, + codeRunner = { + enabled = true, + default_method = "slime", + }, + }) end) diff --git a/plugin/22_languages.lua b/plugin/22_languages.lua index ed4682a..1983b25 100644 --- a/plugin/22_languages.lua +++ b/plugin/22_languages.lua @@ -1,7 +1,6 @@ local add = Config.add local now_if_args = Config.now_if_args local later = MiniDeps.later -local nix = require('config.nix') if not Config.isNixCats then local m_add = MiniDeps.add @@ -13,21 +12,19 @@ end -- lua later(function() - if nix.get_cat("lua", false) then - add("luvit-meta") - add("lazydev") - require("lazydev").setup({ - library = { - -- See the configuration section for more details - -- Load luvit types when the `vim.uv` word is found - "lua", - "mini.nvim", - "MiniDeps", - { path = "luvit-meta/library", words = { "vim%.uv" } }, - { path = "${3rd}/luv/library", words = { "vim%.uv" } }, - }, - }) - end + add("luvit-meta") + add("lazydev") + require("lazydev").setup({ + library = { + -- See the configuration section for more details + -- Load luvit types when the `vim.uv` word is found + "lua", + "mini.nvim", + "MiniDeps", + { path = "luvit-meta/library", words = { "vim%.uv" } }, + { path = "${3rd}/luv/library", words = { "vim%.uv" } }, + }, + }) end) -- Markdown diff --git a/plugin/25_lsp.lua b/plugin/25_lsp.lua index f3c4c50..8c67295 100644 --- a/plugin/25_lsp.lua +++ b/plugin/25_lsp.lua @@ -15,17 +15,17 @@ now_if_args(function() marksman = { filetypes = { "markdown", "markdown_inline", "codecompanion" }, }, - r_ls = { - filetypes = { 'r', 'rmd', 'rmarkdown' }, - settings = { - ['r_ls'] = { - lsp = { - rich_documentation = true, - enable = true, - }, - }, - } - }, + -- r_language_server = { + -- filetypes = { 'r', 'rmd', 'rmarkdown' }, + -- settings = { + -- ['r_language_server'] = { + -- lsp = { + -- rich_documentation = true, + -- enable = true, + -- }, + -- }, + -- } + -- }, julials = { settings = { julia = { 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