Skip to content

Commit e4bf006

Browse files
PHPCraftdreamclaude
andcommitted
editor 0.5.0 — spec/ktav 0.5.0 sync, highlighting parity, icon, build-only release pipeline
Sync vscode/lsp/intellij to spec 0.5.0 and ktav 0.5.0. Highlighting parity (VS Code + IntelliJ): - inline bracket matching, whole-string selection, `##` line comments - IntelliJ native lexer rewrite (## comments, inline tokenization, COMMA); fresh lexer per getHighlightingLexer() call (a shared mutable lexer made colours flicker) - bare array-item line is one scalar to EOL — `a, b` is one string (commas separate items only inline) and `hello{world` / IPs like `127.0.0.1` keep one string highlight; key-vs-item decided by `:` only - a line beginning with `{`/`[` is an inline-compound array item, tokenised structurally (was mis-read as `key: value`) - numbers require a well-formed form (≤1 dot / ≤1 exponent) so `127.0.0.1` and versions are strings, not floats - distinct value-type palette across all IDEs: strings #1FB0FF, numbers #2563EB, booleans #C26A12, null #B11A1A, keys #333333. LSP gains a dedicated `null` semantic-token type (was lumped with booleans as keyword); IntelliJ ships matching Default/Darcula colour schemes; VS Code grammar splits boolean/null scopes - plugin icon Dual-license MIT OR Apache-2.0 across the repo (LICENSE-MIT + LICENSE-APACHE, README en/ru/zh, CONTRIBUTING en/ru/zh, manifest SPDX). LSP test suite brought to spec 0.5.0: drop typed-scalar / inline-forbidden fixtures, re-pin error wording, point the conformance corpus at spec/versions/0.5. cargo fmt applied. release.yml: a tag push BUILDS ONLY (cross-platform artifacts → GH Release, no registry publish). Registry publishes (crates.io / VS Code Marketplace / Open VSX / JetBrains) run ONLY on a manual workflow_dispatch with publish=true, so the same tag can be re-run unchanged once tokens are configured. Each publish is gated on its token and marked continue-on-error. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent fd431b7 commit e4bf006

50 files changed

Lines changed: 2415 additions & 408 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release.yml

Lines changed: 100 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,22 @@ name: Release
66
# notes from CHANGELOG.md). Each subproject's publish step is gated
77
# on its own verify step.
88
#
9-
# Required secrets (set per subproject's environment):
9+
# Build vs. publish: the build/package steps always run and produce
10+
# universal artifacts — a fat VSIX bundling all 6 platform LSP binaries
11+
# and a single IntelliJ plugin zip that loads on every JetBrains IDE on
12+
# every OS. Publishing is OFF for tag pushes — a `git push origin v*`
13+
# only builds artifacts and attaches them to the GH Release. Registry
14+
# publishes run ONLY on a manual `workflow_dispatch` with `publish: true`
15+
# (re-run the same tag once tokens are configured, version unchanged).
16+
# Even then each publish is BEST-EFFORT: skipped when its token is unset
17+
# and marked `continue-on-error`, so a missing token, an Open VSX read-
18+
# only window, or a pending JetBrains first-upload moderation never
19+
# blocks the run or the artifact upload.
20+
#
21+
# Optional secrets (set per subproject's environment). Absent → that
22+
# registry publish is skipped, artifacts still ship to the GH Release:
1023
# • crates-io → CARGO_REGISTRY_TOKEN
11-
# • npm-vscode → VSCE_PAT, OVSX_PAT
24+
# • npm-vscode → VSCE_PAT (VS Code Marketplace), OVSX_PAT (Open VSX)
1225
# • intellij → INTELLIJ_PUBLISH_TOKEN
1326

1427
on:
@@ -18,8 +31,12 @@ on:
1831
workflow_dispatch:
1932
inputs:
2033
tag:
21-
description: "Tag to publish (e.g. v0.1.0). Must already exist."
34+
description: "Tag to build/publish (e.g. v0.1.0). Must already exist."
2235
required: true
36+
publish:
37+
description: "Publish to registries (crates.io / Marketplace / Open VSX / JetBrains). Tag pushes NEVER publish — they only build artifacts."
38+
type: boolean
39+
default: true
2340

2441
permissions:
2542
contents: read
@@ -75,6 +92,10 @@ jobs:
7592
needs: [verify-versions, lsp-binaries]
7693
runs-on: ubuntu-latest
7794
environment: crates-io
95+
env:
96+
# Job-level so the publish step's `if:` can detect whether the token
97+
# is configured (secrets are only visible to `if:` via the env context).
98+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
7899
defaults:
79100
run:
80101
working-directory: lsp
@@ -90,8 +111,12 @@ jobs:
90111
- run: cargo clippy --release --all-targets -- -D warnings
91112
- run: cargo test --release
92113
- name: cargo publish
93-
env:
94-
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
114+
# Publishes only on a manual dispatch with publish=true; tag pushes
115+
# build only. Best-effort: skip without a token, and don't fail the
116+
# run if this version was already published. fmt/clippy/test above
117+
# still gate the build, so a genuinely broken crate blocks the run.
118+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish && env.CARGO_REGISTRY_TOKEN != '' }}
119+
continue-on-error: true
95120
run: cargo publish
96121

97122
# ------------------------------------------------------------------
@@ -183,6 +208,11 @@ jobs:
183208
needs: [verify-versions, lsp-binaries]
184209
runs-on: ubuntu-latest
185210
environment: npm-vscode
211+
env:
212+
# Job-level so each publish step's `if:` can detect whether the token
213+
# is configured (secrets reach `if:` only through the env context).
214+
VSCE_PAT: ${{ secrets.VSCE_PAT }}
215+
OVSX_PAT: ${{ secrets.OVSX_PAT }}
186216
defaults:
187217
run:
188218
working-directory: vscode
@@ -202,14 +232,25 @@ jobs:
202232
- name: Organize binaries
203233
shell: bash
204234
run: |
205-
mkdir -p ../vscode/bin/{linux-x64,linux-arm64,darwin-x64,darwin-arm64,win32-x64,win32-arm64}
206-
[ -d "binaries/ktav-lsp-linux-amd64" ] && cp binaries/ktav-lsp-linux-amd64/ktav-lsp ../vscode/bin/linux-x64/
207-
[ -d "binaries/ktav-lsp-linux-arm64" ] && cp binaries/ktav-lsp-linux-arm64/ktav-lsp ../vscode/bin/linux-arm64/
208-
[ -d "binaries/ktav-lsp-darwin-amd64" ] && cp binaries/ktav-lsp-darwin-amd64/ktav-lsp ../vscode/bin/darwin-x64/
209-
[ -d "binaries/ktav-lsp-darwin-arm64" ] && cp binaries/ktav-lsp-darwin-arm64/ktav-lsp ../vscode/bin/darwin-arm64/
210-
[ -d "binaries/ktav-lsp-windows-amd64.exe" ] && cp binaries/ktav-lsp-windows-amd64.exe/ktav-lsp.exe ../vscode/bin/win32-x64/
211-
[ -d "binaries/ktav-lsp-windows-arm64.exe" ] && cp binaries/ktav-lsp-windows-arm64.exe/ktav-lsp.exe ../vscode/bin/win32-arm64/
212-
ls -lhR ../vscode/bin/
235+
# `download-artifact` placed the artifacts at $GITHUB_WORKSPACE/binaries
236+
# (workspace-root relative — NOT relative to this step's vscode
237+
# working-directory). Each artifact dir holds ONE file named after the
238+
# asset (lsp-binaries stages it as `$asset`, not `ktav-lsp`). Copy each
239+
# into the platform dir the extension probes, renamed to `ktav-lsp[.exe]`.
240+
# Absolute $GITHUB_WORKSPACE paths avoid any cwd ambiguity; no `[ -d ]`
241+
# guards so a missing binary fails the release loudly instead of
242+
# silently shipping a partial (Windows-only) VSIX.
243+
B="$GITHUB_WORKSPACE/binaries"
244+
D="$GITHUB_WORKSPACE/vscode/bin"
245+
mkdir -p "$D"/{linux-x64,linux-arm64,darwin-x64,darwin-arm64,win32-x64,win32-arm64}
246+
cp "$B/ktav-lsp-linux-amd64/ktav-lsp-linux-amd64" "$D/linux-x64/ktav-lsp"
247+
cp "$B/ktav-lsp-linux-arm64/ktav-lsp-linux-arm64" "$D/linux-arm64/ktav-lsp"
248+
cp "$B/ktav-lsp-darwin-amd64/ktav-lsp-darwin-amd64" "$D/darwin-x64/ktav-lsp"
249+
cp "$B/ktav-lsp-darwin-arm64/ktav-lsp-darwin-arm64" "$D/darwin-arm64/ktav-lsp"
250+
cp "$B/ktav-lsp-windows-amd64.exe/ktav-lsp-windows-amd64.exe" "$D/win32-x64/ktav-lsp.exe"
251+
cp "$B/ktav-lsp-windows-arm64.exe/ktav-lsp-windows-arm64.exe" "$D/win32-arm64/ktav-lsp.exe"
252+
chmod +x "$D/linux-x64/ktav-lsp" "$D/linux-arm64/ktav-lsp" "$D/darwin-x64/ktav-lsp" "$D/darwin-arm64/ktav-lsp"
253+
ls -lhR "$D"
213254
214255
- uses: actions/setup-node@v6
215256
with:
@@ -227,13 +268,25 @@ jobs:
227268
- name: Package .vsix
228269
run: npx vsce package --no-dependencies
229270
- name: Publish to VS Code Marketplace
230-
env:
231-
VSCE_PAT: ${{ secrets.VSCE_PAT }}
271+
# Publishes only on a manual dispatch with publish=true; tag pushes
272+
# build only. The Marketplace PAT requires an Azure DevOps org (behind
273+
# an Azure subscription wall) — when VSCE_PAT is unset the step skips
274+
# and the fat VSIX still ships as a GH Release artifact for manual
275+
# upload. continue-on-error keeps a failed publish from blocking the run.
276+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish && env.VSCE_PAT != '' }}
277+
continue-on-error: true
232278
run: npx vsce publish --no-dependencies --pat "$VSCE_PAT"
233279
- name: Publish to Open VSX
234-
env:
235-
OVSX_PAT: ${{ secrets.OVSX_PAT }}
280+
# Publishes only on a manual dispatch with publish=true; tag pushes
281+
# build only. Skipped when OVSX_PAT is unset. continue-on-error so an
282+
# Open VSX read-only maintenance window, or a namespace not yet
283+
# created, doesn't fail the run — re-run later with
284+
# `ovsx publish ktav-<ver>.vsix --pat <token>` (no rebuild needed).
285+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish && env.OVSX_PAT != '' }}
286+
continue-on-error: true
236287
run: npx ovsx publish --pat "$OVSX_PAT" *.vsix
288+
# The universal VSIX always ships, regardless of whether either publish
289+
# ran — this is the artifact for manual Marketplace / Open VSX upload.
237290
- uses: actions/upload-artifact@v5
238291
with:
239292
name: vscode-vsix
@@ -248,6 +301,10 @@ jobs:
248301
needs: [verify-versions, lsp-binaries]
249302
runs-on: ubuntu-latest
250303
environment: intellij
304+
env:
305+
# Job-level so the publish step's `if:` can detect whether the token
306+
# is configured (secrets reach `if:` only through the env context).
307+
INTELLIJ_PUBLISH_TOKEN: ${{ secrets.INTELLIJ_PUBLISH_TOKEN }}
251308
defaults:
252309
run:
253310
working-directory: intellij
@@ -267,14 +324,21 @@ jobs:
267324
- name: Organize binaries
268325
shell: bash
269326
run: |
270-
mkdir -p ../intellij/bin/{linux-x64,linux-arm64,darwin-x64,darwin-arm64,win32-x64,win32-arm64}
271-
[ -d "binaries/ktav-lsp-linux-amd64" ] && cp binaries/ktav-lsp-linux-amd64/ktav-lsp ../intellij/bin/linux-x64/
272-
[ -d "binaries/ktav-lsp-linux-arm64" ] && cp binaries/ktav-lsp-linux-arm64/ktav-lsp ../intellij/bin/linux-arm64/
273-
[ -d "binaries/ktav-lsp-darwin-amd64" ] && cp binaries/ktav-lsp-darwin-amd64/ktav-lsp ../intellij/bin/darwin-x64/
274-
[ -d "binaries/ktav-lsp-darwin-arm64" ] && cp binaries/ktav-lsp-darwin-arm64/ktav-lsp ../intellij/bin/darwin-arm64/
275-
[ -d "binaries/ktav-lsp-windows-amd64.exe" ] && cp binaries/ktav-lsp-windows-amd64.exe/ktav-lsp.exe ../intellij/bin/win32-x64/
276-
[ -d "binaries/ktav-lsp-windows-arm64.exe" ] && cp binaries/ktav-lsp-windows-arm64.exe/ktav-lsp.exe ../intellij/bin/win32-arm64/
277-
ls -lhR ../intellij/bin/
327+
# Same as vscode-publish: artifacts live at $GITHUB_WORKSPACE/binaries
328+
# (workspace-root relative), each dir holding one file named after the
329+
# asset. Copy into the per-platform dir as `ktav-lsp[.exe]`. Absolute
330+
# paths avoid cwd ambiguity; fail loudly on any missing binary.
331+
B="$GITHUB_WORKSPACE/binaries"
332+
D="$GITHUB_WORKSPACE/intellij/bin"
333+
mkdir -p "$D"/{linux-x64,linux-arm64,darwin-x64,darwin-arm64,win32-x64,win32-arm64}
334+
cp "$B/ktav-lsp-linux-amd64/ktav-lsp-linux-amd64" "$D/linux-x64/ktav-lsp"
335+
cp "$B/ktav-lsp-linux-arm64/ktav-lsp-linux-arm64" "$D/linux-arm64/ktav-lsp"
336+
cp "$B/ktav-lsp-darwin-amd64/ktav-lsp-darwin-amd64" "$D/darwin-x64/ktav-lsp"
337+
cp "$B/ktav-lsp-darwin-arm64/ktav-lsp-darwin-arm64" "$D/darwin-arm64/ktav-lsp"
338+
cp "$B/ktav-lsp-windows-amd64.exe/ktav-lsp-windows-amd64.exe" "$D/win32-x64/ktav-lsp.exe"
339+
cp "$B/ktav-lsp-windows-arm64.exe/ktav-lsp-windows-arm64.exe" "$D/win32-arm64/ktav-lsp.exe"
340+
chmod +x "$D/linux-x64/ktav-lsp" "$D/linux-arm64/ktav-lsp" "$D/darwin-x64/ktav-lsp" "$D/darwin-arm64/ktav-lsp"
341+
ls -lhR "$D"
278342
279343
- uses: actions/setup-java@v5
280344
with:
@@ -283,9 +347,18 @@ jobs:
283347
- uses: gradle/actions/setup-gradle@v4
284348
- run: ./gradlew test verifyPlugin buildPlugin --no-daemon
285349
- name: Publish to JetBrains Marketplace
286-
env:
287-
INTELLIJ_PUBLISH_TOKEN: ${{ secrets.INTELLIJ_PUBLISH_TOKEN }}
350+
# Publishes only on a manual dispatch with publish=true; tag pushes
351+
# build only. The FIRST version must be uploaded manually via
352+
# https://plugins.jetbrains.com/plugin/add and pass moderation before
353+
# token publishing works. Skipped when the token is unset, and
354+
# continue-on-error so a rejected/blocked publishPlugin doesn't fail
355+
# the run — the universal plugin zip ships as a GH Release artifact
356+
# for that manual first upload.
357+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish && env.INTELLIJ_PUBLISH_TOKEN != '' }}
358+
continue-on-error: true
288359
run: ./gradlew publishPlugin --no-daemon
360+
# The universal plugin zip (loads on all JetBrains IDEs / all OSes,
361+
# bundling every platform LSP binary) always ships.
289362
- uses: actions/upload-artifact@v5
290363
with:
291364
name: intellij-zip

CONTRIBUTING.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Contributing to ktav-lang/editor
2+
3+
**Languages:** **English** · [Русский](CONTRIBUTING.ru.md) · [简体中文](CONTRIBUTING.zh.md)
4+
5+
## Core rules
6+
7+
### 1. Every bug fix ships with a regression test
8+
9+
When you find a bug, **before fixing it**, write a test that reproduces
10+
it — the test **must fail on `main`** and pass after the fix. Include
11+
both in the same PR.
12+
13+
### 2. Don't reinvent the format in the editor layer
14+
15+
Editor extensions and the LSP are thin consumers of the `ktav` parser
16+
crate. Format behaviour belongs in the Rust crate
17+
([`ktav-lang/rust`](https://github.com/ktav-lang/rust)) — changing it
18+
there updates every consumer at once. Only **editor-specific
19+
ergonomics** (TextMate scopes, LSP feature wiring, IDE-specific
20+
integrations) belong in this repo.
21+
22+
If your change requires a format change, start a discussion in
23+
[`ktav-lang/spec`](https://github.com/ktav-lang/spec) first.
24+
25+
### 3. One concept per commit
26+
27+
Commits should be atomic: a bug fix and its test together, a feature
28+
and its tests together, a rename on its own, a refactor on its own.
29+
`git log --oneline` should read like a changelog. Don't prefix commit
30+
messages with `feat:` / `fix:` — no conventional commits here.
31+
32+
## Dev setup
33+
34+
Each subproject has its own toolchain. See the README in each:
35+
36+
- `grammars/` — pure JSON; no build
37+
- `vscode/` — Node + `vsce`
38+
- `intellij/` — JDK 17 + Gradle
39+
- `lsp/` — Rust 1.70+
40+
41+
## Language policy
42+
43+
This repo participates in the org-wide three-language policy (EN / RU /
44+
ZH). Every prose file lives in three parallel versions — see
45+
[`ktav-lang/.github/AGENTS.md`](https://github.com/ktav-lang/.github/blob/main/AGENTS.md)
46+
for the naming convention and the "update all three in one commit"
47+
rule.
48+
49+
### License of contributions
50+
51+
Unless you explicitly state otherwise, any contribution intentionally
52+
submitted for inclusion in this project by you, as defined in the
53+
Apache-2.0 license, shall be dual-licensed as **MIT OR Apache-2.0**,
54+
without any additional terms or conditions.

CONTRIBUTING.ru.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Вклад в ktav-lang/editor
2+
3+
**Языки:** [English](CONTRIBUTING.md) · **Русский** · [简体中文](CONTRIBUTING.zh.md)
4+
5+
## Основные правила
6+
7+
### 1. Каждый багфикс сопровождается регрессионным тестом
8+
9+
Когда вы нашли баг, **до исправления** напишите тест, который его
10+
воспроизводит — он **должен падать на `main`** и проходить после
11+
фикса. Оба — в одном PR.
12+
13+
### 2. Не изобретайте формат на уровне редактора
14+
15+
Расширения редакторов и LSP — тонкие потребители крейта-парсера `ktav`.
16+
Поведение формата принадлежит Rust-крейту
17+
([`ktav-lang/rust`](https://github.com/ktav-lang/rust)) — правки там
18+
обновляют всех потребителей одновременно. В этот репозиторий идёт только
19+
**эргономика, специфичная для редакторов** (TextMate-скоупы, обвязка
20+
LSP-фич, интеграции с конкретными IDE).
21+
22+
Если ваше изменение требует правки формата — начните с обсуждения в
23+
[`ktav-lang/spec`](https://github.com/ktav-lang/spec).
24+
25+
### 3. Один концепт — один коммит
26+
27+
Коммиты атомарны: фикс вместе с тестом, фича вместе с тестами,
28+
переименование — отдельно, рефакторинг — отдельно. `git log --oneline`
29+
должен читаться как changelog. Без `feat:` / `fix:` префиксов.
30+
31+
## Dev-окружение
32+
33+
Каждый подпроект — свой toolchain. См. README в каждом:
34+
35+
- `grammars/` — чистый JSON; без build'а
36+
- `vscode/` — Node + `vsce`
37+
- `intellij/` — JDK 17 + Gradle
38+
- `lsp/` — Rust 1.70+
39+
40+
## Языковая политика
41+
42+
Репо участвует в трёхъязычной политике организации (EN / RU / ZH).
43+
Каждый prose-файл живёт в трёх параллельных версиях — см.
44+
[`ktav-lang/.github/AGENTS.md`](https://github.com/ktav-lang/.github/blob/main/AGENTS.md)
45+
про naming convention и правило "обновлять все три в одном коммите".
46+
47+
### Лицензия вкладов
48+
49+
Если вы явно не заявите иное, любой вклад, намеренно отправленный
50+
для включения в этот проект, в соответствии с определением лицензии
51+
Apache-2.0, будет лицензирован на условиях **MIT OR Apache-2.0** без
52+
каких-либо дополнительных условий или ограничений.

CONTRIBUTING.zh.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# 为 ktav-lang/editor 做贡献
2+
3+
**语言:** [English](CONTRIBUTING.md) · [Русский](CONTRIBUTING.ru.md) · **简体中文**
4+
5+
## 核心规则
6+
7+
### 1. 每个 bug 修复都伴随一个回归测试
8+
9+
发现 bug 时,**在修复之前** 先写一个复现它的测试 —— 测试在
10+
`main` 分支上 **必须失败**,修复之后才通过。两者放在同一个 PR。
11+
12+
### 2. 不要在编辑器层重新发明格式
13+
14+
编辑器扩展和 LSP 是 `ktav` 解析器 crate 的薄消费者。格式行为属于
15+
Rust crate
16+
([`ktav-lang/rust`](https://github.com/ktav-lang/rust)) —— 改那里
17+
等于同步更新所有消费者。这里仅收 **编辑器特定的人体工学**
18+
(TextMate scope、LSP 功能接线、IDE 特定集成)。
19+
20+
如果改动需要格式变更,先去
21+
[`ktav-lang/spec`](https://github.com/ktav-lang/spec) 讨论。
22+
23+
### 3. 一个概念一次提交
24+
25+
提交要保持原子:bug 修复与其测试一起、新功能与其测试一起、
26+
重命名单独、重构单独。`git log --oneline` 应当读起来像 changelog。
27+
不要使用 `feat:` / `fix:` 前缀。
28+
29+
## 开发环境
30+
31+
每个子项目都有自己的工具链。详见各子项目下的 `README.md`:
32+
33+
- `grammars/` —— 纯 JSON,无需构建
34+
- `vscode/` —— Node + `vsce`
35+
- `intellij/` —— JDK 17 + Gradle
36+
- `lsp/` —— Rust 1.70+
37+
38+
## 语言政策
39+
40+
本仓库参与组织级三语政策(EN / RU / ZH)。每份 prose 文档都有三种
41+
并行版本 —— 命名约定和"三份一并更新"规则见
42+
[`ktav-lang/.github/AGENTS.md`](https://github.com/ktav-lang/.github/blob/main/AGENTS.md)
43+
44+
### 贡献的许可
45+
46+
除非您另有明确声明,否则您有意提交以纳入本项目的任何贡献(按
47+
Apache-2.0 许可证中的定义),均按 **MIT OR Apache-2.0** 双重许可,
48+
不附加任何额外条款或条件。

0 commit comments

Comments
 (0)