From e0dd9e4185f2ed54191f6407706acbd0d34c24b2 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 8 Jun 2023 11:33:20 -0700 Subject: [PATCH] Make the LSP log view searchable --- crates/lsp_log/src/lsp_log.rs | 100 ++++++++++++++++++++++------ crates/lsp_log/src/lsp_log_tests.rs | 5 +- 2 files changed, 82 insertions(+), 23 deletions(-) diff --git a/crates/lsp_log/src/lsp_log.rs b/crates/lsp_log/src/lsp_log.rs index 1071ed435a..5808b4da2e 100644 --- a/crates/lsp_log/src/lsp_log.rs +++ b/crates/lsp_log/src/lsp_log.rs @@ -20,6 +20,7 @@ use std::{borrow::Cow, sync::Arc}; use theme::{ui, Theme}; use workspace::{ item::{Item, ItemHandle}, + searchable::{SearchableItem, SearchableItemHandle}, ToolbarItemLocation, ToolbarItemView, Workspace, WorkspaceCreated, }; @@ -51,7 +52,7 @@ pub struct LspLogView { log_store: ModelHandle, current_server_id: Option, is_showing_rpc_trace: bool, - editor: Option>, + editor: ViewHandle, project: ModelHandle, } @@ -329,10 +330,11 @@ impl LspLogView { .projects .get(&project.downgrade()) .and_then(|project| project.servers.keys().copied().next()); + let buffer = cx.add_model(|cx| Buffer::new(0, "", cx)); let mut this = Self { + editor: Self::editor_for_buffer(project.clone(), buffer, cx), project, log_store, - editor: None, current_server_id: None, is_showing_rpc_trace: false, }; @@ -342,6 +344,22 @@ impl LspLogView { this } + fn editor_for_buffer( + project: ModelHandle, + buffer: ModelHandle, + cx: &mut ViewContext, + ) -> ViewHandle { + let editor = cx.add_view(|cx| { + let mut editor = Editor::for_buffer(buffer, Some(project), cx); + editor.set_read_only(true); + editor.move_to_end(&Default::default(), cx); + editor + }); + cx.subscribe(&editor, |_, _, event, cx| cx.emit(event.clone())) + .detach(); + editor + } + fn menu_items<'a>(&'a self, cx: &'a AppContext) -> Option> { let log_store = self.log_store.read(cx); let state = log_store.projects.get(&self.project.downgrade())?; @@ -377,12 +395,7 @@ impl LspLogView { if let Some(buffer) = buffer { self.current_server_id = Some(server_id); self.is_showing_rpc_trace = false; - self.editor = Some(cx.add_view(|cx| { - let mut editor = Editor::for_buffer(buffer, Some(self.project.clone()), cx); - editor.set_read_only(true); - editor.move_to_end(&Default::default(), cx); - editor - })); + self.editor = Self::editor_for_buffer(self.project.clone(), buffer, cx); cx.notify(); } } @@ -398,12 +411,7 @@ impl LspLogView { if let Some(buffer) = buffer { self.current_server_id = Some(server_id); self.is_showing_rpc_trace = true; - self.editor = Some(cx.add_view(|cx| { - let mut editor = Editor::for_buffer(buffer, Some(self.project.clone()), cx); - editor.set_read_only(true); - editor.move_to_end(&Default::default(), cx); - editor - })); + self.editor = Self::editor_for_buffer(self.project.clone(), buffer, cx); cx.notify(); } } @@ -434,10 +442,12 @@ impl View for LspLogView { } fn render(&mut self, cx: &mut ViewContext) -> AnyElement { - if let Some(editor) = &self.editor { - ChildView::new(&editor, cx).into_any() - } else { - Empty::new().into_any() + ChildView::new(&self.editor, cx).into_any() + } + + fn focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext) { + if cx.is_self_focused() { + cx.focus(&self.editor); } } } @@ -451,6 +461,58 @@ impl Item for LspLogView { ) -> AnyElement { Label::new("LSP Logs", style.label.clone()).into_any() } + + fn as_searchable(&self, handle: &ViewHandle) -> Option> { + Some(Box::new(handle.clone())) + } +} + +impl SearchableItem for LspLogView { + type Match = ::Match; + + fn to_search_event(event: &Self::Event) -> Option { + Editor::to_search_event(event) + } + + fn clear_matches(&mut self, cx: &mut ViewContext) { + self.editor.update(cx, |e, cx| e.clear_matches(cx)) + } + + fn update_matches(&mut self, matches: Vec, cx: &mut ViewContext) { + self.editor + .update(cx, |e, cx| e.update_matches(matches, cx)) + } + + fn query_suggestion(&mut self, cx: &mut ViewContext) -> String { + self.editor.update(cx, |e, cx| e.query_suggestion(cx)) + } + + fn activate_match( + &mut self, + index: usize, + matches: Vec, + cx: &mut ViewContext, + ) { + self.editor + .update(cx, |e, cx| e.activate_match(index, matches, cx)) + } + + fn find_matches( + &mut self, + query: project::search::SearchQuery, + cx: &mut ViewContext, + ) -> gpui::Task> { + self.editor.update(cx, |e, cx| e.find_matches(query, cx)) + } + + fn active_match_index( + &mut self, + matches: Vec, + cx: &mut ViewContext, + ) -> Option { + self.editor + .update(cx, |e, cx| e.active_match_index(matches, cx)) + } } impl ToolbarItemView for LspLogToolbarItemView { @@ -717,7 +779,7 @@ impl Entity for LogStore { } impl Entity for LspLogView { - type Event = (); + type Event = editor::Event; } impl Entity for LspLogToolbarItemView { diff --git a/crates/lsp_log/src/lsp_log_tests.rs b/crates/lsp_log/src/lsp_log_tests.rs index 4be0db456c..572758ad63 100644 --- a/crates/lsp_log/src/lsp_log_tests.rs +++ b/crates/lsp_log/src/lsp_log_tests.rs @@ -76,10 +76,7 @@ async fn test_lsp_logs(cx: &mut TestAppContext) { logs_selected: true, }] ); - assert_eq!( - view.editor.as_ref().unwrap().read(cx).text(cx), - "hello from the server\n" - ); + assert_eq!(view.editor.read(cx).text(cx), "hello from the server\n"); }); }