Skip to content

Commit 3cf6388

Browse files
committed
Add Project Context status item
1 parent 2bacb5c commit 3cf6388

File tree

5 files changed

+118
-0
lines changed

5 files changed

+118
-0
lines changed

l10n/bundle.l10n.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@
161161
"Fix All: ": "Fix All: ",
162162
"C# Workspace Status": "C# Workspace Status",
163163
"Open solution": "Open solution",
164+
"C# Project Context Status": "C# Project Context Status",
165+
"Project Context": "Project Context",
164166
"Pick a fix all scope": "Pick a fix all scope",
165167
"Fix All Code Action": "Fix All Code Action",
166168
"pipeArgs must be a string or a string array type": "pipeArgs must be a string or a string array type",

src/lsptoolshost/languageStatusBar.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export function registerLanguageStatusItems(
1919
if (!getCSharpDevKit()) {
2020
WorkspaceStatus.createStatusItem(context, languageServerEvents);
2121
}
22+
ProjectContextStatus.createStatusItem(context, languageServer, languageServerEvents);
2223
}
2324

2425
class WorkspaceStatus {
@@ -40,3 +41,43 @@ class WorkspaceStatus {
4041
});
4142
}
4243
}
44+
45+
class ProjectContextStatus {
46+
static createStatusItem(
47+
context: vscode.ExtensionContext,
48+
languageServer: RoslynLanguageServer,
49+
languageServerEvents: RoslynLanguageServerEvents
50+
) {
51+
const projectContextService = languageServer._projectContextService;
52+
53+
const item = vscode.languages.createLanguageStatusItem(
54+
'csharp.projectContextStatus',
55+
languageServerOptions.documentSelector
56+
);
57+
item.name = vscode.l10n.t('C# Project Context Status');
58+
item.detail = vscode.l10n.t('Project Context');
59+
context.subscriptions.push(item);
60+
61+
updateItem(vscode.window.activeTextEditor);
62+
context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(updateItem));
63+
64+
languageServerEvents.onServerStateChange((e) => {
65+
if (e.state === ServerState.ProjectInitializationComplete) {
66+
projectContextService.clear();
67+
updateItem(vscode.window.activeTextEditor);
68+
}
69+
});
70+
71+
async function updateItem(e: vscode.TextEditor | undefined) {
72+
if (e?.document.languageId !== 'csharp') {
73+
item.text = '';
74+
return;
75+
}
76+
77+
const projectContext = await projectContextService.getCurrentProjectContext(e.document.uri);
78+
if (projectContext) {
79+
item.text = projectContext._vs_label;
80+
}
81+
}
82+
}
83+
}

src/lsptoolshost/roslynLanguageServer.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ import { BuildDiagnosticsService } from './buildDiagnosticsService';
6565
import { getComponentPaths } from './builtInComponents';
6666
import { OnAutoInsertFeature } from './onAutoInsertFeature';
6767
import { registerLanguageStatusItems } from './languageStatusBar';
68+
import { ProjectContextService } from './services/projectContextService';
6869

6970
let _channel: vscode.OutputChannel;
7071
let _traceChannel: vscode.OutputChannel;
@@ -106,6 +107,7 @@ export class RoslynLanguageServer {
106107
public readonly _onAutoInsertFeature: OnAutoInsertFeature;
107108

108109
public _buildDiagnosticService: BuildDiagnosticsService;
110+
public _projectContextService: ProjectContextService;
109111

110112
constructor(
111113
private _languageClient: RoslynLanguageClient,
@@ -125,6 +127,8 @@ export class RoslynLanguageServer {
125127
this._buildDiagnosticService = new BuildDiagnosticsService(diagnosticsReportedByBuild);
126128
this.registerDocumentOpenForDiagnostics();
127129

130+
this._projectContextService = new ProjectContextService(this);
131+
128132
// Register Razor dynamic file info handling
129133
this.registerDynamicFileInfo();
130134

src/lsptoolshost/roslynProtocol.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,21 @@ import * as lsp from 'vscode-languageserver-protocol';
88
import { CodeAction, TextDocumentRegistrationOptions } from 'vscode-languageserver-protocol';
99
import { ProjectConfigurationMessage } from '../shared/projectConfiguration';
1010

11+
export interface VSProjectContextList {
12+
_vs_projectContexts: VSProjectContext[];
13+
_vs_defaultIndex: number;
14+
}
15+
16+
export interface VSProjectContext {
17+
_vs_label: string;
18+
_vs_id: string;
19+
_vs_kind: string;
20+
}
21+
22+
export interface VSTextDocumentIdentifier extends lsp.TextDocumentIdentifier {
23+
_vs_projectContext: VSProjectContext | undefined;
24+
}
25+
1126
export interface WorkspaceDebugConfigurationParams {
1227
/**
1328
* Workspace path containing the solution/projects to get debug information for.
@@ -88,6 +103,13 @@ export interface RegisterSolutionSnapshotResponseItem {
88103
id: lsp.integer;
89104
}
90105

106+
export interface VSGetProjectContextParams {
107+
/**
108+
* The document the project context is being requested for.
109+
*/
110+
_vs_textDocument: lsp.TextDocumentIdentifier;
111+
}
112+
91113
export interface RunTestsParams extends lsp.WorkDoneProgressParams, lsp.PartialResultParams {
92114
/**
93115
* The text document containing the tests to run.
@@ -210,6 +232,12 @@ export namespace RegisterSolutionSnapshotRequest {
210232
export const type = new lsp.RequestType0<RegisterSolutionSnapshotResponseItem, void>(method);
211233
}
212234

235+
export namespace VSGetProjectContextsRequest {
236+
export const method = 'textDocument/_vs_getProjectContexts';
237+
export const messageDirection: lsp.MessageDirection = lsp.MessageDirection.clientToServer;
238+
export const type = new lsp.RequestType<VSGetProjectContextParams, VSProjectContextList, void>(method);
239+
}
240+
213241
export namespace ProjectInitializationCompleteNotification {
214242
export const method = 'workspace/projectInitializationComplete';
215243
export const messageDirection: lsp.MessageDirection = lsp.MessageDirection.serverToClient;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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 { VSGetProjectContextsRequest, VSProjectContext, VSProjectContextList } from '../roslynProtocol';
9+
import { TextDocumentIdentifier } from 'vscode-languageserver-protocol';
10+
import { UriConverter } from '../uriConverter';
11+
12+
export class ProjectContextService {
13+
/** Track the project contexts for a particular document uri. */
14+
private _projectContexts: { [uri: string]: Promise<VSProjectContextList> | VSProjectContextList } = {};
15+
16+
constructor(private languageServer: RoslynLanguageServer) {}
17+
18+
clear() {
19+
this._projectContexts = {};
20+
}
21+
22+
async getCurrentProjectContext(uri: string | vscode.Uri): Promise<VSProjectContext | undefined> {
23+
const projectContexts = await this.getProjectContexts(uri);
24+
return projectContexts?._vs_projectContexts[projectContexts._vs_defaultIndex];
25+
}
26+
27+
async getProjectContexts(uri: string | vscode.Uri): Promise<VSProjectContextList | undefined> {
28+
const uriString = uri instanceof vscode.Uri ? UriConverter.serialize(uri) : uri;
29+
30+
if (!(uriString in this._projectContexts)) {
31+
const source = new vscode.CancellationTokenSource();
32+
this._projectContexts[uriString] = this.languageServer
33+
.sendRequest(
34+
VSGetProjectContextsRequest.type,
35+
{ _vs_textDocument: TextDocumentIdentifier.create(uriString) },
36+
source.token
37+
)
38+
.then((contextList) => (this._projectContexts[uriString] = contextList));
39+
}
40+
41+
return this._projectContexts[uriString];
42+
}
43+
}

0 commit comments

Comments
 (0)