forked from intitni/CopilotForXcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFocusedCodeFinder.swift
More file actions
122 lines (104 loc) · 3.9 KB
/
FocusedCodeFinder.swift
File metadata and controls
122 lines (104 loc) · 3.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import Foundation
import SuggestionModel
public struct CodeContext: Equatable {
public enum Scope: Equatable {
case file
case top
case scope(signature: [String])
}
public var scopeSignatures: [String] {
switch scope {
case .file:
return []
case .top:
return ["Top level of the file"]
case let .scope(signature):
return signature
}
}
public var scope: Scope
public var contextRange: CursorRange
public var focusedRange: CursorRange
public var focusedCode: String
public var imports: [String]
public static var empty: CodeContext {
.init(scope: .file, contextRange: .zero, focusedRange: .zero, focusedCode: "", imports: [])
}
public init(
scope: Scope,
contextRange: CursorRange,
focusedRange: CursorRange,
focusedCode: String,
imports: [String]
) {
self.scope = scope
self.contextRange = contextRange
self.focusedRange = focusedRange
self.focusedCode = focusedCode
self.imports = imports
}
}
public protocol FocusedCodeFinder {
func findFocusedCode(
containingRange: CursorRange,
activeDocumentContext: ActiveDocumentContext
) -> CodeContext
}
public struct UnknownLanguageFocusedCodeFinder: FocusedCodeFinder {
let proposedSearchRange: Int
public init(proposedSearchRange: Int) {
self.proposedSearchRange = proposedSearchRange
}
public func findFocusedCode(
containingRange: CursorRange,
activeDocumentContext: ActiveDocumentContext
) -> CodeContext {
guard !activeDocumentContext.lines.isEmpty else { return .empty }
// when user is not selecting any code.
if containingRange.start == containingRange.end {
// search up and down for up to `proposedSearchRange * 2 + 1` lines.
let lines = activeDocumentContext.lines
let proposedLineCount = proposedSearchRange * 2 + 1
let startLineIndex = max(containingRange.start.line - proposedSearchRange, 0)
let endLineIndex = max(
startLineIndex,
min(startLineIndex + proposedLineCount - 1, lines.count - 1)
)
let focusedLines = lines[startLineIndex...endLineIndex]
let contextStartLine = max(startLineIndex - 5, 0)
let contextEndLine = min(endLineIndex + 5, lines.count - 1)
return .init(
scope: .top,
contextRange: .init(
start: .init(line: contextStartLine, character: 0),
end: .init(line: contextEndLine, character: lines[contextEndLine].count)
),
focusedRange: .init(
start: .init(line: startLineIndex, character: 0),
end: .init(line: endLineIndex, character: lines[endLineIndex].count)
),
focusedCode: focusedLines.joined(),
imports: []
)
}
let startLine = max(containingRange.start.line, 0)
let endLine = min(containingRange.end.line, activeDocumentContext.lines.count - 1)
if endLine < startLine { return .empty }
let focusedLines = activeDocumentContext.lines[startLine...endLine]
let contextStartLine = max(startLine - 3, 0)
let contextEndLine = min(endLine + 3, activeDocumentContext.lines.count - 1)
return CodeContext(
scope: .top,
contextRange: .init(
start: .init(line: contextStartLine, character: 0),
end: .init(
line: contextEndLine,
character: activeDocumentContext.lines[contextEndLine].count
)
),
focusedRange: containingRange,
focusedCode: focusedLines.joined(),
imports: []
)
}
}