Skip to content

Commit ed2e4f4

Browse files
committed
Adjust suggestion validation to allow suggestions to rewrite the lines
1 parent 90b2977 commit ed2e4f4

File tree

4 files changed

+187
-98
lines changed

4 files changed

+187
-98
lines changed

Core/Sources/Service/SuggestionCommandHandler/PseudoCommandHandler.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ struct PseudoCommandHandler: CommandHandler {
8787
}
8888

8989
let snapshot = FilespaceSuggestionSnapshot(
90-
linesHash: editor.lines.hashValue,
90+
lines: editor.lines,
9191
cursorPosition: editor.cursorPosition
9292
)
9393

Core/Tests/ServiceTests/FilespaceSuggestionInvalidationTests.swift

Lines changed: 94 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import XCTest
88
class FilespaceSuggestionInvalidationTests: XCTestCase {
99
@WorkspaceActor
1010
func prepare(
11+
lines: [String],
1112
suggestionText: String,
1213
cursorPosition: CursorPosition,
1314
range: CursorRange
@@ -23,17 +24,20 @@ class FilespaceSuggestionInvalidationTests: XCTestCase {
2324
range: range
2425
),
2526
]
27+
filespace.suggestionSourceSnapshot = .init(lines: lines, cursorPosition: cursorPosition)
2628
return filespace
2729
}
2830

2931
func test_text_typing_suggestion_should_be_valid() async throws {
32+
let lines = ["\n", "hell\n", "\n"]
3033
let filespace = try await prepare(
34+
lines: lines,
3135
suggestionText: "hello man",
3236
cursorPosition: .init(line: 1, character: 0),
3337
range: .init(startPair: (1, 0), endPair: (1, 0))
3438
)
3539
let isValid = await filespace.validateSuggestions(
36-
lines: ["\n", "hell\n", "\n"],
40+
lines: lines,
3741
cursorPosition: .init(line: 1, character: 4)
3842
)
3943
XCTAssertTrue(isValid)
@@ -42,60 +46,69 @@ class FilespaceSuggestionInvalidationTests: XCTestCase {
4246
}
4347

4448
func test_text_typing_suggestion_in_the_middle_should_be_valid() async throws {
49+
let lines = ["\n", "hell man\n", "\n"]
4550
let filespace = try await prepare(
51+
lines: lines,
4652
suggestionText: "hello man",
4753
cursorPosition: .init(line: 1, character: 0),
4854
range: .init(startPair: (1, 0), endPair: (1, 0))
4955
)
5056
let isValid = await filespace.validateSuggestions(
51-
lines: ["\n", "hell man\n", "\n"],
57+
lines: lines,
5258
cursorPosition: .init(line: 1, character: 4)
5359
)
5460
XCTAssertTrue(isValid)
5561
let suggestion = filespace.presentingSuggestion
5662
XCTAssertNotNil(suggestion)
5763
}
58-
64+
5965
func test_text_typing_suggestion_with_emoji_in_the_middle_should_be_valid() async throws {
66+
let lines = ["\n", "hell🎆🎆 man\n", "\n"]
6067
let filespace = try await prepare(
68+
lines: lines,
6169
suggestionText: "hello🎆🎆 man",
6270
cursorPosition: .init(line: 1, character: 0),
6371
range: .init(startPair: (1, 0), endPair: (1, 0))
6472
)
6573
let isValid = await filespace.validateSuggestions(
66-
lines: ["\n", "hell🎆🎆 man\n", "\n"],
74+
lines: lines,
6775
cursorPosition: .init(line: 1, character: 4)
6876
)
6977
XCTAssertTrue(isValid)
7078
let suggestion = filespace.presentingSuggestion
7179
XCTAssertNotNil(suggestion)
7280
}
73-
81+
7482
func test_text_typing_suggestion_typed_emoji_in_the_middle_should_be_valid() async throws {
83+
let lines = ["\n", "h🎆🎆o ma\n", "\n"]
7584
let filespace = try await prepare(
85+
lines: lines,
7686
suggestionText: "h🎆🎆o man",
7787
cursorPosition: .init(line: 1, character: 0),
7888
range: .init(startPair: (1, 0), endPair: (1, 0))
7989
)
8090
let isValid = await filespace.validateSuggestions(
81-
lines: ["\n", "h🎆🎆o ma\n", "\n"],
91+
lines: lines,
8292
cursorPosition: .init(line: 1, character: 2)
8393
)
8494
XCTAssertTrue(isValid)
8595
let suggestion = filespace.presentingSuggestion
8696
XCTAssertNotNil(suggestion)
8797
}
88-
98+
8999
func test_text_typing_suggestion_cutting_emoji_in_the_middle_should_be_valid() async throws {
90100
// undefined behavior, must not crash
91-
101+
102+
let lines = ["\n", "h🎆🎆o ma\n", "\n"]
103+
92104
let filespace = try await prepare(
105+
lines: lines,
93106
suggestionText: "h🎆🎆o man",
94107
cursorPosition: .init(line: 1, character: 0),
95108
range: .init(startPair: (1, 0), endPair: (1, 0))
96109
)
97110
let isValid = await filespace.validateSuggestions(
98-
lines: ["\n", "h🎆🎆o ma\n", "\n"],
111+
lines: lines,
99112
cursorPosition: .init(line: 1, character: 3)
100113
)
101114
XCTAssertTrue(isValid)
@@ -104,13 +117,15 @@ class FilespaceSuggestionInvalidationTests: XCTestCase {
104117
}
105118

106119
func test_text_cursor_moved_to_another_line_should_invalidate() async throws {
120+
let lines = ["\n", "hell\n", "\n"]
107121
let filespace = try await prepare(
122+
lines: lines,
108123
suggestionText: "hello man",
109124
cursorPosition: .init(line: 1, character: 0),
110125
range: .init(startPair: (1, 0), endPair: (1, 0))
111126
)
112127
let isValid = await filespace.validateSuggestions(
113-
lines: ["\n", "hell\n", "\n"],
128+
lines: lines,
114129
cursorPosition: .init(line: 2, character: 0)
115130
)
116131
XCTAssertFalse(isValid)
@@ -119,13 +134,15 @@ class FilespaceSuggestionInvalidationTests: XCTestCase {
119134
}
120135

121136
func test_text_cursor_is_invalid_should_invalidate() async throws {
137+
let lines = ["\n", "hell\n", "\n"]
122138
let filespace = try await prepare(
139+
lines: lines,
123140
suggestionText: "hello man",
124141
cursorPosition: .init(line: 100, character: 0),
125142
range: .init(startPair: (1, 0), endPair: (1, 0))
126143
)
127144
let isValid = await filespace.validateSuggestions(
128-
lines: ["\n", "hell\n", "\n"],
145+
lines: lines,
129146
cursorPosition: .init(line: 100, character: 4)
130147
)
131148
XCTAssertFalse(isValid)
@@ -135,9 +152,10 @@ class FilespaceSuggestionInvalidationTests: XCTestCase {
135152

136153
func test_line_content_does_not_match_input_should_invalidate() async throws {
137154
let filespace = try await prepare(
155+
lines: ["\n", "hello\n", "\n"],
138156
suggestionText: "hello man",
139-
cursorPosition: .init(line: 1, character: 0),
140-
range: .init(startPair: (1, 0), endPair: (1, 0))
157+
cursorPosition: .init(line: 1, character: 5),
158+
range: .init(startPair: (1, 0), endPair: (1, 5))
141159
)
142160
let isValid = await filespace.validateSuggestions(
143161
lines: ["\n", "helo\n", "\n"],
@@ -150,9 +168,10 @@ class FilespaceSuggestionInvalidationTests: XCTestCase {
150168

151169
func test_line_content_does_not_match_input_should_invalidate_index_out_of_scope() async throws {
152170
let filespace = try await prepare(
171+
lines: ["\n", "hello\n", "\n"],
153172
suggestionText: "hello man",
154-
cursorPosition: .init(line: 1, character: 0),
155-
range: .init(startPair: (1, 0), endPair: (1, 0))
173+
cursorPosition: .init(line: 1, character: 5),
174+
range: .init(startPair: (1, 0), endPair: (1, 5))
156175
)
157176
let isValid = await filespace.validateSuggestions(
158177
lines: ["\n", "helo\n", "\n"],
@@ -164,13 +183,15 @@ class FilespaceSuggestionInvalidationTests: XCTestCase {
164183
}
165184

166185
func test_finish_typing_the_whole_single_line_suggestion_should_invalidate() async throws {
186+
let lines = ["\n", "hello ma\n", "\n"]
167187
let filespace = try await prepare(
188+
lines: lines,
168189
suggestionText: "hello man",
169-
cursorPosition: .init(line: 1, character: 0),
170-
range: .init(startPair: (1, 0), endPair: (1, 0))
190+
cursorPosition: .init(line: 1, character: 8),
191+
range: .init(startPair: (1, 0), endPair: (1, 8))
171192
)
172193
let wasValid = await filespace.validateSuggestions(
173-
lines: ["\n", "hello ma\n", "\n"],
194+
lines: lines,
174195
cursorPosition: .init(line: 1, character: 8)
175196
)
176197
let isValid = await filespace.validateSuggestions(
@@ -182,15 +203,18 @@ class FilespaceSuggestionInvalidationTests: XCTestCase {
182203
let suggestion = filespace.presentingSuggestion
183204
XCTAssertNil(suggestion)
184205
}
185-
186-
func test_finish_typing_the_whole_single_line_suggestion_with_emoji_should_invalidate() async throws {
206+
207+
func test_finish_typing_the_whole_single_line_suggestion_with_emoji_should_invalidate(
208+
) async throws {
209+
let lines = ["\n", "hello m🎆🎆a\n", "\n"]
187210
let filespace = try await prepare(
211+
lines: lines,
188212
suggestionText: "hello m🎆🎆an",
189213
cursorPosition: .init(line: 1, character: 0),
190214
range: .init(startPair: (1, 0), endPair: (1, 0))
191215
)
192216
let wasValid = await filespace.validateSuggestions(
193-
lines: ["\n", "hello m🎆🎆a\n", "\n"],
217+
lines: lines,
194218
cursorPosition: .init(line: 1, character: 12)
195219
)
196220
let isValid = await filespace.validateSuggestions(
@@ -205,13 +229,15 @@ class FilespaceSuggestionInvalidationTests: XCTestCase {
205229

206230
func test_finish_typing_the_whole_single_line_suggestion_suggestion_is_incomplete_should_invalidate(
207231
) async throws {
232+
let lines = ["\n", "hello ma!!!!\n", "\n"]
208233
let filespace = try await prepare(
234+
lines: lines,
209235
suggestionText: "hello man",
210236
cursorPosition: .init(line: 1, character: 0),
211237
range: .init(startPair: (1, 0), endPair: (1, 0))
212238
)
213239
let wasValid = await filespace.validateSuggestions(
214-
lines: ["\n", "hello ma!!!!\n", "\n"],
240+
lines: lines,
215241
cursorPosition: .init(line: 1, character: 8)
216242
)
217243
let isValid = await filespace.validateSuggestions(
@@ -225,28 +251,33 @@ class FilespaceSuggestionInvalidationTests: XCTestCase {
225251
}
226252

227253
func test_finish_typing_the_whole_multiple_line_suggestion_should_be_valid() async throws {
254+
let lines = ["\n", "hello man\n", "\n"]
228255
let filespace = try await prepare(
256+
lines: lines,
229257
suggestionText: "hello man\nhow are you?",
230258
cursorPosition: .init(line: 1, character: 0),
231259
range: .init(startPair: (1, 0), endPair: (1, 0))
232260
)
233261
let isValid = await filespace.validateSuggestions(
234-
lines: ["\n", "hello man\n", "\n"],
262+
lines: lines,
235263
cursorPosition: .init(line: 1, character: 9)
236264
)
237265
XCTAssertTrue(isValid)
238266
let suggestion = filespace.presentingSuggestion
239267
XCTAssertNotNil(suggestion)
240268
}
241-
242-
func test_finish_typing_the_whole_multiple_line_suggestion_with_emoji_should_be_valid() async throws {
269+
270+
func test_finish_typing_the_whole_multiple_line_suggestion_with_emoji_should_be_valid(
271+
) async throws {
272+
let lines = ["\n", "hello m🎆🎆an\n", "\n"]
243273
let filespace = try await prepare(
274+
lines: lines,
244275
suggestionText: "hello m🎆🎆an\nhow are you?",
245276
cursorPosition: .init(line: 1, character: 0),
246277
range: .init(startPair: (1, 0), endPair: (1, 0))
247278
)
248279
let isValid = await filespace.validateSuggestions(
249-
lines: ["\n", "hello m🎆🎆an\n", "\n"],
280+
lines: lines,
250281
cursorPosition: .init(line: 1, character: 13)
251282
)
252283
XCTAssertTrue(isValid)
@@ -256,18 +287,54 @@ class FilespaceSuggestionInvalidationTests: XCTestCase {
256287

257288
func test_undo_text_to_a_state_before_the_suggestion_was_generated_should_invalidate(
258289
) async throws {
290+
let lines = ["\n", "hell\n", "\n"]
259291
let filespace = try await prepare(
292+
lines: lines,
260293
suggestionText: "hello man",
261294
cursorPosition: .init(line: 1, character: 5), // generating man from hello
262295
range: .init(startPair: (1, 0), endPair: (1, 5))
263296
)
264297
let isValid = await filespace.validateSuggestions(
265-
lines: ["\n", "hell\n", "\n"],
298+
lines: lines,
266299
cursorPosition: .init(line: 1, character: 4)
267300
)
268301
XCTAssertFalse(isValid)
269302
let suggestion = filespace.presentingSuggestion
270303
XCTAssertNil(suggestion)
271304
}
305+
306+
func test_rewriting_the_current_line_by_removing_the_suffix_should_be_valid() async throws {
307+
let lines = ["hello world !!!\n"]
308+
let filespace = try await prepare(
309+
lines: lines,
310+
suggestionText: "hello world",
311+
cursorPosition: .init(line: 0, character: 15),
312+
range: .init(startPair: (0, 0), endPair: (0, 15))
313+
)
314+
let isValid = await filespace.validateSuggestions(
315+
lines: lines,
316+
cursorPosition: .init(line: 0, character: 15)
317+
)
318+
XCTAssertTrue(isValid)
319+
let suggestion = filespace.presentingSuggestion
320+
XCTAssertNotNil(suggestion)
321+
}
322+
323+
func test_rewriting_the_current_line_should_be_valid() async throws {
324+
let lines = ["hello everyone !!!\n"]
325+
let filespace = try await prepare(
326+
lines: lines,
327+
suggestionText: "hello world !!!",
328+
cursorPosition: .init(line: 0, character: 15),
329+
range: .init(startPair: (0, 0), endPair: (0, 15))
330+
)
331+
let isValid = await filespace.validateSuggestions(
332+
lines: lines,
333+
cursorPosition: .init(line: 0, character: 18)
334+
)
335+
XCTAssertTrue(isValid)
336+
let suggestion = filespace.presentingSuggestion
337+
XCTAssertNotNil(suggestion)
338+
}
272339
}
273340

0 commit comments

Comments
 (0)