Skip to content

Commit 61a0a78

Browse files
committed
Update validateSuggestions to handle emojis
1 parent 54a70ef commit 61a0a78

2 files changed

Lines changed: 103 additions & 9 deletions

File tree

Core/Tests/ServiceTests/FilespaceSuggestionInvalidationTests.swift

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,53 @@ class FilespaceSuggestionInvalidationTests: XCTestCase {
5555
let suggestion = filespace.presentingSuggestion
5656
XCTAssertNotNil(suggestion)
5757
}
58+
59+
func test_text_typing_suggestion_with_emoji_in_the_middle_should_be_valid() async throws {
60+
let filespace = try await prepare(
61+
suggestionText: "hello🎆🎆 man",
62+
cursorPosition: .init(line: 1, character: 0),
63+
range: .init(startPair: (1, 0), endPair: (1, 0))
64+
)
65+
let isValid = await filespace.validateSuggestions(
66+
lines: ["\n", "hell🎆🎆 man\n", "\n"],
67+
cursorPosition: .init(line: 1, character: 4)
68+
)
69+
XCTAssertTrue(isValid)
70+
let suggestion = filespace.presentingSuggestion
71+
XCTAssertNotNil(suggestion)
72+
}
73+
74+
func test_text_typing_suggestion_typed_emoji_in_the_middle_should_be_valid() async throws {
75+
let filespace = try await prepare(
76+
suggestionText: "h🎆🎆o man",
77+
cursorPosition: .init(line: 1, character: 0),
78+
range: .init(startPair: (1, 0), endPair: (1, 0))
79+
)
80+
let isValid = await filespace.validateSuggestions(
81+
lines: ["\n", "h🎆🎆o man\n", "\n"],
82+
cursorPosition: .init(line: 1, character: 2)
83+
)
84+
XCTAssertTrue(isValid)
85+
let suggestion = filespace.presentingSuggestion
86+
XCTAssertNotNil(suggestion)
87+
}
88+
89+
func test_text_typing_suggestion_cutting_emoji_in_the_middle_should_be_valid() async throws {
90+
// undefined behavior, must not crash
91+
92+
let filespace = try await prepare(
93+
suggestionText: "h🎆🎆o man",
94+
cursorPosition: .init(line: 1, character: 0),
95+
range: .init(startPair: (1, 0), endPair: (1, 0))
96+
)
97+
let isValid = await filespace.validateSuggestions(
98+
lines: ["\n", "h🎆🎆o man\n", "\n"],
99+
cursorPosition: .init(line: 1, character: 3)
100+
)
101+
XCTAssertTrue(isValid)
102+
let suggestion = filespace.presentingSuggestion
103+
XCTAssertNotNil(suggestion)
104+
}
58105

59106
func test_text_cursor_moved_to_another_line_should_invalidate() async throws {
60107
let filespace = try await prepare(
@@ -122,10 +169,35 @@ class FilespaceSuggestionInvalidationTests: XCTestCase {
122169
cursorPosition: .init(line: 1, character: 0),
123170
range: .init(startPair: (1, 0), endPair: (1, 0))
124171
)
172+
let wasValid = await filespace.validateSuggestions(
173+
lines: ["\n", "hello man\n", "\n"],
174+
cursorPosition: .init(line: 1, character: 8)
175+
)
125176
let isValid = await filespace.validateSuggestions(
126177
lines: ["\n", "hello man\n", "\n"],
127178
cursorPosition: .init(line: 1, character: 9)
128179
)
180+
XCTAssertTrue(wasValid)
181+
XCTAssertFalse(isValid)
182+
let suggestion = filespace.presentingSuggestion
183+
XCTAssertNil(suggestion)
184+
}
185+
186+
func test_finish_typing_the_whole_single_line_suggestion_with_emoji_should_invalidate() async throws {
187+
let filespace = try await prepare(
188+
suggestionText: "hello m🎆🎆an",
189+
cursorPosition: .init(line: 1, character: 0),
190+
range: .init(startPair: (1, 0), endPair: (1, 0))
191+
)
192+
let wasValid = await filespace.validateSuggestions(
193+
lines: ["\n", "hello m🎆🎆an\n", "\n"],
194+
cursorPosition: .init(line: 1, character: 12)
195+
)
196+
let isValid = await filespace.validateSuggestions(
197+
lines: ["\n", "hello m🎆🎆an\n", "\n"],
198+
cursorPosition: .init(line: 1, character: 13)
199+
)
200+
XCTAssertTrue(wasValid)
129201
XCTAssertFalse(isValid)
130202
let suggestion = filespace.presentingSuggestion
131203
XCTAssertNil(suggestion)
@@ -138,10 +210,15 @@ class FilespaceSuggestionInvalidationTests: XCTestCase {
138210
cursorPosition: .init(line: 1, character: 0),
139211
range: .init(startPair: (1, 0), endPair: (1, 0))
140212
)
213+
let wasValid = await filespace.validateSuggestions(
214+
lines: ["\n", "hello man!!!!!\n", "\n"],
215+
cursorPosition: .init(line: 1, character: 8)
216+
)
141217
let isValid = await filespace.validateSuggestions(
142218
lines: ["\n", "hello man!!!!!\n", "\n"],
143219
cursorPosition: .init(line: 1, character: 9)
144220
)
221+
XCTAssertTrue(wasValid)
145222
XCTAssertFalse(isValid)
146223
let suggestion = filespace.presentingSuggestion
147224
XCTAssertNil(suggestion)
@@ -161,6 +238,21 @@ class FilespaceSuggestionInvalidationTests: XCTestCase {
161238
let suggestion = filespace.presentingSuggestion
162239
XCTAssertNotNil(suggestion)
163240
}
241+
242+
func test_finish_typing_the_whole_multiple_line_suggestion_with_emoji_should_be_valid() async throws {
243+
let filespace = try await prepare(
244+
suggestionText: "hello m🎆🎆an\nhow are you?",
245+
cursorPosition: .init(line: 1, character: 0),
246+
range: .init(startPair: (1, 0), endPair: (1, 0))
247+
)
248+
let isValid = await filespace.validateSuggestions(
249+
lines: ["\n", "hello m🎆🎆an\n", "\n"],
250+
cursorPosition: .init(line: 1, character: 13)
251+
)
252+
XCTAssertTrue(isValid)
253+
let suggestion = filespace.presentingSuggestion
254+
XCTAssertNotNil(suggestion)
255+
}
164256

165257
func test_undo_text_to_a_state_before_the_suggestion_was_generated_should_invalidate(
166258
) async throws {

Tool/Sources/WorkspaceSuggestionService/Filespace+SuggestionService.swift

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,22 @@ public extension Filespace {
8282
"Generating suggestion with invalid range"
8383
)
8484

85-
let startIndex = editingLine.index(
86-
editingLine.startIndex,
85+
let uff16View = editingLine.utf16
86+
87+
let startIndex = uff16View.index(
88+
uff16View.startIndex,
8789
offsetBy: max(0, presentingSuggestion.range.start.character),
88-
limitedBy: editingLine.endIndex
89-
) ?? editingLine.startIndex
90+
limitedBy: uff16View.endIndex
91+
) ?? uff16View.startIndex
9092

91-
let endIndex = editingLine.index(
92-
editingLine.startIndex,
93+
let endIndex = uff16View.index(
94+
uff16View.startIndex,
9395
offsetBy: cursorPosition.character,
94-
limitedBy: editingLine.endIndex
95-
) ?? editingLine.endIndex
96+
limitedBy: uff16View.endIndex
97+
) ?? uff16View.endIndex
9698

9799
if endIndex > startIndex {
98-
return String(editingLine[startIndex..<endIndex])
100+
return String(uff16View[startIndex..<endIndex]) ?? ""
99101
}
100102

101103
return ""

0 commit comments

Comments
 (0)