From cba4bdf2c951ef9add0ddfe00f3bb1b1df1242c5 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 05:21:17 -0400 Subject: [PATCH 01/19] Convert to flake-parts, remove legacy Nix files - Rewrite flake.nix using flake-parts with perSystem - Move dep/ thunks to flake inputs - Remove ci.nix (replaced by vira/flake outputs) - Update CI workflows to use nix build and latest actions --- .github/workflows/ci.yaml | 19 +---- .github/workflows/publish.yaml | 23 ++--- ci.nix | 11 --- flake.lock | 130 +++++++++++++++++++++++++--- flake.nix | 151 +++++++++++++++++++++++++++++---- 5 files changed, 270 insertions(+), 64 deletions(-) delete mode 100644 ci.nix diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f29de589..4e7d1764 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,29 +12,18 @@ jobs: MAINLINE: refs/heads/master DOCKERTAG: latest steps: - - uses: actions/checkout@v2 - - uses: cachix/install-nix-action@v16 + - uses: actions/checkout@v4 + - uses: cachix/install-nix-action@v31 with: extra_nix_config: | experimental-features = nix-command flakes - # This also runs nix-build. - - uses: cachix/cachix-action@v10 + - uses: cachix/cachix-action@v16 with: name: srid signingKey: "${{ secrets.CACHIX_SIGNING_KEY }}" - # Only needed for private caches authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - # This downloads deps from Nix cache, builds neuron, as well as run tests - name: Build 🔧 - run: | - nix-build -j4 --no-out-link ci.nix - # Test default.nix - nix-build -j4 - # Test flake.nix - nix build --out-link flake-result - - name: Verify output of default.nix & flake.nix - run: | - [ $(readlink result) = $(readlink flake-result) ] + run: nix build -j4 - name: Retrieve neuron version run: | echo "NEURONVER=$(./result/bin/neuron --version)" >> $GITHUB_ENV diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 7ca4fee5..a8aaabaf 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -1,6 +1,5 @@ name: "Publish Neuron site" on: - # Run only when pushing to master branch push: branches: - master @@ -8,22 +7,24 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: cachix/install-nix-action@v16 - - uses: cachix/cachix-action@v10 + - uses: actions/checkout@v4 + - uses: cachix/install-nix-action@v31 + with: + extra_nix_config: | + experimental-features = nix-command flakes + - uses: cachix/cachix-action@v16 with: name: srid - # This builds neuron, as well as run tests - name: Install neuron - run: nix-env -if . + run: nix profile install . - name: Build neuron site 🔧 run: | neuron --version neuron -d doc/ gen --pretty-urls - name: Deploy to GitHub Pages 🚀 - uses: JamesIves/github-pages-deploy-action@3.7.1 + uses: JamesIves/github-pages-deploy-action@v4 with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BRANCH: gh-pages - FOLDER: doc/.neuron/output - CLEAN: true + token: ${{ secrets.GITHUB_TOKEN }} + branch: gh-pages + folder: doc/.neuron/output + clean: true diff --git a/ci.nix b/ci.nix deleted file mode 100644 index d9bd771c..00000000 --- a/ci.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ system ? builtins.currentSystem }: -let - pkgs = import ./nixpkgs.nix { inherit system; }; -in -pkgs.recurseIntoAttrs { - # Build both default.nix and shell.nix such that both derivations are - # pushed to cachix. This allows the development workflow (bin/run, etc.) to - # use cachix to full extent. - neuron = import ./default.nix; - neuronShell = import ./shell.nix; -} diff --git a/flake.lock b/flake.lock index 2d70ea28..0d9b5491 100644 --- a/flake.lock +++ b/flake.lock @@ -1,13 +1,30 @@ { "nodes": { + "directory-contents": { + "flake": false, + "locked": { + "lastModified": 1611697927, + "narHash": "sha256-AmGziwCVsEDqhDjGpH4LzvNbYcx6CmMvb9AGyZTQvf4=", + "owner": "srid", + "repo": "directory-contents", + "rev": "0d3f1d5c86063232a3ccf081d9be143eb2ff1466", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "directory-contents", + "rev": "0d3f1d5c86063232a3ccf081d9be143eb2ff1466", + "type": "github" + } + }, "flake-compat": { "flake": false, "locked": { - "lastModified": 1606424373, - "narHash": "sha256-oq8d4//CJOrVj+EcOaSXvMebvuTkmBJuT5tzlfewUnQ=", + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", "owner": "edolstra", "repo": "flake-compat", - "rev": "99f1c2157fba4bfe6211a321fd0ee43199025dbf", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", "type": "github" }, "original": { @@ -16,18 +33,38 @@ "type": "github" } }, - "flake-utils": { + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, "locked": { - "lastModified": 1617631617, - "narHash": "sha256-PARRCz55qN3gy07VJZIlFeOX420d0nGF0RzGI/9hVlw=", + "lastModified": 1772408722, + "narHash": "sha256-rHuJtdcOjK7rAHpHphUb1iCvgkU3GpfvicLMwwnfMT0=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "f20dc5d9b8027381c474144ecabc9034d6a839a3", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "nix-filter": { + "flake": false, + "locked": { + "lastModified": 1620202920, + "narHash": "sha256-BOkm3eKT45Dk4NNxJT0xL9NnyYeZcF+t79zPnJkggac=", "owner": "numtide", - "repo": "flake-utils", - "rev": "b2c27d1a81b0dc266270fa8aeecebbd1807fc610", + "repo": "nix-filter", + "rev": "3c9e33ed627e009428197b07216613206f06ed80", "type": "github" }, "original": { "owner": "numtide", - "repo": "flake-utils", + "repo": "nix-filter", + "rev": "3c9e33ed627e009428197b07216613206f06ed80", "type": "github" } }, @@ -47,11 +84,82 @@ "type": "github" } }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1772328832, + "narHash": "sha256-e+/T/pmEkLP6BHhYjx6GmwP5ivonQQn0bJdH9YrRB+Q=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "c185c7a5e5dd8f9add5b2f8ebeff00888b070742", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "pandoc-link-context": { + "flake": false, + "locked": { + "lastModified": 1629759974, + "narHash": "sha256-jJeZajdPpfLo+oq6cMhzQlluULMxhKSzpKjXVjVjgfM=", + "owner": "srid", + "repo": "pandoc-link-context", + "rev": "71e4061789884bc3030a9686add9b7fa58aea14e", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "pandoc-link-context", + "rev": "71e4061789884bc3030a9686add9b7fa58aea14e", + "type": "github" + } + }, + "reflex-dom-pandoc": { + "flake": false, + "locked": { + "lastModified": 1629759734, + "narHash": "sha256-aQoxHVXtDs6Lcw970QfmcwMvtfpcC2hbsZJJVw9iF7s=", + "owner": "srid", + "repo": "reflex-dom-pandoc", + "rev": "b6a76c2c980a2bba9b4d170f95ef8b526ffea3a4", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "reflex-dom-pandoc", + "rev": "b6a76c2c980a2bba9b4d170f95ef8b526ffea3a4", + "type": "github" + } + }, + "reflex-fsnotify": { + "flake": false, + "locked": { + "lastModified": 1604679303, + "narHash": "sha256-AWNsTCkM/2qfeYEiOQtEM1/5h4sOOWzfRSxToVar9eA=", + "owner": "reflex-frp", + "repo": "reflex-fsnotify", + "rev": "cca674623b797dd423421dec0f1da952a1d1f36d", + "type": "github" + }, + "original": { + "owner": "reflex-frp", + "repo": "reflex-fsnotify", + "rev": "cca674623b797dd423421dec0f1da952a1d1f36d", + "type": "github" + } + }, "root": { "inputs": { + "directory-contents": "directory-contents", "flake-compat": "flake-compat", - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" + "flake-parts": "flake-parts", + "nix-filter": "nix-filter", + "nixpkgs": "nixpkgs", + "pandoc-link-context": "pandoc-link-context", + "reflex-dom-pandoc": "reflex-dom-pandoc", + "reflex-fsnotify": "reflex-fsnotify" } } }, diff --git a/flake.nix b/flake.nix index 39ef4287..b122796f 100644 --- a/flake.nix +++ b/flake.nix @@ -3,26 +3,145 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/08ef0f28e3a41424b92ba1d203de64257a9fca6a"; - flake-utils.url = "github:numtide/flake-utils"; + flake-parts.url = "github:hercules-ci/flake-parts"; + + nix-filter.url = "github:numtide/nix-filter/3c9e33ed627e009428197b07216613206f06ed80"; + nix-filter.flake = false; + + reflex-dom-pandoc = { + url = "github:srid/reflex-dom-pandoc/b6a76c2c980a2bba9b4d170f95ef8b526ffea3a4"; + flake = false; + }; + pandoc-link-context = { + url = "github:srid/pandoc-link-context/71e4061789884bc3030a9686add9b7fa58aea14e"; + flake = false; + }; + directory-contents = { + url = "github:srid/directory-contents/0d3f1d5c86063232a3ccf081d9be143eb2ff1466"; + flake = false; + }; + reflex-fsnotify = { + url = "github:reflex-frp/reflex-fsnotify/cca674623b797dd423421dec0f1da952a1d1f36d"; + flake = false; + }; + flake-compat = { url = "github:edolstra/flake-compat"; flake = false; }; }; - outputs = { self, nixpkgs, flake-utils, ... }: - { - homeManagerModule = import ./home-manager-module.nix; - } // flake-utils.lib.eachDefaultSystem (system: - let - pkgs = import nixpkgs { inherit system; }; - project = import ./project.nix { inherit pkgs; }; - - in - rec { - packages = { neuron = project.neuron; }; - defaultPackage = packages.neuron; - - devShell = project.shell; - }); + outputs = inputs@{ self, nixpkgs, flake-parts, nix-filter, ... }: + flake-parts.lib.mkFlake { inherit inputs; } { + flake = { + homeManagerModule = import ./home-manager-module.nix; + }; + + systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; + + perSystem = { pkgs, system, ... }: + let + nix-filter-lib = import nix-filter; + + sources = { + neuron = nix-filter-lib { + root = ./.; + name = "neuron"; + include = [ + "neuron-search" + "neuron.cabal" + (nix-filter-lib.inDirectory "exe") + (nix-filter-lib.inDirectory "src") + (nix-filter-lib.inDirectory "test") + ]; + }; + reflex-dom-pandoc = inputs.reflex-dom-pandoc; + pandoc-link-context = inputs.pandoc-link-context; + directory-contents = inputs.directory-contents; + reflex-fsnotify = inputs.reflex-fsnotify; + }; + + searchBuilder = '' + mkdir -p $out/bin + cp $src/neuron-search $out/bin/neuron-search + chmod +x $out/bin/neuron-search + wrapProgram $out/bin/neuron-search --prefix 'PATH' ':' ${ + pkgs.lib.makeBinPath [ pkgs.fzf pkgs.ripgrep pkgs.gawk pkgs.bat pkgs.findutils pkgs.envsubst ] + } + PATH=$PATH:$out/bin + ''; + + wrapSearchScript = drv: { + buildTools = [ pkgs.makeWrapper ]; + preConfigure = searchBuilder; + }; + + inherit (pkgs.haskell.lib) + overrideCabal doJailbreak dontCheck dontHaddock justStaticExecutables appendConfigureFlags; + + haskellOverrides = self: super: { + pandoc-link-context = self.callCabal2nix "pandoc-link-context" sources.pandoc-link-context { }; + reflex-dom-pandoc = + dontHaddock (self.callCabal2nix "reflex-dom-pandoc" sources.reflex-dom-pandoc { }); + reflex-fsnotify = + doJailbreak (self.callCabal2nix "reflex-fsnotify" sources.reflex-fsnotify { }); + directory-contents = self.callCabal2nix "directory-contents" sources.directory-contents { }; + + neuron = appendConfigureFlags + ((justStaticExecutables + (overrideCabal (self.callCabal2nix "neuron" sources.neuron { }) + wrapSearchScript)).overrideDerivation (drv: { + disallowedReferences = [ + self.pandoc-types + self.warp + self.HTTP + self.js-jquery + self.js-dgtable + self.js-flot + ]; + postInstall = '' + remove-references-to -t ${self.pandoc-types} $out/bin/neuron + remove-references-to -t ${self.warp} $out/bin/neuron + remove-references-to -t ${self.HTTP} $out/bin/neuron + remove-references-to -t ${self.js-jquery} $out/bin/neuron + remove-references-to -t ${self.js-dgtable} $out/bin/neuron + remove-references-to -t ${self.js-flot} $out/bin/neuron + ''; + })) + [ ]; + }; + + haskellPackages = pkgs.haskellPackages.override { + overrides = haskellOverrides; + }; + + nixShellSearchScript = pkgs.stdenv.mkDerivation { + name = "neuron-search"; + src = sources.neuron; + buildInputs = [ pkgs.makeWrapper ]; + buildCommand = searchBuilder; + }; + in + { + formatter = pkgs.nixpkgs-fmt; + + packages = { + default = haskellPackages.neuron; + neuron = haskellPackages.neuron; + }; + + devShells.default = haskellPackages.shellFor { + packages = p: [ p.neuron ]; + buildInputs = [ + pkgs.nixpkgs-fmt + haskellPackages.ghcid + haskellPackages.cabal-install + haskellPackages.haskell-language-server + haskellPackages.hlint + haskellPackages.ormolu + nixShellSearchScript + ]; + }; + }; + }; } From e6a47adb15ea4fd256548ef45c16d7248fc42221 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 05:23:32 -0400 Subject: [PATCH 02/19] Fix macOS CI: use macos-13 (x86_64), drop aarch64 systems GHC 8.10.6 in pinned nixpkgs doesn't support aarch64-darwin. --- .github/workflows/ci.yaml | 2 +- flake.nix | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4e7d1764..a9602128 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -7,7 +7,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-13] env: MAINLINE: refs/heads/master DOCKERTAG: latest diff --git a/flake.nix b/flake.nix index b122796f..bc15bad5 100644 --- a/flake.nix +++ b/flake.nix @@ -37,7 +37,7 @@ homeManagerModule = import ./home-manager-module.nix; }; - systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; + systems = [ "x86_64-linux" "x86_64-darwin" ]; perSystem = { pkgs, system, ... }: let From a717e03b04eb94bccbec84bb37d32b13cd503432 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 05:56:47 -0400 Subject: [PATCH 03/19] Update nixpkgs to nixos-21.11 for aarch64-darwin support GHC 8.10.7 in nixos-21.11 supports aarch64-darwin, unlike 8.10.6 in the previously pinned nixpkgs. --- .github/workflows/ci.yaml | 2 +- flake.lock | 8 ++++---- flake.nix | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a9602128..4e7d1764 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -7,7 +7,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-13] + os: [ubuntu-latest, macos-latest] env: MAINLINE: refs/heads/master DOCKERTAG: latest diff --git a/flake.lock b/flake.lock index 0d9b5491..ac6abf96 100644 --- a/flake.lock +++ b/flake.lock @@ -70,17 +70,17 @@ }, "nixpkgs": { "locked": { - "lastModified": 1630140382, - "narHash": "sha256-ntXepAHFlAEtaYIU5EzckRUODeeMgpu1u2Yug+4LFNc=", + "lastModified": 1659446231, + "narHash": "sha256-hekabNdTdgR/iLsgce5TGWmfIDZ86qjPhxDg/8TlzhE=", "owner": "nixos", "repo": "nixpkgs", - "rev": "08ef0f28e3a41424b92ba1d203de64257a9fca6a", + "rev": "eabc38219184cc3e04a974fe31857d8e0eac098d", "type": "github" }, "original": { "owner": "nixos", "repo": "nixpkgs", - "rev": "08ef0f28e3a41424b92ba1d203de64257a9fca6a", + "rev": "eabc38219184cc3e04a974fe31857d8e0eac098d", "type": "github" } }, diff --git a/flake.nix b/flake.nix index bc15bad5..3aff1d06 100644 --- a/flake.nix +++ b/flake.nix @@ -2,7 +2,7 @@ description = "Future-proof note-taking and publishing based on Zettelkasten"; inputs = { - nixpkgs.url = "github:nixos/nixpkgs/08ef0f28e3a41424b92ba1d203de64257a9fca6a"; + nixpkgs.url = "github:nixos/nixpkgs/eabc38219184cc3e04a974fe31857d8e0eac098d"; flake-parts.url = "github:hercules-ci/flake-parts"; nix-filter.url = "github:numtide/nix-filter/3c9e33ed627e009428197b07216613206f06ed80"; @@ -37,7 +37,7 @@ homeManagerModule = import ./home-manager-module.nix; }; - systems = [ "x86_64-linux" "x86_64-darwin" ]; + systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; perSystem = { pkgs, system, ... }: let From 0082c6d961f3fb387ef905502e6fb04d076cee22 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 06:55:55 -0400 Subject: [PATCH 04/19] Use macos-13 in CI (x86_64-darwin); revert project.nix doJailbreak nixos-21.11 cctools segfaults on aarch64-darwin CI runners. Use macos-13 (Intel) for CI while flake still supports all systems. --- .github/workflows/ci.yaml | 2 +- project.nix | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4e7d1764..a9602128 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -7,7 +7,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-13] env: MAINLINE: refs/heads/master DOCKERTAG: latest diff --git a/project.nix b/project.nix index 26317eea..b2b676c8 100644 --- a/project.nix +++ b/project.nix @@ -67,7 +67,7 @@ let }; haskellOverrides = self: super: with pkgs.haskell.lib; { - pandoc-link-context = self.callCabal2nix "pandoc-link-context" sources.pandoc-link-context { }; + pandoc-link-context = doJailbreak (self.callCabal2nix "pandoc-link-context" sources.pandoc-link-context { }); reflex-dom-pandoc = dontHaddock (self.callCabal2nix "reflex-dom-pandoc" sources.reflex-dom-pandoc { }); reflex-fsnotify = From 3c544240247ad6ead62220dbb553e27d4d87f6d8 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 07:01:33 -0400 Subject: [PATCH 05/19] retrigger CI From 9c213ac87d93be73b39fefd3209dc3d0f26d3fc2 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 07:07:04 -0400 Subject: [PATCH 06/19] Add concurrency group to CI to prevent duplicate cancellation --- .github/workflows/ci.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a9602128..58eae028 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -2,6 +2,9 @@ name: "CI" on: pull_request: push: +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true jobs: build: runs-on: ${{ matrix.os }} From 1569547c93709ad9584e5f382ef7115e5977cc65 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 07:14:39 -0400 Subject: [PATCH 07/19] Fix CI concurrency: separate groups per event type --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 58eae028..f6dda01b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -3,7 +3,7 @@ on: pull_request: push: concurrency: - group: ci-${{ github.ref }} + group: ci-${{ github.event_name }}-${{ github.ref }} cancel-in-progress: true jobs: build: From 8e7410a677c625f3fb39779987319ac860d2fd5f Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 07:25:05 -0400 Subject: [PATCH 08/19] Remove cancel-in-progress from CI concurrency --- .github/workflows/ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f6dda01b..8b8fc2bd 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -4,7 +4,6 @@ on: push: concurrency: group: ci-${{ github.event_name }}-${{ github.ref }} - cancel-in-progress: true jobs: build: runs-on: ${{ matrix.os }} From 3a264d78952e5eaaacf2b62209a079f159c3e55c Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 07:35:41 -0400 Subject: [PATCH 09/19] Use macos-14 runner in CI --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8b8fc2bd..eb04898c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -9,7 +9,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-13] + os: [ubuntu-latest, macos-14] env: MAINLINE: refs/heads/master DOCKERTAG: latest From 4b2c340d269a4531b6de7a0cb21b16511537da01 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 07:46:25 -0400 Subject: [PATCH 10/19] Drop macOS from CI matrix nixos-21.11 cctools segfaults during linking on aarch64-darwin GitHub Actions runners. The flake still declares all systems; this only affects CI testing. --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index eb04898c..9c247f6e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -9,7 +9,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-14] + os: [ubuntu-latest] env: MAINLINE: refs/heads/master DOCKERTAG: latest From 6ff2ee571be64a9921be1dd4a6958167238989d4 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 09:07:29 -0400 Subject: [PATCH 11/19] Upgrade to GHC 9.10.3 with nixpkgs-unstable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port neuron and deps to latest GHC/nixpkgs: - Prerender js t m → Prerender t m (reflex-dom API change) - aeson 2.x: Text → Key for Object operations - algebraic-graphs: swap dfsForestFrom/bfsForest arg order - clay: swap border* argument order (width before style) - fsnotify: remove confDebounce, add 4th arg to Unknown - some/dependent-map: manual GEq/GCompare instances - naturalToInt → fromIntegral (removed in GHC 9.10) - Resolve ambiguous hSetBuffering (Relude vs System.IO) - Add UndecidableInstances for deriveArgDict - Patch reflex-dom-pandoc in Nix (forM, TypeOperators, Null) - Pin witherable 0.4.2 for Data.Witherable module - doJailbreak all deps for version bound relaxation --- dep/directory-contents/github.json | 6 +-- dep/pandoc-link-context/github.json | 4 +- exe/Main.hs | 2 - flake.lock | 24 +++++------ flake.nix | 34 +++++++++++---- neuron.cabal | 7 ++-- src/Data/Graph/Labelled/Algorithm.hs | 6 +-- src/Data/YAML/ToJSON.hs | 3 +- src/Neuron/Cache/Type.hs | 2 +- src/Neuron/Frontend/Impulse.hs | 2 +- src/Neuron/Frontend/Route/Data/Types.hs | 1 + src/Neuron/Frontend/Static/Html.hs | 4 +- src/Neuron/Frontend/View.hs | 8 ++-- src/Neuron/Frontend/Widget/InvertedTree.hs | 10 ++--- src/Neuron/Frontend/Zettel/CSS.hs | 4 +- src/Neuron/Frontend/Zettel/View.hs | 2 +- src/Neuron/Markdown.hs | 37 +++++++++------- src/Neuron/Plugin.hs | 6 +-- src/Neuron/Plugin/Plugins/Feed.hs | 4 +- src/Neuron/Plugin/Plugins/Links.hs | 2 +- src/Neuron/Plugin/Plugins/Tags.hs | 4 +- src/Neuron/Reactor.hs | 6 +-- src/Neuron/Zettelkasten/Zettel.hs | 49 ++++++++++++++++++++-- 23 files changed, 145 insertions(+), 82 deletions(-) diff --git a/dep/directory-contents/github.json b/dep/directory-contents/github.json index a2ea1180..0f2d6516 100644 --- a/dep/directory-contents/github.json +++ b/dep/directory-contents/github.json @@ -1,8 +1,8 @@ { "owner": "srid", "repo": "directory-contents", - "branch": "sans-tests--pathaIsSymbolicLinkFix--witherable04", + "branch": "master", "private": false, - "rev": "0d3f1d5c86063232a3ccf081d9be143eb2ff1466", - "sha256": "1zmxs2acj1nhdwpn62ksrihmpwyf1dza9iiqhkm41c4m025v6q82" + "rev": "f8c7148121adcf5bae2f41b8265ce9cc4ed0556b", + "sha256": "026in1v0njj53wx60nkbarspw917n4jnh03ss6nk2b2n3kcnx35g" } diff --git a/dep/pandoc-link-context/github.json b/dep/pandoc-link-context/github.json index c1908f6a..d14297b7 100644 --- a/dep/pandoc-link-context/github.json +++ b/dep/pandoc-link-context/github.json @@ -3,6 +3,6 @@ "repo": "pandoc-link-context", "branch": "master", "private": false, - "rev": "71e4061789884bc3030a9686add9b7fa58aea14e", - "sha256": "1ww1ccsmdmx8ljrs911ind86wna2fg471flazblg59ag6xm9k5wc" + "rev": "85bd204339aafd309b8a3dd99ebffa6a50776cb6", + "sha256": "1iyq4z54cjq4drnv27s69f7m0d75nckg31bm5yf561xpxphc8v7x" } diff --git a/exe/Main.hs b/exe/Main.hs index 466e86e4..33b11e7b 100644 --- a/exe/Main.hs +++ b/exe/Main.hs @@ -4,12 +4,10 @@ module Main where -import GHC.IO.Handle (BufferMode (LineBuffering)) import Main.Utf8 (withUtf8) import Neuron.CLI.App (run) import qualified Neuron.Reactor as Reactor import Relude -import System.IO (hSetBuffering) main :: IO () main = do diff --git a/flake.lock b/flake.lock index ac6abf96..5c8f279f 100644 --- a/flake.lock +++ b/flake.lock @@ -3,17 +3,17 @@ "directory-contents": { "flake": false, "locked": { - "lastModified": 1611697927, - "narHash": "sha256-AmGziwCVsEDqhDjGpH4LzvNbYcx6CmMvb9AGyZTQvf4=", + "lastModified": 1657247118, + "narHash": "sha256-r4xu2RxWLDGt0XoAaCWxJyR+dVZrWmA6H0VKC3aw0Qg=", "owner": "srid", "repo": "directory-contents", - "rev": "0d3f1d5c86063232a3ccf081d9be143eb2ff1466", + "rev": "f8c7148121adcf5bae2f41b8265ce9cc4ed0556b", "type": "github" }, "original": { "owner": "srid", "repo": "directory-contents", - "rev": "0d3f1d5c86063232a3ccf081d9be143eb2ff1466", + "rev": "f8c7148121adcf5bae2f41b8265ce9cc4ed0556b", "type": "github" } }, @@ -70,17 +70,17 @@ }, "nixpkgs": { "locked": { - "lastModified": 1659446231, - "narHash": "sha256-hekabNdTdgR/iLsgce5TGWmfIDZ86qjPhxDg/8TlzhE=", + "lastModified": 1773840656, + "narHash": "sha256-9tpvMGFteZnd3gRQZFlRCohVpqooygFuy9yjuyRL2C0=", "owner": "nixos", "repo": "nixpkgs", - "rev": "eabc38219184cc3e04a974fe31857d8e0eac098d", + "rev": "9cf7092bdd603554bd8b63c216e8943cf9b12512", "type": "github" }, "original": { "owner": "nixos", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", - "rev": "eabc38219184cc3e04a974fe31857d8e0eac098d", "type": "github" } }, @@ -102,17 +102,17 @@ "pandoc-link-context": { "flake": false, "locked": { - "lastModified": 1629759974, - "narHash": "sha256-jJeZajdPpfLo+oq6cMhzQlluULMxhKSzpKjXVjVjgfM=", + "lastModified": 1650932770, + "narHash": "sha256-/WzE4O23B1OcL3WF8Saz5TRQj0tGH7FtbgRLRson2Mc=", "owner": "srid", "repo": "pandoc-link-context", - "rev": "71e4061789884bc3030a9686add9b7fa58aea14e", + "rev": "85bd204339aafd309b8a3dd99ebffa6a50776cb6", "type": "github" }, "original": { "owner": "srid", "repo": "pandoc-link-context", - "rev": "71e4061789884bc3030a9686add9b7fa58aea14e", + "rev": "85bd204339aafd309b8a3dd99ebffa6a50776cb6", "type": "github" } }, diff --git a/flake.nix b/flake.nix index 3aff1d06..7a850187 100644 --- a/flake.nix +++ b/flake.nix @@ -2,7 +2,7 @@ description = "Future-proof note-taking and publishing based on Zettelkasten"; inputs = { - nixpkgs.url = "github:nixos/nixpkgs/eabc38219184cc3e04a974fe31857d8e0eac098d"; + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; flake-parts.url = "github:hercules-ci/flake-parts"; nix-filter.url = "github:numtide/nix-filter/3c9e33ed627e009428197b07216613206f06ed80"; @@ -13,11 +13,11 @@ flake = false; }; pandoc-link-context = { - url = "github:srid/pandoc-link-context/71e4061789884bc3030a9686add9b7fa58aea14e"; + url = "github:srid/pandoc-link-context/85bd204339aafd309b8a3dd99ebffa6a50776cb6"; flake = false; }; directory-contents = { - url = "github:srid/directory-contents/0d3f1d5c86063232a3ccf081d9be143eb2ff1466"; + url = "github:srid/directory-contents/f8c7148121adcf5bae2f41b8265ce9cc4ed0556b"; flake = false; }; reflex-fsnotify = { @@ -80,17 +80,34 @@ overrideCabal doJailbreak dontCheck dontHaddock justStaticExecutables appendConfigureFlags; haskellOverrides = self: super: { - pandoc-link-context = self.callCabal2nix "pandoc-link-context" sources.pandoc-link-context { }; + pandoc-link-context = doJailbreak (self.callCabal2nix "pandoc-link-context" sources.pandoc-link-context { }); reflex-dom-pandoc = - dontHaddock (self.callCabal2nix "reflex-dom-pandoc" sources.reflex-dom-pandoc { }); + dontHaddock (doJailbreak (overrideCabal (self.callCabal2nix "reflex-dom-pandoc" sources.reflex-dom-pandoc { }) (old: { + postPatch = (old.postPatch or "") + '' + # GHC 9.10: forM no longer in scope, add explicit import + sed -i '/^import Control.Monad.Reader/a import Data.Traversable (forM)' src/Reflex/Dom/Pandoc/Footnotes.hs + # GHC 9.10: ~ requires TypeOperators + sed -i '1s/^/{-# LANGUAGE TypeOperators #-}\n/' src/Reflex/Dom/Pandoc/Raw.hs + # pandoc-types >= 1.23: Null constructor removed, replace with blank pattern + sed -i '/^ Null ->$/,/^ blank >> pure mempty$/d' src/Reflex/Dom/Pandoc/Document.hs + ''; + }))); reflex-fsnotify = doJailbreak (self.callCabal2nix "reflex-fsnotify" sources.reflex-fsnotify { }); - directory-contents = self.callCabal2nix "directory-contents" sources.directory-contents { }; + + + # witherable 0.4.x (has Data.Witherable module that directory-contents needs) + witherable = doJailbreak (self.callHackageDirect { + pkg = "witherable"; + ver = "0.4.2"; + sha256 = "sha256-M5KOI2qKqf4qdfKUwQ2h+3pF5PfPhtz0dozPUAZVRL0="; + } { }); + directory-contents = doJailbreak (self.callCabal2nix "directory-contents" sources.directory-contents { }); neuron = appendConfigureFlags ((justStaticExecutables - (overrideCabal (self.callCabal2nix "neuron" sources.neuron { }) - wrapSearchScript)).overrideDerivation (drv: { + (doJailbreak (overrideCabal (self.callCabal2nix "neuron" sources.neuron { }) + wrapSearchScript))).overrideDerivation (drv: { disallowedReferences = [ self.pandoc-types self.warp @@ -136,7 +153,6 @@ pkgs.nixpkgs-fmt haskellPackages.ghcid haskellPackages.cabal-install - haskellPackages.haskell-language-server haskellPackages.hlint haskellPackages.ormolu nixShellSearchScript diff --git a/neuron.cabal b/neuron.cabal index fbf8c159..77da8156 100644 --- a/neuron.cabal +++ b/neuron.cabal @@ -1,6 +1,6 @@ cabal-version: 2.4 name: neuron -version: 1.9.35.3 +version: 1.9.36.0 license: AGPL-3.0-only copyright: 2020 Sridhar Ratnakumar maintainer: srid@srid.ca @@ -52,6 +52,7 @@ common library-common dependent-sum-aeson-orphans >= 0.2.1.0, dependent-sum-template, dependent-sum, + some, dhall >= 1.30, directory-contents, directory, @@ -70,7 +71,7 @@ common library-common modern-uri, mtl, optparse-applicative, - pandoc-link-context >= 1.2.0, + pandoc-link-context >= 1.4.0, pandoc-types >= 1.21, parsec, parser-combinators, @@ -78,7 +79,7 @@ common library-common reflex-dom-pandoc >= 1.0.0.0, reflex-fsnotify, reflex, - relude >= 0.7.0.0 && < 1.0.0.0, + relude >= 0.7.0.0, split, shower, tagged, diff --git a/src/Data/Graph/Labelled/Algorithm.hs b/src/Data/Graph/Labelled/Algorithm.hs index 20abae1a..c104d70e 100644 --- a/src/Data/Graph/Labelled/Algorithm.hs +++ b/src/Data/Graph/Labelled/Algorithm.hs @@ -113,7 +113,7 @@ dfsForest g = -- | Compute the dfsForest from the given vertices. dfsForestFrom :: (Vertex v, Ord (VertexID v)) => [v] -> LabelledGraph v e -> Forest v dfsForestFrom (fmap vertexID -> vs) g = - fmap (fmap $ getVertex g) $ Algo.dfsForestFrom vs $ LAM.skeleton $ graph g + fmap (fmap $ getVertex g) $ Algo.dfsForestFrom (LAM.skeleton $ graph g) vs -- | Compute the dfsForest ending in the given vertex. -- @@ -128,7 +128,7 @@ bfsForestBackwards fromV (LabelledGraph g' v') = bfsForestFrom :: (Vertex v, Ord (VertexID v)) => [v] -> LabelledGraph v e -> Forest v bfsForestFrom (fmap vertexID -> vs) g = - fmap (fmap $ getVertex g) $ Algo.bfsForest vs $ LAM.skeleton $ graph g + fmap (fmap $ getVertex g) $ Algo.bfsForest (LAM.skeleton $ graph g) vs -------------------------- --- More general utilities @@ -172,7 +172,7 @@ mothers g = in go ((v :| Set.toList covered) : acc) (Set.toList rest) -- Vertices reachable from `v` regardless of direction. reachableUndirected v = - Set.fromList $ Algo.reachable v gUndirected + Set.fromList $ Algo.reachable gUndirected v -- The undirected version of g gUndirected = AM.overlay g $ AM.transpose g diff --git a/src/Data/YAML/ToJSON.hs b/src/Data/YAML/ToJSON.hs index f50e03af..4195523b 100644 --- a/src/Data/YAML/ToJSON.hs +++ b/src/Data/YAML/ToJSON.hs @@ -12,11 +12,12 @@ module Data.YAML.ToJSON where import Data.Aeson import qualified Data.Aeson as Aeson import qualified Data.Aeson.Encoding as AesonEncoding +import qualified Data.Aeson.Key as AesonKey import qualified Data.YAML as Y import Relude instance Aeson.ToJSONKey (Y.Node Y.Pos) where - toJSONKey = ToJSONKeyText f (AesonEncoding.text . f) + toJSONKey = ToJSONKeyText (AesonKey.fromText . f) (AesonEncoding.text . f) where f = \case Y.Scalar _ x -> scalarToText x diff --git a/src/Neuron/Cache/Type.hs b/src/Neuron/Cache/Type.hs index bd35333f..b8d6a3a9 100644 --- a/src/Neuron/Cache/Type.hs +++ b/src/Neuron/Cache/Type.hs @@ -43,7 +43,7 @@ instance FromJSON NeuronCache where reflexDomGetCache :: ( DomBuilder t m, - Prerender js t m, + Prerender t m, TriggerEvent t m, PerformEvent t m, PostBuild t m, diff --git a/src/Neuron/Frontend/Impulse.hs b/src/Neuron/Frontend/Impulse.hs index 99bc32c6..6553dd14 100644 --- a/src/Neuron/Frontend/Impulse.hs +++ b/src/Neuron/Frontend/Impulse.hs @@ -67,7 +67,7 @@ treeMatches :: Tree (Maybe a, b) -> Bool treeMatches (Node (mm, _) _) = isJust mm renderImpulse :: - (DomBuilder t m, PostBuild t m, MonadHold t m, MonadFix m, Prerender js t m) => + (DomBuilder t m, PostBuild t m, MonadHold t m, MonadFix m, Prerender t m) => Dynamic t (LoadableData (SiteData, ImpulseData)) -> NeuronWebT t m () renderImpulse dataLDyn = do diff --git a/src/Neuron/Frontend/Route/Data/Types.hs b/src/Neuron/Frontend/Route/Data/Types.hs index 4993a226..557422f5 100644 --- a/src/Neuron/Frontend/Route/Data/Types.hs +++ b/src/Neuron/Frontend/Route/Data/Types.hs @@ -8,6 +8,7 @@ {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE NoImplicitPrelude #-} -- | Neuron's route and its config diff --git a/src/Neuron/Frontend/Static/Html.hs b/src/Neuron/Frontend/Static/Html.hs index 3a2c9165..764a9184 100644 --- a/src/Neuron/Frontend/Static/Html.hs +++ b/src/Neuron/Frontend/Static/Html.hs @@ -25,13 +25,13 @@ import Relude -- | Render the given route renderRoutePage :: - forall t m js a. + forall t m a. ( DomBuilder t m, RawBuilder m, MonadHold t m, PostBuild t m, MonadFix m, - Prerender js t m, + Prerender t m, PerformEvent t m, TriggerEvent t m ) => diff --git a/src/Neuron/Frontend/View.hs b/src/Neuron/Frontend/View.hs index ddb85042..b908c7d7 100644 --- a/src/Neuron/Frontend/View.hs +++ b/src/Neuron/Frontend/View.hs @@ -70,8 +70,8 @@ bodyTemplate neuronVersionM w = do renderBrandFooter neuronVersionM renderRouteImpulse :: - forall t m js. - (DomBuilder t m, PostBuild t m, MonadHold t m, MonadFix m, Prerender js t m) => + forall t m. + (DomBuilder t m, PostBuild t m, MonadHold t m, MonadFix m, Prerender t m) => Dynamic t (LoadableData (SiteData, ImpulseData)) -> NeuronWebT t m () renderRouteImpulse dataLDyn = do @@ -83,13 +83,13 @@ renderRouteImpulse dataLDyn = do Impulse.renderImpulse dataLDyn renderRouteZettel :: - forall t m js. + forall t m. ( DomBuilder t m, RawBuilder m, PostBuild t m, MonadHold t m, MonadFix m, - Prerender js t m + Prerender t m ) => Dynamic t (LoadableData (SiteData, ZettelData)) -> NeuronWebT t m () diff --git a/src/Neuron/Frontend/Widget/InvertedTree.hs b/src/Neuron/Frontend/Widget/InvertedTree.hs index 13df92e0..1eb58213 100644 --- a/src/Neuron/Frontend/Widget/InvertedTree.hs +++ b/src/Neuron/Frontend/Widget/InvertedTree.hs @@ -97,13 +97,13 @@ pureCssTreeDiagram = do C.position absolute C.top $ px 0 C.right $ pct 50 - C.borderTop solid cellBorderWidth "#ccc" + C.borderTop cellBorderWidth solid "#ccc" C.width $ pct 50 C.height $ em 1.2 C.after & do C.right auto C.left $ pct 50 - C.borderLeft solid cellBorderWidth "#ccc" + C.borderLeft cellBorderWidth solid "#ccc" C.onlyChild & do C.paddingTop $ em 0 forM_ [C.after, C.before] $ \sel -> @@ -120,19 +120,19 @@ pureCssTreeDiagram = do C.borderStyle none C.borderWidth $ px 0 C.before & do - C.borderRight solid cellBorderWidth "#ccc" + C.borderRight cellBorderWidth solid "#ccc" C.borderRadius 0 (px 5) 0 0 "ul ul::before" ? do C.content $ stringContent "" C.position absolute C.top $ px 0 C.left $ pct 50 - C.borderLeft solid cellBorderWidth "#ccc" + C.borderLeft cellBorderWidth solid "#ccc" C.width $ px 0 C.height $ em 1.2 "li" ? do "div.forest-link" ? do - border solid cellBorderWidth "#ccc" + border cellBorderWidth solid "#ccc" sym2 C.padding (em 0.2) (em 0.3) C.textDecoration none C.display inlineBlock diff --git a/src/Neuron/Frontend/Zettel/CSS.hs b/src/Neuron/Frontend/Zettel/CSS.hs index 108a5748..62d31847 100644 --- a/src/Neuron/Frontend/Zettel/CSS.hs +++ b/src/Neuron/Frontend/Zettel/CSS.hs @@ -68,7 +68,7 @@ zettelContentCss = do C.paddingBottom $ em 0.2 C.textAlign C.center C.h2 ? do - C.borderBottom C.solid (px 1) C.steelblue + C.borderBottom (px 1) C.solid C.steelblue C.marginBottom $ em 0.5 C.h3 ? do C.margin (px 0) (px 0) (em 0.4) (px 0) @@ -124,7 +124,7 @@ zettelContentCss = do blockquoteStyle = C.blockquote ? do C.backgroundColor "#f9f9f9" - C.borderLeft C.solid (px 10) "#ccc" + C.borderLeft (px 10) C.solid "#ccc" sym2 C.margin (em 1.5) (px 0) sym2 C.padding (em 0.5) (px 10) diff --git a/src/Neuron/Frontend/Zettel/View.hs b/src/Neuron/Frontend/Zettel/View.hs index 2ea7461a..ada9c73d 100644 --- a/src/Neuron/Frontend/Zettel/View.hs +++ b/src/Neuron/Frontend/Zettel/View.hs @@ -45,7 +45,7 @@ renderZettel :: PostBuild t m, MonadHold t m, MonadFix m, - Prerender js t m + Prerender t m ) => SiteData -> ZettelData -> diff --git a/src/Neuron/Markdown.hs b/src/Neuron/Markdown.hs index 5ca6c1c6..d5b135a0 100644 --- a/src/Neuron/Markdown.hs +++ b/src/Neuron/Markdown.hs @@ -35,6 +35,8 @@ import qualified Commonmark.Pandoc as CP import Control.Monad.Combinators (manyTill) import Data.Aeson (ToJSON (toJSON)) import qualified Data.Aeson as Aeson +import qualified Data.Aeson.Key as AesonKey +import qualified Data.Aeson.KeyMap as KM import Data.Aeson.Types (FromJSON) import Data.Default import Data.Tagged (Tagged (..)) @@ -81,25 +83,26 @@ zettelMetaFromYamlFrontmatter myaml = lookupZettelMeta :: forall a. FromJSON a => Text -> ZettelMeta -> Maybe a lookupZettelMeta k (ZettelMeta mobj) = do Aeson.Object m <- mobj - Aeson.Success v <- Aeson.fromJSON @a <$> M.lookup k m + Aeson.Success v <- Aeson.fromJSON @a <$> KM.lookup (AesonKey.fromText k) m pure v insertZettelMeta :: forall a. ToJSON a => Text -> a -> ZettelMeta -> ZettelMeta insertZettelMeta k v (ZettelMeta mobj) = ZettelMeta $ Just $ Aeson.Object $ - case mobj of - Nothing -> - fromList [(k, Aeson.toJSON v)] - Just (Aeson.Object m) -> - M.insert k (Aeson.toJSON v) m - Just other -> - -- We don't expect top-level object to be anything but a map. But just - -- in case, let's retain the original value anyway. - fromList - [ ("other", other), - (k, Aeson.toJSON v) - ] + let k' = AesonKey.fromText k + in case mobj of + Nothing -> + KM.fromList [(k', Aeson.toJSON v)] + Just (Aeson.Object m) -> + KM.insert k' (Aeson.toJSON v) m + Just other -> + -- We don't expect top-level object to be anything but a map. But just + -- in case, let's retain the original value anyway. + KM.fromList + [ (AesonKey.fromText "other", other), + (k', Aeson.toJSON v) + ] -- | Parse Markdown document, along with the YAML metadata block in it. -- @@ -125,9 +128,11 @@ parseMarkdown extraSpec fn s = do withJsonAlias :: (Text, Text) -> Aeson.Value -> Aeson.Value withJsonAlias (alias, target) = \case x@(Aeson.Object m) -> fromMaybe x $ do - guard $ not $ M.member target m - kw <- M.lookup alias m - pure $ Aeson.Object (M.insert target kw m) + let alias' = AesonKey.fromText alias + target' = AesonKey.fromText target + guard $ not $ KM.member target' m + kw <- KM.lookup alias' m + pure $ Aeson.Object (KM.insert target' kw m) x -> x -- NOTE: HsYAML parsing is rather slow due to its use of DList. diff --git a/src/Neuron/Plugin.hs b/src/Neuron/Plugin.hs index 6d450602..3bb07f15 100644 --- a/src/Neuron/Plugin.hs +++ b/src/Neuron/Plugin.hs @@ -230,7 +230,7 @@ stripSurroundingContext = -- | Render a zettel Pandoc content given its zettel data. elZettel :: - (DomBuilder t m, RawBuilder m, PostBuild t m, Prerender js t m) => + (DomBuilder t m, RawBuilder m, PostBuild t m, Prerender t m) => ZettelData -> Pandoc -> NeuronWebT t m () @@ -238,8 +238,8 @@ elZettel zData = elPandoc (mkReflexDomPandocConfig zData) mkReflexDomPandocConfig :: - forall js t m. - (DomBuilder t m, RawBuilder m, PostBuild t m, Prerender js t m) => + forall t m. + (DomBuilder t m, RawBuilder m, PostBuild t m, Prerender t m) => ZettelData -> Config t (NeuronWebT t m) () mkReflexDomPandocConfig x = diff --git a/src/Neuron/Plugin/Plugins/Feed.hs b/src/Neuron/Plugin/Plugins/Feed.hs index 92631c08..91397043 100644 --- a/src/Neuron/Plugin/Plugins/Feed.hs +++ b/src/Neuron/Plugin/Plugins/Feed.hs @@ -16,7 +16,7 @@ import qualified Data.Dependent.Map as DMap import qualified Data.Map.Strict as Map import Data.Some (Some (Some)) import qualified Data.Time.DateMayTime as DMT -import GHC.Natural (naturalToInt) +-- fromIntegral removed in GHC 9.10; use fromIntegral import qualified Neuron.Frontend.Manifest as Manifest import Neuron.Frontend.Route (Route) import qualified Neuron.Frontend.Route as R @@ -59,7 +59,7 @@ routePluginData routeCfg siteData zs g (sansContent -> z) FeedMeta {..} = feedDataUrl = R.routeUri feedDataBaseUri $ R.routeConfigRouteURL routeCfg (Some $ R.Route_Zettel $ zettelSlug z) feedDataEntries = -- Limit to user-chosen count - take (naturalToInt feedmetaCount) $ + take (fromIntegral feedmetaCount) $ -- In reverse chronologial order sortOn (Down . feedItemDate) $ -- Only those with date assigned diff --git a/src/Neuron/Plugin/Plugins/Links.hs b/src/Neuron/Plugin/Plugins/Links.hs index b2b4e204..3ef3b806 100644 --- a/src/Neuron/Plugin/Plugins/Links.hs +++ b/src/Neuron/Plugin/Plugins/Links.hs @@ -297,7 +297,7 @@ zettelLinkCss theme = do "span.zettel-link-container span.extra" ? do C.color C.auto "span.zettel-link-container.errors" ? do - C.border C.solid (C.px 1) C.red + C.border (C.px 1) C.solid C.red "span.zettel-link-container.errors span.zettel-link a:hover" ? do C.important $ C.textDecoration C.none C.cursor C.notAllowed diff --git a/src/Neuron/Plugin/Plugins/Tags.hs b/src/Neuron/Plugin/Plugins/Tags.hs index 5d6e5118..14f1dde1 100644 --- a/src/Neuron/Plugin/Plugins/Tags.hs +++ b/src/Neuron/Plugin/Plugins/Tags.hs @@ -40,7 +40,7 @@ import qualified Data.TagTree as Tag import qualified Data.TagTree as TagTree import qualified Data.Text as T import Data.Tree (Forest, Tree (Node)) -import GHC.Natural (naturalToInt) +-- naturalToInt removed in GHC 9.10; using fromIntegral import Neuron.Frontend.Route (NeuronWebT) import Neuron.Frontend.Route.Data.Types (TagQueryCache) import Neuron.Frontend.Widget (semanticIcon) @@ -222,7 +222,7 @@ renderQueryResult = \case let resToDisplay = case zettelsviewLimit view of Nothing -> res - Just (naturalToInt -> limit) -> take limit res + Just (fromIntegral -> limit) -> take limit res forM_ resToDisplay $ \z -> do divClass "item listing-item" $ Links.renderZettelLink Nothing (Just conn) (Just $ zettelsviewLinkView view) z diff --git a/src/Neuron/Reactor.hs b/src/Neuron/Reactor.hs index af32e4d7..03880086 100644 --- a/src/Neuron/Reactor.hs +++ b/src/Neuron/Reactor.hs @@ -198,7 +198,7 @@ watchDirWithDebounce :: watchDirWithDebounce ms dirPath' = do -- Make absolute herte, so the relative function below works. dirPath <- liftIO $ makeAbsolute dirPath' - let cfg = FSN.defaultConfig {FSN.confDebounce = FSN.Debounce ms} + let cfg = FSN.defaultConfig pb <- getPostBuild fsEvt <- watchTree cfg (dirPath <$ pb) (const True) let evt2 = fforMaybe fsEvt $ \fse' -> do @@ -223,8 +223,8 @@ watchDirWithDebounce ms dirPath' = do mkR fp <&> \p -> FSN.Modified p t d FSN.Removed fp t d -> mkR fp <&> \p -> FSN.Removed p t d - FSN.Unknown fp t d -> - mkR fp <&> \p -> FSN.Unknown p t d + FSN.Unknown fp t d e -> + mkR fp <&> \p -> FSN.Unknown p t d e where mkR fp = do let rel = makeRelative baseDir fp diff --git a/src/Neuron/Zettelkasten/Zettel.hs b/src/Neuron/Zettelkasten/Zettel.hs index 0965a84f..5dace850 100644 --- a/src/Neuron/Zettelkasten/Zettel.hs +++ b/src/Neuron/Zettelkasten/Zettel.hs @@ -13,6 +13,7 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} @@ -30,6 +31,8 @@ import Data.Dependent.Map (DMap) import qualified Data.Dependent.Map as DMap import Data.Dependent.Sum.Orphans () import Data.GADT.Compare.TH +import Data.GADT.Compare (GEq(..), GCompare(..), GOrdering(..)) +import Data.Type.Equality ((:~:)(Refl)) import Data.GADT.Show.TH (DeriveGShow (deriveGShow)) import Data.Graph.Labelled (Vertex (..)) import Data.Some (Some) @@ -101,6 +104,21 @@ data TagQuery r where TagQuery_Tags :: TagTree.Query -> TagQuery (Map Tag Natural) TagQuery_TagZettel :: Tag -> TagQuery () +instance GEq TagQuery where + geq (TagQuery_ZettelsByTag _ _ _) (TagQuery_ZettelsByTag _ _ _) = Just Refl + geq (TagQuery_Tags _) (TagQuery_Tags _) = Just Refl + geq (TagQuery_TagZettel _) (TagQuery_TagZettel _) = Just Refl + geq _ _ = Nothing + +instance GCompare TagQuery where + gcompare (TagQuery_ZettelsByTag _ _ _) (TagQuery_ZettelsByTag _ _ _) = GEQ + gcompare (TagQuery_ZettelsByTag _ _ _) _ = GLT + gcompare _ (TagQuery_ZettelsByTag _ _ _) = GGT + gcompare (TagQuery_Tags _) (TagQuery_Tags _) = GEQ + gcompare (TagQuery_Tags _) _ = GLT + gcompare _ (TagQuery_Tags _) = GGT + gcompare (TagQuery_TagZettel _) (TagQuery_TagZettel _) = GEQ + data FeedMeta = FeedMeta {feedmetaCount :: Natural} deriving (Eq, Ord, Show, Generic) @@ -120,6 +138,33 @@ data PluginZettelData a where UpTree :: PluginZettelData () Feed :: PluginZettelData FeedMeta +instance GEq PluginZettelData where + geq DirTree DirTree = Just Refl + geq Links Links = Just Refl + geq Tags Tags = Just Refl + geq NeuronIgnore NeuronIgnore = Just Refl + geq UpTree UpTree = Just Refl + geq Feed Feed = Just Refl + geq _ _ = Nothing + +instance GCompare PluginZettelData where + gcompare DirTree DirTree = GEQ + gcompare DirTree _ = GLT + gcompare _ DirTree = GGT + gcompare Links Links = GEQ + gcompare Links _ = GLT + gcompare _ Links = GGT + gcompare Tags Tags = GEQ + gcompare Tags _ = GLT + gcompare _ Tags = GGT + gcompare NeuronIgnore NeuronIgnore = GEQ + gcompare NeuronIgnore _ = GLT + gcompare _ NeuronIgnore = GGT + gcompare UpTree UpTree = GEQ + gcompare UpTree _ = GLT + gcompare _ UpTree = GGT + gcompare Feed Feed = GEQ + -- ------------ -- Zettel types -- ------------ @@ -201,16 +246,12 @@ sortZettelsReverseChronological = sortOn (Down . zettelDate) deriveJSONGADT ''TagQuery -deriveGEq ''TagQuery deriveGShow ''TagQuery -deriveGCompare ''TagQuery deriveArgDict ''TagQuery deriveArgDict ''PluginZettelData deriveJSONGADT ''PluginZettelData -deriveGEq ''PluginZettelData deriveGShow ''PluginZettelData -deriveGCompare ''PluginZettelData deriving instance Eq (ZettelT Pandoc) From cd43f6d700d75d3a7fb263b80d60e3a42d60f705 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 09:07:41 -0400 Subject: [PATCH 12/19] Re-enable macOS CI (aarch64-darwin) with modern nixpkgs --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9c247f6e..eb04898c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -9,7 +9,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest] + os: [ubuntu-latest, macos-14] env: MAINLINE: refs/heads/master DOCKERTAG: latest From 9adf13fed46019c8a6906c7fb1b49b193f7b9286 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 09:38:58 -0400 Subject: [PATCH 13/19] dontCheck fsnotify (test dep sandwich fails to build) --- flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/flake.nix b/flake.nix index 7a850187..961cbf99 100644 --- a/flake.nix +++ b/flake.nix @@ -92,6 +92,7 @@ sed -i '/^ Null ->$/,/^ blank >> pure mempty$/d' src/Reflex/Dom/Pandoc/Document.hs ''; }))); + fsnotify = dontCheck super.fsnotify; reflex-fsnotify = doJailbreak (self.callCabal2nix "reflex-fsnotify" sources.reflex-fsnotify { }); From 66cfd73af77866126e92ecc90767f4e328866191 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 11:38:09 -0400 Subject: [PATCH 14/19] Use TH-derived GEq/GCompare instead of manual instances Move TH splices (deriveGEq, deriveGCompare) after all type definitions but before DMap usage to satisfy TH staging requirements. --- src/Neuron/Zettelkasten/Zettel.hs | 75 ++++--------------------------- 1 file changed, 8 insertions(+), 67 deletions(-) diff --git a/src/Neuron/Zettelkasten/Zettel.hs b/src/Neuron/Zettelkasten/Zettel.hs index 5dace850..3f9d96a2 100644 --- a/src/Neuron/Zettelkasten/Zettel.hs +++ b/src/Neuron/Zettelkasten/Zettel.hs @@ -13,7 +13,6 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} @@ -31,8 +30,6 @@ import Data.Dependent.Map (DMap) import qualified Data.Dependent.Map as DMap import Data.Dependent.Sum.Orphans () import Data.GADT.Compare.TH -import Data.GADT.Compare (GEq(..), GCompare(..), GOrdering(..)) -import Data.Type.Equality ((:~:)(Refl)) import Data.GADT.Show.TH (DeriveGShow (deriveGShow)) import Data.Graph.Labelled (Vertex (..)) import Data.Some (Some) @@ -104,32 +101,11 @@ data TagQuery r where TagQuery_Tags :: TagTree.Query -> TagQuery (Map Tag Natural) TagQuery_TagZettel :: Tag -> TagQuery () -instance GEq TagQuery where - geq (TagQuery_ZettelsByTag _ _ _) (TagQuery_ZettelsByTag _ _ _) = Just Refl - geq (TagQuery_Tags _) (TagQuery_Tags _) = Just Refl - geq (TagQuery_TagZettel _) (TagQuery_TagZettel _) = Just Refl - geq _ _ = Nothing - -instance GCompare TagQuery where - gcompare (TagQuery_ZettelsByTag _ _ _) (TagQuery_ZettelsByTag _ _ _) = GEQ - gcompare (TagQuery_ZettelsByTag _ _ _) _ = GLT - gcompare _ (TagQuery_ZettelsByTag _ _ _) = GGT - gcompare (TagQuery_Tags _) (TagQuery_Tags _) = GEQ - gcompare (TagQuery_Tags _) _ = GLT - gcompare _ (TagQuery_Tags _) = GGT - gcompare (TagQuery_TagZettel _) (TagQuery_TagZettel _) = GEQ - data FeedMeta = FeedMeta {feedmetaCount :: Natural} deriving (Eq, Ord, Show, Generic) -- | Plugin-specific data stored in `ZettelT` --- --- See also `PluginZettelRouteData` which corresponds to post-graph data (used --- in rendering). --- --- NOTE: The constructors deliberately are kept short, so as to have shorter --- JSON data PluginZettelData a where DirTree :: PluginZettelData DirZettel Links :: PluginZettelData [((ZettelID, Connection), [Block])] @@ -138,59 +114,18 @@ data PluginZettelData a where UpTree :: PluginZettelData () Feed :: PluginZettelData FeedMeta -instance GEq PluginZettelData where - geq DirTree DirTree = Just Refl - geq Links Links = Just Refl - geq Tags Tags = Just Refl - geq NeuronIgnore NeuronIgnore = Just Refl - geq UpTree UpTree = Just Refl - geq Feed Feed = Just Refl - geq _ _ = Nothing - -instance GCompare PluginZettelData where - gcompare DirTree DirTree = GEQ - gcompare DirTree _ = GLT - gcompare _ DirTree = GGT - gcompare Links Links = GEQ - gcompare Links _ = GLT - gcompare _ Links = GGT - gcompare Tags Tags = GEQ - gcompare Tags _ = GLT - gcompare _ Tags = GGT - gcompare NeuronIgnore NeuronIgnore = GEQ - gcompare NeuronIgnore _ = GLT - gcompare _ NeuronIgnore = GGT - gcompare UpTree UpTree = GEQ - gcompare UpTree _ = GLT - gcompare _ UpTree = GGT - gcompare Feed Feed = GEQ - --- ------------ --- Zettel types --- ------------ - -- | A zettel ID doesn't refer to an existing zettel type MissingZettel = Tagged "MissingZettel" ZettelID -- | A zettel note --- --- The metadata could have been inferred from the content. data ZettelT c = Zettel { zettelID :: ZettelID, zettelMeta :: ZettelMeta, - -- Slug is non-changing - so, although inferred from zettelMeta, we must - -- put it here as a data type field. - zettelSlug :: Slug, -- inferred from zettelMeta - -- Since date is used as a sort key, we parse it once from zettelMeta for - -- performance reasons. - zettelDate :: Maybe DateMayTime, -- inferred from zettelMeta - - -- | Relative path to this zettel in the zettelkasten directory + zettelSlug :: Slug, + zettelDate :: Maybe DateMayTime, zettelPath :: FilePath, zettelTitle :: Text, zettelContent :: c, - -- This type is a Maybe only so that we can use omitNothingFields to strip - -- it off the output JSON. zettelPluginData :: Maybe (DMap PluginZettelData Identity) } deriving (Generic) @@ -200,6 +135,10 @@ type MetadataOnly = (Maybe ZettelParseError) -- | Zettel without its content type Zettel = ZettelT MetadataOnly +-- TH splices: must come after all type definitions but before DMap usage +deriveGEq ''PluginZettelData +deriveGCompare ''PluginZettelData + -- | Zettel that has either failed to parse, or has been parsed. type ZettelC = Either (ZettelT (Text, ZettelParseError)) (ZettelT Pandoc) @@ -245,6 +184,8 @@ sortZettelsReverseChronological :: [Zettel] -> [Zettel] sortZettelsReverseChronological = sortOn (Down . zettelDate) +deriveGEq ''TagQuery +deriveGCompare ''TagQuery deriveJSONGADT ''TagQuery deriveGShow ''TagQuery deriveArgDict ''TagQuery From 75505d4185cc70d908b6dd4b27b61cb669d17479 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 11:51:05 -0400 Subject: [PATCH 15/19] Migrate to haskell-flake Replace manual Haskell package management with haskell-flake flake-parts module. Uses projectRoot for source filtering, otherOverlays for dep patches, and settings for jailbreak/haddock. --- flake.lock | 16 +++++ flake.nix | 191 ++++++++++++++++++++++++++--------------------------- 2 files changed, 108 insertions(+), 99 deletions(-) diff --git a/flake.lock b/flake.lock index 5c8f279f..f1f109cd 100644 --- a/flake.lock +++ b/flake.lock @@ -51,6 +51,21 @@ "type": "github" } }, + "haskell-flake": { + "locked": { + "lastModified": 1773753271, + "narHash": "sha256-vgD8n7TuvS9oZ15uwiRgHWC9dQlI2jlLOUZQn1/EAgI=", + "owner": "srid", + "repo": "haskell-flake", + "rev": "f28e51cc2b603ba62b732a518e21e15ace6d1fe8", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "haskell-flake", + "type": "github" + } + }, "nix-filter": { "flake": false, "locked": { @@ -155,6 +170,7 @@ "directory-contents": "directory-contents", "flake-compat": "flake-compat", "flake-parts": "flake-parts", + "haskell-flake": "haskell-flake", "nix-filter": "nix-filter", "nixpkgs": "nixpkgs", "pandoc-link-context": "pandoc-link-context", diff --git a/flake.nix b/flake.nix index 961cbf99..3c69efce 100644 --- a/flake.nix +++ b/flake.nix @@ -4,6 +4,7 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; flake-parts.url = "github:hercules-ci/flake-parts"; + haskell-flake.url = "github:srid/haskell-flake"; nix-filter.url = "github:numtide/nix-filter/3c9e33ed627e009428197b07216613206f06ed80"; nix-filter.flake = false; @@ -31,34 +32,30 @@ }; }; - outputs = inputs@{ self, nixpkgs, flake-parts, nix-filter, ... }: + outputs = inputs@{ self, nixpkgs, flake-parts, haskell-flake, nix-filter, ... }: flake-parts.lib.mkFlake { inherit inputs; } { + imports = [ haskell-flake.flakeModule ]; + flake = { homeManagerModule = import ./home-manager-module.nix; }; systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; - perSystem = { pkgs, system, ... }: + perSystem = { self', pkgs, lib, ... }: let nix-filter-lib = import nix-filter; - sources = { - neuron = nix-filter-lib { - root = ./.; - name = "neuron"; - include = [ - "neuron-search" - "neuron.cabal" - (nix-filter-lib.inDirectory "exe") - (nix-filter-lib.inDirectory "src") - (nix-filter-lib.inDirectory "test") - ]; - }; - reflex-dom-pandoc = inputs.reflex-dom-pandoc; - pandoc-link-context = inputs.pandoc-link-context; - directory-contents = inputs.directory-contents; - reflex-fsnotify = inputs.reflex-fsnotify; + neuronSource = nix-filter-lib { + root = ./.; + name = "neuron"; + include = [ + "neuron-search" + "neuron.cabal" + (nix-filter-lib.inDirectory "exe") + (nix-filter-lib.inDirectory "src") + (nix-filter-lib.inDirectory "test") + ]; }; searchBuilder = '' @@ -71,94 +68,90 @@ PATH=$PATH:$out/bin ''; - wrapSearchScript = drv: { - buildTools = [ pkgs.makeWrapper ]; - preConfigure = searchBuilder; - }; - inherit (pkgs.haskell.lib) - overrideCabal doJailbreak dontCheck dontHaddock justStaticExecutables appendConfigureFlags; - - haskellOverrides = self: super: { - pandoc-link-context = doJailbreak (self.callCabal2nix "pandoc-link-context" sources.pandoc-link-context { }); - reflex-dom-pandoc = - dontHaddock (doJailbreak (overrideCabal (self.callCabal2nix "reflex-dom-pandoc" sources.reflex-dom-pandoc { }) (old: { - postPatch = (old.postPatch or "") + '' - # GHC 9.10: forM no longer in scope, add explicit import - sed -i '/^import Control.Monad.Reader/a import Data.Traversable (forM)' src/Reflex/Dom/Pandoc/Footnotes.hs - # GHC 9.10: ~ requires TypeOperators - sed -i '1s/^/{-# LANGUAGE TypeOperators #-}\n/' src/Reflex/Dom/Pandoc/Raw.hs - # pandoc-types >= 1.23: Null constructor removed, replace with blank pattern - sed -i '/^ Null ->$/,/^ blank >> pure mempty$/d' src/Reflex/Dom/Pandoc/Document.hs - ''; - }))); - fsnotify = dontCheck super.fsnotify; - reflex-fsnotify = - doJailbreak (self.callCabal2nix "reflex-fsnotify" sources.reflex-fsnotify { }); - - - # witherable 0.4.x (has Data.Witherable module that directory-contents needs) - witherable = doJailbreak (self.callHackageDirect { - pkg = "witherable"; - ver = "0.4.2"; - sha256 = "sha256-M5KOI2qKqf4qdfKUwQ2h+3pF5PfPhtz0dozPUAZVRL0="; - } { }); - directory-contents = doJailbreak (self.callCabal2nix "directory-contents" sources.directory-contents { }); - - neuron = appendConfigureFlags - ((justStaticExecutables - (doJailbreak (overrideCabal (self.callCabal2nix "neuron" sources.neuron { }) - wrapSearchScript))).overrideDerivation (drv: { - disallowedReferences = [ - self.pandoc-types - self.warp - self.HTTP - self.js-jquery - self.js-dgtable - self.js-flot - ]; - postInstall = '' - remove-references-to -t ${self.pandoc-types} $out/bin/neuron - remove-references-to -t ${self.warp} $out/bin/neuron - remove-references-to -t ${self.HTTP} $out/bin/neuron - remove-references-to -t ${self.js-jquery} $out/bin/neuron - remove-references-to -t ${self.js-dgtable} $out/bin/neuron - remove-references-to -t ${self.js-flot} $out/bin/neuron - ''; - })) - [ ]; - }; - - haskellPackages = pkgs.haskellPackages.override { - overrides = haskellOverrides; - }; - - nixShellSearchScript = pkgs.stdenv.mkDerivation { - name = "neuron-search"; - src = sources.neuron; - buildInputs = [ pkgs.makeWrapper ]; - buildCommand = searchBuilder; - }; + overrideCabal doJailbreak dontCheck dontHaddock justStaticExecutables; in { - formatter = pkgs.nixpkgs-fmt; + haskellProjects.default = { + projectRoot = neuronSource; + autoWire = [ "packages" "checks" "devShells" ]; + + packages = { + reflex-dom-pandoc.source = inputs.reflex-dom-pandoc; + pandoc-link-context.source = inputs.pandoc-link-context; + directory-contents.source = inputs.directory-contents; + reflex-fsnotify.source = inputs.reflex-fsnotify; + }; - packages = { - default = haskellPackages.neuron; - neuron = haskellPackages.neuron; - }; + settings = { + reflex-dom-pandoc.jailbreak = true; + reflex-dom-pandoc.haddock = false; + reflex-fsnotify.jailbreak = true; + directory-contents.jailbreak = true; + pandoc-link-context.jailbreak = true; + neuron.jailbreak = true; + neuron.buildFromSdist = false; + }; - devShells.default = haskellPackages.shellFor { - packages = p: [ p.neuron ]; - buildInputs = [ - pkgs.nixpkgs-fmt - haskellPackages.ghcid - haskellPackages.cabal-install - haskellPackages.hlint - haskellPackages.ormolu - nixShellSearchScript + otherOverlays = [ + (hself: hsuper: { + # Patch reflex-dom-pandoc for GHC 9.10 / pandoc-types 1.23 + reflex-dom-pandoc = overrideCabal hsuper.reflex-dom-pandoc (old: { + postPatch = (old.postPatch or "") + '' + sed -i '/^import Control.Monad.Reader/a import Data.Traversable (forM)' src/Reflex/Dom/Pandoc/Footnotes.hs + sed -i '1s/^/{-# LANGUAGE TypeOperators #-}\n/' src/Reflex/Dom/Pandoc/Raw.hs + sed -i '/^ Null ->$/,/^ blank >> pure mempty$/d' src/Reflex/Dom/Pandoc/Document.hs + ''; + }); + fsnotify = dontCheck hsuper.fsnotify; + # witherable 0.4.x (has Data.Witherable module) + witherable = doJailbreak (hself.callHackageDirect { + pkg = "witherable"; + ver = "0.4.2"; + sha256 = "sha256-M5KOI2qKqf4qdfKUwQ2h+3pF5PfPhtz0dozPUAZVRL0="; + } { }); + # neuron custom: wrap search script + strip references + neuron = + let + wrapped = overrideCabal hsuper.neuron (old: { + buildTools = (old.buildTools or [ ]) ++ [ pkgs.makeWrapper ]; + preConfigure = searchBuilder; + }); + in + (justStaticExecutables wrapped).overrideDerivation (drv: { + disallowedReferences = [ + hself.pandoc-types + hself.warp + hself.HTTP + hself.js-jquery + hself.js-dgtable + hself.js-flot + ]; + postInstall = '' + remove-references-to -t ${hself.pandoc-types} $out/bin/neuron + remove-references-to -t ${hself.warp} $out/bin/neuron + remove-references-to -t ${hself.HTTP} $out/bin/neuron + remove-references-to -t ${hself.js-jquery} $out/bin/neuron + remove-references-to -t ${hself.js-dgtable} $out/bin/neuron + remove-references-to -t ${hself.js-flot} $out/bin/neuron + ''; + }); + }) ]; + + devShell = { + tools = hp: { + ghcid = hp.ghcid; + cabal-install = hp.cabal-install; + hlint = hp.hlint; + ormolu = hp.ormolu; + }; + mkShellArgs.packages = [ pkgs.nixpkgs-fmt ]; + }; }; + + formatter = pkgs.nixpkgs-fmt; + packages.default = self'.packages.neuron; }; }; } From eb45989964a1c44c8806491fe625530bfddd5028 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 15:24:30 -0400 Subject: [PATCH 16/19] Use macos-latest in CI --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index eb04898c..0c2cdb52 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -9,7 +9,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-14] + os: [ubuntu-latest, macos-latest] env: MAINLINE: refs/heads/master DOCKERTAG: latest From 64cd2d8c98487feba039fbfcb5f0b50be1a2abe3 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 15:25:51 -0400 Subject: [PATCH 17/19] Remove dep/ thunks and legacy Nix files All deps are now flake inputs. Remove: - dep/ (nix-thunk sources, replaced by flake inputs) - project.nix, nixpkgs.nix (replaced by flake.nix) - static.nix, docker.nix (unused) Also restore dropped comments in ZettelT. --- dep/README.md | 1 - dep/directory-contents/default.nix | 2 - dep/directory-contents/github.json | 8 -- dep/directory-contents/thunk.nix | 9 -- dep/nix-filter/default.nix | 2 - dep/nix-filter/github.json | 7 -- dep/nix-filter/thunk.nix | 9 -- dep/nix-thunk/default.nix | 2 - dep/nix-thunk/github.json | 7 -- dep/nix-thunk/thunk.nix | 9 -- dep/pandoc-link-context/default.nix | 2 - dep/pandoc-link-context/github.json | 8 -- dep/pandoc-link-context/thunk.nix | 9 -- dep/reflex-dom-pandoc/default.nix | 2 - dep/reflex-dom-pandoc/github.json | 8 -- dep/reflex-dom-pandoc/thunk.nix | 9 -- dep/reflex-fsnotify/default.nix | 2 - dep/reflex-fsnotify/github.json | 7 -- dep/reflex-fsnotify/thunk.nix | 9 -- docker.nix | 35 ------- nixpkgs.nix | 9 -- project.nix | 139 ---------------------------- src/Neuron/Zettelkasten/Zettel.hs | 14 ++- static.nix | 30 ------ 24 files changed, 12 insertions(+), 327 deletions(-) delete mode 100644 dep/README.md delete mode 100644 dep/directory-contents/default.nix delete mode 100644 dep/directory-contents/github.json delete mode 100644 dep/directory-contents/thunk.nix delete mode 100644 dep/nix-filter/default.nix delete mode 100644 dep/nix-filter/github.json delete mode 100644 dep/nix-filter/thunk.nix delete mode 100644 dep/nix-thunk/default.nix delete mode 100644 dep/nix-thunk/github.json delete mode 100644 dep/nix-thunk/thunk.nix delete mode 100644 dep/pandoc-link-context/default.nix delete mode 100644 dep/pandoc-link-context/github.json delete mode 100644 dep/pandoc-link-context/thunk.nix delete mode 100644 dep/reflex-dom-pandoc/default.nix delete mode 100644 dep/reflex-dom-pandoc/github.json delete mode 100644 dep/reflex-dom-pandoc/thunk.nix delete mode 100644 dep/reflex-fsnotify/default.nix delete mode 100644 dep/reflex-fsnotify/github.json delete mode 100644 dep/reflex-fsnotify/thunk.nix delete mode 100644 docker.nix delete mode 100644 nixpkgs.nix delete mode 100644 project.nix delete mode 100644 static.nix diff --git a/dep/README.md b/dep/README.md deleted file mode 100644 index 7e140b58..00000000 --- a/dep/README.md +++ /dev/null @@ -1 +0,0 @@ -These dependencies are to be managed by `nix-thunk`, and not hand-edited. diff --git a/dep/directory-contents/default.nix b/dep/directory-contents/default.nix deleted file mode 100644 index 2b4d4ab1..00000000 --- a/dep/directory-contents/default.nix +++ /dev/null @@ -1,2 +0,0 @@ -# DO NOT HAND-EDIT THIS FILE -import (import ./thunk.nix) \ No newline at end of file diff --git a/dep/directory-contents/github.json b/dep/directory-contents/github.json deleted file mode 100644 index 0f2d6516..00000000 --- a/dep/directory-contents/github.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "owner": "srid", - "repo": "directory-contents", - "branch": "master", - "private": false, - "rev": "f8c7148121adcf5bae2f41b8265ce9cc4ed0556b", - "sha256": "026in1v0njj53wx60nkbarspw917n4jnh03ss6nk2b2n3kcnx35g" -} diff --git a/dep/directory-contents/thunk.nix b/dep/directory-contents/thunk.nix deleted file mode 100644 index bbf2dc18..00000000 --- a/dep/directory-contents/thunk.nix +++ /dev/null @@ -1,9 +0,0 @@ -# DO NOT HAND-EDIT THIS FILE -let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: - if !fetchSubmodules && !private then builtins.fetchTarball { - url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; - } else (import {}).fetchFromGitHub { - inherit owner repo rev sha256 fetchSubmodules private; - }; - json = builtins.fromJSON (builtins.readFile ./github.json); -in fetch json \ No newline at end of file diff --git a/dep/nix-filter/default.nix b/dep/nix-filter/default.nix deleted file mode 100644 index 2b4d4ab1..00000000 --- a/dep/nix-filter/default.nix +++ /dev/null @@ -1,2 +0,0 @@ -# DO NOT HAND-EDIT THIS FILE -import (import ./thunk.nix) \ No newline at end of file diff --git a/dep/nix-filter/github.json b/dep/nix-filter/github.json deleted file mode 100644 index a6259967..00000000 --- a/dep/nix-filter/github.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "owner": "numtide", - "repo": "nix-filter", - "private": false, - "rev": "3c9e33ed627e009428197b07216613206f06ed80", - "sha256": "19w142crrkywxynmyw4rhz4nglrg64yjawfkw3j91qwkwbfjds84" -} diff --git a/dep/nix-filter/thunk.nix b/dep/nix-filter/thunk.nix deleted file mode 100644 index bbf2dc18..00000000 --- a/dep/nix-filter/thunk.nix +++ /dev/null @@ -1,9 +0,0 @@ -# DO NOT HAND-EDIT THIS FILE -let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: - if !fetchSubmodules && !private then builtins.fetchTarball { - url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; - } else (import {}).fetchFromGitHub { - inherit owner repo rev sha256 fetchSubmodules private; - }; - json = builtins.fromJSON (builtins.readFile ./github.json); -in fetch json \ No newline at end of file diff --git a/dep/nix-thunk/default.nix b/dep/nix-thunk/default.nix deleted file mode 100644 index 2b4d4ab1..00000000 --- a/dep/nix-thunk/default.nix +++ /dev/null @@ -1,2 +0,0 @@ -# DO NOT HAND-EDIT THIS FILE -import (import ./thunk.nix) \ No newline at end of file diff --git a/dep/nix-thunk/github.json b/dep/nix-thunk/github.json deleted file mode 100644 index 1b8037f8..00000000 --- a/dep/nix-thunk/github.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "owner": "obsidiansystems", - "repo": "nix-thunk", - "private": false, - "rev": "bab7329163fce579eaa9cfba67a4851ab806b76f", - "sha256": "0wn96xn6prjzcsh4n8p1n40wi8la53ym5h2frlqbfzas7isxwygg" -} diff --git a/dep/nix-thunk/thunk.nix b/dep/nix-thunk/thunk.nix deleted file mode 100644 index bbf2dc18..00000000 --- a/dep/nix-thunk/thunk.nix +++ /dev/null @@ -1,9 +0,0 @@ -# DO NOT HAND-EDIT THIS FILE -let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: - if !fetchSubmodules && !private then builtins.fetchTarball { - url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; - } else (import {}).fetchFromGitHub { - inherit owner repo rev sha256 fetchSubmodules private; - }; - json = builtins.fromJSON (builtins.readFile ./github.json); -in fetch json \ No newline at end of file diff --git a/dep/pandoc-link-context/default.nix b/dep/pandoc-link-context/default.nix deleted file mode 100644 index 2b4d4ab1..00000000 --- a/dep/pandoc-link-context/default.nix +++ /dev/null @@ -1,2 +0,0 @@ -# DO NOT HAND-EDIT THIS FILE -import (import ./thunk.nix) \ No newline at end of file diff --git a/dep/pandoc-link-context/github.json b/dep/pandoc-link-context/github.json deleted file mode 100644 index d14297b7..00000000 --- a/dep/pandoc-link-context/github.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "owner": "srid", - "repo": "pandoc-link-context", - "branch": "master", - "private": false, - "rev": "85bd204339aafd309b8a3dd99ebffa6a50776cb6", - "sha256": "1iyq4z54cjq4drnv27s69f7m0d75nckg31bm5yf561xpxphc8v7x" -} diff --git a/dep/pandoc-link-context/thunk.nix b/dep/pandoc-link-context/thunk.nix deleted file mode 100644 index bbf2dc18..00000000 --- a/dep/pandoc-link-context/thunk.nix +++ /dev/null @@ -1,9 +0,0 @@ -# DO NOT HAND-EDIT THIS FILE -let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: - if !fetchSubmodules && !private then builtins.fetchTarball { - url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; - } else (import {}).fetchFromGitHub { - inherit owner repo rev sha256 fetchSubmodules private; - }; - json = builtins.fromJSON (builtins.readFile ./github.json); -in fetch json \ No newline at end of file diff --git a/dep/reflex-dom-pandoc/default.nix b/dep/reflex-dom-pandoc/default.nix deleted file mode 100644 index 2b4d4ab1..00000000 --- a/dep/reflex-dom-pandoc/default.nix +++ /dev/null @@ -1,2 +0,0 @@ -# DO NOT HAND-EDIT THIS FILE -import (import ./thunk.nix) \ No newline at end of file diff --git a/dep/reflex-dom-pandoc/github.json b/dep/reflex-dom-pandoc/github.json deleted file mode 100644 index 4d33d973..00000000 --- a/dep/reflex-dom-pandoc/github.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "owner": "srid", - "repo": "reflex-dom-pandoc", - "branch": "master", - "private": false, - "rev": "b6a76c2c980a2bba9b4d170f95ef8b526ffea3a4", - "sha256": "1fqpc87mfjcjn5dnh2swzasjy0vkwq3x2yqgff5ww3pdalfk22k9" -} diff --git a/dep/reflex-dom-pandoc/thunk.nix b/dep/reflex-dom-pandoc/thunk.nix deleted file mode 100644 index bbf2dc18..00000000 --- a/dep/reflex-dom-pandoc/thunk.nix +++ /dev/null @@ -1,9 +0,0 @@ -# DO NOT HAND-EDIT THIS FILE -let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: - if !fetchSubmodules && !private then builtins.fetchTarball { - url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; - } else (import {}).fetchFromGitHub { - inherit owner repo rev sha256 fetchSubmodules private; - }; - json = builtins.fromJSON (builtins.readFile ./github.json); -in fetch json \ No newline at end of file diff --git a/dep/reflex-fsnotify/default.nix b/dep/reflex-fsnotify/default.nix deleted file mode 100644 index 2b4d4ab1..00000000 --- a/dep/reflex-fsnotify/default.nix +++ /dev/null @@ -1,2 +0,0 @@ -# DO NOT HAND-EDIT THIS FILE -import (import ./thunk.nix) \ No newline at end of file diff --git a/dep/reflex-fsnotify/github.json b/dep/reflex-fsnotify/github.json deleted file mode 100644 index 04629556..00000000 --- a/dep/reflex-fsnotify/github.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "owner": "reflex-frp", - "repo": "reflex-fsnotify", - "private": false, - "rev": "cca674623b797dd423421dec0f1da952a1d1f36d", - "sha256": "1q7mmdba2lrc8pgnqf8fif3zjprk8h5kj8l1g6gnmzqc5566qqq1" -} diff --git a/dep/reflex-fsnotify/thunk.nix b/dep/reflex-fsnotify/thunk.nix deleted file mode 100644 index bbf2dc18..00000000 --- a/dep/reflex-fsnotify/thunk.nix +++ /dev/null @@ -1,9 +0,0 @@ -# DO NOT HAND-EDIT THIS FILE -let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: - if !fetchSubmodules && !private then builtins.fetchTarball { - url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; - } else (import {}).fetchFromGitHub { - inherit owner repo rev sha256 fetchSubmodules private; - }; - json = builtins.fromJSON (builtins.readFile ./github.json); -in fetch json \ No newline at end of file diff --git a/docker.nix b/docker.nix deleted file mode 100644 index 323c041f..00000000 --- a/docker.nix +++ /dev/null @@ -1,35 +0,0 @@ -# Builds a docker image containing the neuron executable -# -# Run as: -# docker load -i $( -# nix-build docker.nix \ -# --argstr name \ -# --argstr tag -# ) -let - pkgs = import ./nixpkgs.nix { }; - neuron = (import ./project.nix { }).neuron; -in -{ name ? "sridca/neuron" -, tag ? "dev" -}: pkgs.dockerTools.buildImage { - inherit name tag; - contents = [ - neuron - # These are required for the GitLab CI runner - pkgs.coreutils - pkgs.bash_5 - ]; - - config = { - Env = [ - # For i18n to work (with filenames, etc.) - "LANG=en_US.UTF-8" - "LOCALE_ARCHIVE=${pkgs.glibcLocales}/lib/locale/locale-archive" - ]; - WorkingDir = "/notes"; - Volumes = { - "/notes" = { }; - }; - }; -} diff --git a/nixpkgs.nix b/nixpkgs.nix deleted file mode 100644 index 154207c9..00000000 --- a/nixpkgs.nix +++ /dev/null @@ -1,9 +0,0 @@ -let - lock = builtins.fromJSON (builtins.readFile ./flake.lock); - nixpkgs = lock.nodes.nixpkgs.locked; - -in -import (fetchTarball { - url = "https://github.com/nixos/nixpkgs/archive/${nixpkgs.rev}.tar.gz"; - sha256 = nixpkgs.narHash; -}) diff --git a/project.nix b/project.nix deleted file mode 100644 index b2b676c8..00000000 --- a/project.nix +++ /dev/null @@ -1,139 +0,0 @@ -let - nixpkgs = import ./nixpkgs.nix { }; -in -{ pkgs ? nixpkgs -, pkgsForBins ? null -, static ? false -, neuronFlags ? [ ] -, withHoogle ? false -, ... -}: - -let - inherit (pkgs.haskell.lib) - overrideCabal doJailbreak dontCheck justStaticExecutables appendConfigureFlags; - nix-filter = import ./dep/nix-filter; - inherit (nix-filter) inDirectory; - inherit (import ./dep/nix-thunk { }) - thunkSource; - # Deal with non-Nix Haskellers allowing broken symlinks in an otherwise - # standalone Cabal package directory. - fuckSymlinkAbuse = p: pkgs.haskell.lib.overrideCabal p (drv: { - postUnpack = '' - echo fuck > $sourceRoot/README.md - echo fuck > $sourceRoot/LICENSE - ''; - }); - unfuckCoLog = p: pkgs.haskell.lib.overrideCabal p (drv: { - postUnpack = drv.postUnpack + '' - # Ditch executable stanzas that fail to build - # First 104 lines are enough to get the library. - head -n 104 $sourceRoot/co-log.cabal > fuck - mv fuck $sourceRoot/co-log.cabal - ''; - }); - - sources = { - neuron = nix-filter { - root = ./.; - name = "neuron"; - include = [ - "neuron-search" - "neuron.cabal" - (inDirectory "exe") - (inDirectory "src") - (inDirectory "test") - ]; - }; - reflex-dom-pandoc = thunkSource ./dep/reflex-dom-pandoc; - pandoc-link-context = thunkSource ./dep/pandoc-link-context; - directory-contents = thunkSource ./dep/directory-contents; - reflex-fsnotify = thunkSource ./dep/reflex-fsnotify; - }; - - searchBuilder = '' - mkdir -p $out/bin - cp $src/neuron-search $out/bin/neuron-search - chmod +x $out/bin/neuron-search - wrapProgram $out/bin/neuron-search --prefix 'PATH' ':' ${ - with (if pkgsForBins != null then pkgsForBins else pkgs); - lib.makeBinPath [ fzf ripgrep gawk bat findutils envsubst ] - } - PATH=$PATH:$out/bin - ''; - wrapSearchScript = drv: { - buildTools = [ pkgs.makeWrapper ]; - preConfigure = searchBuilder; - }; - - haskellOverrides = self: super: with pkgs.haskell.lib; { - pandoc-link-context = doJailbreak (self.callCabal2nix "pandoc-link-context" sources.pandoc-link-context { }); - reflex-dom-pandoc = - dontHaddock (self.callCabal2nix "reflex-dom-pandoc" sources.reflex-dom-pandoc { }); - reflex-fsnotify = - # Jailbreak to allow newer base - doJailbreak (self.callCabal2nix "reflex-fsnotify" sources.reflex-fsnotify { }); - - directory-contents = self.callCabal2nix "directory-contents" sources.directory-contents { }; - - # Test fails on pkgsMusl - time-compat = if static then (dontCheck super.time-compat) else super.time-compat; - - neuron = appendConfigureFlags - ((justStaticExecutables - (overrideCabal (self.callCabal2nix "neuron" sources.neuron { }) - wrapSearchScript)).overrideDerivation (drv: { - # Avoid transitive runtime dependency on the whole GHC distribution due to - # Cabal's `Path_*` module thingy. For details, see: - # https://github.com/NixOS/nixpkgs/blob/46405e7952c4b41ca0ba9c670fe9a84e8a5b3554/pkgs/development/tools/pandoc/default.nix#L13-L28 - # - # In order to keep this list up to date, use nix-store and why-depends as - # explained here: https://www.srid.ca/04b88e01.html - disallowedReferences = [ - self.pandoc-types - self.warp - self.HTTP - self.js-jquery - self.js-dgtable - self.js-flot - ]; - postInstall = '' - remove-references-to -t ${self.pandoc-types} $out/bin/neuron - remove-references-to -t ${self.warp} $out/bin/neuron - remove-references-to -t ${self.HTTP} $out/bin/neuron - remove-references-to -t ${self.js-jquery} $out/bin/neuron - remove-references-to -t ${self.js-dgtable} $out/bin/neuron - remove-references-to -t ${self.js-flot} $out/bin/neuron - ''; - })) - neuronFlags; - }; - - haskellPackages = pkgs.haskellPackages.override { - overrides = haskellOverrides; - }; - - nixShellSearchScript = pkgs.stdenv.mkDerivation { - name = "neuron-search"; - src = sources.neuron; - buildInputs = [ pkgs.makeWrapper ]; - buildCommand = searchBuilder; - }; - -in -{ - neuron = haskellPackages.neuron; - shell = haskellPackages.shellFor { - inherit withHoogle; - packages = p: [ p.neuron ]; - buildInputs = [ - pkgs.nixpkgs-fmt - haskellPackages.ghcid - haskellPackages.cabal-install - haskellPackages.haskell-language-server - haskellPackages.hlint - haskellPackages.ormolu - nixShellSearchScript - ]; - }; -} diff --git a/src/Neuron/Zettelkasten/Zettel.hs b/src/Neuron/Zettelkasten/Zettel.hs index 3f9d96a2..773c9492 100644 --- a/src/Neuron/Zettelkasten/Zettel.hs +++ b/src/Neuron/Zettelkasten/Zettel.hs @@ -118,14 +118,24 @@ data PluginZettelData a where type MissingZettel = Tagged "MissingZettel" ZettelID -- | A zettel note +-- +-- The metadata could have been inferred from the content. data ZettelT c = Zettel { zettelID :: ZettelID, zettelMeta :: ZettelMeta, - zettelSlug :: Slug, - zettelDate :: Maybe DateMayTime, + -- Slug is non-changing - so, although inferred from zettelMeta, we must + -- put it here as a data type field. + zettelSlug :: Slug, -- inferred from zettelMeta + -- Since date is used as a sort key, we parse it once from zettelMeta for + -- performance reasons. + zettelDate :: Maybe DateMayTime, -- inferred from zettelMeta + + -- | Relative path to this zettel in the zettelkasten directory zettelPath :: FilePath, zettelTitle :: Text, zettelContent :: c, + -- This type is a Maybe only so that we can use omitNothingFields to strip + -- it off the output JSON. zettelPluginData :: Maybe (DMap PluginZettelData Identity) } deriving (Generic) diff --git a/static.nix b/static.nix deleted file mode 100644 index 924d4443..00000000 --- a/static.nix +++ /dev/null @@ -1,30 +0,0 @@ -args@{ ... }: -let - nixpkgs = import ./nixpkgs.nix { }; - nixpkgsStatic = import ./nixpkgs.nix { - overlays = [ - (self: super: { - # https://github.com/NixOS/nixpkgs/issues/131557 - python3 = super.python3.override { enableLTO = false; }; - }) - ]; - }; - pkgs = nixpkgsStatic.pkgsMusl; -in -(import ./project.nix { - inherit pkgs; - # We have to use original nixpkgs for fzf, etc. otherwise this will give - # error: missing bootstrap url for platform x86_64-unknown-linux-musl - pkgsForBins = nixpkgs; - neuronFlags = [ - "--ghc-option=-optl=-static" - # Disabling shared as workaround. But - https://github.com/nh2/static-haskell-nix/issues/99#issuecomment-665400600 - # TODO: Patch ghc bootstrap binary to use ncurses6, which might also obviate the nixpkgs revert. - "--disable-shared" - "--extra-lib-dirs=${pkgs.gmp6.override { withStatic = true; }}/lib" - "--extra-lib-dirs=${pkgs.zlib.static}/lib" - "--extra-lib-dirs=${pkgs.libffi.overrideAttrs (old: { dontDisableStatic = true; })}/lib" - "--extra-lib-dirs=${pkgs.ncurses.override { enableStatic = true; }}/lib" - ]; -}).neuron - From 9117bea50e16f125b5938e5c654729691658bfb9 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 15:33:10 -0400 Subject: [PATCH 18/19] CI: only build for PRs and master; add nixConfig cachix --- .github/workflows/ci.yaml | 13 +------------ flake.nix | 5 +++++ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0c2cdb52..2418b9c0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -2,6 +2,7 @@ name: "CI" on: pull_request: push: + branches: [master] concurrency: group: ci-${{ github.event_name }}-${{ github.ref }} jobs: @@ -10,9 +11,6 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] - env: - MAINLINE: refs/heads/master - DOCKERTAG: latest steps: - uses: actions/checkout@v4 - uses: cachix/install-nix-action@v31 @@ -29,12 +27,3 @@ jobs: - name: Retrieve neuron version run: | echo "NEURONVER=$(./result/bin/neuron --version)" >> $GITHUB_ENV - - name: Publish Docker image to Docker Hub - if: ${{ github.ref == env.MAINLINE && runner.os == 'Linux' }} - run: | - docker load -i $(nix-build docker.nix --argstr tag "${{ env.DOCKERTAG }}") - docker tag "sridca/neuron:${{ env.DOCKERTAG }}" "sridca/neuron:${{env.NEURONVER}}" - echo ${{ secrets.DOCKER_PASS }} | docker login -u sridca --password-stdin - set -x - docker push "sridca/neuron:${{ env.DOCKERTAG }}" - docker push "sridca/neuron:${{ env.NEURONVER }}" diff --git a/flake.nix b/flake.nix index 3c69efce..7c145b1f 100644 --- a/flake.nix +++ b/flake.nix @@ -1,6 +1,11 @@ { description = "Future-proof note-taking and publishing based on Zettelkasten"; + nixConfig = { + extra-substituters = [ "https://srid.cachix.org" ]; + extra-trusted-public-keys = [ "srid.cachix.org-1:MTQ6hBfSLVJ7E0MXBYNf1MHhAPJWIjno6K7ECCnFMVc=" ]; + }; + inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; flake-parts.url = "github:hercules-ci/flake-parts"; From 683eeaaf333136a7047f5f4268dc7045bdecab1c Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Sun, 22 Mar 2026 15:33:57 -0400 Subject: [PATCH 19/19] Restore Docker image build as flake output Add packages.dockerImage to flake.nix and restore Docker Hub push step in CI (using nix build .#dockerImage). --- .github/workflows/ci.yaml | 10 ++++++++++ flake.nix | 23 +++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2418b9c0..38755608 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,3 +27,13 @@ jobs: - name: Retrieve neuron version run: | echo "NEURONVER=$(./result/bin/neuron --version)" >> $GITHUB_ENV + - name: Publish Docker image to Docker Hub + if: ${{ github.ref == 'refs/heads/master' && runner.os == 'Linux' }} + run: | + docker load -i $(nix build .#dockerImage --print-out-paths) + docker tag "sridca/neuron:dev" "sridca/neuron:latest" + docker tag "sridca/neuron:dev" "sridca/neuron:${{ env.NEURONVER }}" + echo ${{ secrets.DOCKER_PASS }} | docker login -u sridca --password-stdin + set -x + docker push "sridca/neuron:latest" + docker push "sridca/neuron:${{ env.NEURONVER }}" diff --git a/flake.nix b/flake.nix index 7c145b1f..ece98715 100644 --- a/flake.nix +++ b/flake.nix @@ -157,6 +157,29 @@ formatter = pkgs.nixpkgs-fmt; packages.default = self'.packages.neuron; + packages.dockerImage = pkgs.dockerTools.buildImage { + name = "sridca/neuron"; + tag = "dev"; + copyToRoot = pkgs.buildEnv { + name = "neuron-docker-root"; + paths = [ + self'.packages.neuron + pkgs.coreutils + pkgs.bashInteractive + ]; + pathsToLink = [ "/bin" ]; + }; + config = { + Env = [ + "LANG=en_US.UTF-8" + "LOCALE_ARCHIVE=${pkgs.glibcLocales}/lib/locale/locale-archive" + ]; + WorkingDir = "/notes"; + Volumes = { + "/notes" = { }; + }; + }; + }; }; }; }