forked from CodeEditApp/CodeEditSourceEditor
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSuggestionTriggerCharacterModel.swift
More file actions
69 lines (60 loc) · 2.26 KB
/
SuggestionTriggerCharacterModel.swift
File metadata and controls
69 lines (60 loc) · 2.26 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
//
// SuggestionTriggerCharacterModel.swift
// CodeEditSourceEditor
//
// Created by Khan Winter on 8/25/25.
//
import AppKit
import CodeEditTextView
import TextStory
/// Triggers the suggestion window when trigger characters are typed.
/// Designed to be called in the ``TextViewDelegate``'s didReplaceCharacters method.
///
/// Was originally a `TextFilter` model, however those are called before text is changed and cursors are updated.
/// The suggestion model expects up-to-date cursor positions as well as complete text contents. This being
/// essentially a textview delegate ensures both of those promises are upheld.
@MainActor
final class SuggestionTriggerCharacterModel {
weak var controller: TextViewController?
private var lastPosition: NSRange?
func textView(_ textView: TextView, didReplaceContentsIn range: NSRange, with string: String) {
guard let controller, let completionDelegate = controller.completionDelegate else {
return
}
let triggerCharacters = completionDelegate.completionTriggerCharacters()
let mutation = TextMutation(
string: string,
range: range,
limit: textView.textStorage.length
)
guard mutation.delta >= 0,
let lastChar = mutation.string.last else {
lastPosition = nil
return
}
guard triggerCharacters.contains(String(lastChar)) || lastChar.isNumber || lastChar.isLetter else {
lastPosition = nil
return
}
let range = NSRange(location: mutation.postApplyRange.max, length: 0)
lastPosition = range
SuggestionController.shared.cursorsUpdated(
textView: controller,
delegate: completionDelegate,
position: CursorPosition(range: range),
presentIfNot: true
)
}
func selectionUpdated(_ position: CursorPosition) {
guard let controller, let completionDelegate = controller.completionDelegate else {
return
}
if lastPosition != position.range {
SuggestionController.shared.cursorsUpdated(
textView: controller,
delegate: completionDelegate,
position: position
)
}
}
}