forked from intitni/CopilotForXcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFilespace+SuggestionService.swift
More file actions
86 lines (73 loc) · 2.72 KB
/
Filespace+SuggestionService.swift
File metadata and controls
86 lines (73 loc) · 2.72 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
import Foundation
import SuggestionModel
import Workspace
struct FilespaceSuggestionSnapshot: Equatable {
var linesHash: Int
var cursorPosition: CursorPosition
}
struct FilespaceSuggestionSnapshotKey: FilespacePropertyKey {
static func createDefaultValue()
-> FilespaceSuggestionSnapshot { .init(linesHash: -1, cursorPosition: .outOfScope) }
}
extension FilespacePropertyValues {
var suggestionSourceSnapshot: FilespaceSuggestionSnapshot {
get { self[FilespaceSuggestionSnapshotKey.self] }
set { self[FilespaceSuggestionSnapshotKey.self] = newValue }
}
}
extension Filespace {
func resetSnapshot() {
// swiftformat:disable redundantSelf
self.suggestionSourceSnapshot = FilespaceSuggestionSnapshotKey.createDefaultValue()
// swiftformat:enable all
}
/// Validate the suggestion is still valid.
/// - Parameters:
/// - lines: lines of the file
/// - cursorPosition: cursor position
/// - Returns: `true` if the suggestion is still valid
@WorkspaceActor
func validateSuggestions(lines: [String], cursorPosition: CursorPosition) -> Bool {
guard let presentingSuggestion else { return false }
// cursor has moved to another line
if cursorPosition.line != presentingSuggestion.position.line {
reset()
resetSnapshot()
return false
}
// the cursor position is valid
guard cursorPosition.line >= 0, cursorPosition.line < lines.count else {
reset()
resetSnapshot()
return false
}
let editingLine = lines[cursorPosition.line].dropLast(1) // dropping \n
let suggestionLines = presentingSuggestion.text.split(separator: "\n")
let suggestionFirstLine = suggestionLines.first ?? ""
// the line content doesn't match the suggestion
if cursorPosition.character > 0,
!suggestionFirstLine.hasPrefix(editingLine[..<(editingLine.index(
editingLine.startIndex,
offsetBy: cursorPosition.character,
limitedBy: editingLine.endIndex
) ?? editingLine.endIndex)])
{
reset()
resetSnapshot()
return false
}
// finished typing the whole suggestion when the suggestion has only one line
if editingLine.hasPrefix(suggestionFirstLine), suggestionLines.count <= 1 {
reset()
resetSnapshot()
return false
}
// undo to a state before the suggestion was generated
if editingLine.count < presentingSuggestion.position.character {
reset()
resetSnapshot()
return false
}
return true
}
}