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' )
@@ -537,6 +543,40 @@ describe('Client integration', () => {
537
543
)
538
544
} )
539
545
546
+ test ( 'Progress percentage is an integer' , async ( ) => {
547
+ const progressToken = 'TEST-PROGRESS-PERCENTAGE'
548
+ const percentages : Array < number | undefined > = [ ]
549
+ let currentProgressResolver : ( value : unknown ) => void | undefined
550
+
551
+ // Set up middleware that calls the current resolve function when it gets its 'end' progress event.
552
+ middleware . handleWorkDoneProgress = ( token : ProgressToken , params : WorkDoneProgressBegin | WorkDoneProgressReport | WorkDoneProgressEnd , next ) => {
553
+ if ( token === progressToken ) {
554
+ const percentage = params . kind === 'report' || params . kind === 'begin' ? params . percentage : undefined
555
+ percentages . push ( percentage )
556
+
557
+ if ( params . kind === 'end' ) {
558
+ setImmediate ( currentProgressResolver )
559
+ }
560
+ }
561
+ return next ( token , params )
562
+ }
563
+
564
+ // Trigger a progress event.
565
+ await new Promise < unknown > ( resolve => {
566
+ currentProgressResolver = resolve
567
+ void client . sendRequest (
568
+ new ProtocolRequestType < any , null , never , any , any > ( 'testing/sendPercentageProgress' ) ,
569
+ { } ,
570
+ tokenSource . token ,
571
+ )
572
+ } )
573
+
574
+ middleware . handleWorkDoneProgress = undefined
575
+
576
+ // Ensure percentages are rounded according to the spec
577
+ assert . deepStrictEqual ( percentages , [ 0 , 50 , undefined ] )
578
+ } )
579
+
540
580
test ( 'Document Formatting' , async ( ) => {
541
581
const provider = client . getFeature ( DocumentFormattingRequest . method ) . getProvider ( document )
542
582
isDefined ( provider )
@@ -821,12 +861,13 @@ describe('Client integration', () => {
821
861
822
862
const referenceFileUri = URI . parse ( '/dummy-edit' )
823
863
function ensureReferenceEdit ( edits : WorkspaceEdit , type : string , expectedLines : string [ ] ) {
824
- // // Ensure the edits are as expected.
864
+ // Ensure the edits are as expected.
825
865
assert . strictEqual ( edits . documentChanges ?. length , 1 )
826
866
const edit = edits . documentChanges [ 0 ] as TextDocumentEdit
827
867
assert . strictEqual ( edit . edits . length , 1 )
828
868
assert . strictEqual ( edit . textDocument . uri , referenceFileUri . path )
829
- assert . strictEqual ( edit . edits [ 0 ] . newText . trim ( ) , `${ type } :\n${ expectedLines . join ( '\n' ) } ` . trim ( ) )
869
+ const expectedTextEdit = edit . edits [ 0 ] as TextEdit
870
+ assert . strictEqual ( expectedTextEdit . newText . trim ( ) , `${ type } :\n${ expectedLines . join ( '\n' ) } ` . trim ( ) )
830
871
}
831
872
async function ensureNotificationReceived ( type : string , params : any ) {
832
873
const result = await client . sendRequest (
@@ -1350,6 +1391,27 @@ describe('Client integration', () => {
1350
1391
} , true )
1351
1392
} )
1352
1393
1394
+ test ( 'Inline Completions' , async ( ) => {
1395
+ const provider = client . getFeature ( InlineCompletionRequest . method ) ?. getProvider ( document )
1396
+ isDefined ( provider )
1397
+ const results = ( await provider . provideInlineCompletionItems ( document , position , { triggerKind : 1 , selectedCompletionInfo : { range, text : 'text' } } , tokenSource . token ) ) as InlineCompletionItem [ ]
1398
+
1399
+ isArray ( results , InlineCompletionItem , 1 )
1400
+
1401
+ rangeEqual ( results [ 0 ] . range ! , 1 , 2 , 3 , 4 )
1402
+ assert . strictEqual ( results [ 0 ] . filterText ! , 'te' )
1403
+ assert . strictEqual ( results [ 0 ] . insertText , 'text inline' )
1404
+
1405
+ let middlewareCalled = false
1406
+ middleware . provideInlineCompletionItems = ( d , r , c , t , n ) => {
1407
+ middlewareCalled = true
1408
+ return n ( d , r , c , t )
1409
+ }
1410
+ await provider . provideInlineCompletionItems ( document , position , { triggerKind : 1 , selectedCompletionInfo : undefined } , tokenSource . token )
1411
+ middleware . provideInlineCompletionItems = undefined
1412
+ assert . strictEqual ( middlewareCalled , true )
1413
+ } )
1414
+
1353
1415
test ( 'Workspace symbols' , async ( ) => {
1354
1416
const providers = client . getFeature ( WorkspaceSymbolRequest . method ) . getProviders ( )
1355
1417
isDefined ( providers )
@@ -1364,6 +1426,59 @@ describe('Client integration', () => {
1364
1426
isDefined ( symbol )
1365
1427
rangeEqual ( symbol . location [ 'range' ] , 1 , 2 , 3 , 4 )
1366
1428
} )
1429
+
1430
+ test ( 'General middleware' , async ( ) => {
1431
+ let middlewareCallCount = 0
1432
+ // Add a general middleware for both requests and notifications
1433
+ middleware . sendRequest = ( type , param , token , next ) => {
1434
+ middlewareCallCount ++
1435
+ return next ( type , param , token )
1436
+ }
1437
+ middleware . sendNotification = ( type , next , params ) => {
1438
+ middlewareCallCount ++
1439
+ return next ( type , params )
1440
+ }
1441
+ // Send a request
1442
+ const definitionProvider = client . getFeature ( DefinitionRequest . method ) . getProvider ( document )
1443
+ isDefined ( definitionProvider )
1444
+ await definitionProvider . provideDefinition ( document , position , tokenSource . token )
1445
+ // Send a notification
1446
+ const notificationProvider = client . getFeature ( DidSaveTextDocumentNotification . method ) . getProvider ( document )
1447
+ isDefined ( notificationProvider )
1448
+ await notificationProvider . send ( document )
1449
+ // Verify that both the request and notification went through the middleware
1450
+ middleware . sendRequest = undefined
1451
+ middleware . sendNotification = undefined
1452
+ assert . strictEqual ( middlewareCallCount , 2 )
1453
+ } )
1454
+
1455
+ test ( 'applyEdit middleware' , async ( ) => {
1456
+ const middlewareEvents : Array < ApplyWorkspaceEditParams > = [ ]
1457
+ let currentProgressResolver : ( value : unknown ) => void | undefined
1458
+
1459
+ middleware . workspace = middleware . workspace || { }
1460
+ middleware . workspace . handleApplyEdit = async ( params , next ) => {
1461
+ middlewareEvents . push ( params )
1462
+ setImmediate ( currentProgressResolver )
1463
+ return next ( params , tokenSource . token )
1464
+ }
1465
+
1466
+ // Trigger sample applyEdit event.
1467
+ await new Promise < unknown > ( resolve => {
1468
+ currentProgressResolver = resolve
1469
+ void client . sendRequest (
1470
+ new ProtocolRequestType < any , null , never , any , any > ( 'testing/sendApplyEdit' ) ,
1471
+ { } ,
1472
+ tokenSource . token ,
1473
+ )
1474
+ } )
1475
+
1476
+ middleware . workspace . handleApplyEdit = undefined
1477
+
1478
+ // Ensure event was handled.
1479
+ assert . strictEqual ( middlewareEvents . length , 1 )
1480
+ assert . strictEqual ( middlewareEvents [ 0 ] . label , 'Apply Edit' )
1481
+ } )
1367
1482
} )
1368
1483
1369
1484
namespace CrashNotification {
@@ -1382,8 +1497,8 @@ class CrashClient extends LanguageClient {
1382
1497
} )
1383
1498
}
1384
1499
1385
- protected handleConnectionClosed ( ) : void {
1386
- super . handleConnectionClosed ( )
1500
+ protected async handleConnectionClosed ( ) : Promise < void > {
1501
+ await super . handleConnectionClosed ( )
1387
1502
this . resolve ! ( )
1388
1503
}
1389
1504
}
0 commit comments