internal: Properly handle language configuration config changes

This commit is contained in:
Lukas Wirth 2022-10-20 21:12:58 +02:00
parent f3cce5feea
commit a8e0a20ce4
3 changed files with 88 additions and 80 deletions

View file

@ -11,13 +11,9 @@ export type RunnableEnvCfg =
export class Config {
readonly extensionId = "rust-lang.rust-analyzer";
configureLang: vscode.Disposable | undefined;
readonly rootSection = "rust-analyzer";
private readonly requiresWorkspaceReloadOpts = [
// FIXME: This shouldn't be here, changing this setting should reload
// `continueCommentsOnNewline` behavior without restart
"typing",
].map((opt) => `${this.rootSection}.${opt}`);
private readonly requiresReloadOpts = [
"cargo",
"procMacro",
@ -25,9 +21,7 @@ export class Config {
"server",
"files",
"lens", // works as lens.*
]
.map((opt) => `${this.rootSection}.${opt}`)
.concat(this.requiresWorkspaceReloadOpts);
].map((opt) => `${this.rootSection}.${opt}`);
readonly package: {
version: string;
@ -45,6 +39,11 @@ export class Config {
ctx.subscriptions
);
this.refreshLogging();
this.configureLanguage();
}
dispose() {
this.configureLang?.dispose();
}
private refreshLogging() {
@ -58,34 +57,87 @@ export class Config {
private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) {
this.refreshLogging();
this.configureLanguage();
const requiresReloadOpt = this.requiresReloadOpts.find((opt) =>
event.affectsConfiguration(opt)
);
if (!requiresReloadOpt) return;
const requiresWorkspaceReloadOpt = this.requiresWorkspaceReloadOpts.find((opt) =>
event.affectsConfiguration(opt)
);
if (!requiresWorkspaceReloadOpt && this.restartServerOnConfigChange) {
if (this.restartServerOnConfigChange) {
await vscode.commands.executeCommand("rust-analyzer.reload");
return;
}
const message = requiresWorkspaceReloadOpt
? `Changing "${requiresWorkspaceReloadOpt}" requires a window reload`
: `Changing "${requiresReloadOpt}" requires a reload`;
const userResponse = await vscode.window.showInformationMessage(message, "Reload now");
const message = `Changing "${requiresReloadOpt}" requires a server restart`;
const userResponse = await vscode.window.showInformationMessage(message, "Restart now");
if (userResponse === "Reload now") {
const command = requiresWorkspaceReloadOpt
? "workbench.action.reloadWindow"
: "rust-analyzer.reload";
if (userResponse === "Reload now") {
if (userResponse) {
const command = "rust-analyzer.reload";
await vscode.commands.executeCommand(command);
}
}
/**
* Sets up additional language configuration that's impossible to do via a
* separate language-configuration.json file. See [1] for more information.
*
* [1]: https://github.com/Microsoft/vscode/issues/11514#issuecomment-244707076
*/
private configureLanguage() {
if (this.typingContinueCommentsOnNewline && !this.configureLang) {
const indentAction = vscode.IndentAction.None;
this.configureLang = vscode.languages.setLanguageConfiguration("rust", {
onEnterRules: [
{
// Doc single-line comment
// e.g. ///|
beforeText: /^\s*\/{3}.*$/,
action: { indentAction, appendText: "/// " },
},
{
// Parent doc single-line comment
// e.g. //!|
beforeText: /^\s*\/{2}\!.*$/,
action: { indentAction, appendText: "//! " },
},
{
// Begins an auto-closed multi-line comment (standard or parent doc)
// e.g. /** | */ or /*! | */
beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
afterText: /^\s*\*\/$/,
action: {
indentAction: vscode.IndentAction.IndentOutdent,
appendText: " * ",
},
},
{
// Begins a multi-line comment (standard or parent doc)
// e.g. /** ...| or /*! ...|
beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
action: { indentAction, appendText: " * " },
},
{
// Continues a multi-line comment
// e.g. * ...|
beforeText: /^(\ \ )*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
action: { indentAction, appendText: "* " },
},
{
// Dedents after closing a multi-line comment
// e.g. */|
beforeText: /^(\ \ )*\ \*\/\s*$/,
action: { indentAction, removeText: 1 },
},
],
});
}
if (!this.typingContinueCommentsOnNewline && this.configureLang) {
this.configureLang.dispose();
this.configureLang = undefined;
}
}
// We don't do runtime config validation here for simplicity. More on stackoverflow:

View file

@ -38,6 +38,7 @@ export class Ctx {
this.dispose();
},
});
extCtx.subscriptions.push(this);
this.statusBar.text = "rust-analyzer";
this.statusBar.tooltip = "ready";
this.statusBar.command = "rust-analyzer.analyzerStatus";
@ -48,10 +49,15 @@ export class Ctx {
this.config = new Config(extCtx);
}
dispose() {
this.config.dispose();
}
clientFetcher() {
const self = this;
return {
get client(): lc.LanguageClient | undefined {
return this.client;
return self.client;
},
};
}

View file

@ -77,10 +77,6 @@ async function activateServer(ctx: Ctx): Promise<RustAnalyzerExtensionApi> {
await initCommonContext(ctx);
if (ctx.config.typingContinueCommentsOnNewline) {
ctx.pushExtCleanup(configureLanguage());
}
vscode.workspace.onDidChangeConfiguration(
async (_) => {
await ctx
@ -129,6 +125,11 @@ async function initCommonContext(ctx: Ctx) {
ctx.registerCommand("stopServer", (_) => async () => {
// FIXME: We should re-use the client, that is ctx.deactivate() if none of the configs have changed
await ctx.disposeClient();
ctx.setServerStatus({
health: "ok",
quiescent: true,
message: "server is not running",
});
});
ctx.registerCommand("analyzerStatus", commands.analyzerStatus);
ctx.registerCommand("memoryUsage", commands.memoryUsage);
@ -172,54 +173,3 @@ async function initCommonContext(ctx: Ctx) {
defaultOnEnter.dispose();
ctx.registerCommand("onEnter", commands.onEnter);
}
/**
* Sets up additional language configuration that's impossible to do via a
* separate language-configuration.json file. See [1] for more information.
*
* [1]: https://github.com/Microsoft/vscode/issues/11514#issuecomment-244707076
*/
function configureLanguage(): vscode.Disposable {
const indentAction = vscode.IndentAction.None;
return vscode.languages.setLanguageConfiguration("rust", {
onEnterRules: [
{
// Doc single-line comment
// e.g. ///|
beforeText: /^\s*\/{3}.*$/,
action: { indentAction, appendText: "/// " },
},
{
// Parent doc single-line comment
// e.g. //!|
beforeText: /^\s*\/{2}\!.*$/,
action: { indentAction, appendText: "//! " },
},
{
// Begins an auto-closed multi-line comment (standard or parent doc)
// e.g. /** | */ or /*! | */
beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
afterText: /^\s*\*\/$/,
action: { indentAction: vscode.IndentAction.IndentOutdent, appendText: " * " },
},
{
// Begins a multi-line comment (standard or parent doc)
// e.g. /** ...| or /*! ...|
beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
action: { indentAction, appendText: " * " },
},
{
// Continues a multi-line comment
// e.g. * ...|
beforeText: /^(\ \ )*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
action: { indentAction, appendText: "* " },
},
{
// Dedents after closing a multi-line comment
// e.g. */|
beforeText: /^(\ \ )*\ \*\/\s*$/,
action: { indentAction, removeText: 1 },
},
],
});
}