1use crate::Buffer;
2use gpui2::{Context, TestAppContext};
3use text::{Point, ToPoint};
4
5// use crate::language_settings::{
6// AllLanguageSettings, AllLanguageSettingsContent, LanguageSettingsContent,
7// };
8
9// use super::*;
10// use clock::ReplicaId;
11// use collections::BTreeMap;
12// use gpui2::{AppContext, Handle};
13// use indoc::indoc;
14// use proto::deserialize_operation;
15// use rand::prelude::*;
16// use regex::RegexBuilder;
17// use settings::SettingsStore;
18// use std::{
19// cell::RefCell,
20// env,
21// ops::Range,
22// rc::Rc,
23// time::{Duration, Instant},
24// };
25// use text::network::Network;
26// use text::LineEnding;
27// use unindent::Unindent as _;
28// use util::{assert_set_eq, post_inc, test::marked_text_ranges, RandomCharIter};
29
30// lazy_static! {
31// static ref TRAILING_WHITESPACE_REGEX: Regex = RegexBuilder::new("[ \t]+$")
32// .multi_line(true)
33// .build()
34// .unwrap();
35// }
36
37// #[cfg(test)]
38// #[ctor::ctor]
39// fn init_logger() {
40// if std::env::var("RUST_LOG").is_ok() {
41// env_logger::init();
42// }
43// }
44
45// #[gpui::test]
46// fn test_line_endings(cx: &mut gpui::AppContext) {
47// init_settings(cx, |_| {});
48
49// cx.add_model(|cx| {
50// let mut buffer = Buffer::new(0, cx.model_id() as u64, "one\r\ntwo\rthree")
51// .with_language(Arc::new(rust_lang()), cx);
52// assert_eq!(buffer.text(), "one\ntwo\nthree");
53// assert_eq!(buffer.line_ending(), LineEnding::Windows);
54
55// buffer.check_invariants();
56// buffer.edit(
57// [(buffer.len()..buffer.len(), "\r\nfour")],
58// Some(AutoindentMode::EachLine),
59// cx,
60// );
61// buffer.edit([(0..0, "zero\r\n")], None, cx);
62// assert_eq!(buffer.text(), "zero\none\ntwo\nthree\nfour");
63// assert_eq!(buffer.line_ending(), LineEnding::Windows);
64// buffer.check_invariants();
65
66// buffer
67// });
68// }
69
70// #[gpui::test]
71// fn test_select_language() {
72// let registry = Arc::new(LanguageRegistry::test());
73// registry.add(Arc::new(Language::new(
74// LanguageConfig {
75// name: "Rust".into(),
76// path_suffixes: vec!["rs".to_string()],
77// ..Default::default()
78// },
79// Some(tree_sitter_rust::language()),
80// )));
81// registry.add(Arc::new(Language::new(
82// LanguageConfig {
83// name: "Make".into(),
84// path_suffixes: vec!["Makefile".to_string(), "mk".to_string()],
85// ..Default::default()
86// },
87// Some(tree_sitter_rust::language()),
88// )));
89
90// // matching file extension
91// assert_eq!(
92// registry
93// .language_for_file("zed/lib.rs", None)
94// .now_or_never()
95// .and_then(|l| Some(l.ok()?.name())),
96// Some("Rust".into())
97// );
98// assert_eq!(
99// registry
100// .language_for_file("zed/lib.mk", None)
101// .now_or_never()
102// .and_then(|l| Some(l.ok()?.name())),
103// Some("Make".into())
104// );
105
106// // matching filename
107// assert_eq!(
108// registry
109// .language_for_file("zed/Makefile", None)
110// .now_or_never()
111// .and_then(|l| Some(l.ok()?.name())),
112// Some("Make".into())
113// );
114
115// // matching suffix that is not the full file extension or filename
116// assert_eq!(
117// registry
118// .language_for_file("zed/cars", None)
119// .now_or_never()
120// .and_then(|l| Some(l.ok()?.name())),
121// None
122// );
123// assert_eq!(
124// registry
125// .language_for_file("zed/a.cars", None)
126// .now_or_never()
127// .and_then(|l| Some(l.ok()?.name())),
128// None
129// );
130// assert_eq!(
131// registry
132// .language_for_file("zed/sumk", None)
133// .now_or_never()
134// .and_then(|l| Some(l.ok()?.name())),
135// None
136// );
137// }
138
139// #[gpui::test]
140// fn test_edit_events(cx: &mut gpui::AppContext) {
141// let mut now = Instant::now();
142// let buffer_1_events = Rc::new(RefCell::new(Vec::new()));
143// let buffer_2_events = Rc::new(RefCell::new(Vec::new()));
144
145// let buffer1 = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "abcdef"));
146// let buffer2 = cx.add_model(|cx| Buffer::new(1, cx.model_id() as u64, "abcdef"));
147// let buffer1_ops = Rc::new(RefCell::new(Vec::new()));
148// buffer1.update(cx, {
149// let buffer1_ops = buffer1_ops.clone();
150// |buffer, cx| {
151// let buffer_1_events = buffer_1_events.clone();
152// cx.subscribe(&buffer1, move |_, _, event, _| match event.clone() {
153// Event::Operation(op) => buffer1_ops.borrow_mut().push(op),
154// event => buffer_1_events.borrow_mut().push(event),
155// })
156// .detach();
157// let buffer_2_events = buffer_2_events.clone();
158// cx.subscribe(&buffer2, move |_, _, event, _| {
159// buffer_2_events.borrow_mut().push(event.clone())
160// })
161// .detach();
162
163// // An edit emits an edited event, followed by a dirty changed event,
164// // since the buffer was previously in a clean state.
165// buffer.edit([(2..4, "XYZ")], None, cx);
166
167// // An empty transaction does not emit any events.
168// buffer.start_transaction();
169// buffer.end_transaction(cx);
170
171// // A transaction containing two edits emits one edited event.
172// now += Duration::from_secs(1);
173// buffer.start_transaction_at(now);
174// buffer.edit([(5..5, "u")], None, cx);
175// buffer.edit([(6..6, "w")], None, cx);
176// buffer.end_transaction_at(now, cx);
177
178// // Undoing a transaction emits one edited event.
179// buffer.undo(cx);
180// }
181// });
182
183// // Incorporating a set of remote ops emits a single edited event,
184// // followed by a dirty changed event.
185// buffer2.update(cx, |buffer, cx| {
186// buffer
187// .apply_ops(buffer1_ops.borrow_mut().drain(..), cx)
188// .unwrap();
189// });
190// assert_eq!(
191// mem::take(&mut *buffer_1_events.borrow_mut()),
192// vec![
193// Event::Edited,
194// Event::DirtyChanged,
195// Event::Edited,
196// Event::Edited,
197// ]
198// );
199// assert_eq!(
200// mem::take(&mut *buffer_2_events.borrow_mut()),
201// vec![Event::Edited, Event::DirtyChanged]
202// );
203
204// buffer1.update(cx, |buffer, cx| {
205// // Undoing the first transaction emits edited event, followed by a
206// // dirty changed event, since the buffer is again in a clean state.
207// buffer.undo(cx);
208// });
209// // Incorporating the remote ops again emits a single edited event,
210// // followed by a dirty changed event.
211// buffer2.update(cx, |buffer, cx| {
212// buffer
213// .apply_ops(buffer1_ops.borrow_mut().drain(..), cx)
214// .unwrap();
215// });
216// assert_eq!(
217// mem::take(&mut *buffer_1_events.borrow_mut()),
218// vec![Event::Edited, Event::DirtyChanged,]
219// );
220// assert_eq!(
221// mem::take(&mut *buffer_2_events.borrow_mut()),
222// vec![Event::Edited, Event::DirtyChanged]
223// );
224// }
225
226// #[gpui::test] todo!()
227#[gpui2::test]
228async fn test_apply_diff(cx: &mut TestAppContext) {
229 let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n";
230 let buffer = cx.entity(|cx| Buffer::new(0, cx.entity_id().as_u64(), text));
231 let anchor = buffer.update(cx, |buffer, _| buffer.anchor_before(Point::new(3, 3)));
232
233 let text = "a\nccc\ndddd\nffffff\n";
234 let diff = buffer.update(cx, |b, cx| b.diff(text.into(), cx)).await;
235 buffer.update(cx, |buffer, cx| {
236 buffer.apply_diff(diff, cx).unwrap();
237 assert_eq!(buffer.text(), text);
238 assert_eq!(anchor.to_point(buffer), Point::new(2, 3));
239 });
240
241 let text = "a\n1\n\nccc\ndd2dd\nffffff\n";
242 let diff = buffer.update(cx, |b, cx| b.diff(text.into(), cx)).await;
243 buffer.update(cx, |buffer, cx| {
244 buffer.apply_diff(diff, cx).unwrap();
245 assert_eq!(buffer.text(), text);
246 assert_eq!(anchor.to_point(buffer), Point::new(4, 4));
247 });
248}
249
250// #[gpui::test(iterations = 10)]
251// async fn test_normalize_whitespace(cx: &mut gpui::TestAppContext) {
252// let text = [
253// "zero", //
254// "one ", // 2 trailing spaces
255// "two", //
256// "three ", // 3 trailing spaces
257// "four", //
258// "five ", // 4 trailing spaces
259// ]
260// .join("\n");
261
262// let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, text));
263
264// // Spawn a task to format the buffer's whitespace.
265// // Pause so that the foratting task starts running.
266// let format = buffer.read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx));
267// smol::future::yield_now().await;
268
269// // Edit the buffer while the normalization task is running.
270// let version_before_edit = buffer.read_with(cx, |buffer, _| buffer.version());
271// buffer.update(cx, |buffer, cx| {
272// buffer.edit(
273// [
274// (Point::new(0, 1)..Point::new(0, 1), "EE"),
275// (Point::new(3, 5)..Point::new(3, 5), "EEE"),
276// ],
277// None,
278// cx,
279// );
280// });
281
282// let format_diff = format.await;
283// buffer.update(cx, |buffer, cx| {
284// let version_before_format = format_diff.base_version.clone();
285// buffer.apply_diff(format_diff, cx);
286
287// // The outcome depends on the order of concurrent taks.
288// //
289// // If the edit occurred while searching for trailing whitespace ranges,
290// // then the trailing whitespace region touched by the edit is left intact.
291// if version_before_format == version_before_edit {
292// assert_eq!(
293// buffer.text(),
294// [
295// "zEEero", //
296// "one", //
297// "two", //
298// "threeEEE ", //
299// "four", //
300// "five", //
301// ]
302// .join("\n")
303// );
304// }
305// // Otherwise, all trailing whitespace is removed.
306// else {
307// assert_eq!(
308// buffer.text(),
309// [
310// "zEEero", //
311// "one", //
312// "two", //
313// "threeEEE", //
314// "four", //
315// "five", //
316// ]
317// .join("\n")
318// );
319// }
320// });
321// }
322
323// #[gpui::test]
324// async fn test_reparse(cx: &mut gpui::TestAppContext) {
325// let text = "fn a() {}";
326// let buffer = cx.add_model(|cx| {
327// Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx)
328// });
329
330// // Wait for the initial text to parse
331// buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
332// assert_eq!(
333// get_tree_sexp(&buffer, cx),
334// concat!(
335// "(source_file (function_item name: (identifier) ",
336// "parameters: (parameters) ",
337// "body: (block)))"
338// )
339// );
340
341// buffer.update(cx, |buffer, _| {
342// buffer.set_sync_parse_timeout(Duration::ZERO)
343// });
344
345// // Perform some edits (add parameter and variable reference)
346// // Parsing doesn't begin until the transaction is complete
347// buffer.update(cx, |buf, cx| {
348// buf.start_transaction();
349
350// let offset = buf.text().find(')').unwrap();
351// buf.edit([(offset..offset, "b: C")], None, cx);
352// assert!(!buf.is_parsing());
353
354// let offset = buf.text().find('}').unwrap();
355// buf.edit([(offset..offset, " d; ")], None, cx);
356// assert!(!buf.is_parsing());
357
358// buf.end_transaction(cx);
359// assert_eq!(buf.text(), "fn a(b: C) { d; }");
360// assert!(buf.is_parsing());
361// });
362// buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
363// assert_eq!(
364// get_tree_sexp(&buffer, cx),
365// concat!(
366// "(source_file (function_item name: (identifier) ",
367// "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
368// "body: (block (expression_statement (identifier)))))"
369// )
370// );
371
372// // Perform a series of edits without waiting for the current parse to complete:
373// // * turn identifier into a field expression
374// // * turn field expression into a method call
375// // * add a turbofish to the method call
376// buffer.update(cx, |buf, cx| {
377// let offset = buf.text().find(';').unwrap();
378// buf.edit([(offset..offset, ".e")], None, cx);
379// assert_eq!(buf.text(), "fn a(b: C) { d.e; }");
380// assert!(buf.is_parsing());
381// });
382// buffer.update(cx, |buf, cx| {
383// let offset = buf.text().find(';').unwrap();
384// buf.edit([(offset..offset, "(f)")], None, cx);
385// assert_eq!(buf.text(), "fn a(b: C) { d.e(f); }");
386// assert!(buf.is_parsing());
387// });
388// buffer.update(cx, |buf, cx| {
389// let offset = buf.text().find("(f)").unwrap();
390// buf.edit([(offset..offset, "::<G>")], None, cx);
391// assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
392// assert!(buf.is_parsing());
393// });
394// buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
395// assert_eq!(
396// get_tree_sexp(&buffer, cx),
397// concat!(
398// "(source_file (function_item name: (identifier) ",
399// "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
400// "body: (block (expression_statement (call_expression ",
401// "function: (generic_function ",
402// "function: (field_expression value: (identifier) field: (field_identifier)) ",
403// "type_arguments: (type_arguments (type_identifier))) ",
404// "arguments: (arguments (identifier)))))))",
405// )
406// );
407
408// buffer.update(cx, |buf, cx| {
409// buf.undo(cx);
410// buf.undo(cx);
411// buf.undo(cx);
412// buf.undo(cx);
413// assert_eq!(buf.text(), "fn a() {}");
414// assert!(buf.is_parsing());
415// });
416// buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
417// assert_eq!(
418// get_tree_sexp(&buffer, cx),
419// concat!(
420// "(source_file (function_item name: (identifier) ",
421// "parameters: (parameters) ",
422// "body: (block)))"
423// )
424// );
425
426// buffer.update(cx, |buf, cx| {
427// buf.redo(cx);
428// buf.redo(cx);
429// buf.redo(cx);
430// buf.redo(cx);
431// assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
432// assert!(buf.is_parsing());
433// });
434// buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
435// assert_eq!(
436// get_tree_sexp(&buffer, cx),
437// concat!(
438// "(source_file (function_item name: (identifier) ",
439// "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
440// "body: (block (expression_statement (call_expression ",
441// "function: (generic_function ",
442// "function: (field_expression value: (identifier) field: (field_identifier)) ",
443// "type_arguments: (type_arguments (type_identifier))) ",
444// "arguments: (arguments (identifier)))))))",
445// )
446// );
447// }
448
449// #[gpui::test]
450// async fn test_resetting_language(cx: &mut gpui::TestAppContext) {
451// let buffer = cx.add_model(|cx| {
452// let mut buffer =
453// Buffer::new(0, cx.model_id() as u64, "{}").with_language(Arc::new(rust_lang()), cx);
454// buffer.set_sync_parse_timeout(Duration::ZERO);
455// buffer
456// });
457
458// // Wait for the initial text to parse
459// buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
460// assert_eq!(
461// get_tree_sexp(&buffer, cx),
462// "(source_file (expression_statement (block)))"
463// );
464
465// buffer.update(cx, |buffer, cx| {
466// buffer.set_language(Some(Arc::new(json_lang())), cx)
467// });
468// buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
469// assert_eq!(get_tree_sexp(&buffer, cx), "(document (object))");
470// }
471
472// #[gpui::test]
473// async fn test_outline(cx: &mut gpui::TestAppContext) {
474// let text = r#"
475// struct Person {
476// name: String,
477// age: usize,
478// }
479
480// mod module {
481// enum LoginState {
482// LoggedOut,
483// LoggingOn,
484// LoggedIn {
485// person: Person,
486// time: Instant,
487// }
488// }
489// }
490
491// impl Eq for Person {}
492
493// impl Drop for Person {
494// fn drop(&mut self) {
495// println!("bye");
496// }
497// }
498// "#
499// .unindent();
500
501// let buffer = cx.add_model(|cx| {
502// Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx)
503// });
504// let outline = buffer
505// .read_with(cx, |buffer, _| buffer.snapshot().outline(None))
506// .unwrap();
507
508// assert_eq!(
509// outline
510// .items
511// .iter()
512// .map(|item| (item.text.as_str(), item.depth))
513// .collect::<Vec<_>>(),
514// &[
515// ("struct Person", 0),
516// ("name", 1),
517// ("age", 1),
518// ("mod module", 0),
519// ("enum LoginState", 1),
520// ("LoggedOut", 2),
521// ("LoggingOn", 2),
522// ("LoggedIn", 2),
523// ("person", 3),
524// ("time", 3),
525// ("impl Eq for Person", 0),
526// ("impl Drop for Person", 0),
527// ("fn drop", 1),
528// ]
529// );
530
531// // Without space, we only match on names
532// assert_eq!(
533// search(&outline, "oon", cx).await,
534// &[
535// ("mod module", vec![]), // included as the parent of a match
536// ("enum LoginState", vec![]), // included as the parent of a match
537// ("LoggingOn", vec![1, 7, 8]), // matches
538// ("impl Drop for Person", vec![7, 18, 19]), // matches in two disjoint names
539// ]
540// );
541
542// assert_eq!(
543// search(&outline, "dp p", cx).await,
544// &[
545// ("impl Drop for Person", vec![5, 8, 9, 14]),
546// ("fn drop", vec![]),
547// ]
548// );
549// assert_eq!(
550// search(&outline, "dpn", cx).await,
551// &[("impl Drop for Person", vec![5, 14, 19])]
552// );
553// assert_eq!(
554// search(&outline, "impl ", cx).await,
555// &[
556// ("impl Eq for Person", vec![0, 1, 2, 3, 4]),
557// ("impl Drop for Person", vec![0, 1, 2, 3, 4]),
558// ("fn drop", vec![]),
559// ]
560// );
561
562// async fn search<'a>(
563// outline: &'a Outline<Anchor>,
564// query: &'a str,
565// cx: &'a gpui::TestAppContext,
566// ) -> Vec<(&'a str, Vec<usize>)> {
567// let matches = cx
568// .read(|cx| outline.search(query, cx.background().clone()))
569// .await;
570// matches
571// .into_iter()
572// .map(|mat| (outline.items[mat.candidate_id].text.as_str(), mat.positions))
573// .collect::<Vec<_>>()
574// }
575// }
576
577// #[gpui::test]
578// async fn test_outline_nodes_with_newlines(cx: &mut gpui::TestAppContext) {
579// let text = r#"
580// impl A for B<
581// C
582// > {
583// };
584// "#
585// .unindent();
586
587// let buffer = cx.add_model(|cx| {
588// Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx)
589// });
590// let outline = buffer
591// .read_with(cx, |buffer, _| buffer.snapshot().outline(None))
592// .unwrap();
593
594// assert_eq!(
595// outline
596// .items
597// .iter()
598// .map(|item| (item.text.as_str(), item.depth))
599// .collect::<Vec<_>>(),
600// &[("impl A for B<", 0)]
601// );
602// }
603
604// #[gpui::test]
605// async fn test_outline_with_extra_context(cx: &mut gpui::TestAppContext) {
606// let language = javascript_lang()
607// .with_outline_query(
608// r#"
609// (function_declaration
610// "function" @context
611// name: (_) @name
612// parameters: (formal_parameters
613// "(" @context.extra
614// ")" @context.extra)) @item
615// "#,
616// )
617// .unwrap();
618
619// let text = r#"
620// function a() {}
621// function b(c) {}
622// "#
623// .unindent();
624
625// let buffer = cx.add_model(|cx| {
626// Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(language), cx)
627// });
628// let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
629
630// // extra context nodes are included in the outline.
631// let outline = snapshot.outline(None).unwrap();
632// assert_eq!(
633// outline
634// .items
635// .iter()
636// .map(|item| (item.text.as_str(), item.depth))
637// .collect::<Vec<_>>(),
638// &[("function a()", 0), ("function b( )", 0),]
639// );
640
641// // extra context nodes do not appear in breadcrumbs.
642// let symbols = snapshot.symbols_containing(3, None).unwrap();
643// assert_eq!(
644// symbols
645// .iter()
646// .map(|item| (item.text.as_str(), item.depth))
647// .collect::<Vec<_>>(),
648// &[("function a", 0)]
649// );
650// }
651
652// #[gpui::test]
653// async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
654// let text = r#"
655// impl Person {
656// fn one() {
657// 1
658// }
659
660// fn two() {
661// 2
662// }fn three() {
663// 3
664// }
665// }
666// "#
667// .unindent();
668
669// let buffer = cx.add_model(|cx| {
670// Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx)
671// });
672// let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
673
674// // point is at the start of an item
675// assert_eq!(
676// symbols_containing(Point::new(1, 4), &snapshot),
677// vec![
678// (
679// "impl Person".to_string(),
680// Point::new(0, 0)..Point::new(10, 1)
681// ),
682// ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
683// ]
684// );
685
686// // point is in the middle of an item
687// assert_eq!(
688// symbols_containing(Point::new(2, 8), &snapshot),
689// vec![
690// (
691// "impl Person".to_string(),
692// Point::new(0, 0)..Point::new(10, 1)
693// ),
694// ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
695// ]
696// );
697
698// // point is at the end of an item
699// assert_eq!(
700// symbols_containing(Point::new(3, 5), &snapshot),
701// vec![
702// (
703// "impl Person".to_string(),
704// Point::new(0, 0)..Point::new(10, 1)
705// ),
706// ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
707// ]
708// );
709
710// // point is in between two adjacent items
711// assert_eq!(
712// symbols_containing(Point::new(7, 5), &snapshot),
713// vec![
714// (
715// "impl Person".to_string(),
716// Point::new(0, 0)..Point::new(10, 1)
717// ),
718// ("fn two".to_string(), Point::new(5, 4)..Point::new(7, 5))
719// ]
720// );
721
722// fn symbols_containing(
723// position: Point,
724// snapshot: &BufferSnapshot,
725// ) -> Vec<(String, Range<Point>)> {
726// snapshot
727// .symbols_containing(position, None)
728// .unwrap()
729// .into_iter()
730// .map(|item| {
731// (
732// item.text,
733// item.range.start.to_point(snapshot)..item.range.end.to_point(snapshot),
734// )
735// })
736// .collect()
737// }
738// }
739
740// #[gpui::test]
741// fn test_enclosing_bracket_ranges(cx: &mut AppContext) {
742// let mut assert = |selection_text, range_markers| {
743// assert_bracket_pairs(selection_text, range_markers, rust_lang(), cx)
744// };
745
746// assert(
747// indoc! {"
748// mod x {
749// moˇd y {
750
751// }
752// }
753// let foo = 1;"},
754// vec![indoc! {"
755// mod x «{»
756// mod y {
757
758// }
759// «}»
760// let foo = 1;"}],
761// );
762
763// assert(
764// indoc! {"
765// mod x {
766// mod y ˇ{
767
768// }
769// }
770// let foo = 1;"},
771// vec![
772// indoc! {"
773// mod x «{»
774// mod y {
775
776// }
777// «}»
778// let foo = 1;"},
779// indoc! {"
780// mod x {
781// mod y «{»
782
783// «}»
784// }
785// let foo = 1;"},
786// ],
787// );
788
789// assert(
790// indoc! {"
791// mod x {
792// mod y {
793
794// }ˇ
795// }
796// let foo = 1;"},
797// vec![
798// indoc! {"
799// mod x «{»
800// mod y {
801
802// }
803// «}»
804// let foo = 1;"},
805// indoc! {"
806// mod x {
807// mod y «{»
808
809// «}»
810// }
811// let foo = 1;"},
812// ],
813// );
814
815// assert(
816// indoc! {"
817// mod x {
818// mod y {
819
820// }
821// ˇ}
822// let foo = 1;"},
823// vec![indoc! {"
824// mod x «{»
825// mod y {
826
827// }
828// «}»
829// let foo = 1;"}],
830// );
831
832// assert(
833// indoc! {"
834// mod x {
835// mod y {
836
837// }
838// }
839// let fˇoo = 1;"},
840// vec![],
841// );
842
843// // Regression test: avoid crash when querying at the end of the buffer.
844// assert(
845// indoc! {"
846// mod x {
847// mod y {
848
849// }
850// }
851// let foo = 1;ˇ"},
852// vec![],
853// );
854// }
855
856// #[gpui::test]
857// fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(cx: &mut AppContext) {
858// let mut assert = |selection_text, bracket_pair_texts| {
859// assert_bracket_pairs(selection_text, bracket_pair_texts, javascript_lang(), cx)
860// };
861
862// assert(
863// indoc! {"
864// for (const a in b)ˇ {
865// // a comment that's longer than the for-loop header
866// }"},
867// vec![indoc! {"
868// for «(»const a in b«)» {
869// // a comment that's longer than the for-loop header
870// }"}],
871// );
872
873// // Regression test: even though the parent node of the parentheses (the for loop) does
874// // intersect the given range, the parentheses themselves do not contain the range, so
875// // they should not be returned. Only the curly braces contain the range.
876// assert(
877// indoc! {"
878// for (const a in b) {ˇ
879// // a comment that's longer than the for-loop header
880// }"},
881// vec![indoc! {"
882// for (const a in b) «{»
883// // a comment that's longer than the for-loop header
884// «}»"}],
885// );
886// }
887
888// #[gpui::test]
889// fn test_range_for_syntax_ancestor(cx: &mut AppContext) {
890// cx.add_model(|cx| {
891// let text = "fn a() { b(|c| {}) }";
892// let buffer =
893// Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx);
894// let snapshot = buffer.snapshot();
895
896// assert_eq!(
897// snapshot.range_for_syntax_ancestor(empty_range_at(text, "|")),
898// Some(range_of(text, "|"))
899// );
900// assert_eq!(
901// snapshot.range_for_syntax_ancestor(range_of(text, "|")),
902// Some(range_of(text, "|c|"))
903// );
904// assert_eq!(
905// snapshot.range_for_syntax_ancestor(range_of(text, "|c|")),
906// Some(range_of(text, "|c| {}"))
907// );
908// assert_eq!(
909// snapshot.range_for_syntax_ancestor(range_of(text, "|c| {}")),
910// Some(range_of(text, "(|c| {})"))
911// );
912
913// buffer
914// });
915
916// fn empty_range_at(text: &str, part: &str) -> Range<usize> {
917// let start = text.find(part).unwrap();
918// start..start
919// }
920
921// fn range_of(text: &str, part: &str) -> Range<usize> {
922// let start = text.find(part).unwrap();
923// start..start + part.len()
924// }
925// }
926
927// #[gpui::test]
928// fn test_autoindent_with_soft_tabs(cx: &mut AppContext) {
929// init_settings(cx, |_| {});
930
931// cx.add_model(|cx| {
932// let text = "fn a() {}";
933// let mut buffer =
934// Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx);
935
936// buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
937// assert_eq!(buffer.text(), "fn a() {\n \n}");
938
939// buffer.edit(
940// [(Point::new(1, 4)..Point::new(1, 4), "b()\n")],
941// Some(AutoindentMode::EachLine),
942// cx,
943// );
944// assert_eq!(buffer.text(), "fn a() {\n b()\n \n}");
945
946// // Create a field expression on a new line, causing that line
947// // to be indented.
948// buffer.edit(
949// [(Point::new(2, 4)..Point::new(2, 4), ".c")],
950// Some(AutoindentMode::EachLine),
951// cx,
952// );
953// assert_eq!(buffer.text(), "fn a() {\n b()\n .c\n}");
954
955// // Remove the dot so that the line is no longer a field expression,
956// // causing the line to be outdented.
957// buffer.edit(
958// [(Point::new(2, 8)..Point::new(2, 9), "")],
959// Some(AutoindentMode::EachLine),
960// cx,
961// );
962// assert_eq!(buffer.text(), "fn a() {\n b()\n c\n}");
963
964// buffer
965// });
966// }
967
968// #[gpui::test]
969// fn test_autoindent_with_hard_tabs(cx: &mut AppContext) {
970// init_settings(cx, |settings| {
971// settings.defaults.hard_tabs = Some(true);
972// });
973
974// cx.add_model(|cx| {
975// let text = "fn a() {}";
976// let mut buffer =
977// Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx);
978
979// buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
980// assert_eq!(buffer.text(), "fn a() {\n\t\n}");
981
982// buffer.edit(
983// [(Point::new(1, 1)..Point::new(1, 1), "b()\n")],
984// Some(AutoindentMode::EachLine),
985// cx,
986// );
987// assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\n}");
988
989// // Create a field expression on a new line, causing that line
990// // to be indented.
991// buffer.edit(
992// [(Point::new(2, 1)..Point::new(2, 1), ".c")],
993// Some(AutoindentMode::EachLine),
994// cx,
995// );
996// assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\t.c\n}");
997
998// // Remove the dot so that the line is no longer a field expression,
999// // causing the line to be outdented.
1000// buffer.edit(
1001// [(Point::new(2, 2)..Point::new(2, 3), "")],
1002// Some(AutoindentMode::EachLine),
1003// cx,
1004// );
1005// assert_eq!(buffer.text(), "fn a() {\n\tb()\n\tc\n}");
1006
1007// buffer
1008// });
1009// }
1010
1011// #[gpui::test]
1012// fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppContext) {
1013// init_settings(cx, |_| {});
1014
1015// cx.add_model(|cx| {
1016// let mut buffer = Buffer::new(
1017// 0,
1018// cx.model_id() as u64,
1019// "
1020// fn a() {
1021// c;
1022// d;
1023// }
1024// "
1025// .unindent(),
1026// )
1027// .with_language(Arc::new(rust_lang()), cx);
1028
1029// // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
1030// // their indentation is not adjusted.
1031// buffer.edit_via_marked_text(
1032// &"
1033// fn a() {
1034// c«()»;
1035// d«()»;
1036// }
1037// "
1038// .unindent(),
1039// Some(AutoindentMode::EachLine),
1040// cx,
1041// );
1042// assert_eq!(
1043// buffer.text(),
1044// "
1045// fn a() {
1046// c();
1047// d();
1048// }
1049// "
1050// .unindent()
1051// );
1052
1053// // When appending new content after these lines, the indentation is based on the
1054// // preceding lines' actual indentation.
1055// buffer.edit_via_marked_text(
1056// &"
1057// fn a() {
1058// c«
1059// .f
1060// .g()»;
1061// d«
1062// .f
1063// .g()»;
1064// }
1065// "
1066// .unindent(),
1067// Some(AutoindentMode::EachLine),
1068// cx,
1069// );
1070
1071// assert_eq!(
1072// buffer.text(),
1073// "
1074// fn a() {
1075// c
1076// .f
1077// .g();
1078// d
1079// .f
1080// .g();
1081// }
1082// "
1083// .unindent()
1084// );
1085// buffer
1086// });
1087
1088// cx.add_model(|cx| {
1089// let mut buffer = Buffer::new(
1090// 0,
1091// cx.model_id() as u64,
1092// "
1093// fn a() {
1094// b();
1095// |
1096// "
1097// .replace("|", "") // marker to preserve trailing whitespace
1098// .unindent(),
1099// )
1100// .with_language(Arc::new(rust_lang()), cx);
1101
1102// // Insert a closing brace. It is outdented.
1103// buffer.edit_via_marked_text(
1104// &"
1105// fn a() {
1106// b();
1107// «}»
1108// "
1109// .unindent(),
1110// Some(AutoindentMode::EachLine),
1111// cx,
1112// );
1113// assert_eq!(
1114// buffer.text(),
1115// "
1116// fn a() {
1117// b();
1118// }
1119// "
1120// .unindent()
1121// );
1122
1123// // Manually edit the leading whitespace. The edit is preserved.
1124// buffer.edit_via_marked_text(
1125// &"
1126// fn a() {
1127// b();
1128// « »}
1129// "
1130// .unindent(),
1131// Some(AutoindentMode::EachLine),
1132// cx,
1133// );
1134// assert_eq!(
1135// buffer.text(),
1136// "
1137// fn a() {
1138// b();
1139// }
1140// "
1141// .unindent()
1142// );
1143// buffer
1144// });
1145// }
1146
1147// #[gpui::test]
1148// fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut AppContext) {
1149// init_settings(cx, |_| {});
1150
1151// cx.add_model(|cx| {
1152// let mut buffer = Buffer::new(
1153// 0,
1154// cx.model_id() as u64,
1155// "
1156// fn a() {
1157// i
1158// }
1159// "
1160// .unindent(),
1161// )
1162// .with_language(Arc::new(rust_lang()), cx);
1163
1164// // Regression test: line does not get outdented due to syntax error
1165// buffer.edit_via_marked_text(
1166// &"
1167// fn a() {
1168// i«f let Some(x) = y»
1169// }
1170// "
1171// .unindent(),
1172// Some(AutoindentMode::EachLine),
1173// cx,
1174// );
1175// assert_eq!(
1176// buffer.text(),
1177// "
1178// fn a() {
1179// if let Some(x) = y
1180// }
1181// "
1182// .unindent()
1183// );
1184
1185// buffer.edit_via_marked_text(
1186// &"
1187// fn a() {
1188// if let Some(x) = y« {»
1189// }
1190// "
1191// .unindent(),
1192// Some(AutoindentMode::EachLine),
1193// cx,
1194// );
1195// assert_eq!(
1196// buffer.text(),
1197// "
1198// fn a() {
1199// if let Some(x) = y {
1200// }
1201// "
1202// .unindent()
1203// );
1204
1205// buffer
1206// });
1207// }
1208
1209// #[gpui::test]
1210// fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut AppContext) {
1211// init_settings(cx, |_| {});
1212
1213// cx.add_model(|cx| {
1214// let mut buffer = Buffer::new(
1215// 0,
1216// cx.model_id() as u64,
1217// "
1218// fn a() {}
1219// "
1220// .unindent(),
1221// )
1222// .with_language(Arc::new(rust_lang()), cx);
1223
1224// buffer.edit_via_marked_text(
1225// &"
1226// fn a(«
1227// b») {}
1228// "
1229// .unindent(),
1230// Some(AutoindentMode::EachLine),
1231// cx,
1232// );
1233// assert_eq!(
1234// buffer.text(),
1235// "
1236// fn a(
1237// b) {}
1238// "
1239// .unindent()
1240// );
1241
1242// // The indentation suggestion changed because `@end` node (a close paren)
1243// // is now at the beginning of the line.
1244// buffer.edit_via_marked_text(
1245// &"
1246// fn a(
1247// ˇ) {}
1248// "
1249// .unindent(),
1250// Some(AutoindentMode::EachLine),
1251// cx,
1252// );
1253// assert_eq!(
1254// buffer.text(),
1255// "
1256// fn a(
1257// ) {}
1258// "
1259// .unindent()
1260// );
1261
1262// buffer
1263// });
1264// }
1265
1266// #[gpui::test]
1267// fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut AppContext) {
1268// init_settings(cx, |_| {});
1269
1270// cx.add_model(|cx| {
1271// let text = "a\nb";
1272// let mut buffer =
1273// Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx);
1274// buffer.edit(
1275// [(0..1, "\n"), (2..3, "\n")],
1276// Some(AutoindentMode::EachLine),
1277// cx,
1278// );
1279// assert_eq!(buffer.text(), "\n\n\n");
1280// buffer
1281// });
1282// }
1283
1284// #[gpui::test]
1285// fn test_autoindent_multi_line_insertion(cx: &mut AppContext) {
1286// init_settings(cx, |_| {});
1287
1288// cx.add_model(|cx| {
1289// let text = "
1290// const a: usize = 1;
1291// fn b() {
1292// if c {
1293// let d = 2;
1294// }
1295// }
1296// "
1297// .unindent();
1298
1299// let mut buffer =
1300// Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx);
1301// buffer.edit(
1302// [(Point::new(3, 0)..Point::new(3, 0), "e(\n f()\n);\n")],
1303// Some(AutoindentMode::EachLine),
1304// cx,
1305// );
1306// assert_eq!(
1307// buffer.text(),
1308// "
1309// const a: usize = 1;
1310// fn b() {
1311// if c {
1312// e(
1313// f()
1314// );
1315// let d = 2;
1316// }
1317// }
1318// "
1319// .unindent()
1320// );
1321
1322// buffer
1323// });
1324// }
1325
1326// #[gpui::test]
1327// fn test_autoindent_block_mode(cx: &mut AppContext) {
1328// init_settings(cx, |_| {});
1329
1330// cx.add_model(|cx| {
1331// let text = r#"
1332// fn a() {
1333// b();
1334// }
1335// "#
1336// .unindent();
1337// let mut buffer =
1338// Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx);
1339
1340// // When this text was copied, both of the quotation marks were at the same
1341// // indent level, but the indentation of the first line was not included in
1342// // the copied text. This information is retained in the
1343// // 'original_indent_columns' vector.
1344// let original_indent_columns = vec![4];
1345// let inserted_text = r#"
1346// "
1347// c
1348// d
1349// e
1350// "
1351// "#
1352// .unindent();
1353
1354// // Insert the block at column zero. The entire block is indented
1355// // so that the first line matches the previous line's indentation.
1356// buffer.edit(
1357// [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
1358// Some(AutoindentMode::Block {
1359// original_indent_columns: original_indent_columns.clone(),
1360// }),
1361// cx,
1362// );
1363// assert_eq!(
1364// buffer.text(),
1365// r#"
1366// fn a() {
1367// b();
1368// "
1369// c
1370// d
1371// e
1372// "
1373// }
1374// "#
1375// .unindent()
1376// );
1377
1378// // Grouping is disabled in tests, so we need 2 undos
1379// buffer.undo(cx); // Undo the auto-indent
1380// buffer.undo(cx); // Undo the original edit
1381
1382// // Insert the block at a deeper indent level. The entire block is outdented.
1383// buffer.edit([(Point::new(2, 0)..Point::new(2, 0), " ")], None, cx);
1384// buffer.edit(
1385// [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
1386// Some(AutoindentMode::Block {
1387// original_indent_columns: original_indent_columns.clone(),
1388// }),
1389// cx,
1390// );
1391// assert_eq!(
1392// buffer.text(),
1393// r#"
1394// fn a() {
1395// b();
1396// "
1397// c
1398// d
1399// e
1400// "
1401// }
1402// "#
1403// .unindent()
1404// );
1405
1406// buffer
1407// });
1408// }
1409
1410// #[gpui::test]
1411// fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut AppContext) {
1412// init_settings(cx, |_| {});
1413
1414// cx.add_model(|cx| {
1415// let text = r#"
1416// fn a() {
1417// if b() {
1418
1419// }
1420// }
1421// "#
1422// .unindent();
1423// let mut buffer =
1424// Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(rust_lang()), cx);
1425
1426// // The original indent columns are not known, so this text is
1427// // auto-indented in a block as if the first line was copied in
1428// // its entirety.
1429// let original_indent_columns = Vec::new();
1430// let inserted_text = " c\n .d()\n .e();";
1431
1432// // Insert the block at column zero. The entire block is indented
1433// // so that the first line matches the previous line's indentation.
1434// buffer.edit(
1435// [(Point::new(2, 0)..Point::new(2, 0), inserted_text)],
1436// Some(AutoindentMode::Block {
1437// original_indent_columns: original_indent_columns.clone(),
1438// }),
1439// cx,
1440// );
1441// assert_eq!(
1442// buffer.text(),
1443// r#"
1444// fn a() {
1445// if b() {
1446// c
1447// .d()
1448// .e();
1449// }
1450// }
1451// "#
1452// .unindent()
1453// );
1454
1455// // Grouping is disabled in tests, so we need 2 undos
1456// buffer.undo(cx); // Undo the auto-indent
1457// buffer.undo(cx); // Undo the original edit
1458
1459// // Insert the block at a deeper indent level. The entire block is outdented.
1460// buffer.edit(
1461// [(Point::new(2, 0)..Point::new(2, 0), " ".repeat(12))],
1462// None,
1463// cx,
1464// );
1465// buffer.edit(
1466// [(Point::new(2, 12)..Point::new(2, 12), inserted_text)],
1467// Some(AutoindentMode::Block {
1468// original_indent_columns: Vec::new(),
1469// }),
1470// cx,
1471// );
1472// assert_eq!(
1473// buffer.text(),
1474// r#"
1475// fn a() {
1476// if b() {
1477// c
1478// .d()
1479// .e();
1480// }
1481// }
1482// "#
1483// .unindent()
1484// );
1485
1486// buffer
1487// });
1488// }
1489
1490// #[gpui::test]
1491// fn test_autoindent_language_without_indents_query(cx: &mut AppContext) {
1492// init_settings(cx, |_| {});
1493
1494// cx.add_model(|cx| {
1495// let text = "
1496// * one
1497// - a
1498// - b
1499// * two
1500// "
1501// .unindent();
1502
1503// let mut buffer = Buffer::new(0, cx.model_id() as u64, text).with_language(
1504// Arc::new(Language::new(
1505// LanguageConfig {
1506// name: "Markdown".into(),
1507// auto_indent_using_last_non_empty_line: false,
1508// ..Default::default()
1509// },
1510// Some(tree_sitter_json::language()),
1511// )),
1512// cx,
1513// );
1514// buffer.edit(
1515// [(Point::new(3, 0)..Point::new(3, 0), "\n")],
1516// Some(AutoindentMode::EachLine),
1517// cx,
1518// );
1519// assert_eq!(
1520// buffer.text(),
1521// "
1522// * one
1523// - a
1524// - b
1525
1526// * two
1527// "
1528// .unindent()
1529// );
1530// buffer
1531// });
1532// }
1533
1534// #[gpui::test]
1535// fn test_autoindent_with_injected_languages(cx: &mut AppContext) {
1536// init_settings(cx, |settings| {
1537// settings.languages.extend([
1538// (
1539// "HTML".into(),
1540// LanguageSettingsContent {
1541// tab_size: Some(2.try_into().unwrap()),
1542// ..Default::default()
1543// },
1544// ),
1545// (
1546// "JavaScript".into(),
1547// LanguageSettingsContent {
1548// tab_size: Some(8.try_into().unwrap()),
1549// ..Default::default()
1550// },
1551// ),
1552// ])
1553// });
1554
1555// let html_language = Arc::new(html_lang());
1556
1557// let javascript_language = Arc::new(javascript_lang());
1558
1559// let language_registry = Arc::new(LanguageRegistry::test());
1560// language_registry.add(html_language.clone());
1561// language_registry.add(javascript_language.clone());
1562
1563// cx.add_model(|cx| {
1564// let (text, ranges) = marked_text_ranges(
1565// &"
1566// <div>ˇ
1567// </div>
1568// <script>
1569// init({ˇ
1570// })
1571// </script>
1572// <span>ˇ
1573// </span>
1574// "
1575// .unindent(),
1576// false,
1577// );
1578
1579// let mut buffer = Buffer::new(0, cx.model_id() as u64, text);
1580// buffer.set_language_registry(language_registry);
1581// buffer.set_language(Some(html_language), cx);
1582// buffer.edit(
1583// ranges.into_iter().map(|range| (range, "\na")),
1584// Some(AutoindentMode::EachLine),
1585// cx,
1586// );
1587// assert_eq!(
1588// buffer.text(),
1589// "
1590// <div>
1591// a
1592// </div>
1593// <script>
1594// init({
1595// a
1596// })
1597// </script>
1598// <span>
1599// a
1600// </span>
1601// "
1602// .unindent()
1603// );
1604// buffer
1605// });
1606// }
1607
1608// #[gpui::test]
1609// fn test_autoindent_query_with_outdent_captures(cx: &mut AppContext) {
1610// init_settings(cx, |settings| {
1611// settings.defaults.tab_size = Some(2.try_into().unwrap());
1612// });
1613
1614// cx.add_model(|cx| {
1615// let mut buffer =
1616// Buffer::new(0, cx.model_id() as u64, "").with_language(Arc::new(ruby_lang()), cx);
1617
1618// let text = r#"
1619// class C
1620// def a(b, c)
1621// puts b
1622// puts c
1623// rescue
1624// puts "errored"
1625// exit 1
1626// end
1627// end
1628// "#
1629// .unindent();
1630
1631// buffer.edit([(0..0, text)], Some(AutoindentMode::EachLine), cx);
1632
1633// assert_eq!(
1634// buffer.text(),
1635// r#"
1636// class C
1637// def a(b, c)
1638// puts b
1639// puts c
1640// rescue
1641// puts "errored"
1642// exit 1
1643// end
1644// end
1645// "#
1646// .unindent()
1647// );
1648
1649// buffer
1650// });
1651// }
1652
1653// #[gpui::test]
1654// fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
1655// init_settings(cx, |_| {});
1656
1657// cx.add_model(|cx| {
1658// let language = Language::new(
1659// LanguageConfig {
1660// name: "JavaScript".into(),
1661// line_comment: Some("// ".into()),
1662// brackets: BracketPairConfig {
1663// pairs: vec![
1664// BracketPair {
1665// start: "{".into(),
1666// end: "}".into(),
1667// close: true,
1668// newline: false,
1669// },
1670// BracketPair {
1671// start: "'".into(),
1672// end: "'".into(),
1673// close: true,
1674// newline: false,
1675// },
1676// ],
1677// disabled_scopes_by_bracket_ix: vec![
1678// Vec::new(), //
1679// vec!["string".into()],
1680// ],
1681// },
1682// overrides: [(
1683// "element".into(),
1684// LanguageConfigOverride {
1685// line_comment: Override::Remove { remove: true },
1686// block_comment: Override::Set(("{/*".into(), "*/}".into())),
1687// ..Default::default()
1688// },
1689// )]
1690// .into_iter()
1691// .collect(),
1692// ..Default::default()
1693// },
1694// Some(tree_sitter_typescript::language_tsx()),
1695// )
1696// .with_override_query(
1697// r#"
1698// (jsx_element) @element
1699// (string) @string
1700// "#,
1701// )
1702// .unwrap();
1703
1704// let text = r#"a["b"] = <C d="e"></C>;"#;
1705
1706// let buffer =
1707// Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(language), cx);
1708// let snapshot = buffer.snapshot();
1709
1710// let config = snapshot.language_scope_at(0).unwrap();
1711// assert_eq!(config.line_comment_prefix().unwrap().as_ref(), "// ");
1712// // Both bracket pairs are enabled
1713// assert_eq!(
1714// config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1715// &[true, true]
1716// );
1717
1718// let string_config = snapshot.language_scope_at(3).unwrap();
1719// assert_eq!(string_config.line_comment_prefix().unwrap().as_ref(), "// ");
1720// // Second bracket pair is disabled
1721// assert_eq!(
1722// string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1723// &[true, false]
1724// );
1725
1726// let element_config = snapshot.language_scope_at(10).unwrap();
1727// assert_eq!(element_config.line_comment_prefix(), None);
1728// assert_eq!(
1729// element_config.block_comment_delimiters(),
1730// Some((&"{/*".into(), &"*/}".into()))
1731// );
1732// // Both bracket pairs are enabled
1733// assert_eq!(
1734// element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1735// &[true, true]
1736// );
1737
1738// buffer
1739// });
1740// }
1741
1742// #[gpui::test]
1743// fn test_language_scope_at_with_rust(cx: &mut AppContext) {
1744// init_settings(cx, |_| {});
1745
1746// cx.add_model(|cx| {
1747// let language = Language::new(
1748// LanguageConfig {
1749// name: "Rust".into(),
1750// brackets: BracketPairConfig {
1751// pairs: vec![
1752// BracketPair {
1753// start: "{".into(),
1754// end: "}".into(),
1755// close: true,
1756// newline: false,
1757// },
1758// BracketPair {
1759// start: "'".into(),
1760// end: "'".into(),
1761// close: true,
1762// newline: false,
1763// },
1764// ],
1765// disabled_scopes_by_bracket_ix: vec![
1766// Vec::new(), //
1767// vec!["string".into()],
1768// ],
1769// },
1770// ..Default::default()
1771// },
1772// Some(tree_sitter_rust::language()),
1773// )
1774// .with_override_query(
1775// r#"
1776// (string_literal) @string
1777// "#,
1778// )
1779// .unwrap();
1780
1781// let text = r#"
1782// const S: &'static str = "hello";
1783// "#
1784// .unindent();
1785
1786// let buffer = Buffer::new(0, cx.model_id() as u64, text.clone())
1787// .with_language(Arc::new(language), cx);
1788// let snapshot = buffer.snapshot();
1789
1790// // By default, all brackets are enabled
1791// let config = snapshot.language_scope_at(0).unwrap();
1792// assert_eq!(
1793// config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1794// &[true, true]
1795// );
1796
1797// // Within a string, the quotation brackets are disabled.
1798// let string_config = snapshot
1799// .language_scope_at(text.find("ello").unwrap())
1800// .unwrap();
1801// assert_eq!(
1802// string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1803// &[true, false]
1804// );
1805
1806// buffer
1807// });
1808// }
1809
1810// #[gpui::test]
1811// fn test_language_scope_at_with_combined_injections(cx: &mut AppContext) {
1812// init_settings(cx, |_| {});
1813
1814// cx.add_model(|cx| {
1815// let text = r#"
1816// <ol>
1817// <% people.each do |person| %>
1818// <li>
1819// <%= person.name %>
1820// </li>
1821// <% end %>
1822// </ol>
1823// "#
1824// .unindent();
1825
1826// let language_registry = Arc::new(LanguageRegistry::test());
1827// language_registry.add(Arc::new(ruby_lang()));
1828// language_registry.add(Arc::new(html_lang()));
1829// language_registry.add(Arc::new(erb_lang()));
1830
1831// let mut buffer = Buffer::new(0, cx.model_id() as u64, text);
1832// buffer.set_language_registry(language_registry.clone());
1833// buffer.set_language(
1834// language_registry
1835// .language_for_name("ERB")
1836// .now_or_never()
1837// .unwrap()
1838// .ok(),
1839// cx,
1840// );
1841
1842// let snapshot = buffer.snapshot();
1843// let html_config = snapshot.language_scope_at(Point::new(2, 4)).unwrap();
1844// assert_eq!(html_config.line_comment_prefix(), None);
1845// assert_eq!(
1846// html_config.block_comment_delimiters(),
1847// Some((&"<!--".into(), &"-->".into()))
1848// );
1849
1850// let ruby_config = snapshot.language_scope_at(Point::new(3, 12)).unwrap();
1851// assert_eq!(ruby_config.line_comment_prefix().unwrap().as_ref(), "# ");
1852// assert_eq!(ruby_config.block_comment_delimiters(), None);
1853
1854// buffer
1855// });
1856// }
1857
1858// #[gpui::test]
1859// fn test_serialization(cx: &mut gpui::AppContext) {
1860// let mut now = Instant::now();
1861
1862// let buffer1 = cx.add_model(|cx| {
1863// let mut buffer = Buffer::new(0, cx.model_id() as u64, "abc");
1864// buffer.edit([(3..3, "D")], None, cx);
1865
1866// now += Duration::from_secs(1);
1867// buffer.start_transaction_at(now);
1868// buffer.edit([(4..4, "E")], None, cx);
1869// buffer.end_transaction_at(now, cx);
1870// assert_eq!(buffer.text(), "abcDE");
1871
1872// buffer.undo(cx);
1873// assert_eq!(buffer.text(), "abcD");
1874
1875// buffer.edit([(4..4, "F")], None, cx);
1876// assert_eq!(buffer.text(), "abcDF");
1877// buffer
1878// });
1879// assert_eq!(buffer1.read(cx).text(), "abcDF");
1880
1881// let state = buffer1.read(cx).to_proto();
1882// let ops = cx
1883// .background()
1884// .block(buffer1.read(cx).serialize_ops(None, cx));
1885// let buffer2 = cx.add_model(|cx| {
1886// let mut buffer = Buffer::from_proto(1, state, None).unwrap();
1887// buffer
1888// .apply_ops(
1889// ops.into_iter()
1890// .map(|op| proto::deserialize_operation(op).unwrap()),
1891// cx,
1892// )
1893// .unwrap();
1894// buffer
1895// });
1896// assert_eq!(buffer2.read(cx).text(), "abcDF");
1897// }
1898
1899// #[gpui::test(iterations = 100)]
1900// fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
1901// let min_peers = env::var("MIN_PEERS")
1902// .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
1903// .unwrap_or(1);
1904// let max_peers = env::var("MAX_PEERS")
1905// .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
1906// .unwrap_or(5);
1907// let operations = env::var("OPERATIONS")
1908// .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1909// .unwrap_or(10);
1910
1911// let base_text_len = rng.gen_range(0..10);
1912// let base_text = RandomCharIter::new(&mut rng)
1913// .take(base_text_len)
1914// .collect::<String>();
1915// let mut replica_ids = Vec::new();
1916// let mut buffers = Vec::new();
1917// let network = Rc::new(RefCell::new(Network::new(rng.clone())));
1918// let base_buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, base_text.as_str()));
1919
1920// for i in 0..rng.gen_range(min_peers..=max_peers) {
1921// let buffer = cx.add_model(|cx| {
1922// let state = base_buffer.read(cx).to_proto();
1923// let ops = cx
1924// .background()
1925// .block(base_buffer.read(cx).serialize_ops(None, cx));
1926// let mut buffer = Buffer::from_proto(i as ReplicaId, state, None).unwrap();
1927// buffer
1928// .apply_ops(
1929// ops.into_iter()
1930// .map(|op| proto::deserialize_operation(op).unwrap()),
1931// cx,
1932// )
1933// .unwrap();
1934// buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1935// let network = network.clone();
1936// cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1937// if let Event::Operation(op) = event {
1938// network
1939// .borrow_mut()
1940// .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
1941// }
1942// })
1943// .detach();
1944// buffer
1945// });
1946// buffers.push(buffer);
1947// replica_ids.push(i as ReplicaId);
1948// network.borrow_mut().add_peer(i as ReplicaId);
1949// log::info!("Adding initial peer with replica id {}", i);
1950// }
1951
1952// log::info!("initial text: {:?}", base_text);
1953
1954// let mut now = Instant::now();
1955// let mut mutation_count = operations;
1956// let mut next_diagnostic_id = 0;
1957// let mut active_selections = BTreeMap::default();
1958// loop {
1959// let replica_index = rng.gen_range(0..replica_ids.len());
1960// let replica_id = replica_ids[replica_index];
1961// let buffer = &mut buffers[replica_index];
1962// let mut new_buffer = None;
1963// match rng.gen_range(0..100) {
1964// 0..=29 if mutation_count != 0 => {
1965// buffer.update(cx, |buffer, cx| {
1966// buffer.start_transaction_at(now);
1967// buffer.randomly_edit(&mut rng, 5, cx);
1968// buffer.end_transaction_at(now, cx);
1969// log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1970// });
1971// mutation_count -= 1;
1972// }
1973// 30..=39 if mutation_count != 0 => {
1974// buffer.update(cx, |buffer, cx| {
1975// if rng.gen_bool(0.2) {
1976// log::info!("peer {} clearing active selections", replica_id);
1977// active_selections.remove(&replica_id);
1978// buffer.remove_active_selections(cx);
1979// } else {
1980// let mut selections = Vec::new();
1981// for id in 0..rng.gen_range(1..=5) {
1982// let range = buffer.random_byte_range(0, &mut rng);
1983// selections.push(Selection {
1984// id,
1985// start: buffer.anchor_before(range.start),
1986// end: buffer.anchor_before(range.end),
1987// reversed: false,
1988// goal: SelectionGoal::None,
1989// });
1990// }
1991// let selections: Arc<[Selection<Anchor>]> = selections.into();
1992// log::info!(
1993// "peer {} setting active selections: {:?}",
1994// replica_id,
1995// selections
1996// );
1997// active_selections.insert(replica_id, selections.clone());
1998// buffer.set_active_selections(selections, false, Default::default(), cx);
1999// }
2000// });
2001// mutation_count -= 1;
2002// }
2003// 40..=49 if mutation_count != 0 && replica_id == 0 => {
2004// let entry_count = rng.gen_range(1..=5);
2005// buffer.update(cx, |buffer, cx| {
2006// let diagnostics = DiagnosticSet::new(
2007// (0..entry_count).map(|_| {
2008// let range = buffer.random_byte_range(0, &mut rng);
2009// let range = range.to_point_utf16(buffer);
2010// let range = range.start..range.end;
2011// DiagnosticEntry {
2012// range,
2013// diagnostic: Diagnostic {
2014// message: post_inc(&mut next_diagnostic_id).to_string(),
2015// ..Default::default()
2016// },
2017// }
2018// }),
2019// buffer,
2020// );
2021// log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
2022// buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
2023// });
2024// mutation_count -= 1;
2025// }
2026// 50..=59 if replica_ids.len() < max_peers => {
2027// let old_buffer_state = buffer.read(cx).to_proto();
2028// let old_buffer_ops = cx
2029// .background()
2030// .block(buffer.read(cx).serialize_ops(None, cx));
2031// let new_replica_id = (0..=replica_ids.len() as ReplicaId)
2032// .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
2033// .choose(&mut rng)
2034// .unwrap();
2035// log::info!(
2036// "Adding new replica {} (replicating from {})",
2037// new_replica_id,
2038// replica_id
2039// );
2040// new_buffer = Some(cx.add_model(|cx| {
2041// let mut new_buffer =
2042// Buffer::from_proto(new_replica_id, old_buffer_state, None).unwrap();
2043// new_buffer
2044// .apply_ops(
2045// old_buffer_ops
2046// .into_iter()
2047// .map(|op| deserialize_operation(op).unwrap()),
2048// cx,
2049// )
2050// .unwrap();
2051// log::info!(
2052// "New replica {} text: {:?}",
2053// new_buffer.replica_id(),
2054// new_buffer.text()
2055// );
2056// new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2057// let network = network.clone();
2058// cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2059// if let Event::Operation(op) = event {
2060// network.borrow_mut().broadcast(
2061// buffer.replica_id(),
2062// vec![proto::serialize_operation(op)],
2063// );
2064// }
2065// })
2066// .detach();
2067// new_buffer
2068// }));
2069// network.borrow_mut().replicate(replica_id, new_replica_id);
2070
2071// if new_replica_id as usize == replica_ids.len() {
2072// replica_ids.push(new_replica_id);
2073// } else {
2074// let new_buffer = new_buffer.take().unwrap();
2075// while network.borrow().has_unreceived(new_replica_id) {
2076// let ops = network
2077// .borrow_mut()
2078// .receive(new_replica_id)
2079// .into_iter()
2080// .map(|op| proto::deserialize_operation(op).unwrap());
2081// if ops.len() > 0 {
2082// log::info!(
2083// "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2084// new_replica_id,
2085// buffer.read(cx).version(),
2086// ops.len(),
2087// ops
2088// );
2089// new_buffer.update(cx, |new_buffer, cx| {
2090// new_buffer.apply_ops(ops, cx).unwrap();
2091// });
2092// }
2093// }
2094// buffers[new_replica_id as usize] = new_buffer;
2095// }
2096// }
2097// 60..=69 if mutation_count != 0 => {
2098// buffer.update(cx, |buffer, cx| {
2099// buffer.randomly_undo_redo(&mut rng, cx);
2100// log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2101// });
2102// mutation_count -= 1;
2103// }
2104// _ if network.borrow().has_unreceived(replica_id) => {
2105// let ops = network
2106// .borrow_mut()
2107// .receive(replica_id)
2108// .into_iter()
2109// .map(|op| proto::deserialize_operation(op).unwrap());
2110// if ops.len() > 0 {
2111// log::info!(
2112// "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2113// replica_id,
2114// buffer.read(cx).version(),
2115// ops.len(),
2116// ops
2117// );
2118// buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
2119// }
2120// }
2121// _ => {}
2122// }
2123
2124// now += Duration::from_millis(rng.gen_range(0..=200));
2125// buffers.extend(new_buffer);
2126
2127// for buffer in &buffers {
2128// buffer.read(cx).check_invariants();
2129// }
2130
2131// if mutation_count == 0 && network.borrow().is_idle() {
2132// break;
2133// }
2134// }
2135
2136// let first_buffer = buffers[0].read(cx).snapshot();
2137// for buffer in &buffers[1..] {
2138// let buffer = buffer.read(cx).snapshot();
2139// assert_eq!(
2140// buffer.version(),
2141// first_buffer.version(),
2142// "Replica {} version != Replica 0 version",
2143// buffer.replica_id()
2144// );
2145// assert_eq!(
2146// buffer.text(),
2147// first_buffer.text(),
2148// "Replica {} text != Replica 0 text",
2149// buffer.replica_id()
2150// );
2151// assert_eq!(
2152// buffer
2153// .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
2154// .collect::<Vec<_>>(),
2155// first_buffer
2156// .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2157// .collect::<Vec<_>>(),
2158// "Replica {} diagnostics != Replica 0 diagnostics",
2159// buffer.replica_id()
2160// );
2161// }
2162
2163// for buffer in &buffers {
2164// let buffer = buffer.read(cx).snapshot();
2165// let actual_remote_selections = buffer
2166// .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
2167// .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2168// .collect::<Vec<_>>();
2169// let expected_remote_selections = active_selections
2170// .iter()
2171// .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2172// .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2173// .collect::<Vec<_>>();
2174// assert_eq!(
2175// actual_remote_selections,
2176// expected_remote_selections,
2177// "Replica {} remote selections != expected selections",
2178// buffer.replica_id()
2179// );
2180// }
2181// }
2182
2183// #[test]
2184// fn test_contiguous_ranges() {
2185// assert_eq!(
2186// contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2187// &[1..4, 5..7, 9..13]
2188// );
2189
2190// // Respects the `max_len` parameter
2191// assert_eq!(
2192// contiguous_ranges(
2193// [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2194// 3
2195// )
2196// .collect::<Vec<_>>(),
2197// &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2198// );
2199// }
2200
2201// #[gpui::test(iterations = 500)]
2202// fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2203// // Generate a random multi-line string containing
2204// // some lines with trailing whitespace.
2205// let mut text = String::new();
2206// for _ in 0..rng.gen_range(0..16) {
2207// for _ in 0..rng.gen_range(0..36) {
2208// text.push(match rng.gen_range(0..10) {
2209// 0..=1 => ' ',
2210// 3 => '\t',
2211// _ => rng.gen_range('a'..'z'),
2212// });
2213// }
2214// text.push('\n');
2215// }
2216
2217// match rng.gen_range(0..10) {
2218// // sometimes remove the last newline
2219// 0..=1 => drop(text.pop()), //
2220
2221// // sometimes add extra newlines
2222// 2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2223// _ => {}
2224// }
2225
2226// let rope = Rope::from(text.as_str());
2227// let actual_ranges = trailing_whitespace_ranges(&rope);
2228// let expected_ranges = TRAILING_WHITESPACE_REGEX
2229// .find_iter(&text)
2230// .map(|m| m.range())
2231// .collect::<Vec<_>>();
2232// assert_eq!(
2233// actual_ranges,
2234// expected_ranges,
2235// "wrong ranges for text lines:\n{:?}",
2236// text.split("\n").collect::<Vec<_>>()
2237// );
2238// }
2239
2240// fn ruby_lang() -> Language {
2241// Language::new(
2242// LanguageConfig {
2243// name: "Ruby".into(),
2244// path_suffixes: vec!["rb".to_string()],
2245// line_comment: Some("# ".into()),
2246// ..Default::default()
2247// },
2248// Some(tree_sitter_ruby::language()),
2249// )
2250// .with_indents_query(
2251// r#"
2252// (class "end" @end) @indent
2253// (method "end" @end) @indent
2254// (rescue) @outdent
2255// (then) @indent
2256// "#,
2257// )
2258// .unwrap()
2259// }
2260
2261// fn html_lang() -> Language {
2262// Language::new(
2263// LanguageConfig {
2264// name: "HTML".into(),
2265// block_comment: Some(("<!--".into(), "-->".into())),
2266// ..Default::default()
2267// },
2268// Some(tree_sitter_html::language()),
2269// )
2270// .with_indents_query(
2271// "
2272// (element
2273// (start_tag) @start
2274// (end_tag)? @end) @indent
2275// ",
2276// )
2277// .unwrap()
2278// .with_injection_query(
2279// r#"
2280// (script_element
2281// (raw_text) @content
2282// (#set! "language" "javascript"))
2283// "#,
2284// )
2285// .unwrap()
2286// }
2287
2288// fn erb_lang() -> Language {
2289// Language::new(
2290// LanguageConfig {
2291// name: "ERB".into(),
2292// path_suffixes: vec!["erb".to_string()],
2293// block_comment: Some(("<%#".into(), "%>".into())),
2294// ..Default::default()
2295// },
2296// Some(tree_sitter_embedded_template::language()),
2297// )
2298// .with_injection_query(
2299// r#"
2300// (
2301// (code) @content
2302// (#set! "language" "ruby")
2303// (#set! "combined")
2304// )
2305
2306// (
2307// (content) @content
2308// (#set! "language" "html")
2309// (#set! "combined")
2310// )
2311// "#,
2312// )
2313// .unwrap()
2314// }
2315
2316// fn rust_lang() -> Language {
2317// Language::new(
2318// LanguageConfig {
2319// name: "Rust".into(),
2320// path_suffixes: vec!["rs".to_string()],
2321// ..Default::default()
2322// },
2323// Some(tree_sitter_rust::language()),
2324// )
2325// .with_indents_query(
2326// r#"
2327// (call_expression) @indent
2328// (field_expression) @indent
2329// (_ "(" ")" @end) @indent
2330// (_ "{" "}" @end) @indent
2331// "#,
2332// )
2333// .unwrap()
2334// .with_brackets_query(
2335// r#"
2336// ("{" @open "}" @close)
2337// "#,
2338// )
2339// .unwrap()
2340// .with_outline_query(
2341// r#"
2342// (struct_item
2343// "struct" @context
2344// name: (_) @name) @item
2345// (enum_item
2346// "enum" @context
2347// name: (_) @name) @item
2348// (enum_variant
2349// name: (_) @name) @item
2350// (field_declaration
2351// name: (_) @name) @item
2352// (impl_item
2353// "impl" @context
2354// trait: (_)? @name
2355// "for"? @context
2356// type: (_) @name) @item
2357// (function_item
2358// "fn" @context
2359// name: (_) @name) @item
2360// (mod_item
2361// "mod" @context
2362// name: (_) @name) @item
2363// "#,
2364// )
2365// .unwrap()
2366// }
2367
2368// fn json_lang() -> Language {
2369// Language::new(
2370// LanguageConfig {
2371// name: "Json".into(),
2372// path_suffixes: vec!["js".to_string()],
2373// ..Default::default()
2374// },
2375// Some(tree_sitter_json::language()),
2376// )
2377// }
2378
2379// fn javascript_lang() -> Language {
2380// Language::new(
2381// LanguageConfig {
2382// name: "JavaScript".into(),
2383// ..Default::default()
2384// },
2385// Some(tree_sitter_typescript::language_tsx()),
2386// )
2387// .with_brackets_query(
2388// r#"
2389// ("{" @open "}" @close)
2390// ("(" @open ")" @close)
2391// "#,
2392// )
2393// .unwrap()
2394// .with_indents_query(
2395// r#"
2396// (object "}" @end) @indent
2397// "#,
2398// )
2399// .unwrap()
2400// }
2401
2402// fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
2403// buffer.read_with(cx, |buffer, _| {
2404// let snapshot = buffer.snapshot();
2405// let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2406// layers[0].node().to_sexp()
2407// })
2408// }
2409
2410// // Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2411// fn assert_bracket_pairs(
2412// selection_text: &'static str,
2413// bracket_pair_texts: Vec<&'static str>,
2414// language: Language,
2415// cx: &mut AppContext,
2416// ) {
2417// let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2418// let buffer = cx.add_model(|cx| {
2419// Buffer::new(0, cx.model_id() as u64, expected_text.clone())
2420// .with_language(Arc::new(language), cx)
2421// });
2422// let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2423
2424// let selection_range = selection_ranges[0].clone();
2425
2426// let bracket_pairs = bracket_pair_texts
2427// .into_iter()
2428// .map(|pair_text| {
2429// let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2430// assert_eq!(bracket_text, expected_text);
2431// (ranges[0].clone(), ranges[1].clone())
2432// })
2433// .collect::<Vec<_>>();
2434
2435// assert_set_eq!(
2436// buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2437// bracket_pairs
2438// );
2439// }
2440
2441// fn init_settings(cx: &mut AppContext, f: fn(&mut AllLanguageSettingsContent)) {
2442// cx.set_global(SettingsStore::test(cx));
2443// crate::init(cx);
2444// cx.update_global::<SettingsStore, _, _>(|settings, cx| {
2445// settings.update_user_settings::<AllLanguageSettings>(cx, f);
2446// });
2447// }