Skip to content

Commit 933c7a2

Browse files
committed
Add Mock Completion Delegate To Example
1 parent af114f9 commit 933c7a2

File tree

6 files changed

+93
-7
lines changed

6 files changed

+93
-7
lines changed

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
6C1365462B8A7F2D004A1D18 /* LanguagePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C1365452B8A7F2D004A1D18 /* LanguagePicker.swift */; };
2121
6C1365482B8A7FBF004A1D18 /* EditorTheme+Default.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C1365472B8A7FBF004A1D18 /* EditorTheme+Default.swift */; };
2222
6C13654D2B8A821E004A1D18 /* NSColor+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C13654C2B8A821E004A1D18 /* NSColor+Hex.swift */; };
23+
6C8B564C2E3018CC00DC3F29 /* MockCompletionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8B564B2E3018CC00DC3F29 /* MockCompletionDelegate.swift */; };
2324
6CF31D4E2DB6A252006A77FD /* StatusBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF31D4D2DB6A252006A77FD /* StatusBar.swift */; };
2425
/* End PBXBuildFile section */
2526

@@ -38,6 +39,7 @@
3839
6C1365452B8A7F2D004A1D18 /* LanguagePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguagePicker.swift; sourceTree = "<group>"; };
3940
6C1365472B8A7FBF004A1D18 /* EditorTheme+Default.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EditorTheme+Default.swift"; sourceTree = "<group>"; };
4041
6C13654C2B8A821E004A1D18 /* NSColor+Hex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSColor+Hex.swift"; sourceTree = "<group>"; };
42+
6C8B564B2E3018CC00DC3F29 /* MockCompletionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCompletionDelegate.swift; sourceTree = "<group>"; };
4143
6CF31D4D2DB6A252006A77FD /* StatusBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusBar.swift; sourceTree = "<group>"; };
4244
/* End PBXFileReference section */
4345

@@ -116,6 +118,7 @@
116118
6C13654A2B8A7FD2004A1D18 /* Views */ = {
117119
isa = PBXGroup;
118120
children = (
121+
6C8B564B2E3018CC00DC3F29 /* MockCompletionDelegate.swift */,
119122
6C1365312B8A7B94004A1D18 /* ContentView.swift */,
120123
6CF31D4D2DB6A252006A77FD /* StatusBar.swift */,
121124
6C1365452B8A7F2D004A1D18 /* LanguagePicker.swift */,
@@ -215,6 +218,7 @@
215218
6CF31D4E2DB6A252006A77FD /* StatusBar.swift in Sources */,
216219
6C13652E2B8A7B94004A1D18 /* CodeEditSourceEditorExampleApp.swift in Sources */,
217220
6C1365442B8A7EED004A1D18 /* String+Lines.swift in Sources */,
221+
6C8B564C2E3018CC00DC3F29 /* MockCompletionDelegate.swift in Sources */,
218222
1CB30C3A2DAA1C28008058A7 /* IndentPicker.swift in Sources */,
219223
6C1365322B8A7B94004A1D18 /* ContentView.swift in Sources */,
220224
6C1365462B8A7F2D004A1D18 /* LanguagePicker.swift in Sources */,

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/ContentView.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ struct ContentView: View {
2222
@State private var editorState = SourceEditorState(
2323
cursorPositions: [CursorPosition(line: 1, column: 1)]
2424
)
25+
@StateObject private var suggestions: MockCompletionDelegate = MockCompletionDelegate()
2526

2627
@State private var font: NSFont = NSFont.monospacedSystemFont(ofSize: 12, weight: .medium)
2728
@AppStorage("wrapLines") private var wrapLines: Bool = true
@@ -71,7 +72,8 @@ struct ContentView: View {
7172
warningCharacters: warningCharacters
7273
)
7374
),
74-
state: $editorState
75+
state: $editorState,
76+
completionDelegate: suggestions
7577
)
7678
.overlay(alignment: .bottom) {
7779
StatusBar(
@@ -88,7 +90,7 @@ struct ContentView: View {
8890
indentOption: $indentOption,
8991
reformatAtColumn: $reformatAtColumn,
9092
showReformattingGuide: $showReformattingGuide,
91-
showFoldingRibbon: $showFoldingRibbon
93+
showFoldingRibbon: $showFoldingRibbon,
9294
invisibles: $invisibleCharactersConfig,
9395
warningCharacters: $warningCharacters
9496
)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//
2+
// MockCompletionDelegate.swift
3+
// CodeEditSourceEditorExample
4+
//
5+
// Created by Khan Winter on 7/22/25.
6+
//
7+
8+
import AppKit
9+
import CodeEditSourceEditor
10+
import CodeEditTextView
11+
12+
class MockCompletionDelegate: CodeSuggestionDelegate, ObservableObject {
13+
class Suggestion: CodeSuggestionEntry {
14+
let text: String
15+
var view: NSView {
16+
let view = NSTextField(string: text)
17+
view.isEditable = false
18+
view.isSelectable = false
19+
view.isBezeled = false
20+
view.isBordered = false
21+
view.backgroundColor = .clear
22+
view.textColor = .black
23+
return view
24+
}
25+
26+
init(text: String) {
27+
self.text = text
28+
}
29+
}
30+
31+
func completionSuggestionsRequested(
32+
textView: TextViewController,
33+
cursorPosition: CursorPosition
34+
) async -> (windowPosition: CursorPosition, items: [CodeSuggestionEntry])? {
35+
try? await Task.sleep(for: .seconds(0.2))
36+
return (cursorPosition, [Suggestion(text: "Hello"), Suggestion(text: "World")])
37+
}
38+
39+
func completionOnCursorMove(
40+
textView: TextViewController,
41+
cursorPosition: CursorPosition
42+
) -> [CodeSuggestionEntry]? {
43+
if Bool.random() {
44+
[Suggestion(text: "Another one")]
45+
} else {
46+
nil
47+
}
48+
}
49+
50+
func completionWindowApplyCompletion(
51+
item: CodeSuggestionEntry,
52+
textView: TextViewController,
53+
cursorPosition: CursorPosition
54+
) {
55+
guard let suggestion = item as? Suggestion else {
56+
return
57+
}
58+
textView.textView.undoManager?.beginUndoGrouping()
59+
textView.textView.insertText(suggestion.text)
60+
textView.textView.undoManager?.endUndoGrouping()
61+
}
62+
}

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/StatusBar.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ struct StatusBar: View {
104104
}
105105
}
106106
scrollPosition
107-
Text(getLabel(state.cursorPositions))
107+
Text(getLabel(state.cursorPositions ?? []))
108108
}
109109
.foregroundStyle(.secondary)
110110

@@ -118,9 +118,9 @@ struct StatusBar: View {
118118
.foregroundStyle(.secondary)
119119

120120
Button {
121-
state.findPanelVisible.toggle()
121+
state.findPanelVisible?.toggle()
122122
} label: {
123-
Text(state.findPanelVisible ? "Hide" : "Show") + Text(" Find")
123+
Text((state.findPanelVisible ?? false) ? "Hide" : "Show") + Text(" Find")
124124
}
125125
.buttonStyle(.borderless)
126126
.foregroundStyle(.secondary)

Sources/CodeEditSourceEditor/SourceEditor/SourceEditor.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ public struct SourceEditor: NSViewControllerRepresentable {
3535
state: Binding<SourceEditorState>,
3636
highlightProviders: [any HighlightProviding]? = nil,
3737
undoManager: CEUndoManager? = nil,
38-
coordinators: [any TextViewCoordinator] = []
38+
coordinators: [any TextViewCoordinator] = [],
39+
completionDelegate: CodeSuggestionDelegate? = nil
3940
) {
4041
self.text = .binding(text)
4142
self.language = language
@@ -44,6 +45,7 @@ public struct SourceEditor: NSViewControllerRepresentable {
4445
self.highlightProviders = highlightProviders
4546
self.undoManager = undoManager
4647
self.coordinators = coordinators
48+
self.completionDelegate = completionDelegate
4749
}
4850

4951
/// Initializes a new source editor
@@ -64,7 +66,8 @@ public struct SourceEditor: NSViewControllerRepresentable {
6466
state: Binding<SourceEditorState>,
6567
highlightProviders: [any HighlightProviding]? = nil,
6668
undoManager: CEUndoManager? = nil,
67-
coordinators: [any TextViewCoordinator] = []
69+
coordinators: [any TextViewCoordinator] = [],
70+
completionDelegate: CodeSuggestionDelegate? = nil
6871
) {
6972
self.text = .storage(text)
7073
self.language = language
@@ -73,6 +76,7 @@ public struct SourceEditor: NSViewControllerRepresentable {
7376
self.highlightProviders = highlightProviders
7477
self.undoManager = undoManager
7578
self.coordinators = coordinators
79+
self.completionDelegate = completionDelegate
7680
}
7781

7882
var text: TextAPI
@@ -82,6 +86,7 @@ public struct SourceEditor: NSViewControllerRepresentable {
8286
var highlightProviders: [any HighlightProviding]?
8387
var undoManager: CEUndoManager?
8488
var coordinators: [any TextViewCoordinator]
89+
weak var completionDelegate: CodeSuggestionDelegate?
8590

8691
public typealias NSViewControllerType = TextViewController
8792

@@ -108,6 +113,8 @@ public struct SourceEditor: NSViewControllerRepresentable {
108113
controller.setCursorPositions(state.cursorPositions ?? [])
109114
}
110115

116+
controller.completionDelegate = completionDelegate
117+
111118
context.coordinator.setController(controller)
112119
return controller
113120
}
@@ -117,6 +124,8 @@ public struct SourceEditor: NSViewControllerRepresentable {
117124
}
118125

119126
public func updateNSViewController(_ controller: TextViewController, context: Context) {
127+
controller.completionDelegate = completionDelegate
128+
120129
context.coordinator.updateHighlightProviders(highlightProviders)
121130

122131
// Prevent infinite loop of update notifications

0 commit comments

Comments
 (0)