Skip to content
This repository was archived by the owner on Nov 18, 2022. It is now read-only.

Commit faa0343

Browse files
authored
Merge pull request #220 from Xanewok/default-user-toolchain
Use local active toolchain as default for rust-client.channel
2 parents dfbfd7b + be6e9fb commit faa0343

File tree

4 files changed

+74
-5
lines changed

4 files changed

+74
-5
lines changed

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,11 @@
165165
"description": "Update the RLS whenever the extension starts up."
166166
},
167167
"rust-client.channel": {
168-
"type": "string",
169-
"default": "nightly",
168+
"type": [
169+
"string",
170+
"null"
171+
],
172+
"default": null,
170173
"description": "Rust channel to install RLS from."
171174
},
172175
"rust-client.rls-name": {

src/configuration.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import { workspace, WorkspaceConfiguration } from 'vscode';
1414
import { RevealOutputChannelOn } from 'vscode-languageclient';
1515

16+
import { getActiveChannel } from './rustup';
17+
1618
function fromStringToRevealOutputChannelOn(value: string): RevealOutputChannelOn {
1719
switch (value && value.toLowerCase()) {
1820
case 'info':
@@ -58,15 +60,38 @@ export class RLSConfiguration {
5860
this.revealOutputChannelOn = RLSConfiguration.readRevealOutputChannelOn(configuration);
5961
this.updateOnStartup = configuration.get<boolean>('rust-client.updateOnStartup', true);
6062

61-
this.channel = configuration.get('rust-client.channel', 'nightly');
63+
this.channel = RLSConfiguration.readChannel(this.rustupPath, configuration);
6264
this.componentName = configuration.get('rust-client.rls-name', 'rls');
6365

6466
// Hidden options that are not exposed to the user
6567
this.rlsPath = configuration.get('rls.path', null);
6668
this.rlsRoot = configuration.get('rls.root', null);
6769
}
70+
6871
private static readRevealOutputChannelOn(configuration: WorkspaceConfiguration) {
6972
const setting = configuration.get<string>('rust-client.revealOutputChannelOn', 'never');
7073
return fromStringToRevealOutputChannelOn(setting);
7174
}
75+
76+
/**
77+
* Tries to fetch the `rust-client.channel` configuration value. If missing,
78+
* falls back on active toolchain specified by rustup (at `rustupPath`),
79+
* finally defaulting to `nightly` if all fails.
80+
*/
81+
private static readChannel(rustupPath: string, configuration: WorkspaceConfiguration): string {
82+
const channel = configuration.get<string | null>('rust-client.channel', null);
83+
if (channel !== null) {
84+
return channel;
85+
} else {
86+
try {
87+
return getActiveChannel(rustupPath);
88+
}
89+
// rustup might not be installed at the time the configuration is
90+
// initially loaded, so silently ignore the error and return a default value
91+
catch (e) {
92+
return 'nightly';
93+
}
94+
95+
}
96+
}
7297
}

src/extension.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import { commands, ExtensionContext, IndentAction, languages, TextEditor,
2323
import { LanguageClient, LanguageClientOptions, Location, NotificationType,
2424
ServerOptions } from 'vscode-languageclient';
2525

26+
// FIXME(#233): Don't only rely on lazily initializing it once on startup,
27+
// handle possible `rust-client.*` value changes while extension is running
2628
export const CONFIGURATION = RLSConfiguration.loadFromWorkspace();
2729

2830
function getSysroot(env: Object): string | Error {

src/rustup.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
'use strict';
1212

1313
import * as child_process from 'child_process';
14-
import { window } from 'vscode';
14+
import { window, workspace } from 'vscode';
1515

1616
import { execChildProcess } from './utils/child_process';
1717
import { startSpinner, stopSpinner } from './spinner';
@@ -172,4 +172,43 @@ async function installRls(): Promise<void> {
172172
}
173173

174174
stopSpinner('RLS components installed successfully');
175-
}
175+
}
176+
177+
/**
178+
* Parses given output of `rustup show` and retrieves the local active toolchain.
179+
*/
180+
export function parseActiveToolchain(rustupOutput: string): string {
181+
// There may a default entry under 'installed toolchains' section, so search
182+
// for currently active/overridden one only under 'active toolchain' section
183+
const activeToolchainsIndex = rustupOutput.search('active toolchain');
184+
if (activeToolchainsIndex === -1) {
185+
throw new Error(`couldn't find active toolchains`);
186+
}
187+
188+
rustupOutput = rustupOutput.substr(activeToolchainsIndex);
189+
190+
const matchActiveChannel = new RegExp(/^(\S*) \((?:default|overridden)/gm);
191+
const match = matchActiveChannel.exec(rustupOutput);
192+
if (match === null) {
193+
throw new Error(`couldn't find active toolchain under 'active toolchains'`);
194+
} else if (match.length > 2) {
195+
throw new Error(`multiple active toolchains found under 'active toolchains'`);
196+
}
197+
198+
return match[1];
199+
}
200+
201+
/**
202+
* Returns active (including local overrides) toolchain, as specified by rustup.
203+
* May throw if rustup at specified path can't be executed.
204+
*/
205+
export function getActiveChannel(rustupPath: string, cwd = workspace.rootPath): string {
206+
// rustup info might differ depending on where it's executed
207+
// (e.g. when a toolchain is locally overriden), so executing it
208+
// under our current workspace root should give us close enough result
209+
const output = child_process.execSync(`${rustupPath} show`, {cwd: cwd}).toString();
210+
211+
const activeChannel = parseActiveToolchain(output);
212+
console.info(`Detected active channel: ${activeChannel} (since 'rust-client.channel' is unspecified)`);
213+
return activeChannel;
214+
}

0 commit comments

Comments
 (0)