Skip to content

Commit aca3c30

Browse files
bors[bot]matklad
andauthored
Merge #3629
3629: Alternative aproach to plugin auto update r=matklad a=matklad This is very much WIP (as in, I haven't run this once), but I like the result so far. cc @Veetaha The primary focus here on simplification: * local simplification of data structures and control-flow: using union of strings instead of an enum, using unwrapped GitHub API responses * global simplification of control flow: all logic is now in `main.ts`, implemented as linear functions without abstractions. This is stateful side-effective code, so arguments from [Carmack](http://number-none.com/blow/john_carmack_on_inlined_code.html) very much apply. We need all user interractions, all mutations, and all network requests to happen in a single file. * as a side-effect of condensing everything to functions, we can get rid of various enums. The enums were basically a reified control flow: ``` enum E { A, B } fn foo() -> E { if cond { E::A } else { E::B } } fn bar(e: E) { match e { E::A => do_a(), E::B => do_b(), } } ==>> fn all() { if cond { do_a() } else { do_b() } } ``` * simplification of model: we don't need to reinstall on settings update, we can just ask the user to reload, we don't need to handle nightly=>stable fallback, we can ask the user to reinstall extension, (todo) we don't need to parse out the date from the version, we can use build id for nightly and for stable we can write the info directly into package.json. Co-authored-by: Aleksey Kladov <[email protected]>
2 parents 5533672 + fb6e655 commit aca3c30

File tree

13 files changed

+265
-691
lines changed

13 files changed

+265
-691
lines changed

.vscode/launch.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"request": "launch",
1717
"runtimeExecutable": "${execPath}",
1818
"args": [
19+
// "--user-data-dir=${workspaceFolder}/target/code",
1920
"--disable-extensions",
2021
"--extensionDevelopmentPath=${workspaceFolder}/editors/code"
2122
],

editors/code/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@
228228
"default": "stable",
229229
"markdownEnumDescriptions": [
230230
"`\"stable\"` updates are shipped weekly, they don't contain cutting-edge features from VSCode proposed APIs but have less bugs in general",
231-
"`\"nightly\"` updates are shipped daily, they contain cutting-edge features and latest bug fixes. These releases help us get your feedback very quickly and speed up rust-analyzer development **drastically**"
231+
"`\"nightly\"` updates are shipped daily (extension updates automatically by downloading artifacts directly from GitHub), they contain cutting-edge features and latest bug fixes. These releases help us get your feedback very quickly and speed up rust-analyzer development **drastically**"
232232
],
233233
"markdownDescription": "Choose `\"nightly\"` updates to get the latest features and bug fixes every day. While `\"stable\"` releases occur weekly and don't contain cutting-edge features from VSCode proposed APIs"
234234
},
Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,10 @@
1-
import * as vscode from 'vscode';
2-
import { ensureServerBinary } from '../installation/server';
1+
import * as vscode from "vscode";
2+
import { spawnSync } from "child_process";
33
import { Ctx, Cmd } from '../ctx';
4-
import { spawnSync } from 'child_process';
54

65
export function serverVersion(ctx: Ctx): Cmd {
76
return async () => {
8-
const binaryPath = await ensureServerBinary(ctx.config, ctx.state);
9-
10-
if (binaryPath == null) {
11-
throw new Error(
12-
"Rust Analyzer Language Server is not available. " +
13-
"Please, ensure its [proper installation](https://rust-analyzer.github.io/manual.html#installation)."
14-
);
15-
}
16-
17-
const version = spawnSync(binaryPath, ["--version"], { encoding: "utf8" }).stdout;
7+
const version = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" }).stdout;
188
vscode.window.showInformationMessage('rust-analyzer version : ' + version);
199
};
2010
}

editors/code/src/config.ts

Lines changed: 7 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
import * as os from "os";
21
import * as vscode from 'vscode';
3-
import { ArtifactSource } from "./installation/interfaces";
4-
import { log, vscodeReloadWindow } from "./util";
5-
6-
const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG;
2+
import { log } from "./util";
73

84
export interface InlayHintOptions {
95
typeHints: boolean;
@@ -25,10 +21,7 @@ export interface CargoFeatures {
2521
loadOutDirsFromCheck: boolean;
2622
}
2723

28-
export const enum UpdatesChannel {
29-
Stable = "stable",
30-
Nightly = "nightly"
31-
}
24+
export type UpdatesChannel = "stable" | "nightly";
3225

3326
export const NIGHTLY_TAG = "nightly";
3427
export class Config {
@@ -41,6 +34,7 @@ export class Config {
4134
"cargo-watch",
4235
"highlighting.semanticTokens",
4336
"inlayHints",
37+
"updates.channel",
4438
]
4539
.map(opt => `${this.rootSection}.${opt}`);
4640

@@ -94,100 +88,17 @@ export class Config {
9488
);
9589

9690
if (userResponse === "Reload now") {
97-
await vscodeReloadWindow();
91+
await vscode.commands.executeCommand("workbench.action.reloadWindow");
9892
}
9993
}
10094

101-
private static replaceTildeWithHomeDir(path: string) {
102-
if (path.startsWith("~/")) {
103-
return os.homedir() + path.slice("~".length);
104-
}
105-
return path;
106-
}
107-
108-
/**
109-
* Name of the binary artifact for `rust-analyzer` that is published for
110-
* `platform` on GitHub releases. (It is also stored under the same name when
111-
* downloaded by the extension).
112-
*/
113-
get prebuiltServerFileName(): null | string {
114-
// See possible `arch` values here:
115-
// https://nodejs.org/api/process.html#process_process_arch
116-
117-
switch (process.platform) {
118-
119-
case "linux": {
120-
switch (process.arch) {
121-
case "arm":
122-
case "arm64": return null;
123-
124-
default: return "rust-analyzer-linux";
125-
}
126-
}
127-
128-
case "darwin": return "rust-analyzer-mac";
129-
case "win32": return "rust-analyzer-windows.exe";
130-
131-
// Users on these platforms yet need to manually build from sources
132-
case "aix":
133-
case "android":
134-
case "freebsd":
135-
case "openbsd":
136-
case "sunos":
137-
case "cygwin":
138-
case "netbsd": return null;
139-
// The list of platforms is exhaustive (see `NodeJS.Platform` type definition)
140-
}
141-
}
142-
143-
get installedExtensionUpdateChannel(): UpdatesChannel {
144-
return this.extensionReleaseTag === NIGHTLY_TAG
145-
? UpdatesChannel.Nightly
146-
: UpdatesChannel.Stable;
147-
}
148-
149-
get serverSource(): null | ArtifactSource {
150-
const serverPath = RA_LSP_DEBUG ?? this.serverPath;
151-
152-
if (serverPath) {
153-
return {
154-
type: ArtifactSource.Type.ExplicitPath,
155-
path: Config.replaceTildeWithHomeDir(serverPath)
156-
};
157-
}
158-
159-
const prebuiltBinaryName = this.prebuiltServerFileName;
160-
161-
if (!prebuiltBinaryName) return null;
162-
163-
return this.createGithubReleaseSource(
164-
prebuiltBinaryName,
165-
this.extensionReleaseTag
166-
);
167-
}
168-
169-
private createGithubReleaseSource(file: string, tag: string): ArtifactSource.GithubRelease {
170-
return {
171-
type: ArtifactSource.Type.GithubRelease,
172-
file,
173-
tag,
174-
dir: this.ctx.globalStoragePath,
175-
repo: {
176-
name: "rust-analyzer",
177-
owner: "rust-analyzer",
178-
}
179-
};
180-
}
181-
182-
get nightlyVsixSource(): ArtifactSource.GithubRelease {
183-
return this.createGithubReleaseSource("rust-analyzer.vsix", NIGHTLY_TAG);
184-
}
95+
get globalStoragePath(): string { return this.ctx.globalStoragePath; }
18596

18697
// We don't do runtime config validation here for simplicity. More on stackoverflow:
18798
// https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension
18899

189-
private get serverPath() { return this.cfg.get("serverPath") as null | string; }
190-
get updatesChannel() { return this.cfg.get("updates.channel") as UpdatesChannel; }
100+
get serverPath() { return this.cfg.get("serverPath") as null | string; }
101+
get channel() { return this.cfg.get<"stable" | "nightly">("updates.channel")!; }
191102
get askBeforeDownload() { return this.cfg.get("updates.askBeforeDownload") as boolean; }
192103
get highlightingSemanticTokens() { return this.cfg.get("highlighting.semanticTokens") as boolean; }
193104
get highlightingOn() { return this.cfg.get("highlightingOn") as boolean; }

editors/code/src/ctx.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,20 @@ import * as lc from 'vscode-languageclient';
44
import { Config } from './config';
55
import { createClient } from './client';
66
import { isRustEditor, RustEditor } from './util';
7-
import { PersistentState } from './persistent_state';
87

98
export class Ctx {
109
private constructor(
1110
readonly config: Config,
12-
readonly state: PersistentState,
1311
private readonly extCtx: vscode.ExtensionContext,
14-
readonly client: lc.LanguageClient
12+
readonly client: lc.LanguageClient,
13+
readonly serverPath: string,
1514
) {
1615

1716
}
1817

19-
static async create(config: Config, state: PersistentState, extCtx: vscode.ExtensionContext, serverPath: string): Promise<Ctx> {
18+
static async create(config: Config, extCtx: vscode.ExtensionContext, serverPath: string): Promise<Ctx> {
2019
const client = await createClient(config, serverPath);
21-
const res = new Ctx(config, state, extCtx, client);
20+
const res = new Ctx(config, extCtx, client, serverPath);
2221
res.pushCleanup(client.start());
2322
await client.onReady();
2423
return res;

editors/code/src/installation/extension.ts

Lines changed: 0 additions & 146 deletions
This file was deleted.

0 commit comments

Comments
 (0)