From 4359b88e265a958b70681049be87cdb45fe5dd38 Mon Sep 17 00:00:00 2001 From: Mucheen <145200703+Mucheen@users.noreply.github.com> Date: Thu, 22 Oct 2026 22:39:14 +0800 Subject: [PATCH 1/2] refactor: select Cargo through shared executable candidates --- README.md | 16 ++++++++++++---- .../backend/main.mjs | 2 +- io.github.lithe-idea.cargo-build/plugin.json | 10 ++++++---- sdk.lock.json | 2 +- test/core.test.mjs | 4 ++-- test/integration.test.mjs | 10 +++++----- 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index c54cbd2..c005a8c 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,10 @@ Cargo is a community build plugin for Lithe. It uses Lithe's native Cargo tool window and Build Output to build, check, test, clean, and run Rust projects. -**0.1.1 is a preview release.** Native disk-installation and full UI acceptance +**0.1.2 is unreleased preview source.** Native disk-installation and full UI acceptance are still pending. Automated integration and host compatibility run in this repository's CI. -The plugin requires a Lithe preview with API 3 `buildSystems: 2`, `settings: 2`, +The plugin requires a Lithe preview with API 3 `buildSystems: 1`, `executableResolution: 1`, `settings: 2`, `buildProviders: 1` and `serverProcess: 1`. Windows is not supported yet. ## Install @@ -15,7 +15,9 @@ Install Rust/Cargo 1.70+ and Node.js 20.3+ first. Node runs the metadata provide Cargo and rust-analyzer are not bundled. Existing Rust language intelligence continues to use Lithe's Rust language service. -Download `cargo-build-0.1.1-darwin.zip` from [Releases](https://github.com/Lithe-IDEA/lithe-plugin-cargo/releases). +For this branch, build `dist/cargo-build-0.1.2-darwin.zip` with `node scripts/package.mjs`. +The published 0.1.1 preview remains available from [Releases](https://github.com/Lithe-IDEA/lithe-plugin-cargo/releases) +and keeps its older host requirements. In Lithe, choose Settings → Plugins → Install from Disk, select the ZIP, review Cargo/Node and its permissions, and restart. Enable Cargo, open the Cargo workspace root, then open the Cargo tool window and load the project model. @@ -32,7 +34,7 @@ same executable. A missing, non-executable or too-old selection fails visibly instead of silently choosing a different Cargo installation. The executable's parent directory is placed first on PATH for companion tools. -Version 0.1.1 requires a preview host with `buildSystems: 2` and `settings: 2`. +Version 0.1.2 requires a preview host with `buildSystems: 1`, `executableResolution: 1` and `settings: 2`. Its exact tested host revision is recorded in `sdk.lock.json`; older hosts keep using the compatible 0.1.0 release through the Store. Existing published ZIPs are immutable and are never replaced. @@ -137,3 +139,9 @@ Published ZIP bytes are immutable: fixes require a new version. The Store index records the repository URL, API requirements, release URL and archive SHA-256. First inclusion and pre-releases use a reviewed Store pull request. + +The 0.1.2 source migrates custom Cargo selection to the shared ordered executable +candidates. Published 0.1.0/0.1.1 preview archives remain immutable. A compatible +host must advertise `executableResolution: 1`; the setting is a candidate ahead +of automatic PATH discovery, with empty values skipped and explicit failures +reported by the host. Maven/Gradle-style automatic candidates need no path setting. diff --git a/io.github.lithe-idea.cargo-build/backend/main.mjs b/io.github.lithe-idea.cargo-build/backend/main.mjs index 5184b39..2547799 100644 --- a/io.github.lithe-idea.cargo-build/backend/main.mjs +++ b/io.github.lithe-idea.cargo-build/backend/main.mjs @@ -2,6 +2,6 @@ import { createBackend, PluginError } from './vendor/lithe-plugin-sdk/index.mjs'; import { registerCargoProvider } from './provider.mjs'; -const backend = createBackend({ name: 'cargo-build', version: '0.1.1' }); +const backend = createBackend({ name: 'cargo-build', version: '0.1.2' }); registerCargoProvider(backend, PluginError); await backend.listen(); diff --git a/io.github.lithe-idea.cargo-build/plugin.json b/io.github.lithe-idea.cargo-build/plugin.json index b2ebca3..e5a15d4 100644 --- a/io.github.lithe-idea.cargo-build/plugin.json +++ b/io.github.lithe-idea.cargo-build/plugin.json @@ -2,9 +2,9 @@ "schemaVersion": 2, "id": "io.github.lithe-idea.cargo-build", "displayName": "Cargo", - "version": "0.1.1", + "version": "0.1.2", "pluginAPIVersion": 3, - "requires": { "buildProviders": 1, "buildSystems": 2, "serverProcess": 1, "settings": 2 }, + "requires": { "buildProviders": 1, "buildSystems": 1, "executableResolution": 1, "serverProcess": 1, "settings": 2 }, "vendor": { "id": "io.github.lithe-idea", "displayName": "Lithe Community", "signatureRequirement": "none" }, "permissions": ["languageServer.launch", "process.build"], "activationEvents": ["onBuildSystem:cargo"], @@ -21,8 +21,10 @@ "displayName": "Cargo", "detection": { "markers": ["Cargo.toml"], "nesting": "outermost" }, "invocation": { - "executableSetting": "cargoPath", - "executables": [{ "kind": "command", "command": "cargo" }], + "executables": [ + { "id": "selected", "kind": "setting", "settingID": "cargoPath" }, + { "kind": "command", "command": "cargo" } + ], "globalArguments": ["--color", "never"], "version": { "arguments": ["--version"], "pattern": "cargo (\\d+\\.\\d+\\.\\d+)" }, "minimumVersion": "1.70" diff --git a/sdk.lock.json b/sdk.lock.json index 2ed76ea..2bcdead 100644 --- a/sdk.lock.json +++ b/sdk.lock.json @@ -2,7 +2,7 @@ "schemaVersion": 1, "source": { "repository": "https://github.com/1lck/Lithe-IDEA", - "revision": "a972d4204ce4c178d0314872119c11db8d435341" + "revision": "5bac51971ad5d1da6b460748c30bdd5c83912e00" }, "files": [ { diff --git a/test/core.test.mjs b/test/core.test.mjs index 76cc4c8..c8a3143 100644 --- a/test/core.test.mjs +++ b/test/core.test.mjs @@ -7,12 +7,12 @@ import { build, core, integrationSkip, workspace } from './support/core.mjs'; test('Core validates the distributable manifest and requires a provider-capable host', { timeout: 15000, skip: integrationSkip }, async () => { const manifest = JSON.parse(await readFile(join(repository, 'io.github.lithe-idea.cargo-build/plugin.json'), 'utf8')); - const hostCapabilities = { buildSystems: [1, 2], buildProviders: [1], serverProcess: [1], settings: [1, 2] }; + const hostCapabilities = { buildSystems: [1, 2], buildProviders: [1], serverProcess: [1], settings: [1, 2], executableResolution: [1] }; assert.equal((await core('plugins.declarative.validate', { manifest, hostCapabilities })).status, 'ok'); const review = await core('plugins.marketplace.installReview', { manifest, hostCapabilities }); assert.equal(review.status, 'ok'); for (const kind of ['runtimeBuildProvider', 'buildSystem']) assert.ok(review.review.programs.some((item) => item.kind === kind)); - const oldHost = await core('plugins.declarative.validate', { manifest, hostCapabilities: { ...hostCapabilities, buildSystems: [1] } }); + const oldHost = await core('plugins.declarative.validate', { manifest, hostCapabilities: { ...hostCapabilities, executableResolution: [] } }); assert.equal(oldHost.error.code, 'plugin.api.unsupported'); const unsupported = await core('plugins.declarative.validate', { manifest, hostCapabilities: { buildSystems: [1], serverProcess: [1] } }); assert.equal(unsupported.error.code, 'plugin.api.unsupported'); diff --git a/test/integration.test.mjs b/test/integration.test.mjs index 142daa8..249f6dd 100644 --- a/test/integration.test.mjs +++ b/test/integration.test.mjs @@ -46,10 +46,10 @@ test('packaged provider loads a real Cargo workspace; build/test/run/clean leave const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`; await writeFile(tool, `#!/bin/sh\nprintf '%s\\n' "$1" >> ${quote(calls)}\nexec ${quote(discovered.stdout.trim())} "$@"\n`, { mode: 0o755 }); const configured = await build('build.invocationPlan', { root: '.', platform: 'macos', settings: { cargoPath: tool } }); - assert.equal(configured.invocation.configuredExecutable, tool); + assert.equal(configured.invocation.executables[0].path, tool); const automatic = await build('build.invocationPlan', { root: '.', platform: 'macos', settings: { cargoPath: '' } }); - assert.equal(automatic.invocation.configuredExecutable, undefined); - assert.deepEqual(automatic.invocation.executables, [{ kind: 'command', command: 'cargo' }]); + assert.equal(automatic.invocation.executables[0].path, null); + assert.deepEqual(automatic.invocation.executables, [{ kind: 'setting', settingID: 'cargoPath', path: null }, { kind: 'command', command: 'cargo' }]); const built = await buildPackage(join(scratch, 'packages')); const baseline = await snapshot(built.directory); const backend = spawn(process.execPath, [join(built.directory, 'backend/main.mjs')], { @@ -62,7 +62,7 @@ test('packaged provider loads a real Cargo workspace; build/test/run/clean leave }); const initialized = await host.initialize({ litheBuild: { versions: [1] } }, pathToFileURL(root).href + '/'); assert.equal(initialized.result.capabilities.experimental.litheBuild.version, 1); - const modelPlan = await build('build.modelPlan', { root: '.', options: { offline: true }, tool: { executable: configured.invocation.configuredExecutable } }); + const modelPlan = await build('build.modelPlan', { root: '.', options: { offline: true }, tool: { executable: configured.invocation.executables[0].path } }); const loaded = await host.request(modelPlan.plan.provider.method, modelPlan.plan.provider.params); assert.equal(loaded.error, undefined, JSON.stringify(loaded.error)); assert.deepEqual(loaded.result, { format: 'litheBuildModel', version: 1, ...JSON.parse(await readFile(join(here, 'fixtures/model.json'))) }); @@ -74,7 +74,7 @@ test('packaged provider loads a real Cargo workspace; build/test/run/clean leave // separately hand-written Cargo command lines in this integration test. const cargo = async (command, request) => { const { plan } = await build(command, { root: '.', options, ...request }); - return runProcess(configured.invocation.configuredExecutable, plan.arguments, { + return runProcess(configured.invocation.executables[0].path, plan.arguments, { cwd: join(root, plan.workingDirectory), env: { ...process.env, ...plan.environment, CARGO_TARGET_DIR: join(scratch, 'target') }, signal: AbortSignal.timeout(20000), maxOutputBytes: 1024 * 1024 }); From 56501c58aff4408f6e19b6c20ecb19adc5e93d11 Mon Sep 17 00:00:00 2001 From: Mucheen <145200703+Mucheen@users.noreply.github.com> Date: Thu, 22 Oct 2026 22:45:18 +0800 Subject: [PATCH 2/2] test: pin merged preview host for candidate compatibility --- sdk.lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk.lock.json b/sdk.lock.json index 2bcdead..5cadbc8 100644 --- a/sdk.lock.json +++ b/sdk.lock.json @@ -2,7 +2,7 @@ "schemaVersion": 1, "source": { "repository": "https://github.com/1lck/Lithe-IDEA", - "revision": "5bac51971ad5d1da6b460748c30bdd5c83912e00" + "revision": "d06d5bf9f41729de1051e7f73c1c10648bc3a691" }, "files": [ {