nandi/frqpublic Fork 0
e50cbc7270d8278b3f9d2bad4f5eb99ac57207e4
Commits
Clone
git clone https://git.rickub.com/nandi/frq.git
git clone ssh://git@rickub.com/nandi/frq.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

justfile · 503 lines · 22.1 KBMakefile Blame HistoryRaw
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago1# The work is here now, in recipe bodies, where it used to be in scripts/ —
2# babashka scripts run through a scripts/bb that went looking for a babashka.
3# That indirection bought one thing worth having, a shared way to reach nix on
4# a host that keeps it in a container, and `nix` below is the whole of it.
5#
One frontend where there were three, and a core that is not Clojure 438b247 nandi 21h ago6# Every recipe that builds has the same shape: outside the dev shell, re-enter
7# it and come back to this same recipe; inside, do the work. The re-entry test
8# is an environment variable only the shell sets — no flag to forget, and no
9# second code path for someone who runs `nix develop --command just ...` by
10# hand.
Take glimmer-vidya from gitlab, so a stranger can build this 5c40e75 nandi 19d ago11
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago12set shell := ["bash", "-euo", "pipefail", "-c"]
A freeq client in jolt, as glimmer components on Vidya 4719d6f nandi 20d ago13
Give the terminal's classpath an nREPL, and hand recipes their arguments 664397d nandi 10d ago14# Every recipe below is a `#!` script and passes its arguments on with "$@".
15# Without this that is empty in one — just interpolates into a shebang recipe
One frontend where there were three, and a core that is not Clojure 438b247 nandi 21h ago16# rather than handing it argv — and a recipe silently ignored its flags.
Give the terminal's classpath an nREPL, and hand recipes their arguments 664397d nandi 10d ago17set positional-arguments
18
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago19# nix is not on every host this runs on: on the machine these recipes were
20# written for it lives in an Arch distrobox, at the same path — which is why
21# the container is entered rather than the tree copied into it. See CLAUDE.md.
22nix := `command -v nix >/dev/null 2>&1 && echo nix || echo "distrobox enter arch -- nix"`
23
24# --max-jobs 0 is what sends the work to the `builders` entry rather than
25# compiling it here. Left to the default, nix prefers the local machine, and a
One frontend where there were three, and a core that is not Clojure 438b247 nandi 21h ago26# cold Flutter toolchain is a lot of compiling on a laptop — for a derivation a
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago27# remote builder has likely built already. FRQ_MAX_JOBS=auto is the way out on
28# a machine with no builder configured.
29jobs := env("FRQ_MAX_JOBS", "0")
30
A freeq client in jolt, as glimmer components on Vidya 4719d6f nandi 20d ago31default:
32 @just --list
33
Build the APK, out of ClojureDart and Flutter e2b0e6b nandi 7d ago34# The APK: ClojureDart compiled to Dart, then Flutter's Gradle build.
35#
36# Impure on purpose, and worth saying why rather than leaving it to be
37# discovered. Gradle resolves its own dependencies over the network and
38# installs build-tools and a platform into ANDROID_HOME as it goes, so it
39# cannot run in a sandbox and cannot write to the store. What nix gives here
40# is the toolchain — clojure, a JDK, Flutter, and an SDK composed by
41# androidenv — and the recipe copies that SDK somewhere writable
42# (flutter/.home) for Gradle to finish off. That copy and everything Gradle
43# leaves behind are gitignored.
44#
45# No ndkVersion in android/app/build.gradle.kts, for the same reason: the
46# Flutter template sets it, setting it makes Gradle fetch that exact NDK, and
47# there is no native code here to need one.
48#
49# just apk build the debug APK
50# just apk install build it and put it on a connected device
51# just apk run install and launch
52# just apk log logcat, filtered to this app
53apk action="build":
54 #!/usr/bin/env bash
55 set -euo pipefail
56 cd "{{justfile_directory()}}/flutter"
57
Build the APK from the flake, at the rev flake.lock pins 77d4bec nandi 7d ago58 # The flake's, not an --impure --expr against whatever nixos-unstable is
59 # today: the licence config the SDK needs lives in `androidPkgsFor` now,
60 # so this is an ordinary output at the rev flake.lock pins.
61 sdk="$(nix build --no-link --print-out-paths \
62 "{{justfile_directory()}}#android-sdk")/libexec/android-sdk"
Build the APK, out of ClojureDart and Flutter e2b0e6b nandi 7d ago63
Let adb keep its identity when the APK recipe moves HOME bc0e14f nandi 7d ago64 # adb keeps the key the phone has already trusted under the real HOME, and
65 # HOME moves below so Gradle can write into the SDK copy. Told where to
66 # look, adb keeps its identity; left to find $HOME/.android it generates a
67 # new one, the device stops recognising this machine, and the deploy ends
68 # in "no devices/emulators found" while `adb devices` in any other shell
69 # lists it perfectly well.
70 export ANDROID_USER_HOME="${ANDROID_USER_HOME:-$HOME/.android}"
71
Build the APK, out of ClojureDart and Flutter e2b0e6b nandi 7d ago72 export HOME="$PWD/.home"
73 export ANDROID_HOME="$HOME/android-sdk"
74 export ANDROID_SDK_ROOT="$ANDROID_HOME"
75 mkdir -p "$HOME"
76
77 # Gradle writes into ANDROID_HOME, so it is a copy rather than the store
78 # path. Made once and kept: re-copying would throw away the build-tools
79 # and platform Gradle installed into it on the last run.
80 if [ ! -d "$ANDROID_HOME" ]; then
81 cp -r "$sdk" "$ANDROID_HOME"
82 chmod -R u+w "$ANDROID_HOME"
83 fi
84
Seed the ClojureDart caches out of the flake f2e12af nandi 7d ago85 # The compile's three caches, same flake-output-and-copy shape as the SDK
86 # and for the same reason: tools.deps and pub both write into theirs, and
87 # the store is read-only. What this buys is the "Resolving dependencies…
88 # Downloading packages…" that used to open every run.
89 deps="$(nix build --no-link --print-out-paths \
90 "{{justfile_directory()}}#cljd-deps")"
91
92 # Neither of these follows HOME. Both are read off the JVM's user.home,
93 # which comes from /etc/passwd rather than the environment — so moving
94 # HOME below is not enough to move them, and left alone they would be the
95 # real ~/.m2 and ~/.gitlibs, shared with every other project on the box.
96 export GITLIBS="$HOME/gitlibs"
97 m2="$HOME/m2"
98 export PUB_CACHE="$HOME/.pub-cache"
99
100 # Seeded once each and then left alone, exactly as ANDROID_HOME is: after
101 # the first compile these hold whatever the working tree has asked for
102 # since, and re-copying would throw that away.
103 seed() {
104 [ -e "$2" ] && return 0
105 mkdir -p "$(dirname "$2")"
106 cp -r "$deps/$1" "$2"
107 chmod -R u+w "$2"
108 }
109 seed m2 "$m2"
110 seed gitlibs "$GITLIBS"
111 seed pub-cache "$PUB_CACHE"
112 seed clojuredart/cache "$PWD/.clojuredart/cache"
113
Build the APK from the flake, at the rev flake.lock pins 77d4bec nandi 7d ago114 # Also the flake's. `nix shell nixpkgs#...` read the registry, which is a
115 # different and unlocked nixpkgs — the Flutter that built the APK could
116 # move under it without flake.lock changing a line.
117 flutter="nix develop {{justfile_directory()}}#flutter --command"
Build the APK, out of ClojureDart and Flutter e2b0e6b nandi 7d ago118
Seed the ClojureDart caches out of the flake f2e12af nandi 7d ago119 # cljd-deps ships the analyzer project unresolved — a fixed-output
120 # derivation may not name the store, and a resolved pub project is
121 # nothing but store paths. So it is resolved here instead, offline,
122 # against the cache that derivation did fetch. ClojureDart reaches for the
123 # network only when bin/analyzer.dart is missing, and after this it is not.
124 for helper in .clojuredart/cache/*/cljd_helper; do
125 [ -d "$helper" ] || continue
126 [ -e "$helper/.dart_tool/package_config.json" ] && continue
127 ( cd "$helper" && $flutter flutter pub get --offline )
128 done
129
130 $flutter clojure -Sdeps "{:mvn/local-repo \"$m2\"}" -M:cljd compile
Build the APK, out of ClojureDart and Flutter e2b0e6b nandi 7d ago131
132 # Rewritten every run: it carries absolute store paths, and the flutter
133 # one moves whenever nixpkgs does.
134 $flutter flutter config --android-sdk "$ANDROID_HOME" >/dev/null
135
136 apk=build/app/outputs/flutter-apk/app-debug.apk
137 adb="${ADB:-$ANDROID_HOME/platform-tools/adb}"
138
139 case "{{action}}" in
140 build) $flutter flutter build apk --debug ;;
141 install) $flutter flutter build apk --debug && "$adb" install -r "$apk" ;;
142 run) $flutter flutter build apk --debug && "$adb" install -r "$apk" \
143 && "$adb" shell monkey -p uk.nandi.frq -c android.intent.category.LAUNCHER 1 ;;
144 log) "$adb" logcat -s flutter ;;
145 *) echo "usage: just apk [build|install|run|log]" >&2; exit 1 ;;
146 esac
147
One frontend where there were three, and a core that is not Clojure 438b247 nandi 21h ago148# What may appear in common/, checked. Needs nothing built: it reads the
149# source, so it is the one check that runs anywhere, and CI runs exactly this.
Check what common/ may contain, on every push 86c2e1b nandi 7d ago150check-common:
151 #!/usr/bin/env bash
152 python3 tools/check-common.py common
153
One frontend where there were three, and a core that is not Clojure 438b247 nandi 21h ago154# The desktop GUI: the same screens the APK paints, on Flutter's Linux target.
Give the terminal's classpath an nREPL, and hand recipes their arguments 664397d nandi 10d ago155#
One frontend where there were three, and a core that is not Clojure 438b247 nandi 21h ago156# This recipe and `just apk` are two targets over one tree, and the split is
157# the one the APK already draws. Everything under `common/` — the screens, the
158# cells, `frq.io` — is shared; what differs is who answers the host. So this
159# is `just apk` with the Android half taken out: the same `clojure -M:cljd compile` over the same flutter/src,
Paint the desktop with Flutter too, beside libcosmic fc5f63c nandi 7d ago160# then Flutter's Linux target rather than its Android one. CMake and Ninja
161# instead of Gradle, `flutter/linux/` as the runner, no SDK and no JDK.
162#
163# Still impure, for one of the two reasons `apk` is: pub.dev resolution and
164# Flutter's own engine artifacts are network. What it does NOT need is the
165# writable-ANDROID_HOME dance — nothing here writes into the store — so there
166# is no `flutter/.home` on this path.
167#
One frontend where there were three, and a core that is not Clojure 438b247 nandi 21h ago168# nixGL because Flutter paints through GL, and off NixOS the driver is the
169# host's.
Paint the desktop with Flutter too, beside libcosmic fc5f63c nandi 7d ago170#
171# just flutter-desktop build the debug bundle
172# just flutter-desktop run build it and open the window
173flutter-desktop action="build":
174 #!/usr/bin/env bash
175 set -euo pipefail
176 cd "{{justfile_directory()}}"
177 if [ -z "${FRQ_FLUTTER_DESKTOP:-}" ]; then
178 exec {{nix}} develop .#flutter-desktop --max-jobs {{jobs}} \
179 --command just flutter-desktop "$@"
180 fi
181 cd flutter
182
Seed the ClojureDart caches out of the flake f2e12af nandi 7d ago183 # The same three caches `just apk` seeds, in the same place and out of the
184 # same flake output — one compiler, one set of dependencies, and no reason
185 # for the two frontends to keep a copy each. `.home/` is `apk`'s directory
186 # by name and this is the only thing put there from here, which is the
187 # point: whichever recipe runs first pays for the copy and the other finds
188 # it warm.
189 #
190 # No `nix build` here, unlike `apk`: this recipe is already inside the
191 # shell that names FRQ_CLJD_DEPS by the time it gets this far, and `apk`
192 # needs the path before it enters anything.
193 #
194 # m2 and gitlibs are set here for the reason they are set there — the JVM
195 # reads user.home out of /etc/passwd, so neither follows HOME and left
196 # alone they are the real ~/.m2 and ~/.gitlibs.
197 export PUB_CACHE="$PWD/.home/.pub-cache"
198 export GITLIBS="$PWD/.home/gitlibs"
199 m2="$PWD/.home/m2"
200
201 seed() {
202 [ -e "$2" ] && return 0
203 mkdir -p "$(dirname "$2")"
204 cp -r "$FRQ_CLJD_DEPS/$1" "$2"
205 chmod -R u+w "$2"
206 }
207 seed m2 "$m2"
208 seed gitlibs "$GITLIBS"
209 seed pub-cache "$PUB_CACHE"
210 seed clojuredart/cache "$PWD/.clojuredart/cache"
211
212 # Resolved here rather than in cljd-deps, which was not allowed to name
213 # the store — see the same loop in `apk`.
214 for helper in .clojuredart/cache/*/cljd_helper; do
215 [ -d "$helper" ] || continue
216 [ -e "$helper/.dart_tool/package_config.json" ] && continue
217 ( cd "$helper" && flutter pub get --offline )
218 done
219
220 clojure -Sdeps "{:mvn/local-repo \"$m2\"}" -M:cljd compile
Paint the desktop with Flutter too, beside libcosmic fc5f63c nandi 7d ago221 flutter build linux --debug
222
223 # x64/arm64 is Flutter's own name for the host arch, not uname's.
224 case "$(uname -m)" in
225 x86_64) arch=x64 ;;
226 aarch64) arch=arm64 ;;
227 *) echo "unknown arch $(uname -m)" >&2; exit 1 ;;
228 esac
229 bundle="build/linux/$arch/debug/bundle"
230
231 case "{{action}}" in
232 build) echo "built $PWD/$bundle/frq" ;;
233 run)
234 runner=()
235 [ -e /run/current-system ] || runner=("$NIXGL")
236 exec "${runner[@]}" "$bundle/frq"
237 ;;
238 *) echo "usage: just flutter-desktop [build|run]" >&2; exit 1 ;;
239 esac
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago240
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago241# The third frontend: the same screens again, compiled to JavaScript.
242#
243# `flutter-desktop` with the Linux half taken out. One `clojure -M:cljd
244# compile` over the same flutter/src and common/, then Flutter's web target
245# instead of its Linux one — dart2js instead of CMake and Ninja, and a
246# directory of static files instead of a bundle with an executable in it.
247#
Three tarballs where a devShell was 5ce66d5 nandi yesterday248# And the one target with no nix in it. The other two need the host: a JDK
249# and the Android SDK for `apk`, GTK and a C++ toolchain and nixGL for
250# `flutter-desktop`. This one needs a Dart, a JVM and a browser, and the
251# browser is not ours — so `tools/toolchain.sh` fetches the first two as
252# pinned tarballs into `.toolchain/` and there is nothing left for a devShell
253# to supply. That is what lets the container in `.modal/flutter-web/` drop
254# its image build too: same script, same three pins, no store to populate.
255#
256# Impure for the reason the other two are: pub.dev resolution and Flutter's
257# engine artifacts are network, and now the toolchain is as well — pinned by
258# sha256, which is the reproducibility that was worth having out of the store.
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago259#
260# The entry point is `frq.main-web`, not `frq.main`: path_provider has no web
261# implementation, so the `getApplicationSupportDirectory` that `frq.main`
262# awaits throws MissingPluginException before any widget is built. The web
263# entry installs `frq.io.web` — localStorage behind the same seam — and awaits
264# nothing. `frq.net.dart` is still the socket half, so connecting will want a
265# WebSocket before this does more than paint.
266#
Three tarballs where a devShell was 5ce66d5 nandi yesterday267# One build and no `--debug` variant, because there is nothing to gain from
268# one: dart2js at -O1 measured 52.5s against the release build's 49.8s on the
269# same source change here, so a second, larger bundle would buy noise. See
270# `tools/build-web.sh`, which writes the numbers down.
271#
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago272# just flutter-web build build/web
273# just flutter-web serve build it and serve it on $PORT (8080)
Three tarballs where a devShell was 5ce66d5 nandi yesterday274# just flutter-web serve 3000 ...on another port
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago275flutter-web action="build" port="8080":
276 #!/usr/bin/env bash
277 set -euo pipefail
Three tarballs where a devShell was 5ce66d5 nandi yesterday278 # A wrapper and nothing else. The build is a shell script because the
279 # container runs it too, and a container that had to install `just` to
280 # start would be one dependency away from the point.
281 exec "{{justfile_directory()}}/tools/build-web.sh" {{action}} {{port}}
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago282
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago283# The containers in `.modal/`, run on Modal rather than here. This machine
284# evaluates and Modal builds — see CLAUDE.md, which says so rather more
285# firmly — and these two recipes are the whole interface to that.
286#
One frontend where there were three, and a core that is not Clojure 438b247 nandi 21h ago287# Named for where the work happens, the way `flutter-desktop` is named for
288# what paints: there is no re-entry test here because nothing
A Mesa nobody needed, and the AppImage that carried it 9db383c nandi 23h ago289# re-enters. There is no `nix` variable either, and that used to be because
One frontend where there were three, and a core that is not Clojure 438b247 nandi 21h ago290# nix ran out there — now it is because neither of these containers has any
291# nix in it at all.
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago292#
293# just modal flutter-dev the incremental Flutter loop
One frontend where there were three, and a core that is not Clojure 438b247 nandi 21h ago294# just modal flutter-web the web bundle
295modal container="flutter-dev" *args:
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago296 #!/usr/bin/env bash
297 set -euo pipefail
298 cd "{{justfile_directory()}}"
299 shift
300 exec modal run ".modal/{{container}}/container.py" "$@"
301
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago302# The Modal-built web bundle, served from this machine on localhost.
303#
304# Not a local build: `modal volume get` pulls what `just modal flutter-web`
305# already compiled out of the devshell volume, so this needs no Flutter, no
306# Dart and no nix — only python, which the flake shell has and so does the
307# machine.
308#
309# It exists for one reason, and the reason is the auth broker rather than
310# convenience. freeq's broker finishes an OAuth login by redirecting the
311# browser to `return_to`, and it will only redirect to an origin on its
312# allowlist: its own https hosts, and `http://localhost` or `http://127.0.0.1`
313# on ANY port. A build served from anywhere else — the Modal URL included —
314# gets `400 Invalid return_to URL` and can never complete a Bluesky sign-in,
315# no matter what the client does. localhost is the one allowlisted origin we
316# can serve from, so this is how Bluesky sign-in is tested.
317#
318# Guest and app-password sign-in need none of this; they work on the deployed
319# URL, because neither goes near the broker.
320#
321# just web-local fetch and serve on :8080
322# just web-local 3000 another port; any port is allowlisted
323web-local port="8080":
324 #!/usr/bin/env bash
325 set -euo pipefail
326 cd "{{justfile_directory()}}"
327 out="{{justfile_directory()}}/.web-local"
328 mkdir -p "$out"
329 echo "fetching the Modal-built bundle…"
330 # --force: this is a mirror of the volume, and a stale file left behind
331 # would be served in preference to the one just built.
332 modal volume get --force devshell frq-flutter-web/flutter/build/web "$out"
333 echo
334 echo " http://localhost:{{port}}"
335 echo
336 echo "Bluesky sign-in works here and not on the Modal URL: the broker"
337 echo "allowlists localhost on any port. Put wss://irc.freeq.at/irc in the"
338 echo "Server field — a browser has no TCP."
339 exec python3 -m http.server {{port}} --bind 127.0.0.1 --directory "$out/web"
340
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago341# A sandbox left running with the container's own image, volumes and
342# environment, and the command to get into it. `modal shell --image` cannot
343# be pointed at a published Modal image like arch-nix, so attaching to a
344# running sandbox is the only way to get a shell that is the container.
345#
346# It blocks: an ephemeral app stops when its entrypoint returns and takes the
347# sandbox with it. Attach from a second terminal, and Ctrl-C here when done —
348# the sandbox bills until you do.
349#
350# just modal-shell flutter-dev, the usual one
One frontend where there were three, and a core that is not Clojure 438b247 nandi 21h ago351# just modal-shell flutter-web the web bundle container
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago352modal-shell container="flutter-dev":
353 #!/usr/bin/env bash
354 set -euo pipefail
355 cd "{{justfile_directory()}}"
356 exec modal run ".modal/{{container}}/container.py" --shell
One frontend where there were three, and a core that is not Clojure 438b247 nandi 21h ago357
358# The Nim core's test suite.
359#
360# It needs no Flutter, no Dart and no Android SDK — which is the point of
361# having the logic here rather than under `common/`: a rule about the IRC wire
362# format can be checked in a second, on any machine, without a toolchain that
363# takes minutes to enter.
364#
365# just nim-test the whole suite
366# just nim-test tircparse one file
367nim-test file="":
368 #!/usr/bin/env bash
369 set -euo pipefail
370 cd "{{justfile_directory()}}"
371 if [ -z "${FRQ_NIM:-}" ]; then
372 exec {{nix}} develop .#nim --max-jobs {{jobs}} --command just nim-test "$@"
373 fi
374 cd nim
375 if [ -n "{{file}}" ]; then
376 exec nim c -r --hints:off --path:src "tests/{{file}}.nim"
377 fi
378 for t in tests/t*.nim; do
379 echo "== $t"
380 nim c -r --hints:off --path:src "$t"
381 done
382
383# The Nim core as a shared library, into build/nim.
384#
The renderer, and a transport bug that took four tries 58e6c97 nandi 18h ago385# `--mm:orc` and not refc, and it is not a preference: refc gives each thread
386# its own GC heap, so the Socket the reader and writer threads share is a ref
387# from another heap and dereferencing it segfaults. ORC's heap is shared.
One frontend where there were three, and a core that is not Clojure 438b247 nandi 21h ago388#
389# `-d:release` and not `-d:danger`: the bounds checks are what turn a
390# malformed line off a socket into an exception instead of a read past the end
391# of a buffer, and this parses exactly that.
392nim-lib:
393 #!/usr/bin/env bash
394 set -euo pipefail
395 cd "{{justfile_directory()}}"
396 if [ -z "${FRQ_NIM:-}" ]; then
397 exec {{nix}} develop .#nim --max-jobs {{jobs}} --command just nim-lib
398 fi
399 out="{{justfile_directory()}}/build/nim"
400 mkdir -p "$out"
401 cd nim
402 nim c --app:lib --mm:orc -d:release --hints:off \
403 --path:src --out:"$out/libfrqcore.so" src/frq_core.nim
404 echo "built $out/libfrqcore.so"
405 nm -D --defined-only "$out/libfrqcore.so" | grep ' T frq_' || true
The binding is Dart, and it works f7aea3b nandi 20h ago406
407# The Dart side of the Nim boundary, on the plain Dart VM.
408#
409# No Flutter, no emulator, no ClojureDart — `dart/frq_core` is ordinary Dart
410# over `dart:ffi` and is not a Flutter package, so the test that proves the
411# marshalling runs in a second. Passing `just nim-test` and failing this one is a
412# marshalling bug, which is the whole reason the two suites are separate.
413#
414# Builds the library first: the test dlopens a real .so and there is no point
415# reporting that it could not find one.
416dart-test:
417 #!/usr/bin/env bash
418 set -euo pipefail
419 cd "{{justfile_directory()}}"
420 if [ -z "${FRQ_DART:-}" ]; then
421 # nim-lib before the re-entry, not after: it enters a shell of its own
422 # and doing it on the far side would build the library twice.
423 just nim-lib
424 exec {{nix}} develop .#dart --max-jobs {{jobs}} --command just dart-test
425 fi
426 cd dart/frq_core
427 dart pub get
428 dart test -r expanded
Nim owns the screen, Dart owns the pixels 43a02c2 nandi 20h ago429
The renderer, and a transport bug that took four tries 58e6c97 nandi 18h ago430# The whole Nim stack against a real freeq: socket, state and screens.
431#
432# Connects, waits for the room list, opens a room and prints what the tree
433# actually contains — through the FFI, so it is the path the window uses.
434# Not in any suite: it needs a network and a running freeq.
435nim-live *args:
436 #!/usr/bin/env bash
437 set -euo pipefail
438 cd "{{justfile_directory()}}"
439 if [ -z "${FRQ_DART:-}" ]; then
440 just nim-lib
441 exec {{nix}} develop .#dart --max-jobs {{jobs}} --command just nim-live "$@"
442 fi
443 shift || true
444 cd dart/frq_core
445 dart pub get >/dev/null
446 exec dart run tool/live_ui.dart "$@"
447
448# frq with Nim owning the state and the screens, rendered by Flutter.
449#
450# No ClojureDart on this path. `lib/main_nim.dart` asks the Nim core for a
451# widget tree and paints it; the screens are ports of `common/frq/screens/`.
452#
453# just nim-ui build it
454# just nim-ui run open the window
455nim-ui action="build":
456 #!/usr/bin/env bash
457 set -euo pipefail
458 cd "{{justfile_directory()}}"
459 if [ -z "${FRQ_FLUTTER_DESKTOP:-}" ]; then
460 just nim-lib
461 exec {{nix}} develop .#flutter-desktop --max-jobs {{jobs}} \
462 --command just nim-ui "$@"
463 fi
464 cd flutter
465 flutter pub get
466 export LD_LIBRARY_PATH="${FRQ_OPENSSL_LIB:-}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
467 runner=()
468 [ -e /run/current-system ] || runner=("$NIXGL")
469 case "{{action}}" in
470 build) exec "${runner[@]}" flutter build linux --debug -t lib/main_nim.dart ;;
471 run) exec "${runner[@]}" flutter run -d linux -t lib/main_nim.dart ;;
472 *) echo "usage: just nim-ui [build|run]" >&2; exit 1 ;;
473 esac
474
475# The ClojureDart app, with the Nim core as its transport only.
Nim under the existing UI, not instead of it 56551a8 nandi 19h ago476#
477# This is the wiring that matters: `frq.main-nim` is `frq.main` with one line
478# changed — `frq.net.nim/install!` where it says `frq.net.dart/install!`. Every
479# screen, every cell and every action is the one that was already there. Nim
480# owns the socket, the TLS and the line framing, and nothing else.
481#
482# just nim-app build it
483# just nim-app run open the window
484nim-app action="build":
485 #!/usr/bin/env bash
486 set -euo pipefail
487 cd "{{justfile_directory()}}"
488 if [ -z "${FRQ_FLUTTER_DESKTOP:-}" ]; then
489 just nim-lib
490 exec {{nix}} develop .#flutter-desktop --max-jobs {{jobs}} \
491 --command just nim-app "$@"
492 fi
493 cd flutter
494 flutter pub get
495 export LD_LIBRARY_PATH="${FRQ_OPENSSL_LIB:-}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
496 clojure -M:cljd compile frq.main-nim
497 runner=()
498 [ -e /run/current-system ] || runner=("$NIXGL")
499 case "{{action}}" in
500 build) exec "${runner[@]}" flutter build linux --debug -t lib/main_nim_app.dart ;;
501 run) exec "${runner[@]}" flutter run -d linux -t lib/main_nim_app.dart ;;
502 *) echo "usage: just nim-app [build|run]" >&2; exit 1 ;;
503 esac