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'
@@ -97,11 +97,12 @@ describe('Client integration', () => {
97
97
run : { module : serverModule , transport : TransportKind . ipc } ,
98
98
debug : { module : serverModule , transport : TransportKind . ipc , options : { execArgv : [ '--nolazy' , '--inspect=6014' ] } }
99
99
}
100
- const documentSelector : DocumentSelector = [ { scheme : 'lsptests' } ]
100
+ const documentSelector : DocumentSelector = [ { scheme : 'lsptests' , language : 'bat' } ]
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,7 +862,7 @@ 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 )
@@ -1351,6 +1391,27 @@ describe('Client integration', () => {
1351
1391
} , true )
1352
1392
} )
1353
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
+
1354
1415
test ( 'Workspace symbols' , async ( ) => {
1355
1416
const providers = client . getFeature ( WorkspaceSymbolRequest . method ) . getProviders ( )
1356
1417
isDefined ( providers )
@@ -1365,6 +1426,58 @@ describe('Client integration', () => {
1365
1426
isDefined ( symbol )
1366
1427
rangeEqual ( symbol . location [ 'range' ] , 1 , 2 , 3 , 4 )
1367
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 . deepStrictEqual ( middlewareEvents , [ { label : 'Apply Edit' , edit : { } } ] )
1480
+ } )
1368
1481
} )
1369
1482
1370
1483
namespace CrashNotification {
@@ -1383,9 +1496,9 @@ class CrashClient extends LanguageClient {
1383
1496
} )
1384
1497
}
1385
1498
1386
- protected handleConnectionClosed ( ) : void {
1387
- super . handleConnectionClosed ( )
1499
+ protected handleConnectionClosed ( ) : Promise < void > {
1388
1500
this . resolve ! ( )
1501
+ return super . handleConnectionClosed ( )
1389
1502
}
1390
1503
}
1391
1504
0 commit comments