These might come in handy ;D whoops

This commit is contained in:
jess 2026-04-25 04:00:29 -07:00
parent 3cfaa7d370
commit 1d4c9c96cb
7 changed files with 234 additions and 7 deletions

View File

@ -1,2 +1,2 @@
[alias]
xtask = "run --quiet --release --package xtask --"
xtask = "run --release --package xtask --"

View File

@ -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.

42
scripts/linux/build.sh Executable file
View File

@ -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"

58
scripts/linux/install.sh Executable file
View File

@ -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/<ver>/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/<ver>/plugins/" >&2
echo " $FLATPAK_ROOT/<ver>/plugins/" >&2
echo "launch KiCad once first so it creates its data dirs, then re-run." >&2
exit 1
fi

100
scripts/macos/build.sh Executable file
View File

@ -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"

25
scripts/macos/install.sh Executable file
View File

@ -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"

View File

@ -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);