tests.rs

  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}