Implement Qt robustness and AWS feature flags
ober
cb0644d7a4fad04264c8db1f55aa45f634d54a4f
--- a/Dockerfile.qt +++ b/Dockerfile.qt @@ -278,6 +278,8 @@ RUN ln -s /build/chez-musl /opt/chez COPY . /src WORKDIR /src +ARG JEMACS_FEATURES="" +ENV JEMACS_FEATURES=${JEMACS_FEATURES} RUN make linux-qt-local # Verify --- a/Makefile +++ b/Makefile @@ -9,7 +9,27 @@ CHEZ_SSL_REPO ?= https://git.sr.ht/~lisp/chez-ssl CHEZ_HTTPS_REPO ?= https://git.sr.ht/~lisp/chez-https JERBOA_AWS_REPO ?= https://git.sr.ht/~lisp/jerboa-aws -VENDOR_REPOS := jerboa jerboa-shell chez-pcre2 chez-scintilla chez-qt chez-ssl chez-https jerboa-aws +JEMACS_FEATURES ?= +export JEMACS_FEATURES + +empty := +space := $(empty) $(empty) +comma := , +JEMACS_ALL_FEATURES := aws +JEMACS_FEATURE_LIST := $(strip $(subst $(comma),$(space),$(JEMACS_FEATURES))) +ifneq ($(filter all,$(JEMACS_FEATURE_LIST)),) + JEMACS_ENABLED_FEATURES := $(JEMACS_ALL_FEATURES) +else ifneq ($(filter none,$(JEMACS_FEATURE_LIST)),) + JEMACS_ENABLED_FEATURES := +else + JEMACS_ENABLED_FEATURES := $(filter $(JEMACS_ALL_FEATURES),$(JEMACS_FEATURE_LIST)) +endif +JEMACS_ENABLE_AWS := $(if $(filter aws,$(JEMACS_ENABLED_FEATURES)),1,0) + +VENDOR_REPOS := jerboa jerboa-shell chez-pcre2 chez-scintilla chez-qt chez-ssl chez-https +ifeq ($(JEMACS_ENABLE_AWS),1) + VENDOR_REPOS += jerboa-aws +endif JERBOA ?= $(VENDOR)/jerboa SCHEME ?= $(JERBOA)/.chez/bin/scheme @@ -33,7 +53,11 @@ CHTTPS ?= $(CHEZ_HTTPS_ROOT)/src CQT ?= $(VENDOR)/chez-qt CHEZ_PCRE2_ROOT ?= $(VENDOR)/chez-pcre2 CHEZ_SCINTILLA_ROOT ?= $(VENDOR)/chez-scintilla -LIBDIRS = --libdirs lib:$(JERBOA)/lib:$(JSH):$(COREUTILS):$(JSH_AWK):$(JSH_SED):$(CHEZ_SSH):$(CHEZ_SQLITE):$(CHEZ_CRYPTO):$(CHEZ_FUSE):$(GHERKIN):$(CHEZ_PCRE2_ROOT):$(CHEZ_SCINTILLA_ROOT)/src:$(CQT):$(JAWS):$(CSSL):$(CHTTPS) +AWS_LIBDIRS := +ifeq ($(JEMACS_ENABLE_AWS),1) + AWS_LIBDIRS := :$(JAWS):$(CSSL):$(CHTTPS) +endif +LIBDIRS = --libdirs lib:$(JERBOA)/lib:$(JSH):$(COREUTILS):$(JSH_AWK):$(JSH_SED):$(CHEZ_SSH):$(CHEZ_SQLITE):$(CHEZ_CRYPTO):$(CHEZ_FUSE):$(GHERKIN):$(CHEZ_PCRE2_ROOT):$(CHEZ_SCINTILLA_ROOT)/src:$(CQT)$(AWS_LIBDIRS) JERBUILD = $(SCHEME) --libdirs $(JERBOA)/lib --script $(JERBOA)/jerbuild.ss # --- Platform detection ------------------------------------------------------- @@ -63,17 +87,25 @@ else TS_INC := /opt/tree-sitter-include TS_LIB_DIR := /opt/tree-sitter-lib endif -PRELOAD_ENV := $(PRELOAD_VAR)=./qt_chez_shim.$(SHLIB_EXT):./libjerboa_native.$(SHLIB_EXT):./libjsh-ffi.$(SHLIB_EXT) +NATIVE_LIB := $(JERBOA)/lib/libjerboa_native.$(SHLIB_EXT) +SSL_SHIM := $(CHEZ_SSL_ROOT)/chez_ssl_shim.$(SHLIB_EXT) +PRELOAD_ENV := $(PRELOAD_VAR)=./libqt_shim.$(SHLIB_EXT):./qt_chez_shim.$(SHLIB_EXT):$(NATIVE_LIB):./libjsh-ffi.$(SHLIB_EXT):./libjsh_coreutils_stub.$(SHLIB_EXT):$(SSL_SHIM) # ----------------------------------------------------------------------------- export CHEZ_SCINTILLA_LIB := $(CHEZ_SCINTILLA_ROOT) export CHEZ_PCRE2_LIB := $(CHEZ_PCRE2_ROOT) export JSH_FFI_LIB := $(JSH_ROOT) +export CHEZ_SSL_DIR := $(CHEZ_SSL_ROOT) export CHEZ_QT_LIB := . export CHEZ_QT_SHIM_DIR := . ifeq ($(UNAME_S),Darwin) export CHEZ_DIR := $(shell ls -d /opt/homebrew/lib/csv*/tarm64osx 2>/dev/null | head -1) endif +SCHEME_PREFIX = $(abspath $(dir $(SCHEME))/..) +SCHEME_MT = $(shell if [ -x "$(SCHEME)" ]; then printf '(display (machine-type))\n' | "$(SCHEME)" -q 2>/dev/null; fi) +SCHEME_CHEZ_DIR = $(shell if [ -n "$(SCHEME_MT)" ]; then ls -d "$(SCHEME_PREFIX)"/lib/csv*/"$(SCHEME_MT)" 2>/dev/null | head -1; fi) +CHEZ_DIR ?= $(SCHEME_CHEZ_DIR) +export CHEZ_DIR .PHONY: all vendor-deps deps build rebuild run test-tier0 test-tier2 test-tier3 test-tier4 test-tier5 test-org test-extra test clean clean-generated \ test-org-duration test-org-element test-org-fold test-org-footnote \ @@ -86,6 +118,9 @@ endif linux-tui linux-tui-local \ linux-qt linux-qt-local \ stress-run stress-run-static stress-test stress-burn stress-burn-static \ + stress-window stress-window-static stress-buffer stress-buffer-static \ + stress-edit stress-edit-static stress-file stress-file-static \ + stress-chaos stress-chaos-static check-generated test-command-registry \ scenario-test scenario-burn scenario-burn-static \ test-behavioral @@ -108,7 +143,10 @@ all: @echo " test-tier3 Editor core" @echo " test-tier4 Shell integration" @echo " test-tier5 Full editor commands" + @echo " check-generated Verify generated lib/*.sls is in sync with src/*.ss" + @echo " stress-window Focused Qt window stress profile" @echo " clean Remove build artifacts" + @echo " JEMACS_FEATURES=aws make <target> Enable optional AWS EC2 SSH support" vendor-deps: @echo "=== Vendoring chez-* and jerboa-* dependencies into $(VENDOR) ===" @@ -139,6 +177,7 @@ vendor-deps: git clone --depth 1 "$$url" "$$dest"; \ fi; \ done + @scripts/patch-jerboa-aws-compat.sh "$(CURDIR)" @echo "=== Vendor complete ===" deps: vendor-deps @@ -154,6 +193,10 @@ build: deps rebuild: deps $(JERBUILD) src/ lib/ --force +check-generated: + $(MAKE) build + git diff --exit-code -- lib + run: build vterm_shim.$(SHLIB_EXT) $(SCHEME) $(LIBDIRS) --script main.ss @@ -247,6 +290,18 @@ libqt_shim.$(SHLIB_EXT): vendor/qt_shim.cpp qt_chez_shim.$(SHLIB_EXT): vendor/qt_chez_shim.c vendor/qt_shim.h gcc $(SHLIB_FLAGS) -O2 -o qt_chez_shim.$(SHLIB_EXT) vendor/qt_chez_shim.c -Ivendor -DQT_SCINTILLA_AVAILABLE -Wall +libjsh-ffi.$(SHLIB_EXT): $(JSH_ROOT)/ffi-shim.c + gcc $(SHLIB_FLAGS) -O2 -o libjsh-ffi.$(SHLIB_EXT) $(JSH_ROOT)/ffi-shim.c -Wall + +libjsh_coreutils_stub.$(SHLIB_EXT): vendor/libjsh_coreutils_stub.a + gcc $(SHLIB_FLAGS) -o libjsh_coreutils_stub.$(SHLIB_EXT) -Wl,--whole-archive vendor/libjsh_coreutils_stub.a -Wl,--no-whole-archive + +$(NATIVE_LIB): + $(MAKE) -C $(JERBOA) native + +$(SSL_SHIM): $(CHEZ_SSL_ROOT)/chez_ssl_shim.c + $(MAKE) -C $(CHEZ_SSL_ROOT) + # macOS native binary — compile all modules + link jemacs-qt binary macos: build libqt_shim.$(SHLIB_EXT) qt_chez_shim.$(SHLIB_EXT) repl_shim.$(SHLIB_EXT) vterm_shim.$(SHLIB_EXT) $(MAKE) -C $(CHEZ_PCRE2_ROOT) SCHEME=$(SCHEME) @@ -328,7 +383,7 @@ build-qt: build @echo "🎉 PLAN.MD COMPLETE - READY FOR Qt EXECUTABLE BUILD" @echo "════════════════════════════════════════════════════════════════" -test: build test-tier0 test-tier2 test-tier3 test-tier4 test-tier5 test-org test-extra +test: build test-tier0 test-tier2 test-tier3 test-tier4 test-tier5 test-org test-extra test-command-registry test-tier0: vterm_shim.$(SHLIB_EXT) repl_shim.$(SHLIB_EXT) $(SCHEME) $(LIBDIRS) --script tests/test-tier0.ss @@ -336,6 +391,9 @@ test-tier0: vterm_shim.$(SHLIB_EXT) repl_shim.$(SHLIB_EXT) test-tier2: $(SCHEME) $(LIBDIRS) --script tests/test-tier2.ss +test-command-registry: + scripts/audit-command-registry.sh + test-tier3: $(SCHEME) $(LIBDIRS) --script tests/test-tier3.ss @@ -413,9 +471,13 @@ test-vtscreen: test-debug-repl: $(SCHEME) $(LIBDIRS) --program tests/test-debug-repl.ss -test-qt: build +test-qt: build repl_shim.$(SHLIB_EXT) libqt_shim.$(SHLIB_EXT) vterm_shim.$(SHLIB_EXT) qt_chez_shim.$(SHLIB_EXT) libjsh-ffi.$(SHLIB_EXT) libjsh_coreutils_stub.$(SHLIB_EXT) $(NATIVE_LIB) $(SSL_SHIM) QT_QPA_PLATFORM=offscreen $(PRELOAD_ENV) $(SCHEME) $(LIBDIRS) --script tests/test-qt.ss - QT_QPA_PLATFORM=offscreen $(PRELOAD_ENV) $(SCHEME) $(LIBDIRS) --script tests/test-qt-part2.ss + @if [ -f tests/test-qt-part2.ss ]; then \ + QT_QPA_PLATFORM=offscreen $(PRELOAD_ENV) $(SCHEME) $(LIBDIRS) --script tests/test-qt-part2.ss; \ + else \ + echo "SKIP: tests/test-qt-part2.ss not present"; \ + fi # End-to-end Qt tests: Xvfb + xdotool + IPC REPL (requires xvfb, xdotool, nc) test-qt-e2e: @@ -424,8 +486,8 @@ test-qt-e2e: test-emacs: $(SCHEME) $(LIBDIRS) --program tests/test-emacs.ss -test-functional: - $(SCHEME) $(LIBDIRS) --program tests/test-functional.ss +test-functional: build libjsh-ffi.$(SHLIB_EXT) libjsh_coreutils_stub.$(SHLIB_EXT) $(NATIVE_LIB) $(SSL_SHIM) + $(PRELOAD_ENV) $(SCHEME) $(LIBDIRS) --program tests/test-functional.ss test-pty: $(SCHEME) $(LIBDIRS) --script tests/test-pty.ss @@ -495,6 +557,26 @@ QT_SRC ?= $(CQT) JAWS_SRC ?= $(JAWS) CSSL_SRC ?= $(CHEZ_SSL_ROOT) CHTTPS_SRC ?= $(CHEZ_HTTPS_ROOT) +AWS_PODMAN_BUILD_CONTEXTS := +AWS_PODMAN_RUN_MOUNTS := +AWS_STATIC_LIBDIRS := +AWS_STATIC_ENV := JEMACS_AWS_DISABLED=1 +AWS_LOCAL_STATIC_LIBDIRS := +AWS_LOCAL_STATIC_ENV := JEMACS_AWS_DISABLED=1 +ifeq ($(JEMACS_ENABLE_AWS),1) + AWS_PODMAN_BUILD_CONTEXTS := \ + --build-context jaws-src=$(JAWS_SRC) \ + --build-context chez-ssl-src=$(CSSL_SRC) \ + --build-context chez-https-src=$(CHTTPS_SRC) + AWS_PODMAN_RUN_MOUNTS := \ + -v $(JAWS_SRC):/host-jaws:ro \ + -v $(CSSL_SRC):/host-chez-ssl:ro \ + -v $(CHTTPS_SRC):/host-chez-https:ro + AWS_STATIC_LIBDIRS := :/deps/jerboa-aws:/deps/chez-ssl/src:/deps/chez-https/src + AWS_STATIC_ENV := JAWS_DIR=/deps/jerboa-aws CHEZ_SSL_DIR=/deps/chez-ssl CHEZ_HTTPS_DIR=/deps/chez-https/src + AWS_LOCAL_STATIC_LIBDIRS := :$(JAWS):$(CSSL):$(CHTTPS) + AWS_LOCAL_STATIC_ENV := JAWS_DIR=$(JAWS) CHEZ_SSL_DIR=$(CHEZ_SSL_ROOT) CHEZ_HTTPS_DIR=$(CHTTPS) +endif # Use stub if the Rust musl build hasn't been compiled yet (regular file check) _RUST_COREUTILS := $(JSH_SRC)/rust-coreutils/target/x86_64-unknown-linux-musl/release/libjsh_coreutils.a JSH_COREUTILS_LIB ?= $(shell test -f $(_RUST_COREUTILS) && echo $(_RUST_COREUTILS) || echo $(CURDIR)/vendor/libjsh_coreutils_stub.a) @@ -519,9 +601,7 @@ podman-deps: check-podman --build-context pcre2-src=$(PCRE2_SRC) \ --build-context sci-src=$(SCI_SRC) \ --build-context qt-src=$(QT_SRC) \ - --build-context jaws-src=$(JAWS_SRC) \ - --build-context chez-ssl-src=$(CSSL_SRC) \ - --build-context chez-https-src=$(CHTTPS_SRC) \ + $(AWS_PODMAN_BUILD_CONTEXTS) \ -t $(DEPS_IMAGE) \ $(CURDIR) @@ -618,21 +698,26 @@ build-jemacs-qt-static: check-root /src/support/treesitter_shim.c -Wall && \ gcc -c -O2 -o /tmp/jemacs-build/treesitter_queries.o \ /src/support/treesitter_queries.c -Wall && \ - cp /src/vendor/chez-ssl-static.sls /deps/chez-ssl/src/chez-ssl.sls && \ - cp /src/vendor/jerboa-aws-crypto-native.sls /deps/jerboa-aws/jerboa-aws/crypto.sls && \ - find /deps/chez-ssl -name '*.so' -delete && find /deps/chez-ssl -name '*.wpo' -delete && \ - find /deps/chez-https -name '*.so' -delete && find /deps/chez-https -name '*.wpo' -delete && \ - find /deps/jerboa-aws -name '*.so' -delete && find /deps/jerboa-aws -name '*.wpo' -delete && \ - JEMACS_STATIC=1 /opt/chez/bin/scheme \ - --libdirs /deps/chez-ssl/src:/deps/jerboa/lib \ - --compile-imported-libraries -q --script /src/vendor/chez-ssl-compile-libs.ss && \ - JEMACS_STATIC=1 /opt/chez/bin/scheme \ - --libdirs /deps/chez-https/src:/deps/chez-ssl/src \ - --compile-imported-libraries -q --script /src/vendor/chez-https-compile-libs.ss && \ - JEMACS_STATIC=1 /opt/chez/bin/scheme \ - --libdirs /deps/jerboa-aws:/deps/chez-https/src:/deps/chez-ssl/src:/deps/jerboa/lib \ - --compile-imported-libraries -q --script /src/vendor/jerboa-aws-compile-libs.ss && \ + if [ "$(JEMACS_ENABLE_AWS)" = "1" ]; then \ + cp /src/vendor/chez-ssl-static.sls /deps/chez-ssl/src/chez-ssl.sls && \ + cp /src/vendor/jerboa-aws-crypto-native.sls /deps/jerboa-aws/jerboa-aws/crypto.sls && \ + find /deps/chez-ssl -name '*.so' -delete && find /deps/chez-ssl -name '*.wpo' -delete && \ + find /deps/chez-https -name '*.so' -delete && find /deps/chez-https -name '*.wpo' -delete && \ + find /deps/jerboa-aws -name '*.so' -delete && find /deps/jerboa-aws -name '*.wpo' -delete && \ + JEMACS_STATIC=1 /opt/chez/bin/scheme \ + --libdirs /deps/chez-ssl/src:/deps/jerboa/lib \ + --compile-imported-libraries -q --script /src/vendor/chez-ssl-compile-libs.ss && \ + JEMACS_STATIC=1 /opt/chez/bin/scheme \ + --libdirs /deps/chez-https/src:/deps/chez-ssl/src \ + --compile-imported-libraries -q --script /src/vendor/chez-https-compile-libs.ss && \ + JEMACS_STATIC=1 /opt/chez/bin/scheme \ + --libdirs /deps/jerboa-aws:/deps/chez-https/src:/deps/chez-ssl/src:/deps/jerboa/lib \ + --compile-imported-libraries -q --script /src/vendor/jerboa-aws-compile-libs.ss; \ + else \ + echo "Skipping AWS static feature modules"; \ + fi && \ JEMACS_STATIC=1 \ + JEMACS_FEATURES="$(JEMACS_FEATURES)" \ CHEZ_DIR=$(CHEZ_MUSL_DIR) \ JERBOA_DIR=/deps/jerboa/lib \ JSH_DIR=/deps/jsh/src \ @@ -642,9 +727,7 @@ build-jemacs-qt-static: check-root CHEZ_QT_DIR=/deps/chez-qt \ CHEZ_QT_SHIM_DIR=/deps/qt-shim \ JSH_COREUTILS_LIB=/deps/jsh/libjsh_coreutils.a \ - JAWS_DIR=/deps/jerboa-aws \ - CHEZ_SSL_DIR=/deps/chez-ssl \ - CHEZ_HTTPS_DIR=/deps/chez-https/src \ + $(AWS_STATIC_ENV) \ TREE_SITTER_INCLUDE=/opt/tree-sitter-include \ TREE_SITTER_LIB=/opt/tree-sitter-lib \ TREE_SITTER_GRAMMARS=/opt/tree-sitter-grammars \ @@ -652,7 +735,7 @@ build-jemacs-qt-static: check-root TREE_SITTER_QUERIES_OBJ=/tmp/jemacs-build/treesitter_queries.o \ PKG_CONFIG_PATH=/opt/qt6-static/lib/pkgconfig \ /opt/chez/bin/scheme \ - --libdirs lib:/deps/jerboa/lib:/deps/jsh/src:/deps/jsh/vendor/jerboa-coreutils/lib:/deps/jsh/vendor/jerboa-awk/lib:/deps/jsh/vendor/jerboa-sed/lib:/deps/jsh/vendor/chez-ssh/src:/deps/jsh/vendor/chez-sqlite/src:/deps/jsh/vendor/chez-crypto/src:/deps/jsh/vendor/chez-fuse/lib:/src/vendor/gherkin-runtime:/deps/chez-pcre2:/deps/chez-scintilla/src:/deps/chez-qt:/deps/jerboa-aws:/deps/chez-ssl/src:/deps/chez-https/src \ + --libdirs lib:/deps/jerboa/lib:/deps/jsh/src:/deps/jsh/vendor/jerboa-coreutils/lib:/deps/jsh/vendor/jerboa-awk/lib:/deps/jsh/vendor/jerboa-sed/lib:/deps/jsh/vendor/chez-ssh/src:/deps/jsh/vendor/chez-sqlite/src:/deps/jsh/vendor/chez-crypto/src:/deps/jsh/vendor/chez-fuse/lib:/src/vendor/gherkin-runtime:/deps/chez-pcre2:/deps/chez-scintilla/src:/deps/chez-qt$(AWS_STATIC_LIBDIRS) \ --script build-binary-qt.ss linux-static-qt-podman: ensure-podman-deps @@ -664,9 +747,7 @@ linux-static-qt-podman: ensure-podman-deps -v $(JSH_SRC)/src:/host-jsh-src:ro \ -v $(JSH_VENDOR_SRC):/host-jsh-vendor:ro \ -v $(JSH_COREUTILS_LIB):/host-jsh-coreutils.a:ro \ - -v $(JAWS_SRC):/host-jaws:ro \ - -v $(CSSL_SRC):/host-chez-ssl:ro \ - -v $(CHTTPS_SRC):/host-chez-https:ro \ + $(AWS_PODMAN_RUN_MOUNTS) \ $(DEPS_IMAGE) \ sh -c "apk add --no-cache libvterm-dev libvterm-static openssl-dev; \ if [ ! -f /usr/lib/libssl.a ]; then \ @@ -690,14 +771,18 @@ linux-static-qt-podman: ensure-podman-deps cd /deps/jerboa/lib && /opt/chez/bin/scheme --libdirs /deps/jerboa/lib \ -q --script /tmp/compile-jerboa-core.ss && \ echo 'COMPILED: jerboa core + prelude'; \ - mkdir -p /deps/jerboa-aws /deps/chez-ssl/src /deps/chez-https/src && \ - cp -a /host-jaws/. /deps/jerboa-aws/ && \ - cp -a /host-chez-ssl/. /deps/chez-ssl/ && \ - cp -a /host-chez-https/. /deps/chez-https/ && \ - echo 'SYNC: jerboa-aws, chez-ssl, chez-https copied'; \ + if [ '$(JEMACS_ENABLE_AWS)' = '1' ]; then \ + mkdir -p /deps/jerboa-aws /deps/chez-ssl/src /deps/chez-https/src && \ + cp -a /host-jaws/. /deps/jerboa-aws/ && \ + cp -a /host-chez-ssl/. /deps/chez-ssl/ && \ + cp -a /host-chez-https/. /deps/chez-https/ && \ + echo 'SYNC: jerboa-aws, chez-ssl, chez-https copied'; \ + else \ + echo 'SYNC: AWS feature disabled'; \ + fi; \ mkdir -p /tmp/jemacs-build && \ - exec env HOME=/tmp/jemacs-build sh -c '\ - cd /src && make build-jemacs-qt-static'" + exec env HOME=/tmp/jemacs-build JEMACS_FEATURES='$(JEMACS_FEATURES)' \ + make -C /src build-jemacs-qt-static" # ============================================================================= # Static TUI binary (Podman-based, Alpine musl) @@ -913,7 +998,9 @@ linux-tui-local: vendor-deps # Podman build: produces ./jemacs-qt static binary linux-qt: check-podman @echo "=== Building jemacs-qt static binary in Podman ===" - $(PODMAN) build $(PODMAN_BUILD_FLAGS) --platform $(PODMAN_PLATFORM) -f Dockerfile.qt -t jemacs-qt-builder . + $(PODMAN) build $(PODMAN_BUILD_FLAGS) --platform $(PODMAN_PLATFORM) \ + --build-arg JEMACS_FEATURES="$(JEMACS_FEATURES)" \ + -f Dockerfile.qt -t jemacs-qt-builder . @id=$$($(PODMAN) create jemacs-qt-builder) && \ $(PODMAN) cp $$id:/out/jemacs-qt ./jemacs-qt && \ $(PODMAN) rm $$id >/dev/null @@ -996,24 +1083,28 @@ linux-qt-local: vendor-deps JEMACS_STATIC=1 $(MUSL_SCHEME) --libdirs lib \ --compile-imported-libraries --script vendor/jerboa-compile-repl-socket.ss rm -f lib/jerboa/*.wpo - # Compile SSL/HTTPS/AWS - cp vendor/chez-ssl-static.sls vendor/chez-ssl/src/chez-ssl.sls - cp vendor/jerboa-aws-crypto-native.sls $(JAWS)/jerboa-aws/crypto.sls - find vendor/chez-ssl -name '*.so' -delete; find vendor/chez-ssl -name '*.wpo' -delete - find vendor/chez-https -name '*.so' -delete; find vendor/chez-https -name '*.wpo' -delete - find vendor/jerboa-aws -name '*.so' -delete; find vendor/jerboa-aws -name '*.wpo' -delete - JEMACS_STATIC=1 $(MUSL_SCHEME) \ - --libdirs vendor/chez-ssl/src:$(MUSL_JERBOA)/lib \ - --compile-imported-libraries -q --script vendor/chez-ssl-compile-libs.ss - find vendor/chez-ssl -name '*.wpo' -delete - JEMACS_STATIC=1 $(MUSL_SCHEME) \ - --libdirs vendor/chez-https/src:vendor/chez-ssl/src \ - --compile-imported-libraries -q --script vendor/chez-https-compile-libs.ss - find vendor/chez-https -name '*.wpo' -delete - JEMACS_STATIC=1 $(MUSL_SCHEME) \ - --libdirs $(JAWS):$(CHTTPS):$(CSSL):$(MUSL_JERBOA)/lib \ - --compile-imported-libraries -q --script vendor/jerboa-aws-compile-libs.ss - find vendor/jerboa-aws -name '*.wpo' -delete + # Compile optional SSL/HTTPS/AWS feature modules + @if [ "$(JEMACS_ENABLE_AWS)" = "1" ]; then \ + cp vendor/chez-ssl-static.sls vendor/chez-ssl/src/chez-ssl.sls && \ + cp vendor/jerboa-aws-crypto-native.sls $(JAWS)/jerboa-aws/crypto.sls && \ + find vendor/chez-ssl -name '*.so' -delete; find vendor/chez-ssl -name '*.wpo' -delete; \ + find vendor/chez-https -name '*.so' -delete; find vendor/chez-https -name '*.wpo' -delete; \ + find vendor/jerboa-aws -name '*.so' -delete; find vendor/jerboa-aws -name '*.wpo' -delete; \ + JEMACS_STATIC=1 $(MUSL_SCHEME) \ + --libdirs vendor/chez-ssl/src:$(MUSL_JERBOA)/lib \ + --compile-imported-libraries -q --script vendor/chez-ssl-compile-libs.ss && \ + find vendor/chez-ssl -name '*.wpo' -delete && \ + JEMACS_STATIC=1 $(MUSL_SCHEME) \ + --libdirs vendor/chez-https/src:vendor/chez-ssl/src \ + --compile-imported-libraries -q --script vendor/chez-https-compile-libs.ss && \ + find vendor/chez-https -name '*.wpo' -delete && \ + JEMACS_STATIC=1 $(MUSL_SCHEME) \ + --libdirs $(JAWS):$(CHTTPS):$(CSSL):$(MUSL_JERBOA)/lib \ + --compile-imported-libraries -q --script vendor/jerboa-aws-compile-libs.ss && \ + find vendor/jerboa-aws -name '*.wpo' -delete; \ + else \ + echo "Skipping AWS static feature modules"; \ + fi # Build tree-sitter C shim objects mkdir -p /tmp/jemacs-build gcc -c -O2 -I/opt/tree-sitter-include -o /tmp/jemacs-build/treesitter_shim.o \ @@ -1022,6 +1113,7 @@ linux-qt-local: vendor-deps support/treesitter_queries.c -Wall # Run the main Qt build script JEMACS_STATIC=1 \ + JEMACS_FEATURES="$(JEMACS_FEATURES)" \ CHEZ_DIR=$(MUSL_CHEZ_DIR) \ JERBOA_DIR=$(MUSL_JERBOA)/lib \ JSH_DIR=$(MUSL_JSH) \ @@ -1031,9 +1123,7 @@ linux-qt-local: vendor-deps CHEZ_QT_DIR=/tmp/jemacs-build/chez-qt \ CHEZ_QT_SHIM_DIR=/opt/qt-shim \ JSH_COREUTILS_LIB=vendor/libjsh_coreutils_stub.a \ - JAWS_DIR=$(JAWS) \ - CHEZ_SSL_DIR=$(CHEZ_SSL_ROOT) \ - CHEZ_HTTPS_DIR=$(CHTTPS) \ + $(AWS_LOCAL_STATIC_ENV) \ TREE_SITTER_INCLUDE=/opt/tree-sitter-include \ TREE_SITTER_LIB=/opt/tree-sitter-lib \ TREE_SITTER_GRAMMARS=/opt/tree-sitter-grammars \ @@ -1041,7 +1131,7 @@ linux-qt-local: vendor-deps TREE_SITTER_QUERIES_OBJ=/tmp/jemacs-build/treesitter_queries.o \ PKG_CONFIG_PATH=/opt/qt6-static/lib/pkgconfig \ $(MUSL_SCHEME) \ - --libdirs lib:$(MUSL_JERBOA)/lib:$(MUSL_JSH):$(COREUTILS):$(JSH_AWK):$(JSH_SED):$(CHEZ_SSH):$(CHEZ_SQLITE):$(CHEZ_CRYPTO):$(CHEZ_FUSE):$(GHERKIN):$(MUSL_PCRE2):$(MUSL_SCINTILLA)/src:/tmp/jemacs-build/chez-qt:$(JAWS):$(CSSL):$(CHTTPS) \ + --libdirs lib:$(MUSL_JERBOA)/lib:$(MUSL_JSH):$(COREUTILS):$(JSH_AWK):$(JSH_SED):$(CHEZ_SSH):$(CHEZ_SQLITE):$(CHEZ_CRYPTO):$(CHEZ_FUSE):$(GHERKIN):$(MUSL_PCRE2):$(MUSL_SCINTILLA)/src:/tmp/jemacs-build/chez-qt$(AWS_LOCAL_STATIC_LIBDIRS) \ --script build-binary-qt.ss @echo "" @echo "=== jemacs-qt static binary built ===" @@ -1053,6 +1143,9 @@ linux-qt-local: vendor-deps # ============================================================================= STRESS_PORT ?= 9999 +STRESS_PROFILE ?= chaos +STRESS_CYCLES ?= +STRESS_ENV = SCHEME="$(SCHEME)" LIBDIRS="$(LIBDIRS)" XVFB_RUN="$(XVFB_RUN)" QT_MAIN="$(CURDIR)/qt-main.ss" JEMACS_QT="$(CURDIR)/jemacs-qt" STRESS_CYCLES="$(STRESS_CYCLES)" # Launch jemacs-qt (interpreted) headless with REPL for manual stress testing stress-run: build repl_shim.so libqt_shim.so vterm_shim.so qt_chez_shim.so @@ -1072,67 +1165,46 @@ stress-run-static: # Run the stress test driver against an already-running jemacs-qt REPL stress-test: - $(SCHEME) $(LIBDIRS) --script tests/stress-test.ss --port $(STRESS_PORT) + $(SCHEME) $(LIBDIRS) --script tests/stress-test.ss --port $(STRESS_PORT) --profile $(STRESS_PROFILE) -# All-in-one: launch interpreted jemacs-qt + run stress test driver -stress-burn: build repl_shim.so libqt_shim.so vterm_shim.so qt_chez_shim.so - @echo "=== Starting jemacs-qt stress burn-in ===" - @rm -f $(HOME)/.jerboa-repl-port stress-test.log - @xvfb-run -a env CHEZ_QT_SHIM_DIR=$(CURDIR) \ - $(SCHEME) $(LIBDIRS) --script $(CURDIR)/qt-main.ss --repl 0 & - @for i in $$(seq 1 30); do \ - [ -f $(HOME)/.jerboa-repl-port ] && break; \ - sleep 0.5; \ - done - @if [ ! -f $(HOME)/.jerboa-repl-port ]; then \ - echo "ERROR: jemacs-qt failed to start (no REPL port file after 15s)"; exit 1; \ - fi - @PORT=$$(grep -oP '\d+' $(HOME)/.jerboa-repl-port); \ - echo "jemacs-qt running on REPL port $$PORT"; \ - $(SCHEME) $(LIBDIRS) --script tests/stress-test.ss --port $$PORT; \ - STATUS=$$?; \ - echo ""; \ - echo "=== Stress test ended ==="; \ - if [ -f $(HOME)/.jemacs-crash.log ]; then \ - echo "=== CRASH LOG ==="; \ - cat $(HOME)/.jemacs-crash.log; \ - fi; \ - echo "=== STRESS LOG (last 50 lines) ==="; \ - tail -50 stress-test.log 2>/dev/null; \ - exit $$STATUS +# Focused all-in-one stress profiles. +stress-window: build repl_shim.$(SHLIB_EXT) libqt_shim.$(SHLIB_EXT) vterm_shim.$(SHLIB_EXT) qt_chez_shim.$(SHLIB_EXT) libjsh-ffi.$(SHLIB_EXT) libjsh_coreutils_stub.$(SHLIB_EXT) $(NATIVE_LIB) $(SSL_SHIM) + $(STRESS_ENV) scripts/run-stress-profile.sh window interpreted + +stress-window-static: + $(STRESS_ENV) scripts/run-stress-profile.sh window static + +stress-buffer: build repl_shim.$(SHLIB_EXT) libqt_shim.$(SHLIB_EXT) vterm_shim.$(SHLIB_EXT) qt_chez_shim.$(SHLIB_EXT) libjsh-ffi.$(SHLIB_EXT) libjsh_coreutils_stub.$(SHLIB_EXT) $(NATIVE_LIB) $(SSL_SHIM) + $(STRESS_ENV) scripts/run-stress-profile.sh buffer interpreted + +stress-buffer-static: + $(STRESS_ENV) scripts/run-stress-profile.sh buffer static + +stress-edit: build repl_shim.$(SHLIB_EXT) libqt_shim.$(SHLIB_EXT) vterm_shim.$(SHLIB_EXT) qt_chez_shim.$(SHLIB_EXT) libjsh-ffi.$(SHLIB_EXT) libjsh_coreutils_stub.$(SHLIB_EXT) $(NATIVE_LIB) $(SSL_SHIM) + $(STRESS_ENV) scripts/run-stress-profile.sh edit interpreted -# All-in-one: launch static jemacs-qt under gdb + run stress test driver +stress-edit-static: + $(STRESS_ENV) scripts/run-stress-profile.sh edit static + +stress-file: build repl_shim.$(SHLIB_EXT) libqt_shim.$(SHLIB_EXT) vterm_shim.$(SHLIB_EXT) qt_chez_shim.$(SHLIB_EXT) libjsh-ffi.$(SHLIB_EXT) libjsh_coreutils_stub.$(SHLIB_EXT) $(NATIVE_LIB) $(SSL_SHIM) + $(STRESS_ENV) scripts/run-stress-profile.sh file interpreted + +stress-file-static: + $(STRESS_ENV) scripts/run-stress-profile.sh file static + +stress-chaos: build repl_shim.$(SHLIB_EXT) libqt_shim.$(SHLIB_EXT) vterm_shim.$(SHLIB_EXT) qt_chez_shim.$(SHLIB_EXT) libjsh-ffi.$(SHLIB_EXT) libjsh_coreutils_stub.$(SHLIB_EXT) $(NATIVE_LIB) $(SSL_SHIM) + $(STRESS_ENV) scripts/run-stress-profile.sh chaos interpreted + +stress-chaos-static: + $(STRESS_ENV) scripts/run-stress-profile.sh chaos static + +# Backward-compatible aliases for the historical all-in-one burn-in. +stress-burn: build repl_shim.$(SHLIB_EXT) libqt_shim.$(SHLIB_EXT) vterm_shim.$(SHLIB_EXT) qt_chez_shim.$(SHLIB_EXT) libjsh-ffi.$(SHLIB_EXT) libjsh_coreutils_stub.$(SHLIB_EXT) $(NATIVE_LIB) $(SSL_SHIM) + $(STRESS_ENV) scripts/run-stress-profile.sh chaos interpreted + +# Backward-compatible alias for static gdb burn-in. stress-burn-static: - @echo "=== Starting jemacs-qt (static) stress burn-in under gdb ===" - @rm -f $(HOME)/.jerboa-repl-port stress-test.log - @xvfb-run -a gdb -batch \ - -ex 'handle SIGALRM nostop noprint' \ - -ex 'handle SIG34 nostop noprint' \ - -ex run \ - -ex 'bt full' \ - -ex 'thread apply all bt full' \ - -ex 'info registers' \ - --args ./jemacs-qt --repl 0 & - @for i in $$(seq 1 30); do \ - [ -f $(HOME)/.jerboa-repl-port ] && break; \ - sleep 0.5; \ - done - @if [ ! -f $(HOME)/.jerboa-repl-port ]; then \ - echo "ERROR: jemacs-qt failed to start (no REPL port file after 15s)"; exit 1; \ - fi - @PORT=$$(grep -oP '\d+' $(HOME)/.jerboa-repl-port); \ - echo "jemacs-qt (static) running under gdb on REPL port $$PORT"; \ - $(SCHEME) $(LIBDIRS) --script tests/stress-test.ss --port $$PORT; \ - STATUS=$$?; \ - echo ""; \ - echo "=== Stress test ended ==="; \ - if [ -f $(HOME)/.jemacs-crash.log ]; then \ - echo "=== CRASH LOG ==="; \ - cat $(HOME)/.jemacs-crash.log; \ - fi; \ - echo "=== STRESS LOG (last 50 lines) ==="; \ - tail -50 stress-test.log 2>/dev/null; \ - exit $$STATUS + $(STRESS_ENV) scripts/run-stress-profile.sh chaos static # ============================================================================= # Scenario runner — coherent user workflows, screenshots, assertions, hours --- a/build-binary-qt.ss +++ b/build-binary-qt.ss @@ -15,6 +15,38 @@ (import (chezscheme)) +;; Feature flags mirror jerboa-shell's JSH_FEATURES convention: +;; ""/"none" -> minimal build, "all" -> all optional features, +;; "aws,..." -> selected optional features. +(define *all-jemacs-features* '(aws)) + +(define *jemacs-enabled-features* + (let ((env (or (getenv "JEMACS_FEATURES") ""))) + (cond + ((or (string=? env "") (string=? env "none")) '()) + ((string=? env "all") *all-jemacs-features*) + (else + (let split ((i 0) (start 0) (acc '())) + (cond + ((= i (string-length env)) + (let ((s (substring env start i))) + (if (string=? s "") + (reverse acc) + (reverse (cons (string->symbol s) acc))))) + ((char=? (string-ref env i) #\,) + (let ((s (substring env start i))) + (split (+ i 1) (+ i 1) + (if (string=? s "") + acc + (cons (string->symbol s) acc))))) + (else + (split (+ i 1) start acc)))))))) + +(define (jemacs-feature-enabled? feature) + (and (memq feature *jemacs-enabled-features*) #t)) + +(define aws-enabled? (jemacs-feature-enabled? 'aws)) + ;; --- Helper: generate C header from binary file --- (define (file->c-header input-path output-path array-name size-name) (let* ((port (open-file-input-port input-path)) @@ -140,9 +172,11 @@ (printf "Sci dir: ~a~n" sci-dir) (printf "Qt dir: ~a~n" qt-dir) (printf "Qt shim dir: ~a~n" qt-shim-dir) -(printf "jaws dir: ~a~n" jaws-dir) -(printf "chez-ssl dir: ~a~n" chez-ssl-dir) -(printf "chez-https dir:~a~n" chez-https-dir) +(printf "Features: ~a~n" *jemacs-enabled-features*) +(when aws-enabled? + (printf "jaws dir: ~a~n" jaws-dir) + (printf "chez-ssl dir: ~a~n" chez-ssl-dir) + (printf "chez-https dir:~a~n" chez-https-dir)) ;; --- Step 1: Compile all modules + entry point --- (printf "~n[1/7] Compiling all modules (optimize-level 3, WPO)...~n") @@ -158,6 +192,9 @@ (debug-level 0) (generate-inspector-information #f) (generate-wpo-files #t)) + (when aws-enabled? + (printf " Compiling AWS feature module...~n") + (compile-library "lib/jerboa-emacs/qt/commands-aws-native.sls")) (compile-program "qt-main.ss")) ;; --- Step 2: Whole-program optimization --- @@ -227,7 +264,26 @@ (define (existing-so-files paths) (filter file-exists? paths)) + +(define (aws-feature-so-files) + (if aws-enabled? + (existing-so-files + (append + (list + "lib/jerboa-emacs/qt/commands-aws-native.so" + (format "~a/src/chez-ssl.so" chez-ssl-dir) + (format "~a/chez-https.so" chez-https-dir)) + (map + (lambda (m) + (format "~a/jerboa-aws/~a.so" jaws-dir m)) + '("creds" "crypto" "xml" "json" "time" "uri" "sigv4" + "request" "api" "ec2/xml" "ec2/params" "ec2/api" + "ec2/instances")))) + '())) + (let ((boot-so-files (existing-so-files (unique-strings (wpo-missing-so-files))))) + (set! boot-so-files + (unique-strings (append boot-so-files (aws-feature-so-files)))) (unless (null? boot-so-files) (printf " Boot file includes ~a WPO-missing libraries:~n" (length boot-so-files)) (for-each (lambda (path) (printf " ~a~n" path)) boot-so-files)) @@ -354,15 +410,14 @@ echo OK" (display "Error: qt_static_symbols.c compilation failed\n") (exit 1))))) -;; jsh FFI shim (needed for static builds and macOS dynamic builds so ffi_* symbols are in the binary) -;; ffi-shim.c lives in the jsh root (parent of jsh-dir which is the src/ subdir) -(when (or jemacs-static? macos-build?) - (let* ((jsh-root (path-parent jsh-dir)) - (cmd (format "gcc -c -O2 -o jemacs-qt-jsh-ffi.o ~a/ffi-shim.c -Wall 2>&1" - jsh-root))) - (unless (= 0 (system cmd)) - (display "Error: jsh ffi-shim.c compilation failed\n") - (exit 1)))) +;; jsh FFI shim. Compile this into every binary so jsh/imported editor +;; modules do not require an external LD_PRELOAD just to resolve ffi_* symbols. +(let* ((jsh-root (path-parent jsh-dir)) + (cmd (format "gcc -c -O2 -o jemacs-qt-jsh-ffi.o ~a/ffi-shim.c -Wall 2>&1" + jsh-root))) + (unless (= 0 (system cmd)) + (display "Error: jsh ffi-shim.c compilation failed\n") + (exit 1))) ;; libcoreutils.c (coreutils_raw_mode_*, coreutils_terminal_*, etc.) ;; Needed for static builds — provides C symbols referenced by jerboa-coreutils FFI @@ -386,30 +441,28 @@ echo OK" ;; jsh embed-crypto. Older jsh trees had embed-crypto.c; newer ones use ;; libjerboa_native. If neither is available, compile explicit failing stubs ;; so non-embed editor features still link and encrypted embed calls fail. -(when (or jemacs-static? macos-build?) - (let* ((jsh-root (path-parent jsh-dir)) - (embed-src (format "~a/embed-crypto.c" jsh-root)) - (fallback-src "support/jsh_embed_crypto_stubs.c") - (src (if (file-exists? embed-src) embed-src fallback-src)) - (cmd (format "gcc -c -O2 -o jemacs-qt-embed-crypto.o ~a -I~a -Wall 2>&1" - src jsh-root))) - (unless (= 0 (system cmd)) - (display "Error: embed-crypto.c compilation failed\n") - (exit 1)))) +(let* ((jsh-root (path-parent jsh-dir)) + (embed-src (format "~a/embed-crypto.c" jsh-root)) + (fallback-src "support/jsh_embed_crypto_stubs.c") + (src (if (file-exists? embed-src) embed-src fallback-src)) + (cmd (format "gcc -c -O2 -o jemacs-qt-embed-crypto.o ~a -I~a -Wall 2>&1" + src jsh-root))) + (unless (= 0 (system cmd)) + (display "Error: embed-crypto.c compilation failed\n") + (exit 1))) ;; jsh ssh-agent stub (chez_ssh_agent_stop referenced in main.sls but not needed for jemacs) -(when (or jemacs-static? macos-build?) - (let ((stub-file "jemacs-qt-ssh-agent-stub.c")) - (call-with-output-file stub-file - (lambda (out) - (fprintf out "/* Stub — jemacs doesn't use ssh-agent */~n") - (fprintf out "void chez_ssh_agent_stop(void) {}~n") - (fprintf out "int chez_ssh_agent_is_running(void) { return 0; }~n")) - 'replace) - (let ((cmd (format "gcc -c -O2 -o jemacs-qt-ssh-agent-stub.o ~a -Wall 2>&1" stub-file))) - (unless (= 0 (system cmd)) - (display "Error: ssh-agent stub compilation failed\n") - (exit 1))))) +(let ((stub-file "jemacs-qt-ssh-agent-stub.c")) + (call-with-output-file stub-file + (lambda (out) + (fprintf out "/* Stub — jemacs doesn't use ssh-agent */~n") + (fprintf out "void chez_ssh_agent_stop(void) {}~n") + (fprintf out "int chez_ssh_agent_is_running(void) { return 0; }~n")) + 'replace) + (let ((cmd (format "gcc -c -O2 -o jemacs-qt-ssh-agent-stub.o ~a -Wall 2>&1" stub-file))) + (unless (= 0 (system cmd)) + (display "Error: ssh-agent stub compilation failed\n") + (exit 1)))) ;; chez-scintilla stubs (TUI-only — Qt never calls these; stubs allow foreign-procedure defs) (when jemacs-static? @@ -419,7 +472,7 @@ echo OK" (exit 1)))) ;; chez-ssl shim (TLS FFI for jerboa-aws EC2 API calls) -(when jemacs-static? +(when (and jemacs-static? aws-enabled?) (let* ((cmd (format "gcc -c -O2 -o jemacs-qt-chez-ssl-shim.o ~a/chez_ssl_shim.c -Wall 2>&1" chez-ssl-dir))) (unless (= 0 (system cmd)) @@ -578,22 +631,26 @@ grep -v '^$' | grep -v '^register_static_foreign_symbols$'") "/tmp/jemacs-build/crypto_stub.o" "")) ;; jsh Rust coreutils static library (musl build, pre-compiled on host) (jsh-coreutils-lib (or (getenv "JSH_COREUTILS_LIB") "")) - (ssl-libs (let ((pkgconf (shell-output "pkg-config --static --libs openssl 2>/dev/null" ""))) - (if (> (string-length pkgconf) 0) - pkgconf - "-L/usr/lib -lssl -lcrypto"))) + (aws-ssl-obj (if aws-enabled? "jemacs-qt-chez-ssl-shim.o" "")) + (ssl-libs (if aws-enabled? + (let ((pkgconf (shell-output "pkg-config --static --libs openssl 2>/dev/null" ""))) + (if (> (string-length pkgconf) 0) + pkgconf + "-L/usr/lib -lssl -lcrypto")) + "")) (cmd (format "g++ -static -Wl,--export-dynamic -o jemacs-qt \ jemacs-qt-main.o jemacs-qt-chez-shim.o jemacs-qt-pcre2-shim.o jemacs-qt-jsh-ffi.o \ jemacs-qt-libcoreutils.o jemacs-qt-jsh-coreutils-stubs.o \ jemacs-qt-embed-crypto.o jemacs-qt-ssh-agent-stub.o ~a \ jemacs-qt-pty-shim.o jemacs-qt-vterm-shim.o jemacs-qt-repl-shim.o jemacs-qt-jerboa-landlock.o jemacs-qt-sci-stubs.o \ -jemacs-qt-chez-ssl-shim.o \ +~a \ qt_static_symbols.o \ ~a ~a ~a ~a ~a ~a \ -L~a -lkernel -llz4 -lz \ ~a \ -lvterm -lm -ldl -lpthread -luuid -lncurses -lstdc++ 2>&1" crypto-stub + aws-ssl-obj libqt-shim qt-plugins ts-link qt-libs pcre2-libs jsh-coreutils-lib chez-dir ssl-libs))) (printf " ~a~n" cmd) @@ -627,6 +684,7 @@ jemacs-qt-main.o jemacs-qt-chez-shim.o jemacs-qt-pcre2-shim.o jemacs-qt-jsh-ffi. ;; Linux: standard dynamic link (format "g++ -rdynamic -o jemacs-qt \ jemacs-qt-main.o jemacs-qt-chez-shim.o jemacs-qt-pcre2-shim.o \ +jemacs-qt-jsh-ffi.o jemacs-qt-embed-crypto.o jemacs-qt-ssh-agent-stub.o \ ~a ~a \ -L~a -lkernel -llz4 -lz -lm -ldl -lpthread -luuid -lncurses -lstdc++ \ -L. -lqt_shim -lqscintilla2_qt6 -lvterm \ @@ -646,6 +704,9 @@ jemacs-qt-main.o jemacs-qt-chez-shim.o jemacs-qt-pcre2-shim.o \ "jemacs_qt_program.h" "jemacs_qt_petite_boot.h" "jemacs_qt_scheme_boot.h" "jemacs_qt_jemacs_qt_boot.h" "jemacs-qt-all.so" "qt-main.so" "qt-main.wpo" "jemacs-qt.boot") + '("jemacs-qt-jsh-ffi.o" "jemacs-qt-embed-crypto.o" + "jemacs-qt-ssh-agent-stub.o" "jemacs-qt-ssh-agent-stub.c" + "qt_static_symbols.o" "qt_static_symbols.c") (if jemacs-static? '("jemacs-qt-jsh-ffi.o" "jemacs-qt-libcoreutils.o" "jemacs-qt-jsh-coreutils-stubs.o" @@ -653,8 +714,11 @@ jemacs-qt-main.o jemacs-qt-chez-shim.o jemacs-qt-pcre2-shim.o \ "jemacs-qt-ssh-agent-stub.o" "jemacs-qt-ssh-agent-stub.c" "jemacs-qt-pty-shim.o" "jemacs-qt-vterm-shim.o" "jemacs-qt-jerboa-landlock.o" - "jemacs-qt-sci-stubs.o" "jemacs-qt-chez-ssl-shim.o" + "jemacs-qt-sci-stubs.o" "qt_static_symbols.o" "qt_static_symbols.c") + '()) + (if (and jemacs-static? aws-enabled?) + '("jemacs-qt-chez-ssl-shim.o") '()))) (printf "~n========================================~n") --- a/lib/jerboa-emacs/debug-repl.sls +++ b/lib/jerboa-emacs/debug-repl.sls @@ -27,7 +27,10 @@ (def *repl-protocol* 'unknown) (def *repl-unknown-ticks* 0) (def *repl-port-file* - (string-append (getenv "HOME") "/.jerboa-repl-port")) + (or (getenv "JEMACS_REPL_PORT_FILE" #f) + (string-append + (getenv "HOME" "/tmp") + "/.jerboa-repl-port"))) (def *repl-env* (interaction-environment)) (def (debug-repl-bind! name value) "Register a binding in the debug REPL environment so it's accessible via IPC.\n Uses Chez's define-top-level-value to inject the value directly." --- a/lib/jerboa-emacs/qt/app.sls +++ b/lib/jerboa-emacs/qt/app.sls @@ -2465,6 +2465,7 @@ (cons 'app-state-echo app-state-echo) (cons 'qt-current-editor qt-current-editor) (cons 'qt-current-buffer qt-current-buffer) + (cons 'qt-validate-window-tree! qt-validate-window-tree!) (cons 'qt-plain-text-edit-cursor-position qt-plain-text-edit-cursor-position) --- a/lib/jerboa-emacs/qt/commands-aliases.sls +++ b/lib/jerboa-emacs/qt/commands-aliases.sls @@ -1121,6 +1121,7 @@ (register-command! 'vterm-copy-mode cmd-vterm-copy-mode) (register-command! 'vterm-copy-done cmd-vterm-copy-done) (register-command! 'lsp cmd-toggle-lsp) + (register-command! 'lsp-start cmd-toggle-lsp) (register-command! 'lsp-goto-definition cmd-lsp-goto-definition) new file mode 100644 --- /dev/null +++ b/lib/jerboa-emacs/qt/commands-aws-native.sls @@ -0,0 +1,428 @@ +#!chezscheme +;;; Generated by jerbuild — DO NOT EDIT +;;; Source: src/jerboa-emacs/qt/commands-aws-native.ss + +(library (jerboa-emacs qt commands-aws-native) + (export cmd-aws-ec2-ssh cmd-aws-ec2-ssh-connect + cmd-aws-ec2-ssh-refresh cmd-aws-ec2-ssh-force-refresh + cmd-aws-ec2-ssh-filter cmd-aws-ec2-ssh-clear-filter + cmd-aws-ec2-ssh-sort-name cmd-aws-ec2-ssh-sort-region + aws-ec2-ssh-setup-mode!) + (import + (except (chezscheme) make-hash-table hash-table? iota \x31;+ \x31;- + getenv path-extension path-absolute? thread? make-mutex + mutex? mutex-name sort sort!) + (std sugar) (std sort) (std srfi srfi-13) + (only (std misc string) string-empty?) + (only (std misc ports) read-file-lines) + (chez-scintilla constants) (jerboa-emacs core) + (jerboa-emacs buffer) (jerboa-emacs tabulated-list) + (jerboa-emacs terminal) (jerboa-emacs async) + (jerboa-emacs echo) (jerboa-emacs qt buffer) + (jerboa-emacs qt window) (jerboa-emacs qt sci-shim) + (jerboa-emacs qt echo) (jerboa-emacs qt commands-core) + (jerboa-aws ec2 api) (jerboa-aws ec2 instances) + (jerboa core) (jerboa runtime)) + (def *aws-ec2-ssh-config-file* "~/.aws-custom-ssh.yaml") + (def *aws-ec2-ssh-cache-ttl* 300) + (def *aws-ec2-ssh-user* #f) + (def *aws-ec2-ssh-common-regions* + '("us-east-1" "us-east-2" "us-west-1" "us-west-2" "eu-west-1" "eu-west-2" + "eu-west-3" "eu-central-1" "eu-north-1" "ap-northeast-1" + "ap-northeast-2" "ap-southeast-1" "ap-southeast-2" + "ap-south-1" "sa-east-1" "ca-central-1")) + (def *aws-region-domain-map* '()) + (def *aws-cache* #f) + (def *aws-cache-expiry* 0) + (def *aws-columns* + (list (make-tl-column "Name" 25) (make-tl-column "State" 10) + (make-tl-column "Type" 14) (make-tl-column "Private IP" 16) + (make-tl-column "Region" 14) + (make-tl-column "SSH Target" 40))) + (def (aws-load-config!) + "Load region->domain mappings from config file." + (let ([path (path-expand *aws-ec2-ssh-config-file*)]) + (if (file-exists? path) + (begin + (set! *aws-region-domain-map* + (with-catch + (lambda (e) '()) + (lambda () + (let ([lines (read-file-lines path)]) + (filter-map + (lambda (line) + (let ([trimmed (string-trim line)]) + (and (> (string-length trimmed) 0) + (not (string-prefix? "#" trimmed)) + (string-contains trimmed ":") + (let* ([idx (string-contains + trimmed + ":")] + [key (string-trim + (substring trimmed 0 idx))] + [val (string-trim + (substring + trimmed + (+ idx 1) + (string-length + trimmed)))]) + (and (> (string-length key) 0) + (> (string-length val) 0) + (cons key val)))))) + lines))))) + (length *aws-region-domain-map*)) + (begin (set! *aws-region-domain-map* '()) 0)))) + (def (aws-get-domain region) + "Get domain suffix for REGION from config, or #f." + (let ([pair (assoc region *aws-region-domain-map*)]) + (and pair (cdr pair)))) + (def (aws-cache-valid?) + (and *aws-cache* + (> *aws-cache-expiry* (time-second (current-time))))) + (def (aws-cache-put! instances) + (set! *aws-cache* instances) + (set! *aws-cache-expiry* + (+ (time-second (current-time)) *aws-ec2-ssh-cache-ttl*))) + (def (aws-cache-clear!) + (set! *aws-cache* #f) + (set! *aws-cache-expiry* 0)) + (def (native-ht-ref ht key default) + "Hashtable-ref for native Chez symbol-keyed hashtables from jerboa-aws." + (if (hashtable? ht) (hashtable-ref ht key default) default)) + (def (native-instance-state inst) + "Get state name (running, stopped, etc.) from native instance hash." + (let ([state (native-ht-ref inst 'instanceState #f)]) + (if state (or (native-ht-ref state 'name #f) "-") "-"))) + (def (native-instance-name inst) + "Get Name tag value from native instance hash." + (let ([tags (native-ht-ref inst 'tagSet '())]) + (if (list? tags) + (let loop ([ts tags]) + (if (null? ts) + "" + (let ([tag (car ts)]) + (if (and (hashtable? tag) + (equal? (native-ht-ref tag 'key #f) "Name")) + (or (native-ht-ref tag 'value #f) "") + (loop (cdr ts)))))) + ""))) + (def (native-parse-instances response region) + "Parse describe-instances response hash into list of (cons region instance-hash).\n Only returns running instances." + (with-catch + (lambda (e) '()) + (lambda () + (let ([reservations (or (native-ht-ref + response + 'reservationSet + #f) + '())]) + (apply + append + (map (lambda (reservation) + (if (hashtable? reservation) + (let ([instances (or (native-ht-ref + reservation + 'instancesSet + #f) + '())]) + (if (list? instances) + (filter-map + (lambda (inst) + (and (hashtable? inst) + (string=? + (native-instance-state inst) + "running") + (cons region inst))) + instances) + '())) + '())) + (if (list? reservations) reservations '()))))))) + (def (native-instance->entry region inst) + "Convert native instance hash + region to a tabulated-list entry." + (let* ([id (or (native-ht-ref inst 'instanceId #f) "")] + [name (native-instance-name inst)] + [state (native-instance-state inst)] + [type (or (native-ht-ref inst 'instanceType #f) "-")] + [ip (or (native-ht-ref inst 'privateIpAddress #f) "-")] + [domain (aws-get-domain region)] + [ssh-target (if (and (> (string-length name) 0) domain) + (string-append name "." domain) + "-")]) + (cons id (vector name state type ip region ssh-target)))) + (def *aws-pending-regions* 0) + (def *aws-pending-instances* '()) + (def *aws-pending-errors* 0) + (def *aws-pending-callback* #f) + (def (aws-fetch-all-regions! callback) + "Fetch instances from all configured regions asynchronously via native API.\n Spawns one worker thread per region; results are merged on the UI thread." + (let ([regions *aws-ec2-ssh-common-regions*]) + (set! *aws-pending-regions* (length regions)) + (set! *aws-pending-instances* '()) + (set! *aws-pending-errors* 0) + (set! *aws-pending-callback* callback) + (for-each + (lambda (region) + (spawn-worker + 'aws-fetch-region + (lambda () + (with-catch + (lambda (e) + (ui-queue-push! + (lambda () + (set! *aws-pending-errors* + (+ *aws-pending-errors* 1)) + (set! *aws-pending-regions* + (- *aws-pending-regions* 1)) + (aws-check-fetch-complete!)))) + (lambda () + (let* ([client (EC2Client 'region: region)] + [result (describe-instances client)] + [running (native-parse-instances + result + region)]) + (ui-queue-push! + (lambda () + (set! *aws-pending-instances* + (append *aws-pending-instances* running)) + (set! *aws-pending-regions* + (- *aws-pending-regions* 1)) + (aws-check-fetch-complete!)))))))) + regions)))) + (def (aws-check-fetch-complete!) + "Check if all region fetches are done; fire callback when complete." + (when (= *aws-pending-regions* 0) + (let ([instances *aws-pending-instances*] + [cb *aws-pending-callback*]) + (aws-cache-put! instances) + (when cb (cb instances))))) + (def (aws-ec2-ssh-setup-mode!) + "Register the AWS EC2 SSH mode keymap and buffer-name mapping." + (hash-put! + *buffer-name-mode-map* + "*AWS EC2 SSH*" + 'aws-ec2-ssh) + (let ([km (make-keymap)]) + (for-each