-
Notifications
You must be signed in to change notification settings - Fork 63
Support experimental language server #1183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
a8ca9d8
8232a6d
57d9c7a
8f7860b
95b6153
c209e41
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| import * as path from "path"; | ||
| import * as fs from "fs"; | ||
| import { | ||
| workspace, | ||
| ExtensionContext, | ||
|
|
@@ -23,6 +24,7 @@ import { | |
| ServerOptions, | ||
| State, | ||
| TransportKind, | ||
| DidChangeConfigurationNotification, | ||
| } from "vscode-languageclient/node"; | ||
|
|
||
| import * as customCommands from "./commands"; | ||
|
|
@@ -90,6 +92,58 @@ export function activate(context: ExtensionContext) { | |
| "rescript", | ||
| ); | ||
|
|
||
| const useExperimentalServer = workspace | ||
| .getConfiguration("rescript") | ||
| .get<string | null>("experimentalServerPath", null); | ||
|
|
||
| function createExperimentalLanguageClient(serverPath: string) { | ||
| if (!fs.existsSync(serverPath)) { | ||
| const message = `The experimental server is enabled with \`experimentalServerPath\`, but no language server was found at ${serverPath}. See the instructions for using the experimental server in [ADD_LINK_TO_DOCS_HERE].`; | ||
| outputChannel.appendLine(message); | ||
| window.showErrorMessage(message); | ||
| outputChannel.show(); | ||
| throw new Error(message); | ||
| } | ||
|
|
||
| let serverOptions: ServerOptions = { | ||
| run: { | ||
| command: serverPath, | ||
| transport: TransportKind.stdio, | ||
| }, | ||
| debug: { | ||
| command: serverPath, | ||
| transport: TransportKind.stdio, | ||
| }, | ||
| }; | ||
|
|
||
| // Options to control the language client | ||
| let clientOptions: LanguageClientOptions = { | ||
| documentSelector: [{ scheme: "file", language: "rescript" }], | ||
| outputChannel, | ||
| markdown: { | ||
| isTrusted: true, | ||
| }, | ||
| middleware: { | ||
| workspace: { | ||
| configuration: async (_params, _token, _next) => { | ||
| // For the experimental server, we don't want to send the full configuration | ||
| // We send only setting inside rescript.settings, i.e, server settings | ||
| return [workspace.getConfiguration("rescript.settings")]; | ||
| }, | ||
| }, | ||
| }, | ||
|
Comment on lines
+126
to
+134
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we don't use middleware, the server will retrieve all fields within |
||
| }; | ||
|
|
||
| const client = new LanguageClient( | ||
| "ReScriptLSP", | ||
| "Experimental ReScript Language Server", | ||
| serverOptions, | ||
| clientOptions, | ||
| ); | ||
|
|
||
| return client; | ||
| } | ||
|
|
||
| function createLanguageClient() { | ||
| // The server is implemented in node | ||
| let serverModule = context.asAbsolutePath( | ||
|
|
@@ -143,36 +197,42 @@ export function activate(context: ExtensionContext) { | |
| clientOptions, | ||
| ); | ||
|
|
||
| // This sets up a listener that, if we're in code analysis mode, triggers | ||
| // code analysis as the LS server reports that ReScript compilation has | ||
| // finished. This is needed because code analysis must wait until | ||
| // compilation has finished, and the most reliable source for that is the LS | ||
| // server, that already keeps track of when the compiler finishes in order to | ||
| // other provide fresh diagnostics. | ||
| context.subscriptions.push( | ||
| client.onDidChangeState(({ newState }) => { | ||
| if (newState === State.Running) { | ||
| context.subscriptions.push( | ||
| client.onNotification("rescript/compilationFinished", () => { | ||
| if (inCodeAnalysisState.active === true) { | ||
| customCommands.codeAnalysisWithReanalyze( | ||
| diagnosticsCollection, | ||
| diagnosticsResultCodeActions, | ||
| outputChannel, | ||
| codeAnalysisRunningStatusBarItem, | ||
| ); | ||
| } | ||
| }), | ||
| ); | ||
| } | ||
| }), | ||
| ); | ||
|
|
||
| return client; | ||
| } | ||
|
|
||
| function createClient() { | ||
| return useExperimentalServer != null | ||
| ? createExperimentalLanguageClient(useExperimentalServer) | ||
| : createLanguageClient(); | ||
| } | ||
|
|
||
| // Create the language client and start the client. | ||
| client = createLanguageClient(); | ||
| client = createClient(); | ||
|
|
||
| // This sets up a listener that, if we're in code analysis mode, triggers | ||
| // code analysis as the LS server reports that ReScript compilation has | ||
| // finished. This is needed because code analysis must wait until | ||
| // compilation has finished, and the most reliable source for that is the LS | ||
| // server, that already keeps track of when the compiler finishes in order to | ||
| // other provide fresh diagnostics. | ||
| context.subscriptions.push( | ||
| client.onDidChangeState(({ newState }) => { | ||
| if (newState === State.Running) { | ||
| context.subscriptions.push( | ||
| client.onNotification("rescript/compilationFinished", () => { | ||
| if (inCodeAnalysisState.active === true) { | ||
| customCommands.codeAnalysisWithReanalyze( | ||
| diagnosticsCollection, | ||
| diagnosticsResultCodeActions, | ||
| outputChannel, | ||
| codeAnalysisRunningStatusBarItem, | ||
| ); | ||
| } | ||
| }), | ||
| ); | ||
| } | ||
| }), | ||
| ); | ||
|
|
||
| // Create a custom diagnostics collection, for cases where we want to report | ||
| // diagnostics programatically from inside of the extension. The reason this | ||
|
|
@@ -263,7 +323,7 @@ export function activate(context: ExtensionContext) { | |
| // Compact success display: project label plus a green check emoji | ||
| compilationStatusBarItem.text = `$(check) ReScript: Ok`; | ||
| compilationStatusBarItem.backgroundColor = undefined; | ||
| compilationStatusBarItem.color = null; | ||
| compilationStatusBarItem.color = undefined; | ||
| compilationStatusBarItem.command = undefined; | ||
| const projects = successes.map((e) => e.project).join(", "); | ||
| compilationStatusBarItem.tooltip = projects | ||
|
|
@@ -333,7 +393,7 @@ export function activate(context: ExtensionContext) { | |
| const removeAllCodeAction = new CodeAction("Remove all unused in file"); | ||
| const edit = new WorkspaceEdit(); | ||
| allRemoveActionEdits.forEach((subEdit) => { | ||
| subEdit.codeAction.edit.entries().forEach(([uri, [textEdit]]) => { | ||
| subEdit.codeAction.edit?.entries().forEach(([uri, [textEdit]]) => { | ||
| edit.replace(uri, textEdit.range, textEdit.newText); | ||
| }); | ||
| }); | ||
|
|
@@ -361,7 +421,7 @@ export function activate(context: ExtensionContext) { | |
|
|
||
| const document = editor.document; | ||
| const diagnostics = diagnosticsCollection.get(document.uri); | ||
| const newDiagnostics = diagnostics.filter((d) => d !== diagnostic); | ||
| const newDiagnostics = diagnostics?.filter((d) => d !== diagnostic); | ||
| diagnosticsCollection.set(document.uri, newDiagnostics); | ||
| }, | ||
| ); | ||
|
|
@@ -513,7 +573,7 @@ export function activate(context: ExtensionContext) { | |
|
|
||
| commands.registerCommand("rescript-vscode.restart_language_server", () => { | ||
| client.stop().then(() => { | ||
| client = createLanguageClient(); | ||
| client = createClient(); | ||
| client.start(); | ||
| }); | ||
| }); | ||
|
|
@@ -549,7 +609,9 @@ export function activate(context: ExtensionContext) { | |
| // Send a general message that configuration has updated. Clients | ||
| // interested can then pull the new configuration as they see fit. | ||
| client | ||
| .sendNotification("workspace/didChangeConfiguration") | ||
| .sendNotification(DidChangeConfigurationNotification.type, { | ||
| settings: null, | ||
| }) | ||
|
Comment on lines
+612
to
+614
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The notification This was breaking the experimental server. |
||
| .catch((err) => { | ||
| window.showErrorMessage(String(err)); | ||
| }); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove
See the instructions...