diff --git a/.github/workflows/update.yml b/.github/workflows/update.yml index 96cb868..a42ac30 100644 --- a/.github/workflows/update.yml +++ b/.github/workflows/update.yml @@ -22,6 +22,7 @@ jobs: name: rde authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' extraPullNames: rstats-on-nix, nix-community + - run: cd templates/rde/ && nix develop -c p-updateDeps - name: Update ed flake.lock uses: DeterminateSystems/update-flake-lock@v28 with: diff --git a/templates/ed/README.md b/templates/ed/README.md deleted file mode 100644 index 272d827..0000000 --- a/templates/ed/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# Project Editor - -A per-project Neovim wrapper built with [nix-wrapper-modules](https://birdeehub.github.io/nix-wrapper-modules/) and [nvimConfig](https://github.com/dwinkler1/nvimConfig). - -## Setup - -The flake provides two entry points: - -| Command | What you get | -|---|---| -| `direnv allow` / `nix develop` | **(Recommended)** A shell with `nv` and all enabled language toolchains (R, Python, Julia, Quarto) on `PATH`. | -| `nix run` | Launches only the `nv` editor. Language toolchains (R, Python, etc.) are **not** on `PATH`. | - -### With direnv (recommended) - -```bash -direnv allow # enter the devShell automatically -nv # launch the pre-configured Neovim -R # R REPL is available (if enabled in flake.nix) -``` - -### Without direnv - -```bash -nix develop # enter the devShell manually -nv # launch Neovim -R # R REPL is available (if enabled in flake.nix) -``` - -> **Why `nix run` only gives the editor:** The flake's `packages.default` is the wrapped Neovim binary. Language toolchains (R, radian, quarto, etc.) live in `devShells.default`. Use `nix develop` (or `direnv allow`) to get the full environment. - -## Configuration - -The `flake.nix` is the single source of truth. Key knobs: - -| Option | What it controls | -|---|---| -| `cats` | Toggle language support (nix, r, python, julia, etc.) | -| `settings.lang_packages.` | Language-specific packages installed in the wrapper | -| `settings.colorscheme` | Neovim colorscheme | -| `settings.background` | `"dark"` or `"light"` | -| `settings.wrapRc` | When `true`, init.lua is embedded (rebuild to change); when `false`, init.lua is external (reload without rebuild) | -| `binName` | The wrapper binary name (`nv` by default) | -| `env` | Environment variables set in the wrapper | -| `extraPackages` | Extra system packages available in the wrapper's PATH | -| `specs.extraLua` | Inject lazy.nvim plugin specs | - -### Adding packages without editing flake.nix - -Create any of these optional files in the project root to add dependencies without modifying `flake.nix`: - -- **`python-packages.nix`** — receives `python3Packages`, return a list of packages: - ```nix - p: with p; [ numpy scipy ] - ``` - -- **`r-packages.nix`** — receives `rpkgs` (includes `rPackages`), return a list: - ```nix - p: with p.rPackages; [ ggplot2 data.table ] - ``` - -- **`julia-packages.nix`** — no arguments, return a list of package name strings: - ```nix - [ "DataFrames" "Plots" ] - ``` - -## Formatting - -```bash -nix fmt -``` - -Uses `nixfmt-rfc-style` pinned via the flake's `formatter` output. diff --git a/templates/ed/flake.lock b/templates/ed/flake.lock index 19c77b2..8da8614 100644 --- a/templates/ed/flake.lock +++ b/templates/ed/flake.lock @@ -22,11 +22,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1778869304, - "narHash": "sha256-30sZNZoA1cqF5JNO9fVX+wgiQYjB7HJqqJ4ztCDeBZE=", + "lastModified": 1776877367, + "narHash": "sha256-EHq1/OX139R1RvBzOJ0aMRT3xnWyqtHBRUBuO1gFzjI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d233902339c02a9c334e7e593de68855ad26c4cb", + "rev": "0726a0ecb6d4e08f6adced58726b95db924cef57", "type": "github" }, "original": { @@ -45,19 +45,20 @@ "nixpkgs" ], "plugins-cmp-pandoc-references": "plugins-cmp-pandoc-references", - "plugins-r": "plugins-r", - "r-nvim-nix": "r-nvim-nix", + "plugins-r": [ + "plugins-r" + ], "rixpkgs": [ "rixpkgs" ], "wrappers": "wrappers" }, "locked": { - "lastModified": 1779362150, - "narHash": "sha256-y3JTpxmNgtEYG1m21Ymvdmrul/WvJzOCX45AlV21aak=", + "lastModified": 1776413627, + "narHash": "sha256-pU3u7T4MqpjUWxflNvd4i47FURp756L7nMRL8MV+QEw=", "owner": "dwinkler1", "repo": "nvimConfig", - "rev": "af6d975129768cce36ac4c46198ab2b3ebaafad3", + "rev": "2617face3b1be40534d2cae7f0a374a062b3710d", "type": "github" }, "original": { @@ -85,45 +86,20 @@ "plugins-r": { "flake": false, "locked": { - "lastModified": 1776905071, - "narHash": "sha256-dXox6qEs1VDE7vPNDoN8bY4g06uj1IEs6uki72w8lpA=", + "lastModified": 1769881528, + "narHash": "sha256-oQSHHu6filJkAyH94yEvyTVuxA+5MU2dMOEAnsIjJKQ=", "owner": "R-nvim", "repo": "R.nvim", - "rev": "582f2af11290ac067e49018db38e12a511325556", + "rev": "958b472d763cb258927c7ef69af4fd9945cc5469", "type": "github" }, "original": { "owner": "R-nvim", - "ref": "v0.99.4", + "ref": "v0.99.3", "repo": "R.nvim", "type": "github" } }, - "r-nvim-nix": { - "inputs": { - "nixpkgs": [ - "nvimConfig", - "rixpkgs" - ], - "rnvimsrc": [ - "nvimConfig", - "plugins-r" - ] - }, - "locked": { - "lastModified": 1778684156, - "narHash": "sha256-Z4y1tQfkIsPK4NRxGn668HMDfWxnxNxSJ0CAOOXiIfY=", - "owner": "dwinkler1", - "repo": "r_nvim_nix", - "rev": "2f49dfee27886068e2f49cbd54558ce4cc424c82", - "type": "github" - }, - "original": { - "owner": "dwinkler1", - "repo": "r_nvim_nix", - "type": "github" - } - }, "rixpkgs": { "locked": { "lastModified": 1771303851, @@ -135,8 +111,8 @@ }, "original": { "owner": "dwinkler1", + "ref": "nixpkgs", "repo": "rixpkgs", - "rev": "af2dd3f7b4b172077747c0869d4e30702fb71b0e", "type": "github" } }, @@ -145,6 +121,7 @@ "fran": "fran", "nixpkgs": "nixpkgs", "nvimConfig": "nvimConfig", + "plugins-r": "plugins-r", "rixpkgs": "rixpkgs" } }, @@ -156,11 +133,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/templates/ed/flake.nix b/templates/ed/flake.nix index b674c62..08a618d 100644 --- a/templates/ed/flake.nix +++ b/templates/ed/flake.nix @@ -7,184 +7,115 @@ nvimConfig, ... } @ inputs: let - # ── Shared language support flags ────────────────────────────── - # Used by both the neovim wrapper module and the devShell - cats = { - clickhouse = false; - gitPlugins = false; - julia = false; - lua = false; - markdown = false; - nix = true; - optional = false; - python = false; - r = false; + projectSettings = {pkgs}: { + cats = { + clickhouse = false; + gitPlugins = false; + julia = false; + lua = false; + markdown = false; + nix = true; + optional = false; + python = false; + r = false; + }; + + settings = let + # With `replace` packages are replaced otherwise they are merged with base packages + replace = pkgs.lib.mkForce; + in { + lang_packages = { + python = replace ( + (with pkgs.python3Packages; [ + duckdb + polars + ]) + ++ ( + if builtins.pathExists ./python-packages.nix + # p: with p; [ ... ] + then import ./python-packages.nix pkgs.python3Packages + else [] + ) + ); + + r = replace ( + (with pkgs.rpkgs.rPackages; [ + fixest + # pkgs.extraRPackages.musicMetadata + ]) + ++ ( + if builtins.pathExists ./r-packages.nix + # p: with p.rPackages; [ ... ] + then import ./r-packages.nix pkgs.rpkgs + else [] + ) + ); + + julia = replace ([ + "StatsBase" + ] + ++ ( + if builtins.pathExists ./julia-packages.nix + # [ ... ] + then import ./julia-packages.nix + else [] + )); + }; + colorscheme = "kanagawa"; + background = "dark"; + wrapRc = true; + }; + binName = "vv"; + + env = { + IS_PROJECT_EDITOR = "1"; + R_LIBS_USER = "./.nvimcom"; + }; + + extraPackages = with pkgs; [ + cowsay + ]; + + specs.extraLua = let + name = builtins.baseNameOf (builtins.toString ./.); + in { + data = pkgs.vimPlugins.mini-notify; + before = ["INIT_MAIN"]; + config = '' + require("mini.notify").setup() + vim.notify = MiniNotify.make_notify() + vim.notify("Welcome to ${name}!") + ''; + }; }; - # ── Language package lists ──────────────────────────────────── - # Shared between wrapper lang_packages and devShell toolchains. - # Accept pkgs so they work inside forAllSystems for each system. - - rPackages = pkgs: - (with pkgs.rpkgs.rPackages; [ - fixest - # pkgs.extraRPackages.musicMetadata - ]) - ++ ( - if builtins.pathExists ./r-packages.nix - # p: with p.rPackages; [ ... ] - then import ./r-packages.nix pkgs.rpkgs - else [] - ); - - pythonPackages = pkgs: - (with pkgs.python3Packages; [ - duckdb - polars - ]) - ++ ( - if builtins.pathExists ./python-packages.nix - # p: with p; [ ... ] - then import ./python-packages.nix pkgs.python3Packages - else [] - ); - - juliaPackages = - ["StatsBase"] - ++ ( - if builtins.pathExists ./julia-packages.nix - # [ ... ] - then import ./julia-packages.nix - else [] - ); - - systems = ["aarch64-darwin" "x86_64-linux" "aarch64-linux"]; + systems = nixpkgs.lib.systems.flakeExposed; forAllSystems = nixpkgs.lib.genAttrs systems; overlays = [inputs.nvimConfig.overlays.dependencies]; in { - formatter = forAllSystems (system: nixpkgs.legacyPackages.${system}.nixfmt-rfc-style); - packages = forAllSystems (system: let - pkgs = import nixpkgs { - inherit system overlays; - config = {allowUnfree = true;}; - }; - # Plain attrset — pkgs is captured from the surrounding scope, - # so the module system does not need lazy _module.args resolution. - projectSettings = { - inherit cats; - settings = let - # With `replace` packages are replaced otherwise they are merged with base packages - replace = pkgs.lib.mkForce; - in { - lang_packages = { - python = replace (pythonPackages pkgs); - r = replace (rPackages pkgs); - julia = replace juliaPackages; - }; - colorscheme = "kanagawa"; - background = "dark"; - wrapRc = true; - }; - binName = "nv"; + pkgs = import nixpkgs {inherit system overlays;}; + baseNvim = nvimConfig.packages.${system}.default; - env = { - IS_PROJECT_EDITOR = "1"; - }; - - runtimePkgs = with pkgs; [ - cowsay - ]; - - specs.extraLua = let - name = builtins.baseNameOf (builtins.toString ./.); - in { - data = pkgs.vimPlugins.mini-notify; - before = ["INIT_MAIN"]; - config = '' - require("mini.notify").setup() - vim.notify = MiniNotify.make_notify() - vim.notify("Welcome to ${name}!") - ''; - }; - }; - evalResult = nvimConfig.inputs.wrappers.lib.evalModules { - modules = [ - nvimConfig.wrapperModules.default - projectSettings - ]; - }; + nvim = (baseNvim.eval (projectSettings {inherit pkgs;})).config.wrapper; + default = nvim; in { - default = evalResult.config.wrap {inherit pkgs;}; + default = nvim; }); devShells = forAllSystems (system: let - pkgs = import nixpkgs { - inherit system overlays; - config = {allowUnfree = true;}; - }; + pkgs = import nixpkgs {inherit system overlays;}; nv = self.packages.${system}.default; in { default = pkgs.mkShell { - shellHook = '' - exec nu - alias gst='git status' - alias glol='git log --oneline --graph --decorate' - alias gc='git commit' - alias gl='git pull' - alias gp='git push' - ''; - packages = - [ - nv - pkgs.git - pkgs.pre-commit - pkgs.nushell - ] - # ── R toolchain (R REPL, quarto, LSP, formatter) ───── - ++ pkgs.lib.optionals cats.r (let - r_packages = (pkgs.baseRPackages or []) ++ rPackages pkgs; - in [ - (pkgs.rWrapper.override {packages = r_packages;}) - pkgs.radianWrapper - pkgs.air-formatter - pkgs.yaml-language-server - pkgs.nvimcom - pkgs.rnvimserver - ]) - # ── Python toolchain (interpreter, LSP, formatter) ──── - ++ pkgs.lib.optionals cats.python [ - (pkgs.python3.withPackages (ps: pkgs.basePythonPackages ps ++ pythonPackages pkgs)) - pkgs.nodejs - pkgs.ruff - pkgs.basedpyright - pkgs.uv - ] - # ── Julia toolchain ─────────────────────────────────── - ++ pkgs.lib.optionals cats.julia [ - pkgs.julia-bin.withPackages - juliaPackages - ] - # ── Markdown toolchain (quarto, zk) ─────────────────── - ++ (let - r_packages = (pkgs.baseRPackages or []) ++ rPackages pkgs; - quarto = - if cats.r - then pkgs.quarto.override {extraRPackages = r_packages;} - else pkgs.quarto; - in - pkgs.lib.optionals cats.markdown [ - pkgs.python313Packages.pylatexenc - quarto - pkgs.zk - ]); + packages = [nv pkgs.updateR]; }; }); }; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - rixpkgs.url = "github:dwinkler1/rixpkgs/af2dd3f7b4b172077747c0869d4e30702fb71b0e"; + rixpkgs.url = "github:dwinkler1/rixpkgs/nixpkgs"; fran = { url = "github:dwinkler1/fran"; inputs = { @@ -197,7 +128,12 @@ rixpkgs.follows = "rixpkgs"; nixpkgs.follows = "nixpkgs"; fran.follows = "fran"; + "plugins-r".follows = "plugins-r"; }; }; + "plugins-r" = { + url = "github:R-nvim/R.nvim/v0.99.3"; + flake = false; + }; }; } diff --git a/templates/rde/flake.nix b/templates/rde/flake.nix index 12ae4f0..27e3f5a 100644 --- a/templates/rde/flake.nix +++ b/templates/rde/flake.nix @@ -185,6 +185,10 @@ julia = config.enabledLanguages.julia; python = config.enabledLanguages.python; r = config.enabledLanguages.r; + # Enable markdown/quarto plugins whenever R is active so that + # .qmd buffers get proper syntax highlighting and chunk + # recognition via quarto-nvim and otter-nvim. + markdown = config.enabledLanguages.r; project = true; gitPlugins = config.enabledPackages.gitPlugins; background = config.theme.background; @@ -202,11 +206,22 @@ # Development shell configuration devShells = forSystems (system: let pkgs = import nixpkgs {inherit system;}; + # When R is enabled, build an overlaid pkgs that includes the R-enhanced + # quarto (with knitr and other R packages baked in via extraRPackages). + # This ensures `quarto render` from the terminal also works correctly. + rPkgs = + if config.enabledLanguages.r + then + import nixpkgs { + inherit system; + overlays = [rixOverlay rOverlay]; + } + else pkgs; # Language-specific packages that should be available in shell - languagePackages = with pkgs; + languagePackages = [] - ++ (if config.enabledLanguages.r then [quarto] else []) - ++ (if config.enabledLanguages.python then [uv] else []) + ++ (if config.enabledLanguages.r then [rPkgs.quarto] else []) + ++ (if config.enabledLanguages.python then [pkgs.uv] else []) ++ (if config.enabledLanguages.julia then [] else []); in { default = pkgs.mkShell { diff --git a/templates/rde/overlays/r.nix b/templates/rde/overlays/r.nix index 255079b..13415ba 100644 --- a/templates/rde/overlays/r.nix +++ b/templates/rde/overlays/r.nix @@ -18,8 +18,10 @@ final: prev: let broom # Tidy model outputs data_table # Fast data manipulation janitor # Data cleaning helpers + knitr # Required by Quarto to execute R code chunks languageserver # LSP for IDE support reprex # Reproducible examples + rmarkdown # Required by Quarto for R-based rendering styler # Code formatting tidyverse # Data science ecosystem ]