1// use std::{
2// borrow::Cow,
3// ops::{Deref, DerefMut, Range},
4// sync::Arc,
5// };
6
7// use anyhow::Result;
8
9// use crate::{Editor, ToPoint};
10// use collections::HashSet;
11// use futures::Future;
12// use gpui::{json, View, ViewContext};
13// use indoc::indoc;
14// use language::{point_to_lsp, FakeLspAdapter, Language, LanguageConfig, LanguageQueries};
15// use lsp::{notification, request};
16// use multi_buffer::ToPointUtf16;
17// use project::Project;
18// use smol::stream::StreamExt;
19// use workspace::{AppState, Workspace, WorkspaceHandle};
20
21// use super::editor_test_context::EditorTestContext;
22
23// pub struct EditorLspTestContext<'a> {
24// pub cx: EditorTestContext<'a>,
25// pub lsp: lsp::FakeLanguageServer,
26// pub workspace: View<Workspace>,
27// pub buffer_lsp_url: lsp::Url,
28// }
29
30// impl<'a> EditorLspTestContext<'a> {
31// pub async fn new(
32// mut language: Language,
33// capabilities: lsp::ServerCapabilities,
34// cx: &'a mut gpui::TestAppContext,
35// ) -> EditorLspTestContext<'a> {
36// use json::json;
37
38// let app_state = cx.update(AppState::test);
39
40// cx.update(|cx| {
41// language::init(cx);
42// crate::init(cx);
43// workspace::init(app_state.clone(), cx);
44// Project::init_settings(cx);
45// });
46
47// let file_name = format!(
48// "file.{}",
49// language
50// .path_suffixes()
51// .first()
52// .expect("language must have a path suffix for EditorLspTestContext")
53// );
54
55// let mut fake_servers = language
56// .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
57// capabilities,
58// ..Default::default()
59// }))
60// .await;
61
62// let project = Project::test(app_state.fs.clone(), [], cx).await;
63// project.update(cx, |project, _| project.languages().add(Arc::new(language)));
64
65// app_state
66// .fs
67// .as_fake()
68// .insert_tree("/root", json!({ "dir": { file_name.clone(): "" }}))
69// .await;
70
71// let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
72// let workspace = window.root(cx);
73// project
74// .update(cx, |project, cx| {
75// project.find_or_create_local_worktree("/root", true, cx)
76// })
77// .await
78// .unwrap();
79// cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
80// .await;
81
82// let file = cx.read(|cx| workspace.file_project_paths(cx)[0].clone());
83// let item = workspace
84// .update(cx, |workspace, cx| {
85// workspace.open_path(file, None, true, cx)
86// })
87// .await
88// .expect("Could not open test file");
89
90// let editor = cx.update(|cx| {
91// item.act_as::<Editor>(cx)
92// .expect("Opened test file wasn't an editor")
93// });
94// editor.update(cx, |_, cx| cx.focus_self());
95
96// let lsp = fake_servers.next().await.unwrap();
97
98// Self {
99// cx: EditorTestContext {
100// cx,
101// window: window.into(),
102// editor,
103// },
104// lsp,
105// workspace,
106// buffer_lsp_url: lsp::Url::from_file_path(format!("/root/dir/{file_name}")).unwrap(),
107// }
108// }
109
110// pub async fn new_rust(
111// capabilities: lsp::ServerCapabilities,
112// cx: &'a mut gpui::TestAppContext,
113// ) -> EditorLspTestContext<'a> {
114// let language = Language::new(
115// LanguageConfig {
116// name: "Rust".into(),
117// path_suffixes: vec!["rs".to_string()],
118// ..Default::default()
119// },
120// Some(tree_sitter_rust::language()),
121// )
122// .with_queries(LanguageQueries {
123// indents: Some(Cow::from(indoc! {r#"
124// [
125// ((where_clause) _ @end)
126// (field_expression)
127// (call_expression)
128// (assignment_expression)
129// (let_declaration)
130// (let_chain)
131// (await_expression)
132// ] @indent
133
134// (_ "[" "]" @end) @indent
135// (_ "<" ">" @end) @indent
136// (_ "{" "}" @end) @indent
137// (_ "(" ")" @end) @indent"#})),
138// brackets: Some(Cow::from(indoc! {r#"
139// ("(" @open ")" @close)
140// ("[" @open "]" @close)
141// ("{" @open "}" @close)
142// ("<" @open ">" @close)
143// ("\"" @open "\"" @close)
144// (closure_parameters "|" @open "|" @close)"#})),
145// ..Default::default()
146// })
147// .expect("Could not parse queries");
148
149// Self::new(language, capabilities, cx).await
150// }
151
152// pub async fn new_typescript(
153// capabilities: lsp::ServerCapabilities,
154// cx: &'a mut gpui::TestAppContext,
155// ) -> EditorLspTestContext<'a> {
156// let mut word_characters: HashSet<char> = Default::default();
157// word_characters.insert('$');
158// word_characters.insert('#');
159// let language = Language::new(
160// LanguageConfig {
161// name: "Typescript".into(),
162// path_suffixes: vec!["ts".to_string()],
163// brackets: language::BracketPairConfig {
164// pairs: vec![language::BracketPair {
165// start: "{".to_string(),
166// end: "}".to_string(),
167// close: true,
168// newline: true,
169// }],
170// disabled_scopes_by_bracket_ix: Default::default(),
171// },
172// word_characters,
173// ..Default::default()
174// },
175// Some(tree_sitter_typescript::language_typescript()),
176// )
177// .with_queries(LanguageQueries {
178// brackets: Some(Cow::from(indoc! {r#"
179// ("(" @open ")" @close)
180// ("[" @open "]" @close)
181// ("{" @open "}" @close)
182// ("<" @open ">" @close)
183// ("\"" @open "\"" @close)"#})),
184// indents: Some(Cow::from(indoc! {r#"
185// [
186// (call_expression)
187// (assignment_expression)
188// (member_expression)
189// (lexical_declaration)
190// (variable_declaration)
191// (assignment_expression)
192// (if_statement)
193// (for_statement)
194// ] @indent
195
196// (_ "[" "]" @end) @indent
197// (_ "<" ">" @end) @indent
198// (_ "{" "}" @end) @indent
199// (_ "(" ")" @end) @indent
200// "#})),
201// ..Default::default()
202// })
203// .expect("Could not parse queries");
204
205// Self::new(language, capabilities, cx).await
206// }
207
208// // Constructs lsp range using a marked string with '[', ']' range delimiters
209// pub fn lsp_range(&mut self, marked_text: &str) -> lsp::Range {
210// let ranges = self.ranges(marked_text);
211// self.to_lsp_range(ranges[0].clone())
212// }
213
214// pub fn to_lsp_range(&mut self, range: Range<usize>) -> lsp::Range {
215// let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx));
216// let start_point = range.start.to_point(&snapshot.buffer_snapshot);
217// let end_point = range.end.to_point(&snapshot.buffer_snapshot);
218
219// self.editor(|editor, cx| {
220// let buffer = editor.buffer().read(cx);
221// let start = point_to_lsp(
222// buffer
223// .point_to_buffer_offset(start_point, cx)
224// .unwrap()
225// .1
226// .to_point_utf16(&buffer.read(cx)),
227// );
228// let end = point_to_lsp(
229// buffer
230// .point_to_buffer_offset(end_point, cx)
231// .unwrap()
232// .1
233// .to_point_utf16(&buffer.read(cx)),
234// );
235
236// lsp::Range { start, end }
237// })
238// }
239
240// pub fn to_lsp(&mut self, offset: usize) -> lsp::Position {
241// let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx));
242// let point = offset.to_point(&snapshot.buffer_snapshot);
243
244// self.editor(|editor, cx| {
245// let buffer = editor.buffer().read(cx);
246// point_to_lsp(
247// buffer
248// .point_to_buffer_offset(point, cx)
249// .unwrap()
250// .1
251// .to_point_utf16(&buffer.read(cx)),
252// )
253// })
254// }
255
256// pub fn update_workspace<F, T>(&mut self, update: F) -> T
257// where
258// F: FnOnce(&mut Workspace, &mut ViewContext<Workspace>) -> T,
259// {
260// self.workspace.update(self.cx.cx, update)
261// }
262
263// pub fn handle_request<T, F, Fut>(
264// &self,
265// mut handler: F,
266// ) -> futures::channel::mpsc::UnboundedReceiver<()>
267// where
268// T: 'static + request::Request,
269// T::Params: 'static + Send,
270// F: 'static + Send + FnMut(lsp::Url, T::Params, gpui::AsyncAppContext) -> Fut,
271// Fut: 'static + Send + Future<Output = Result<T::Result>>,
272// {
273// let url = self.buffer_lsp_url.clone();
274// self.lsp.handle_request::<T, _, _>(move |params, cx| {
275// let url = url.clone();
276// handler(url, params, cx)
277// })
278// }
279
280// pub fn notify<T: notification::Notification>(&self, params: T::Params) {
281// self.lsp.notify::<T>(params);
282// }
283// }
284
285// impl<'a> Deref for EditorLspTestContext<'a> {
286// type Target = EditorTestContext<'a>;
287
288// fn deref(&self) -> &Self::Target {
289// &self.cx
290// }
291// }
292
293// impl<'a> DerefMut for EditorLspTestContext<'a> {
294// fn deref_mut(&mut self) -> &mut Self::Target {
295// &mut self.cx
296// }
297// }