From 1d4c9c96cbdbab0471d777ffea95d91586dd499f Mon Sep 17 00:00:00 2001 From: jess Date: Sat, 25 Apr 2026 04:00:29 -0700 Subject: [PATCH] These might come in handy ;D whoops --- .cargo/config.toml | 2 +- README.md | 12 ++--- scripts/linux/build.sh | 42 ++++++++++++++++ scripts/linux/install.sh | 58 +++++++++++++++++++++++ scripts/macos/build.sh | 100 +++++++++++++++++++++++++++++++++++++++ scripts/macos/install.sh | 25 ++++++++++ xtask/src/main.rs | 2 + 7 files changed, 234 insertions(+), 7 deletions(-) create mode 100755 scripts/linux/build.sh create mode 100755 scripts/linux/install.sh create mode 100755 scripts/macos/build.sh create mode 100755 scripts/macos/install.sh diff --git a/.cargo/config.toml b/.cargo/config.toml index c6536eb..e11d56a 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,2 +1,2 @@ [alias] -xtask = "run --quiet --release --package xtask --" +xtask = "run --release --package xtask --" diff --git a/README.md b/README.md index ff77596..e674202 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Layers -An image maniplulation program-style logical-layer panel for KiCad 10. Adds a overlay-style panel (in the spirit of Paint DOT net) into named logical layers. -You can add or subtract your selection to and from the layer, or to and from the board. You can hide and unhide each layers cleanly. You can rename/colour/lock/annotate, sort and organize the layers, a layer can have childen. +An image maniplulation program-style logical-layer panel for KiCad 10. -There are also boolean operations (merge/subtract/intersect) between layers (logical) -snap to grid, and more to come. Operations are all composed together as one commit and can easily be undone with Edit->Undo or equivalent. +You can add or subtract your selection to and from the layer, or to and from the board. You can hide and unhide each layer cleanly. You can rename/colour/lock/annotate, sort and organize the layers, a layer can also have childen. + +There are also boolean operations (merge/subtract/intersect) between layers (logical), snap to grid, and more to come. Operations are all composed together as one commit and can easily be undone with Edit->Undo or equivalent. Rendering of in-panel board previews is powered by [Siphon](https://git.else-if.org/jess/Siphon), a pure-Rust KiCad-board-to-vectors crate. You would not technically need KiCad installed to produce the vectors, it is a completely isolated utility which makes no calls at all to kicad-cli. @@ -28,7 +28,7 @@ cd Layers cargo xtask install ``` -Installs to `~/Documents/KiCad/10.0/plugins/com.jesshunter.layers/`. +Installs to `~/Documents/KiCad/10.0/plugins/com.jesshunter.layers/` ### Windows (10 / 11, ARM64 or x86_64) @@ -151,7 +151,7 @@ cd Layers cargo xtask install ``` -Installs to `~/.local/share/kicad/10.0/plugins/com.jesshunter.layers/`. +Installs to `~/.local/share/kicad/10.0/plugins/com.jesshunter.layers/` In both cases, it checks both the standard directory and the Flatpak directory. If you for some reason have both, it places it in both. If for some reason you have both but only want it in one of them, you can just delete it from the one you don't want it in. diff --git a/scripts/linux/build.sh b/scripts/linux/build.sh new file mode 100755 index 0000000..efe4cd6 --- /dev/null +++ b/scripts/linux/build.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +cd "$ROOT" + +render_plugin_json() { + local entrypoint="$1" + local out="$2" + local in="$ROOT/plugin.json.in" + if [ ! -f "$in" ]; then + echo "ERROR: $in not found" >&2 + exit 1 + fi + sed "s|@ENTRYPOINT@|$entrypoint|g" "$in" > "$out" +} + +STAGE="$ROOT/build/bin/com.jesshunter.layers" +APPDIR="$STAGE/bin" + +rm -rf "$STAGE" +mkdir -p "$APPDIR" "$STAGE/resources" + +if command -v rsvg-convert >/dev/null 2>&1 && [ -f "$ROOT/resources/Layers.svg" ]; then + for size in 24 48 128 256; do + if [ ! -f "$ROOT/resources/icon-${size}.png" ]; then + rsvg-convert --width "$size" --height "$size" \ + "$ROOT/resources/Layers.svg" -o "$ROOT/resources/icon-${size}.png" + fi + done +fi + +cargo build --release --bin layers + +cp "$ROOT/target/release/layers" "$APPDIR/Layers" +chmod +x "$APPDIR/Layers" +render_plugin_json "bin/Layers" "$STAGE/plugin.json" +[ -f "$ROOT/LICENCE" ] && cp "$ROOT/LICENCE" "$STAGE/LICENCE" +cp -r "$ROOT/resources/." "$STAGE/resources/" + +echo "staged: $STAGE" +echo "bin: $APPDIR/Layers" diff --git a/scripts/linux/install.sh b/scripts/linux/install.sh new file mode 100755 index 0000000..142afe3 --- /dev/null +++ b/scripts/linux/install.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +cd "$ROOT" + +case "$(uname -s)" in + Linux) ;; + *) echo "wrong platform: $(uname -s) — use cargo xtask install" >&2; exit 1;; +esac + +bash "$ROOT/scripts/linux/build.sh" + +STAGE="$ROOT/build/bin/com.jesshunter.layers" +PLUGIN_ID="com.jesshunter.layers" + +# Drop into every existing KiCad >=10 install we can find — native and flatpak, +# every version dir KiCad has already created. We never mkdir kicad//plugins; +# KiCad creates it on first launch and we only fill in our own subdir. +install_to_kicad_root() { + local kicad_root="$1" + [ -d "$kicad_root" ] || return 1 + local installed=0 + for ver_dir in "$kicad_root"/*/; do + local ver + ver="$(basename "$ver_dir")" + [[ "$ver" =~ ^([0-9]+)\.0$ ]] || continue + (( ${BASH_REMATCH[1]} >= 10 )) || continue + local plugins_dir="${ver_dir}plugins" + [ -d "$plugins_dir" ] || continue + + local target="$plugins_dir/$PLUGIN_ID" + rm -rf "$target/bin" "$target/resources" "$target/plugin.json" "$target/LICENCE" + mkdir -p "$target/bin" "$target/resources" + cp -R "$STAGE/bin/." "$target/bin/" + [ -f "$STAGE/plugin.json" ] && cp "$STAGE/plugin.json" "$target/plugin.json" + [ -f "$STAGE/LICENCE" ] && cp "$STAGE/LICENCE" "$target/LICENCE" + cp -R "$STAGE/resources/." "$target/resources/" + echo "installed: $target" + installed=1 + done + return $((1 - installed)) +} + +NATIVE_ROOT="${XDG_DATA_HOME:-$HOME/.local/share}/kicad" +FLATPAK_ROOT="$HOME/.var/app/org.kicad.KiCad/data/kicad" + +ok=0 +install_to_kicad_root "$NATIVE_ROOT" && ok=1 || true +install_to_kicad_root "$FLATPAK_ROOT" && ok=1 || true + +if [ "$ok" -eq 0 ]; then + echo "no KiCad 10+ install detected. checked:" >&2 + echo " $NATIVE_ROOT//plugins/" >&2 + echo " $FLATPAK_ROOT//plugins/" >&2 + echo "launch KiCad once first so it creates its data dirs, then re-run." >&2 + exit 1 +fi diff --git a/scripts/macos/build.sh b/scripts/macos/build.sh new file mode 100755 index 0000000..77137fc --- /dev/null +++ b/scripts/macos/build.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +cd "$ROOT" + +# Renders plugin.json.in -> $2 with @ENTRYPOINT@ replaced by $1. +render_plugin_json() { + local entrypoint="$1" + local out="$2" + local in="$ROOT/plugin.json.in" + if [ ! -f "$in" ]; then + echo "ERROR: $in not found" >&2 + exit 1 + fi + sed "s|@ENTRYPOINT@|$entrypoint|g" "$in" > "$out" +} + +STAGE="$ROOT/build/bin/com.jesshunter.layers" +APP="$STAGE/bin/Layers.app" +CONTENTS="$APP/Contents" +MACOS_DIR="$CONTENTS/MacOS" +RESOURCES_DIR="$CONTENTS/Resources" + +rm -rf "$STAGE" +mkdir -p "$STAGE/bin" "$STAGE/resources" "$MACOS_DIR" "$RESOURCES_DIR" + +# Icon PNGs for the KiCad toolbar — rendered straight from Layers.svg. +if command -v rsvg-convert >/dev/null 2>&1 && [ -f "$ROOT/resources/Layers.svg" ]; then + for size in 24 48; do + rsvg-convert --width "$size" --height "$size" \ + "$ROOT/resources/Layers.svg" -o "$ROOT/resources/icon-${size}.png" + done +fi + +# Local path overrides for sibling checkouts (kicad-ipc-rs). +# Injected only while this script runs; Cargo.toml stays clean for commits. +CARGO_TOML="$ROOT/Cargo.toml" +CARGO_BAK="" +PATCH_APPLIED=0 +if [ -d "$ROOT/../kicad-ipc-rs" ] || [ -d "$ROOT/../Siphon" ]; then + CARGO_BAK="$(mktemp "${TMPDIR:-/tmp}/Cargo.toml.orig.XXXXXX")" + cp "$CARGO_TOML" "$CARGO_BAK" + { + if [ -d "$ROOT/../kicad-ipc-rs" ]; then + printf '\n[patch."https://git.else-if.org/jess/kicad-ipc-rs.git"]\n' + printf 'kicad-ipc-rs = { path = "../kicad-ipc-rs" }\n' + echo "using local ../kicad-ipc-rs (patch injected transiently)" >&2 + fi + if [ -d "$ROOT/../Siphon" ]; then + printf '\n[patch."https://git.else-if.org/jess/Siphon.git"]\n' + printf 'siphon = { path = "../Siphon" }\n' + echo "using local ../Siphon (patch injected transiently)" >&2 + fi + } >> "$CARGO_TOML" + PATCH_APPLIED=1 + trap 'if [ $PATCH_APPLIED -eq 1 ] && [ -f "$CARGO_BAK" ]; then cp "$CARGO_BAK" "$CARGO_TOML"; rm -f "$CARGO_BAK"; fi' EXIT +fi + +# Rust staticlib. +cargo build --release +RUST_LIB="$ROOT/target/release" +if [ ! -f "$RUST_LIB/liblayers.a" ]; then + echo "ERROR: liblayers.a not found at $RUST_LIB" >&2 + exit 1 +fi + +SDK="$(xcrun --show-sdk-path)" +RUST_FLAGS=(-import-objc-header "$ROOT/include/layers.h" -L "$RUST_LIB" -llayers) + +# Swift shell → Layers.app/Contents/MacOS/Layers +swiftc \ + -target arm64-apple-macosx14.0 \ + -sdk "$SDK" \ + "${RUST_FLAGS[@]}" \ + -framework Cocoa \ + -framework Metal \ + -framework MetalKit \ + -framework QuartzCore \ + -framework CoreGraphics \ + -framework CoreFoundation \ + -framework CoreVideo \ + -O \ + -o "$MACOS_DIR/Layers" \ + "$ROOT"/src/*.swift + +cp "$ROOT/Info.plist" "$CONTENTS/Info.plist" + +# Adhoc sign so Gatekeeper lets it launch. +codesign --force --sign - "$APP" + +# KiCad plugin payload alongside the .app bundle. +render_plugin_json "bin/Layers.app/Contents/MacOS/Layers" "$STAGE/plugin.json" +cp -R "$ROOT/resources/." "$STAGE/resources/" +if [ -f "$ROOT/LICENCE" ]; then + cp "$ROOT/LICENCE" "$STAGE/LICENCE" +fi + +echo "staged: $STAGE" +echo "app: $APP" diff --git a/scripts/macos/install.sh b/scripts/macos/install.sh new file mode 100755 index 0000000..30931e3 --- /dev/null +++ b/scripts/macos/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +cd "$ROOT" + +case "$(uname -s)" in + Darwin) ;; + *) echo "wrong platform: $(uname -s) — use cargo xtask install" >&2; exit 1;; +esac + +INSTALL_DIR="$HOME/Documents/KiCad/10.0/plugins/com.jesshunter.layers" + +bash "$ROOT/scripts/macos/build.sh" + +rm -rf "$INSTALL_DIR/bin" "$INSTALL_DIR/resources" "$INSTALL_DIR/plugin.json" "$INSTALL_DIR/LICENCE" +mkdir -p "$INSTALL_DIR/bin" "$INSTALL_DIR/resources" + +STAGE="$ROOT/build/bin/com.jesshunter.layers" +cp -R "$STAGE/bin/Layers.app" "$INSTALL_DIR/bin/Layers.app" +cp "$STAGE/plugin.json" "$INSTALL_DIR/plugin.json" +cp -R "$STAGE/resources/." "$INSTALL_DIR/resources/" +[ -f "$STAGE/LICENCE" ] && cp "$STAGE/LICENCE" "$INSTALL_DIR/LICENCE" + +echo "installed: $INSTALL_DIR" diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 99c859d..7e0aede 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -52,6 +52,8 @@ fn main() -> ExitCode { return ExitCode::from(1); } + eprintln!("→ {} {}", runner.join(" "), script.display()); + let mut command = Command::new(runner[0]); for arg in &runner[1..] { command.arg(arg);