@@ -607,106 +607,68 @@ extension SwiftLanguageServer {
607
607
}
608
608
609
609
public func documentColor( _ req: DocumentColorRequest ) async throws -> [ ColorInformation ] {
610
- let keys = self . keys
611
-
612
610
guard let snapshot = self . documentManager. latestSnapshot ( req. textDocument. uri) else {
613
611
logger. error ( " failed to find snapshot for url \( req. textDocument. uri. forLogging) " )
614
612
return [ ]
615
613
}
616
614
617
- let helperDocumentName = " DocumentColor: " + snapshot. uri. pseudoPath
618
- let skreq = SKDRequestDictionary ( sourcekitd: self . sourcekitd)
619
- skreq [ keys. request] = self . requests. editor_open
620
- skreq [ keys. name] = helperDocumentName
621
- skreq [ keys. sourcetext] = snapshot. text
622
- skreq [ keys. syntactic_only] = 1
623
-
624
- let dict = try await self . sourcekitd. send ( skreq)
625
- defer {
626
- let closeHelperReq = SKDRequestDictionary ( sourcekitd: self . sourcekitd)
627
- closeHelperReq [ keys. request] = self . requests. editor_close
628
- closeHelperReq [ keys. name] = helperDocumentName
629
- // FIXME: (async) We might receive two concurrent document color requests for the
630
- // same document, in which race to open/close a document with the same name in
631
- // sourcekitd. The solution is to either
632
- // - Not open the helper document and instead rely on the document that is already
633
- // open or
634
- // - Prefix the helper document with a UUID to make sure the two concurrent
635
- // requests operate on different documents as far as sourcekitd is concerned.
636
- Task {
637
- _ = try ? await self . sourcekitd. send ( closeHelperReq)
638
- }
639
- }
615
+ let syntaxTree = await syntaxTreeManager. syntaxTree ( for: snapshot)
640
616
641
- guard let results : SKDResponseArray = dict [ self . keys . substructure ] else {
642
- return [ ]
643
- }
617
+ class ColorLiteralFinder : SyntaxVisitor {
618
+ let snapshot : DocumentSnapshot
619
+ var result : [ ColorInformation ] = [ ]
644
620
645
- func colorInformation( dict: SKDResponseDictionary ) -> ColorInformation ? {
646
- guard let kind: sourcekitd_uid_t = dict [ self . keys. kind] ,
647
- kind == self . values. expr_object_literal,
648
- let name: String = dict [ self . keys. name] ,
649
- name == " colorLiteral " ,
650
- let offset: Int = dict [ self . keys. offset] ,
651
- let start: Position = snapshot. positionOf ( utf8Offset: offset) ,
652
- let length: Int = dict [ self . keys. length] ,
653
- let end: Position = snapshot. positionOf ( utf8Offset: offset + length) ,
654
- let substructure: SKDResponseArray = dict [ self . keys. substructure]
655
- else {
656
- return nil
621
+ init ( snapshot: DocumentSnapshot ) {
622
+ self . snapshot = snapshot
623
+ super. init ( viewMode: . sourceAccurate)
657
624
}
658
- var red , green , blue , alpha : Double ?
659
- substructure. forEach { ( i: Int , value: SKDResponseDictionary ) in
660
- guard let name: String = value [ self . keys. name] ,
661
- let bodyoffset: Int = value [ self . keys. bodyoffset] ,
662
- let bodylength: Int = value [ self . keys. bodylength]
663
- else {
664
- return true
625
+
626
+ override func visit( _ node: MacroExpansionExprSyntax ) -> SyntaxVisitorContinueKind {
627
+ guard node. macroName. text == " colorLiteral " else {
628
+ return . visitChildren
665
629
}
666
- let view = snapshot. text. utf8
667
- let bodyStart = view. index ( view. startIndex, offsetBy: bodyoffset)
668
- let bodyEnd = view. index ( view. startIndex, offsetBy: bodyoffset + bodylength)
669
- let value = String ( view [ bodyStart..< bodyEnd] ) . flatMap ( Double . init)
670
- switch name {
671
- case " red " :
672
- red = value
673
- case " green " :
674
- green = value
675
- case " blue " :
676
- blue = value
677
- case " alpha " :
678
- alpha = value
679
- default :
680
- break
630
+ func extractArgument( _ argumentName: String , from arguments: LabeledExprListSyntax ) -> Double ? {
631
+ for argument in arguments {
632
+ if argument. label? . text == argumentName {
633
+ if let integer = argument. expression. as ( IntegerLiteralExprSyntax . self) {
634
+ return Double ( integer. literal. text)
635
+ } else if let integer = argument. expression. as ( FloatLiteralExprSyntax . self) {
636
+ return Double ( integer. literal. text)
637
+ }
638
+ }
639
+ }
640
+ return nil
641
+ }
642
+ guard let red = extractArgument ( " red " , from: node. arguments) ,
643
+ let green = extractArgument ( " green " , from: node. arguments) ,
644
+ let blue = extractArgument ( " blue " , from: node. arguments) ,
645
+ let alpha = extractArgument ( " alpha " , from: node. arguments)
646
+ else {
647
+ return . skipChildren
681
648
}
682
- return true
683
- }
684
- if let red = red,
685
- let green = green,
686
- let blue = blue,
687
- let alpha = alpha
688
- {
689
- let color = Color ( red: red, green: green, blue: blue, alpha: alpha)
690
- return ColorInformation ( range: start..< end, color: color)
691
- } else {
692
- return nil
693
- }
694
- }
695
649
696
- func colorInformation( array: SKDResponseArray ) -> [ ColorInformation ] {
697
- var result : [ ColorInformation ] = [ ]
698
- array. forEach { ( i: Int , value: SKDResponseDictionary ) in
699
- if let documentSymbol = colorInformation ( dict: value) {
700
- result. append ( documentSymbol)
701
- } else if let substructure: SKDResponseArray = value [ self . keys. substructure] {
702
- result += colorInformation ( array: substructure)
650
+ guard let startPosition = snapshot. position ( of: node. position) ,
651
+ let endPosition = snapshot. position ( of: node. endPosition)
652
+ else {
653
+ return . skipChildren
703
654
}
704
- return true
655
+
656
+ result. append (
657
+ ColorInformation (
658
+ range: startPosition..< endPosition,
659
+ color: Color ( red: red, green: green, blue: blue, alpha: alpha)
660
+ )
661
+ )
662
+
663
+ return . skipChildren
705
664
}
706
- return result
707
665
}
708
666
709
- return colorInformation ( array: results)
667
+ try Task . checkCancellation ( )
668
+
669
+ let colorLiteralFinder = ColorLiteralFinder ( snapshot: snapshot)
670
+ colorLiteralFinder. walk ( syntaxTree)
671
+ return colorLiteralFinder. result
710
672
}
711
673
712
674
public func colorPresentation( _ req: ColorPresentationRequest ) async throws -> [ ColorPresentation ] {
0 commit comments