Skip to content

Commit 8f9d25b

Browse files
committed
feat(lsp): LSP 3.18
- inlineCompletion Closes #5071
1 parent 98fa66a commit 8f9d25b

11 files changed

+379
-150
lines changed

package-lock.json

+27-22
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
"eslint-plugin-jsdoc": "^48.11.0",
8282
"jest": "29.7.0",
8383
"typescript": "^5.5.4",
84-
"vscode-languageserver": "^9.0.1"
84+
"vscode-languageserver": "^10.0.0-next.10"
8585
},
8686
"dependencies": {
8787
"@chemzqm/neovim": "^6.1.2",
@@ -108,9 +108,9 @@
108108
"unidecode": "^1.0.1",
109109
"unzip-stream": "^0.3.4",
110110
"uuid": "^9.0.1",
111-
"vscode-languageserver-protocol": "^3.17.5",
112-
"vscode-languageserver-textdocument": "^1.0.11",
113-
"vscode-languageserver-types": "^3.17.5",
111+
"vscode-languageserver-protocol": "^3.17.6-next.10",
112+
"vscode-languageserver-textdocument": "^1.0.12",
113+
"vscode-languageserver-types": "^3.17.6-next.5",
114114
"vscode-uri": "^3.0.8",
115115
"which": "^4.0.0"
116116
}

src/__tests__/client/features.test.ts

+110-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as assert from 'assert'
22
import path from 'path'
3-
import { CallHierarchyIncomingCall, CallHierarchyItem, CallHierarchyOutgoingCall, CallHierarchyPrepareRequest, CancellationToken, CancellationTokenSource, CodeAction, CodeActionRequest, CodeLensRequest, Color, ColorInformation, ColorPresentation, CompletionItem, CompletionRequest, CompletionTriggerKind, ConfigurationRequest, DeclarationRequest, DefinitionRequest, DidChangeConfigurationNotification, DidChangeTextDocumentNotification, DidChangeWatchedFilesNotification, DidCloseTextDocumentNotification, DidCreateFilesNotification, DidDeleteFilesNotification, DidOpenTextDocumentNotification, DidRenameFilesNotification, DidSaveTextDocumentNotification, Disposable, DocumentColorRequest, DocumentDiagnosticReport, DocumentDiagnosticReportKind, DocumentDiagnosticRequest, DocumentFormattingRequest, DocumentHighlight, DocumentHighlightKind, DocumentHighlightRequest, DocumentLink, DocumentLinkRequest, DocumentOnTypeFormattingRequest, DocumentRangeFormattingRequest, DocumentSelector, DocumentSymbolRequest, FoldingRange, FoldingRangeRequest, FullDocumentDiagnosticReport, Hover, HoverRequest, ImplementationRequest, InlayHintKind, InlayHintLabelPart, InlayHintRequest, InlineValueEvaluatableExpression, InlineValueRequest, InlineValueText, InlineValueVariableLookup, LinkedEditingRangeRequest, Location, NotificationType0, ParameterInformation, Position, ProgressToken, ProtocolRequestType, Range, ReferencesRequest, RenameRequest, SelectionRange, SelectionRangeRequest, SemanticTokensRegistrationType, SignatureHelpRequest, SignatureHelpTriggerKind, SignatureInformation, TextDocumentEdit, TextDocumentSyncKind, TextEdit, TypeDefinitionRequest, TypeHierarchyPrepareRequest, WillCreateFilesRequest, WillDeleteFilesRequest, WillRenameFilesRequest, WillSaveTextDocumentNotification, WillSaveTextDocumentWaitUntilRequest, WorkDoneProgressBegin, WorkDoneProgressCreateRequest, WorkDoneProgressEnd, WorkDoneProgressReport, WorkspaceEdit, WorkspaceSymbolRequest } from 'vscode-languageserver-protocol'
3+
import { ApplyWorkspaceEditParams, CallHierarchyIncomingCall, CallHierarchyItem, CallHierarchyOutgoingCall, CallHierarchyPrepareRequest, CancellationToken, CancellationTokenSource, CodeAction, CodeActionRequest, CodeLensRequest, Color, ColorInformation, ColorPresentation, CompletionItem, CompletionRequest, CompletionTriggerKind, ConfigurationRequest, DeclarationRequest, DefinitionRequest, DidChangeConfigurationNotification, DidChangeTextDocumentNotification, DidChangeWatchedFilesNotification, DidCloseTextDocumentNotification, DidCreateFilesNotification, DidDeleteFilesNotification, DidOpenTextDocumentNotification, DidRenameFilesNotification, DidSaveTextDocumentNotification, Disposable, DocumentColorRequest, DocumentDiagnosticReport, DocumentDiagnosticReportKind, DocumentDiagnosticRequest, DocumentFormattingRequest, DocumentHighlight, DocumentHighlightKind, DocumentHighlightRequest, DocumentLink, DocumentLinkRequest, DocumentOnTypeFormattingRequest, DocumentRangeFormattingRequest, DocumentSelector, DocumentSymbolRequest, FoldingRange, FoldingRangeRequest, FullDocumentDiagnosticReport, Hover, HoverRequest, ImplementationRequest, InlayHintKind, InlayHintLabelPart, InlayHintRequest, InlineCompletionItem, InlineCompletionRequest, InlineValueEvaluatableExpression, InlineValueRequest, InlineValueText, InlineValueVariableLookup, LinkedEditingRangeRequest, Location, NotificationType0, ParameterInformation, Position, ProgressToken, ProtocolRequestType, Range, ReferencesRequest, RenameRequest, SelectionRange, SelectionRangeRequest, SemanticTokensRegistrationType, SignatureHelpRequest, SignatureHelpTriggerKind, SignatureInformation, TextDocumentEdit, TextDocumentSyncKind, TextEdit, TypeDefinitionRequest, TypeHierarchyPrepareRequest, WillCreateFilesRequest, WillDeleteFilesRequest, WillRenameFilesRequest, WillSaveTextDocumentNotification, WillSaveTextDocumentWaitUntilRequest, WorkDoneProgressBegin, WorkDoneProgressCreateRequest, WorkDoneProgressEnd, WorkDoneProgressReport, WorkspaceEdit, WorkspaceSymbolRequest } from 'vscode-languageserver-protocol'
44
import { TextDocument } from 'vscode-languageserver-textdocument'
55
import { URI } from 'vscode-uri'
66
import commands from '../../commands'
@@ -154,6 +154,7 @@ describe('Client integration', () => {
154154
documentSelector: [{ language: '*' }]
155155
},
156156
selectionRangeProvider: true,
157+
inlineCompletionProvider: true,
157158
inlineValueProvider: {},
158159
inlayHintProvider: {
159160
resolveProvider: true
@@ -270,6 +271,7 @@ describe('Client integration', () => {
270271
testFeature(SemanticTokensRegistrationType.method, 'document')
271272
testFeature(LinkedEditingRangeRequest.method, 'document')
272273
testFeature(TypeHierarchyPrepareRequest.method, 'document')
274+
testFeature(InlineCompletionRequest.method, 'document')
273275
testFeature(InlineValueRequest.method, 'document')
274276
testFeature(InlayHintRequest.method, 'document')
275277
testFeature(WorkspaceSymbolRequest.method, 'workspace')
@@ -538,6 +540,40 @@ describe('Client integration', () => {
538540
)
539541
})
540542

543+
test('Progress percentage is an integer', async () => {
544+
const progressToken = 'TEST-PROGRESS-PERCENTAGE'
545+
const percentages: Array<number | undefined> = []
546+
let currentProgressResolver: (value: unknown) => void | undefined
547+
548+
// Set up middleware that calls the current resolve function when it gets its 'end' progress event.
549+
middleware.handleWorkDoneProgress = (token: ProgressToken, params: WorkDoneProgressBegin | WorkDoneProgressReport | WorkDoneProgressEnd, next) => {
550+
if (token === progressToken) {
551+
const percentage = params.kind === 'report' || params.kind === 'begin' ? params.percentage : undefined
552+
percentages.push(percentage)
553+
554+
if (params.kind === 'end') {
555+
setImmediate(currentProgressResolver)
556+
}
557+
}
558+
return next(token, params)
559+
}
560+
561+
// Trigger a progress event.
562+
await new Promise<unknown>(resolve => {
563+
currentProgressResolver = resolve
564+
void client.sendRequest(
565+
new ProtocolRequestType<any, null, never, any, any>('testing/sendPercentageProgress'),
566+
{},
567+
tokenSource.token,
568+
)
569+
})
570+
571+
middleware.handleWorkDoneProgress = undefined
572+
573+
// Ensure percentages are rounded according to the spec
574+
assert.deepStrictEqual(percentages, [0, 50, undefined])
575+
})
576+
541577
test('Document Formatting', async () => {
542578
const provider = client.getFeature(DocumentFormattingRequest.method).getProvider(document)
543579
isDefined(provider)
@@ -1351,6 +1387,27 @@ describe('Client integration', () => {
13511387
}, true)
13521388
})
13531389

1390+
test('Inline Completions', async () => {
1391+
const provider = client.getFeature(InlineCompletionRequest.method)?.getProvider(document)
1392+
isDefined(provider)
1393+
const results = (await provider.provideInlineCompletionItems(document, position, { triggerKind: 1, selectedCompletionInfo: { range, text: 'text' } }, tokenSource.token)) as InlineCompletionItem[]
1394+
1395+
isArray(results, InlineCompletionItem, 1)
1396+
1397+
rangeEqual(results[0].range!, 1, 2, 3, 4)
1398+
assert.strictEqual(results[0].filterText!, 'te')
1399+
assert.strictEqual(results[0].insertText, 'text inline')
1400+
1401+
let middlewareCalled = false
1402+
middleware.provideInlineCompletionItems = (d, r, c, t, n) => {
1403+
middlewareCalled = true
1404+
return n(d, r, c, t)
1405+
}
1406+
await provider.provideInlineCompletionItems(document, position, { triggerKind: 1, selectedCompletionInfo: undefined }, tokenSource.token)
1407+
middleware.provideInlineCompletionItems = undefined
1408+
assert.strictEqual(middlewareCalled, true)
1409+
})
1410+
13541411
test('Workspace symbols', async () => {
13551412
const providers = client.getFeature(WorkspaceSymbolRequest.method).getProviders()
13561413
isDefined(providers)
@@ -1365,6 +1422,58 @@ describe('Client integration', () => {
13651422
isDefined(symbol)
13661423
rangeEqual(symbol.location['range'], 1, 2, 3, 4)
13671424
})
1425+
1426+
test('General middleware', async () => {
1427+
let middlewareCallCount = 0
1428+
// Add a general middleware for both requests and notifications
1429+
middleware.sendRequest = (type, param, token, next) => {
1430+
middlewareCallCount++
1431+
return next(type, param, token)
1432+
}
1433+
middleware.sendNotification = (type, next, params) => {
1434+
middlewareCallCount++
1435+
return next(type, params)
1436+
}
1437+
// Send a request
1438+
const definitionProvider = client.getFeature(DefinitionRequest.method).getProvider(document)
1439+
isDefined(definitionProvider)
1440+
await definitionProvider.provideDefinition(document, position, tokenSource.token)
1441+
// Send a notification
1442+
const notificationProvider = client.getFeature(DidSaveTextDocumentNotification.method).getProvider(document)
1443+
isDefined(notificationProvider)
1444+
await notificationProvider.send(document)
1445+
// Verify that both the request and notification went through the middleware
1446+
middleware.sendRequest = undefined
1447+
middleware.sendNotification = undefined
1448+
assert.strictEqual(middlewareCallCount, 2)
1449+
})
1450+
1451+
test('applyEdit middleware', async () => {
1452+
const middlewareEvents: Array<ApplyWorkspaceEditParams> = []
1453+
let currentProgressResolver: (value: unknown) => void | undefined
1454+
1455+
middleware.workspace = middleware.workspace || {}
1456+
middleware.workspace.handleApplyEdit = async (params, next) => {
1457+
middlewareEvents.push(params)
1458+
setImmediate(currentProgressResolver)
1459+
return next(params, tokenSource.token)
1460+
}
1461+
1462+
// Trigger sample applyEdit event.
1463+
await new Promise<unknown>(resolve => {
1464+
currentProgressResolver = resolve
1465+
void client.sendRequest(
1466+
new ProtocolRequestType<any, null, never, any, any>('testing/sendApplyEdit'),
1467+
{},
1468+
tokenSource.token,
1469+
)
1470+
})
1471+
1472+
middleware.workspace.handleApplyEdit = undefined
1473+
1474+
// Ensure event was handled.
1475+
assert.deepStrictEqual(middlewareEvents, [{ label: 'Apply Edit', edit: {} }])
1476+
})
13681477
})
13691478

13701479
namespace CrashNotification {

0 commit comments

Comments
 (0)