Skip to content

Commit 85e960f

Browse files
Merge pull request #671 from ivanz/feature/view-assembly-metadata-165
Adds support for viewing type information for types not in the source
2 parents 1c06c9d + 083f208 commit 85e960f

File tree

6 files changed

+129
-17
lines changed

6 files changed

+129
-17
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { workspace, Uri, TextDocument, Disposable, TextDocumentContentProvider} from 'vscode';
2+
import { MetadataResponse } from '../omnisharp/protocol';
3+
4+
export class DefinitionMetadataDocumentProvider implements TextDocumentContentProvider, Disposable {
5+
private _scheme = "omnisharp-metadata";
6+
private _registration : Disposable;
7+
private _documents: Map<string, MetadataResponse>;
8+
private _documentClosedSubscription: Disposable;
9+
10+
constructor() {
11+
this._documents = new Map<string, MetadataResponse>();
12+
this._documentClosedSubscription = workspace.onDidCloseTextDocument(this.onTextDocumentClosed);
13+
}
14+
15+
private onTextDocumentClosed(document: TextDocument) : void {
16+
this._documents.delete(document.uri.toString());
17+
}
18+
19+
public dispose() : void {
20+
this._registration.dispose();
21+
this._documentClosedSubscription.dispose();
22+
this._documents.clear();
23+
}
24+
25+
public addMetadataResponse(metadataResponse: MetadataResponse) : Uri {
26+
const uri = this.createUri(metadataResponse);
27+
28+
this._documents.set(uri.toString(), metadataResponse);
29+
30+
return uri;
31+
}
32+
33+
public register() : void {
34+
this._registration = workspace.registerTextDocumentContentProvider(this._scheme, this);
35+
}
36+
37+
public provideTextDocumentContent(uri : Uri) : string {
38+
return this._documents.get(uri.toString()).Source;
39+
}
40+
41+
private createUri(metadataResponse: MetadataResponse) : Uri {
42+
return Uri.parse(this._scheme + "://" +
43+
metadataResponse.SourceName.replace(/\\/g, "/")
44+
.replace(/(.*)\/(.*)/g, "$1/[metadata] $2"));
45+
}
46+
}

src/features/definitionProvider.ts

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,49 @@
66
'use strict';
77

88
import AbstractSupport from './abstractProvider';
9+
import {MetadataRequest, GoToDefinitionRequest, MetadataSource} from '../omnisharp/protocol';
910
import * as serverUtils from '../omnisharp/utils';
1011
import {createRequest, toLocation} from '../omnisharp/typeConvertion';
11-
import {TextDocument, Position, Location, CancellationToken, DefinitionProvider} from 'vscode';
12+
import {Uri, TextDocument, Position, Location, CancellationToken, DefinitionProvider} from 'vscode';
13+
import {DefinitionMetadataDocumentProvider} from './definitionMetadataDocumentProvider';
14+
1215

1316
export default class CSharpDefinitionProvider extends AbstractSupport implements DefinitionProvider {
17+
private _definitionMetadataDocumentProvider: DefinitionMetadataDocumentProvider;
18+
19+
constructor(server, definitionMetadataDocumentProvider: DefinitionMetadataDocumentProvider) {
20+
super(server);
21+
this._definitionMetadataDocumentProvider = definitionMetadataDocumentProvider;
22+
}
1423

1524
public provideDefinition(document: TextDocument, position: Position, token: CancellationToken): Promise<Location> {
1625

17-
let req = createRequest(document, position);
26+
let req = <GoToDefinitionRequest>createRequest(document, position);
27+
req.WantMetadata = true;
28+
29+
return serverUtils.goToDefinition(this._server, req, token).then(gotoDefinitionResponse => {
30+
31+
if (gotoDefinitionResponse && gotoDefinitionResponse.FileName) {
32+
return toLocation(gotoDefinitionResponse);
33+
} else if (gotoDefinitionResponse.MetadataSource) {
34+
const metadataSource: MetadataSource = gotoDefinitionResponse.MetadataSource;
35+
36+
return serverUtils.getMetadata(this._server, <MetadataRequest> {
37+
Timeout: 5000,
38+
AssemblyName: metadataSource.AssemblyName,
39+
VersionNumber: metadataSource.VersionNumber,
40+
ProjectName: metadataSource.ProjectName,
41+
Language: metadataSource.Language,
42+
TypeName: metadataSource.TypeName
43+
}).then(metadataResponse => {
44+
if (!metadataResponse || !metadataResponse.Source || !metadataResponse.SourceName) {
45+
return;
46+
}
1847

19-
return serverUtils.goToDefinition(this._server, req, token).then(value => {
20-
if (value && value.FileName) {
21-
return toLocation(value);
22-
}
48+
const uri: Uri = this._definitionMetadataDocumentProvider.addMetadataResponse(metadataResponse);
49+
return new Location(uri, new Position(gotoDefinitionResponse.Line - 1, gotoDefinitionResponse.Column - 1));
50+
});
51+
}
2352
});
2453
}
2554
}

src/main.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ import * as coreclrdebug from './coreclr-debug/activate';
2626
import {addAssetsIfNecessary} from './assets';
2727
import * as vscode from 'vscode';
2828
import TelemetryReporter from 'vscode-extension-telemetry';
29+
import {DefinitionMetadataDocumentProvider} from './features/definitionMetadataDocumentProvider';
30+
2931

3032
export function activate(context: vscode.ExtensionContext): any {
31-
33+
3234
const extensionId = 'ms-vscode.csharp';
3335
const extension = vscode.extensions.getExtension(extensionId);
3436
const extensionVersion = extension.packageJSON.version;
@@ -48,7 +50,11 @@ export function activate(context: vscode.ExtensionContext): any {
4850

4951
disposables.push(server.onServerStart(() => {
5052
// register language feature provider on start
51-
localDisposables.push(vscode.languages.registerDefinitionProvider(_selector, new DefinitionProvider(server)));
53+
const definitionMetadataDocumentProvider = new DefinitionMetadataDocumentProvider();
54+
definitionMetadataDocumentProvider.register();
55+
localDisposables.push(definitionMetadataDocumentProvider);
56+
57+
localDisposables.push(vscode.languages.registerDefinitionProvider(_selector, new DefinitionProvider(server, definitionMetadataDocumentProvider)));
5258
localDisposables.push(vscode.languages.registerCodeLensProvider(_selector, new CodeLensProvider(server)));
5359
localDisposables.push(vscode.languages.registerDocumentHighlightProvider(_selector, new DocumentHighlightProvider(server)));
5460
localDisposables.push(vscode.languages.registerDocumentSymbolProvider(_selector, new DocumentSymbolProvider(server)));
@@ -74,7 +80,7 @@ export function activate(context: vscode.ExtensionContext): any {
7480

7581
disposables.push(registerCommands(server, context.extensionPath));
7682
disposables.push(reportStatus(server));
77-
83+
7884
disposables.push(server.onServerStart(() => {
7985
// Update or add tasks.json and launch.json
8086
addAssetsIfNecessary(server);
@@ -89,10 +95,10 @@ export function activate(context: vscode.ExtensionContext): any {
8995
advisor.dispose();
9096
server.stop();
9197
}));
92-
98+
9399
// activate coreclr-debug
94100
coreclrdebug.activate(context, reporter);
95-
101+
96102
context.subscriptions.push(...disposables);
97103
}
98104

src/omnisharp/protocol.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export module Requests {
2626
export const SignatureHelp = '/signatureHelp';
2727
export const TypeLookup = '/typelookup';
2828
export const UpdateBuffer = '/updatebuffer';
29+
export const Metadata = '/metadata';
2930
}
3031

3132
export interface Request {
@@ -36,6 +37,11 @@ export interface Request {
3637
Changes?: LinePositionSpanTextChange[];
3738
}
3839

40+
export interface GoToDefinitionRequest extends Request
41+
{
42+
WantMetadata?: boolean;
43+
}
44+
3945
export interface LinePositionSpanTextChange {
4046
NewText: string;
4147
StartLine: number;
@@ -44,6 +50,23 @@ export interface LinePositionSpanTextChange {
4450
EndColumn: number;
4551
}
4652

53+
export interface MetadataSource {
54+
AssemblyName: string;
55+
ProjectName: string;
56+
VersionNumber: string;
57+
Language: string;
58+
TypeName: string;
59+
}
60+
61+
export interface MetadataRequest extends MetadataSource {
62+
Timeout?: number;
63+
}
64+
65+
export interface MetadataResponse {
66+
SourceName: string;
67+
Source: string;
68+
}
69+
4770
export interface UpdateBufferRequest extends Request {
4871
FromDisk?: boolean;
4972
}
@@ -119,6 +142,10 @@ export interface ResourceLocation {
119142
Column: number;
120143
}
121144

145+
export interface GoToDefinitionResponse extends ResourceLocation {
146+
MetadataSource?: MetadataSource;
147+
}
148+
122149
export interface Error {
123150
Message: string;
124151
Line: number;

src/omnisharp/server.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export abstract class OmnisharpServer {
109109
return {
110110
path: config.get<string>('omnisharp'),
111111
usesMono: config.get<boolean>('omnisharpUsesMono')
112-
}
112+
};
113113
}
114114

115115
private _recordRequestDelay(requestName: string, elapsedTime: number) {
@@ -122,7 +122,7 @@ export abstract class OmnisharpServer {
122122
tracker.reportDelay(elapsedTime);
123123
}
124124

125-
private _reportTelemetry() {
125+
private _reportTelemetry() {
126126
const delayTrackers = this._delayTrackers;
127127

128128
for (const path in delayTrackers) {
@@ -235,7 +235,7 @@ export abstract class OmnisharpServer {
235235

236236
private _start(launchTarget: LaunchTarget): Promise<void> {
237237
const options = this._readOptions();
238-
238+
239239
let flavor: omnisharp.Flavor;
240240
if (options.path !== undefined && options.usesMono === true) {
241241
flavor = omnisharp.Flavor.Mono;
@@ -416,7 +416,7 @@ export abstract class OmnisharpServer {
416416

417417
throw err;
418418
}
419-
419+
420420
const config = vscode.workspace.getConfiguration();
421421
const proxy = config.get<string>('http.proxy');
422422
const strictSSL = config.get('http.proxyStrictSSL', true);

src/omnisharp/utils.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ export function getCodeActions(server: OmnisharpServer, request: protocol.V2.Get
4545
return server.makeRequest<protocol.V2.GetCodeActionsResponse>(protocol.V2.Requests.GetCodeActions, request, token);
4646
}
4747

48-
export function goToDefinition(server: OmnisharpServer, request: protocol.Request, token: vscode.CancellationToken) {
49-
return server.makeRequest<protocol.ResourceLocation>(protocol.Requests.GoToDefinition, request);
48+
export function goToDefinition(server: OmnisharpServer, request: protocol.GoToDefinitionRequest, token: vscode.CancellationToken) {
49+
return server.makeRequest<protocol.GoToDefinitionResponse>(protocol.Requests.GoToDefinition, request);
5050
}
5151

5252
export function rename(server: OmnisharpServer, request: protocol.RenameRequest, token: vscode.CancellationToken) {
@@ -73,6 +73,10 @@ export function updateBuffer(server: OmnisharpServer, request: protocol.UpdateBu
7373
return server.makeRequest<boolean>(protocol.Requests.UpdateBuffer, request);
7474
}
7575

76+
export function getMetadata(server: OmnisharpServer, request: protocol.MetadataRequest) {
77+
return server.makeRequest<protocol.MetadataResponse>(protocol.Requests.Metadata, request);
78+
}
79+
7680
export function getTestStartInfo(server: OmnisharpServer, request: protocol.V2.GetTestStartInfoRequest) {
7781
return server.makeRequest<protocol.V2.GetTestStartInfoResponse>(protocol.V2.Requests.GetTestStartInfo, request);
7882
}

0 commit comments

Comments
 (0)