diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index be75d9df2..45d45ac41 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,7 +44,7 @@ jobs: gulp test npm run test:artifacts env: - CODE_VERSION: 1.65.0 + CODE_VERSION: 1.66.0 DISPLAY: :99.0 - name: Build platform-specific extension package diff --git a/CHANGELOG.md b/CHANGELOG.md index ae606aa98..fef04c1c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ * coreclr debug configuration should support input variables for envFile ([#5102](https://github.com/OmniSharp/omnisharp-vscode/issues/5102), PR: [#5189](https://github.com/OmniSharp/omnisharp-vscode/pull/5189)) * Fix small spelling mistake (PR: [#5215](https://github.com/OmniSharp/omnisharp-vscode/pull/5215)) * Low-hanging nullable fruit (PR: [#5186](https://github.com/OmniSharp/omnisharp-vscode/pull/5186)) +* Fire a buffer update instead of filechanged when active editor changes ([#5216](https://github.com/OmniSharp/omnisharp-vscode/issues/5216), PR: [#5218](https://github.com/OmniSharp/omnisharp-vscode/pull/5218)) +* Add support for InlayHint.TextEdits (PR: [#5177](https://github.com/OmniSharp/omnisharp-vscode/pull/5177)) * Fix .net6 OmniSharp acquisition on Linux arm64 (PR: [#5172](https://github.com/OmniSharp/omnisharp-vscode/pull/5172)) * Remove project.json reference in debugger.md (PR: [#5210](https://github.com/OmniSharp/omnisharp-vscode/pull/5210)) * Update debugger to 1.24.5 (PR: [#5211](https://github.com/OmniSharp/omnisharp-vscode/pull/5211)) diff --git a/README.md b/README.md index 339406ee9..0189f68d7 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ See issue [#5120](https://github.com/OmniSharp/omnisharp-vscode/issues/5120) for * coreclr debug configuration should support input variables for envFile ([#5102](https://github.com/OmniSharp/omnisharp-vscode/issues/5102), PR: [#5189](https://github.com/OmniSharp/omnisharp-vscode/pull/5189)) * Fix small spelling mistake (PR: [#5215](https://github.com/OmniSharp/omnisharp-vscode/pull/5215)) * Low-hanging nullable fruit (PR: [#5186](https://github.com/OmniSharp/omnisharp-vscode/pull/5186)) +* Fire a buffer update instead of filechanged when active editor changes ([#5216](https://github.com/OmniSharp/omnisharp-vscode/issues/5216), PR: [#5218](https://github.com/OmniSharp/omnisharp-vscode/pull/5218)) +* Add support for InlayHint.TextEdits (PR: [#5177](https://github.com/OmniSharp/omnisharp-vscode/pull/5177)) * Fix .net6 OmniSharp acquisition on Linux arm64 (PR: [#5172](https://github.com/OmniSharp/omnisharp-vscode/pull/5172)) * Remove project.json reference in debugger.md (PR: [#5210](https://github.com/OmniSharp/omnisharp-vscode/pull/5210)) * Update debugger to 1.24.5 (PR: [#5211](https://github.com/OmniSharp/omnisharp-vscode/pull/5211)) diff --git a/package-lock.json b/package-lock.json index c86a00699..7ab57a760 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,7 @@ "@types/semver": "5.5.0", "@types/tmp": "0.0.33", "@types/unzipper": "^0.9.1", - "@types/vscode": "1.65.0", + "@types/vscode": "1.66.0", "@types/yauzl": "2.9.1", "@vscode/test-electron": "2.1.3", "archiver": "5.3.0", @@ -77,7 +77,7 @@ "webpack-cli": "4.6.0" }, "engines": { - "vscode": "^1.65.0" + "vscode": "^1.66.0" } }, "node_modules/@discoveryjs/json-ext": { @@ -331,10 +331,11 @@ } }, "node_modules/@types/vscode": { - "version": "1.65.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.65.0.tgz", - "integrity": "sha512-wQhExnh2nEzpjDMSKhUvnNmz3ucpd3E+R7wJkOhBNK3No6fG3VUdmVmMOKD0A8NDZDDDiQcLNxe3oGmX5SjJ5w==", - "dev": true + "version": "1.66.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.66.0.tgz", + "integrity": "sha512-ZfJck4M7nrGasfs4A4YbUoxis3Vu24cETw3DERsNYtDZmYSYtk6ljKexKFKhImO/ZmY6ZMsmegu2FPkXoUFImA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/yauzl": { "version": "2.9.1", @@ -9612,9 +9613,9 @@ } }, "@types/vscode": { - "version": "1.65.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.65.0.tgz", - "integrity": "sha512-wQhExnh2nEzpjDMSKhUvnNmz3ucpd3E+R7wJkOhBNK3No6fG3VUdmVmMOKD0A8NDZDDDiQcLNxe3oGmX5SjJ5w==", + "version": "1.66.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.66.0.tgz", + "integrity": "sha512-ZfJck4M7nrGasfs4A4YbUoxis3Vu24cETw3DERsNYtDZmYSYtk6ljKexKFKhImO/ZmY6ZMsmegu2FPkXoUFImA==", "dev": true }, "@types/yauzl": { diff --git a/package.json b/package.json index 7d90922d9..b87e539b9 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "@types/semver": "5.5.0", "@types/tmp": "0.0.33", "@types/unzipper": "^0.9.1", - "@types/vscode": "1.65.0", + "@types/vscode": "1.66.0", "@types/yauzl": "2.9.1", "@vscode/test-electron": "2.1.3", "archiver": "5.3.0", @@ -576,7 +576,7 @@ } ], "engines": { - "vscode": "^1.65.0" + "vscode": "^1.66.0" }, "activationEvents": [ "onDebugInitialConfigurations", diff --git a/src/features/inlayHintProvider.ts b/src/features/inlayHintProvider.ts index cfc449cec..fd0a17c01 100644 --- a/src/features/inlayHintProvider.ts +++ b/src/features/inlayHintProvider.ts @@ -8,8 +8,8 @@ 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 { InlayHint, InlayHintRequest, InlayHintResolve as InlayHintResolveRequest, LinePositionSpanTextChange } from '../omnisharp/protocol'; +import { fromVSCodeRange, toVSCodePosition, toVSCodeTextEdit } from '../omnisharp/typeConversion'; import { isVirtualCSharpDocument } from './virtualDocumentTracker'; export default class CSharpInlayHintProvider extends AbstractProvider implements vscode.InlayHintsProvider { @@ -34,7 +34,7 @@ export default class CSharpInlayHintProvider extends AbstractProvider implements if (document.uri.scheme !== "file") { return []; } - + if (isVirtualCSharpDocument(document)) { return []; } @@ -50,7 +50,7 @@ export default class CSharpInlayHintProvider extends AbstractProvider implements const hints = await serverUtils.getInlayHints(this._server, request, token); return hints.InlayHints.map((inlayHint): vscode.InlayHint => { - const mappedHint = this.toVscodeHint(inlayHint); + const mappedHint = this.toVSCodeHint(inlayHint); this._hintsMap.set(mappedHint, inlayHint); return mappedHint; }); @@ -68,17 +68,22 @@ export default class CSharpInlayHintProvider extends AbstractProvider implements try { const result = await serverUtils.resolveInlayHints(this._server, request, token); - return this.toVscodeHint(result); + return this.toVSCodeHint(result); } catch (error) { return Promise.reject(`Problem invoking 'ResolveInlayHints' on OmniSharpServer: ${error}`); } } - private toVscodeHint(inlayHint: InlayHint): vscode.InlayHint { + private toVSCodeHint(inlayHint: InlayHint): vscode.InlayHint { return { label: inlayHint.Label, position: toVSCodePosition(inlayHint.Position), - tooltip: new vscode.MarkdownString(inlayHint.Tooltip ?? "") + tooltip: new vscode.MarkdownString(inlayHint.Tooltip ?? ""), + textEdits: toVSCodeTextEdits(inlayHint.TextEdits), }; + + function toVSCodeTextEdits(textEdits: LinePositionSpanTextChange[]): vscode.TextEdit[] { + return textEdits ? textEdits.map(toVSCodeTextEdit) : undefined; + } } } diff --git a/src/omnisharp/protocol.ts b/src/omnisharp/protocol.ts index e50693925..4b59554ed 100644 --- a/src/omnisharp/protocol.ts +++ b/src/omnisharp/protocol.ts @@ -592,6 +592,7 @@ export interface InlayHint { Label: string; Tooltip?: string; Data: any; + TextEdits?: LinePositionSpanTextChange[]; } export interface InlayHintResponse { diff --git a/src/omnisharp/typeConversion.ts b/src/omnisharp/typeConversion.ts index d299f5caf..c4708d0df 100644 --- a/src/omnisharp/typeConversion.ts +++ b/src/omnisharp/typeConversion.ts @@ -62,6 +62,10 @@ export function toVSCodePosition(point: protocol.V2.Point): vscode.Position { return new vscode.Position(point.Line, point.Column); } +export function toVSCodeTextEdit(textChange: protocol.LinePositionSpanTextChange): vscode.TextEdit { + return new vscode.TextEdit(toRange2(textChange), textChange.NewText); +} + export function createRequest(document: vscode.TextDocument, where: vscode.Position, includeBuffer: boolean = false): T { // for metadata sources, we need to remove the [metadata] from the filename, and prepend the $metadata$ authority // this is expected by the Omnisharp server to support metadata-to-metadata navigation diff --git a/test/integrationTests/inlayHints.integration.test.ts b/test/integrationTests/inlayHints.integration.test.ts index 455fec069..28557e613 100644 --- a/test/integrationTests/inlayHints.integration.test.ts +++ b/test/integrationTests/inlayHints.integration.test.ts @@ -9,6 +9,7 @@ import { should, assert } from 'chai'; import { activateCSharpExtension, isRazorWorkspace, isSlnWithGenerator, restartOmniSharpServer } from './integrationHelpers'; import testAssetWorkspace from './testAssets/testAssetWorkspace'; import * as path from 'path'; +import { InlayHint, LinePositionSpanTextChange } from '../../src/omnisharp/protocol'; const chai = require('chai'); chai.use(require('chai-arrays')); @@ -49,7 +50,7 @@ suite(`Inlay Hints ${testAssetWorkspace.description}`, function () { const projectDirectory = testAssetWorkspace.projects[0].projectDirectoryPath; const filePath = path.join(projectDirectory, fileName); fileUri = vscode.Uri.file(filePath); - + await vscode.commands.executeCommand("vscode.open", fileUri); await testAssetWorkspace.waitForIdle(activation.eventStream); }); @@ -60,19 +61,42 @@ suite(`Inlay Hints ${testAssetWorkspace.description}`, function () { test("Hints retrieved for region", async () => { const range = new vscode.Range(new vscode.Position(4, 8), new vscode.Position(15, 85)); - const hints : vscode.InlayHint[] = await vscode.commands.executeCommand('vscode.executeInlayHintProvider', fileUri, range); + const hints: vscode.InlayHint[] = await vscode.commands.executeCommand('vscode.executeInlayHintProvider', fileUri, range); + assert.lengthOf(hints, 6); - assertValues(hints[0], 'InlayHints ', 6, 12); - assertValues(hints[1], ' InlayHints', 7, 27); - assertValues(hints[2], 'string ', 8, 28); - assertValues(hints[3], 'i: ', 9, 17); - assertValues(hints[4], 'param1: ', 10, 15); - assertValues(hints[5], 'param1: ', 11, 27); - - function assertValues(hint: vscode.InlayHint, expectedLabel: string, expectedLine: number, expectedCharacter: number) { - assert.equal(hint.label, expectedLabel); - assert.equal(hint.position.line, expectedLine); - assert.equal(hint.position.character, expectedCharacter); + + assertInlayHintEqual(hints[0], { Label: 'InlayHints ', Position: { Line: 6, Column: 12 }, Data: {}, TextEdits: [{ StartLine: 6, StartColumn: 8, EndLine: 6, EndColumn: 11, NewText: 'InlayHints' }] }); + assertInlayHintEqual(hints[1], { Label: ' InlayHints', Position: { Line: 7, Column: 27 }, Data: {}, TextEdits: [{ StartLine: 7, StartColumn: 27, EndLine: 7, EndColumn: 27, NewText: ' InlayHints' }] }); + assertInlayHintEqual(hints[2], { Label: 'string ', Position: { Line: 8, Column: 28 }, Data: {}, TextEdits: [{ StartLine: 8, StartColumn: 28, EndLine: 8, EndColumn: 28, NewText: 'string ' }] }); + assertInlayHintEqual(hints[3], { Label: 'i: ', Position: { Line: 9, Column: 17 }, Data: {}, TextEdits: [{ StartLine: 9, StartColumn: 17, EndLine: 9, EndColumn: 17, NewText: 'i: ' }] }); + assertInlayHintEqual(hints[4], { Label: 'param1: ', Position: { Line: 10, Column: 15 }, Data: {}, TextEdits: [{ StartLine: 10, StartColumn: 15, EndLine: 10, EndColumn: 15, NewText: 'param1: ' }] }); + assertInlayHintEqual(hints[5], { Label: 'param1: ', Position: { Line: 11, Column: 27 }, Data: {}, TextEdits: [{ StartLine: 11, StartColumn: 27, EndLine: 11, EndColumn: 27, NewText: 'param1: ' }] }); + + function assertInlayHintEqual(actual: vscode.InlayHint, expected: InlayHint) { + assert.equal(actual.label, expected.Label); + assert.equal(actual.position.line, expected.Position.Line); + assert.equal(actual.position.character, expected.Position.Column); + + if (!actual.textEdits) { + assert.isUndefined(expected.TextEdits); + return; + } + + assert.equal(actual.textEdits.length, expected.TextEdits.length); + for (let i = 0; i < actual.textEdits.length; i++) { + const actualTextEdit = actual.textEdits[i]; + const expectedTextEdit = expected.TextEdits[i]; + + assertTextEditEqual(actualTextEdit, expectedTextEdit); + } + } + + function assertTextEditEqual(actual: vscode.TextEdit, expected: LinePositionSpanTextChange) { + assert.equal(actual.range.start.line, expected.StartLine); + assert.equal(actual.range.start.character, expected.StartColumn); + assert.equal(actual.range.end.line, expected.EndLine); + assert.equal(actual.range.end.character, expected.EndColumn); + assert.equal(actual.newText, expected.NewText); } }); });