-
-
Notifications
You must be signed in to change notification settings - Fork 427
Expand file tree
/
Copy pathFilespace+SuggestionService.swift
More file actions
177 lines (157 loc) · 5.9 KB
/
Copy pathFilespace+SuggestionService.swift
File metadata and controls
177 lines (157 loc) · 5.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
import Foundation
import SuggestionBasic
import SuggestionInjector
import Workspace
// MARK: - Suggestion Control
public extension Filespace {
@MainActor
var activeCodeSuggestion: CodeSuggestion? {
suggestionManager?.displaySuggestions.activeSuggestion?.activeCodeSuggestion
}
func setSuggestions(_ suggestions: [CodeSuggestion]) {
Task { @WorkspaceActor in
suggestionManager?.invalidateAllSuggestions()
suggestionManager?.receiveSuggestions(suggestions)
}
}
}
extension Filespace {
/// Get the displaying suggestion at the current index. And clear the displaying suggestions.
///
/// If an index is not provided, accept the active suggestion.
func acceptSuggestion(inGroup groupIndex: Int?) async -> CodeSuggestion? {
guard let suggestionManager else { return nil }
guard let suggestion = await {
if let groupIndex {
return await suggestionManager.displaySuggestions.suggestions[groupIndex]
} else {
return await suggestionManager.displaySuggestions.activeSuggestion
}
}()
else { return nil }
func finishAccepting() async {
suggestionManager.invalidateDisplaySuggestions()
await suggestionManager.defaultSuggestionProvider.resetSnapshot()
}
switch suggestion {
case let .group(group):
if let codeSuggestion = group.activeSuggestion {
await finishAccepting()
return codeSuggestion
}
return nil
case let .action(action):
await finishAccepting()
return action.suggestion
}
}
/// Reject the displaying suggestion at the current index.
func rejectSuggestion(inGroup groupIndex: Int?) async -> [CodeSuggestion] {
guard let suggestionManager else { return [] }
func extractCodeSuggestions(
_ displaySuggestion: FileSuggestionManager.DisplaySuggestion
) -> [CodeSuggestion] {
switch displaySuggestion {
case let .group(group):
return group.suggestions
case let .action(action):
return [action.suggestion]
}
}
let displaySuggestions = await suggestionManager.displaySuggestions
if let groupIndex {
if groupIndex >= 0, groupIndex < displaySuggestions.count {
let displaySuggestions = displaySuggestions[groupIndex]
let suggestionsInGroup = extractCodeSuggestions(displaySuggestions)
await suggestionManager.invalidateDisplaySuggestions(inGroup: groupIndex)
await suggestionManager.defaultSuggestionProvider.resetSnapshot()
return suggestionsInGroup
} else {
return []
}
} else {
let suggestions = displaySuggestions.suggestions.flatMap {
extractCodeSuggestions($0)
}
suggestionManager.invalidateDisplaySuggestions()
await suggestionManager.defaultSuggestionProvider.resetSnapshot()
return suggestions
}
}
func selectNextSuggestionGroup() {
guard let suggestionManager else { return }
Task {
await suggestionManager.nextSuggestionGroup()
}
}
func selectPreviousSuggestionGroup() {
guard let suggestionManager else { return }
Task {
await suggestionManager.previousSuggestionGroup()
}
}
func selectNextSuggestion(inGroup groupIndex: Int?) {
guard let suggestionManager else { return }
Task {
let groupIndex = if let groupIndex {
groupIndex
} else {
await suggestionManager.displaySuggestions.anchorIndex
}
await suggestionManager.nextSuggestionInGroup(index: groupIndex)
}
}
func selectPreviousSuggestion(inGroup groupIndex: Int?) {
guard let suggestionManager else { return }
Task {
let groupIndex = if let groupIndex {
groupIndex
} else {
await suggestionManager.displaySuggestions.anchorIndex
}
await suggestionManager.previousSuggestionInGroup(index: groupIndex)
}
}
}
// MARK: - Validation
public extension Filespace {
/// Validate the suggestion is still valid.
/// - Parameters:
/// - lines: lines of the file
/// - cursorPosition: cursor position
/// - alwaysTrueIfCursorNotMoved: for unit tests
/// - Returns: `true` if the suggestion is still valid
@WorkspaceActor
@discardableResult func validateSuggestions(
lines: [String],
cursorPosition: CursorPosition
) async -> Bool {
guard let suggestionManager else { return false }
suggestionManager.updateCursorPosition(cursorPosition)
let displaySuggestions = await suggestionManager.displaySuggestions
let displayedSuggestionIds = Set(
displaySuggestions
.flatMap { suggestion in
switch suggestion {
case let .action(action):
return [action.suggestion.id]
case let .group(group):
return group.suggestions.map { $0.id }
}
}
)
for provider in suggestionManager.suggestionProviders {
_ = provider.validateSuggestions(
displayedSuggestionIds: displayedSuggestionIds,
lines: lines,
cursorPosition: cursorPosition
)
}
let stillValid = suggestionManager.defaultSuggestionProvider.validateSuggestions(
displayedSuggestionIds: displayedSuggestionIds,
lines: lines,
cursorPosition: cursorPosition
)
return stillValid
}
}