Skip to content

Commit 08d06dd

Browse files
committed
WIP
1 parent 3388ef8 commit 08d06dd

File tree

3 files changed

+94
-8
lines changed

3 files changed

+94
-8
lines changed

vscode/src/sorbet.ts

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import * as vscode from "vscode";
2+
import {
3+
LanguageClient,
4+
ServerOptions,
5+
LanguageClientOptions,
6+
RevealOutputChannelOn,
7+
} from "vscode-languageclient/node";
8+
9+
import { WorkspaceChannel } from "./workspaceChannel";
10+
import { Ruby } from "./ruby";
11+
12+
// Experimental Sorbet client to be used along with the Ruby LSP
13+
// TODO required to move forward:
14+
// - Before starting the Sorbet client
15+
// - we need to check if the Sorbet extension is installed
16+
// - we need to check if sorbet/config exists
17+
//
18+
// TODO later:
19+
// - Automatic restarts when sorbet/config changes
20+
// - Allow starting, stopping and restarting the Sorbet client separately
21+
// - Allow automatic restarts to target a specific client (so that we don't have to restart Sorbet on a rubocop.yml
22+
// change)
23+
// - Report Sorbet status (have the server send WorkDoneProgress notifications instead of using a custom built status
24+
// bar)
25+
export default class SorbetClient extends LanguageClient {
26+
constructor(
27+
ruby: Ruby,
28+
workspaceFolder: vscode.WorkspaceFolder,
29+
outputChannel: WorkspaceChannel,
30+
) {
31+
const serverOptions: ServerOptions = {
32+
command: "bundle",
33+
args: ["exec", "srb", "tc", "--lsp"],
34+
options: {
35+
cwd: workspaceFolder.uri.fsPath,
36+
env: ruby.env,
37+
shell: true,
38+
},
39+
};
40+
41+
const clientOptions: LanguageClientOptions = {
42+
documentSelector: [
43+
{ language: "ruby", pattern: `${workspaceFolder.uri.fsPath}/**/*` },
44+
],
45+
workspaceFolder,
46+
diagnosticCollectionName: "sorbet",
47+
outputChannel,
48+
revealOutputChannelOn: RevealOutputChannelOn.Never,
49+
};
50+
51+
super("sorbet", serverOptions, clientOptions);
52+
}
53+
}

vscode/src/workspace.ts

+35-8
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import {
1010
STATUS_EMITTER,
1111
debounce,
1212
} from "./common";
13-
import { WorkspaceChannel } from "./workspaceChannel";
13+
import { SorbetWorkspaceChannel, WorkspaceChannel } from "./workspaceChannel";
14+
import SorbetClient from "./sorbet";
1415

1516
export class Workspace implements WorkspaceInterface {
1617
public lspClient?: Client;
@@ -22,6 +23,7 @@ export class Workspace implements WorkspaceInterface {
2223
private readonly isMainWorkspace: boolean;
2324
private readonly telemetry: vscode.TelemetryLogger;
2425
private needsRestart = false;
26+
private sorbetClient?: SorbetClient;
2527
#rebaseInProgress = false;
2628
#error = false;
2729

@@ -96,6 +98,10 @@ export class Workspace implements WorkspaceInterface {
9698
await this.lspClient.stop();
9799
await this.lspClient.dispose();
98100
}
101+
if (this.sorbetClient) {
102+
await this.sorbetClient.stop();
103+
await this.sorbetClient.dispose();
104+
}
99105

100106
this.lspClient = new Client(
101107
this.context,
@@ -106,11 +112,17 @@ export class Workspace implements WorkspaceInterface {
106112
this.outputChannel,
107113
this.isMainWorkspace,
108114
);
115+
this.sorbetClient = new SorbetClient(
116+
this.ruby,
117+
this.workspaceFolder,
118+
new SorbetWorkspaceChannel(this.workspaceFolder.name, LOG_CHANNEL),
119+
);
109120

110121
try {
111122
STATUS_EMITTER.fire(this);
112123
await this.lspClient.start();
113124
await this.lspClient.afterStart();
125+
await this.sorbetClient.start();
114126
STATUS_EMITTER.fire(this);
115127

116128
// If something triggered a restart while we were still booting, then now we need to perform the restart since the
@@ -126,7 +138,19 @@ export class Workspace implements WorkspaceInterface {
126138
}
127139

128140
async stop() {
129-
await this.lspClient?.stop();
141+
try {
142+
await this.lspClient?.stop();
143+
} catch (error: any) {
144+
this.outputChannel.error(`Error stopping the Ruby LSP: ${error.message}`);
145+
}
146+
147+
try {
148+
await this.sorbetClient?.stop();
149+
} catch (error: any) {
150+
this.outputChannel.error(
151+
`Error stopping the Sorbet server: ${error.message}`,
152+
);
153+
}
130154
}
131155

132156
async restart() {
@@ -138,28 +162,30 @@ export class Workspace implements WorkspaceInterface {
138162
this.error = false;
139163

140164
// If there's no client, then we can just start a new one
141-
if (!this.lspClient) {
165+
if (!this.lspClient && !this.sorbetClient) {
142166
return this.start();
143167
}
144168

145-
switch (this.lspClient.state) {
169+
switch (this.lspClient!.state) {
146170
// If the server is still starting, then it may not be ready to handle a shutdown request yet. Trying to send
147-
// one could lead to a hanging process. Instead we set a flag and only restart once the server finished booting
148-
// in `start`
171+
// one could lead to a hanging process. Instead we set a flag and only restart once the server finished
172+
// booting in `start`
149173
case State.Starting:
150174
this.needsRestart = true;
151175
break;
152176
// If the server is running, we want to stop it, dispose of the client and start a new one
153177
case State.Running:
154178
await this.stop();
155-
await this.lspClient.dispose();
179+
await this.dispose();
156180
this.lspClient = undefined;
181+
this.sorbetClient = undefined;
157182
await this.start();
158183
break;
159184
// If the server is already stopped, then we need to dispose it and start a new one
160185
case State.Stopped:
161-
await this.lspClient.dispose();
186+
await this.dispose();
162187
this.lspClient = undefined;
188+
this.sorbetClient = undefined;
163189
await this.start();
164190
break;
165191
}
@@ -171,6 +197,7 @@ export class Workspace implements WorkspaceInterface {
171197

172198
async dispose() {
173199
await this.lspClient?.dispose();
200+
await this.sorbetClient?.dispose();
174201
}
175202

176203
// Install or update the `ruby-lsp` gem globally with `gem install ruby-lsp` or `gem update ruby-lsp`. We only try to

vscode/src/workspaceChannel.ts

+6
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,9 @@ export class WorkspaceChannel implements vscode.LogOutputChannel {
7373
this.actualChannel.dispose();
7474
}
7575
}
76+
77+
export class SorbetWorkspaceChannel extends WorkspaceChannel {
78+
constructor(workspaceName: string, actualChannel: vscode.LogOutputChannel) {
79+
super(`${workspaceName} [Sorbet]`, actualChannel);
80+
}
81+
}

0 commit comments

Comments
 (0)