1
1
import * as assert from 'assert'
2
2
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'
4
4
import { TextDocument } from 'vscode-languageserver-textdocument'
5
5
import { URI } from 'vscode-uri'
6
6
import commands from '../../commands'
@@ -101,7 +101,8 @@ describe('Client integration', () => {
101
101
102
102
middleware = { }
103
103
const clientOptions : LanguageClientOptions = {
104
- documentSelector, synchronize : { } , initializationOptions : { } , middleware
104
+ documentSelector, synchronize : { } , initializationOptions : { } , middleware,
105
+ workspaceFolder : { name : 'test_folder' , uri : URI . parse ( 'file-test:///' ) . toString ( ) } ,
105
106
}
106
107
107
108
client = new LanguageClient ( 'test svr' , 'Test Language Server' , serverOptions , clientOptions )
@@ -137,7 +138,9 @@ describe('Client integration', () => {
137
138
resolveProvider : true
138
139
} ,
139
140
documentFormattingProvider : true ,
140
- documentRangeFormattingProvider : true ,
141
+ documentRangeFormattingProvider : {
142
+ rangesSupport : true
143
+ } ,
141
144
documentOnTypeFormattingProvider : {
142
145
firstTriggerCharacter : ':'
143
146
} ,
@@ -147,13 +150,15 @@ describe('Client integration', () => {
147
150
documentLinkProvider : {
148
151
resolveProvider : true
149
152
} ,
153
+ documentSymbolProvider : true ,
150
154
colorProvider : true ,
151
155
declarationProvider : true ,
152
156
foldingRangeProvider : true ,
153
157
implementationProvider : {
154
158
documentSelector : [ { language : '*' } ]
155
159
} ,
156
160
selectionRangeProvider : true ,
161
+ inlineCompletionProvider : { } ,
157
162
inlineValueProvider : { } ,
158
163
inlayHintProvider : {
159
164
resolveProvider : true
@@ -270,6 +275,7 @@ describe('Client integration', () => {
270
275
testFeature ( SemanticTokensRegistrationType . method , 'document' )
271
276
testFeature ( LinkedEditingRangeRequest . method , 'document' )
272
277
testFeature ( TypeHierarchyPrepareRequest . method , 'document' )
278
+ testFeature ( InlineCompletionRequest . method , 'document' )
273
279
testFeature ( InlineValueRequest . method , 'document' )
274
280
testFeature ( InlayHintRequest . method , 'document' )
275
281
testFeature ( WorkspaceSymbolRequest . method , 'workspace' )
@@ -538,6 +544,40 @@ describe('Client integration', () => {
538
544
)
539
545
} )
540
546
547
+ test ( 'Progress percentage is an integer' , async ( ) => {
548
+ const progressToken = 'TEST-PROGRESS-PERCENTAGE'
549
+ const percentages : Array < number | undefined > = [ ]
550
+ let currentProgressResolver : ( value : unknown ) => void | undefined
551
+
552
+ // Set up middleware that calls the current resolve function when it gets its 'end' progress event.
553
+ middleware . handleWorkDoneProgress = ( token : ProgressToken , params : WorkDoneProgressBegin | WorkDoneProgressReport | WorkDoneProgressEnd , next ) => {
554
+ if ( token === progressToken ) {
555
+ const percentage = params . kind === 'report' || params . kind === 'begin' ? params . percentage : undefined
556
+ percentages . push ( percentage )
557
+
558
+ if ( params . kind === 'end' ) {
559
+ setImmediate ( currentProgressResolver )
560
+ }
561
+ }
562
+ return next ( token , params )
563
+ }
564
+
565
+ // Trigger a progress event.
566
+ await new Promise < unknown > ( resolve => {
567
+ currentProgressResolver = resolve
568
+ void client . sendRequest (
569
+ new ProtocolRequestType < any , null , never , any , any > ( 'testing/sendPercentageProgress' ) ,
570
+ { } ,
571
+ tokenSource . token ,
572
+ )
573
+ } )
574
+
575
+ middleware . handleWorkDoneProgress = undefined
576
+
577
+ // Ensure percentages are rounded according to the spec
578
+ assert . deepStrictEqual ( percentages , [ 0 , 50 , undefined ] )
579
+ } )
580
+
541
581
test ( 'Document Formatting' , async ( ) => {
542
582
const provider = client . getFeature ( DocumentFormattingRequest . method ) . getProvider ( document )
543
583
isDefined ( provider )
@@ -822,12 +862,13 @@ describe('Client integration', () => {
822
862
823
863
const referenceFileUri = URI . parse ( '/dummy-edit' )
824
864
function ensureReferenceEdit ( edits : WorkspaceEdit , type : string , expectedLines : string [ ] ) {
825
- // // Ensure the edits are as expected.
865
+ // Ensure the edits are as expected.
826
866
assert . strictEqual ( edits . documentChanges ?. length , 1 )
827
867
const edit = edits . documentChanges [ 0 ] as TextDocumentEdit
828
868
assert . strictEqual ( edit . edits . length , 1 )
829
869
assert . strictEqual ( edit . textDocument . uri , referenceFileUri . path )
830
- assert . strictEqual ( edit . edits [ 0 ] . newText . trim ( ) , `${ type } :\n${ expectedLines . join ( '\n' ) } ` . trim ( ) )
870
+ const expectedTextEdit = edit . edits [ 0 ] as TextEdit
871
+ assert . strictEqual ( expectedTextEdit . newText . trim ( ) , `${ type } :\n${ expectedLines . join ( '\n' ) } ` . trim ( ) )
831
872
}
832
873
async function ensureNotificationReceived ( type : string , params : any ) {
833
874
const result = await client . sendRequest (
@@ -1351,6 +1392,27 @@ describe('Client integration', () => {
1351
1392
} , true )
1352
1393
} )
1353
1394
1395
+ test ( 'Inline Completions' , async ( ) => {
1396
+ const provider = client . getFeature ( InlineCompletionRequest . method ) ?. getProvider ( document )
1397
+ isDefined ( provider )
1398
+ const results = ( await provider . provideInlineCompletionItems ( document , position , { triggerKind : 1 , selectedCompletionInfo : { range, text : 'text' } } , tokenSource . token ) ) as InlineCompletionItem [ ]
1399
+
1400
+ isArray ( results , InlineCompletionItem , 1 )
1401
+
1402
+ rangeEqual ( results [ 0 ] . range ! , 1 , 2 , 3 , 4 )
1403
+ assert . strictEqual ( results [ 0 ] . filterText ! , 'te' )
1404
+ assert . strictEqual ( results [ 0 ] . insertText , 'text inline' )
1405
+
1406
+ let middlewareCalled = false
1407
+ middleware . provideInlineCompletionItems = ( d , r , c , t , n ) => {
1408
+ middlewareCalled = true
1409
+ return n ( d , r , c , t )
1410
+ }
1411
+ await provider . provideInlineCompletionItems ( document , position , { triggerKind : 1 , selectedCompletionInfo : undefined } , tokenSource . token )
1412
+ middleware . provideInlineCompletionItems = undefined
1413
+ assert . strictEqual ( middlewareCalled , true )
1414
+ } )
1415
+
1354
1416
test ( 'Workspace symbols' , async ( ) => {
1355
1417
const providers = client . getFeature ( WorkspaceSymbolRequest . method ) . getProviders ( )
1356
1418
isDefined ( providers )
@@ -1365,6 +1427,59 @@ describe('Client integration', () => {
1365
1427
isDefined ( symbol )
1366
1428
rangeEqual ( symbol . location [ 'range' ] , 1 , 2 , 3 , 4 )
1367
1429
} )
1430
+
1431
+ test ( 'General middleware' , async ( ) => {
1432
+ let middlewareCallCount = 0
1433
+ // Add a general middleware for both requests and notifications
1434
+ middleware . sendRequest = ( type , param , token , next ) => {
1435
+ middlewareCallCount ++
1436
+ return next ( type , param , token )
1437
+ }
1438
+ middleware . sendNotification = ( type , next , params ) => {
1439
+ middlewareCallCount ++
1440
+ return next ( type , params )
1441
+ }
1442
+ // Send a request
1443
+ const definitionProvider = client . getFeature ( DefinitionRequest . method ) . getProvider ( document )
1444
+ isDefined ( definitionProvider )
1445
+ await definitionProvider . provideDefinition ( document , position , tokenSource . token )
1446
+ // Send a notification
1447
+ const notificationProvider = client . getFeature ( DidSaveTextDocumentNotification . method ) . getProvider ( document )
1448
+ isDefined ( notificationProvider )
1449
+ await notificationProvider . send ( document )
1450
+ // Verify that both the request and notification went through the middleware
1451
+ middleware . sendRequest = undefined
1452
+ middleware . sendNotification = undefined
1453
+ assert . strictEqual ( middlewareCallCount , 2 )
1454
+ } )
1455
+
1456
+ test ( 'applyEdit middleware' , async ( ) => {
1457
+ const middlewareEvents : Array < ApplyWorkspaceEditParams > = [ ]
1458
+ let currentProgressResolver : ( value : unknown ) => void | undefined
1459
+
1460
+ middleware . workspace = middleware . workspace || { }
1461
+ middleware . workspace . handleApplyEdit = async ( params , next ) => {
1462
+ middlewareEvents . push ( params )
1463
+ setImmediate ( currentProgressResolver )
1464
+ return next ( params , tokenSource . token )
1465
+ }
1466
+
1467
+ // Trigger sample applyEdit event.
1468
+ await new Promise < unknown > ( resolve => {
1469
+ currentProgressResolver = resolve
1470
+ void client . sendRequest (
1471
+ new ProtocolRequestType < any , null , never , any , any > ( 'testing/sendApplyEdit' ) ,
1472
+ { } ,
1473
+ tokenSource . token ,
1474
+ )
1475
+ } )
1476
+
1477
+ middleware . workspace . handleApplyEdit = undefined
1478
+
1479
+ // Ensure event was handled.
1480
+ assert . strictEqual ( middlewareEvents . length , 1 )
1481
+ assert . strictEqual ( middlewareEvents [ 0 ] . label , 'Apply Edit' )
1482
+ } )
1368
1483
} )
1369
1484
1370
1485
namespace CrashNotification {
@@ -1383,8 +1498,8 @@ class CrashClient extends LanguageClient {
1383
1498
} )
1384
1499
}
1385
1500
1386
- protected handleConnectionClosed ( ) : void {
1387
- super . handleConnectionClosed ( )
1501
+ protected async handleConnectionClosed ( ) : Promise < void > {
1502
+ await super . handleConnectionClosed ( )
1388
1503
this . resolve ! ( )
1389
1504
}
1390
1505
}
0 commit comments