1// SPDX-FileCopyrightText: 2025 The Project Pterodactyl Developers 2// 3// SPDX-License-Identifier: MPL-2.0 4 5import Foundation 6import LanguageServerProtocol 7 8private enum ArraySymmetry { 9 case identity 10 case reverse 11} 12 13extension Array { 14 fileprivate func apply(symmetry: ArraySymmetry) -> any Collection<Element> { 15 switch symmetry { 16 case .identity: self 17 case .reverse: reversed() 18 } 19 } 20} 21 22extension SyntaxTree.Cursor { 23 private func firstVisibleNode(under symmetry: ArraySymmetry) -> SyntaxTree.Cursor? { 24 switch node { 25 case .token(let token, _): 26 return token.kind.isVisible ? self : nil 27 case .tree: 28 for child in children.apply(symmetry: symmetry) { 29 if let visibleChild = child.firstVisibleNode(under: symmetry) { return visibleChild } 30 continue 31 } 32 33 return nil 34 } 35 } 36 37 private var visibleUtf16Range: Range<Int>? { 38 guard 39 let firstNode = firstVisibleNode(under: .identity), 40 let lastNode = firstVisibleNode(under: .reverse) 41 else { return nil } 42 return firstNode.utf16Range.lowerBound..<lastNode.utf16Range.upperBound 43 } 44 45 private func collectFoldingRanges(_ sink: inout [FoldingRange]) { 46 if let foldingRangeKind = node.tree?.metadata?.delimitedFoldingRangeKind, let visibleUtf16Range { 47 let startLocation = lineMap.location(at: visibleUtf16Range.lowerBound) 48 let endLocation = lineMap.location(at: visibleUtf16Range.upperBound) 49 let foldingRange = FoldingRange(startLine: startLocation.line, endLine: endLocation.line, kind: foldingRangeKind) 50 sink.append(foldingRange) 51 } 52 53 for child in children { 54 child.collectFoldingRanges(&sink) 55 } 56 } 57 58 public var foldingRanges: [FoldingRange] { 59 var sink: [FoldingRange] = [] 60 collectFoldingRanges(&sink) 61 return sink 62 } 63}