Skip to content
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

Support inlay hints #5107

Merged
merged 12 commits into from
Mar 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ jobs:
gulp test
npm run test:artifacts
env:
CODE_VERSION: 1.45.0
CODE_VERSION: 1.65.0
DISPLAY: :99.0

- name: Build platform-specific extension package
run: gulp 'vsix:release:package:platform-specific'
run: gulp 'vsix:release:package:platform-specific'
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 63 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
"@types/semver": "5.5.0",
"@types/tmp": "0.0.33",
"@types/unzipper": "^0.9.1",
"@types/vscode": "1.58.0",
"@types/vscode": "1.65.0",
"@types/yauzl": "2.9.1",
"archiver": "5.3.0",
"chai": "4.3.4",
Expand Down Expand Up @@ -539,7 +539,7 @@
}
],
"engines": {
"vscode": "^1.61.0"
"vscode": "^1.65.0"
},
"activationEvents": [
"onDebugInitialConfigurations",
Expand Down Expand Up @@ -852,6 +852,66 @@
"default": true,
"description": "Shows the OmniSharp log in the Output pane when OmniSharp reports an error."
},
"csharp.inlayHints.parameters.enabled": {
"type": "boolean",
"default": false,
"description": "Display inline parameter name hints"
},
"csharp.inlayHints.parameters.forLiteralParameters": {
"type": "boolean",
"default": false,
"description": "Show hints for literals"
},
"csharp.inlayHints.parameters.forObjectCreationParameters": {
"type": "boolean",
"default": false,
"description": "Show hints for 'new' expressions"
},
"csharp.inlayHints.parameters.forIndexerParameters": {
"type": "boolean",
"default": false,
"description": "Show hints for indexers"
},
"csharp.inlayHints.parameters.forOtherParameters": {
"type": "boolean",
"default": false,
"description": "Show hints for everything else"
},
"csharp.inlayHints.parameters.suppressForParametersThatDifferOnlyBySuffix": {
"type": "boolean",
"default": false,
"description": "Suppress hints when parameter names differ only by suffix"
},
"csharp.inlayHints.parameters.suppressForParametersThatMatchMethodIntent": {
"type": "boolean",
"default": false,
"description": "Suppress hints when parameter name matches the method's intent"
},
"csharp.inlayHints.parameters.suppressForParametersThatMatchArgumentName": {
"type": "boolean",
"default": false,
"description": "Suppress hints when argument matches parameter name"
},
"csharp.inlayHints.types.enabled": {
"type": "boolean",
"default": false,
"description": "Display inline type hints"
},
"csharp.inlayHints.types.forImplicitVariableTypes": {
"type": "boolean",
"default": false,
"description": "Show hints for variables with inferred types"
},
"csharp.inlayHints.types.forLambdaParameterTypes": {
"type": "boolean",
"default": false,
"description": "Show hints for lambda parameter types"
},
"csharp.inlayHints.types.forImplicitObjectCreation": {
"type": "boolean",
"default": false,
"description": "Show hints for implicit object creation"
},
"omnisharp.path": {
"type": [
"string",
Expand Down Expand Up @@ -4011,4 +4071,4 @@
}
]
}
}
}
6 changes: 3 additions & 3 deletions src/features/fileOpenCloseProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ class FileOpenCloseProvider implements IDisposable {
await serverUtils.fileClose(this._server, { FileName: e.fileName });
}

private async _onActiveTextEditorChange(e: vscode.TextEditor) {
if (shouldIgnoreDocument(e.document)) {
private async _onActiveTextEditorChange(e: vscode.TextEditor | undefined) {
if (e === undefined || shouldIgnoreDocument(e.document)) {
return;
}

Expand All @@ -71,4 +71,4 @@ function shouldIgnoreDocument(document: vscode.TextDocument) {
}

return false;
}
}
79 changes: 79 additions & 0 deletions src/features/inlayHintProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as serverUtils from '../omnisharp/utils';
import * as vscode from 'vscode';
import AbstractProvider from './abstractProvider';
import { OmniSharpServer } from '../omnisharp/server';
import { LanguageMiddlewareFeature } from '../omnisharp/LanguageMiddlewareFeature';
import CompositeDisposable from '../CompositeDisposable';
import { InlayHint, InlayHintRequest, InlayHintResolve as InlayHintResolveRequest } from '../omnisharp/protocol';
import { fromVSCodeRange, toVSCodePosition } from '../omnisharp/typeConversion';
import { isVirtualCSharpDocument } from './virtualDocumentTracker';

export default class CSharpInlayHintProvider extends AbstractProvider implements vscode.InlayHintsProvider {
private readonly _onDidChangeInlayHints = new vscode.EventEmitter<void>();
public readonly onDidChangeInlayHints = this._onDidChangeInlayHints.event;

private readonly _hintsMap = new Map<vscode.InlayHint, InlayHint>();

constructor(server: OmniSharpServer, languageMiddlewareFeature: LanguageMiddlewareFeature) {
super(server, languageMiddlewareFeature);
this.addDisposables(new CompositeDisposable(
this._onDidChangeInlayHints,
vscode.workspace.onDidChangeTextDocument(e => {
if (e.document.languageId === 'csharp') {
this._onDidChangeInlayHints.fire();
}
})));
}

async provideInlayHints(document: vscode.TextDocument, range: vscode.Range, token: vscode.CancellationToken): Promise<vscode.InlayHint[]> {
if (isVirtualCSharpDocument(document)) {
return [];
}

const request: InlayHintRequest = {
Location: {
FileName: document.fileName,
Range: fromVSCodeRange(range)
}
};

try {
const hints = await serverUtils.getInlayHints(this._server, request, token);

return hints.InlayHints.map((inlayHint): vscode.InlayHint => {
const mappedHint = this.toVscodeHint(inlayHint);
this._hintsMap.set(mappedHint, inlayHint);
return mappedHint;
});
} catch (error) {
return Promise.reject(`Problem invoking 'GetInlayHints' on OmniSharpServer: ${error}`);
}
}

async resolveInlayHint?(hint: vscode.InlayHint, token: vscode.CancellationToken): Promise<vscode.InlayHint> {
if (!this._hintsMap.has(hint)) {
return Promise.reject(`Outdated inlay hint was requested to be resolved, aborting.`);
}

const request: InlayHintResolveRequest = { Hint: this._hintsMap.get(hint) };

try {
const result = await serverUtils.resolveInlayHints(this._server, request, token);
return this.toVscodeHint(result);
} catch (error) {
return Promise.reject(`Problem invoking 'ResolveInlayHints' on OmniSharpServer: ${error}`);
}
}

private toVscodeHint(inlayHint: InlayHint): vscode.InlayHint {
return {
label: inlayHint.Label,
position: toVSCodePosition(inlayHint.Position),
tooltip: new vscode.MarkdownString(inlayHint.Tooltip ?? "")
};
}
}
14 changes: 13 additions & 1 deletion src/observers/OptionChangeObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,19 @@ const omniSharpOptions: ReadonlyArray<OptionsKey> = [
"enableAsyncCompletion",
"useModernNet",
"analyzeOpenDocumentsOnly",
"enableRoslynAnalyzers"
"enableRoslynAnalyzers",
"inlayHintsEnableForParameters",
"inlayHintsForLiteralParameters",
"inlayHintsForObjectCreationParameters",
"inlayHintsForIndexerParameters",
"inlayHintsForOtherParameters",
"inlayHintsSuppressForParametersThatDifferOnlyBySuffix",
"inlayHintsSuppressForParametersThatMatchMethodIntent",
"inlayHintsSuppressForParametersThatMatchArgumentName",
"inlayHintsEnableForTypes",
"inlayHintsForImplicitVariableTypes",
"inlayHintsForLambdaParameterTypes",
"inlayHintsForImplicitObjectCreation",
];

function OmniSharpOptionChangeObservable(optionObservable: Observable<Options>): Observable<Options> {
Expand Down
4 changes: 4 additions & 0 deletions src/omnisharp/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import SemanticTokensProvider from '../features/semanticTokensProvider';
import SourceGeneratedDocumentProvider from '../features/sourceGeneratedDocumentProvider';
import { getDecompilationAuthorization } from './decompilationPrompt';
import { OmniSharpDotnetResolver } from './OmniSharpDotnetResolver';
import CSharpInlayHintProvider from '../features/inlayHintProvider';
import fileOpenClose from '../features/fileOpenCloseProvider';

export interface ActivationResult {
Expand Down Expand Up @@ -119,6 +120,9 @@ export async function activate(context: vscode.ExtensionContext, packageJSON: an
const semanticTokensProvider = new SemanticTokensProvider(server, optionProvider, languageMiddlewareFeature);
localDisposables.add(vscode.languages.registerDocumentSemanticTokensProvider(documentSelector, semanticTokensProvider, semanticTokensProvider.getLegend()));
localDisposables.add(vscode.languages.registerDocumentRangeSemanticTokensProvider(documentSelector, semanticTokensProvider, semanticTokensProvider.getLegend()));

const inlayHintsProvider = new CSharpInlayHintProvider(server, languageMiddlewareFeature);
localDisposables.add(vscode.languages.registerInlayHintsProvider(documentSelector, inlayHintsProvider));
}));

disposables.add(server.onServerStop(() => {
Expand Down
37 changes: 37 additions & 0 deletions src/omnisharp/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ export class Options {
public enableAsyncCompletion: boolean,
public analyzeOpenDocumentsOnly: boolean,
public useSemanticHighlighting: boolean,
public inlayHintsEnableForParameters: boolean,
public inlayHintsForLiteralParameters: boolean,
public inlayHintsForObjectCreationParameters: boolean,
public inlayHintsForIndexerParameters: boolean,
public inlayHintsForOtherParameters: boolean,
public inlayHintsSuppressForParametersThatDifferOnlyBySuffix: boolean,
public inlayHintsSuppressForParametersThatMatchMethodIntent: boolean,
public inlayHintsSuppressForParametersThatMatchArgumentName: boolean,
public inlayHintsEnableForTypes: boolean,
public inlayHintsForImplicitVariableTypes: boolean,
public inlayHintsForLambdaParameterTypes: boolean,
public inlayHintsForImplicitObjectCreation: boolean,
public razorPluginPath?: string,
public defaultLaunchSolution?: string,
public monoPath?: string,
Expand Down Expand Up @@ -94,6 +106,19 @@ export class Options {

const useSemanticHighlighting = csharpConfig.get<boolean>('semanticHighlighting.enabled', false);

const inlayHintsEnableForParameters = csharpConfig.get<boolean>('inlayHints.parameters.enabled', false);
const inlayHintsForLiteralParameters = csharpConfig.get<boolean>('inlayHints.parameters.forLiteralParameters', false);
const inlayHintsForObjectCreationParameters = csharpConfig.get<boolean>('inlayHints.parameters.forObjectCreationParameters', false);
const inlayHintsForIndexerParameters = csharpConfig.get<boolean>('inlayHints.parameters.forIndexerParameters', false);
const inlayHintsForOtherParameters = csharpConfig.get<boolean>('inlayHints.parameters.forOtherParameters', false);
const inlayHintsSuppressForParametersThatDifferOnlyBySuffix = csharpConfig.get<boolean>('inlayHints.parameters.suppressForParametersThatDifferOnlyBySuffix', false);
const inlayHintsSuppressForParametersThatMatchMethodIntent = csharpConfig.get<boolean>('inlayHints.parameters.suppressForParametersThatMatchMethodIntent', false);
const inlayHintsSuppressForParametersThatMatchArgumentName = csharpConfig.get<boolean>('inlayHints.parameters.suppressForParametersThatMatchArgumentName', false);
const inlayHintsEnableForTypes = csharpConfig.get<boolean>('inlayHints.types.enabled', false);
const inlayHintsForImplicitVariableTypes = csharpConfig.get<boolean>('inlayHints.types.forImplicitVariableTypes', false);
const inlayHintsForLambdaParameterTypes = csharpConfig.get<boolean>('inlayHints.types.forLambdaParameterTypes', false);
const inlayHintsForImplicitObjectCreation = csharpConfig.get<boolean>('inlayHints.types.forImplicitObjectCreation', false);

const disableCodeActions = csharpConfig.get<boolean>('disableCodeActions', false);

const disableMSBuildDiagnosticWarning = omnisharpConfig.get<boolean>('disableMSBuildDiagnosticWarning', false);
Expand Down Expand Up @@ -145,6 +170,18 @@ export class Options {
enableAsyncCompletion,
analyzeOpenDocumentsOnly,
useSemanticHighlighting,
inlayHintsEnableForParameters,
inlayHintsForLiteralParameters,
inlayHintsForObjectCreationParameters,
inlayHintsForIndexerParameters,
inlayHintsForOtherParameters,
inlayHintsSuppressForParametersThatDifferOnlyBySuffix,
inlayHintsSuppressForParametersThatMatchMethodIntent,
inlayHintsSuppressForParametersThatMatchArgumentName,
inlayHintsEnableForTypes,
inlayHintsForImplicitVariableTypes,
inlayHintsForLambdaParameterTypes,
inlayHintsForImplicitObjectCreation,
razorPluginPath,
defaultLaunchSolution,
monoPath,
Expand Down
21 changes: 21 additions & 0 deletions src/omnisharp/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export module Requests {
export const SourceGeneratedFile = '/sourcegeneratedfile';
export const UpdateSourceGeneratedFile = '/updatesourcegeneratedfile';
export const SourceGeneratedFileClosed = '/sourcegeneratedfileclosed';
export const InlayHint = '/inlayHint';
export const InlayHintResolve = '/inlayHint/resolve';
export const FileOpen = '/open';
export const FileClose = '/close';
}
Expand Down Expand Up @@ -581,6 +583,25 @@ export enum UpdateType {
export interface SourceGeneratedFileClosedRequest extends SourceGeneratedFileInfo {
}

export interface InlayHintRequest {
Location: V2.Location;
}

export interface InlayHint {
Position: V2.Point;
Label: string;
Tooltip?: string;
Data: any;
}

export interface InlayHintResponse {
InlayHints: InlayHint[];
}

export interface InlayHintResolve {
Hint: InlayHint;
}

export interface Definition {
Location: V2.Location;
MetadataSource?: MetadataSource;
Expand Down
Loading