Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"name": "CLEAR Compiler",

// Microsoft's Ruby 3.2 base image — same minor as CI
// (.github/workflows/ci.yml's RUBY_VERSION).
"image": "mcr.microsoft.com/devcontainers/ruby:1-3.2",

// Node + npm for building the in-repo VS Code extension
// (.vscode/extensions/cheat-lang). Plus git so the workspace
// can interact with origin.
"features": {
"ghcr.io/devcontainers/features/node:1": { "version": "22" },
"ghcr.io/devcontainers/features/git:1": {}
},

// Runs once after the container is created. See setup.sh — installs
// gems, downloads the pinned Zig toolchain, and compiles the VS Code
// extension so the LSP is ready as soon as the user opens a .cht file.
"postCreateCommand": "bash .devcontainer/setup.sh",

// Runs on every container start (including rebuilds and resumes from
// a stopped state). `bundle install` is idempotent and fast when the
// gems are already present; running it here means the LSP recovers
// automatically if the gem cache went missing between sessions.
"postStartCommand": "bundle install --quiet",

"customizations": {
"vscode": {
"settings": {
"files.associations": {
"*.cht": "clear"
},
"[clear]": {
"editor.tabSize": 2,
"editor.insertSpaces": true,
"editor.detectIndentation": false
}
},
// Extensions from the marketplace that pair well with editing a
// Ruby + Zig + TypeScript multi-language repo. The in-repo
// .vscode/extensions/cheat-lang extension auto-loads from the
// workspace; no marketplace install needed for it.
"extensions": [
"rebornix.ruby",
"ziglang.vscode-zig"
]
}
},

"remoteUser": "vscode",

// Reasonable defaults; bump when the project gains web servers or
// dashboards that need port forwarding.
"forwardPorts": []
}
72 changes: 72 additions & 0 deletions .devcontainer/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env bash
# Devcontainer post-create hook. Runs once when the container is built.
#
# Steps (idempotent — safe to re-run):
# 1. Install Ruby gems for the compiler.
# 2. Install Zig (matches the version pinned in CI).
# 3. Build the in-repo VS Code extension.

set -euo pipefail

ZIG_VERSION="0.16.0"
ZIG_INSTALL_DIR="/usr/local/share/zig"

echo "[devcontainer] $(date '+%H:%M:%S') step 1/3 — bundle install"
bundle install

echo "[devcontainer] $(date '+%H:%M:%S') step 2/3 — installing Zig ${ZIG_VERSION}"
if command -v zig >/dev/null 2>&1; then
echo " zig already on PATH ($(zig version)) — skipping"
else
arch="$(uname -m)"
case "$arch" in
x86_64) zig_arch="x86_64-linux" ;;
aarch64) zig_arch="aarch64-linux" ;;
*) echo " unsupported arch: $arch — install zig manually"; exit 0 ;;
esac
tarball="zig-${zig_arch}-${ZIG_VERSION}.tar.xz"
url="https://ziglang.org/download/${ZIG_VERSION}/${tarball}"

echo " downloading ${url}"
curl -fsSL "$url" -o "/tmp/${tarball}"

sudo mkdir -p "$ZIG_INSTALL_DIR"
sudo tar -xJf "/tmp/${tarball}" -C "$ZIG_INSTALL_DIR" --strip-components=1
sudo ln -sf "$ZIG_INSTALL_DIR/zig" /usr/local/bin/zig
rm -f "/tmp/${tarball}"
echo " zig $(zig version) installed at $ZIG_INSTALL_DIR"
fi

echo "[devcontainer] $(date '+%H:%M:%S') step 3/4 — building VS Code extension"
pushd .vscode/extensions/cheat-lang >/dev/null
npm install --silent
npm run compile
popd >/dev/null

echo "[devcontainer] $(date '+%H:%M:%S') step 4/4 — installing extension into VS Code Server"
# VS Code (and Codespaces) does NOT auto-load extensions from
# `.vscode/extensions/<name>/` — that's a Cursor-specific convention.
# To get the extension loaded in vanilla VS Code Server, symlink the
# built directory into `~/.vscode-server/extensions/` using the
# `<publisher>.<name>-<version>` naming convention VS Code expects.
EXT_SRC="$PWD/.vscode/extensions/cheat-lang"
EXT_NAME="clear.clear-lang-0.2.0"

# Codespaces uses ~/.vscode-server/extensions; some Dev Containers
# use ~/.vscode-remote/extensions. Symlink to whichever exists, and
# create both as a belt-and-suspenders.
for VSCODE_HOME in "$HOME/.vscode-server" "$HOME/.vscode-remote"; do
mkdir -p "$VSCODE_HOME/extensions"
ln -sfn "$EXT_SRC" "$VSCODE_HOME/extensions/$EXT_NAME"
echo " installed at $VSCODE_HOME/extensions/$EXT_NAME"
done

echo "[devcontainer] $(date '+%H:%M:%S') setup complete"
echo ""
echo " Try it:"
echo " 1. Open any .cht file (try transpile-tests/01_smoke.cht)"
echo " 2. Squiggles, hover (mouse-over), and Ctrl+. (quick fix) all work."
echo ""
echo " Run the test suite:"
echo " bundle exec prspec spec/ # 4180+ Ruby specs"
echo " ./clear test transpile-tests/ # 514 transpile tests"
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# Ignore everything at root, then explicitly allow known files/dirs.
# Anything new dropped at root is ignored by default.
/*
!/.devcontainer/
!/.github/
!/.gitignore
!/.rspec
Expand All @@ -17,6 +18,7 @@
!/TODO.md
!/WALKTHROUGH.md
!/clear
!/bin/
!/benchmarks/
!/docs/
!/examples/
Expand Down
25 changes: 0 additions & 25 deletions .vscode/extensions/cheat-lang

This file was deleted.

3 changes: 3 additions & 0 deletions .vscode/extensions/cheat-lang/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
out/
*.vsix
119 changes: 119 additions & 0 deletions .vscode/extensions/cheat-lang/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# clear-lang — VS Code extension for CLEAR

Syntax highlighting + Language Server integration for the CLEAR
programming language (`.cht` files). Surfaces diagnostics, hover
documentation, and quick-fix code actions in VS Code, the same way
the Neovim setup does.

## What you'll get

- **Squiggles** on every error with the registry code shown.
- **Hover** (cursor on a diagnostic) — markdown popup with the
registry's summary, cause, fix hint, and a worked bad-vs-good
example pulled from the test suite.
- **Quick-fix menu** (Ctrl+. / Cmd+.) — choose from the available
auto / interactive fixes; accepting one applies the edit.

## One-time setup (from the cheat repo root)

The extension lives inside the repo at
`.vscode/extensions/cheat-lang/`. Build the TypeScript client:

```sh
cd .vscode/extensions/cheat-lang
npm install
npm run compile
```

This produces `out/extension.js` (the entry point referenced by
`package.json`). The extension is now ready.

### How VS Code finds it

VS Code automatically loads extensions found in `.vscode/extensions/`
when you open the workspace. No manual install step needed beyond
`npm run compile`. Reload the VS Code window (Ctrl+Shift+P →
"Developer: Reload Window") to pick up the freshly-built extension.

## Verifying

Open any `.cht` file. The status bar should show "CLEAR" as the
language. Open the Output panel (Ctrl+Shift+U) and select
"CLEAR Language Server" from the dropdown — you should see startup
log lines from the server.

Try a deliberately-broken file:

```clear
FN main() RETURNS Void ->
_ = doesNotExist;
x = 5;
WITH RESTRICT x { _ = x; }
END
```

You should see:

1. Squiggles under `doesNotExist` (line 2) and the `WITH RESTRICT x`
line (line 4).
2. Hover the mouse over `doesNotExist` → tooltip with the registry
markdown.
3. Cursor on the `x` of `RESTRICT x`, press Ctrl+. → menu offers
"Declare 'x' as MUTABLE at its binding site (line 3).". Accept;
the buffer updates.

## Settings

`clear.serverPath` (string, default `""`) — absolute path to
`bin/clear-lsp`. Defaults to auto-detecting from the extension's
install location, which works when the extension lives inside the
cheat repo. Set it explicitly when installing as a `.vsix` outside
the repo.

`clear.serverArgs` (array of string, default
`["--log-level=info"]`) — extra arguments passed to clear-lsp. Bump
to `--log-level=debug` for verbose protocol logs.

`clear.useBundleExec` (boolean, default `true`) — whether to
invoke the server via `bundle exec`. Set to false if your
environment has the right gems on `$LOAD_PATH` already (uncommon).

## Troubleshooting

- **"clear-lsp not found at /path"** — the auto-detection failed.
Either move the extension to `.vscode/extensions/cheat-lang/`
inside your cheat clone, or set `clear.serverPath` manually.
- **Server starts then stops immediately** — open the
"CLEAR Language Server" output channel; the server's stderr
appears there. Common causes: missing gems (`bundle install` in
the repo root) or wrong Ruby version.
- **No diagnostics on a file with errors** — confirm the language
is "CLEAR" in the status bar; if VS Code thinks it's plain text,
the language registration didn't take. Try reloading the window.

## Files

```
.vscode/extensions/cheat-lang/
├── package.json — extension manifest
├── tsconfig.json — TypeScript config
├── language-configuration.json — comments, brackets, indentation
├── README.md — this file
├── src/extension.ts — LSP client (TypeScript)
├── syntaxes/clear.tmLanguage.json — syntax highlighting grammar
└── out/extension.js — compiled client (generated)
```

## Packaging as a .vsix (optional)

For distribution outside the repo, install `vsce` and package:

```sh
npm install -g @vscode/vsce
cd .vscode/extensions/cheat-lang
vsce package
```

Produces `clear-lang-0.2.0.vsix`. Install via "Extensions: Install
from VSIX..." in VS Code. Users will need to set `clear.serverPath`
manually since auto-detection won't find the binary.
27 changes: 27 additions & 0 deletions .vscode/extensions/cheat-lang/language-configuration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"comments": {
"lineComment": "#"
},
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
],
"autoClosingPairs": [
{ "open": "{", "close": "}" },
{ "open": "[", "close": "]" },
{ "open": "(", "close": ")" },
{ "open": "\"", "close": "\"", "notIn": ["string"] }
],
"surroundingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""]
],
"indentationRules": {
"increaseIndentPattern": "(.*\\s(DO|THEN|->)\\s*$)|(.*\\{\\s*$)|(\\bSTRUCT\\s+\\w+\\s*\\{\\s*$)|(\\bENUM\\s+\\w+\\s*\\{\\s*$)|(\\bUNION\\s+\\w+\\s*\\{\\s*$)",
"decreaseIndentPattern": "^\\s*(END|\\}|ELSE|ELSE_IF|CATCH)\\b"
},
"wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)"
}
Loading
Loading