1use crate::{motion::Motion, Vim};
2use editor::Bias;
3use gpui::MutableAppContext;
4use language::SelectionGoal;
5
6pub fn delete_over(vim: &mut Vim, motion: Motion, cx: &mut MutableAppContext) {
7 vim.update_active_editor(cx, |editor, cx| {
8 editor.transact(cx, |editor, cx| {
9 editor.set_clip_at_line_ends(false, cx);
10 editor.move_selections(cx, |map, selection| {
11 let original_head = selection.head();
12 motion.expand_selection(map, selection, true);
13 selection.goal = SelectionGoal::Column(original_head.column());
14 });
15 editor.insert(&"", cx);
16
17 // Fixup cursor position after the deletion
18 editor.set_clip_at_line_ends(true, cx);
19 editor.move_cursors(cx, |map, mut cursor, goal| {
20 if motion.linewise() {
21 if let SelectionGoal::Column(column) = goal {
22 *cursor.column_mut() = column
23 }
24 }
25
26 (map.clip_point(cursor, Bias::Left), SelectionGoal::None)
27 });
28 });
29 });
30}
31
32#[cfg(test)]
33mod test {
34 use indoc::indoc;
35
36 use crate::vim_test_context::VimTestContext;
37
38 #[gpui::test]
39 async fn test_delete_h(cx: &mut gpui::TestAppContext) {
40 let cx = VimTestContext::new(cx, true).await;
41 let mut cx = cx.binding(["d", "h"]);
42 cx.assert("Te|st", "T|st");
43 cx.assert("T|est", "|est");
44 cx.assert("|Test", "|Test");
45 cx.assert(
46 indoc! {"
47 Test
48 |test"},
49 indoc! {"
50 Test
51 |test"},
52 );
53 }
54
55 #[gpui::test]
56 async fn test_delete_l(cx: &mut gpui::TestAppContext) {
57 let cx = VimTestContext::new(cx, true).await;
58 let mut cx = cx.binding(["d", "l"]);
59 cx.assert("|Test", "|est");
60 cx.assert("Te|st", "Te|t");
61 cx.assert("Tes|t", "Te|s");
62 cx.assert(
63 indoc! {"
64 Tes|t
65 test"},
66 indoc! {"
67 Te|s
68 test"},
69 );
70 }
71
72 #[gpui::test]
73 async fn test_delete_w(cx: &mut gpui::TestAppContext) {
74 let cx = VimTestContext::new(cx, true).await;
75 let mut cx = cx.binding(["d", "w"]);
76 cx.assert("Te|st", "T|e");
77 cx.assert("T|est test", "T|test");
78 cx.assert(
79 indoc! {"
80 Test te|st
81 test"},
82 indoc! {"
83 Test t|e
84 test"},
85 );
86 cx.assert(
87 indoc! {"
88 Test tes|t
89 test"},
90 indoc! {"
91 Test te|s
92 test"},
93 );
94 cx.assert(
95 indoc! {"
96 Test test
97 |
98 test"},
99 indoc! {"
100 Test test
101 |
102 test"},
103 );
104
105 let mut cx = cx.binding(["d", "shift-W"]);
106 cx.assert("Test te|st-test test", "Test te|test");
107 }
108
109 #[gpui::test]
110 async fn test_delete_e(cx: &mut gpui::TestAppContext) {
111 let cx = VimTestContext::new(cx, true).await;
112 let mut cx = cx.binding(["d", "e"]);
113 cx.assert("Te|st Test", "Te| Test");
114 cx.assert("T|est test", "T| test");
115 cx.assert(
116 indoc! {"
117 Test te|st
118 test"},
119 indoc! {"
120 Test t|e
121 test"},
122 );
123 cx.assert(
124 indoc! {"
125 Test tes|t
126 test"},
127 "Test te|s",
128 );
129 cx.assert(
130 indoc! {"
131 Test test
132 |
133 test"},
134 indoc! {"
135 Test test
136 |
137 test"},
138 );
139
140 let mut cx = cx.binding(["d", "shift-E"]);
141 cx.assert("Test te|st-test test", "Test te| test");
142 }
143
144 #[gpui::test]
145 async fn test_delete_b(cx: &mut gpui::TestAppContext) {
146 let cx = VimTestContext::new(cx, true).await;
147 let mut cx = cx.binding(["d", "b"]);
148 cx.assert("Te|st Test", "|st Test");
149 cx.assert("Test |test", "|test");
150 cx.assert("Test1 test2 |test3", "Test1 |test3");
151 cx.assert(
152 indoc! {"
153 Test test
154 |test"},
155 // Trailing whitespace after cursor
156 indoc! {"
157 Test|
158 test"},
159 );
160 cx.assert(
161 indoc! {"
162 Test test
163 |
164 test"},
165 // Trailing whitespace after cursor
166 indoc! {"
167 Test|
168
169 test"},
170 );
171
172 let mut cx = cx.binding(["d", "shift-B"]);
173 cx.assert("Test test-test |test", "Test |test");
174 }
175
176 #[gpui::test]
177 async fn test_delete_end_of_line(cx: &mut gpui::TestAppContext) {
178 let cx = VimTestContext::new(cx, true).await;
179 let mut cx = cx.binding(["d", "shift-$"]);
180 cx.assert(
181 indoc! {"
182 The q|uick
183 brown fox"},
184 indoc! {"
185 The |q
186 brown fox"},
187 );
188 cx.assert(
189 indoc! {"
190 The quick
191 |
192 brown fox"},
193 indoc! {"
194 The quick
195 |
196 brown fox"},
197 );
198 }
199
200 #[gpui::test]
201 async fn test_delete_0(cx: &mut gpui::TestAppContext) {
202 let cx = VimTestContext::new(cx, true).await;
203 let mut cx = cx.binding(["d", "0"]);
204 cx.assert(
205 indoc! {"
206 The q|uick
207 brown fox"},
208 indoc! {"
209 |uick
210 brown fox"},
211 );
212 cx.assert(
213 indoc! {"
214 The quick
215 |
216 brown fox"},
217 indoc! {"
218 The quick
219 |
220 brown fox"},
221 );
222 }
223
224 #[gpui::test]
225 async fn test_delete_k(cx: &mut gpui::TestAppContext) {
226 let cx = VimTestContext::new(cx, true).await;
227 let mut cx = cx.binding(["d", "k"]);
228 cx.assert(
229 indoc! {"
230 The quick
231 brown |fox
232 jumps over"},
233 "jumps |over",
234 );
235 cx.assert(
236 indoc! {"
237 The quick
238 brown fox
239 jumps |over"},
240 "The qu|ick",
241 );
242 cx.assert(
243 indoc! {"
244 The q|uick
245 brown fox
246 jumps over"},
247 indoc! {"
248 brown| fox
249 jumps over"},
250 );
251 cx.assert(
252 indoc! {"
253 |brown fox
254 jumps over"},
255 "|jumps over",
256 );
257 }
258
259 #[gpui::test]
260 async fn test_delete_j(cx: &mut gpui::TestAppContext) {
261 let cx = VimTestContext::new(cx, true).await;
262 let mut cx = cx.binding(["d", "j"]);
263 cx.assert(
264 indoc! {"
265 The quick
266 brown |fox
267 jumps over"},
268 "The qu|ick",
269 );
270 cx.assert(
271 indoc! {"
272 The quick
273 brown fox
274 jumps |over"},
275 indoc! {"
276 The quick
277 brown |fox"},
278 );
279 cx.assert(
280 indoc! {"
281 The q|uick
282 brown fox
283 jumps over"},
284 "jumps| over",
285 );
286 cx.assert(
287 indoc! {"
288 The quick
289 brown fox
290 |"},
291 indoc! {"
292 The quick
293 |brown fox"},
294 );
295 }
296
297 #[gpui::test]
298 async fn test_delete_end_of_document(cx: &mut gpui::TestAppContext) {
299 let cx = VimTestContext::new(cx, true).await;
300 let mut cx = cx.binding(["d", "shift-G"]);
301 cx.assert(
302 indoc! {"
303 The quick
304 brown| fox
305 jumps over
306 the lazy"},
307 "The q|uick",
308 );
309 cx.assert(
310 indoc! {"
311 The quick
312 brown| fox
313 jumps over
314 the lazy"},
315 "The q|uick",
316 );
317 cx.assert(
318 indoc! {"
319 The quick
320 brown fox
321 jumps over
322 the l|azy"},
323 indoc! {"
324 The quick
325 brown fox
326 jumps| over"},
327 );
328 cx.assert(
329 indoc! {"
330 The quick
331 brown fox
332 jumps over
333 |"},
334 indoc! {"
335 The quick
336 brown fox
337 |jumps over"},
338 );
339 }
340
341 #[gpui::test]
342 async fn test_delete_gg(cx: &mut gpui::TestAppContext) {
343 let cx = VimTestContext::new(cx, true).await;
344 let mut cx = cx.binding(["d", "g", "g"]);
345 cx.assert(
346 indoc! {"
347 The quick
348 brown| fox
349 jumps over
350 the lazy"},
351 indoc! {"
352 jumps| over
353 the lazy"},
354 );
355 cx.assert(
356 indoc! {"
357 The quick
358 brown fox
359 jumps over
360 the l|azy"},
361 "|",
362 );
363 cx.assert(
364 indoc! {"
365 The q|uick
366 brown fox
367 jumps over
368 the lazy"},
369 indoc! {"
370 brown| fox
371 jumps over
372 the lazy"},
373 );
374 cx.assert(
375 indoc! {"
376 |
377 brown fox
378 jumps over
379 the lazy"},
380 indoc! {"
381 |brown fox
382 jumps over
383 the lazy"},
384 );
385 }
386}