Skip to content

Commit 6ce956b

Browse files
authored
Merge pull request #7254 from dotnet/dev/jorobich/workspace-status-item
Add workspace status item to the Language Status bar.
2 parents b13a80d + 9e3ee21 commit 6ce956b

File tree

8 files changed

+97
-23
lines changed

8 files changed

+97
-23
lines changed

l10n/bundle.l10n.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@
144144
"Failed to run test: {0}": "Failed to run test: {0}",
145145
"Failed to start debugger: {0}": "Failed to start debugger: {0}",
146146
"Test run already in progress": "Test run already in progress",
147+
"Workspace projects": "Workspace projects",
147148
"Your workspace has multiple Visual Studio Solution files; please select one to get full IntelliSense.": "Your workspace has multiple Visual Studio Solution files; please select one to get full IntelliSense.",
148149
"Choose": "Choose",
149150
"Choose and set default": "Choose and set default",
@@ -158,6 +159,8 @@
158159
"C# configuration has changed. Would you like to reload the window to apply your changes?": "C# configuration has changed. Would you like to reload the window to apply your changes?",
159160
"Nested Code Action": "Nested Code Action",
160161
"Fix All: ": "Fix All: ",
162+
"C# Workspace Status": "C# Workspace Status",
163+
"Open solution": "Open solution",
161164
"Pick a fix all scope": "Pick a fix all scope",
162165
"Fix All Code Action": "Fix All Code Action",
163166
"pipeArgs must be a string or a string array type": "pipeArgs must be a string or a string array type",

src/lsptoolshost/debugger.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { IWorkspaceDebugInformationProvider } from '../shared/IWorkspaceDebugInf
1010
import { RoslynLanguageServer } from './roslynLanguageServer';
1111
import { RoslynWorkspaceDebugInformationProvider } from './roslynWorkspaceDebugConfigurationProvider';
1212
import { PlatformInformation } from '../shared/platform';
13-
import { ServerStateChange } from './serverStateChange';
13+
import { ServerState } from './serverStateChange';
1414
import { DotnetConfigurationResolver } from '../shared/dotnetConfigurationProvider';
1515
import { getCSharpDevKit } from '../utils/getCSharpDevKit';
1616
import { RoslynLanguageServerEvents } from './languageServerEvents';
@@ -25,8 +25,8 @@ export function registerDebugger(
2525
const workspaceInformationProvider: IWorkspaceDebugInformationProvider =
2626
new RoslynWorkspaceDebugInformationProvider(languageServer, csharpOutputChannel);
2727

28-
const disposable = languageServerEvents.onServerStateChange(async (state) => {
29-
if (state === ServerStateChange.ProjectInitializationComplete) {
28+
const disposable = languageServerEvents.onServerStateChange(async (e) => {
29+
if (e.state === ServerState.ProjectInitializationComplete) {
3030
const csharpDevkitExtension = getCSharpDevKit();
3131
if (!csharpDevkitExtension) {
3232
// Update or add tasks.json and launch.json

src/lsptoolshost/languageServerEvents.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import * as vscode from 'vscode';
7-
import { ServerStateChange } from './serverStateChange';
7+
import { ServerStateChangeEvent } from './serverStateChange';
88
import { IDisposable } from '../disposable';
99

1010
/**
1111
* Defines events that are fired by the language server.
1212
* These events can be consumed to wait for the server to reach a certain state.
1313
*/
1414
export interface LanguageServerEvents {
15-
readonly onServerStateChange: vscode.Event<ServerStateChange>;
15+
readonly onServerStateChange: vscode.Event<ServerStateChangeEvent>;
1616
}
1717

1818
/**
@@ -21,9 +21,9 @@ export interface LanguageServerEvents {
2121
* register for events without having to know about the specific current state of the language server.
2222
*/
2323
export class RoslynLanguageServerEvents implements LanguageServerEvents, IDisposable {
24-
public readonly onServerStateChangeEmitter = new vscode.EventEmitter<ServerStateChange>();
24+
public readonly onServerStateChangeEmitter = new vscode.EventEmitter<ServerStateChangeEvent>();
2525

26-
public get onServerStateChange(): vscode.Event<ServerStateChange> {
26+
public get onServerStateChange(): vscode.Event<ServerStateChangeEvent> {
2727
return this.onServerStateChangeEmitter.event;
2828
}
2929

src/lsptoolshost/languageStatusBar.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as vscode from 'vscode';
7+
import { RoslynLanguageServer } from './roslynLanguageServer';
8+
import { RoslynLanguageServerEvents } from './languageServerEvents';
9+
import { languageServerOptions } from '../shared/options';
10+
import { ServerState } from './serverStateChange';
11+
import { getCSharpDevKit } from '../utils/getCSharpDevKit';
12+
13+
export function registerLanguageStatusItems(
14+
context: vscode.ExtensionContext,
15+
languageServer: RoslynLanguageServer,
16+
languageServerEvents: RoslynLanguageServerEvents
17+
) {
18+
// DevKit will provide an equivalent workspace status item.
19+
if (!getCSharpDevKit()) {
20+
WorkspaceStatus.createStatusItem(context, languageServerEvents);
21+
}
22+
}
23+
24+
class WorkspaceStatus {
25+
static createStatusItem(context: vscode.ExtensionContext, languageServerEvents: RoslynLanguageServerEvents) {
26+
const item = vscode.languages.createLanguageStatusItem(
27+
'csharp.workspaceStatus',
28+
languageServerOptions.documentSelector
29+
);
30+
item.name = vscode.l10n.t('C# Workspace Status');
31+
item.command = {
32+
command: 'dotnet.openSolution',
33+
title: vscode.l10n.t('Open solution'),
34+
};
35+
context.subscriptions.push(item);
36+
37+
languageServerEvents.onServerStateChange((e) => {
38+
item.text = e.workspaceLabel;
39+
item.busy = e.state === ServerState.ProjectInitializationStarted;
40+
});
41+
}
42+
}

src/lsptoolshost/roslynLanguageServer.ts

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import ShowInformationMessage from '../shared/observers/utils/showInformationMes
3737
import * as RoslynProtocol from './roslynProtocol';
3838
import { CSharpDevKitExports } from '../csharpDevKitExports';
3939
import { SolutionSnapshotId } from './services/ISolutionSnapshotProvider';
40-
import { ServerStateChange } from './serverStateChange';
40+
import { ServerState } from './serverStateChange';
4141
import TelemetryReporter from '@vscode/extension-telemetry';
4242
import CSharpIntelliCodeExports from '../csharpIntelliCodeExports';
4343
import { csharpDevkitExtensionId, csharpDevkitIntelliCodeExtensionId, getCSharpDevKit } from '../utils/getCSharpDevKit';
@@ -64,6 +64,7 @@ import { registerRestoreCommands } from './restore';
6464
import { BuildDiagnosticsService } from './buildDiagnosticsService';
6565
import { getComponentPaths } from './builtInComponents';
6666
import { OnAutoInsertFeature } from './onAutoInsertFeature';
67+
import { registerLanguageStatusItems } from './languageStatusBar';
6768

6869
let _channel: vscode.OutputChannel;
6970
let _traceChannel: vscode.OutputChannel;
@@ -115,7 +116,7 @@ export class RoslynLanguageServer {
115116
) {
116117
this.registerSetTrace();
117118
this.registerSendOpenSolution();
118-
this.registerOnProjectInitializationComplete();
119+
this.registerProjectInitialization();
119120
this.registerReportProjectConfiguration();
120121
this.registerExtensionsChanged();
121122
this.registerTelemetryChanged();
@@ -157,14 +158,20 @@ export class RoslynLanguageServer {
157158
await this.openDefaultSolutionOrProjects();
158159
}
159160
await this.sendOrSubscribeForServiceBrokerConnection();
160-
this._languageServerEvents.onServerStateChangeEmitter.fire(ServerStateChange.Started);
161+
this._languageServerEvents.onServerStateChangeEmitter.fire({
162+
state: ServerState.Started,
163+
workspaceLabel: this.workspaceDisplayName(),
164+
});
161165
}
162166
});
163167
}
164168

165-
private registerOnProjectInitializationComplete() {
169+
private registerProjectInitialization() {
166170
this._languageClient.onNotification(RoslynProtocol.ProjectInitializationCompleteNotification.type, () => {
167-
this._languageServerEvents.onServerStateChangeEmitter.fire(ServerStateChange.ProjectInitializationComplete);
171+
this._languageServerEvents.onServerStateChangeEmitter.fire({
172+
state: ServerState.ProjectInitializationComplete,
173+
workspaceLabel: this.workspaceDisplayName(),
174+
});
168175
});
169176
}
170177

@@ -262,6 +269,16 @@ export class RoslynLanguageServer {
262269
await this._languageClient.restart();
263270
}
264271

272+
public workspaceDisplayName(): string {
273+
if (this._solutionFile !== undefined) {
274+
return path.basename(this._solutionFile.fsPath);
275+
} else if (this._projectFiles?.length > 0) {
276+
return vscode.l10n.t('Workspace projects');
277+
}
278+
279+
return '';
280+
}
281+
265282
/**
266283
* Returns whether or not the underlying LSP server is running or not.
267284
*/
@@ -379,16 +396,20 @@ export class RoslynLanguageServer {
379396
await this._languageClient.sendNotification(RoslynProtocol.OpenSolutionNotification.type, {
380397
solution: protocolUri,
381398
});
382-
}
383-
384-
if (this._projectFiles.length > 0) {
399+
} else if (this._projectFiles.length > 0) {
385400
const projectProtocolUris = this._projectFiles.map((uri) =>
386401
this._languageClient.clientOptions.uriConverters!.code2Protocol(uri)
387402
);
388403
await this._languageClient.sendNotification(RoslynProtocol.OpenProjectNotification.type, {
389404
projects: projectProtocolUris,
390405
});
406+
} else {
407+
return;
391408
}
409+
this._languageServerEvents.onServerStateChangeEmitter.fire({
410+
state: ServerState.ProjectInitializationStarted,
411+
workspaceLabel: this.workspaceDisplayName(),
412+
});
392413
}
393414
}
394415

@@ -979,6 +1000,8 @@ export async function activateRoslynLanguageServer(
9791000
languageServerEvents
9801001
);
9811002

1003+
registerLanguageStatusItems(context, languageServer, languageServerEvents);
1004+
9821005
// Register any commands that need to be handled by the extension.
9831006
registerCommands(context, languageServer, hostExecutableResolver, _channel);
9841007
registerNestedCodeActionCommands(context, languageServer, _channel);

src/lsptoolshost/serverStateChange.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
export enum ServerStateChange {
6+
export enum ServerState {
77
Started = 0,
8-
ProjectInitializationComplete = 1,
8+
ProjectInitializationStarted = 1,
9+
ProjectInitializationComplete = 2,
10+
}
11+
12+
export interface ServerStateChangeEvent {
13+
state: ServerState;
14+
workspaceLabel: string;
915
}

src/main.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import { RazorOmnisharpDownloader } from './razor/razorOmnisharpDownloader';
5252
import { RoslynLanguageServerExport } from './lsptoolshost/roslynLanguageServerExportChannel';
5353
import { registerOmnisharpOptionChanges } from './omnisharp/omnisharpOptionChanges';
5454
import { RoslynLanguageServerEvents } from './lsptoolshost/languageServerEvents';
55-
import { ServerStateChange } from './lsptoolshost/serverStateChange';
55+
import { ServerState } from './lsptoolshost/serverStateChange';
5656
import { SolutionSnapshotProvider } from './lsptoolshost/services/solutionSnapshotProvider';
5757
import { commonOptions, languageServerOptions, omnisharpOptions, razorOptions } from './shared/options';
5858
import { BuildResultDiagnostics } from './lsptoolshost/services/buildResultReporterService';
@@ -149,8 +149,8 @@ export async function activate(
149149

150150
// Setup a listener for project initialization complete before we start the server.
151151
projectInitializationCompletePromise = new Promise((resolve, _) => {
152-
roslynLanguageServerEvents.onServerStateChange(async (state) => {
153-
if (state === ServerStateChange.ProjectInitializationComplete) {
152+
roslynLanguageServerEvents.onServerStateChange(async (e) => {
153+
if (e.state === ServerState.ProjectInitializationComplete) {
154154
resolve();
155155
}
156156
});

test/integrationTests/integrationHelpers.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import * as vscode from 'vscode';
77
import * as path from 'path';
88
import { CSharpExtensionExports } from '../../src/csharpExtensionExports';
99
import { existsSync } from 'fs';
10-
import { ServerStateChange } from '../../src/lsptoolshost/serverStateChange';
10+
import { ServerState } from '../../src/lsptoolshost/serverStateChange';
1111
import testAssetWorkspace from './testAssets/testAssetWorkspace';
1212

1313
export async function activateCSharpExtension(): Promise<void> {
@@ -72,8 +72,8 @@ export async function restartLanguageServer(): Promise<void> {
7272
const csharpExtension = vscode.extensions.getExtension<CSharpExtensionExports>('ms-dotnettools.csharp');
7373
// Register to wait for initialization events and restart the server.
7474
const waitForInitialProjectLoad = new Promise<void>((resolve, _) => {
75-
csharpExtension!.exports.experimental.languageServerEvents.onServerStateChange(async (state) => {
76-
if (state === ServerStateChange.ProjectInitializationComplete) {
75+
csharpExtension!.exports.experimental.languageServerEvents.onServerStateChange(async (e) => {
76+
if (e.state === ServerState.ProjectInitializationComplete) {
7777
resolve();
7878
}
7979
});

0 commit comments

Comments
 (0)