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
27 changes: 27 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: CI

on:
pull_request:
push:
branches: [main]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

- uses: actions/setup-node@v7
with:
node-version-file: .tool-versions
cache: npm

- run: npm ci

- run: npm run compile

- run: npm test

# Catches a malformed package.json or a missing contributed file before a tag.
- name: Verify the extension packages
run: npx @vscode/vsce package --out dexter-lsp-ci.vsix
57 changes: 57 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: Release

on:
push:
tags: ['v[0-9]+.[0-9]+.[0-9]+']

permissions:
contents: write

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

- uses: actions/setup-node@v7
with:
node-version-file: .tool-versions
cache: npm

- run: npm ci

# A tag that disagrees with package.json would publish a wrong version.
- name: Check the tag matches package.json
run: |
tag="${GITHUB_REF_NAME#v}"
pkg="$(node -p "require('./package.json').version")"
if [ "$tag" != "$pkg" ]; then
echo "Tag $GITHUB_REF_NAME does not match package.json ($pkg)." >&2
exit 1
fi

# The marketplaces use different publisher namespaces and a .vsix embeds
# its publisher, so each one needs its own package.
- name: Package for both marketplaces
run: |
make package
make package-openvsx

- name: Extract the changelog section for this version
run: |
awk -v v="${GITHUB_REF_NAME#v}" '
$0 ~ "^## v" v "$" { found = 1; next }
found && /^## / { exit }
found { print }
' CHANGELOG.md > release-notes.md
if [ ! -s release-notes.md ]; then
echo "No CHANGELOG.md section for $GITHUB_REF_NAME." >&2
exit 1
fi
cat release-notes.md

- uses: softprops/action-gh-release@v3
with:
body_path: release-notes.md
files: |
dexter-lsp-*.vsix
72 changes: 0 additions & 72 deletions .gitlab-ci.yml

This file was deleted.

4 changes: 4 additions & 0 deletions .vscodeignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
.vscode/**
.vscode-test/**
.github/**
src/**
test/**
.gitignore
.tool-versions
Makefile
tsconfig.json
**/*.map
13 changes: 11 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
# Changelog

## Unreleased
## v0.3.0

- Automatically download a checksum-verified Dexter binary from GitHub releases when one is not already installed
- Check extension-managed binaries for updates daily without modifying system installations
- Prefer an explicitly configured binary, then a Dexter installation on `PATH`, before using the extension-managed binary
- Respect global and combined-language `editor.formatOnSave` settings
- Respect global and combined-language `editor.formatOnSave` settings — the extension no longer forces format on save off for Elixir
- Best-effort support for a Windows `dexter.binary`; automatic installation stays unavailable there
- Added the **Dexter: Restart Language Server** command to the Command Palette
- Changing a Dexter setting now offers a restart, and a restart applies the new settings
- `dexter.binary` accepts a `~` path or a workspace-relative path, and gives a clear error when the binary is missing or is not executable
- Added the `dexter.maxTransientDocuments` setting

## v0.2.1

- Expanded the documented feature list to cover autocompletion, hover documentation, rename, signature help, workspace symbols, code actions, and call hierarchy

## v0.2.0

Expand Down
51 changes: 44 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,29 +1,66 @@
.PHONY: install build watch package install-vscode install-cursor install clean
.PHONY: install build watch test package package-openvsx install-vscode install-cursor install publish publish-vscode publish-openvsx release clean

install: install-cursor

install-deps:
# Reinstalls only when the lockfile is newer than the tree, so `npm ci` in CI is
# not followed by a redundant `npm install`.
node_modules: package-lock.json
npm install
@touch node_modules

build: install-deps
install-deps: node_modules

build: node_modules
npm run compile

watch: install-deps
watch: node_modules
npm run watch

test: node_modules
npm test

PKG_VERSION := $(shell node -p "require('./package.json').version")

# The two marketplaces use different publisher namespaces. A .vsix embeds its
# publisher, so each marketplace needs its own package.
PUBLISHER_VSCODE := remoteoss
PUBLISHER_OPENVSX := remote-com-oss

VSIX := dexter-lsp-$(PKG_VERSION).vsix
VSIX_OPENVSX := dexter-lsp-$(PKG_VERSION)-openvsx.vsix

package: build
npx @vscode/vsce package
npx @vscode/vsce package --out $(VSIX)

VSIX := dexter-lsp-$(shell node -p "require('./package.json').version").vsix
# Repackages with the Open VSX publisher, then always restores package.json.
package-openvsx: build
@set -e; \
trap 'npm pkg set publisher=$(PUBLISHER_VSCODE)' EXIT; \
npm pkg set publisher=$(PUBLISHER_OPENVSX); \
npx @vscode/vsce package --out $(VSIX_OPENVSX)

install-vscode: package
code --install-extension $(VSIX)

install-cursor: package
cursor --install-extension $(VSIX)

# Needs VSCE_PAT. Publishes to the VS Code Marketplace as $(PUBLISHER_VSCODE).
publish-vscode: package
npx @vscode/vsce publish --packagePath $(VSIX)

# Needs OVSX_PAT. Publishes to Open VSX (Cursor) as $(PUBLISHER_OPENVSX).
publish-openvsx: package-openvsx
npx ovsx publish $(VSIX_OPENVSX)

publish: publish-vscode publish-openvsx

release:
@if [ -z "$(VERSION)" ]; then echo "Usage: make release VERSION=0.2.0"; exit 1; fi
@if [ -z "$(VERSION)" ]; then echo "Usage: make release VERSION=0.3.0"; exit 1; fi
@if [ "$(VERSION)" != "$(PKG_VERSION)" ]; then \
echo "VERSION=$(VERSION) does not match package.json ($(PKG_VERSION)). Bump package.json first."; \
exit 1; \
fi
@git tag v$(VERSION)
@git push origin v$(VERSION)
@echo "Tagged and pushed v$(VERSION)"
Expand Down
74 changes: 65 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
- Autocompletion with snippet support across aliases, imports, and `use` injections
- Hover documentation for `@doc`, `@moduledoc`, `@typedoc`, and `@spec`
- Near-instant format on save, including support for any formatter plugins your project has configured, like Styler
- Syntax highlighting for Elixir, EEx, HEEx, and LiveBook
- Syntax highlighting for Elixir, EEx, HEEx, and Livebook
- Monorepo-aware with automatic reindexing on git branch switches

See the [Dexter repo](https://github.com/remoteoss/dexter) for the full feature list.
Expand All @@ -34,44 +34,100 @@ Dexter stores its project index in `.dexter/`. The directory manages its own `.g

| Setting | Default | Description |
|---------|---------|-------------|
| `dexter.binary` | `"dexter"` | Path to the dexter binary |
| `dexter.binary` | `"dexter"` | Path to the dexter binary, or a command name to find on `PATH`. Accepts `~` and workspace-relative paths |
| `dexter.autoInstall` | `true` | Download Dexter into extension storage when it is not installed |
| `dexter.autoUpdate` | `true` | Keep the extension-managed Dexter binary up to date |
| `dexter.followDelegates` | `true` | Follow `defdelegate` to the target function definition |
| `dexter.maxTransientDocuments` | `50` | Buffers the server keeps for files the editor never opened. `0` disables caching |
| `dexter.stdlibPath` | `""` | Path to the Elixir stdlib `lib/` directory. Auto-detected if not set |
| `dexter.debug` | `false` | Enable verbose LSP logging (view with **Output → Dexter**) |

To enable format on save globally:
### Format on save

The extension does not change your format-on-save settings. To turn format on save on
globally:

```json
{
"editor.formatOnSave": true
}
```

Or enable it only for Dexter-supported languages:
Or turn it on only for the languages Dexter supports:

```json
{
"[elixir][phoenix-heex]": { "editor.formatOnSave": true }
}
```

If another Elixir extension is installed, set Dexter as the default formatter. The
extension ID is different in each editor:

```json
// VS Code
{
"[elixir]": { "editor.defaultFormatter": "remoteoss.dexter-lsp" }
}

// Cursor
{
"[elixir]": { "editor.defaultFormatter": "remote-com-oss.dexter-lsp" }
}
```

Dexter settings are read when the language server starts. After you change one, the
extension offers to restart the server. You can also restart it yourself from the
Command Palette.

## Commands

| Command | Description |
|---------|-------------|
| **Dexter: Restart Language Server** | Restarts the language server and applies the current settings. Use it after an update, or if the server stops responding |

## Development

```sh
git clone https://github.com/remoteoss/dexter-vscode.git
cd dexter-vscode
make install # installs to Cursor by default, or: make install-vscode
make test # runs the unit tests
```

The tests cover binary resolution, checksum verification, and the release asset
mapping. They stub the `vscode` module, so they run under plain Node and need no
editor. GitHub Actions runs them on every pull request.

### Releasing

1. Create a release branch, bump the version in `package.json`, and update `CHANGELOG.md`
2. Merge the branch into `main`
3. Tag and push:
GitHub Actions builds and packages the extension, but the two marketplaces are
published by hand. The marketplaces use different publisher namespaces, so each one
needs its own package:

| Editor | Marketplace | Extension ID |
|--------|-------------|--------------|
| VS Code | Visual Studio Marketplace | `remoteoss.dexter-lsp` |
| Cursor | Open VSX | `remote-com-oss.dexter-lsp` |

1. Create a release branch. Bump the version in `package.json` and add a `CHANGELOG.md`
entry with a `## v<version>` heading.
2. Merge the branch into `main`, then check out `main`.
3. Tag and push. The tag must match the version in `package.json`:
```sh
make release VERSION=0.3.0
```
The `Release` workflow then builds both packages and creates the GitHub release,
using that version's `CHANGELOG.md` section as the release notes. It fails if the
tag and `package.json` disagree, or if the changelog section is missing.
4. Publish to both marketplaces:
```sh
make release VERSION=0.2.0
export VSCE_PAT=... # Visual Studio Marketplace token
export OVSX_PAT=... # Open VSX token
make publish
```
Or publish to one at a time with `make publish-vscode` and `make publish-openvsx`.

CI will pick up the tag and publish the extension automatically.
To build the packages without publishing, run `make package` and `make package-openvsx`.
`make package-openvsx` sets the Open VSX publisher, builds the package, then restores
`package.json`.
Loading
Loading