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::<usize>(&[], 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                &[
284                    Selection {
285                        id: 0,
286                        start: Point::new(1, 0),
287                        end: Point::new(1, 0),
288                        reversed: false,
289                        goal: SelectionGoal::None,
290                    },
291                    Selection {
292                        id: 1,
293                        start: Point::new(4, 0),
294                        end: 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            .point_selections(&buffer)
312            .map(|selection| selection.point_range(&buffer))
313            .collect::<Vec<_>>();
314
315        assert_eq!(selection_ranges[0], empty(Point::new(1, 4)));
316        assert_eq!(selection_ranges[1], empty(Point::new(4, 0)));
317
318        buffer
319    });
320}
321
322#[gpui::test]
323fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut MutableAppContext) {
324    cx.add_model(|cx| {
325        let text = "
326            fn a() {
327            c;
328            d;
329            }
330        "
331        .unindent();
332
333        let mut buffer = Buffer::new(0, text, cx).with_language(rust_lang(), None, cx);
334
335        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
336        // their indentation is not adjusted.
337        buffer.edit_with_autoindent([empty(Point::new(1, 1)), empty(Point::new(2, 1))], "()", cx);
338        assert_eq!(
339            buffer.text(),
340            "
341            fn a() {
342            c();
343            d();
344            }
345            "
346            .unindent()
347        );
348
349        // When appending new content after these lines, the indentation is based on the
350        // preceding lines' actual indentation.
351        buffer.edit_with_autoindent(
352            [empty(Point::new(1, 1)), empty(Point::new(2, 1))],
353            "\n.f\n.g",
354            cx,
355        );
356        assert_eq!(
357            buffer.text(),
358            "
359            fn a() {
360            c
361                .f
362                .g();
363            d
364                .f
365                .g();
366            }
367            "
368            .unindent()
369        );
370        buffer
371    });
372}
373
374#[gpui::test]
375fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut MutableAppContext) {
376    cx.add_model(|cx| {
377        let text = "
378            fn a() {}
379        "
380        .unindent();
381
382        let mut buffer = Buffer::new(0, text, cx).with_language(rust_lang(), None, cx);
383
384        buffer.edit_with_autoindent([5..5], "\nb", cx);
385        assert_eq!(
386            buffer.text(),
387            "
388                fn a(
389                    b) {}
390            "
391            .unindent()
392        );
393
394        // The indentation suggestion changed because `@end` node (a close paren)
395        // is now at the beginning of the line.
396        buffer.edit_with_autoindent([Point::new(1, 4)..Point::new(1, 5)], "", cx);
397        assert_eq!(
398            buffer.text(),
399            "
400                fn a(
401                ) {}
402            "
403            .unindent()
404        );
405
406        buffer
407    });
408}
409
410#[gpui::test]
411async fn test_diagnostics(mut cx: gpui::TestAppContext) {
412    let (language_server, mut fake) = lsp::LanguageServer::fake(&cx.background()).await;
413
414    let text = "
415        fn a() { A }
416        fn b() { BB }
417        fn c() { CCC }
418    "
419    .unindent();
420
421    let buffer = cx.add_model(|cx| {
422        Buffer::new(0, text, cx).with_language(rust_lang(), Some(language_server), cx)
423    });
424
425    let open_notification = fake
426        .receive_notification::<lsp::notification::DidOpenTextDocument>()
427        .await;
428
429    // Edit the buffer, moving the content down
430    buffer.update(&mut cx, |buffer, cx| buffer.edit([0..0], "\n\n", cx));
431    let change_notification_1 = fake
432        .receive_notification::<lsp::notification::DidChangeTextDocument>()
433        .await;
434    assert!(change_notification_1.text_document.version > open_notification.text_document.version);
435
436    buffer.update(&mut cx, |buffer, cx| {
437        // Receive diagnostics for an earlier version of the buffer.
438        buffer
439            .update_diagnostics(
440                Some(open_notification.text_document.version),
441                vec![
442                    lsp::Diagnostic {
443                        range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
444                        severity: Some(lsp::DiagnosticSeverity::ERROR),
445                        message: "undefined variable 'A'".to_string(),
446                        ..Default::default()
447                    },
448                    lsp::Diagnostic {
449                        range: lsp::Range::new(lsp::Position::new(1, 9), lsp::Position::new(1, 11)),
450                        severity: Some(lsp::DiagnosticSeverity::ERROR),
451                        message: "undefined variable 'BB'".to_string(),
452                        ..Default::default()
453                    },
454                    lsp::Diagnostic {
455                        range: lsp::Range::new(lsp::Position::new(2, 9), lsp::Position::new(2, 12)),
456                        severity: Some(lsp::DiagnosticSeverity::ERROR),
457                        message: "undefined variable 'CCC'".to_string(),
458                        ..Default::default()
459                    },
460                ],
461                cx,
462            )
463            .unwrap();
464
465        // The diagnostics have moved down since they were created.
466        assert_eq!(
467            buffer
468                .diagnostics_in_range(Point::new(3, 0)..Point::new(5, 0))
469                .collect::<Vec<_>>(),
470            &[
471                Diagnostic {
472                    range: Point::new(3, 9)..Point::new(3, 11),
473                    severity: DiagnosticSeverity::ERROR,
474                    message: "undefined variable 'BB'".to_string()
475                },
476                Diagnostic {
477                    range: Point::new(4, 9)..Point::new(4, 12),
478                    severity: DiagnosticSeverity::ERROR,
479                    message: "undefined variable 'CCC'".to_string()
480                }
481            ]
482        );
483        assert_eq!(
484            chunks_with_diagnostics(buffer, 0..buffer.len()),
485            [
486                ("\n\nfn a() { ".to_string(), None),
487                ("A".to_string(), Some(DiagnosticSeverity::ERROR)),
488                (" }\nfn b() { ".to_string(), None),
489                ("BB".to_string(), Some(DiagnosticSeverity::ERROR)),
490                (" }\nfn c() { ".to_string(), None),
491                ("CCC".to_string(), Some(DiagnosticSeverity::ERROR)),
492                (" }\n".to_string(), None),
493            ]
494        );
495        assert_eq!(
496            chunks_with_diagnostics(buffer, Point::new(3, 10)..Point::new(4, 11)),
497            [
498                ("B".to_string(), Some(DiagnosticSeverity::ERROR)),
499                (" }\nfn c() { ".to_string(), None),
500                ("CC".to_string(), Some(DiagnosticSeverity::ERROR)),
501            ]
502        );
503
504        // Ensure overlapping diagnostics are highlighted correctly.
505        buffer
506            .update_diagnostics(
507                Some(open_notification.text_document.version),
508                vec![
509                    lsp::Diagnostic {
510                        range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
511                        severity: Some(lsp::DiagnosticSeverity::ERROR),
512                        message: "undefined variable 'A'".to_string(),
513                        ..Default::default()
514                    },
515                    lsp::Diagnostic {
516                        range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 12)),
517                        severity: Some(lsp::DiagnosticSeverity::WARNING),
518                        message: "unreachable statement".to_string(),
519                        ..Default::default()
520                    },
521                ],
522                cx,
523            )
524            .unwrap();
525        assert_eq!(
526            buffer
527                .diagnostics_in_range(Point::new(2, 0)..Point::new(3, 0))
528                .collect::<Vec<_>>(),
529            &[
530                Diagnostic {
531                    range: Point::new(2, 9)..Point::new(2, 12),
532                    severity: DiagnosticSeverity::WARNING,
533                    message: "unreachable statement".to_string()
534                },
535                Diagnostic {
536                    range: Point::new(2, 9)..Point::new(2, 10),
537                    severity: DiagnosticSeverity::ERROR,
538                    message: "undefined variable 'A'".to_string()
539                },
540            ]
541        );
542        assert_eq!(
543            chunks_with_diagnostics(buffer, Point::new(2, 0)..Point::new(3, 0)),
544            [
545                ("fn a() { ".to_string(), None),
546                ("A".to_string(), Some(DiagnosticSeverity::ERROR)),
547                (" }".to_string(), Some(DiagnosticSeverity::WARNING)),
548                ("\n".to_string(), None),
549            ]
550        );
551        assert_eq!(
552            chunks_with_diagnostics(buffer, Point::new(2, 10)..Point::new(3, 0)),
553            [
554                (" }".to_string(), Some(DiagnosticSeverity::WARNING)),
555                ("\n".to_string(), None),
556            ]
557        );
558    });
559
560    // Keep editing the buffer and ensure disk-based diagnostics get translated according to the
561    // changes since the last save.
562    buffer.update(&mut cx, |buffer, cx| {
563        buffer.edit(Some(Point::new(2, 0)..Point::new(2, 0)), "    ", cx);
564        buffer.edit(Some(Point::new(2, 8)..Point::new(2, 10)), "(x: usize)", cx);
565    });
566    let change_notification_2 = fake
567        .receive_notification::<lsp::notification::DidChangeTextDocument>()
568        .await;
569    assert!(
570        change_notification_2.text_document.version > change_notification_1.text_document.version
571    );
572
573    buffer.update(&mut cx, |buffer, cx| {
574        buffer
575            .update_diagnostics(
576                Some(change_notification_2.text_document.version),
577                vec![
578                    lsp::Diagnostic {
579                        range: lsp::Range::new(lsp::Position::new(1, 9), lsp::Position::new(1, 11)),
580                        severity: Some(lsp::DiagnosticSeverity::ERROR),
581                        message: "undefined variable 'BB'".to_string(),
582                        source: Some("rustc".to_string()),
583                        ..Default::default()
584                    },
585                    lsp::Diagnostic {
586                        range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)),
587                        severity: Some(lsp::DiagnosticSeverity::ERROR),
588                        message: "undefined variable 'A'".to_string(),
589                        source: Some("rustc".to_string()),
590                        ..Default::default()
591                    },
592                ],
593                cx,
594            )
595            .unwrap();
596        assert_eq!(
597            buffer
598                .diagnostics_in_range(0..buffer.len())
599                .collect::<Vec<_>>(),
600            &[
601                Diagnostic {
602                    range: Point::new(2, 21)..Point::new(2, 22),
603                    severity: DiagnosticSeverity::ERROR,
604                    message: "undefined variable 'A'".to_string()
605                },
606                Diagnostic {
607                    range: Point::new(3, 9)..Point::new(3, 11),
608                    severity: DiagnosticSeverity::ERROR,
609                    message: "undefined variable 'BB'".to_string()
610                },
611            ]
612        );
613    });
614
615    fn chunks_with_diagnostics<T: ToOffset>(
616        buffer: &Buffer,
617        range: Range<T>,
618    ) -> Vec<(String, Option<DiagnosticSeverity>)> {
619        let mut chunks: Vec<(String, Option<DiagnosticSeverity>)> = Vec::new();
620        for chunk in buffer.snapshot().highlighted_text_for_range(range) {
621            if chunks
622                .last()
623                .map_or(false, |prev_chunk| prev_chunk.1 == chunk.diagnostic)
624            {
625                chunks.last_mut().unwrap().0.push_str(chunk.text);
626            } else {
627                chunks.push((chunk.text.to_string(), chunk.diagnostic));
628            }
629        }
630        chunks
631    }
632}
633
634#[test]
635fn test_contiguous_ranges() {
636    assert_eq!(
637        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12], 100).collect::<Vec<_>>(),
638        &[1..4, 5..7, 9..13]
639    );
640
641    // Respects the `max_len` parameter
642    assert_eq!(
643        contiguous_ranges([2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31], 3).collect::<Vec<_>>(),
644        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
645    );
646}
647
648impl Buffer {
649    pub fn enclosing_bracket_point_ranges<T: ToOffset>(
650        &self,
651        range: Range<T>,
652    ) -> Option<(Range<Point>, Range<Point>)> {
653        self.enclosing_bracket_ranges(range).map(|(start, end)| {
654            let point_start = start.start.to_point(self)..start.end.to_point(self);
655            let point_end = end.start.to_point(self)..end.end.to_point(self);
656            (point_start, point_end)
657        })
658    }
659}
660
661fn rust_lang() -> Option<Arc<Language>> {
662    Some(Arc::new(
663        Language::new(
664            LanguageConfig {
665                name: "Rust".to_string(),
666                path_suffixes: vec!["rs".to_string()],
667                language_server: Some(LanguageServerConfig {
668                    binary: "rust-analyzer".to_string(),
669                    disk_based_diagnostic_sources: HashSet::from_iter(vec!["rustc".to_string()]),
670                }),
671                ..Default::default()
672            },
673            tree_sitter_rust::language(),
674        )
675        .with_indents_query(
676            r#"
677                (call_expression) @indent
678                (field_expression) @indent
679                (_ "(" ")" @end) @indent
680                (_ "{" "}" @end) @indent
681            "#,
682        )
683        .unwrap()
684        .with_brackets_query(r#" ("{" @open "}" @close) "#)
685        .unwrap(),
686    ))
687}
688
689fn empty(point: Point) -> Range<Point> {
690    point..point
691}