editor_lsp_test_context.rs

  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// }