@@ -71,6 +71,7 @@ public final class SourceKitServer: LanguageServer {
71
71
registerWorkspaceNotfication ( SourceKitServer . didSaveDocument)
72
72
registerWorkspaceRequest ( SourceKitServer . completion)
73
73
registerWorkspaceRequest ( SourceKitServer . hover)
74
+ registerWorkspaceRequest ( SourceKitServer . workspaceSymbols)
74
75
registerWorkspaceRequest ( SourceKitServer . definition)
75
76
registerWorkspaceRequest ( SourceKitServer . references)
76
77
registerWorkspaceRequest ( SourceKitServer . documentSymbolHighlight)
@@ -269,7 +270,8 @@ extension SourceKitServer {
269
270
clientCapabilities: req. params. capabilities. textDocument? . codeAction,
270
271
codeActionOptions: CodeActionOptions ( codeActionKinds: nil ) ,
271
272
supportsCodeActions: false // TODO: Turn it on after a provider is implemented.
272
- )
273
+ ) ,
274
+ workspaceSymbolProvider: true
273
275
) ) )
274
276
}
275
277
@@ -338,6 +340,51 @@ extension SourceKitServer {
338
340
toolchainTextDocumentRequest ( req, workspace: workspace, fallback: nil )
339
341
}
340
342
343
+ /// Find all symbols in the workspace that include a string in their name.
344
+ /// - returns: An array of SymbolOccurrences that match the string.
345
+ func findWorkspaceSymbols( matching: String ) -> [ SymbolOccurrence ] {
346
+ var symbolOccurenceResults : [ SymbolOccurrence ] = [ ]
347
+ workspace? . index? . forEachCanonicalSymbolOccurrence (
348
+ containing: matching,
349
+ anchorStart: false ,
350
+ anchorEnd: false ,
351
+ subsequence: true ,
352
+ ignoreCase: true
353
+ ) { symbol in
354
+ if !symbol. location. isSystem && !symbol. roles. contains ( . accessorOf) {
355
+ symbolOccurenceResults. append ( symbol)
356
+ }
357
+ return true
358
+ }
359
+ return symbolOccurenceResults
360
+ }
361
+
362
+ /// Handle a workspace/symbols request, returning the SymbolInformation.
363
+ /// - returns: An array with SymbolInformation for each matching symbol in the workspace.
364
+ func workspaceSymbols( _ req: Request < WorkspaceSymbolsRequest > , workspace: Workspace ) {
365
+ let symbols = findWorkspaceSymbols (
366
+ matching: req. params. query
367
+ ) . map ( { symbolOccurrence -> SymbolInformation in
368
+ let symbolPosition = Position (
369
+ line: symbolOccurrence. location. line - 1 , // 1-based -> 0-based
370
+ // FIXME: we need to convert the utf8/utf16 column, which may require reading the file!
371
+ utf16index: symbolOccurrence. location. utf8Column - 1 )
372
+
373
+ let symbolLocation = Location (
374
+ url: URL ( fileURLWithPath: symbolOccurrence. location. path) ,
375
+ range: Range ( symbolPosition) )
376
+
377
+ return SymbolInformation (
378
+ name: symbolOccurrence. symbol. name,
379
+ kind: symbolOccurrence. symbol. kind. toLspSymbolKind ( ) ,
380
+ deprecated: false ,
381
+ location: symbolLocation,
382
+ containerName: symbolOccurrence. getContainerName ( )
383
+ )
384
+ } )
385
+ req. reply ( symbols)
386
+ }
387
+
341
388
/// Forwards a SymbolInfoRequest to the appropriate toolchain service for this document.
342
389
func symbolInfo( _ req: Request < SymbolInfoRequest > , workspace: Workspace ) {
343
390
toolchainTextDocumentRequest ( req, workspace: workspace, fallback: [ ] )
@@ -523,3 +570,54 @@ public func languageService(
523
570
524
571
public typealias Notification = LanguageServerProtocol . Notification
525
572
public typealias Diagnostic = LanguageServerProtocol . Diagnostic
573
+
574
+ extension IndexSymbolKind {
575
+ func toLspSymbolKind( ) -> SymbolKind {
576
+ switch self {
577
+ case Self . class:
578
+ return . class
579
+ case Self . classMethod,
580
+ Self . instanceMethod,
581
+ Self . staticMethod:
582
+ return . method
583
+ case Self . instanceProperty,
584
+ Self . staticProperty,
585
+ Self . classProperty:
586
+ return . property
587
+ case Self . enum:
588
+ return . enum
589
+ case Self . enumConstant: // Unsure about this one
590
+ return . enumMember
591
+ case Self . protocol:
592
+ return . interface
593
+ case Self . function,
594
+ Self . conversionFunction: // assuming conversion function is function
595
+ return . function
596
+ case Self . variable:
597
+ return . variable
598
+ case Self . struct:
599
+ return . struct
600
+ case Self . parameter:
601
+ return . typeParameter
602
+ case Self . parameter:
603
+ return . typeParameter
604
+
605
+ default :
606
+ return . null
607
+ }
608
+ }
609
+ }
610
+
611
+ extension SymbolOccurrence {
612
+ /// Get the name of the symbol that is a parent of this symbol, if one exists
613
+ func getContainerName( ) -> String ? {
614
+ var foundChildRelation : SymbolRelation ?
615
+ self . forEachRelation { relation in
616
+ if relation. roles. contains ( . childOf) {
617
+ foundChildRelation = relation
618
+ }
619
+ return false
620
+ }
621
+ return foundChildRelation? . symbol. name
622
+ }
623
+ }
0 commit comments