1use super::*;
2use crate::language::LanguageServerConfig;
3use gpui::{ModelHandle, MutableAppContext};
4use std::{iter::FromIterator, rc::Rc};
5use unindent::Unindent as _;
6
7#[gpui::test]
8fn test_edit_events(cx: &mut gpui::MutableAppContext) {
9 let mut now = Instant::now();
10 let buffer_1_events = Rc::new(RefCell::new(Vec::new()));
11 let buffer_2_events = Rc::new(RefCell::new(Vec::new()));
12
13 let buffer1 = cx.add_model(|cx| Buffer::new(0, "abcdef", cx));
14 let buffer2 = cx.add_model(|cx| Buffer::new(1, "abcdef", cx));
15 let buffer_ops = buffer1.update(cx, |buffer, cx| {
16 let buffer_1_events = buffer_1_events.clone();
17 cx.subscribe(&buffer1, move |_, _, event, _| {
18 buffer_1_events.borrow_mut().push(event.clone())
19 })
20 .detach();
21 let buffer_2_events = buffer_2_events.clone();
22 cx.subscribe(&buffer2, move |_, _, event, _| {
23 buffer_2_events.borrow_mut().push(event.clone())
24 })
25 .detach();
26
27 // An edit emits an edited event, followed by a dirtied event,
28 // since the buffer was previously in a clean state.
29 buffer.edit(Some(2..4), "XYZ", cx);
30
31 // An empty transaction does not emit any events.
32 buffer.start_transaction(None).unwrap();
33 buffer.end_transaction(None, cx).unwrap();
34
35 // A transaction containing two edits emits one edited event.
36 now += Duration::from_secs(1);
37 buffer.start_transaction_at(None, now).unwrap();
38 buffer.edit(Some(5..5), "u", cx);
39 buffer.edit(Some(6..6), "w", cx);
40 buffer.end_transaction_at(None, now, cx).unwrap();
41
42 // Undoing a transaction emits one edited event.
43 buffer.undo(cx);
44
45 buffer.operations.clone()
46 });
47
48 // Incorporating a set of remote ops emits a single edited event,
49 // followed by a dirtied event.
50 buffer2.update(cx, |buffer, cx| {
51 buffer.apply_ops(buffer_ops, cx).unwrap();
52 });
53
54 let buffer_1_events = buffer_1_events.borrow();
55 assert_eq!(
56 *buffer_1_events,
57 vec![Event::Edited, Event::Dirtied, Event::Edited, Event::Edited]
58 );
59
60 let buffer_2_events = buffer_2_events.borrow();
61 assert_eq!(*buffer_2_events, vec![Event::Edited, Event::Dirtied]);
62}
63
64#[gpui::test]
65async fn test_apply_diff(mut cx: gpui::TestAppContext) {
66 let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n";
67 let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
68
69 let text = "a\nccc\ndddd\nffffff\n";
70 let diff = buffer.read_with(&cx, |b, cx| b.diff(text.into(), cx)).await;
71 buffer.update(&mut cx, |b, cx| b.apply_diff(diff, cx));
72 cx.read(|cx| assert_eq!(buffer.read(cx).text(), text));
73
74 let text = "a\n1\n\nccc\ndd2dd\nffffff\n";
75 let diff = buffer.read_with(&cx, |b, cx| b.diff(text.into(), cx)).await;
76 buffer.update(&mut cx, |b, cx| b.apply_diff(diff, cx));
77 cx.read(|cx| assert_eq!(buffer.read(cx).text(), text));
78}
79
80#[gpui::test]
81async fn test_reparse(mut cx: gpui::TestAppContext) {
82 let text = "fn a() {}";
83 let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(rust_lang(), None, cx));
84
85 // Wait for the initial text to parse
86 buffer
87 .condition(&cx, |buffer, _| !buffer.is_parsing())
88 .await;
89 assert_eq!(
90 get_tree_sexp(&buffer, &cx),
91 concat!(
92 "(source_file (function_item name: (identifier) ",
93 "parameters: (parameters) ",
94 "body: (block)))"
95 )
96 );
97
98 buffer.update(&mut cx, |buffer, _| {
99 buffer.set_sync_parse_timeout(Duration::ZERO)
100 });
101
102 // Perform some edits (add parameter and variable reference)
103 // Parsing doesn't begin until the transaction is complete
104 buffer.update(&mut cx, |buf, cx| {
105 buf.start_transaction(None).unwrap();
106
107 let offset = buf.text().find(")").unwrap();
108 buf.edit(vec![offset..offset], "b: C", cx);
109 assert!(!buf.is_parsing());
110
111 let offset = buf.text().find("}").unwrap();
112 buf.edit(vec![offset..offset], " d; ", cx);
113 assert!(!buf.is_parsing());
114
115 buf.end_transaction(None, cx).unwrap();
116 assert_eq!(buf.text(), "fn a(b: C) { d; }");
117 assert!(buf.is_parsing());
118 });
119 buffer
120 .condition(&cx, |buffer, _| !buffer.is_parsing())
121 .await;
122 assert_eq!(
123 get_tree_sexp(&buffer, &cx),
124 concat!(
125 "(source_file (function_item name: (identifier) ",
126 "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
127 "body: (block (identifier))))"
128 )
129 );
130
131 // Perform a series of edits without waiting for the current parse to complete:
132 // * turn identifier into a field expression
133 // * turn field expression into a method call
134 // * add a turbofish to the method call
135 buffer.update(&mut cx, |buf, cx| {
136 let offset = buf.text().find(";").unwrap();
137 buf.edit(vec![offset..offset], ".e", cx);
138 assert_eq!(buf.text(), "fn a(b: C) { d.e; }");
139 assert!(buf.is_parsing());
140 });
141 buffer.update(&mut cx, |buf, cx| {
142 let offset = buf.text().find(";").unwrap();
143 buf.edit(vec![offset..offset], "(f)", cx);
144 assert_eq!(buf.text(), "fn a(b: C) { d.e(f); }");
145 assert!(buf.is_parsing());
146 });
147 buffer.update(&mut cx, |buf, cx| {
148 let offset = buf.text().find("(f)").unwrap();
149 buf.edit(vec![offset..offset], "::<G>", cx);
150 assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
151 assert!(buf.is_parsing());
152 });
153 buffer
154 .condition(&cx, |buffer, _| !buffer.is_parsing())
155 .await;
156 assert_eq!(
157 get_tree_sexp(&buffer, &cx),
158 concat!(
159 "(source_file (function_item name: (identifier) ",
160 "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
161 "body: (block (call_expression ",
162 "function: (generic_function ",
163 "function: (field_expression value: (identifier) field: (field_identifier)) ",
164 "type_arguments: (type_arguments (type_identifier))) ",
165 "arguments: (arguments (identifier))))))",
166 )
167 );
168
169 buffer.update(&mut cx, |buf, cx| {
170 buf.undo(cx);
171 assert_eq!(buf.text(), "fn a() {}");
172 assert!(buf.is_parsing());
173 });
174 buffer
175 .condition(&cx, |buffer, _| !buffer.is_parsing())
176 .await;
177 assert_eq!(
178 get_tree_sexp(&buffer, &cx),
179 concat!(
180 "(source_file (function_item name: (identifier) ",
181 "parameters: (parameters) ",
182 "body: (block)))"
183 )
184 );
185
186 buffer.update(&mut cx, |buf, cx| {
187 buf.redo(cx);
188 assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
189 assert!(buf.is_parsing());
190 });
191 buffer
192 .condition(&cx, |buffer, _| !buffer.is_parsing())
193 .await;
194 assert_eq!(
195 get_tree_sexp(&buffer, &cx),
196 concat!(
197 "(source_file (function_item name: (identifier) ",
198 "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
199 "body: (block (call_expression ",
200 "function: (generic_function ",
201 "function: (field_expression value: (identifier) field: (field_identifier)) ",
202 "type_arguments: (type_arguments (type_identifier))) ",
203 "arguments: (arguments (identifier))))))",
204 )
205 );
206
207 fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
208 buffer.read_with(cx, |buffer, _| {
209 buffer.syntax_tree().unwrap().root_node().to_sexp()
210 })
211 }
212}
213
214#[gpui::test]
215fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
216 let buffer = cx.add_model(|cx| {
217 let text = "
218 mod x {
219 mod y {
220
221 }
222 }
223 "
224 .unindent();
225 Buffer::new(0, text, cx).with_language(rust_lang(), None, cx)
226 });
227 let buffer = buffer.read(cx);
228 assert_eq!(
229 buffer.enclosing_bracket_point_ranges(Point::new(1, 6)..Point::new(1, 6)),
230 Some((
231 Point::new(0, 6)..Point::new(0, 7),
232 Point::new(4, 0)..Point::new(4, 1)
233 ))
234 );
235 assert_eq!(
236 buffer.enclosing_bracket_point_ranges(Point::new(1, 10)..Point::new(1, 10)),
237 Some((
238 Point::new(1, 10)..Point::new(1, 11),
239 Point::new(3, 4)..Point::new(3, 5)
240 ))
241 );
242 assert_eq!(
243 buffer.enclosing_bracket_point_ranges(Point::new(3, 5)..Point::new(3, 5)),
244 Some((
245 Point::new(1, 10)..Point::new(1, 11),
246 Point::new(3, 4)..Point::new(3, 5)
247 ))
248 );
249}
250
251#[gpui::test]
252fn test_edit_with_autoindent(cx: &mut MutableAppContext) {
253 cx.add_model(|cx| {
254 let text = "fn a() {}";
255 let mut buffer = Buffer::new(0, text, cx).with_language(rust_lang(), None, cx);
256
257 buffer.edit_with_autoindent([8..8], "\n\n", cx);
258 assert_eq!(buffer.text(), "fn a() {\n \n}");
259
260 buffer.edit_with_autoindent([Point::new(1, 4)..Point::new(1, 4)], "b()\n", cx);
261 assert_eq!(buffer.text(), "fn a() {\n b()\n \n}");
262
263 buffer.edit_with_autoindent([Point::new(2, 4)..Point::new(2, 4)], ".c", cx);
264 assert_eq!(buffer.text(), "fn a() {\n b()\n .c\n}");
265
266 buffer
267 });
268}
269
270#[gpui::test]
271fn test_autoindent_moves_selections(cx: &mut MutableAppContext) {
272 cx.add_model(|cx| {
273 let text = "fn a() {}";
274
275 let mut buffer = Buffer::new(0, text, cx).with_language(rust_lang(), None, cx);
276
277 let selection_set_id = buffer.add_selection_set(Vec::new(), cx);
278 buffer.start_transaction(Some(selection_set_id)).unwrap();
279 buffer.edit_with_autoindent([5..5, 9..9], "\n\n", cx);
280 buffer
281 .update_selection_set(
282 selection_set_id,
283 vec![
284 Selection {
285 id: 0,
286 start: buffer.anchor_before(Point::new(1, 0)),
287 end: buffer.anchor_before(Point::new(1, 0)),
288 reversed: false,
289 goal: SelectionGoal::None,
290 },
291 Selection {
292 id: 1,
293 start: buffer.anchor_before(Point::new(4, 0)),
294 end: buffer.anchor_before(Point::new(4, 0)),
295 reversed: false,
296 goal: SelectionGoal::None,
297 },
298 ],
299 cx,
300 )
301 .unwrap();
302 assert_eq!(buffer.text(), "fn a(\n\n) {}\n\n");
303
304 // Ending the transaction runs the auto-indent. The selection
305 // at the start of the auto-indented row is pushed to the right.
306 buffer.end_transaction(Some(selection_set_id), cx).unwrap();
307 assert_eq!(buffer.text(), "fn a(\n \n) {}\n\n");
308 let selection_ranges = buffer
309 .selection_set(selection_set_id)
310 .unwrap()
311 .selections
312 .iter()
313 .map(|selection| selection.point_range(&buffer))
314 .collect::<Vec<_>>();
315
316 assert_eq!(selection_ranges[0], empty(Point::new(1, 4)));
317 assert_eq!(selection_ranges[1], empty(Point::new(4, 0)));
318
319 buffer
320 });
321}
322
323#[gpui::test]
324fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut MutableAppContext) {
325 cx.add_model(|cx| {
326 let text = "
327 fn a() {
328 c;
329 d;
330 }
331 "
332 .unindent();
333
334 let mut buffer = Buffer::new(0, text, cx).with_language(rust_lang(), None, cx);
335
336 // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
337 // their indentation is not adjusted.
338 buffer.edit_with_autoindent([empty(Point::new(1, 1)), empty(Point::new(2, 1))], "()", cx);
339 assert_eq!(
340 buffer.text(),
341 "
342 fn a() {
343 c();
344 d();
345 }
346 "
347 .unindent()
348 );
349
350 // When appending new content after these lines, the indentation is based on the
351 // preceding lines' actual indentation.
352 buffer.edit_with_autoindent(
353 [empty(Point::new(1, 1)), empty(Point::new(2, 1))],
354 "\n.f\n.g",
355 cx,
356 );
357 assert_eq!(
358 buffer.text(),
359 "
360 fn a() {
361 c
362 .f
363 .g();
364 d
365 .f
366 .g();
367 }
368 "
369 .unindent()
370 );
371 buffer
372 });
373}
374
375#[gpui::test]
376fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut MutableAppContext) {
377 cx.add_model(|cx| {
378 let text = "
379 fn a() {}
380 "
381 .unindent();
382
383 let mut buffer = Buffer::new(0, text, cx).with_language(rust_lang(), None, cx);
384
385 buffer.edit_with_autoindent([5..5], "\nb", cx);
386 assert_eq!(
387 buffer.text(),
388 "
389 fn a(
390 b) {}
391 "
392 .unindent()
393 );
394
395 // The indentation suggestion changed because `@end` node (a close paren)
396 // is now at the beginning of the line.
397 buffer.edit_with_autoindent([Point::new(1, 4)..Point::new(1, 5)], "", cx);
398 assert_eq!(
399 buffer.text(),
400 "
401 fn a(
402 ) {}
403 "
404 .unindent()
405 );
406
407 buffer
408 });
409}
410
411#[gpui::test]
412async fn test_diagnostics(mut cx: gpui::TestAppContext) {
413 let (language_server, mut fake) = lsp::LanguageServer::fake(&cx.background()).await;
414
415 let text = "
416 fn a() { A }
417 fn b() { BB }
418 fn c() { CCC }
419 "
420 .unindent();
421
422 let buffer = cx.add_model(|cx| {
423 Buffer::new(0, text, cx).with_language(rust_lang(), Some(language_server), cx)
424 });
425
426 let open_notification = fake
427 .receive_notification::<lsp::notification::DidOpenTextDocument>()
428 .await;
429
430 // Edit the buffer, moving the content down
431 buffer.update(&mut cx, |buffer, cx| buffer.edit([0..0], "\n\n", cx));
432 let change_notification_1 = fake
433 .receive_notification::<lsp::notification::DidChangeTextDocument>()
434 .await;
435 assert!(change_notification_1.text_document.version > open_notification.text_document.version);
436
437 buffer.update(&mut cx, |buffer, cx| {
438 // Receive diagnostics for an earlier version of the buffer.
439 buffer
440 .update_diagnostics(
441 Some(open_notification.text_document.version),
442 vec![
443 lsp::Diagnostic {
444 range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
445 severity: Some(lsp::DiagnosticSeverity::ERROR),
446 message: "undefined variable 'A'".to_string(),
447 ..Default::default()
448 },
449 lsp::Diagnostic {
450 range: lsp::Range::new(lsp::Position::new(1, 9), lsp::Position::new(1, 11)),
451 severity: Some(lsp::DiagnosticSeverity::ERROR),
452 message: "undefined variable 'BB'".to_string(),
453 ..Default::default()
454 },
455 lsp::Diagnostic {
456 range: lsp::Range::new(lsp::Position::new(2, 9), lsp::Position::new(2, 12)),
457 severity: Some(lsp::DiagnosticSeverity::ERROR),
458 message: "undefined variable 'CCC'".to_string(),
459 ..Default::default()
460 },
461 ],
462 cx,
463 )
464 .unwrap();
465
466 // The diagnostics have moved down since they were created.
467 assert_eq!(
468 buffer
469 .diagnostics_in_range(Point::new(3, 0)..Point::new(5, 0))
470 .collect::<Vec<_>>(),
471 &[
472 Diagnostic {
473 range: Point::new(3, 9)..Point::new(3, 11),
474 severity: DiagnosticSeverity::ERROR,
475 message: "undefined variable 'BB'".to_string()
476 },
477 Diagnostic {
478 range: Point::new(4, 9)..Point::new(4, 12),
479 severity: DiagnosticSeverity::ERROR,
480 message: "undefined variable 'CCC'".to_string()
481 }
482 ]
483 );
484 assert_eq!(
485 chunks_with_diagnostics(buffer, 0..buffer.len()),
486 [
487 ("\n\nfn a() { ".to_string(), None),
488 ("A".to_string(), Some(DiagnosticSeverity::ERROR)),
489 (" }\nfn b() { ".to_string(), None),
490 ("BB".to_string(), Some(DiagnosticSeverity::ERROR)),
491 (" }\nfn c() { ".to_string(), None),
492 ("CCC".to_string(), Some(DiagnosticSeverity::ERROR)),
493 (" }\n".to_string(), None),
494 ]
495 );
496 assert_eq!(
497 chunks_with_diagnostics(buffer, Point::new(3, 10)..Point::new(4, 11)),
498 [
499 ("B".to_string(), Some(DiagnosticSeverity::ERROR)),
500 (" }\nfn c() { ".to_string(), None),
501 ("CC".to_string(), Some(DiagnosticSeverity::ERROR)),
502 ]
503 );
504
505 // Ensure overlapping diagnostics are highlighted correctly.
506 buffer
507 .update_diagnostics(
508 Some(open_notification.text_document.version),
509 vec![
510 lsp::Diagnostic {
511 range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
512 severity: Some(lsp::DiagnosticSeverity::ERROR),
513 message: "undefined variable 'A'".to_string(),
514 ..Default::default()
515 },
516 lsp::Diagnostic {
517 range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 12)),
518 severity: Some(lsp::DiagnosticSeverity::WARNING),
519 message: "unreachable statement".to_string(),
520 ..Default::default()
521 },
522 ],
523 cx,
524 )
525 .unwrap();
526 assert_eq!(
527 buffer
528 .diagnostics_in_range(Point::new(2, 0)..Point::new(3, 0))
529 .collect::<Vec<_>>(),
530 &[
531 Diagnostic {
532 range: Point::new(2, 9)..Point::new(2, 12),
533 severity: DiagnosticSeverity::WARNING,
534 message: "unreachable statement".to_string()
535 },
536 Diagnostic {
537 range: Point::new(2, 9)..Point::new(2, 10),
538 severity: DiagnosticSeverity::ERROR,
539 message: "undefined variable 'A'".to_string()
540 },
541 ]
542 );
543 assert_eq!(
544 chunks_with_diagnostics(buffer, Point::new(2, 0)..Point::new(3, 0)),
545 [
546 ("fn a() { ".to_string(), None),
547 ("A".to_string(), Some(DiagnosticSeverity::ERROR)),
548 (" }".to_string(), Some(DiagnosticSeverity::WARNING)),
549 ("\n".to_string(), None),
550 ]
551 );
552 assert_eq!(
553 chunks_with_diagnostics(buffer, Point::new(2, 10)..Point::new(3, 0)),
554 [
555 (" }".to_string(), Some(DiagnosticSeverity::WARNING)),
556 ("\n".to_string(), None),
557 ]
558 );
559 });
560
561 // Keep editing the buffer and ensure disk-based diagnostics get translated according to the
562 // changes since the last save.
563 buffer.update(&mut cx, |buffer, cx| {
564 buffer.edit(Some(Point::new(2, 0)..Point::new(2, 0)), " ", cx);
565 buffer.edit(Some(Point::new(2, 8)..Point::new(2, 10)), "(x: usize)", cx);
566 });
567 let change_notification_2 = fake
568 .receive_notification::<lsp::notification::DidChangeTextDocument>()
569 .await;
570 assert!(
571 change_notification_2.text_document.version > change_notification_1.text_document.version
572 );
573
574 buffer.update(&mut cx, |buffer, cx| {
575 buffer
576 .update_diagnostics(
577 Some(change_notification_2.text_document.version),
578 vec![
579 lsp::Diagnostic {
580 range: lsp::Range::new(lsp::Position::new(1, 9), lsp::Position::new(1, 11)),
581 severity: Some(lsp::DiagnosticSeverity::ERROR),
582 message: "undefined variable 'BB'".to_string(),
583 source: Some("rustc".to_string()),
584 ..Default::default()
585 },
586 lsp::Diagnostic {
587 range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
588 severity: Some(lsp::DiagnosticSeverity::ERROR),
589 message: "undefined variable 'A'".to_string(),
590 source: Some("rustc".to_string()),
591 ..Default::default()
592 },
593 ],
594 cx,
595 )
596 .unwrap();
597 assert_eq!(
598 buffer
599 .diagnostics_in_range(0..buffer.len())
600 .collect::<Vec<_>>(),
601 &[
602 Diagnostic {
603 range: Point::new(2, 21)..Point::new(2, 22),
604 severity: DiagnosticSeverity::ERROR,
605 message: "undefined variable 'A'".to_string()
606 },
607 Diagnostic {
608 range: Point::new(3, 9)..Point::new(3, 11),
609 severity: DiagnosticSeverity::ERROR,
610 message: "undefined variable 'BB'".to_string()
611 },
612 ]
613 );
614 });
615
616 fn chunks_with_diagnostics<T: ToOffset>(
617 buffer: &Buffer,
618 range: Range<T>,
619 ) -> Vec<(String, Option<DiagnosticSeverity>)> {
620 let mut chunks: Vec<(String, Option<DiagnosticSeverity>)> = Vec::new();
621 for chunk in buffer.snapshot().highlighted_text_for_range(range) {
622 if chunks
623 .last()
624 .map_or(false, |prev_chunk| prev_chunk.1 == chunk.diagnostic)
625 {
626 chunks.last_mut().unwrap().0.push_str(chunk.text);
627 } else {
628 chunks.push((chunk.text.to_string(), chunk.diagnostic));
629 }
630 }
631 chunks
632 }
633}
634
635#[test]
636fn test_contiguous_ranges() {
637 assert_eq!(
638 contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12], 100).collect::<Vec<_>>(),
639 &[1..4, 5..7, 9..13]
640 );
641
642 // Respects the `max_len` parameter
643 assert_eq!(
644 contiguous_ranges([2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31], 3).collect::<Vec<_>>(),
645 &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
646 );
647}
648
649impl Buffer {
650 pub fn enclosing_bracket_point_ranges<T: ToOffset>(
651 &self,
652 range: Range<T>,
653 ) -> Option<(Range<Point>, Range<Point>)> {
654 self.enclosing_bracket_ranges(range).map(|(start, end)| {
655 let point_start = start.start.to_point(self)..start.end.to_point(self);
656 let point_end = end.start.to_point(self)..end.end.to_point(self);
657 (point_start, point_end)
658 })
659 }
660}
661
662fn rust_lang() -> Option<Arc<Language>> {
663 Some(Arc::new(
664 Language::new(
665 LanguageConfig {
666 name: "Rust".to_string(),
667 path_suffixes: vec!["rs".to_string()],
668 language_server: Some(LanguageServerConfig {
669 binary: "rust-analyzer".to_string(),
670 disk_based_diagnostic_sources: HashSet::from_iter(vec!["rustc".to_string()]),
671 }),
672 ..Default::default()
673 },
674 tree_sitter_rust::language(),
675 )
676 .with_indents_query(
677 r#"
678 (call_expression) @indent
679 (field_expression) @indent
680 (_ "(" ")" @end) @indent
681 (_ "{" "}" @end) @indent
682 "#,
683 )
684 .unwrap()
685 .with_brackets_query(r#" ("{" @open "}" @close) "#)
686 .unwrap(),
687 ))
688}
689
690fn empty(point: Point) -> Range<Point> {
691 point..point
692}