plum

#treesitter#compiler#wasm

git clone https://git.pyrossh.dev/plum

A statically typed, imperative programming language inspired by rust, python


Makefile.toml
# Dev-loop tasks for iterating on tree-sitter-plum/plum-lsp without a full
# `cargo build -p plum-cli` (which re-embeds both into the `plum` binary via
# build.rs, then still needs a `plum editor <name>` re-run to pick them up).
# Run with `cargo make <task>` (needs https://github.com/sagiegurari/cargo-make:
# `cargo install cargo-make`).
#
# `plum editor helix`/`plum editor vscode` (the CLI's own install commands)
# remain the way to set editor support up the first time; `refresh-editors`
# here only updates whichever of those are already present.

[config]
default_to_workspace = false

[tasks.grammar-so]
description = "Compile the tree-sitter-plum grammar into a native shared library"
script_runner = "@shell"
script = '''
set -e
SRC=plum-tooling/tree-sitter-plum/src
OUT=target/plum-grammar.so
mkdir -p target
${CC:-cc} -shared -fPIC -O2 -I "$SRC" -o "$OUT" "$SRC/parser.c" "$SRC/scanner.c"
echo "compiled $OUT"
'''

[tasks.lsp-release]
description = "Build plum-lsp in release mode"
command = "cargo"
args = ["build", "--release", "-p", "plum-lsp"]

[tasks.refresh-editors]
description = "Recompile the grammar + plum-lsp from current source and refresh them in whichever editor configs `plum editor helix`/`plum editor vscode` already set up"
dependencies = ["grammar-so", "lsp-release"]
script_runner = "@shell"
script = '''
set -e
LSP_BIN=target/release/plum-lsp
GRAMMAR_SO=target/plum-grammar.so

HELIX_DIR="${HELIX_RUNTIME_CONFIG:-${XDG_CONFIG_HOME:-$HOME/.config}/helix}"
if [ -f "$HELIX_DIR/languages.toml" ]; then
  mkdir -p "$HELIX_DIR/runtime/grammars"
  cp "$GRAMMAR_SO" "$HELIX_DIR/runtime/grammars/plum.so"
  cp "$LSP_BIN" "$HELIX_DIR/plum-lsp"
  chmod +x "$HELIX_DIR/plum-lsp"
  echo "refreshed $HELIX_DIR/runtime/grammars/plum.so"
  echo "refreshed $HELIX_DIR/plum-lsp"
else
  echo "Helix not installed (run \`plum editor helix\` first) — skipping"
fi

# Extension id/version must match plum-cli/src/editor.rs's VSCODE_PUBLISHER /
# VSCODE_EXTENSION_NAME / VSCODE_EXTENSION_VERSION consts.
found_vscode=0
for dir_name in .vscode .vscode-insiders; do
  ext_dir="$HOME/$dir_name/extensions/plum-lang.plum-0.0.1"
  if [ -d "$ext_dir" ]; then
    mkdir -p "$ext_dir/server"
    cp "$LSP_BIN" "$ext_dir/server/plum-lsp"
    chmod +x "$ext_dir/server/plum-lsp"
    echo "refreshed $ext_dir/server/plum-lsp"
    found_vscode=1
  fi
done
if [ "$found_vscode" = "0" ]; then
  echo "VSCode not installed (run \`plum editor vscode\` first) — skipping"
fi
'''

# ---- release binaries -------------------------------------------------------
#
# Only the `plum` binary itself is distributed — `plum-lsp`, the tree-sitter
# grammar `.so`, and the VSCode extension bundle are all embedded INTO it by
# plum-cli/build.rs already, and `plum editor helix`/`vscode` extract them at
# install time. There's nothing separate to ship.
#
# Linux/Windows are cross-compiled via https://github.com/cross-rs/cross
# (`cargo install cross --git https://github.com/cross-rs/cross`, needs
# Docker) — it ships a proper per-target C toolchain (gcc-multilib for Linux,
# mingw-w64 for Windows), which a bare `cargo build --target ...` doesn't have
# and this project needs (tree-sitter's scanner.c/parser.c are compiled via
# the `cc` crate). macOS still builds natively since that's what's running
# this Makefile.
#
# `cargo make release` is the one-shot version: builds all 3 platforms, tags
# v<version> locally, regenerates README.md's download links, and uploads
# everything to R2. Version comes from plum-cli/Cargo.toml — bump that first.

[env]
PLUM_VERSION = { script = ["grep -m1 '^version' plum-cli/Cargo.toml | sed -E 's/version = \"(.*)\"/\\1/'"] }

[tasks.dist-macos]
description = "Build a release plum-cli binary for this Mac into dist/plum-cli/"
script_runner = "@shell"
script = '''
set -e
cargo build --release -p plum-cli
mkdir -p dist/plum-cli
ARCH=$(uname -m)
case "$ARCH" in
  arm64|aarch64) ARCH=arm64 ;;
  x86_64) ARCH=x86_64 ;;
esac
OUT="dist/plum-cli/plum-darwin-$ARCH"
cp target/release/plum "$OUT"
echo "built $OUT"
'''

[tasks.dist-linux]
description = "Cross-build a release plum-cli binary for Linux x86_64 (via `cross`) into dist/plum-cli/"
script_runner = "@shell"
script = '''
set -e
cross build --release -p plum-cli --target x86_64-unknown-linux-gnu
mkdir -p dist/plum-cli
cp target/x86_64-unknown-linux-gnu/release/plum dist/plum-cli/plum-linux-x86_64
echo "built dist/plum-cli/plum-linux-x86_64"
'''

[tasks.dist-windows]
description = "Cross-build a release plum-cli binary for Windows x86_64 (via `cross`) into dist/plum-cli/"
script_runner = "@shell"
script = '''
set -e
cross build --release -p plum-cli --target x86_64-pc-windows-gnu
mkdir -p dist/plum-cli
cp target/x86_64-pc-windows-gnu/release/plum.exe dist/plum-cli/plum-windows-x86_64.exe
echo "built dist/plum-cli/plum-windows-x86_64.exe"
'''

[tasks.dist-all]
description = "Build release plum-cli binaries for macOS, Linux, and Windows into dist/plum-cli/"
dependencies = ["dist-macos", "dist-linux", "dist-windows"]

[tasks.tag-release]
description = "Create a local git tag v<version> (from plum-cli/Cargo.toml) for this release, if it doesn't already exist"
script_runner = "@shell"
script = '''
set -e
TAG="v${PLUM_VERSION}"
if git rev-parse "$TAG" >/dev/null 2>&1; then
  echo "tag $TAG already exists, skipping"
else
  git tag -a "$TAG" -m "plum-cli $TAG"
  echo "created tag $TAG locally — push it yourself with: git push origin $TAG"
fi
'''

[tasks.update-readme]
description = "Rewrite README.md's prebuilt-binaries block (between the <!-- prebuilt-binaries:... --> markers) to point at the current version"
script_runner = "@shell"
script = '''
set -e
BASE="https://git.pyrossh.dev/releases/plum-cli/v${PLUM_VERSION}"
awk -v base="$BASE" '
  /<!-- prebuilt-binaries:start -->/ {
    print
    print "| Platform | Download |"
    print "| --- | --- |"
    print "| macOS (Apple Silicon) | [plum-darwin-arm64](" base "/plum-darwin-arm64) |"
    print "| Linux (x86_64) | [plum-linux-x86_64](" base "/plum-linux-x86_64) |"
    print "| Windows (x86_64) | [plum-windows-x86_64.exe](" base "/plum-windows-x86_64.exe) |"
    print ""
    print "Make it executable and put it on your `PATH`, e.g. on macOS/Linux:"
    print ""
    print "```sh"
    print "curl -L -o plum " base "/plum-darwin-arm64"
    print "chmod +x plum"
    print "mv plum ~/.cargo/bin/plum   # or anywhere else already on your PATH"
    print "```"
    in_block = 1
    next
  }
  /<!-- prebuilt-binaries:end -->/ { in_block = 0 }
  in_block == 1 { next }
  { print }
' README.md > README.md.tmp
mv README.md.tmp README.md
echo "updated README.md prebuilt-binaries links to v${PLUM_VERSION}"
'''

[tasks.release]
description = "Build macOS/Linux/Windows release binaries, tag v<version>, update README download links, and upload all 3 to R2 (requires the `git` rclone remote — see `rclone config show git`)"
dependencies = ["dist-all", "tag-release", "update-readme"]
script_runner = "@shell"
script = '''
set -e
# `--s3-no-check-bucket`: the R2 access token here is scoped to this one
# bucket with no ListBuckets/CreateBucket permission, so rclone's default
# "does this bucket exist?" preflight (which needs one of those) fails —
# skip it and assume the bucket (already created out-of-band) exists.
rclone copy dist/plum-cli/ "git:git/releases/plum-cli/v${PLUM_VERSION}/" --s3-no-check-bucket --progress
echo ""
echo "published v${PLUM_VERSION}. Remaining steps:"
echo "  git add README.md && git commit -m \"release v${PLUM_VERSION}\""
echo "  git push && git push origin v${PLUM_VERSION}"
'''