1// SPDX-FileCopyrightText: 2025 The Project Pterodactyl Developers
2// SPDX-FileCopyrightText: 2026 The Project Pterodactyl Developers
3//
4// SPDX-License-Identifier: MPL-2.0
5
6import Algorithms
7import LanguageServerProtocol
8
9public struct LineMap: Codable, Sendable {
10 private let utf16LineOffsets: [Int]
11
12 public init(source: String) {
13 var offsets: [Int] = [0]
14 for idx in source.indices {
15 if source[idx].isNewline {
16 let next = source.index(after: idx)
17 let utf16Offset = next.utf16Offset(in: source)
18 offsets.append(utf16Offset)
19 }
20 }
21
22 self.utf16LineOffsets = offsets
23 }
24
25 public func lspPosition(at utf16Offset: Int) -> LanguageServerProtocol.Position {
26 let partitioningIndex = utf16LineOffsets.partitioningIndex { $0 > utf16Offset }
27 let lineIndex = partitioningIndex == 0 ? 0 : partitioningIndex - 1
28 let lineStart = utf16LineOffsets[lineIndex]
29 let lineNumber = lineIndex
30 let columnNumber = utf16Offset - lineStart
31 return Position(line: lineNumber, character: columnNumber)
32 }
33
34 public func lspRange(of range: Range<Int>) -> LanguageServerProtocol.LSPRange {
35 let start = lspPosition(at: range.lowerBound)
36 let end = lspPosition(at: range.upperBound)
37 return LSPRange(start: start, end: end)
38 }
39
40 public func range(from lspRange: LSPRange) -> Range<Int> {
41 offset(at: lspRange.start)..<offset(at: lspRange.end)
42 }
43
44 public func offset(at position: LanguageServerProtocol.Position) -> Int {
45 let lineOffset = utf16LineOffsets[position.line]
46 return lineOffset + position.character
47 }
48}