char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somdeslop: factor module prep/transpilatione/etc into loader.rsab5df08

main
2 folders9 files

files

avril-typescript/
tests/
.gitignore23 B
.vscodeignore89 B
README.md8.9 KiB
avril-config.tmLanguage.json1.2 KiB
extension.cjs11.8 KiB
language-configuration.json546 B
package.json3.0 KiB
pnpm-lock.yaml37.4 KiB
pnpm-workspace.yaml159 B

avril for VS Code

Native TypeScript language features, live diagnostics, and avril.conf syntax highlighting. The client launches avril lsp directly; it does not run a Deno or JavaScript language server.

Build and install

There are three pieces: the Avril executable, a separately built patched native TypeScript executable, and the VS Code extension. The extension does not bundle either executable. Stock typescript from npm and unpatched native TypeScript executables cannot serve as the LSP backend.

Prerequisites:

1. Build Avril and the patched compiler

Run these commands from the Avril repository root, in a Unix shell:

cargo build --locked -p avril-cli --bin avril

typescript_src=$(mktemp -d)
git clone --filter=blob:none --no-checkout \
  https://github.com/microsoft/TypeScript.git "$typescript_src"
git -C "$typescript_src" checkout --detach b5c34ba0c61a756c8abaf133236dddf982c27f45
bash lib/lsp/typescript/build.sh "$typescript_src" "/absolute/path/to/avril-tsc"

printf 'avril.lsp.executable: %s\n' "$PWD/target/debug/avril"
printf 'avril.lsp.backend: %s\n' "/absolute/path/to/avril-tsc"

Copy the two printed paths for the settings below. The compiler executable is installed outside the temporary checkout and embeds its library declarations; the checkout is not needed at runtime. The script checks the pinned revision, applies bridge.patch, runs the native bridge tests, and builds 7.1.0-dev.20261013.1.

If Go is not on PATH, replace the build.sh command above with:

nix shell nixpkgs#go --command bash lib/lsp/typescript/build.sh \
  "$typescript_src" "/absolute/path/to/avril-tsc"

The script requires a clean checkout and leaves it patched. To rebuild after an Avril patch update, use a fresh checkout rather than rerunning it on the patched one. See lib/lsp/BACKEND.md in the source checkout for the backend contract.

2. Package and install the extension

Still starting from the Avril repository root:

cd editors/vscode
pnpm install --frozen-lockfile --prod=false --ignore-scripts
pnpm run package
code --install-extension avril.vsix --force

If your Node installation does not include npm on PATH, Nix can supply both for packaging: run nix shell nixpkgs#nodejs_24 --command pnpm run package from editors/vscode instead of the plain package command.

Use codium instead of code for VSCodium. Alternatively, choose Extensions: Install from VSIX... and select editors/vscode/avril.vsix. After installing or updating, run Developer: Reload Window.

The extension bundles its client dependencies. Projects do not need an npm install; this adds no npm/Node compatibility to avril guests.

Live language server

  1. Open and trust a local workspace. The client currently uses its first folder; other workspace folders retain their own TypeScript language features.

  2. Set these user settings (executable settings are machine-scoped):

    {
      "avril.lsp.backend": "/absolute/path/to/avril-tsc",
      "avril.lsp.executable": "/absolute/path/to/avril/target/debug/avril"
    }

    Substitute the literal absolute paths printed during the build. These settings do not expand ~, $HOME, or ${workspaceFolder}. Open Preferences: Open User Settings (JSON) to edit them; do not put these machine-scoped paths in the project's .vscode/settings.json. If you built Avril in release mode or installed it separately, use that executable instead. You do not need to set typescript.tsdk.

  3. Keep VS Code's built-in TypeScript and JavaScript Language Features extension enabled. avril suppresses its competing results for the active folder while the language server runs, and restores them when it stops.

  4. With avril.conf directly in the first workspace folder, the language server starts automatically once the backend is configured. Nested configurations do not trigger startup. Without a root configuration, run avril: Start Language Server manually, then open a TS/TSX/JS/JSX file.

The server follows real avril configuration, imports, packages, and declarations. Unsaved imports and disk/config changes refresh automatically. No manifest or generated tsconfig is needed. The editor may populate the permitted cache, but never writes lockfiles or application files.

Use avril.lsp.options for CLI policy flags, for example ["--offline", "--frozen"]. Restart the language server after changing launch settings. avril: Stop Language Server shuts down the server and native child and prevents automatic restarts until you run avril: Start Language Server or reload the window. Set avril.lsp.autoStart to false to opt out persistently. Use avril.lsp.preferences for native TypeScript preferences (for example, {"referencesCodeLensEnabled": true, "includeInlayParameterNameHints": "all"}). These update live; omitted preferences preserve native defaults. Creating a root avril.conf starts the server; removing it stops an automatically started server. Untrusted workspaces cannot start it.

Avril uses the native TypeScript language-service results for completion and resolution, navigation, rename, symbols, formatting, semantic tokens, inlay hints, call hierarchy, code actions, and the other capabilities advertised by the server. Type hierarchy is not advertised because the pinned native backend does not implement it. Workspace sources remain editable; acquired npm files open as immutable avril-builtin:/dependencies/ documents. HTTPS, HTTP, and builtin declarations open through read-only avril-https:, avril-http:, and avril-builtin: providers. The native backend's server capabilities are exposed directly; resolution and edits remain subject to Avril's project authority. The server currently rebuilds complete generations; broader discovery and checking-context limitations are listed in lib/lsp/README.md in the source checkout.

Verify the setup

Open a TypeScript file and check hover, completion, and Go to Definition. For a known example, open lib/lsp/tests/fixture from this repository as the workspace folder, then open main.tsx: hovering localValue should show its literal type 42, and Go to Definition should reach dep file.ts.

If startup fails, open View: Toggle Output and select avril. Check that both executable paths exist, the backend was built with this repository's patch, the workspace is trusted, and avril.conf is directly in its first folder (or start the server manually). The extension launches avril lsp; you do not need to run it separately in a terminal.

After rebuilding either executable, run avril: Stop Language Server, then avril: Start Language Server to replace the running processes. Repackage and reinstall the VSIX only when the extension itself changes.

Validation

Run the client lifecycle, ownership, CodeLens conversion, and read-only document URI roundtrip tests with pnpm test from editors/vscode/.

From the repository root, after installing client dependencies:

export AVRIL_LSP_BACKEND=/absolute/path/to/avril-tsc
export AVRIL_LSP_AVRIL="$PWD/target/debug/avril"
profile=$(mktemp -d /tmp/avril-editor-test.XXXXXX)
xvfb-run -a codium --wait --verbose --disable-gpu --ozone-platform=x11 \
  --user-data-dir="$profile/user" --extensions-dir="$profile/extensions" \
  --skip-welcome --skip-release-notes --disable-workspace-trust \
  --extensionDevelopmentPath="$PWD/editors/vscode" \
  --extensionTestsPath="$PWD/editors/vscode/tests/editor.cjs" \
  "$PWD/lib/lsp/tests/fixture" > "$profile/test.log" 2>&1
grep AVRIL_EDITOR_TESTS_PASSED "$profile/test.log"

The actual extension-host test invokes hover, definition, completion, signature help, rename, and references CodeLens providers; it also runs the resolved CodeLens command through VS Code's built-in references UI. It checks unsaved edits and diagnostics, and opens real builtin declarations. It also checks automatic startup and restoration/suppression of built-in TypeScript diagnostics across server stop/start. It never saves fixture application files. The trust override is for this known fixture only; systems without Chromium sandbox support may also need --no-sandbox for the isolated test window. Require the success marker: some editor versions exit zero even when extension tests fail. Tests are excluded from the packaged extension.

Run the server's live/protocol/lifecycle and native API regression tests using the commands in lib/lsp/README.md in the source checkout.