Commits: 6
Setup DevEnv with typst and tinymist (Typst LSP)
new file mode 100644
index 0000000..c5d670d
--- /dev/null
+++ b/.envrc
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+if ! has nix_direnv_version || ! nix_direnv_version 3.1.0; then
+ source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.1.0/direnvrc" "sha256-yMJ2OVMzrFaDPn7q8nCBZFRYpL/f0RcHzhmw/i6btJM="
+fi
+
+export DEVENV_IN_DIRENV_SHELL=true
+
+watch_file flake.nix
+watch_file flake.lock
+if ! use flake . --no-pure-eval; then
+ echo "devenv could not be built. The devenv environment was not loaded. Make the necessary changes to devenv.nix and hit enter to try again." >&2
+finew file mode 100644
index 0000000..f03ce8a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.devenv
+.direnvnew file mode 100644
index 0000000..fdbdf50
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,849 @@
+{
+ "nodes": {
+ "cachix": {
+ "inputs": {
+ "devenv": [
+ "devenv"
+ ],
+ "flake-compat": [
+ "devenv",
+ "flake-compat"
+ ],
+ "git-hooks": [
+ "devenv",
+ "git-hooks"
+ ],
+ "nixpkgs": [
+ "devenv",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1767714506,
+ "narHash": "sha256-WaTs0t1CxhgxbIuvQ97OFhDTVUGd1HA+KzLZUZBhe0s=",
+ "owner": "cachix",
+ "repo": "cachix",
+ "rev": "894c649f0daaa38bbcfb21de64be47dfa7cd0ec9",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "ref": "latest",
+ "repo": "cachix",
+ "type": "github"
+ }
+ },
+ "cachix_2": {
+ "inputs": {
+ "devenv": [
+ "devenv",
+ "crate2nix"
+ ],
+ "flake-compat": [
+ "devenv",
+ "crate2nix"
+ ],
+ "git-hooks": "git-hooks",
+ "nixpkgs": "nixpkgs"
+ },
+ "locked": {
+ "lastModified": 1767714506,
+ "narHash": "sha256-WaTs0t1CxhgxbIuvQ97OFhDTVUGd1HA+KzLZUZBhe0s=",
+ "owner": "cachix",
+ "repo": "cachix",
+ "rev": "894c649f0daaa38bbcfb21de64be47dfa7cd0ec9",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "ref": "latest",
+ "repo": "cachix",
+ "type": "github"
+ }
+ },
+ "cachix_3": {
+ "inputs": {
+ "devenv": [
+ "devenv",
+ "crate2nix",
+ "crate2nix_stable"
+ ],
+ "flake-compat": [
+ "devenv",
+ "crate2nix",
+ "crate2nix_stable"
+ ],
+ "git-hooks": "git-hooks_2",
+ "nixpkgs": "nixpkgs_2"
+ },
+ "locked": {
+ "lastModified": 1767714506,
+ "narHash": "sha256-WaTs0t1CxhgxbIuvQ97OFhDTVUGd1HA+KzLZUZBhe0s=",
+ "owner": "cachix",
+ "repo": "cachix",
+ "rev": "894c649f0daaa38bbcfb21de64be47dfa7cd0ec9",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "ref": "latest",
+ "repo": "cachix",
+ "type": "github"
+ }
+ },
+ "crate2nix": {
+ "inputs": {
+ "cachix": "cachix_2",
+ "crate2nix_stable": "crate2nix_stable",
+ "devshell": "devshell_2",
+ "flake-compat": "flake-compat_2",
+ "flake-parts": "flake-parts_2",
+ "nix-test-runner": "nix-test-runner_2",
+ "nixpkgs": [
+ "devenv",
+ "nixpkgs"
+ ],
+ "pre-commit-hooks": "pre-commit-hooks_2"
+ },
+ "locked": {
+ "lastModified": 1773440526,
+ "narHash": "sha256-OcX1MYqUdoalY3/vU67PEx8m6RvqGxX0LwKonjzXn7I=",
+ "owner": "nix-community",
+ "repo": "crate2nix",
+ "rev": "e697d3049c909580128caa856ab8eb709556a97b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "repo": "crate2nix",
+ "type": "github"
+ }
+ },
+ "crate2nix_stable": {
+ "inputs": {
+ "cachix": "cachix_3",
+ "crate2nix_stable": [
+ "devenv",
+ "crate2nix",
+ "crate2nix_stable"
+ ],
+ "devshell": "devshell",
+ "flake-compat": "flake-compat",
+ "flake-parts": "flake-parts",
+ "nix-test-runner": "nix-test-runner",
+ "nixpkgs": "nixpkgs_3",
+ "pre-commit-hooks": "pre-commit-hooks"
+ },
+ "locked": {
+ "lastModified": 1769627083,
+ "narHash": "sha256-SUuruvw1/moNzCZosHaa60QMTL+L9huWdsCBN6XZIic=",
+ "owner": "nix-community",
+ "repo": "crate2nix",
+ "rev": "7c33e664668faecf7655fa53861d7a80c9e464a2",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "ref": "0.15.0",
+ "repo": "crate2nix",
+ "type": "github"
+ }
+ },
+ "devenv": {
+ "inputs": {
+ "cachix": "cachix",
+ "crate2nix": "crate2nix",
+ "flake-compat": "flake-compat_3",
+ "flake-parts": "flake-parts_3",
+ "git-hooks": "git-hooks_3",
+ "nix": "nix",
+ "nixd": "nixd",
+ "nixpkgs": [
+ "nixpkgs"
+ ],
+ "rust-overlay": "rust-overlay"
+ },
+ "locked": {
+ "lastModified": 1774052327,
+ "narHash": "sha256-gQhiHj8q5NAa8jGTmoaS8FRgo8bVoAL2difjmcLtdgo=",
+ "owner": "cachix",
+ "repo": "devenv",
+ "rev": "43c650cae3ca65b6095819e4613614c242588cd7",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "repo": "devenv",
+ "type": "github"
+ }
+ },
+ "devshell": {
+ "inputs": {
+ "nixpkgs": [
+ "devenv",
+ "crate2nix",
+ "crate2nix_stable",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1768818222,
+ "narHash": "sha256-460jc0+CZfyaO8+w8JNtlClB2n4ui1RbHfPTLkpwhU8=",
+ "owner": "numtide",
+ "repo": "devshell",
+ "rev": "255a2b1725a20d060f566e4755dbf571bbbb5f76",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "devshell",
+ "type": "github"
+ }
+ },
+ "devshell_2": {
+ "inputs": {
+ "nixpkgs": [
+ "devenv",
+ "crate2nix",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1768818222,
+ "narHash": "sha256-460jc0+CZfyaO8+w8JNtlClB2n4ui1RbHfPTLkpwhU8=",
+ "owner": "numtide",
+ "repo": "devshell",
+ "rev": "255a2b1725a20d060f566e4755dbf571bbbb5f76",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "devshell",
+ "type": "github"
+ }
+ },
+ "flake-compat": {
+ "locked": {
+ "lastModified": 1733328505,
+ "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
+ "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
+ "revCount": 69,
+ "type": "tarball",
+ "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.1.0/01948eb7-9cba-704f-bbf3-3fa956735b52/source.tar.gz"
+ },
+ "original": {
+ "type": "tarball",
+ "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
+ }
+ },
+ "flake-compat_2": {
+ "locked": {
+ "lastModified": 1733328505,
+ "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
+ "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
+ "revCount": 69,
+ "type": "tarball",
+ "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.1.0/01948eb7-9cba-704f-bbf3-3fa956735b52/source.tar.gz"
+ },
+ "original": {
+ "type": "tarball",
+ "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
+ }
+ },
+ "flake-compat_3": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1767039857,
+ "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
+ "owner": "edolstra",
+ "repo": "flake-compat",
+ "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
+ "type": "github"
+ },
+ "original": {
+ "owner": "edolstra",
+ "repo": "flake-compat",
+ "type": "github"
+ }
+ },
+ "flake-parts": {
+ "inputs": {
+ "nixpkgs-lib": [
+ "devenv",
+ "crate2nix",
+ "crate2nix_stable",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1768135262,
+ "narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=",
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "type": "github"
+ }
+ },
+ "flake-parts_2": {
+ "inputs": {
+ "nixpkgs-lib": [
+ "devenv",
+ "crate2nix",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1768135262,
+ "narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=",
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "type": "github"
+ }
+ },
+ "flake-parts_3": {
+ "inputs": {
+ "nixpkgs-lib": [
+ "devenv",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1772408722,
+ "narHash": "sha256-rHuJtdcOjK7rAHpHphUb1iCvgkU3GpfvicLMwwnfMT0=",
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "rev": "f20dc5d9b8027381c474144ecabc9034d6a839a3",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "type": "github"
+ }
+ },
+ "git-hooks": {
+ "inputs": {
+ "flake-compat": [
+ "devenv",
+ "crate2nix",
+ "cachix",
+ "flake-compat"
+ ],
+ "gitignore": "gitignore",
+ "nixpkgs": [
+ "devenv",
+ "crate2nix",
+ "cachix",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1765404074,
+ "narHash": "sha256-+ZDU2d+vzWkEJiqprvV5PR26DVFN2vgddwG5SnPZcUM=",
+ "owner": "cachix",
+ "repo": "git-hooks.nix",
+ "rev": "2d6f58930fbcd82f6f9fd59fb6d13e37684ca529",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "repo": "git-hooks.nix",
+ "type": "github"
+ }
+ },
+ "git-hooks_2": {
+ "inputs": {
+ "flake-compat": [
+ "devenv",
+ "crate2nix",
+ "crate2nix_stable",
+ "cachix",
+ "flake-compat"
+ ],
+ "gitignore": "gitignore_2",
+ "nixpkgs": [
+ "devenv",
+ "crate2nix",
+ "crate2nix_stable",
+ "cachix",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1765404074,
+ "narHash": "sha256-+ZDU2d+vzWkEJiqprvV5PR26DVFN2vgddwG5SnPZcUM=",
+ "owner": "cachix",
+ "repo": "git-hooks.nix",
+ "rev": "2d6f58930fbcd82f6f9fd59fb6d13e37684ca529",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "repo": "git-hooks.nix",
+ "type": "github"
+ }
+ },
+ "git-hooks_3": {
+ "inputs": {
+ "flake-compat": [
+ "devenv",
+ "flake-compat"
+ ],
+ "gitignore": "gitignore_5",
+ "nixpkgs": [
+ "devenv",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1772893680,
+ "narHash": "sha256-JDqZMgxUTCq85ObSaFw0HhE+lvdOre1lx9iI6vYyOEs=",
+ "owner": "cachix",
+ "repo": "git-hooks.nix",
+ "rev": "8baab586afc9c9b57645a734c820e4ac0a604af9",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "repo": "git-hooks.nix",
+ "type": "github"
+ }
+ },
+ "gitignore": {
+ "inputs": {
+ "nixpkgs": [
+ "devenv",
+ "crate2nix",
+ "cachix",
+ "git-hooks",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1709087332,
+ "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "type": "github"
+ }
+ },
+ "gitignore_2": {
+ "inputs": {
+ "nixpkgs": [
+ "devenv",
+ "crate2nix",
+ "crate2nix_stable",
+ "cachix",
+ "git-hooks",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1709087332,
+ "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "type": "github"
+ }
+ },
+ "gitignore_3": {
+ "inputs": {
+ "nixpkgs": [
+ "devenv",
+ "crate2nix",
+ "crate2nix_stable",
+ "pre-commit-hooks",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1709087332,
+ "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "type": "github"
+ }
+ },
+ "gitignore_4": {
+ "inputs": {
+ "nixpkgs": [
+ "devenv",
+ "crate2nix",
+ "pre-commit-hooks",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1709087332,
+ "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "type": "github"
+ }
+ },
+ "gitignore_5": {
+ "inputs": {
+ "nixpkgs": [
+ "devenv",
+ "git-hooks",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1709087332,
+ "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "type": "github"
+ }
+ },
+ "nix": {
+ "inputs": {
+ "flake-compat": [
+ "devenv",
+ "flake-compat"
+ ],
+ "flake-parts": [
+ "devenv",
+ "flake-parts"
+ ],
+ "git-hooks-nix": [
+ "devenv",
+ "git-hooks"
+ ],
+ "nixpkgs": [
+ "devenv",
+ "nixpkgs"
+ ],
+ "nixpkgs-23-11": [
+ "devenv"
+ ],
+ "nixpkgs-regression": [
+ "devenv"
+ ]
+ },
+ "locked": {
+ "lastModified": 1773936165,
+ "narHash": "sha256-iL6V03FP1vLJ/YJr0KHcNP+0lyyM9pT4rnRSk57DSYc=",
+ "owner": "cachix",
+ "repo": "nix",
+ "rev": "185e962dbc1b4925f5da3d05725a11e2ecea4a14",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "ref": "devenv-2.32",
+ "repo": "nix",
+ "type": "github"
+ }
+ },
+ "nix-test-runner": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1588761593,
+ "narHash": "sha256-FKJykltAN/g3eIceJl4SfDnnyuH2jHImhMrXS2KvGIs=",
+ "owner": "stoeffel",
+ "repo": "nix-test-runner",
+ "rev": "c45d45b11ecef3eb9d834c3b6304c05c49b06ca2",
+ "type": "github"
+ },
+ "original": {
+ "owner": "stoeffel",
+ "repo": "nix-test-runner",
+ "type": "github"
+ }
+ },
+ "nix-test-runner_2": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1588761593,
+ "narHash": "sha256-FKJykltAN/g3eIceJl4SfDnnyuH2jHImhMrXS2KvGIs=",
+ "owner": "stoeffel",
+ "repo": "nix-test-runner",
+ "rev": "c45d45b11ecef3eb9d834c3b6304c05c49b06ca2",
+ "type": "github"
+ },
+ "original": {
+ "owner": "stoeffel",
+ "repo": "nix-test-runner",
+ "type": "github"
+ }
+ },
+ "nixd": {
+ "inputs": {
+ "flake-parts": [
+ "devenv",
+ "flake-parts"
+ ],
+ "nixpkgs": [
+ "devenv",
+ "nixpkgs"
+ ],
+ "treefmt-nix": "treefmt-nix"
+ },
+ "locked": {
+ "lastModified": 1773634079,
+ "narHash": "sha256-49qb4QNMv77VOeEux+sMd0uBhPvvHgVc0r938Bulvbo=",
+ "owner": "nix-community",
+ "repo": "nixd",
+ "rev": "8ecf93d4d93745e05ea53534e8b94f5e9506e6bd",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "repo": "nixd",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1765186076,
+ "narHash": "sha256-hM20uyap1a0M9d344I692r+ik4gTMyj60cQWO+hAYP8=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "addf7cf5f383a3101ecfba091b98d0a1263dc9b8",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "nixpkgs-src": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1773597492,
+ "narHash": "sha256-hQ284SkIeNaeyud+LS0WVLX+WL2rxcVZLFEaK0e03zg=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "a07d4ce6bee67d7c838a8a5796e75dff9caa21ef",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixpkgs-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "nixpkgs_2": {
+ "locked": {
+ "lastModified": 1765186076,
+ "narHash": "sha256-hM20uyap1a0M9d344I692r+ik4gTMyj60cQWO+hAYP8=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "addf7cf5f383a3101ecfba091b98d0a1263dc9b8",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "nixpkgs_3": {
+ "locked": {
+ "lastModified": 1769433173,
+ "narHash": "sha256-Gf1dFYgD344WZ3q0LPlRoWaNdNQq8kSBDLEWulRQSEs=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "13b0f9e6ac78abbbb736c635d87845c4f4bee51b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixpkgs-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "nixpkgs_4": {
+ "inputs": {
+ "nixpkgs-src": "nixpkgs-src"
+ },
+ "locked": {
+ "lastModified": 1773704619,
+ "narHash": "sha256-LKtmit8Sr81z8+N2vpIaN/fyiQJ8f7XJ6tMSKyDVQ9s=",
+ "owner": "cachix",
+ "repo": "devenv-nixpkgs",
+ "rev": "906534d75b0e2fe74a719559dfb1ad3563485f43",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "ref": "rolling",
+ "repo": "devenv-nixpkgs",
+ "type": "github"
+ }
+ },
+ "pre-commit-hooks": {
+ "inputs": {
+ "flake-compat": [
+ "devenv",
+ "crate2nix",
+ "crate2nix_stable",
+ "flake-compat"
+ ],
+ "gitignore": "gitignore_3",
+ "nixpkgs": [
+ "devenv",
+ "crate2nix",
+ "crate2nix_stable",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1769069492,
+ "narHash": "sha256-Efs3VUPelRduf3PpfPP2ovEB4CXT7vHf8W+xc49RL/U=",
+ "owner": "cachix",
+ "repo": "pre-commit-hooks.nix",
+ "rev": "a1ef738813b15cf8ec759bdff5761b027e3e1d23",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "repo": "pre-commit-hooks.nix",
+ "type": "github"
+ }
+ },
+ "pre-commit-hooks_2": {
+ "inputs": {
+ "flake-compat": [
+ "devenv",
+ "crate2nix",
+ "flake-compat"
+ ],
+ "gitignore": "gitignore_4",
+ "nixpkgs": [
+ "devenv",
+ "crate2nix",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1769069492,
+ "narHash": "sha256-Efs3VUPelRduf3PpfPP2ovEB4CXT7vHf8W+xc49RL/U=",
+ "owner": "cachix",
+ "repo": "pre-commit-hooks.nix",
+ "rev": "a1ef738813b15cf8ec759bdff5761b027e3e1d23",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "repo": "pre-commit-hooks.nix",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "devenv": "devenv",
+ "nixpkgs": "nixpkgs_4",
+ "systems": "systems"
+ }
+ },
+ "rust-overlay": {
+ "inputs": {
+ "nixpkgs": [
+ "devenv",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1773630837,
+ "narHash": "sha256-zJhgAGnbVKeBMJOb9ctZm4BGS/Rnrz+5lfSXTVah4HQ=",
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "rev": "f600ea449c7b5bb596fa1cf21c871cc5b9e31316",
+ "type": "github"
+ },
+ "original": {
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "type": "github"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ },
+ "treefmt-nix": {
+ "inputs": {
+ "nixpkgs": [
+ "devenv",
+ "nixd",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1772660329,
+ "narHash": "sha256-IjU1FxYqm+VDe5qIOxoW+pISBlGvVApRjiw/Y/ttJzY=",
+ "owner": "numtide",
+ "repo": "treefmt-nix",
+ "rev": "3710e0e1218041bbad640352a0440114b1e10428",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "treefmt-nix",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}new file mode 100644
index 0000000..74cf48c
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,39 @@
+{
+ inputs = {
+ nixpkgs.url = "github:cachix/devenv-nixpkgs/rolling";
+ systems.url = "github:nix-systems/default";
+ devenv.url = "github:cachix/devenv";
+ devenv.inputs.nixpkgs.follows = "nixpkgs";
+ };
+
+ nixConfig = {
+ extra-trusted-public-keys = "devenv.cachix.org-1:w1cLUi8dv3hnoSPGAuibQv+f9TZLr6cv/Hm9XgU50cw=";
+ extra-substituters = "https://devenv.cachix.org";
+ };
+
+ outputs = { self, nixpkgs, devenv, systems, ... } @ inputs:
+ let
+ forEachSystem = nixpkgs.lib.genAttrs (import systems);
+ in
+ {
+ devShells = forEachSystem
+ (system:
+ let
+ pkgs = nixpkgs.legacyPackages.${system};
+ in
+ {
+ default = devenv.lib.mkShell {
+ inherit inputs pkgs;
+ modules = [
+ {
+ # https://devenv.sh/reference/options/
+ packages = with pkgs; [
+ typst
+ tinymist
+ ];
+ }
+ ];
+ };
+ });
+ };
+}new file mode 100644
index 0000000..d4c65e2
--- /dev/null
+++ b/playground.typ
@@ -0,0 +1,11 @@
+= Layout Playground
+
++ First thing
++ Second thing
+
+Here?
+
+There?
+
+#circle(fill: red, width: 100% )[#align(center)[Hello there]]
+Describe the problem
index d4c65e2..b166f27 100644
--- a/playground.typ
+++ b/playground.typ
@@ -1,11 +1,17 @@
== Layout Playground
=
-+ First thing
-+ Second thing
+#let images = ((60, 120), (120, 200), (100, 40), (300, 250))
=
-Here?
+We have #images.len() images.
=
-There?
+#for ((width, height)) in images {
+ rect(width: width * 1pt, height: height * 1pt, align(center + horizon)[#width × #height])
+}
+
+The goal is to put them in a row, so that:
+
++ The whole available width of the page is used.
++ All images have the same height.
++ The aspect ratio of every image is preserved.
=
-#circle(fill: red, width: 100% )[#align(center)[Hello there]]
=Implement the solution and describe the math
I haven't figured out yet how to get the actual dimensions of the parent
container. There are layout and measure functions, but they confuse
me.
index b166f27..340560d 100644
--- a/playground.typ
+++ b/playground.typ
@@ -1,11 +1,25 @@
== Layout Playground
=
-#let images = ((60, 120), (120, 200), (100, 40), (300, 250))
+#let images = (
+ (60, 120, red),
+ (120, 200, green),
+ (100, 30, blue),
+ (300, 250, yellow)
+)
=
=We have #images.len() images.
=
-#for ((width, height)) in images {
- rect(width: width * 1pt, height: height * 1pt, align(center + horizon)[#width × #height])
+#let rects = images.map( image => {
+ let (width, height, color) = image
+ rect(
+ width: width * 1pt,
+ height: height * 1pt,
+ fill: color,
+ align(center + horizon)[#width × #height])
+})
+
+#for r in rects {
+ r
=}
=
=The goal is to put them in a row, so that:
@@ -15,3 +29,127 @@ The goal is to put them in a row, so that:
=+ The aspect ratio of every image is preserved.
=
=
+== Step 1
+
+Calculate individual aspect ratios as $w / h$.
+
+#let aspects = images.map(size => (
+ width: size.at(0) * 1pt,
+ height: size.at(1) * 1pt,
+ ratio: size.at(0) / size.at(1))
+)
+
+#table(columns: 2,
+ [*Size*], [*Aspect ratio*],
+ ..for (width, height, ratio) in aspects {
+ ([#width × #height], [#calc.round(digits: 3, ratio)])
+ }
+)
+
+== Step 2
+
+Sum the aspect ratios of all the images to get the total aspect ratio of the row of images.
+
+#let total_aspect_ratio = aspects.map(a => a.ratio).sum()
+
+#rect(
+ height: 100% / total_aspect_ratio,
+ width: 100%,
+ align(center + horizon)[1 × #calc.round(digits: 3, total_aspect_ratio)]
+)
+
+== Step 3
+
+Take available width of the parent container (e.g. page - margins).
+
+// #let available_width = layout(size => size.width)
+// FIXME: This gives content, I want a Length. For now let's just assume it:
+#let available_width = 300pt
+
+#let straightedge = line(length: available_width)
+
+Available width: #available_width
+#straightedge
+
+For each image:
+
++ calculate the `fraction` of the width it can take, as `image_aspect_ratio / total_aspect_ratio`.
++ calculate the `final_width` as `available_width * fraction`
++ calculate the `scaling_factor` as `final_width / image_width`
++ scale the image by the `scaling_factor`
+
+
+
+#box()[
+ #grid(
+ columns: images.len(),
+
+ ..rects.enumerate().map(((index, this_rect)) => {
+ let aspect = aspects.at(index)
+ let image_aspect_ratio = aspect.ratio
+ let width_fraction = image_aspect_ratio / total_aspect_ratio
+ let final_width = width_fraction * available_width
+ let scaling_factor = final_width / aspect.width * 100%
+
+ scale(this_rect, scaling_factor, reflow: true)
+ })
+ )
+]
+#straightedge
+
+Adding gaps (gutter) between images is not difficult. Just subtract the width of the gutter (its length × number of images - 1) from the available space.
+
+#let gutter = 2pt
+
+
+#let total_gutter = gutter * (rects.len() - 1)
+#box()[
+ With gutter of #gutter
+
+ #straightedge
+ #grid(
+ columns: images.len(),
+ column-gutter: gutter,
+
+ ..rects.enumerate().map(((index, this_rect)) => {
+ let aspect = aspects.at(index)
+ let image_aspect_ratio = aspect.ratio
+ let width_fraction = image_aspect_ratio / total_aspect_ratio
+ let final_width = width_fraction * (available_width - total_gutter)
+ let scaling_factor = final_width / aspect.width * 100%
+
+ scale(this_rect, scaling_factor, reflow: true)
+ })
+ )
+]
+
+#let gutter = 16pt
+
+
+#let total_gutter = gutter * (rects.len() - 1)
+#box()[
+ With gutter of #gutter
+
+ #straightedge
+ #grid(
+ columns: images.len(),
+ column-gutter: gutter,
+
+ ..rects.enumerate().map(((index, this_rect)) => {
+ let aspect = aspects.at(index)
+ let image_aspect_ratio = aspect.ratio
+ let width_fraction = image_aspect_ratio / total_aspect_ratio
+ let final_width = width_fraction * (available_width - total_gutter)
+ let scaling_factor = final_width / aspect.width * 100%
+
+ scale(this_rect, scaling_factor, reflow: true)
+ })
+ )
+]
+
+
+*TODO*: Pack it as a function
+
+*TODO*: Use actual images (figure out how to get their dimensions or aspect ratios)
+
+*TODO*: How to get the actual width of a parent containerImprove the document layout
Put the "images" in a grid, break page on h2
index 340560d..fbfd23b 100644
--- a/playground.typ
+++ b/playground.typ
@@ -18,9 +18,11 @@ We have #images.len() images.
= align(center + horizon)[#width × #height])
=})
=
-#for r in rects {
- r
-}
+#grid(
+ columns: (auto, auto),
+ gutter: 10pt,
+ ..rects
+)
=
=The goal is to put them in a row, so that:
=
@@ -28,6 +30,10 @@ The goal is to put them in a row, so that:
=+ All images have the same height.
=+ The aspect ratio of every image is preserved.
=
+#show heading.where(depth: 2): body => {
+ pagebreak(weak: true)
+ body
+}
=
=== Step 1
=Add some images from placedog.net (cute)
Get the dimensions of sample 2 images.
new file mode 100644
index 0000000..e637019
Binary files /dev/null and b/300x600.jpg differnew file mode 100644
index 0000000..64dd9f1
Binary files /dev/null and b/360x480.jpg differnew file mode 100644
index 0000000..1dfa8ab
Binary files /dev/null and b/500x480.jpg differnew file mode 100644
index 0000000..d0c7387
Binary files /dev/null and b/780x300.jpg differindex fbfd23b..cb902a2 100644
--- a/playground.typ
+++ b/playground.typ
@@ -154,8 +154,26 @@ Adding gaps (gutter) between images is not difficult. Just subtract the width of
=]
=
=
-*TODO*: Pack it as a function
+== Use actual images
+
+#let i = image("300x600.jpg")
+
+#box[
+ The following image size is #context measure(i)
+
+ #i
+]
+
+#let i = image("500x480.jpg")
+#box[
+ The following image size is #context measure(i)
+
+ #i
+]
+
+== *TODO*: Pack it as a function
+
+
+== *TODO*: How to get the actual width of a parent container
=
-*TODO*: Use actual images (figure out how to get their dimensions or aspect ratios)
=
-*TODO*: How to get the actual width of a parent containerImplement the solution
Works with actual images and fills the parent container. Wrapped in a
image-row function.
index cb902a2..ef39395 100644
--- a/playground.typ
+++ b/playground.typ
@@ -171,9 +171,121 @@ Adding gaps (gutter) between images is not difficult. Just subtract the width of
= #i
=]
=
-== *TODO*: Pack it as a function
+== How to get the actual width of a parent container
=
+#context layout(size => [
+ The parent layout can only be accessed inside a `context`. Here the width is #size.width. It is best to wrap the whole computation in ```typst context layout(size => { ... })``` expression.
+])
=
-== *TODO*: How to get the actual width of a parent container
+== Pack it as a function
=
+#let image-row(gutter: 0pt, ..paths) = {
+ context {
+ let images = paths.pos().map(path => {
+ let content = image(path)
+ let size = measure(content)
+ let ratio = size.width / size.height
+ return (path: path, content: content, ratio: ratio, ..size)
+ })
+
+
+ let total_ratio = images.fold(0, (acc, item) => acc + item.ratio)
+ let total_gutter = gutter * (images.len() - 1)
+
+ layout(parent => grid(
+ columns: images.len(),
+ column-gutter: gutter,
+
+ ..images.map((item) => {
+ let width_fraction = item.ratio / total_ratio
+ let final_width = width_fraction * (parent.width - total_gutter)
+ let scaling_factor = final_width / item.width * 100%
+
+ scale(item.content, scaling_factor, reflow: true)
+ })
+ ))
+ }
+}
+
+Now we have everything we need! Here are some examples.
+
+=== 4 images, no gutter
+
+#image-row(
+ "300x600.jpg",
+ "500x480.jpg",
+ "360x480.jpg",
+ "780x300.jpg",
+)
+
+=== 2 image, gutter of 2t
+
+#image-row(
+ gutter: 2pt,
+ "300x600.jpg",
+ "780x300.jpg",
+)
+
+=== 1 image, gutter set, but has no effect
+
+#image-row(
+ gutter: 2pt,
+ "780x300.jpg",
+)
+
+=== Inside a figure
+
+
+#figure(
+ caption: [Some lovely dogs here])[
+ #image-row(
+ gutter: 4pt,
+ "360x480.jpg",
+ "780x300.jpg",
+ "300x600.jpg",
+ "500x480.jpg",
+ )
+ ]
+
+#pagebreak()
+
+=== Inside containers of various sizes
+
+#for width in (40%, 60%, 85%) {
+ align(center, rect(
+ width: width
+
+ )[
+ #layout(size => [This container is #size.width wide])
+ #image-row(
+ gutter: 4pt,
+ "360x480.jpg",
+ "780x300.jpg",
+ "300x600.jpg",
+ "500x480.jpg",
+ )
+ ])
+}
+
+
+#pagebreak()
+
+=== Multiple rows
+
+#image-row(
+ gutter: 4pt,
+ "300x600.jpg",
+ "780x300.jpg",
+)
+#v(4pt, weak: true)
+#image-row(
+ gutter: 4pt,
+ "360x480.jpg",
+ "500x480.jpg",
+)
+
+== TODO: Implement `image-rows` function
=
++ Multiple rows, each in an array
++ Automatic vertical spacing
++ In a box, to prevent page breaks inside