From a88320dc5f10a9b09ebbb7bc6d1ec02ec7ad4f76 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 16 Mar 2022 13:34:04 -0700 Subject: [PATCH 01/14] Remove workspace::Item trait Co-Authored-By: Nathan Sobo Co-Authored-By: Keith Simmons Co-Authored-By: Antonio Scandurra --- crates/diagnostics/src/diagnostics.rs | 103 +++---- crates/editor/src/editor.rs | 88 ++++-- crates/editor/src/items.rs | 151 ++-------- crates/gpui/src/app.rs | 14 + crates/project/src/project.rs | 10 + crates/project/src/worktree.rs | 9 + crates/project_symbols/src/project_symbols.rs | 10 +- crates/search/src/project_search.rs | 76 ++--- crates/workspace/src/pane.rs | 53 ++-- crates/workspace/src/workspace.rs | 282 +++++------------- 10 files changed, 280 insertions(+), 516 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 1a432f52e20658eacd3141aa141d243324b89299..1db19f7f5e786c43634f0291f15061aa7ee3324e 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -25,7 +25,7 @@ use std::{ sync::Arc, }; use util::TryFutureExt; -use workspace::{ItemHandle, ItemNavHistory, ItemViewHandle as _, Settings, Workspace}; +use workspace::{ItemNavHistory, ItemViewHandle as _, Settings, Workspace}; action!(Deploy); @@ -38,12 +38,8 @@ pub fn init(cx: &mut MutableAppContext) { type Event = editor::Event; -struct ProjectDiagnostics { - project: ModelHandle, -} - struct ProjectDiagnosticsEditor { - model: ModelHandle, + project: ModelHandle, workspace: WeakViewHandle, editor: ViewHandle, summary: DiagnosticSummary, @@ -65,16 +61,6 @@ struct DiagnosticGroupState { block_count: usize, } -impl ProjectDiagnostics { - fn new(project: ModelHandle) -> Self { - Self { project } - } -} - -impl Entity for ProjectDiagnostics { - type Event = (); -} - impl Entity for ProjectDiagnosticsEditor { type Event = Event; } @@ -109,12 +95,11 @@ impl View for ProjectDiagnosticsEditor { impl ProjectDiagnosticsEditor { fn new( - model: ModelHandle, + project_handle: ModelHandle, workspace: WeakViewHandle, cx: &mut ViewContext, ) -> Self { - let project = model.read(cx).project.clone(); - cx.subscribe(&project, |this, _, event, cx| match event { + cx.subscribe(&project_handle, |this, _, event, cx| match event { project::Event::DiskBasedDiagnosticsFinished => { this.update_excerpts(cx); this.update_title(cx); @@ -126,20 +111,21 @@ impl ProjectDiagnosticsEditor { }) .detach(); - let excerpts = cx.add_model(|cx| MultiBuffer::new(project.read(cx).replica_id())); + let excerpts = cx.add_model(|cx| MultiBuffer::new(project_handle.read(cx).replica_id())); let editor = cx.add_view(|cx| { - let mut editor = Editor::for_buffer(excerpts.clone(), Some(project.clone()), cx); + let mut editor = Editor::for_buffer(excerpts.clone(), Some(project_handle.clone()), cx); editor.set_vertical_scroll_margin(5, cx); editor }); cx.subscribe(&editor, |_, _, event, cx| cx.emit(*event)) .detach(); - let project = project.read(cx); + let project = project_handle.read(cx); let paths_to_update = project.diagnostic_summaries(cx).map(|e| e.0).collect(); + let summary = project.diagnostic_summary(cx); let mut this = Self { - model, - summary: project.diagnostic_summary(cx), + project: project_handle, + summary, workspace, excerpts, editor, @@ -151,18 +137,20 @@ impl ProjectDiagnosticsEditor { } fn deploy(workspace: &mut Workspace, _: &Deploy, cx: &mut ViewContext) { - if let Some(existing) = workspace.item_of_type::(cx) { + if let Some(existing) = workspace.item_of_type::(cx) { workspace.activate_item(&existing, cx); } else { - let diagnostics = - cx.add_model(|_| ProjectDiagnostics::new(workspace.project().clone())); - workspace.open_item(diagnostics, cx); + let workspace_handle = cx.weak_handle(); + let diagnostics = cx.add_view(|cx| { + ProjectDiagnosticsEditor::new(workspace.project().clone(), workspace_handle, cx) + }); + workspace.open_item(Box::new(diagnostics), cx); } } fn update_excerpts(&mut self, cx: &mut ViewContext) { let paths = mem::take(&mut self.paths_to_update); - let project = self.model.read(cx).project.clone(); + let project = self.project.clone(); cx.spawn(|this, mut cx| { async move { for path in paths { @@ -443,37 +431,12 @@ impl ProjectDiagnosticsEditor { } fn update_title(&mut self, cx: &mut ViewContext) { - self.summary = self.model.read(cx).project.read(cx).diagnostic_summary(cx); + self.summary = self.project.read(cx).diagnostic_summary(cx); cx.emit(Event::TitleChanged); } } -impl workspace::Item for ProjectDiagnostics { - type View = ProjectDiagnosticsEditor; - - fn build_view( - handle: ModelHandle, - workspace: &Workspace, - nav_history: ItemNavHistory, - cx: &mut ViewContext, - ) -> Self::View { - let diagnostics = ProjectDiagnosticsEditor::new(handle, workspace.weak_handle(), cx); - diagnostics - .editor - .update(cx, |editor, _| editor.set_nav_history(Some(nav_history))); - diagnostics - } - - fn project_path(&self) -> Option { - None - } -} - impl workspace::ItemView for ProjectDiagnosticsEditor { - fn item(&self, _: &AppContext) -> Box { - Box::new(self.model.clone()) - } - fn tab_content(&self, style: &theme::Tab, cx: &AppContext) -> ElementBox { render_summary( &self.summary, @@ -486,6 +449,10 @@ impl workspace::ItemView for ProjectDiagnosticsEditor { None } + fn project_entry(&self, _: &AppContext) -> Option { + None + } + fn navigate(&mut self, data: Box, cx: &mut ViewContext) { self.editor .update(cx, |editor, cx| editor.navigate(data, cx)); @@ -532,20 +499,21 @@ impl workspace::ItemView for ProjectDiagnosticsEditor { matches!(event, Event::Saved | Event::Dirtied | Event::TitleChanged) } - fn clone_on_split( - &self, - nav_history: ItemNavHistory, - cx: &mut ViewContext, - ) -> Option + fn set_nav_history(&mut self, nav_history: ItemNavHistory, cx: &mut ViewContext) { + self.editor.update(cx, |editor, _| { + editor.set_nav_history(Some(nav_history)); + }); + } + + fn clone_on_split(&self, cx: &mut ViewContext) -> Option where Self: Sized, { - let diagnostics = - ProjectDiagnosticsEditor::new(self.model.clone(), self.workspace.clone(), cx); - diagnostics.editor.update(cx, |editor, _| { - editor.set_nav_history(Some(nav_history)); - }); - Some(diagnostics) + Some(ProjectDiagnosticsEditor::new( + self.project.clone(), + self.workspace.clone(), + cx, + )) } fn act_as_type( @@ -829,9 +797,8 @@ mod tests { }); // Open the project diagnostics view while there are already diagnostics. - let model = cx.add_model(|_| ProjectDiagnostics::new(project.clone())); let view = cx.add_view(0, |cx| { - ProjectDiagnosticsEditor::new(model, workspace.downgrade(), cx) + ProjectDiagnosticsEditor::new(project.clone(), workspace.downgrade(), cx) }); view.next_notification(&cx).await; diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 8c6904d1360e63b5024f492985db5e18950cef82..6a298591951dc7c8d12476982225cdae01b58503 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -28,7 +28,6 @@ use gpui::{ ModelHandle, MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle, }; -use items::{BufferItemHandle, MultiBufferItemHandle}; use itertools::Itertools as _; pub use language::{char_kind, CharKind}; use language::{ @@ -836,7 +835,32 @@ impl Editor { Self::new(EditorMode::Full, buffer, project, None, cx) } - pub fn clone(&self, nav_history: ItemNavHistory, cx: &mut ViewContext) -> Self { + pub fn find_or_create( + workspace: &mut Workspace, + buffer: ModelHandle, + cx: &mut ViewContext, + ) -> ViewHandle { + let project = workspace.project().clone(); + + if let Some(project_entry) = + project::File::from_dyn(buffer.read(cx).file()).and_then(|file| file.project_entry(cx)) + { + return workspace + .open_item_for_project_entry(project_entry, cx, |cx| { + let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); + Editor::for_buffer(multibuffer, Some(project.clone()), cx) + }) + .downcast::() + .unwrap(); + } + + let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); + let editor = cx.add_view(|cx| Editor::for_buffer(multibuffer, Some(project.clone()), cx)); + workspace.open_item(Box::new(editor.clone()), cx); + editor + } + + pub fn clone(&self, cx: &mut ViewContext) -> Self { let mut clone = Self::new( self.mode, self.buffer.clone(), @@ -846,7 +870,6 @@ impl Editor { ); clone.scroll_position = self.scroll_position; clone.scroll_top_anchor = self.scroll_top_anchor.clone(); - clone.nav_history = Some(nav_history); clone.searchable = self.searchable; clone } @@ -938,14 +961,20 @@ impl Editor { _: &workspace::OpenNew, cx: &mut ViewContext, ) { - let project = workspace.project(); + let project = workspace.project().clone(); if project.read(cx).is_remote() { cx.propagate_action(); } else if let Some(buffer) = project .update(cx, |project, cx| project.create_buffer(cx)) .log_err() { - workspace.open_item(BufferItemHandle(buffer), cx); + let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); + workspace.open_item( + Box::new( + cx.add_view(|cx| Editor::for_buffer(multibuffer, Some(project.clone()), cx)), + ), + cx, + ); } } @@ -2349,7 +2378,11 @@ impl Editor { }); workspace.update(&mut cx, |workspace, cx| { - let editor = workspace.open_item(MultiBufferItemHandle(excerpt_buffer), cx); + let project = workspace.project().clone(); + let editor = workspace.open_item( + Box::new(cx.add_view(|cx| Editor::for_buffer(excerpt_buffer, Some(project), cx))), + cx, + ); if let Some(editor) = editor.act_as::(cx) { editor.update(cx, |editor, cx| { let color = editor.style(cx).highlighted_line_background; @@ -4280,20 +4313,17 @@ impl Editor { return; }; - let definitions = workspace - .project() - .update(cx, |project, cx| project.definition(&buffer, head, cx)); + let project = workspace.project().clone(); + let definitions = project.update(cx, |project, cx| project.definition(&buffer, head, cx)); cx.spawn(|workspace, mut cx| async move { let definitions = definitions.await?; workspace.update(&mut cx, |workspace, cx| { let nav_history = workspace.active_pane().read(cx).nav_history().clone(); for definition in definitions { let range = definition.range.to_offset(definition.buffer.read(cx)); - let target_editor_handle = workspace - .open_item(BufferItemHandle(definition.buffer), cx) - .downcast::() - .unwrap(); + let target_editor_handle = + Self::find_or_create(workspace, definition.buffer, cx); target_editor_handle.update(cx, |target_editor, cx| { // When selecting a definition in a different buffer, disable the nav history // to avoid creating a history entry at the previous cursor location. @@ -4324,9 +4354,8 @@ impl Editor { let (buffer, head) = editor.buffer.read(cx).text_anchor_for_position(head, cx)?; let replica_id = editor.replica_id(cx); - let references = workspace - .project() - .update(cx, |project, cx| project.references(&buffer, head, cx)); + let project = workspace.project().clone(); + let references = project.update(cx, |project, cx| project.references(&buffer, head, cx)); Some(cx.spawn(|workspace, mut cx| async move { let mut locations = references.await?; if locations.is_empty() { @@ -4370,13 +4399,13 @@ impl Editor { }); workspace.update(&mut cx, |workspace, cx| { - let editor = workspace.open_item(MultiBufferItemHandle(excerpt_buffer), cx); - if let Some(editor) = editor.act_as::(cx) { - editor.update(cx, |editor, cx| { - let color = editor.style(cx).highlighted_line_background; - editor.highlight_background::(ranges_to_highlight, color, cx); - }); - } + let editor = + cx.add_view(|cx| Editor::for_buffer(excerpt_buffer, Some(project), cx)); + editor.update(cx, |editor, cx| { + let color = editor.style(cx).highlighted_line_background; + editor.highlight_background::(ranges_to_highlight, color, cx); + }); + workspace.open_item(Box::new(editor), cx); }); Ok(()) @@ -5563,17 +5592,10 @@ impl Editor { // and activating a new item causes the pane to call a method on us reentrantly, // which panics if we're on the stack. cx.defer(move |workspace, cx| { - for (ix, (buffer, ranges)) in new_selections_by_buffer.into_iter().enumerate() { - let buffer = BufferItemHandle(buffer); - if ix == 0 && !workspace.activate_pane_for_item(&buffer, cx) { - workspace.activate_next_pane(cx); - } - - let editor = workspace - .open_item(buffer, cx) - .downcast::() - .unwrap(); + workspace.activate_next_pane(cx); + for (buffer, ranges) in new_selections_by_buffer.into_iter() { + let editor = Self::find_or_create(workspace, buffer, cx); editor.update(cx, |editor, cx| { editor.select_ranges(ranges, Some(Autoscroll::Newest), cx); }); diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index c9af9f0854cf7beba9254dc02cb76e7053079bfc..b84a095e6b2bfa3ee8356164b7f83c8eb02bc23f 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -1,20 +1,16 @@ use crate::{Autoscroll, Editor, Event, MultiBuffer, NavigationData, ToOffset, ToPoint as _}; use anyhow::Result; use gpui::{ - elements::*, AppContext, Entity, ModelContext, ModelHandle, MutableAppContext, RenderContext, - Subscription, Task, View, ViewContext, ViewHandle, WeakModelHandle, + elements::*, AppContext, Entity, ModelContext, ModelHandle, RenderContext, Subscription, Task, + View, ViewContext, ViewHandle, WeakModelHandle, }; use language::{Bias, Buffer, Diagnostic, File as _}; -use project::{File, Project, ProjectPath}; +use project::{File, Project, ProjectEntry, ProjectPath}; +use std::fmt::Write; use std::path::PathBuf; -use std::rc::Rc; -use std::{cell::RefCell, fmt::Write}; use text::{Point, Selection}; use util::ResultExt; -use workspace::{ - ItemHandle, ItemNavHistory, ItemView, ItemViewHandle, NavHistory, PathOpener, Settings, - StatusItemView, WeakItemHandle, Workspace, -}; +use workspace::{ItemNavHistory, ItemView, ItemViewHandle, PathOpener, Settings, StatusItemView}; pub struct BufferOpener; @@ -35,127 +31,22 @@ impl PathOpener for BufferOpener { &self, project: &mut Project, project_path: ProjectPath, + window_id: usize, cx: &mut ModelContext, - ) -> Option>>> { + ) -> Option>>> { let buffer = project.open_buffer(project_path, cx); - let task = cx.spawn(|_, _| async move { + Some(cx.spawn(|project, mut cx| async move { let buffer = buffer.await?; - Ok(Box::new(BufferItemHandle(buffer)) as Box) - }); - Some(task) - } -} - -impl ItemHandle for BufferItemHandle { - fn add_view( - &self, - window_id: usize, - workspace: &Workspace, - nav_history: Rc>, - cx: &mut MutableAppContext, - ) -> Box { - let buffer = cx.add_model(|cx| MultiBuffer::singleton(self.0.clone(), cx)); - Box::new(cx.add_view(window_id, |cx| { - let mut editor = Editor::for_buffer(buffer, Some(workspace.project().clone()), cx); - editor.nav_history = Some(ItemNavHistory::new(nav_history, &cx.handle())); - editor - })) - } - - fn boxed_clone(&self) -> Box { - Box::new(self.clone()) - } - - fn to_any(&self) -> gpui::AnyModelHandle { - self.0.clone().into() - } - - fn downgrade(&self) -> Box { - Box::new(WeakBufferItemHandle(self.0.downgrade())) - } - - fn project_path(&self, cx: &AppContext) -> Option { - File::from_dyn(self.0.read(cx).file()).map(|f| ProjectPath { - worktree_id: f.worktree_id(cx), - path: f.path().clone(), - }) - } - - fn id(&self) -> usize { - self.0.id() - } -} - -impl ItemHandle for MultiBufferItemHandle { - fn add_view( - &self, - window_id: usize, - workspace: &Workspace, - nav_history: Rc>, - cx: &mut MutableAppContext, - ) -> Box { - Box::new(cx.add_view(window_id, |cx| { - let mut editor = - Editor::for_buffer(self.0.clone(), Some(workspace.project().clone()), cx); - editor.nav_history = Some(ItemNavHistory::new(nav_history, &cx.handle())); - editor + let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); + let editor = cx.add_view(window_id, |cx| { + Editor::for_buffer(multibuffer, Some(project), cx) + }); + Ok(Box::new(editor) as Box) })) } - - fn boxed_clone(&self) -> Box { - Box::new(self.clone()) - } - - fn to_any(&self) -> gpui::AnyModelHandle { - self.0.clone().into() - } - - fn downgrade(&self) -> Box { - Box::new(WeakMultiBufferItemHandle(self.0.downgrade())) - } - - fn project_path(&self, _: &AppContext) -> Option { - None - } - - fn id(&self) -> usize { - self.0.id() - } -} - -impl WeakItemHandle for WeakBufferItemHandle { - fn upgrade(&self, cx: &AppContext) -> Option> { - self.0 - .upgrade(cx) - .map(|buffer| Box::new(BufferItemHandle(buffer)) as Box) - } - - fn id(&self) -> usize { - self.0.id() - } -} - -impl WeakItemHandle for WeakMultiBufferItemHandle { - fn upgrade(&self, cx: &AppContext) -> Option> { - self.0 - .upgrade(cx) - .map(|buffer| Box::new(MultiBufferItemHandle(buffer)) as Box) - } - - fn id(&self) -> usize { - self.0.id() - } } impl ItemView for Editor { - fn item(&self, cx: &AppContext) -> Box { - if let Some(buffer) = self.buffer.read(cx).as_singleton() { - Box::new(BufferItemHandle(buffer)) - } else { - Box::new(MultiBufferItemHandle(self.buffer.clone())) - } - } - fn navigate(&mut self, data: Box, cx: &mut ViewContext) { if let Some(data) = data.downcast_ref::() { let buffer = self.buffer.read(cx).read(cx); @@ -184,15 +75,19 @@ impl ItemView for Editor { }) } - fn clone_on_split( - &self, - nav_history: ItemNavHistory, - cx: &mut ViewContext, - ) -> Option + fn project_entry(&self, cx: &AppContext) -> Option { + File::from_dyn(self.buffer().read(cx).file(cx)).and_then(|file| file.project_entry(cx)) + } + + fn clone_on_split(&self, cx: &mut ViewContext) -> Option where Self: Sized, { - Some(self.clone(nav_history, cx)) + Some(self.clone(cx)) + } + + fn set_nav_history(&mut self, history: ItemNavHistory, _: &mut ViewContext) { + self.nav_history = Some(history); } fn deactivated(&mut self, cx: &mut ViewContext) { diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index a03e6e54ae555ca964f2d820fd2df2050874e8a8..a479e5fba1c56c5e543e125be3f523c7c61acc84 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -595,6 +595,14 @@ impl AsyncAppContext { self.update(|cx| cx.add_model(build_model)) } + pub fn add_view(&mut self, window_id: usize, build_view: F) -> ViewHandle + where + T: View, + F: FnOnce(&mut ViewContext) -> T, + { + self.update(|cx| cx.add_view(window_id, build_view)) + } + pub fn platform(&self) -> Arc { self.0.borrow().platform() } @@ -3459,6 +3467,12 @@ impl PartialEq for ViewHandle { } } +impl PartialEq> for ViewHandle { + fn eq(&self, other: &WeakViewHandle) -> bool { + self.window_id == other.window_id && self.view_id == other.view_id + } +} + impl Eq for ViewHandle {} impl Debug for ViewHandle { diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index f5af7fc70ea0c0c89ae707ea3b8cde487c686038..b9bb25a5fcdd9f66f46c82ed73d84a0429e44d96 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -3221,6 +3221,16 @@ impl Project { self.active_entry } + pub fn entry_for_path(&self, path: &ProjectPath, cx: &AppContext) -> Option { + self.worktree_for_id(path.worktree_id, cx)? + .read(cx) + .entry_for_path(&path.path) + .map(|entry| ProjectEntry { + worktree_id: path.worktree_id, + entry_id: entry.id, + }) + } + // RPC message handlers async fn handle_unshare_project( diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 1ef8dd34a0da1d0e11d7e50e7c2b45a248ed08cf..4a121c82e4e7109c3e012f9660a07baaa1cfbb2e 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -1,3 +1,5 @@ +use crate::ProjectEntry; + use super::{ fs::{self, Fs}, ignore::IgnoreStack, @@ -1502,6 +1504,13 @@ impl File { pub fn worktree_id(&self, cx: &AppContext) -> WorktreeId { self.worktree.read(cx).id() } + + pub fn project_entry(&self, cx: &AppContext) -> Option { + self.entry_id.map(|entry_id| ProjectEntry { + worktree_id: self.worktree_id(cx), + entry_id, + }) + } } #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/crates/project_symbols/src/project_symbols.rs b/crates/project_symbols/src/project_symbols.rs index bfd204671f6994a07b5ab1717afc684b9659c9c8..29808ff7d9df5b428f7299493b88a13cece8e8eb 100644 --- a/crates/project_symbols/src/project_symbols.rs +++ b/crates/project_symbols/src/project_symbols.rs @@ -1,6 +1,5 @@ use editor::{ - combine_syntax_and_fuzzy_match_highlights, items::BufferItemHandle, styled_runs_for_code_label, - Autoscroll, Bias, Editor, + combine_syntax_and_fuzzy_match_highlights, styled_runs_for_code_label, Autoscroll, Bias, Editor, }; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ @@ -346,6 +345,7 @@ impl ProjectSymbolsView { let buffer = workspace .project() .update(cx, |project, cx| project.open_buffer_for_symbol(symbol, cx)); + let symbol = symbol.clone(); cx.spawn(|workspace, mut cx| async move { let buffer = buffer.await?; @@ -353,10 +353,8 @@ impl ProjectSymbolsView { let position = buffer .read(cx) .clip_point_utf16(symbol.range.start, Bias::Left); - let editor = workspace - .open_item(BufferItemHandle(buffer), cx) - .downcast::() - .unwrap(); + + let editor = Editor::find_or_create(workspace, buffer, cx); editor.update(cx, |editor, cx| { editor.select_ranges( [position..position], diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index b09c88a4a0ff8b020dbf839684cbbe4c1f3cf88b..56395b107a4b325bd4d1239807bc11456a7becbd 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -7,7 +7,7 @@ use editor::{Anchor, Autoscroll, Editor, MultiBuffer, SelectAll}; use gpui::{ action, elements::*, keymap::Binding, platform::CursorStyle, AppContext, ElementBox, Entity, ModelContext, ModelHandle, MutableAppContext, RenderContext, Task, View, ViewContext, - ViewHandle, WeakModelHandle, + ViewHandle, WeakModelHandle, WeakViewHandle, }; use project::{search::SearchQuery, Project}; use std::{ @@ -16,7 +16,7 @@ use std::{ path::PathBuf, }; use util::ResultExt as _; -use workspace::{Item, ItemHandle, ItemNavHistory, ItemView, Settings, Workspace}; +use workspace::{ItemNavHistory, ItemView, Settings, Workspace}; action!(Deploy); action!(Search); @@ -26,7 +26,7 @@ action!(ToggleFocus); const MAX_TAB_TITLE_LEN: usize = 24; #[derive(Default)] -struct ActiveSearches(HashMap, WeakModelHandle>); +struct ActiveSearches(HashMap, WeakViewHandle>); pub fn init(cx: &mut MutableAppContext) { cx.add_app_state(ActiveSearches::default()); @@ -139,23 +139,6 @@ impl ProjectSearch { } } -impl Item for ProjectSearch { - type View = ProjectSearchView; - - fn build_view( - model: ModelHandle, - _: &Workspace, - nav_history: ItemNavHistory, - cx: &mut gpui::ViewContext, - ) -> Self::View { - ProjectSearchView::new(model, Some(nav_history), cx) - } - - fn project_path(&self) -> Option { - None - } -} - enum ViewEvent { UpdateTab, } @@ -199,11 +182,11 @@ impl View for ProjectSearchView { } fn on_focus(&mut self, cx: &mut ViewContext) { + let handle = cx.weak_handle(); cx.update_app_state(|state: &mut ActiveSearches, cx| { - state.0.insert( - self.model.read(cx).project.downgrade(), - self.model.downgrade(), - ) + state + .0 + .insert(self.model.read(cx).project.downgrade(), handle) }); if self.model.read(cx).match_ranges.is_empty() { @@ -235,10 +218,6 @@ impl ItemView for ProjectSearchView { .update(cx, |editor, cx| editor.deactivated(cx)); } - fn item(&self, _: &gpui::AppContext) -> Box { - Box::new(self.model.clone()) - } - fn tab_content(&self, tab_theme: &theme::Tab, cx: &gpui::AppContext) -> ElementBox { let settings = cx.app_state::(); let search_theme = &settings.theme.search; @@ -271,6 +250,10 @@ impl ItemView for ProjectSearchView { None } + fn project_entry(&self, _: &AppContext) -> Option { + None + } + fn can_save(&self, _: &gpui::AppContext) -> bool { true } @@ -305,16 +288,18 @@ impl ItemView for ProjectSearchView { unreachable!("save_as should not have been called") } - fn clone_on_split( - &self, - nav_history: ItemNavHistory, - cx: &mut ViewContext, - ) -> Option + fn clone_on_split(&self, cx: &mut ViewContext) -> Option where Self: Sized, { let model = self.model.update(cx, |model, cx| model.clone(cx)); - Some(Self::new(model, Some(nav_history), cx)) + Some(Self::new(model, cx)) + } + + fn set_nav_history(&mut self, nav_history: ItemNavHistory, cx: &mut ViewContext) { + self.results_editor.update(cx, |editor, _| { + editor.set_nav_history(Some(nav_history)); + }); } fn navigate(&mut self, data: Box, cx: &mut ViewContext) { @@ -328,11 +313,7 @@ impl ItemView for ProjectSearchView { } impl ProjectSearchView { - fn new( - model: ModelHandle, - nav_history: Option, - cx: &mut ViewContext, - ) -> Self { + fn new(model: ModelHandle, cx: &mut ViewContext) -> Self { let project; let excerpts; let mut query_text = String::new(); @@ -364,7 +345,6 @@ impl ProjectSearchView { let results_editor = cx.add_view(|cx| { let mut editor = Editor::for_buffer(excerpts, Some(project), cx); editor.set_searchable(false); - editor.set_nav_history(nav_history); editor }); cx.observe(&results_editor, |_, _, cx| cx.emit(ViewEvent::UpdateTab)) @@ -406,16 +386,19 @@ impl ProjectSearchView { let existing = active_search .and_then(|active_search| { workspace - .items_of_type::(cx) + .items_of_type::(cx) .find(|search| search == active_search) }) - .or_else(|| workspace.item_of_type::(cx)); + .or_else(|| workspace.item_of_type::(cx)); if let Some(existing) = existing { workspace.activate_item(&existing, cx); } else { let model = cx.add_model(|cx| ProjectSearch::new(workspace.project().clone(), cx)); - workspace.open_item(model, cx); + workspace.open_item( + Box::new(cx.add_view(|cx| ProjectSearchView::new(model, cx))), + cx, + ); } } @@ -450,7 +433,10 @@ impl ProjectSearchView { model.search(new_query, cx); model }); - workspace.open_item(model, cx); + workspace.open_item( + Box::new(cx.add_view(|cx| ProjectSearchView::new(model, cx))), + cx, + ); } } } @@ -732,7 +718,7 @@ mod tests { let search = cx.add_model(|cx| ProjectSearch::new(project, cx)); let search_view = cx.add_view(Default::default(), |cx| { - ProjectSearchView::new(search.clone(), None, cx) + ProjectSearchView::new(search.clone(), cx) }); search_view.update(cx, |search_view, cx| { diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index c54a1b050b341cb75f1768269579f25c43fa64cb..9f5ee5227431df6a60ae76df9cea66331c18869f 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1,5 +1,5 @@ use super::{ItemViewHandle, SplitDirection}; -use crate::{ItemHandle, ItemView, Settings, WeakItemViewHandle, Workspace}; +use crate::{ItemView, Settings, WeakItemViewHandle, Workspace}; use collections::{HashMap, VecDeque}; use gpui::{ action, @@ -10,7 +10,7 @@ use gpui::{ AnyViewHandle, Entity, MutableAppContext, Quad, RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle, }; -use project::ProjectPath; +use project::{ProjectEntry, ProjectPath}; use std::{ any::{Any, TypeId}, cell::RefCell, @@ -97,7 +97,7 @@ pub enum Event { } pub struct Pane { - item_views: Vec<(usize, Box)>, + item_views: Vec<(Option, Box)>, active_item_index: usize, nav_history: Rc>, toolbars: HashMap>, @@ -281,27 +281,23 @@ impl Pane { } } - pub fn open_item( + pub fn open_item( &mut self, - item_handle: T, - workspace: &Workspace, + item_view_to_open: Box, cx: &mut ViewContext, - ) -> Box - where - T: 'static + ItemHandle, - { - for (ix, (item_id, item_view)) in self.item_views.iter().enumerate() { - if *item_id == item_handle.id() { + ) -> Box { + // Find an existing view for the same project entry. + for (ix, (entry_id, item_view)) in self.item_views.iter().enumerate() { + if *entry_id == item_view_to_open.project_entry_id(cx) { let item_view = item_view.boxed_clone(); self.activate_item(ix, cx); return item_view; } } - let item_view = - item_handle.add_view(cx.window_id(), workspace, self.nav_history.clone(), cx); - self.add_item_view(item_view.boxed_clone(), cx); - item_view + item_view_to_open.set_nav_history(self.nav_history.clone(), cx); + self.add_item_view(item_view_to_open.boxed_clone(), cx); + item_view_to_open } pub fn add_item_view( @@ -312,18 +308,11 @@ impl Pane { item_view.added_to_pane(cx); let item_idx = cmp::min(self.active_item_index + 1, self.item_views.len()); self.item_views - .insert(item_idx, (item_view.item(cx).id(), item_view)); + .insert(item_idx, (item_view.project_entry_id(cx), item_view)); self.activate_item(item_idx, cx); cx.notify(); } - pub fn contains_item(&self, item: &dyn ItemHandle) -> bool { - let item_id = item.id(); - self.item_views - .iter() - .any(|(existing_item_id, _)| *existing_item_id == item_id) - } - pub fn item_views(&self) -> impl Iterator> { self.item_views.iter().map(|(_, view)| view) } @@ -334,14 +323,26 @@ impl Pane { .map(|(_, view)| view.clone()) } + pub fn item_for_entry(&self, entry: ProjectEntry) -> Option> { + self.item_views.iter().find_map(|(id, view)| { + if *id == Some(entry.entry_id) { + Some(view.boxed_clone()) + } else { + None + } + }) + } + pub fn index_for_item_view(&self, item_view: &dyn ItemViewHandle) -> Option { self.item_views .iter() .position(|(_, i)| i.id() == item_view.id()) } - pub fn index_for_item(&self, item: &dyn ItemHandle) -> Option { - self.item_views.iter().position(|(id, _)| *id == item.id()) + pub fn index_for_item(&self, item: &dyn ItemViewHandle) -> Option { + self.item_views + .iter() + .position(|(_, my_item)| my_item.id() == item.id()) } pub fn activate_item(&mut self, index: usize, cx: &mut ViewContext) { diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 6bff12a577bab115c96bf8554cbf5e2a3ca59d44..5a3385a0144938a5658524b616c567e6a20fc48f 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -9,7 +9,6 @@ mod status_bar; use anyhow::{anyhow, Result}; use client::{Authenticate, ChannelList, Client, User, UserStore}; use clock::ReplicaId; -use collections::BTreeMap; use gpui::{ action, color::Color, @@ -18,16 +17,16 @@ use gpui::{ json::{self, to_string_pretty, ToJson}, keymap::Binding, platform::{CursorStyle, WindowOptions}, - AnyModelHandle, AnyViewHandle, AppContext, ClipboardItem, Entity, ImageData, ModelContext, - ModelHandle, MutableAppContext, PathPromptOptions, PromptLevel, RenderContext, Task, View, - ViewContext, ViewHandle, WeakModelHandle, WeakViewHandle, + AnyViewHandle, AppContext, ClipboardItem, Entity, ImageData, ModelContext, ModelHandle, + MutableAppContext, PathPromptOptions, PromptLevel, RenderContext, Task, View, ViewContext, + ViewHandle, WeakViewHandle, }; use language::LanguageRegistry; use log::error; pub use pane::*; pub use pane_group::*; use postage::prelude::Stream; -use project::{fs, Fs, Project, ProjectPath, Worktree}; +use project::{fs, Fs, Project, ProjectEntry, ProjectPath, Worktree}; pub use settings::Settings; use sidebar::{Side, Sidebar, SidebarItemId, ToggleSidebarItem, ToggleSidebarItemFocus}; use status_bar::StatusBar; @@ -35,9 +34,7 @@ pub use status_bar::StatusItemView; use std::{ any::{Any, TypeId}, cell::RefCell, - cmp::Reverse, future::Future, - hash::{Hash, Hasher}, path::{Path, PathBuf}, rc::Rc, sync::Arc, @@ -131,30 +128,19 @@ pub trait PathOpener { &self, project: &mut Project, path: ProjectPath, + window_id: usize, cx: &mut ModelContext, - ) -> Option>>>; -} - -pub trait Item: Entity + Sized { - type View: ItemView; - - fn build_view( - handle: ModelHandle, - workspace: &Workspace, - nav_history: ItemNavHistory, - cx: &mut ViewContext, - ) -> Self::View; - - fn project_path(&self) -> Option; + ) -> Option>>>; } pub trait ItemView: View { fn deactivated(&mut self, _: &mut ViewContext) {} fn navigate(&mut self, _: Box, _: &mut ViewContext) {} - fn item(&self, cx: &AppContext) -> Box; fn tab_content(&self, style: &theme::Tab, cx: &AppContext) -> ElementBox; fn project_path(&self, cx: &AppContext) -> Option; - fn clone_on_split(&self, _: ItemNavHistory, _: &mut ViewContext) -> Option + fn project_entry(&self, cx: &AppContext) -> Option; + fn set_nav_history(&mut self, _: ItemNavHistory, _: &mut ViewContext); + fn clone_on_split(&self, _: &mut ViewContext) -> Option where Self: Sized, { @@ -202,36 +188,13 @@ pub trait ItemView: View { } } -pub trait ItemHandle: Send + Sync { - fn id(&self) -> usize; - fn add_view( - &self, - window_id: usize, - workspace: &Workspace, - nav_history: Rc>, - cx: &mut MutableAppContext, - ) -> Box; - fn boxed_clone(&self) -> Box; - fn downgrade(&self) -> Box; - fn to_any(&self) -> AnyModelHandle; - fn project_path(&self, cx: &AppContext) -> Option; -} - -pub trait WeakItemHandle { - fn id(&self) -> usize; - fn upgrade(&self, cx: &AppContext) -> Option>; -} - pub trait ItemViewHandle: 'static { - fn item(&self, cx: &AppContext) -> Box; fn tab_content(&self, style: &theme::Tab, cx: &AppContext) -> ElementBox; fn project_path(&self, cx: &AppContext) -> Option; + fn project_entry_id(&self, cx: &AppContext) -> Option; fn boxed_clone(&self) -> Box; - fn clone_on_split( - &self, - nav_history: Rc>, - cx: &mut MutableAppContext, - ) -> Option>; + fn set_nav_history(&self, nav_history: Rc>, cx: &mut MutableAppContext); + fn clone_on_split(&self, cx: &mut MutableAppContext) -> Option>; fn added_to_pane(&mut self, cx: &mut ViewContext); fn deactivated(&self, cx: &mut MutableAppContext); fn navigate(&self, data: Box, cx: &mut MutableAppContext); @@ -256,97 +219,6 @@ pub trait WeakItemViewHandle { fn upgrade(&self, cx: &AppContext) -> Option>; } -impl ItemHandle for ModelHandle { - fn id(&self) -> usize { - self.id() - } - - fn add_view( - &self, - window_id: usize, - workspace: &Workspace, - nav_history: Rc>, - cx: &mut MutableAppContext, - ) -> Box { - Box::new(cx.add_view(window_id, |cx| { - let nav_history = ItemNavHistory::new(nav_history, &cx.handle()); - T::build_view(self.clone(), workspace, nav_history, cx) - })) - } - - fn boxed_clone(&self) -> Box { - Box::new(self.clone()) - } - - fn downgrade(&self) -> Box { - Box::new(self.downgrade()) - } - - fn to_any(&self) -> AnyModelHandle { - self.clone().into() - } - - fn project_path(&self, cx: &AppContext) -> Option { - self.read(cx).project_path() - } -} - -impl ItemHandle for Box { - fn id(&self) -> usize { - ItemHandle::id(self.as_ref()) - } - - fn add_view( - &self, - window_id: usize, - workspace: &Workspace, - nav_history: Rc>, - cx: &mut MutableAppContext, - ) -> Box { - ItemHandle::add_view(self.as_ref(), window_id, workspace, nav_history, cx) - } - - fn boxed_clone(&self) -> Box { - self.as_ref().boxed_clone() - } - - fn downgrade(&self) -> Box { - self.as_ref().downgrade() - } - - fn to_any(&self) -> AnyModelHandle { - self.as_ref().to_any() - } - - fn project_path(&self, cx: &AppContext) -> Option { - self.as_ref().project_path(cx) - } -} - -impl WeakItemHandle for WeakModelHandle { - fn id(&self) -> usize { - WeakModelHandle::id(self) - } - - fn upgrade(&self, cx: &AppContext) -> Option> { - WeakModelHandle::::upgrade(self, cx).map(|i| Box::new(i) as Box) - } -} - -impl Hash for Box { - fn hash(&self, state: &mut H) { - self.id().hash(state); - } -} - -impl PartialEq for Box { - fn eq(&self, other: &Self) -> bool { - self.id() == other.id() - } -} - -impl Eq for Box {} - impl dyn ItemViewHandle { pub fn downcast(&self) -> Option> { self.to_any().downcast() @@ -359,10 +231,6 @@ impl dyn ItemViewHandle { } impl ItemViewHandle for ViewHandle { - fn item(&self, cx: &AppContext) -> Box { - self.read(cx).item(cx) - } - fn tab_content(&self, style: &theme::Tab, cx: &AppContext) -> ElementBox { self.read(cx).tab_content(style, cx) } @@ -371,23 +239,31 @@ impl ItemViewHandle for ViewHandle { self.read(cx).project_path(cx) } + fn project_entry_id(&self, cx: &AppContext) -> Option { + Some(self.read(cx).project_entry(cx)?.entry_id) + } + fn boxed_clone(&self) -> Box { Box::new(self.clone()) } fn clone_on_split( &self, - nav_history: Rc>, + // nav_history: Rc>, cx: &mut MutableAppContext, ) -> Option> { self.update(cx, |item, cx| { - cx.add_option_view(|cx| { - item.clone_on_split(ItemNavHistory::new(nav_history, &cx.handle()), cx) - }) + cx.add_option_view(|cx| item.clone_on_split(cx)) }) .map(|handle| Box::new(handle) as Box) } + fn set_nav_history(&self, nav_history: Rc>, cx: &mut MutableAppContext) { + self.update(cx, |item, cx| { + item.set_nav_history(ItemNavHistory::new(nav_history, &cx.handle()), cx); + }) + } + fn added_to_pane(&mut self, cx: &mut ViewContext) { cx.subscribe(self, |pane, item, event, cx| { if T::should_close_item_on_event(event) { @@ -469,12 +345,6 @@ impl Clone for Box { } } -impl Clone for Box { - fn clone(&self) -> Box { - self.boxed_clone() - } -} - impl WeakItemViewHandle for WeakViewHandle { fn id(&self) -> usize { self.id() @@ -563,7 +433,7 @@ pub struct Workspace { status_bar: ViewHandle, project: ModelHandle, path_openers: Arc<[Box]>, - items: BTreeMap, Box>, + // items: BTreeMap, Box>, _observe_current_user: Task<()>, } @@ -627,7 +497,6 @@ impl Workspace { right_sidebar: Sidebar::new(Side::Right), project: params.project.clone(), path_openers: params.path_openers.clone(), - items: Default::default(), _observe_current_user, } } @@ -804,16 +673,23 @@ impl Workspace { &mut self, path: ProjectPath, cx: &mut ViewContext, - ) -> Task>> { - if let Some(existing_item) = self.item_for_path(&path, cx) { + ) -> Task>> { + let project_entry = self.project.read(cx).entry_for_path(&path, cx); + + if let Some(existing_item) = project_entry.and_then(|entry| { + self.panes + .iter() + .find_map(|pane| pane.read(cx).item_for_entry(entry)) + }) { return Task::ready(Ok(existing_item)); } let project_path = path.clone(); let path_openers = self.path_openers.clone(); + let window_id = cx.window_id(); self.project.update(cx, |project, cx| { for opener in path_openers.iter() { - if let Some(task) = opener.open(project, project_path.clone(), cx) { + if let Some(task) = opener.open(project, project_path.clone(), window_id, cx) { return task; } } @@ -821,26 +697,19 @@ impl Workspace { }) } - fn item_for_path(&self, path: &ProjectPath, cx: &AppContext) -> Option> { - self.items - .values() - .filter_map(|i| i.upgrade(cx)) - .find(|i| i.project_path(cx).as_ref() == Some(path)) + pub fn item_of_type(&self, cx: &AppContext) -> Option> { + self.items_of_type(cx).max_by_key(|item| item.id()) } - pub fn item_of_type(&self, cx: &AppContext) -> Option> { - self.items - .values() - .find_map(|i| i.upgrade(cx).and_then(|i| i.to_any().downcast())) - } - - pub fn items_of_type<'a, T: Item>( + pub fn items_of_type<'a, T: ItemView>( &'a self, cx: &'a AppContext, - ) -> impl 'a + Iterator> { - self.items - .values() - .filter_map(|i| i.upgrade(cx).and_then(|i| i.to_any().downcast())) + ) -> impl 'a + Iterator> { + self.panes.iter().flat_map(|pane| { + pane.read(cx) + .item_views() + .filter_map(|item| item.to_any().downcast()) + }) } pub fn active_item(&self, cx: &AppContext) -> Option> { @@ -962,52 +831,46 @@ impl Workspace { pane } - pub fn open_item( + pub fn open_item( &mut self, - item_handle: T, + item_view: Box, cx: &mut ViewContext, - ) -> Box - where - T: 'static + ItemHandle, - { - self.open_item_in_pane(item_handle, &self.active_pane().clone(), cx) + ) -> Box { + self.open_item_in_pane(item_view, &self.active_pane().clone(), cx) } - pub fn open_item_in_pane( + pub fn open_item_in_pane( &mut self, - item_handle: T, + item_view: Box, pane: &ViewHandle, cx: &mut ViewContext, - ) -> Box - where - T: 'static + ItemHandle, - { - self.items - .insert(Reverse(item_handle.id()), item_handle.downgrade()); - pane.update(cx, |pane, cx| pane.open_item(item_handle, self, cx)) + ) -> Box { + pane.update(cx, |pane, cx| pane.open_item(item_view, cx)) } - pub fn activate_pane_for_item( + pub fn open_item_for_project_entry( &mut self, - item: &dyn ItemHandle, + project_entry: ProjectEntry, cx: &mut ViewContext, - ) -> bool { - let pane = self.panes.iter().find_map(|pane| { - if pane.read(cx).contains_item(item) { - Some(pane.clone()) - } else { - None - } - }); - if let Some(pane) = pane { - self.activate_pane(pane.clone(), cx); - true - } else { - false + build_view: F, + ) -> Box + where + T: ItemView, + F: FnOnce(&mut ViewContext) -> T, + { + if let Some(existing_item) = self + .panes + .iter() + .find_map(|pane| pane.read(cx).item_for_entry(project_entry)) + { + return existing_item.boxed_clone(); } + + let view = Box::new(cx.add_view(build_view)); + self.open_item(view, cx) } - pub fn activate_item(&mut self, item: &dyn ItemHandle, cx: &mut ViewContext) -> bool { + pub fn activate_item(&mut self, item: &dyn ItemViewHandle, cx: &mut ViewContext) -> bool { let result = self.panes.iter().find_map(|pane| { if let Some(ix) = pane.read(cx).index_for_item(item) { Some((pane.clone(), ix)) @@ -1078,9 +941,8 @@ impl Workspace { self.activate_pane(new_pane.clone(), cx); if let Some(item) = pane.read(cx).active_item() { let nav_history = new_pane.read(cx).nav_history().clone(); - if let Some(clone) = item.clone_on_split(nav_history, cx.as_mut()) { - let item = clone.item(cx).downgrade(); - self.items.insert(Reverse(item.id()), item); + if let Some(clone) = item.clone_on_split(cx.as_mut()) { + clone.set_nav_history(nav_history, cx); new_pane.update(cx, |new_pane, cx| new_pane.add_item_view(clone, cx)); } } From 0036e5c86c39c89b1a560a1e2ffc744d38ad0e24 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 16 Mar 2022 15:59:47 -0600 Subject: [PATCH 02/14] Replace ProjectEntry struct with ProjectEntryId Previously, we tracked the worktree_id and entry_id separately, but now that entry ids are unique across all worktrees this is unnecessary. Co-Authored-By: Max Brunsfeld Co-Authored-By: Keith Simmons --- crates/diagnostics/src/diagnostics.rs | 2 +- crates/editor/src/editor.rs | 4 +- crates/editor/src/items.rs | 6 +- crates/project/src/project.rs | 61 +++++++++---- crates/project/src/worktree.rs | 51 +++++------ crates/project_panel/src/project_panel.rs | 106 +++++++++------------- crates/search/src/project_search.rs | 2 +- crates/workspace/src/pane.rs | 8 +- crates/workspace/src/workspace.rs | 12 +-- 9 files changed, 126 insertions(+), 126 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 1db19f7f5e786c43634f0291f15061aa7ee3324e..2b10adb202283d0b47c18506aaf3559faba06901 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -449,7 +449,7 @@ impl workspace::ItemView for ProjectDiagnosticsEditor { None } - fn project_entry(&self, _: &AppContext) -> Option { + fn project_entry_id(&self, _: &AppContext) -> Option { None } diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 6a298591951dc7c8d12476982225cdae01b58503..704a2cf248156821da6f194428018c3b48075f07 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -842,8 +842,8 @@ impl Editor { ) -> ViewHandle { let project = workspace.project().clone(); - if let Some(project_entry) = - project::File::from_dyn(buffer.read(cx).file()).and_then(|file| file.project_entry(cx)) + if let Some(project_entry) = project::File::from_dyn(buffer.read(cx).file()) + .and_then(|file| file.project_entry_id(cx)) { return workspace .open_item_for_project_entry(project_entry, cx, |cx| { diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index b84a095e6b2bfa3ee8356164b7f83c8eb02bc23f..a9bac1908b5e5ce90eeec4ad0d9f976999a31227 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -5,7 +5,7 @@ use gpui::{ View, ViewContext, ViewHandle, WeakModelHandle, }; use language::{Bias, Buffer, Diagnostic, File as _}; -use project::{File, Project, ProjectEntry, ProjectPath}; +use project::{File, Project, ProjectEntryId, ProjectPath}; use std::fmt::Write; use std::path::PathBuf; use text::{Point, Selection}; @@ -75,8 +75,8 @@ impl ItemView for Editor { }) } - fn project_entry(&self, cx: &AppContext) -> Option { - File::from_dyn(self.buffer().read(cx).file(cx)).and_then(|file| file.project_entry(cx)) + fn project_entry_id(&self, cx: &AppContext) -> Option { + File::from_dyn(self.buffer().read(cx).file(cx)).and_then(|file| file.project_entry_id(cx)) } fn clone_on_split(&self, cx: &mut ViewContext) -> Option diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index b9bb25a5fcdd9f66f46c82ed73d84a0429e44d96..ae60ab825fac9bce7de85a011f98781bfabae937 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -39,7 +39,7 @@ use std::{ path::{Component, Path, PathBuf}, rc::Rc, sync::{ - atomic::{AtomicBool, AtomicUsize}, + atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst}, Arc, }, time::Instant, @@ -51,7 +51,7 @@ pub use worktree::*; pub struct Project { worktrees: Vec, - active_entry: Option, + active_entry: Option, languages: Arc, language_servers: HashMap<(WorktreeId, Arc), Arc>, started_language_servers: HashMap<(WorktreeId, Arc), Task>>>, @@ -114,7 +114,7 @@ pub struct Collaborator { #[derive(Clone, Debug, PartialEq)] pub enum Event { - ActiveEntryChanged(Option), + ActiveEntryChanged(Option), WorktreeRemoved(WorktreeId), DiskBasedDiagnosticsStarted, DiskBasedDiagnosticsUpdated, @@ -226,10 +226,25 @@ impl DiagnosticSummary { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct ProjectEntry { - pub worktree_id: WorktreeId, - pub entry_id: usize, +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct ProjectEntryId(usize); + +impl ProjectEntryId { + pub fn new(counter: &AtomicUsize) -> Self { + Self(counter.fetch_add(1, SeqCst)) + } + + pub fn from_proto(id: u64) -> Self { + Self(id as usize) + } + + pub fn to_proto(&self) -> u64 { + self.0 as u64 + } + + pub fn to_usize(&self) -> usize { + self.0 + } } impl Project { @@ -623,6 +638,24 @@ impl Project { .find(|worktree| worktree.read(cx).id() == id) } + pub fn worktree_for_entry( + &self, + entry_id: ProjectEntryId, + cx: &AppContext, + ) -> Option> { + self.worktrees(cx) + .find(|worktree| worktree.read(cx).contains_entry(entry_id)) + } + + pub fn worktree_id_for_entry( + &self, + entry_id: ProjectEntryId, + cx: &AppContext, + ) -> Option { + self.worktree_for_entry(entry_id, cx) + .map(|worktree| worktree.read(cx).id()) + } + pub fn share(&self, cx: &mut ModelContext) -> Task> { let rpc = self.client.clone(); cx.spawn(|this, mut cx| async move { @@ -3163,10 +3196,7 @@ impl Project { let new_active_entry = entry.and_then(|project_path| { let worktree = self.worktree_for_id(project_path.worktree_id, cx)?; let entry = worktree.read(cx).entry_for_path(project_path.path)?; - Some(ProjectEntry { - worktree_id: project_path.worktree_id, - entry_id: entry.id, - }) + Some(entry.id) }); if new_active_entry != self.active_entry { self.active_entry = new_active_entry; @@ -3217,18 +3247,15 @@ impl Project { } } - pub fn active_entry(&self) -> Option { + pub fn active_entry(&self) -> Option { self.active_entry } - pub fn entry_for_path(&self, path: &ProjectPath, cx: &AppContext) -> Option { + pub fn entry_for_path(&self, path: &ProjectPath, cx: &AppContext) -> Option { self.worktree_for_id(path.worktree_id, cx)? .read(cx) .entry_for_path(&path.path) - .map(|entry| ProjectEntry { - worktree_id: path.worktree_id, - entry_id: entry.id, - }) + .map(|entry| entry.id) } // RPC message handlers diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 4a121c82e4e7109c3e012f9660a07baaa1cfbb2e..2bc9c3d234c58ceb33ba66a0c6cf3a3b1fc925c7 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -1,4 +1,4 @@ -use crate::ProjectEntry; +use crate::ProjectEntryId; use super::{ fs::{self, Fs}, @@ -41,10 +41,7 @@ use std::{ future::Future, ops::{Deref, DerefMut}, path::{Path, PathBuf}, - sync::{ - atomic::{AtomicUsize, Ordering::SeqCst}, - Arc, - }, + sync::{atomic::AtomicUsize, Arc}, time::{Duration, SystemTime}, }; use sum_tree::{Bias, Edit, SeekTarget, SumTree, TreeMap}; @@ -103,7 +100,7 @@ pub struct LocalSnapshot { abs_path: Arc, scan_id: usize, ignores: HashMap, (Arc, usize)>, - removed_entry_ids: HashMap, + removed_entry_ids: HashMap, next_entry_id: Arc, snapshot: Snapshot, } @@ -858,13 +855,16 @@ impl Snapshot { self.id } + pub fn contains_entry(&self, entry_id: ProjectEntryId) -> bool { + self.entries_by_id.get(&entry_id, &()).is_some() + } + pub(crate) fn apply_remote_update(&mut self, update: proto::UpdateWorktree) -> Result<()> { let mut entries_by_path_edits = Vec::new(); let mut entries_by_id_edits = Vec::new(); for entry_id in update.removed_entries { - let entry_id = entry_id as usize; let entry = self - .entry_for_id(entry_id) + .entry_for_id(ProjectEntryId::from_proto(entry_id)) .ok_or_else(|| anyhow!("unknown entry"))?; entries_by_path_edits.push(Edit::Remove(PathKey(entry.path.clone()))); entries_by_id_edits.push(Edit::Remove(entry.id)); @@ -987,7 +987,7 @@ impl Snapshot { }) } - pub fn entry_for_id(&self, id: usize) -> Option<&Entry> { + pub fn entry_for_id(&self, id: ProjectEntryId) -> Option<&Entry> { let entry = self.entries_by_id.get(&id, &())?; self.entry_for_path(&entry.path) } @@ -1064,7 +1064,7 @@ impl LocalSnapshot { other_entries.next(); } Ordering::Greater => { - removed_entries.push(other_entry.id as u64); + removed_entries.push(other_entry.id.to_proto()); other_entries.next(); } } @@ -1075,7 +1075,7 @@ impl LocalSnapshot { self_entries.next(); } (None, Some(other_entry)) => { - removed_entries.push(other_entry.id as u64); + removed_entries.push(other_entry.id.to_proto()); other_entries.next(); } (None, None) => break, @@ -1328,7 +1328,7 @@ pub struct File { pub worktree: ModelHandle, pub path: Arc, pub mtime: SystemTime, - pub(crate) entry_id: Option, + pub(crate) entry_id: Option, pub(crate) is_local: bool, } @@ -1425,7 +1425,7 @@ impl language::File for File { fn to_proto(&self) -> rpc::proto::File { rpc::proto::File { worktree_id: self.worktree.id() as u64, - entry_id: self.entry_id.map(|entry_id| entry_id as u64), + entry_id: self.entry_id.map(|entry_id| entry_id.to_proto()), path: self.path.to_string_lossy().into(), mtime: Some(self.mtime.into()), } @@ -1492,7 +1492,7 @@ impl File { worktree, path: Path::new(&proto.path).into(), mtime: proto.mtime.ok_or_else(|| anyhow!("no timestamp"))?.into(), - entry_id: proto.entry_id.map(|entry_id| entry_id as usize), + entry_id: proto.entry_id.map(ProjectEntryId::from_proto), is_local: false, }) } @@ -1505,17 +1505,14 @@ impl File { self.worktree.read(cx).id() } - pub fn project_entry(&self, cx: &AppContext) -> Option { - self.entry_id.map(|entry_id| ProjectEntry { - worktree_id: self.worktree_id(cx), - entry_id, - }) + pub fn project_entry_id(&self, _: &AppContext) -> Option { + self.entry_id } } #[derive(Clone, Debug, PartialEq, Eq)] pub struct Entry { - pub id: usize, + pub id: ProjectEntryId, pub kind: EntryKind, pub path: Arc, pub inode: u64, @@ -1539,7 +1536,7 @@ impl Entry { root_char_bag: CharBag, ) -> Self { Self { - id: next_entry_id.fetch_add(1, SeqCst), + id: ProjectEntryId::new(next_entry_id), kind: if metadata.is_dir { EntryKind::PendingDir } else { @@ -1629,7 +1626,7 @@ impl sum_tree::Summary for EntrySummary { #[derive(Clone, Debug)] struct PathEntry { - id: usize, + id: ProjectEntryId, path: Arc, is_ignored: bool, scan_id: usize, @@ -1644,7 +1641,7 @@ impl sum_tree::Item for PathEntry { } impl sum_tree::KeyedItem for PathEntry { - type Key = usize; + type Key = ProjectEntryId; fn key(&self) -> Self::Key { self.id @@ -1653,7 +1650,7 @@ impl sum_tree::KeyedItem for PathEntry { #[derive(Clone, Debug, Default)] struct PathEntrySummary { - max_id: usize, + max_id: ProjectEntryId, } impl sum_tree::Summary for PathEntrySummary { @@ -1664,7 +1661,7 @@ impl sum_tree::Summary for PathEntrySummary { } } -impl<'a> sum_tree::Dimension<'a, PathEntrySummary> for usize { +impl<'a> sum_tree::Dimension<'a, PathEntrySummary> for ProjectEntryId { fn add_summary(&mut self, summary: &'a PathEntrySummary, _: &()) { *self = summary.max_id; } @@ -2354,7 +2351,7 @@ impl<'a> Iterator for ChildEntriesIter<'a> { impl<'a> From<&'a Entry> for proto::Entry { fn from(entry: &'a Entry) -> Self { Self { - id: entry.id as u64, + id: entry.id.to_proto(), is_dir: entry.is_dir(), path: entry.path.to_string_lossy().to_string(), inode: entry.inode, @@ -2379,7 +2376,7 @@ impl<'a> TryFrom<(&'a CharBag, proto::Entry)> for Entry { }; let path: Arc = Arc::from(Path::new(&entry.path)); Ok(Entry { - id: entry.id as usize, + id: ProjectEntryId::from_proto(entry.id), kind, path: path.clone(), inode: entry.inode, diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 7f03005b80cc2d8eddab64f0c59a509cf2d6f12b..372f0c169bb06602ebbfc4bbb2f7e576ca4d051e 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -9,7 +9,7 @@ use gpui::{ AppContext, Element, ElementBox, Entity, ModelHandle, MutableAppContext, View, ViewContext, ViewHandle, WeakViewHandle, }; -use project::{Project, ProjectEntry, ProjectPath, Worktree, WorktreeId}; +use project::{Project, ProjectEntryId, ProjectPath, Worktree, WorktreeId}; use std::{ collections::{hash_map, HashMap}, ffi::OsStr, @@ -24,7 +24,7 @@ pub struct ProjectPanel { project: ModelHandle, list: UniformListState, visible_entries: Vec<(WorktreeId, Vec)>, - expanded_dir_ids: HashMap>, + expanded_dir_ids: HashMap>, selection: Option, handle: WeakViewHandle, } @@ -32,7 +32,7 @@ pub struct ProjectPanel { #[derive(Copy, Clone)] struct Selection { worktree_id: WorktreeId, - entry_id: usize, + entry_id: ProjectEntryId, index: usize, } @@ -47,8 +47,8 @@ struct EntryDetails { action!(ExpandSelectedEntry); action!(CollapseSelectedEntry); -action!(ToggleExpanded, ProjectEntry); -action!(Open, ProjectEntry); +action!(ToggleExpanded, ProjectEntryId); +action!(Open, ProjectEntryId); pub fn init(cx: &mut MutableAppContext) { cx.add_action(ProjectPanel::expand_selected_entry); @@ -64,10 +64,7 @@ pub fn init(cx: &mut MutableAppContext) { } pub enum Event { - OpenedEntry { - worktree_id: WorktreeId, - entry_id: usize, - }, + OpenedEntry(ProjectEntryId), } impl ProjectPanel { @@ -78,15 +75,15 @@ impl ProjectPanel { cx.notify(); }) .detach(); - cx.subscribe(&project, |this, _, event, cx| match event { - project::Event::ActiveEntryChanged(Some(ProjectEntry { - worktree_id, - entry_id, - })) => { - this.expand_entry(*worktree_id, *entry_id, cx); - this.update_visible_entries(Some((*worktree_id, *entry_id)), cx); - this.autoscroll(); - cx.notify(); + cx.subscribe(&project, |this, project, event, cx| match event { + project::Event::ActiveEntryChanged(Some(entry_id)) => { + if let Some(worktree_id) = project.read(cx).worktree_id_for_entry(*entry_id, cx) + { + this.expand_entry(worktree_id, *entry_id, cx); + this.update_visible_entries(Some((worktree_id, *entry_id)), cx); + this.autoscroll(); + cx.notify(); + } } project::Event::WorktreeRemoved(id) => { this.expanded_dir_ids.remove(id); @@ -109,16 +106,13 @@ impl ProjectPanel { this }); cx.subscribe(&project_panel, move |workspace, _, event, cx| match event { - &Event::OpenedEntry { - worktree_id, - entry_id, - } => { - if let Some(worktree) = project.read(cx).worktree_for_id(worktree_id, cx) { + &Event::OpenedEntry(entry_id) => { + if let Some(worktree) = project.read(cx).worktree_for_entry(entry_id, cx) { if let Some(entry) = worktree.read(cx).entry_for_id(entry_id) { workspace .open_path( ProjectPath { - worktree_id, + worktree_id: worktree.read(cx).id(), path: entry.path.clone(), }, cx, @@ -152,10 +146,7 @@ impl ProjectPanel { } } } else { - let event = Event::OpenedEntry { - worktree_id: worktree.id(), - entry_id: entry.id, - }; + let event = Event::OpenedEntry(entry.id); cx.emit(event); } } @@ -193,22 +184,20 @@ impl ProjectPanel { } fn toggle_expanded(&mut self, action: &ToggleExpanded, cx: &mut ViewContext) { - let ProjectEntry { - worktree_id, - entry_id, - } = action.0; - - if let Some(expanded_dir_ids) = self.expanded_dir_ids.get_mut(&worktree_id) { - match expanded_dir_ids.binary_search(&entry_id) { - Ok(ix) => { - expanded_dir_ids.remove(ix); - } - Err(ix) => { - expanded_dir_ids.insert(ix, entry_id); + let entry_id = action.0; + if let Some(worktree_id) = self.project.read(cx).worktree_id_for_entry(entry_id, cx) { + if let Some(expanded_dir_ids) = self.expanded_dir_ids.get_mut(&worktree_id) { + match expanded_dir_ids.binary_search(&entry_id) { + Ok(ix) => { + expanded_dir_ids.remove(ix); + } + Err(ix) => { + expanded_dir_ids.insert(ix, entry_id); + } } + self.update_visible_entries(Some((worktree_id, entry_id)), cx); + cx.focus_self(); } - self.update_visible_entries(Some((worktree_id, entry_id)), cx); - cx.focus_self(); } } @@ -229,10 +218,7 @@ impl ProjectPanel { } fn open_entry(&mut self, action: &Open, cx: &mut ViewContext) { - cx.emit(Event::OpenedEntry { - worktree_id: action.0.worktree_id, - entry_id: action.0.entry_id, - }); + cx.emit(Event::OpenedEntry(action.0)); } fn select_next(&mut self, _: &SelectNext, cx: &mut ViewContext) { @@ -313,7 +299,7 @@ impl ProjectPanel { fn update_visible_entries( &mut self, - new_selected_entry: Option<(WorktreeId, usize)>, + new_selected_entry: Option<(WorktreeId, ProjectEntryId)>, cx: &mut ViewContext, ) { let worktrees = self @@ -379,7 +365,7 @@ impl ProjectPanel { fn expand_entry( &mut self, worktree_id: WorktreeId, - entry_id: usize, + entry_id: ProjectEntryId, cx: &mut ViewContext, ) { let project = self.project.read(cx); @@ -411,7 +397,7 @@ impl ProjectPanel { &self, range: Range, cx: &mut ViewContext, - mut callback: impl FnMut(ProjectEntry, EntryDetails, &mut ViewContext), + mut callback: impl FnMut(ProjectEntryId, EntryDetails, &mut ViewContext), ) { let mut ix = 0; for (worktree_id, visible_worktree_entries) in &self.visible_entries { @@ -450,11 +436,7 @@ impl ProjectPanel { e.worktree_id == snapshot.id() && e.entry_id == entry.id }), }; - let entry = ProjectEntry { - worktree_id: snapshot.id(), - entry_id: entry.id, - }; - callback(entry, details, cx); + callback(entry.id, details, cx); } } } @@ -463,13 +445,13 @@ impl ProjectPanel { } fn render_entry( - entry: ProjectEntry, + entry_id: ProjectEntryId, details: EntryDetails, theme: &theme::ProjectPanel, cx: &mut ViewContext, ) -> ElementBox { let is_dir = details.is_dir; - MouseEventHandler::new::(entry.entry_id, cx, |state, _| { + MouseEventHandler::new::(entry_id.to_usize(), cx, |state, _| { let style = match (details.is_selected, state.hovered) { (false, false) => &theme.entry, (false, true) => &theme.hovered_entry, @@ -519,9 +501,9 @@ impl ProjectPanel { }) .on_click(move |cx| { if is_dir { - cx.dispatch_action(ToggleExpanded(entry)) + cx.dispatch_action(ToggleExpanded(entry_id)) } else { - cx.dispatch_action(Open(entry)) + cx.dispatch_action(Open(entry_id)) } }) .with_cursor_style(CursorStyle::PointingHand) @@ -830,13 +812,7 @@ mod tests { let worktree = worktree.read(cx); if let Ok(relative_path) = path.strip_prefix(worktree.root_name()) { let entry_id = worktree.entry_for_path(relative_path).unwrap().id; - panel.toggle_expanded( - &ToggleExpanded(ProjectEntry { - worktree_id: worktree.id(), - entry_id, - }), - cx, - ); + panel.toggle_expanded(&ToggleExpanded(entry_id), cx); return; } } diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 56395b107a4b325bd4d1239807bc11456a7becbd..20df486f486a0fcf58cd6853e55d53262e7a62da 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -250,7 +250,7 @@ impl ItemView for ProjectSearchView { None } - fn project_entry(&self, _: &AppContext) -> Option { + fn project_entry_id(&self, _: &AppContext) -> Option { None } diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 9f5ee5227431df6a60ae76df9cea66331c18869f..5d346279f0fa3e425dca6b7b9db1dd2ddef50cdb 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -10,7 +10,7 @@ use gpui::{ AnyViewHandle, Entity, MutableAppContext, Quad, RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle, }; -use project::{ProjectEntry, ProjectPath}; +use project::{ProjectEntryId, ProjectPath}; use std::{ any::{Any, TypeId}, cell::RefCell, @@ -97,7 +97,7 @@ pub enum Event { } pub struct Pane { - item_views: Vec<(Option, Box)>, + item_views: Vec<(Option, Box)>, active_item_index: usize, nav_history: Rc>, toolbars: HashMap>, @@ -323,9 +323,9 @@ impl Pane { .map(|(_, view)| view.clone()) } - pub fn item_for_entry(&self, entry: ProjectEntry) -> Option> { + pub fn item_for_entry(&self, entry_id: ProjectEntryId) -> Option> { self.item_views.iter().find_map(|(id, view)| { - if *id == Some(entry.entry_id) { + if *id == Some(entry_id) { Some(view.boxed_clone()) } else { None diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 5a3385a0144938a5658524b616c567e6a20fc48f..464eecd307d21207021e70d0d7c74a7695376e52 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -26,7 +26,7 @@ use log::error; pub use pane::*; pub use pane_group::*; use postage::prelude::Stream; -use project::{fs, Fs, Project, ProjectEntry, ProjectPath, Worktree}; +use project::{fs, Fs, Project, ProjectEntryId, ProjectPath, Worktree}; pub use settings::Settings; use sidebar::{Side, Sidebar, SidebarItemId, ToggleSidebarItem, ToggleSidebarItemFocus}; use status_bar::StatusBar; @@ -138,7 +138,7 @@ pub trait ItemView: View { fn navigate(&mut self, _: Box, _: &mut ViewContext) {} fn tab_content(&self, style: &theme::Tab, cx: &AppContext) -> ElementBox; fn project_path(&self, cx: &AppContext) -> Option; - fn project_entry(&self, cx: &AppContext) -> Option; + fn project_entry_id(&self, cx: &AppContext) -> Option; fn set_nav_history(&mut self, _: ItemNavHistory, _: &mut ViewContext); fn clone_on_split(&self, _: &mut ViewContext) -> Option where @@ -191,7 +191,7 @@ pub trait ItemView: View { pub trait ItemViewHandle: 'static { fn tab_content(&self, style: &theme::Tab, cx: &AppContext) -> ElementBox; fn project_path(&self, cx: &AppContext) -> Option; - fn project_entry_id(&self, cx: &AppContext) -> Option; + fn project_entry_id(&self, cx: &AppContext) -> Option; fn boxed_clone(&self) -> Box; fn set_nav_history(&self, nav_history: Rc>, cx: &mut MutableAppContext); fn clone_on_split(&self, cx: &mut MutableAppContext) -> Option>; @@ -239,8 +239,8 @@ impl ItemViewHandle for ViewHandle { self.read(cx).project_path(cx) } - fn project_entry_id(&self, cx: &AppContext) -> Option { - Some(self.read(cx).project_entry(cx)?.entry_id) + fn project_entry_id(&self, cx: &AppContext) -> Option { + self.read(cx).project_entry_id(cx) } fn boxed_clone(&self) -> Box { @@ -850,7 +850,7 @@ impl Workspace { pub fn open_item_for_project_entry( &mut self, - project_entry: ProjectEntry, + project_entry: ProjectEntryId, cx: &mut ViewContext, build_view: F, ) -> Box From 1f9885ec420c952e0a792ff2238bd1c840553b17 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 16 Mar 2022 16:08:13 -0600 Subject: [PATCH 03/14] Remove open_item_in_pane Co-Authored-By: Max Brunsfeld Co-Authored-By: Keith Simmons --- crates/workspace/src/pane.rs | 16 ++++++++-------- crates/workspace/src/workspace.rs | 24 +++++++----------------- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 5d346279f0fa3e425dca6b7b9db1dd2ddef50cdb..7a7b73199e35fa90169ba3b248651c1136410605 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -256,16 +256,16 @@ impl Pane { let item = task.await; if let Some(pane) = pane.upgrade(&cx) { if let Some(item) = item.log_err() { - workspace.update(&mut cx, |workspace, cx| { - pane.update(cx, |p, _| p.nav_history.borrow_mut().set_mode(mode)); - let item_view = workspace.open_item_in_pane(item, &pane, cx); - pane.update(cx, |p, _| { - p.nav_history.borrow_mut().set_mode(NavigationMode::Normal) - }); - + pane.update(&mut cx, |pane, cx| { + pane.nav_history.borrow_mut().set_mode(mode); + let item = pane.open_item(item, cx); + pane.nav_history + .borrow_mut() + .set_mode(NavigationMode::Normal); if let Some(data) = entry.data { - item_view.navigate(data, cx); + item.navigate(data, cx); } + item }); } else { workspace diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 464eecd307d21207021e70d0d7c74a7695376e52..9692a8c90030b5d3e0b89456f2b465f9ec436468 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -658,14 +658,12 @@ impl Workspace { ) -> Task, Arc>> { let load_task = self.load_path(path, cx); let pane = self.active_pane().clone().downgrade(); - cx.spawn(|this, mut cx| async move { + cx.as_mut().spawn(|mut cx| async move { let item = load_task.await?; - this.update(&mut cx, |this, cx| { - let pane = pane - .upgrade(cx) - .ok_or_else(|| anyhow!("could not upgrade pane reference"))?; - Ok(this.open_item_in_pane(item, &pane, cx)) - }) + let pane = pane + .upgrade(&cx) + .ok_or_else(|| anyhow!("could not upgrade pane reference"))?; + Ok(pane.update(&mut cx, |pane, cx| pane.open_item(item, cx))) }) } @@ -836,16 +834,8 @@ impl Workspace { item_view: Box, cx: &mut ViewContext, ) -> Box { - self.open_item_in_pane(item_view, &self.active_pane().clone(), cx) - } - - pub fn open_item_in_pane( - &mut self, - item_view: Box, - pane: &ViewHandle, - cx: &mut ViewContext, - ) -> Box { - pane.update(cx, |pane, cx| pane.open_item(item_view, cx)) + self.active_pane() + .update(cx, |pane, cx| pane.open_item(item_view, cx)) } pub fn open_item_for_project_entry( From 728c7081509740ecb02a6e24e625da53715afd67 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 16 Mar 2022 17:40:09 -0600 Subject: [PATCH 04/14] WIP: Massage opening of editors Co-Authored-By: Max Brunsfeld --- crates/diagnostics/src/diagnostics.rs | 8 +- crates/editor/src/editor.rs | 9 +- crates/editor/src/items.rs | 8 +- crates/project/src/project.rs | 103 +++++++++----- crates/search/src/project_search.rs | 4 - crates/server/src/rpc.rs | 102 ++++++++++---- crates/workspace/src/pane.rs | 48 +++++-- crates/workspace/src/workspace.rs | 190 ++++++++++++++++++++------ 8 files changed, 338 insertions(+), 134 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 2b10adb202283d0b47c18506aaf3559faba06901..7c69f85acf86eed7874732129fa01cf16eb19b7a 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -155,7 +155,9 @@ impl ProjectDiagnosticsEditor { async move { for path in paths { let buffer = project - .update(&mut cx, |project, cx| project.open_buffer(path.clone(), cx)) + .update(&mut cx, |project, cx| { + project.open_buffer_for_path(path.clone(), cx) + }) .await?; this.update(&mut cx, |view, cx| view.populate_excerpts(path, buffer, cx)) } @@ -449,10 +451,6 @@ impl workspace::ItemView for ProjectDiagnosticsEditor { None } - fn project_entry_id(&self, _: &AppContext) -> Option { - None - } - fn navigate(&mut self, data: Box, cx: &mut ViewContext) { self.editor .update(cx, |editor, cx| editor.navigate(data, cx)); diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 704a2cf248156821da6f194428018c3b48075f07..39dad90ece4e572800130bf1b24abf59aa0f1bbf 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -846,10 +846,7 @@ impl Editor { .and_then(|file| file.project_entry_id(cx)) { return workspace - .open_item_for_project_entry(project_entry, cx, |cx| { - let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - Editor::for_buffer(multibuffer, Some(project.clone()), cx) - }) + .open_editor(project_entry, cx) .downcast::() .unwrap(); } @@ -8442,7 +8439,9 @@ mod tests { .0 .read_with(cx, |tree, _| tree.id()); let buffer = project - .update(cx, |project, cx| project.open_buffer((worktree_id, ""), cx)) + .update(cx, |project, cx| { + project.open_buffer_for_path((worktree_id, ""), cx) + }) .await .unwrap(); let mut fake_server = fake_servers.next().await.unwrap(); diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index a9bac1908b5e5ce90eeec4ad0d9f976999a31227..6fec3d7a1cd967bd658fe5c18af5bd8ecc95436f 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -5,7 +5,7 @@ use gpui::{ View, ViewContext, ViewHandle, WeakModelHandle, }; use language::{Bias, Buffer, Diagnostic, File as _}; -use project::{File, Project, ProjectEntryId, ProjectPath}; +use project::{File, Project, ProjectPath}; use std::fmt::Write; use std::path::PathBuf; use text::{Point, Selection}; @@ -34,7 +34,7 @@ impl PathOpener for BufferOpener { window_id: usize, cx: &mut ModelContext, ) -> Option>>> { - let buffer = project.open_buffer(project_path, cx); + let buffer = project.open_buffer_for_path(project_path, cx); Some(cx.spawn(|project, mut cx| async move { let buffer = buffer.await?; let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); @@ -75,10 +75,6 @@ impl ItemView for Editor { }) } - fn project_entry_id(&self, cx: &AppContext) -> Option { - File::from_dyn(self.buffer().read(cx).file(cx)).and_then(|file| file.project_entry_id(cx)) - } - fn clone_on_split(&self, cx: &mut ViewContext) -> Option where Self: Sized, diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index ae60ab825fac9bce7de85a011f98781bfabae937..3484796dd9c35da31a29e8894468085dbceb481d 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -818,7 +818,19 @@ impl Project { Ok(buffer) } - pub fn open_buffer( + pub fn open_buffer_for_entry( + &mut self, + entry_id: ProjectEntryId, + cx: &mut ModelContext, + ) -> Task>> { + if let Some(project_path) = self.path_for_entry(entry_id, cx) { + self.open_buffer_for_path(project_path, cx) + } else { + Task::ready(Err(anyhow!("entry not found"))) + } + } + + pub fn open_buffer_for_path( &mut self, path: impl Into, cx: &mut ModelContext, @@ -953,8 +965,10 @@ impl Project { worktree_id: worktree.read_with(&cx, |worktree, _| worktree.id()), path: relative_path.into(), }; - this.update(&mut cx, |this, cx| this.open_buffer(project_path, cx)) - .await + this.update(&mut cx, |this, cx| { + this.open_buffer_for_path(project_path, cx) + }) + .await }) } @@ -2854,7 +2868,9 @@ impl Project { let buffers_tx = buffers_tx.clone(); cx.spawn(|mut cx| async move { if let Some(buffer) = this - .update(&mut cx, |this, cx| this.open_buffer(project_path, cx)) + .update(&mut cx, |this, cx| { + this.open_buffer_for_path(project_path, cx) + }) .await .log_err() { @@ -3258,6 +3274,14 @@ impl Project { .map(|entry| entry.id) } + pub fn path_for_entry(&self, entry_id: ProjectEntryId, cx: &AppContext) -> Option { + let worktree = self.worktree_for_entry(entry_id, cx)?; + let worktree = worktree.read(cx); + let worktree_id = worktree.id(); + let path = worktree.entry_for_id(entry_id)?.path.clone(); + Some(ProjectPath { worktree_id, path }) + } + // RPC message handlers async fn handle_unshare_project( @@ -3867,7 +3891,7 @@ impl Project { let peer_id = envelope.original_sender_id()?; let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id); let open_buffer = this.update(&mut cx, |this, cx| { - this.open_buffer( + this.open_buffer_for_path( ProjectPath { worktree_id, path: PathBuf::from(envelope.payload.path).into(), @@ -4664,7 +4688,7 @@ mod tests { // Open a buffer without an associated language server. let toml_buffer = project .update(cx, |project, cx| { - project.open_buffer((worktree_id, "Cargo.toml"), cx) + project.open_buffer_for_path((worktree_id, "Cargo.toml"), cx) }) .await .unwrap(); @@ -4672,7 +4696,7 @@ mod tests { // Open a buffer with an associated language server. let rust_buffer = project .update(cx, |project, cx| { - project.open_buffer((worktree_id, "test.rs"), cx) + project.open_buffer_for_path((worktree_id, "test.rs"), cx) }) .await .unwrap(); @@ -4719,7 +4743,7 @@ mod tests { // Open a third buffer with a different associated language server. let json_buffer = project .update(cx, |project, cx| { - project.open_buffer((worktree_id, "package.json"), cx) + project.open_buffer_for_path((worktree_id, "package.json"), cx) }) .await .unwrap(); @@ -4750,7 +4774,7 @@ mod tests { // it is also configured based on the existing language server's capabilities. let rust_buffer2 = project .update(cx, |project, cx| { - project.open_buffer((worktree_id, "test2.rs"), cx) + project.open_buffer_for_path((worktree_id, "test2.rs"), cx) }) .await .unwrap(); @@ -4861,7 +4885,7 @@ mod tests { // Cause worktree to start the fake language server let _buffer = project .update(cx, |project, cx| { - project.open_buffer((worktree_id, Path::new("b.rs")), cx) + project.open_buffer_for_path((worktree_id, Path::new("b.rs")), cx) }) .await .unwrap(); @@ -4908,7 +4932,9 @@ mod tests { ); let buffer = project - .update(cx, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)) + .update(cx, |p, cx| { + p.open_buffer_for_path((worktree_id, "a.rs"), cx) + }) .await .unwrap(); @@ -4975,7 +5001,7 @@ mod tests { let buffer = project .update(cx, |project, cx| { - project.open_buffer((worktree_id, "a.rs"), cx) + project.open_buffer_for_path((worktree_id, "a.rs"), cx) }) .await .unwrap(); @@ -5251,7 +5277,7 @@ mod tests { let buffer = project .update(cx, |project, cx| { - project.open_buffer((worktree_id, "a.rs"), cx) + project.open_buffer_for_path((worktree_id, "a.rs"), cx) }) .await .unwrap(); @@ -5356,7 +5382,7 @@ mod tests { let buffer = project .update(cx, |project, cx| { - project.open_buffer((worktree_id, "a.rs"), cx) + project.open_buffer_for_path((worktree_id, "a.rs"), cx) }) .await .unwrap(); @@ -5514,7 +5540,7 @@ mod tests { let buffer = project .update(cx, |project, cx| { - project.open_buffer((worktree_id, "a.rs"), cx) + project.open_buffer_for_path((worktree_id, "a.rs"), cx) }) .await .unwrap(); @@ -5697,7 +5723,7 @@ mod tests { let buffer = project .update(cx, |project, cx| { - project.open_buffer( + project.open_buffer_for_path( ProjectPath { worktree_id, path: Path::new("").into(), @@ -5793,7 +5819,9 @@ mod tests { .read_with(cx, |tree, _| tree.id()); let buffer = project - .update(cx, |p, cx| p.open_buffer((worktree_id, "file1"), cx)) + .update(cx, |p, cx| { + p.open_buffer_for_path((worktree_id, "file1"), cx) + }) .await .unwrap(); buffer @@ -5831,7 +5859,7 @@ mod tests { .read_with(cx, |tree, _| tree.id()); let buffer = project - .update(cx, |p, cx| p.open_buffer((worktree_id, ""), cx)) + .update(cx, |p, cx| p.open_buffer_for_path((worktree_id, ""), cx)) .await .unwrap(); buffer @@ -5881,7 +5909,7 @@ mod tests { let opened_buffer = project .update(cx, |project, cx| { - project.open_buffer((worktree_id, "file1"), cx) + project.open_buffer_for_path((worktree_id, "file1"), cx) }) .await .unwrap(); @@ -5916,7 +5944,8 @@ mod tests { let worktree_id = tree.read_with(cx, |tree, _| tree.id()); let buffer_for_path = |path: &'static str, cx: &mut gpui::TestAppContext| { - let buffer = project.update(cx, |p, cx| p.open_buffer((worktree_id, path), cx)); + let buffer = + project.update(cx, |p, cx| p.open_buffer_for_path((worktree_id, path), cx)); async move { buffer.await.unwrap() } }; let id_for_path = |path: &'static str, cx: &gpui::TestAppContext| { @@ -6065,9 +6094,9 @@ mod tests { // Spawn multiple tasks to open paths, repeating some paths. let (buffer_a_1, buffer_b, buffer_a_2) = project.update(cx, |p, cx| { ( - p.open_buffer((worktree_id, "a.txt"), cx), - p.open_buffer((worktree_id, "b.txt"), cx), - p.open_buffer((worktree_id, "a.txt"), cx), + p.open_buffer_for_path((worktree_id, "a.txt"), cx), + p.open_buffer_for_path((worktree_id, "b.txt"), cx), + p.open_buffer_for_path((worktree_id, "a.txt"), cx), ) }); @@ -6084,7 +6113,9 @@ mod tests { // Open the same path again while it is still open. drop(buffer_a_1); let buffer_a_3 = project - .update(cx, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) + .update(cx, |p, cx| { + p.open_buffer_for_path((worktree_id, "a.txt"), cx) + }) .await .unwrap(); @@ -6117,7 +6148,9 @@ mod tests { .await; let buffer1 = project - .update(cx, |p, cx| p.open_buffer((worktree_id, "file1"), cx)) + .update(cx, |p, cx| { + p.open_buffer_for_path((worktree_id, "file1"), cx) + }) .await .unwrap(); let events = Rc::new(RefCell::new(Vec::new())); @@ -6187,7 +6220,9 @@ mod tests { // When a file is deleted, the buffer is considered dirty. let events = Rc::new(RefCell::new(Vec::new())); let buffer2 = project - .update(cx, |p, cx| p.open_buffer((worktree_id, "file2"), cx)) + .update(cx, |p, cx| { + p.open_buffer_for_path((worktree_id, "file2"), cx) + }) .await .unwrap(); buffer2.update(cx, |_, cx| { @@ -6208,7 +6243,9 @@ mod tests { // When a file is already dirty when deleted, we don't emit a Dirtied event. let events = Rc::new(RefCell::new(Vec::new())); let buffer3 = project - .update(cx, |p, cx| p.open_buffer((worktree_id, "file3"), cx)) + .update(cx, |p, cx| { + p.open_buffer_for_path((worktree_id, "file3"), cx) + }) .await .unwrap(); buffer3.update(cx, |_, cx| { @@ -6254,7 +6291,9 @@ mod tests { let abs_path = dir.path().join("the-file"); let buffer = project - .update(cx, |p, cx| p.open_buffer((worktree_id, "the-file"), cx)) + .update(cx, |p, cx| { + p.open_buffer_for_path((worktree_id, "the-file"), cx) + }) .await .unwrap(); @@ -6360,7 +6399,9 @@ mod tests { let worktree_id = worktree.read_with(cx, |tree, _| tree.id()); let buffer = project - .update(cx, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)) + .update(cx, |p, cx| { + p.open_buffer_for_path((worktree_id, "a.rs"), cx) + }) .await .unwrap(); @@ -6633,7 +6674,7 @@ mod tests { let buffer = project .update(cx, |project, cx| { - project.open_buffer((worktree_id, Path::new("one.rs")), cx) + project.open_buffer_for_path((worktree_id, Path::new("one.rs")), cx) }) .await .unwrap(); @@ -6771,7 +6812,7 @@ mod tests { let buffer_4 = project .update(cx, |project, cx| { - project.open_buffer((worktree_id, "four.rs"), cx) + project.open_buffer_for_path((worktree_id, "four.rs"), cx) }) .await .unwrap(); diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 20df486f486a0fcf58cd6853e55d53262e7a62da..6208ff4aaa221442d754a539a5c2ab1571664dc6 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -250,10 +250,6 @@ impl ItemView for ProjectSearchView { None } - fn project_entry_id(&self, _: &AppContext) -> Option { - None - } - fn can_save(&self, _: &gpui::AppContext) -> bool { true } diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index ed45c2d5d6b80d46c9d0a7455ff3621506bf14c1..f891dca71cc12a6d30cfeebba6707a48fda476da 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -1137,7 +1137,9 @@ mod tests { // Open the same file as client B and client A. let buffer_b = project_b - .update(cx_b, |p, cx| p.open_buffer((worktree_id, "b.txt"), cx)) + .update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "b.txt"), cx) + }) .await .unwrap(); let buffer_b = cx_b.add_model(|cx| MultiBuffer::singleton(buffer_b, cx)); @@ -1148,7 +1150,9 @@ mod tests { assert!(project.has_open_buffer((worktree_id, "b.txt"), cx)) }); let buffer_a = project_a - .update(cx_a, |p, cx| p.open_buffer((worktree_id, "b.txt"), cx)) + .update(cx_a, |p, cx| { + p.open_buffer_for_path((worktree_id, "b.txt"), cx) + }) .await .unwrap(); @@ -1238,7 +1242,9 @@ mod tests { .await .unwrap(); project_b - .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) + .update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "a.txt"), cx) + }) .await .unwrap(); @@ -1273,7 +1279,9 @@ mod tests { .await .unwrap(); project_b2 - .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) + .update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "a.txt"), cx) + }) .await .unwrap(); } @@ -1352,11 +1360,15 @@ mod tests { // Open and edit a buffer as both guests B and C. let buffer_b = project_b - .update(cx_b, |p, cx| p.open_buffer((worktree_id, "file1"), cx)) + .update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "file1"), cx) + }) .await .unwrap(); let buffer_c = project_c - .update(cx_c, |p, cx| p.open_buffer((worktree_id, "file1"), cx)) + .update(cx_c, |p, cx| { + p.open_buffer_for_path((worktree_id, "file1"), cx) + }) .await .unwrap(); buffer_b.update(cx_b, |buf, cx| buf.edit([0..0], "i-am-b, ", cx)); @@ -1364,7 +1376,9 @@ mod tests { // Open and edit that buffer as the host. let buffer_a = project_a - .update(cx_a, |p, cx| p.open_buffer((worktree_id, "file1"), cx)) + .update(cx_a, |p, cx| { + p.open_buffer_for_path((worktree_id, "file1"), cx) + }) .await .unwrap(); @@ -1514,7 +1528,9 @@ mod tests { // Open a buffer as client B let buffer_b = project_b - .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) + .update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "a.txt"), cx) + }) .await .unwrap(); @@ -1597,7 +1613,9 @@ mod tests { // Open a buffer as client B let buffer_b = project_b - .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) + .update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "a.txt"), cx) + }) .await .unwrap(); buffer_b.read_with(cx_b, |buf, _| { @@ -1677,14 +1695,16 @@ mod tests { // Open a buffer as client A let buffer_a = project_a - .update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) + .update(cx_a, |p, cx| { + p.open_buffer_for_path((worktree_id, "a.txt"), cx) + }) .await .unwrap(); // Start opening the same buffer as client B - let buffer_b = cx_b - .background() - .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))); + let buffer_b = cx_b.background().spawn(project_b.update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "a.txt"), cx) + })); // Edit the buffer as client A while client B is still opening it. cx_b.background().simulate_random_delay().await; @@ -1760,9 +1780,9 @@ mod tests { .await; // Begin opening a buffer as client B, but leave the project before the open completes. - let buffer_b = cx_b - .background() - .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))); + let buffer_b = cx_b.background().spawn(project_b.update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "a.txt"), cx) + })); cx_b.update(|_| drop(project_b)); drop(buffer_b); @@ -1932,7 +1952,7 @@ mod tests { let _ = cx_a .background() .spawn(project_a.update(cx_a, |project, cx| { - project.open_buffer( + project.open_buffer_for_path( ProjectPath { worktree_id, path: Path::new("other.rs").into(), @@ -2053,7 +2073,9 @@ mod tests { // Open the file with the errors on client B. They should be present. let buffer_b = cx_b .background() - .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx))) + .spawn(project_b.update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "a.rs"), cx) + })) .await .unwrap(); @@ -2171,7 +2193,9 @@ mod tests { // Open a file in an editor as the guest. let buffer_b = project_b - .update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx)) + .update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "main.rs"), cx) + }) .await .unwrap(); let (window_b, _) = cx_b.add_window(|_| EmptyView); @@ -2245,7 +2269,9 @@ mod tests { // Open the buffer on the host. let buffer_a = project_a - .update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx)) + .update(cx_a, |p, cx| { + p.open_buffer_for_path((worktree_id, "main.rs"), cx) + }) .await .unwrap(); buffer_a @@ -2369,7 +2395,9 @@ mod tests { let buffer_b = cx_b .background() - .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx))) + .spawn(project_b.update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "a.rs"), cx) + })) .await .unwrap(); @@ -2477,7 +2505,9 @@ mod tests { // Open the file on client B. let buffer_b = cx_b .background() - .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx))) + .spawn(project_b.update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "a.rs"), cx) + })) .await .unwrap(); @@ -2616,7 +2646,9 @@ mod tests { // Open the file on client B. let buffer_b = cx_b .background() - .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "one.rs"), cx))) + .spawn(project_b.update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "one.rs"), cx) + })) .await .unwrap(); @@ -2845,7 +2877,9 @@ mod tests { // Open the file on client B. let buffer_b = cx_b .background() - .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))) + .spawn(project_b.update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "main.rs"), cx) + })) .await .unwrap(); @@ -2992,7 +3026,9 @@ mod tests { // Cause the language server to start. let _buffer = cx_b .background() - .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "one.rs"), cx))) + .spawn(project_b.update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "one.rs"), cx) + })) .await .unwrap(); @@ -3123,7 +3159,9 @@ mod tests { let buffer_b1 = cx_b .background() - .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx))) + .spawn(project_b.update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "a.rs"), cx) + })) .await .unwrap(); @@ -3139,9 +3177,13 @@ mod tests { let buffer_b2; if rng.gen() { definitions = project_b.update(cx_b, |p, cx| p.definition(&buffer_b1, 23, cx)); - buffer_b2 = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "b.rs"), cx)); + buffer_b2 = project_b.update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "b.rs"), cx) + }); } else { - buffer_b2 = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "b.rs"), cx)); + buffer_b2 = project_b.update(cx_b, |p, cx| { + p.open_buffer_for_path((worktree_id, "b.rs"), cx) + }); definitions = project_b.update(cx_b, |p, cx| p.definition(&buffer_b1, 23, cx)); } @@ -4762,7 +4804,7 @@ mod tests { ); let buffer = project .update(&mut cx, |project, cx| { - project.open_buffer(project_path, cx) + project.open_buffer_for_path(project_path, cx) }) .await .unwrap(); @@ -4879,7 +4921,7 @@ mod tests { ); let buffer = project .update(&mut cx, |project, cx| { - project.open_buffer(project_path.clone(), cx) + project.open_buffer_for_path(project_path.clone(), cx) }) .await .unwrap(); diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 7a7b73199e35fa90169ba3b248651c1136410605..73420e213a9337b38b3067842b3b8dff43de82b1 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -258,14 +258,13 @@ impl Pane { if let Some(item) = item.log_err() { pane.update(&mut cx, |pane, cx| { pane.nav_history.borrow_mut().set_mode(mode); - let item = pane.open_item(item, cx); + pane.open_item(item, cx); pane.nav_history .borrow_mut() .set_mode(NavigationMode::Normal); if let Some(data) = entry.data { item.navigate(data, cx); } - item }); } else { workspace @@ -281,34 +280,43 @@ impl Pane { } } - pub fn open_item( + pub(crate) fn open_editor( &mut self, - item_view_to_open: Box, + project_entry_id: ProjectEntryId, cx: &mut ViewContext, + build_editor: impl FnOnce(&mut MutableAppContext) -> Box, ) -> Box { - // Find an existing view for the same project entry. - for (ix, (entry_id, item_view)) in self.item_views.iter().enumerate() { - if *entry_id == item_view_to_open.project_entry_id(cx) { + for (ix, (existing_entry_id, item_view)) in self.item_views.iter().enumerate() { + if *existing_entry_id == Some(project_entry_id) { let item_view = item_view.boxed_clone(); self.activate_item(ix, cx); return item_view; } } - item_view_to_open.set_nav_history(self.nav_history.clone(), cx); - self.add_item_view(item_view_to_open.boxed_clone(), cx); - item_view_to_open + let item_view = build_editor(cx); + self.add_item(Some(project_entry_id), item_view.boxed_clone(), cx); + item_view + } + + pub fn open_item( + &mut self, + item_view_to_open: Box, + cx: &mut ViewContext, + ) { + self.add_item(None, item_view_to_open.boxed_clone(), cx); } - pub fn add_item_view( + pub(crate) fn add_item( &mut self, - mut item_view: Box, + project_entry_id: Option, + mut item: Box, cx: &mut ViewContext, ) { - item_view.added_to_pane(cx); + item.set_nav_history(self.nav_history.clone(), cx); + item.added_to_pane(cx); let item_idx = cmp::min(self.active_item_index + 1, self.item_views.len()); - self.item_views - .insert(item_idx, (item_view.project_entry_id(cx), item_view)); + self.item_views.insert(item_idx, (project_entry_id, item)); self.activate_item(item_idx, cx); cx.notify(); } @@ -323,6 +331,16 @@ impl Pane { .map(|(_, view)| view.clone()) } + pub fn project_entry_id_for_item(&self, item: &dyn ItemViewHandle) -> Option { + self.item_views.iter().find_map(|(entry_id, existing)| { + if existing.id() == item.id() { + *entry_id + } else { + None + } + }) + } + pub fn item_for_entry(&self, entry_id: ProjectEntryId) -> Option> { self.item_views.iter().find_map(|(id, view)| { if *id == Some(entry_id) { diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 9692a8c90030b5d3e0b89456f2b465f9ec436468..d11e773c3fef0b604c7a67cdd29ae8bfc75818c4 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -9,6 +9,7 @@ mod status_bar; use anyhow::{anyhow, Result}; use client::{Authenticate, ChannelList, Client, User, UserStore}; use clock::ReplicaId; +use futures::TryFutureExt; use gpui::{ action, color::Color, @@ -21,7 +22,7 @@ use gpui::{ MutableAppContext, PathPromptOptions, PromptLevel, RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle, }; -use language::LanguageRegistry; +use language::{Buffer, LanguageRegistry}; use log::error; pub use pane::*; pub use pane_group::*; @@ -41,6 +42,15 @@ use std::{ }; use theme::{Theme, ThemeRegistry}; +pub type BuildEditor = Box< + dyn Fn( + usize, + ModelHandle, + ModelHandle, + &mut MutableAppContext, + ) -> Box, +>; + action!(Open, Arc); action!(OpenNew, Arc); action!(OpenPaths, OpenParams); @@ -95,6 +105,16 @@ pub fn init(cx: &mut MutableAppContext) { ]); } +pub fn register_editor_builder(cx: &mut MutableAppContext, build_editor: F) +where + V: ItemView, + F: 'static + Fn(ModelHandle, ModelHandle, &mut ViewContext) -> V, +{ + cx.add_app_state::(Box::new(|window_id, project, model, cx| { + Box::new(cx.add_view(window_id, |cx| build_editor(project, model, cx))) + })); +} + pub struct AppState { pub languages: Arc, pub themes: Arc, @@ -138,7 +158,6 @@ pub trait ItemView: View { fn navigate(&mut self, _: Box, _: &mut ViewContext) {} fn tab_content(&self, style: &theme::Tab, cx: &AppContext) -> ElementBox; fn project_path(&self, cx: &AppContext) -> Option; - fn project_entry_id(&self, cx: &AppContext) -> Option; fn set_nav_history(&mut self, _: ItemNavHistory, _: &mut ViewContext); fn clone_on_split(&self, _: &mut ViewContext) -> Option where @@ -191,7 +210,6 @@ pub trait ItemView: View { pub trait ItemViewHandle: 'static { fn tab_content(&self, style: &theme::Tab, cx: &AppContext) -> ElementBox; fn project_path(&self, cx: &AppContext) -> Option; - fn project_entry_id(&self, cx: &AppContext) -> Option; fn boxed_clone(&self) -> Box; fn set_nav_history(&self, nav_history: Rc>, cx: &mut MutableAppContext); fn clone_on_split(&self, cx: &mut MutableAppContext) -> Option>; @@ -239,10 +257,6 @@ impl ItemViewHandle for ViewHandle { self.read(cx).project_path(cx) } - fn project_entry_id(&self, cx: &AppContext) -> Option { - self.read(cx).project_entry_id(cx) - } - fn boxed_clone(&self) -> Box { Box::new(self.clone()) } @@ -656,6 +670,24 @@ impl Workspace { path: ProjectPath, cx: &mut ViewContext, ) -> Task, Arc>> { + let project_entry = self.project.read(cx).entry_for_path(&path, cx); + + let existing_entry = self + .active_pane() + .update(cx, |pane, cx| pane.activate_project_entry(project_entry)); + + cx.spawn(|this, cx| { + if let Some(existing_entry) = existing_entry { + return Ok(existing_entry); + } + + let load_task = this + .update(&mut cx, |this, cx| { + this.load_project_entry(project_entry, cx) + }) + .await; + }); + let load_task = self.load_path(path, cx); let pane = self.active_pane().clone().downgrade(); cx.as_mut().spawn(|mut cx| async move { @@ -663,7 +695,7 @@ impl Workspace { let pane = pane .upgrade(&cx) .ok_or_else(|| anyhow!("could not upgrade pane reference"))?; - Ok(pane.update(&mut cx, |pane, cx| pane.open_item(item, cx))) + Ok(pane.update(&mut cx, |pane, cx| pane.open_editor(item, cx))) }) } @@ -672,13 +704,23 @@ impl Workspace { path: ProjectPath, cx: &mut ViewContext, ) -> Task>> { - let project_entry = self.project.read(cx).entry_for_path(&path, cx); + if let Some(project_entry) = self.project.read(cx).entry_for_path(&path, cx) { + self.load_project_entry(project_entry, cx) + } else { + Task::ready(Err(anyhow!("no such file {:?}", path))) + } + } - if let Some(existing_item) = project_entry.and_then(|entry| { - self.panes - .iter() - .find_map(|pane| pane.read(cx).item_for_entry(entry)) - }) { + pub fn load_project_entry( + &mut self, + project_entry: ProjectEntryId, + cx: &mut ViewContext, + ) -> Task>> { + if let Some(existing_item) = self + .panes + .iter() + .find_map(|pane| pane.read(cx).item_for_entry(project_entry)) + { return Task::ready(Ok(existing_item)); } @@ -829,37 +871,108 @@ impl Workspace { pane } - pub fn open_item( - &mut self, - item_view: Box, - cx: &mut ViewContext, - ) -> Box { + pub fn open_item(&mut self, item_view: Box, cx: &mut ViewContext) { self.active_pane() .update(cx, |pane, cx| pane.open_item(item_view, cx)) } - pub fn open_item_for_project_entry( + pub fn open_editor( &mut self, project_entry: ProjectEntryId, cx: &mut ViewContext, - build_view: F, - ) -> Box - where - T: ItemView, - F: FnOnce(&mut ViewContext) -> T, - { - if let Some(existing_item) = self - .panes - .iter() - .find_map(|pane| pane.read(cx).item_for_entry(project_entry)) - { - return existing_item.boxed_clone(); - } + ) -> Task, Arc>> { + let pane = self.active_pane().clone(); + let project = self.project().clone(); + let buffer = project.update(cx, |project, cx| { + project.open_buffer_for_entry(project_entry, cx) + }); - let view = Box::new(cx.add_view(build_view)); - self.open_item(view, cx) + cx.spawn(|this, cx| async move { + let buffer = buffer.await?; + let editor = this.update(&mut cx, |this, cx| { + let window_id = cx.window_id(); + pane.update(cx, |pane, cx| { + pane.open_editor(project_entry, cx, |cx| { + cx.app_state::()(window_id, project, buffer, cx) + }) + }) + }); + Ok(editor) + }) } + // pub fn open_path( + // &mut self, + // path: ProjectPath, + // cx: &mut ViewContext, + // ) -> Task, Arc>> { + // let project_entry = self.project.read(cx).entry_for_path(&path, cx); + + // let existing_entry = self + // .active_pane() + // .update(cx, |pane, cx| pane.activate_project_entry(project_entry)); + + // cx.spawn(|this, cx| { + // if let Some(existing_entry) = existing_entry { + // return Ok(existing_entry); + // } + + // let load_task = this + // .update(&mut cx, |this, cx| { + // this.load_project_entry(project_entry, cx) + // }) + // .await; + // }); + + // let load_task = self.load_path(path, cx); + // let pane = self.active_pane().clone().downgrade(); + // cx.as_mut().spawn(|mut cx| async move { + // let item = load_task.await?; + // let pane = pane + // .upgrade(&cx) + // .ok_or_else(|| anyhow!("could not upgrade pane reference"))?; + // Ok(pane.update(&mut cx, |pane, cx| pane.open_editor(item, cx))) + // }) + // } + + // pub fn load_path( + // &mut self, + // path: ProjectPath, + // cx: &mut ViewContext, + // ) -> Task>> { + // if let Some(project_entry) = self.project.read(cx).entry_for_path(&path, cx) { + // self.load_project_entry(project_entry, cx) + // } else { + // Task::ready(Err(anyhow!("no such file {:?}", path))) + // } + // } + + // pub fn load_project_entry( + // &mut self, + // project_entry: ProjectEntryId, + // cx: &mut ViewContext, + // ) -> Task>> { + // if let Some(existing_item) = self + // .panes + // .iter() + // .find_map(|pane| pane.read(cx).item_for_entry(project_entry)) + // { + // return Task::ready(Ok(existing_item)); + // } + + // let project_path = path.clone(); + // let path_openers = self.path_openers.clone(); + // let window_id = cx.window_id(); + // self.project.update(cx, |project, cx| { + // for opener in path_openers.iter() { + // if let Some(task) = opener.open(project, project_path.clone(), window_id, cx) { + // return task; + // } + // } + // Task::ready(Err(anyhow!("no opener found for path {:?}", project_path))) + // }) + // } + pub fn activate_item(&mut self, item: &dyn ItemViewHandle, cx: &mut ViewContext) -> bool { let result = self.panes.iter().find_map(|pane| { if let Some(ix) = pane.read(cx).index_for_item(item) { @@ -930,10 +1043,11 @@ impl Workspace { let new_pane = self.add_pane(cx); self.activate_pane(new_pane.clone(), cx); if let Some(item) = pane.read(cx).active_item() { - let nav_history = new_pane.read(cx).nav_history().clone(); + let project_entry_id = pane.read(cx).project_entry_id_for_item(item.as_ref()); if let Some(clone) = item.clone_on_split(cx.as_mut()) { - clone.set_nav_history(nav_history, cx); - new_pane.update(cx, |new_pane, cx| new_pane.add_item_view(clone, cx)); + new_pane.update(cx, |new_pane, cx| { + new_pane.open_item(project_entry_id, clone, cx); + }); } } self.center.split(&pane, &new_pane, direction).unwrap(); From aced1e2315b8eee5ce2baf2f4769da91f103a647 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 17 Mar 2022 11:29:46 +0100 Subject: [PATCH 05/14] Finish refactoring of how editors are opened --- crates/diagnostics/src/diagnostics.rs | 2 +- crates/editor/src/editor.rs | 41 +++-- crates/editor/src/items.rs | 28 +-- crates/file_finder/src/file_finder.rs | 6 +- crates/gpui/src/app.rs | 6 + crates/search/src/project_search.rs | 4 +- crates/server/src/rpc.rs | 8 +- crates/workspace/src/pane.rs | 16 +- crates/workspace/src/workspace.rs | 236 ++++++-------------------- crates/zed/src/main.rs | 4 +- crates/zed/src/test.rs | 4 +- crates/zed/src/zed.rs | 1 - 12 files changed, 96 insertions(+), 260 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 7c69f85acf86eed7874732129fa01cf16eb19b7a..dbc8fc3e82c87729757d6de2219d8811a5841231 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -144,7 +144,7 @@ impl ProjectDiagnosticsEditor { let diagnostics = cx.add_view(|cx| { ProjectDiagnosticsEditor::new(workspace.project().clone(), workspace_handle, cx) }); - workspace.open_item(Box::new(diagnostics), cx); + workspace.add_item(Box::new(diagnostics), cx); } } diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 39dad90ece4e572800130bf1b24abf59aa0f1bbf..5a5a7cd5e6daf65cfc55c0ce9a5ec5413a964807 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -57,7 +57,7 @@ pub use sum_tree::Bias; use text::rope::TextDimension; use theme::DiagnosticStyle; use util::{post_inc, ResultExt, TryFutureExt}; -use workspace::{settings, ItemNavHistory, PathOpener, Settings, Workspace}; +use workspace::{settings, ItemNavHistory, Settings, Workspace}; const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500); const MAX_LINE_LEN: usize = 1024; @@ -141,8 +141,7 @@ pub enum Direction { Next, } -pub fn init(cx: &mut MutableAppContext, path_openers: &mut Vec>) { - path_openers.push(Box::new(items::BufferOpener)); +pub fn init(cx: &mut MutableAppContext) { cx.add_bindings(vec![ Binding::new("escape", Cancel, Some("Editor")), Binding::new("backspace", Backspace, Some("Editor")), @@ -340,6 +339,11 @@ pub fn init(cx: &mut MutableAppContext, path_openers: &mut Vec ViewHandle { let project = workspace.project().clone(); - if let Some(project_entry) = project::File::from_dyn(buffer.read(cx).file()) + if let Some(item) = project::File::from_dyn(buffer.read(cx).file()) .and_then(|file| file.project_entry_id(cx)) + .and_then(|entry_id| workspace.item_for_entry(entry_id, cx)) + .and_then(|item| item.downcast()) { - return workspace - .open_editor(project_entry, cx) - .downcast::() - .unwrap(); + return item; } let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let editor = cx.add_view(|cx| Editor::for_buffer(multibuffer, Some(project.clone()), cx)); - workspace.open_item(Box::new(editor.clone()), cx); + workspace.add_item(Box::new(editor.clone()), cx); editor } @@ -966,7 +969,7 @@ impl Editor { .log_err() { let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - workspace.open_item( + workspace.add_item( Box::new( cx.add_view(|cx| Editor::for_buffer(multibuffer, Some(project.clone()), cx)), ), @@ -2376,16 +2379,12 @@ impl Editor { workspace.update(&mut cx, |workspace, cx| { let project = workspace.project().clone(); - let editor = workspace.open_item( - Box::new(cx.add_view(|cx| Editor::for_buffer(excerpt_buffer, Some(project), cx))), - cx, - ); - if let Some(editor) = editor.act_as::(cx) { - editor.update(cx, |editor, cx| { - let color = editor.style(cx).highlighted_line_background; - editor.highlight_background::(ranges_to_highlight, color, cx); - }); - } + let editor = cx.add_view(|cx| Editor::for_buffer(excerpt_buffer, Some(project), cx)); + workspace.add_item(Box::new(editor.clone()), cx); + editor.update(cx, |editor, cx| { + let color = editor.style(cx).highlighted_line_background; + editor.highlight_background::(ranges_to_highlight, color, cx); + }); }); Ok(()) @@ -4402,7 +4401,7 @@ impl Editor { let color = editor.style(cx).highlighted_line_background; editor.highlight_background::(ranges_to_highlight, color, cx); }); - workspace.open_item(Box::new(editor), cx); + workspace.add_item(Box::new(editor), cx); }); Ok(()) diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 6fec3d7a1cd967bd658fe5c18af5bd8ecc95436f..8946328b1a3deb18579ce0bd6e6442c07a1c8f75 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -1,8 +1,8 @@ use crate::{Autoscroll, Editor, Event, MultiBuffer, NavigationData, ToOffset, ToPoint as _}; use anyhow::Result; use gpui::{ - elements::*, AppContext, Entity, ModelContext, ModelHandle, RenderContext, Subscription, Task, - View, ViewContext, ViewHandle, WeakModelHandle, + elements::*, AppContext, Entity, ModelHandle, RenderContext, Subscription, Task, View, + ViewContext, ViewHandle, WeakModelHandle, }; use language::{Bias, Buffer, Diagnostic, File as _}; use project::{File, Project, ProjectPath}; @@ -10,9 +10,7 @@ use std::fmt::Write; use std::path::PathBuf; use text::{Point, Selection}; use util::ResultExt; -use workspace::{ItemNavHistory, ItemView, ItemViewHandle, PathOpener, Settings, StatusItemView}; - -pub struct BufferOpener; +use workspace::{ItemNavHistory, ItemView, ItemViewHandle, Settings, StatusItemView}; #[derive(Clone)] pub struct BufferItemHandle(pub ModelHandle); @@ -26,26 +24,6 @@ pub struct MultiBufferItemHandle(pub ModelHandle); #[derive(Clone)] struct WeakMultiBufferItemHandle(WeakModelHandle); -impl PathOpener for BufferOpener { - fn open( - &self, - project: &mut Project, - project_path: ProjectPath, - window_id: usize, - cx: &mut ModelContext, - ) -> Option>>> { - let buffer = project.open_buffer_for_path(project_path, cx); - Some(cx.spawn(|project, mut cx| async move { - let buffer = buffer.await?; - let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - let editor = cx.add_view(window_id, |cx| { - Editor::for_buffer(multibuffer, Some(project), cx) - }); - Ok(Box::new(editor) as Box) - })) - } -} - impl ItemView for Editor { fn navigate(&mut self, data: Box, cx: &mut ViewContext) { if let Some(data) = data.downcast_ref::() { diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 4340cd5a1b7bb30bf05e40c5e0bf6ab1de88a6b5..0dbb336007d4cd0858140c95b212c193798dc077 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -409,14 +409,12 @@ mod tests { #[gpui::test] async fn test_matching_paths(cx: &mut gpui::TestAppContext) { - let mut path_openers = Vec::new(); cx.update(|cx| { super::init(cx); - editor::init(cx, &mut path_openers); + editor::init(cx); }); - let mut params = cx.update(WorkspaceParams::test); - params.path_openers = Arc::from(path_openers); + let params = cx.update(WorkspaceParams::test); params .fs .as_fake() diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index a479e5fba1c56c5e543e125be3f523c7c61acc84..9831c3aa3473ff36c41ace5cdbf63594475a7978 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -3473,6 +3473,12 @@ impl PartialEq> for ViewHandle { } } +impl PartialEq> for WeakViewHandle { + fn eq(&self, other: &ViewHandle) -> bool { + self.window_id == other.window_id && self.view_id == other.view_id + } +} + impl Eq for ViewHandle {} impl Debug for ViewHandle { diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 6208ff4aaa221442d754a539a5c2ab1571664dc6..7644b2f55db1c77cde95421e88ea50d2ec7a5f61 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -391,7 +391,7 @@ impl ProjectSearchView { workspace.activate_item(&existing, cx); } else { let model = cx.add_model(|cx| ProjectSearch::new(workspace.project().clone(), cx)); - workspace.open_item( + workspace.add_item( Box::new(cx.add_view(|cx| ProjectSearchView::new(model, cx))), cx, ); @@ -429,7 +429,7 @@ impl ProjectSearchView { model.search(new_query, cx); model }); - workspace.open_item( + workspace.add_item( Box::new(cx.add_view(|cx| ProjectSearchView::new(model, cx))), cx, ); diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index f891dca71cc12a6d30cfeebba6707a48fda476da..e70957740f72707d3fe6b443dd0cc4ff2e188a15 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -3201,8 +3201,7 @@ mod tests { cx_a.foreground().forbid_parking(); let mut lang_registry = Arc::new(LanguageRegistry::test()); let fs = FakeFs::new(cx_a.background()); - let mut path_openers_b = Vec::new(); - cx_b.update(|cx| editor::init(cx, &mut path_openers_b)); + cx_b.update(|cx| editor::init(cx)); // Set up a fake language server. let (language_server_config, mut fake_language_servers) = LanguageServerConfig::fake(); @@ -3271,7 +3270,6 @@ mod tests { params.client = client_b.client.clone(); params.user_store = client_b.user_store.clone(); params.project = project_b; - params.path_openers = path_openers_b.into(); let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(¶ms, cx)); let editor_b = workspace_b @@ -3437,8 +3435,7 @@ mod tests { cx_a.foreground().forbid_parking(); let mut lang_registry = Arc::new(LanguageRegistry::test()); let fs = FakeFs::new(cx_a.background()); - let mut path_openers_b = Vec::new(); - cx_b.update(|cx| editor::init(cx, &mut path_openers_b)); + cx_b.update(|cx| editor::init(cx)); // Set up a fake language server. let (language_server_config, mut fake_language_servers) = LanguageServerConfig::fake(); @@ -3507,7 +3504,6 @@ mod tests { params.client = client_b.client.clone(); params.user_store = client_b.user_store.clone(); params.project = project_b; - params.path_openers = path_openers_b.into(); let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(¶ms, cx)); let editor_b = workspace_b diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 73420e213a9337b38b3067842b3b8dff43de82b1..e8cbd185f6fdc01581d5eff201085e2e05513f63 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -253,12 +253,12 @@ impl Pane { let pane = pane.downgrade(); let task = workspace.load_path(project_path, cx); cx.spawn(|workspace, mut cx| async move { - let item = task.await; + let task = task.await; if let Some(pane) = pane.upgrade(&cx) { - if let Some(item) = item.log_err() { + if let Some((project_entry_id, build_item)) = task.log_err() { pane.update(&mut cx, |pane, cx| { pane.nav_history.borrow_mut().set_mode(mode); - pane.open_item(item, cx); + let item = pane.open_item(project_entry_id, cx, build_item); pane.nav_history .borrow_mut() .set_mode(NavigationMode::Normal); @@ -280,7 +280,7 @@ impl Pane { } } - pub(crate) fn open_editor( + pub(crate) fn open_item( &mut self, project_entry_id: ProjectEntryId, cx: &mut ViewContext, @@ -299,14 +299,6 @@ impl Pane { item_view } - pub fn open_item( - &mut self, - item_view_to_open: Box, - cx: &mut ViewContext, - ) { - self.add_item(None, item_view_to_open.boxed_clone(), cx); - } - pub(crate) fn add_item( &mut self, project_entry_id: Option, diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index d11e773c3fef0b604c7a67cdd29ae8bfc75818c4..33415e2360bdb281f756cfd6d30effc611b84387 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -9,7 +9,6 @@ mod status_bar; use anyhow::{anyhow, Result}; use client::{Authenticate, ChannelList, Client, User, UserStore}; use clock::ReplicaId; -use futures::TryFutureExt; use gpui::{ action, color::Color, @@ -18,9 +17,9 @@ use gpui::{ json::{self, to_string_pretty, ToJson}, keymap::Binding, platform::{CursorStyle, WindowOptions}, - AnyViewHandle, AppContext, ClipboardItem, Entity, ImageData, ModelContext, ModelHandle, - MutableAppContext, PathPromptOptions, PromptLevel, RenderContext, Task, View, ViewContext, - ViewHandle, WeakViewHandle, + AnyViewHandle, AppContext, ClipboardItem, Entity, ImageData, ModelHandle, MutableAppContext, + PathPromptOptions, PromptLevel, RenderContext, Task, View, ViewContext, ViewHandle, + WeakViewHandle, }; use language::{Buffer, LanguageRegistry}; use log::error; @@ -42,7 +41,7 @@ use std::{ }; use theme::{Theme, ThemeRegistry}; -pub type BuildEditor = Box< +pub type BuildEditor = Arc< dyn Fn( usize, ModelHandle, @@ -110,7 +109,7 @@ where V: ItemView, F: 'static + Fn(ModelHandle, ModelHandle, &mut ViewContext) -> V, { - cx.add_app_state::(Box::new(|window_id, project, model, cx| { + cx.add_app_state::(Arc::new(move |window_id, project, model, cx| { Box::new(cx.add_view(window_id, |cx| build_editor(project, model, cx))) })); } @@ -122,7 +121,6 @@ pub struct AppState { pub user_store: ModelHandle, pub fs: Arc, pub channel_list: ModelHandle, - pub path_openers: Arc<[Box]>, pub build_window_options: &'static dyn Fn() -> WindowOptions<'static>, pub build_workspace: &'static dyn Fn( ModelHandle, @@ -143,16 +141,6 @@ pub struct JoinProjectParams { pub app_state: Arc, } -pub trait PathOpener { - fn open( - &self, - project: &mut Project, - path: ProjectPath, - window_id: usize, - cx: &mut ModelContext, - ) -> Option>>>; -} - pub trait ItemView: View { fn deactivated(&mut self, _: &mut ViewContext) {} fn navigate(&mut self, _: Box, _: &mut ViewContext) {} @@ -378,7 +366,6 @@ pub struct WorkspaceParams { pub languages: Arc, pub user_store: ModelHandle, pub channel_list: ModelHandle, - pub path_openers: Arc<[Box]>, } impl WorkspaceParams { @@ -409,7 +396,6 @@ impl WorkspaceParams { fs, languages, user_store, - path_openers: Arc::from([]), } } @@ -428,7 +414,6 @@ impl WorkspaceParams { languages: app_state.languages.clone(), user_store: app_state.user_store.clone(), channel_list: app_state.channel_list.clone(), - path_openers: app_state.path_openers.clone(), } } } @@ -446,7 +431,6 @@ pub struct Workspace { active_pane: ViewHandle, status_bar: ViewHandle, project: ModelHandle, - path_openers: Arc<[Box]>, // items: BTreeMap, Box>, _observe_current_user: Task<()>, } @@ -510,7 +494,6 @@ impl Workspace { left_sidebar: Sidebar::new(Side::Left), right_sidebar: Sidebar::new(Side::Right), project: params.project.clone(), - path_openers: params.path_openers.clone(), _observe_current_user, } } @@ -665,76 +648,14 @@ impl Workspace { } } - pub fn open_path( - &mut self, - path: ProjectPath, - cx: &mut ViewContext, - ) -> Task, Arc>> { - let project_entry = self.project.read(cx).entry_for_path(&path, cx); - - let existing_entry = self - .active_pane() - .update(cx, |pane, cx| pane.activate_project_entry(project_entry)); - - cx.spawn(|this, cx| { - if let Some(existing_entry) = existing_entry { - return Ok(existing_entry); - } - - let load_task = this - .update(&mut cx, |this, cx| { - this.load_project_entry(project_entry, cx) - }) - .await; - }); - - let load_task = self.load_path(path, cx); - let pane = self.active_pane().clone().downgrade(); - cx.as_mut().spawn(|mut cx| async move { - let item = load_task.await?; - let pane = pane - .upgrade(&cx) - .ok_or_else(|| anyhow!("could not upgrade pane reference"))?; - Ok(pane.update(&mut cx, |pane, cx| pane.open_editor(item, cx))) - }) - } - - pub fn load_path( - &mut self, - path: ProjectPath, - cx: &mut ViewContext, - ) -> Task>> { - if let Some(project_entry) = self.project.read(cx).entry_for_path(&path, cx) { - self.load_project_entry(project_entry, cx) - } else { - Task::ready(Err(anyhow!("no such file {:?}", path))) - } - } - - pub fn load_project_entry( - &mut self, - project_entry: ProjectEntryId, - cx: &mut ViewContext, - ) -> Task>> { - if let Some(existing_item) = self - .panes + pub fn item_for_entry( + &self, + entry_id: ProjectEntryId, + cx: &AppContext, + ) -> Option> { + self.panes() .iter() - .find_map(|pane| pane.read(cx).item_for_entry(project_entry)) - { - return Task::ready(Ok(existing_item)); - } - - let project_path = path.clone(); - let path_openers = self.path_openers.clone(); - let window_id = cx.window_id(); - self.project.update(cx, |project, cx| { - for opener in path_openers.iter() { - if let Some(task) = opener.open(project, project_path.clone(), window_id, cx) { - return task; - } - } - Task::ready(Err(anyhow!("no opener found for path {:?}", project_path))) - }) + .find_map(|pane| pane.read(cx).item_for_entry(entry_id)) } pub fn item_of_type(&self, cx: &AppContext) -> Option> { @@ -871,107 +792,58 @@ impl Workspace { pane } - pub fn open_item(&mut self, item_view: Box, cx: &mut ViewContext) { + pub fn add_item(&mut self, item_view: Box, cx: &mut ViewContext) { self.active_pane() - .update(cx, |pane, cx| pane.open_item(item_view, cx)) + .update(cx, |pane, cx| pane.add_item(None, item_view, cx)) } - pub fn open_editor( + pub fn open_path( &mut self, - project_entry: ProjectEntryId, + path: ProjectPath, cx: &mut ViewContext, ) -> Task, Arc>> { - let pane = self.active_pane().clone(); - let project = self.project().clone(); - let buffer = project.update(cx, |project, cx| { - project.open_buffer_for_entry(project_entry, cx) - }); - - cx.spawn(|this, cx| async move { - let buffer = buffer.await?; - let editor = this.update(&mut cx, |this, cx| { - let window_id = cx.window_id(); + let pane = self.active_pane().downgrade(); + let task = self.load_path(path, cx); + cx.spawn(|this, mut cx| async move { + let (project_entry_id, build_editor) = task.await?; + let pane = pane + .upgrade(&cx) + .ok_or_else(|| anyhow!("pane was closed"))?; + this.update(&mut cx, |_, cx| { pane.update(cx, |pane, cx| { - pane.open_editor(project_entry, cx, |cx| { - cx.app_state::()(window_id, project, buffer, cx) - }) + Ok(pane.open_item(project_entry_id, cx, build_editor)) }) - }); - Ok(editor) + }) }) } - // pub fn open_path( - // &mut self, - // path: ProjectPath, - // cx: &mut ViewContext, - // ) -> Task, Arc>> { - // let project_entry = self.project.read(cx).entry_for_path(&path, cx); - - // let existing_entry = self - // .active_pane() - // .update(cx, |pane, cx| pane.activate_project_entry(project_entry)); - - // cx.spawn(|this, cx| { - // if let Some(existing_entry) = existing_entry { - // return Ok(existing_entry); - // } - - // let load_task = this - // .update(&mut cx, |this, cx| { - // this.load_project_entry(project_entry, cx) - // }) - // .await; - // }); - - // let load_task = self.load_path(path, cx); - // let pane = self.active_pane().clone().downgrade(); - // cx.as_mut().spawn(|mut cx| async move { - // let item = load_task.await?; - // let pane = pane - // .upgrade(&cx) - // .ok_or_else(|| anyhow!("could not upgrade pane reference"))?; - // Ok(pane.update(&mut cx, |pane, cx| pane.open_editor(item, cx))) - // }) - // } - - // pub fn load_path( - // &mut self, - // path: ProjectPath, - // cx: &mut ViewContext, - // ) -> Task>> { - // if let Some(project_entry) = self.project.read(cx).entry_for_path(&path, cx) { - // self.load_project_entry(project_entry, cx) - // } else { - // Task::ready(Err(anyhow!("no such file {:?}", path))) - // } - // } - - // pub fn load_project_entry( - // &mut self, - // project_entry: ProjectEntryId, - // cx: &mut ViewContext, - // ) -> Task>> { - // if let Some(existing_item) = self - // .panes - // .iter() - // .find_map(|pane| pane.read(cx).item_for_entry(project_entry)) - // { - // return Task::ready(Ok(existing_item)); - // } - - // let project_path = path.clone(); - // let path_openers = self.path_openers.clone(); - // let window_id = cx.window_id(); - // self.project.update(cx, |project, cx| { - // for opener in path_openers.iter() { - // if let Some(task) = opener.open(project, project_path.clone(), window_id, cx) { - // return task; - // } - // } - // Task::ready(Err(anyhow!("no opener found for path {:?}", project_path))) - // }) - // } + pub(crate) fn load_path( + &mut self, + path: ProjectPath, + cx: &mut ViewContext, + ) -> Task< + Result<( + ProjectEntryId, + impl 'static + FnOnce(&mut MutableAppContext) -> Box, + )>, + > { + let project = self.project().clone(); + let buffer = project.update(cx, |project, cx| project.open_buffer_for_path(path, cx)); + cx.spawn(|this, mut cx| async move { + let buffer = buffer.await?; + let project_entry_id = buffer.read_with(&cx, |buffer, cx| { + project::File::from_dyn(buffer.file()) + .and_then(|file| file.project_entry_id(cx)) + .ok_or_else(|| anyhow!("buffer has no entry")) + })?; + let (window_id, build_editor) = this.update(&mut cx, |_, cx| { + (cx.window_id(), cx.app_state::().clone()) + }); + let build_editor = + move |cx: &mut MutableAppContext| build_editor(window_id, project, buffer, cx); + Ok((project_entry_id, build_editor)) + }) + } pub fn activate_item(&mut self, item: &dyn ItemViewHandle, cx: &mut ViewContext) -> bool { let result = self.panes.iter().find_map(|pane| { @@ -1046,7 +918,7 @@ impl Workspace { let project_entry_id = pane.read(cx).project_entry_id_for_item(item.as_ref()); if let Some(clone) = item.clone_on_split(cx.as_mut()) { new_pane.update(cx, |new_pane, cx| { - new_pane.open_item(project_entry_id, clone, cx); + new_pane.add_item(project_entry_id, clone, cx); }); } } diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 85960002469249d94503954f4775d4e4e7a23851..190a27973737cbb0ecd2be1eea1633c8bf90c0c3 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -61,7 +61,6 @@ fn main() { app.run(move |cx| { let http = http::client(); let client = client::Client::new(http.clone()); - let mut path_openers = Vec::new(); let mut languages = language::build_language_registry(login_shell_env_loaded); let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http.clone(), cx)); let channel_list = @@ -71,7 +70,7 @@ fn main() { client::Channel::init(&client); client::init(client.clone(), cx); workspace::init(cx); - editor::init(cx, &mut path_openers); + editor::init(cx); go_to_line::init(cx); file_finder::init(cx); chat_panel::init(cx); @@ -120,7 +119,6 @@ fn main() { client, user_store, fs, - path_openers: Arc::from(path_openers), build_window_options: &build_window_options, build_workspace: &build_workspace, }); diff --git a/crates/zed/src/test.rs b/crates/zed/src/test.rs index 35610854f30fd272a8763f6ecc8d016381e12baf..f42e57c35d678570ca9ae559e0318d3b8356920e 100644 --- a/crates/zed/src/test.rs +++ b/crates/zed/src/test.rs @@ -17,8 +17,7 @@ fn init_logger() { pub fn test_app_state(cx: &mut MutableAppContext) -> Arc { let settings = Settings::test(cx); - let mut path_openers = Vec::new(); - editor::init(cx, &mut path_openers); + editor::init(cx); cx.add_app_state(settings); let themes = ThemeRegistry::new(Assets, cx.font_cache().clone()); let http = FakeHttpClient::with_404_response(); @@ -40,7 +39,6 @@ pub fn test_app_state(cx: &mut MutableAppContext) -> Arc { client, user_store, fs: FakeFs::new(cx.background().clone()), - path_openers: Arc::from(path_openers), build_window_options: &build_window_options, build_workspace: &build_workspace, }) diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 20da4e4800b6547b3b6a26096a3a865b7aca08b3..99f02119ce5da060fe45780cd0cb2a97ccff2e9e 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -111,7 +111,6 @@ pub fn build_workspace( languages: app_state.languages.clone(), user_store: app_state.user_store.clone(), channel_list: app_state.channel_list.clone(), - path_openers: app_state.path_openers.clone(), }; let mut workspace = Workspace::new(&workspace_params, cx); let project = workspace.project().clone(); From 0efce8f70a8538b95bd4ea5ad17ecef86c88040c Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 17 Mar 2022 11:32:46 +0100 Subject: [PATCH 06/14] Rename `ItemView` to `Item` --- crates/diagnostics/src/diagnostics.rs | 4 +- crates/diagnostics/src/items.rs | 2 +- crates/editor/src/editor.rs | 6 +- crates/editor/src/items.rs | 8 +- crates/search/src/buffer_search.rs | 4 +- crates/search/src/project_search.rs | 4 +- crates/workspace/src/lsp_status.rs | 4 +- crates/workspace/src/pane.rs | 144 ++++++++++++-------------- crates/workspace/src/status_bar.rs | 8 +- crates/workspace/src/workspace.rs | 63 ++++++----- crates/zed/src/zed.rs | 10 +- 11 files changed, 122 insertions(+), 135 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index dbc8fc3e82c87729757d6de2219d8811a5841231..4eab6984039223c5e7a83df232df4843576e71e4 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -25,7 +25,7 @@ use std::{ sync::Arc, }; use util::TryFutureExt; -use workspace::{ItemNavHistory, ItemViewHandle as _, Settings, Workspace}; +use workspace::{ItemHandle as _, ItemNavHistory, Settings, Workspace}; action!(Deploy); @@ -438,7 +438,7 @@ impl ProjectDiagnosticsEditor { } } -impl workspace::ItemView for ProjectDiagnosticsEditor { +impl workspace::Item for ProjectDiagnosticsEditor { fn tab_content(&self, style: &theme::Tab, cx: &AppContext) -> ElementBox { render_summary( &self.summary, diff --git a/crates/diagnostics/src/items.rs b/crates/diagnostics/src/items.rs index 13d90f01190ea0eeddf14585193f22097988b326..1b4d2a8147818a07ef5b9c2a2255a934dee44d1f 100644 --- a/crates/diagnostics/src/items.rs +++ b/crates/diagnostics/src/items.rs @@ -71,7 +71,7 @@ impl View for DiagnosticSummary { impl StatusItemView for DiagnosticSummary { fn set_active_pane_item( &mut self, - _: Option<&dyn workspace::ItemViewHandle>, + _: Option<&dyn workspace::ItemHandle>, _: &mut ViewContext, ) { } diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 5a5a7cd5e6daf65cfc55c0ce9a5ec5413a964807..56734dd3001a66fd74af9f0a342edef464b151a7 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -6264,7 +6264,7 @@ mod tests { #[gpui::test] fn test_navigation_history(cx: &mut gpui::MutableAppContext) { populate_settings(cx); - use workspace::ItemView; + use workspace::Item; let nav_history = Rc::new(RefCell::new(workspace::NavHistory::default())); let buffer = MultiBuffer::build_simple(&sample_text(30, 5, 'a'), cx); @@ -6283,7 +6283,7 @@ mod tests { editor.select_display_ranges(&[DisplayPoint::new(13, 0)..DisplayPoint::new(13, 3)], cx); let nav_entry = nav_history.borrow_mut().pop_backward().unwrap(); editor.navigate(nav_entry.data.unwrap(), cx); - assert_eq!(nav_entry.item_view.id(), cx.view_id()); + assert_eq!(nav_entry.item.id(), cx.view_id()); assert_eq!( editor.selected_display_ranges(cx), &[DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0)] @@ -6309,7 +6309,7 @@ mod tests { ); let nav_entry = nav_history.borrow_mut().pop_backward().unwrap(); editor.navigate(nav_entry.data.unwrap(), cx); - assert_eq!(nav_entry.item_view.id(), cx.view_id()); + assert_eq!(nav_entry.item.id(), cx.view_id()); assert_eq!( editor.selected_display_ranges(cx), &[DisplayPoint::new(5, 0)..DisplayPoint::new(5, 0)] diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 8946328b1a3deb18579ce0bd6e6442c07a1c8f75..9c69078dc34b45934e52f9022cbee08a697c28ed 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -10,7 +10,7 @@ use std::fmt::Write; use std::path::PathBuf; use text::{Point, Selection}; use util::ResultExt; -use workspace::{ItemNavHistory, ItemView, ItemViewHandle, Settings, StatusItemView}; +use workspace::{Item, ItemHandle, ItemNavHistory, Settings, StatusItemView}; #[derive(Clone)] pub struct BufferItemHandle(pub ModelHandle); @@ -24,7 +24,7 @@ pub struct MultiBufferItemHandle(pub ModelHandle); #[derive(Clone)] struct WeakMultiBufferItemHandle(WeakModelHandle); -impl ItemView for Editor { +impl Item for Editor { fn navigate(&mut self, data: Box, cx: &mut ViewContext) { if let Some(data) = data.downcast_ref::() { let buffer = self.buffer.read(cx).read(cx); @@ -206,7 +206,7 @@ impl View for CursorPosition { impl StatusItemView for CursorPosition { fn set_active_pane_item( &mut self, - active_pane_item: Option<&dyn ItemViewHandle>, + active_pane_item: Option<&dyn ItemHandle>, cx: &mut ViewContext, ) { if let Some(editor) = active_pane_item.and_then(|item| item.downcast::()) { @@ -279,7 +279,7 @@ impl View for DiagnosticMessage { impl StatusItemView for DiagnosticMessage { fn set_active_pane_item( &mut self, - active_pane_item: Option<&dyn ItemViewHandle>, + active_pane_item: Option<&dyn ItemHandle>, cx: &mut ViewContext, ) { if let Some(editor) = active_pane_item.and_then(|item| item.downcast::()) { diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index 24b438c7e465deef2ff6963fa1faa56af790a6dd..41b3d188bbd0e82d130796ffb319bd9ffe790376 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -8,7 +8,7 @@ use gpui::{ use language::OffsetRangeExt; use project::search::SearchQuery; use std::ops::Range; -use workspace::{ItemViewHandle, Pane, Settings, Toolbar, Workspace}; +use workspace::{ItemHandle, Pane, Settings, Toolbar, Workspace}; action!(Deploy, bool); action!(Dismiss); @@ -126,7 +126,7 @@ impl View for SearchBar { impl Toolbar for SearchBar { fn active_item_changed( &mut self, - item: Option>, + item: Option>, cx: &mut ViewContext, ) -> bool { self.active_editor_subscription.take(); diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 7644b2f55db1c77cde95421e88ea50d2ec7a5f61..acf7b2a23405201e94a06a976716649947af89e8 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -16,7 +16,7 @@ use std::{ path::PathBuf, }; use util::ResultExt as _; -use workspace::{ItemNavHistory, ItemView, Settings, Workspace}; +use workspace::{Item, ItemNavHistory, Settings, Workspace}; action!(Deploy); action!(Search); @@ -197,7 +197,7 @@ impl View for ProjectSearchView { } } -impl ItemView for ProjectSearchView { +impl Item for ProjectSearchView { fn act_as_type( &self, type_id: TypeId, diff --git a/crates/workspace/src/lsp_status.rs b/crates/workspace/src/lsp_status.rs index db160ab06fed41d4974d7fd83721f58acb415a19..1b8b89f6910c486e2d606a2a30e53a718e31f971 100644 --- a/crates/workspace/src/lsp_status.rs +++ b/crates/workspace/src/lsp_status.rs @@ -1,4 +1,4 @@ -use crate::{ItemViewHandle, Settings, StatusItemView}; +use crate::{ItemHandle, Settings, StatusItemView}; use futures::StreamExt; use gpui::AppContext; use gpui::{ @@ -187,5 +187,5 @@ impl View for LspStatus { } impl StatusItemView for LspStatus { - fn set_active_pane_item(&mut self, _: Option<&dyn ItemViewHandle>, _: &mut ViewContext) {} + fn set_active_pane_item(&mut self, _: Option<&dyn ItemHandle>, _: &mut ViewContext) {} } diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index e8cbd185f6fdc01581d5eff201085e2e05513f63..552d102729580f04637e00da9167aef1ed62c4bd 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1,5 +1,5 @@ -use super::{ItemViewHandle, SplitDirection}; -use crate::{ItemView, Settings, WeakItemViewHandle, Workspace}; +use super::{ItemHandle, SplitDirection}; +use crate::{Item, Settings, WeakItemHandle, Workspace}; use collections::{HashMap, VecDeque}; use gpui::{ action, @@ -97,7 +97,7 @@ pub enum Event { } pub struct Pane { - item_views: Vec<(Option, Box)>, + items: Vec<(Option, Box)>, active_item_index: usize, nav_history: Rc>, toolbars: HashMap>, @@ -108,7 +108,7 @@ pub struct Pane { pub trait Toolbar: View { fn active_item_changed( &mut self, - item: Option>, + item: Option>, cx: &mut ViewContext, ) -> bool; fn on_dismiss(&mut self, cx: &mut ViewContext); @@ -117,7 +117,7 @@ pub trait Toolbar: View { trait ToolbarHandle { fn active_item_changed( &self, - item: Option>, + item: Option>, cx: &mut MutableAppContext, ) -> bool; fn on_dismiss(&self, cx: &mut MutableAppContext); @@ -126,7 +126,7 @@ trait ToolbarHandle { pub struct ItemNavHistory { history: Rc>, - item_view: Rc, + item: Rc, } #[derive(Default)] @@ -152,14 +152,14 @@ impl Default for NavigationMode { } pub struct NavigationEntry { - pub item_view: Rc, + pub item: Rc, pub data: Option>, } impl Pane { pub fn new() -> Self { Self { - item_views: Vec::new(), + items: Vec::new(), active_item_index: 0, nav_history: Default::default(), toolbars: Default::default(), @@ -216,13 +216,13 @@ impl Pane { // If the item is still present in this pane, then activate it. if let Some(index) = entry - .item_view + .item .upgrade(cx) - .and_then(|v| pane.index_for_item_view(v.as_ref())) + .and_then(|v| pane.index_for_item(v.as_ref())) { - if let Some(item_view) = pane.active_item() { + if let Some(item) = pane.active_item() { pane.nav_history.borrow_mut().set_mode(mode); - item_view.deactivated(cx); + item.deactivated(cx); pane.nav_history .borrow_mut() .set_mode(NavigationMode::Normal); @@ -242,7 +242,7 @@ impl Pane { pane.nav_history .borrow_mut() .paths_by_item - .get(&entry.item_view.id()) + .get(&entry.item.id()) .cloned() .map(|project_path| (project_path, entry)) } @@ -284,47 +284,47 @@ impl Pane { &mut self, project_entry_id: ProjectEntryId, cx: &mut ViewContext, - build_editor: impl FnOnce(&mut MutableAppContext) -> Box, - ) -> Box { - for (ix, (existing_entry_id, item_view)) in self.item_views.iter().enumerate() { + build_editor: impl FnOnce(&mut MutableAppContext) -> Box, + ) -> Box { + for (ix, (existing_entry_id, item)) in self.items.iter().enumerate() { if *existing_entry_id == Some(project_entry_id) { - let item_view = item_view.boxed_clone(); + let item = item.boxed_clone(); self.activate_item(ix, cx); - return item_view; + return item; } } - let item_view = build_editor(cx); - self.add_item(Some(project_entry_id), item_view.boxed_clone(), cx); - item_view + let item = build_editor(cx); + self.add_item(Some(project_entry_id), item.boxed_clone(), cx); + item } pub(crate) fn add_item( &mut self, project_entry_id: Option, - mut item: Box, + mut item: Box, cx: &mut ViewContext, ) { item.set_nav_history(self.nav_history.clone(), cx); item.added_to_pane(cx); - let item_idx = cmp::min(self.active_item_index + 1, self.item_views.len()); - self.item_views.insert(item_idx, (project_entry_id, item)); + let item_idx = cmp::min(self.active_item_index + 1, self.items.len()); + self.items.insert(item_idx, (project_entry_id, item)); self.activate_item(item_idx, cx); cx.notify(); } - pub fn item_views(&self) -> impl Iterator> { - self.item_views.iter().map(|(_, view)| view) + pub fn items(&self) -> impl Iterator> { + self.items.iter().map(|(_, view)| view) } - pub fn active_item(&self) -> Option> { - self.item_views + pub fn active_item(&self) -> Option> { + self.items .get(self.active_item_index) .map(|(_, view)| view.clone()) } - pub fn project_entry_id_for_item(&self, item: &dyn ItemViewHandle) -> Option { - self.item_views.iter().find_map(|(entry_id, existing)| { + pub fn project_entry_id_for_item(&self, item: &dyn ItemHandle) -> Option { + self.items.iter().find_map(|(entry_id, existing)| { if existing.id() == item.id() { *entry_id } else { @@ -333,8 +333,8 @@ impl Pane { }) } - pub fn item_for_entry(&self, entry_id: ProjectEntryId) -> Option> { - self.item_views.iter().find_map(|(id, view)| { + pub fn item_for_entry(&self, entry_id: ProjectEntryId) -> Option> { + self.items.iter().find_map(|(id, view)| { if *id == Some(entry_id) { Some(view.boxed_clone()) } else { @@ -343,25 +343,17 @@ impl Pane { }) } - pub fn index_for_item_view(&self, item_view: &dyn ItemViewHandle) -> Option { - self.item_views - .iter() - .position(|(_, i)| i.id() == item_view.id()) - } - - pub fn index_for_item(&self, item: &dyn ItemViewHandle) -> Option { - self.item_views - .iter() - .position(|(_, my_item)| my_item.id() == item.id()) + pub fn index_for_item(&self, item: &dyn ItemHandle) -> Option { + self.items.iter().position(|(_, i)| i.id() == item.id()) } pub fn activate_item(&mut self, index: usize, cx: &mut ViewContext) { - if index < self.item_views.len() { + if index < self.items.len() { let prev_active_item_ix = mem::replace(&mut self.active_item_index, index); if prev_active_item_ix != self.active_item_index - && prev_active_item_ix < self.item_views.len() + && prev_active_item_ix < self.items.len() { - self.item_views[prev_active_item_ix].1.deactivated(cx); + self.items[prev_active_item_ix].1.deactivated(cx); } self.update_active_toolbar(cx); self.focus_active_item(cx); @@ -374,15 +366,15 @@ impl Pane { let mut index = self.active_item_index; if index > 0 { index -= 1; - } else if self.item_views.len() > 0 { - index = self.item_views.len() - 1; + } else if self.items.len() > 0 { + index = self.items.len() - 1; } self.activate_item(index, cx); } pub fn activate_next_item(&mut self, cx: &mut ViewContext) { let mut index = self.active_item_index; - if index + 1 < self.item_views.len() { + if index + 1 < self.items.len() { index += 1; } else { index = 0; @@ -391,14 +383,14 @@ impl Pane { } pub fn close_active_item(&mut self, cx: &mut ViewContext) { - if !self.item_views.is_empty() { - self.close_item(self.item_views[self.active_item_index].1.id(), cx) + if !self.items.is_empty() { + self.close_item(self.items[self.active_item_index].1.id(), cx) } } pub fn close_inactive_items(&mut self, cx: &mut ViewContext) { - if !self.item_views.is_empty() { - let active_item_id = self.item_views[self.active_item_index].1.id(); + if !self.items.is_empty() { + let active_item_id = self.items[self.active_item_index].1.id(); self.close_items(cx, |id| id != active_item_id); } } @@ -414,10 +406,10 @@ impl Pane { ) { let mut item_ix = 0; let mut new_active_item_index = self.active_item_index; - self.item_views.retain(|(_, item_view)| { - if should_close(item_view.id()) { + self.items.retain(|(_, item)| { + if should_close(item.id()) { if item_ix == self.active_item_index { - item_view.deactivated(cx); + item.deactivated(cx); } if item_ix < self.active_item_index { @@ -425,10 +417,10 @@ impl Pane { } let mut nav_history = self.nav_history.borrow_mut(); - if let Some(path) = item_view.project_path(cx) { - nav_history.paths_by_item.insert(item_view.id(), path); + if let Some(path) = item.project_path(cx) { + nav_history.paths_by_item.insert(item.id(), path); } else { - nav_history.paths_by_item.remove(&item_view.id()); + nav_history.paths_by_item.remove(&item.id()); } item_ix += 1; @@ -439,10 +431,10 @@ impl Pane { } }); - if self.item_views.is_empty() { + if self.items.is_empty() { cx.emit(Event::Remove); } else { - self.active_item_index = cmp::min(new_active_item_index, self.item_views.len() - 1); + self.active_item_index = cmp::min(new_active_item_index, self.items.len() - 1); self.focus_active_item(cx); self.activate(cx); } @@ -511,7 +503,7 @@ impl Pane { } fn update_active_toolbar(&mut self, cx: &mut ViewContext) { - let active_item = self.item_views.get(self.active_item_index); + let active_item = self.items.get(self.active_item_index); for (toolbar_type_id, toolbar) in &self.toolbars { let visible = toolbar.active_item_changed(active_item.map(|i| i.1.clone()), cx); if Some(*toolbar_type_id) == self.active_toolbar_type { @@ -526,7 +518,7 @@ impl Pane { enum Tabs {} let tabs = MouseEventHandler::new::(0, cx, |mouse_state, cx| { let mut row = Flex::row(); - for (ix, (_, item_view)) in self.item_views.iter().enumerate() { + for (ix, (_, item)) in self.items.iter().enumerate() { let is_active = ix == self.active_item_index; row.add_child({ @@ -535,7 +527,7 @@ impl Pane { } else { theme.workspace.tab.clone() }; - let title = item_view.tab_content(&tab_style, cx); + let title = item.tab_content(&tab_style, cx); let mut style = if is_active { theme.workspace.active_tab.clone() @@ -552,9 +544,9 @@ impl Pane { .with_child( Align::new({ let diameter = 7.0; - let icon_color = if item_view.has_conflict(cx) { + let icon_color = if item.has_conflict(cx) { Some(style.icon_conflict) - } else if item_view.is_dirty(cx) { + } else if item.is_dirty(cx) { Some(style.icon_dirty) } else { None @@ -598,7 +590,7 @@ impl Pane { .with_child( Align::new( ConstrainedBox::new(if mouse_state.hovered { - let item_id = item_view.id(); + let item_id = item.id(); enum TabCloseButton {} let icon = Svg::new("icons/x.svg"); MouseEventHandler::new::( @@ -702,7 +694,7 @@ impl View for Pane { impl ToolbarHandle for ViewHandle { fn active_item_changed( &self, - item: Option>, + item: Option>, cx: &mut MutableAppContext, ) -> bool { self.update(cx, |this, cx| this.active_item_changed(item, cx)) @@ -718,10 +710,10 @@ impl ToolbarHandle for ViewHandle { } impl ItemNavHistory { - pub fn new(history: Rc>, item_view: &ViewHandle) -> Self { + pub fn new(history: Rc>, item: &ViewHandle) -> Self { Self { history, - item_view: Rc::new(item_view.downgrade()), + item: Rc::new(item.downgrade()), } } @@ -730,7 +722,7 @@ impl ItemNavHistory { } pub fn push(&self, data: Option) { - self.history.borrow_mut().push(data, self.item_view.clone()); + self.history.borrow_mut().push(data, self.item.clone()); } } @@ -763,11 +755,7 @@ impl NavHistory { self.mode = mode; } - pub fn push( - &mut self, - data: Option, - item_view: Rc, - ) { + pub fn push(&mut self, data: Option, item: Rc) { match self.mode { NavigationMode::Disabled => {} NavigationMode::Normal => { @@ -775,7 +763,7 @@ impl NavHistory { self.backward_stack.pop_front(); } self.backward_stack.push_back(NavigationEntry { - item_view, + item, data: data.map(|data| Box::new(data) as Box), }); self.forward_stack.clear(); @@ -785,7 +773,7 @@ impl NavHistory { self.forward_stack.pop_front(); } self.forward_stack.push_back(NavigationEntry { - item_view, + item, data: data.map(|data| Box::new(data) as Box), }); } @@ -794,7 +782,7 @@ impl NavHistory { self.backward_stack.pop_front(); } self.backward_stack.push_back(NavigationEntry { - item_view, + item, data: data.map(|data| Box::new(data) as Box), }); } diff --git a/crates/workspace/src/status_bar.rs b/crates/workspace/src/status_bar.rs index c387fbe07064ccc136e839f4d8c07a57b1962d84..782e51c706535fbe260f7e827d687449665cdf8f 100644 --- a/crates/workspace/src/status_bar.rs +++ b/crates/workspace/src/status_bar.rs @@ -1,4 +1,4 @@ -use crate::{ItemViewHandle, Pane, Settings}; +use crate::{ItemHandle, Pane, Settings}; use gpui::{ elements::*, AnyViewHandle, ElementBox, Entity, MutableAppContext, RenderContext, Subscription, View, ViewContext, ViewHandle, @@ -7,7 +7,7 @@ use gpui::{ pub trait StatusItemView: View { fn set_active_pane_item( &mut self, - active_pane_item: Option<&dyn crate::ItemViewHandle>, + active_pane_item: Option<&dyn crate::ItemHandle>, cx: &mut ViewContext, ); } @@ -16,7 +16,7 @@ trait StatusItemViewHandle { fn to_any(&self) -> AnyViewHandle; fn set_active_pane_item( &self, - active_pane_item: Option<&dyn ItemViewHandle>, + active_pane_item: Option<&dyn ItemHandle>, cx: &mut MutableAppContext, ); } @@ -114,7 +114,7 @@ impl StatusItemViewHandle for ViewHandle { fn set_active_pane_item( &self, - active_pane_item: Option<&dyn ItemViewHandle>, + active_pane_item: Option<&dyn ItemHandle>, cx: &mut MutableAppContext, ) { self.update(cx, |this, cx| { diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 33415e2360bdb281f756cfd6d30effc611b84387..4dac4d22547df0a526cf36b837bd84ea8d61beac 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -47,7 +47,7 @@ pub type BuildEditor = Arc< ModelHandle, ModelHandle, &mut MutableAppContext, - ) -> Box, + ) -> Box, >; action!(Open, Arc); @@ -106,7 +106,7 @@ pub fn init(cx: &mut MutableAppContext) { pub fn register_editor_builder(cx: &mut MutableAppContext, build_editor: F) where - V: ItemView, + V: Item, F: 'static + Fn(ModelHandle, ModelHandle, &mut ViewContext) -> V, { cx.add_app_state::(Arc::new(move |window_id, project, model, cx| { @@ -141,7 +141,7 @@ pub struct JoinProjectParams { pub app_state: Arc, } -pub trait ItemView: View { +pub trait Item: View { fn deactivated(&mut self, _: &mut ViewContext) {} fn navigate(&mut self, _: Box, _: &mut ViewContext) {} fn tab_content(&self, style: &theme::Tab, cx: &AppContext) -> ElementBox; @@ -195,12 +195,12 @@ pub trait ItemView: View { } } -pub trait ItemViewHandle: 'static { +pub trait ItemHandle: 'static { fn tab_content(&self, style: &theme::Tab, cx: &AppContext) -> ElementBox; fn project_path(&self, cx: &AppContext) -> Option; - fn boxed_clone(&self) -> Box; + fn boxed_clone(&self) -> Box; fn set_nav_history(&self, nav_history: Rc>, cx: &mut MutableAppContext); - fn clone_on_split(&self, cx: &mut MutableAppContext) -> Option>; + fn clone_on_split(&self, cx: &mut MutableAppContext) -> Option>; fn added_to_pane(&mut self, cx: &mut ViewContext); fn deactivated(&self, cx: &mut MutableAppContext); fn navigate(&self, data: Box, cx: &mut MutableAppContext); @@ -220,12 +220,12 @@ pub trait ItemViewHandle: 'static { fn act_as_type(&self, type_id: TypeId, cx: &AppContext) -> Option; } -pub trait WeakItemViewHandle { +pub trait WeakItemHandle { fn id(&self) -> usize; - fn upgrade(&self, cx: &AppContext) -> Option>; + fn upgrade(&self, cx: &AppContext) -> Option>; } -impl dyn ItemViewHandle { +impl dyn ItemHandle { pub fn downcast(&self) -> Option> { self.to_any().downcast() } @@ -236,7 +236,7 @@ impl dyn ItemViewHandle { } } -impl ItemViewHandle for ViewHandle { +impl ItemHandle for ViewHandle { fn tab_content(&self, style: &theme::Tab, cx: &AppContext) -> ElementBox { self.read(cx).tab_content(style, cx) } @@ -245,7 +245,7 @@ impl ItemViewHandle for ViewHandle { self.read(cx).project_path(cx) } - fn boxed_clone(&self) -> Box { + fn boxed_clone(&self) -> Box { Box::new(self.clone()) } @@ -253,11 +253,11 @@ impl ItemViewHandle for ViewHandle { &self, // nav_history: Rc>, cx: &mut MutableAppContext, - ) -> Option> { + ) -> Option> { self.update(cx, |item, cx| { cx.add_option_view(|cx| item.clone_on_split(cx)) }) - .map(|handle| Box::new(handle) as Box) + .map(|handle| Box::new(handle) as Box) } fn set_nav_history(&self, nav_history: Rc>, cx: &mut MutableAppContext) { @@ -273,7 +273,7 @@ impl ItemViewHandle for ViewHandle { return; } if T::should_activate_item_on_event(event) { - if let Some(ix) = pane.index_for_item_view(&item) { + if let Some(ix) = pane.index_for_item(&item) { pane.activate_item(ix, cx); pane.activate(cx); } @@ -335,26 +335,25 @@ impl ItemViewHandle for ViewHandle { } } -impl Into for Box { +impl Into for Box { fn into(self) -> AnyViewHandle { self.to_any() } } -impl Clone for Box { - fn clone(&self) -> Box { +impl Clone for Box { + fn clone(&self) -> Box { self.boxed_clone() } } -impl WeakItemViewHandle for WeakViewHandle { +impl WeakItemHandle for WeakViewHandle { fn id(&self) -> usize { self.id() } - fn upgrade(&self, cx: &AppContext) -> Option> { - self.upgrade(cx) - .map(|v| Box::new(v) as Box) + fn upgrade(&self, cx: &AppContext) -> Option> { + self.upgrade(cx).map(|v| Box::new(v) as Box) } } @@ -556,7 +555,7 @@ impl Workspace { &mut self, abs_paths: &[PathBuf], cx: &mut ViewContext, - ) -> Task, Arc>>>> { + ) -> Task, Arc>>>> { let entries = abs_paths .iter() .cloned() @@ -652,28 +651,28 @@ impl Workspace { &self, entry_id: ProjectEntryId, cx: &AppContext, - ) -> Option> { + ) -> Option> { self.panes() .iter() .find_map(|pane| pane.read(cx).item_for_entry(entry_id)) } - pub fn item_of_type(&self, cx: &AppContext) -> Option> { + pub fn item_of_type(&self, cx: &AppContext) -> Option> { self.items_of_type(cx).max_by_key(|item| item.id()) } - pub fn items_of_type<'a, T: ItemView>( + pub fn items_of_type<'a, T: Item>( &'a self, cx: &'a AppContext, ) -> impl 'a + Iterator> { self.panes.iter().flat_map(|pane| { pane.read(cx) - .item_views() + .items() .filter_map(|item| item.to_any().downcast()) }) } - pub fn active_item(&self, cx: &AppContext) -> Option> { + pub fn active_item(&self, cx: &AppContext) -> Option> { self.active_pane().read(cx).active_item() } @@ -792,16 +791,16 @@ impl Workspace { pane } - pub fn add_item(&mut self, item_view: Box, cx: &mut ViewContext) { + pub fn add_item(&mut self, item: Box, cx: &mut ViewContext) { self.active_pane() - .update(cx, |pane, cx| pane.add_item(None, item_view, cx)) + .update(cx, |pane, cx| pane.add_item(None, item, cx)) } pub fn open_path( &mut self, path: ProjectPath, cx: &mut ViewContext, - ) -> Task, Arc>> { + ) -> Task, Arc>> { let pane = self.active_pane().downgrade(); let task = self.load_path(path, cx); cx.spawn(|this, mut cx| async move { @@ -824,7 +823,7 @@ impl Workspace { ) -> Task< Result<( ProjectEntryId, - impl 'static + FnOnce(&mut MutableAppContext) -> Box, + impl 'static + FnOnce(&mut MutableAppContext) -> Box, )>, > { let project = self.project().clone(); @@ -845,7 +844,7 @@ impl Workspace { }) } - pub fn activate_item(&mut self, item: &dyn ItemViewHandle, cx: &mut ViewContext) -> bool { + pub fn activate_item(&mut self, item: &dyn ItemHandle, cx: &mut ViewContext) -> bool { let result = self.panes.iter().find_map(|pane| { if let Some(ix) = pane.read(cx).index_for_item(item) { Some((pane.clone(), ix)) diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 99f02119ce5da060fe45780cd0cb2a97ccff2e9e..26b4150e240d9e182bc90a18dcf09a3fe38402f0 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -192,7 +192,7 @@ mod tests { use theme::{Theme, ThemeRegistry, DEFAULT_THEME_NAME}; use util::test::temp_tree; use workspace::{ - open_paths, pane, ItemView, ItemViewHandle, OpenNew, Pane, SplitDirection, WorkspaceHandle, + open_paths, pane, Item, ItemHandle, OpenNew, Pane, SplitDirection, WorkspaceHandle, }; #[gpui::test] @@ -324,7 +324,7 @@ mod tests { pane.active_item().unwrap().project_path(cx), Some(file1.clone()) ); - assert_eq!(pane.item_views().count(), 1); + assert_eq!(pane.items().count(), 1); }); // Open the second entry @@ -338,7 +338,7 @@ mod tests { pane.active_item().unwrap().project_path(cx), Some(file2.clone()) ); - assert_eq!(pane.item_views().count(), 2); + assert_eq!(pane.items().count(), 2); }); // Open the first entry again. The existing pane item is activated. @@ -354,7 +354,7 @@ mod tests { pane.active_item().unwrap().project_path(cx), Some(file1.clone()) ); - assert_eq!(pane.item_views().count(), 2); + assert_eq!(pane.items().count(), 2); }); // Split the pane with the first entry, then open the second entry again. @@ -393,7 +393,7 @@ mod tests { Some(file3.clone()) ); let pane_entries = pane - .item_views() + .items() .map(|i| i.project_path(cx).unwrap()) .collect::>(); assert_eq!(pane_entries, &[file1, file2, file3]); From a691c2fbdb01d6c9f70513c40a59d75b262f05f4 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 17 Mar 2022 11:33:58 +0100 Subject: [PATCH 07/14] Delete unused code --- crates/editor/src/items.rs | 18 +++--------------- crates/workspace/src/workspace.rs | 1 - 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 9c69078dc34b45934e52f9022cbee08a697c28ed..d4e779484b2436507b3379031a3a96485c5b6d07 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -1,10 +1,10 @@ -use crate::{Autoscroll, Editor, Event, MultiBuffer, NavigationData, ToOffset, ToPoint as _}; +use crate::{Autoscroll, Editor, Event, NavigationData, ToOffset, ToPoint as _}; use anyhow::Result; use gpui::{ elements::*, AppContext, Entity, ModelHandle, RenderContext, Subscription, Task, View, - ViewContext, ViewHandle, WeakModelHandle, + ViewContext, ViewHandle, }; -use language::{Bias, Buffer, Diagnostic, File as _}; +use language::{Bias, Diagnostic, File as _}; use project::{File, Project, ProjectPath}; use std::fmt::Write; use std::path::PathBuf; @@ -12,18 +12,6 @@ use text::{Point, Selection}; use util::ResultExt; use workspace::{Item, ItemHandle, ItemNavHistory, Settings, StatusItemView}; -#[derive(Clone)] -pub struct BufferItemHandle(pub ModelHandle); - -#[derive(Clone)] -struct WeakBufferItemHandle(WeakModelHandle); - -#[derive(Clone)] -pub struct MultiBufferItemHandle(pub ModelHandle); - -#[derive(Clone)] -struct WeakMultiBufferItemHandle(WeakModelHandle); - impl Item for Editor { fn navigate(&mut self, data: Box, cx: &mut ViewContext) { if let Some(data) = data.downcast_ref::() { diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 4dac4d22547df0a526cf36b837bd84ea8d61beac..e34cf1bff64d6c6ecbf5321b4c308ecd26a37543 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -430,7 +430,6 @@ pub struct Workspace { active_pane: ViewHandle, status_bar: ViewHandle, project: ModelHandle, - // items: BTreeMap, Box>, _observe_current_user: Task<()>, } From e6755f4115e67a63ab3430f268e6b065c226c4f2 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 17 Mar 2022 11:39:39 +0100 Subject: [PATCH 08/14] Search only in active pane when using `Editor::find_or_create` --- crates/editor/src/editor.rs | 3 ++- crates/workspace/src/workspace.rs | 10 ---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 56734dd3001a66fd74af9f0a342edef464b151a7..131b16e8b7cd3a0c6f9759549592110e806aa112 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -848,9 +848,10 @@ impl Editor { if let Some(item) = project::File::from_dyn(buffer.read(cx).file()) .and_then(|file| file.project_entry_id(cx)) - .and_then(|entry_id| workspace.item_for_entry(entry_id, cx)) + .and_then(|entry_id| workspace.active_pane().read(cx).item_for_entry(entry_id)) .and_then(|item| item.downcast()) { + workspace.activate_item(&item, cx); return item; } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index e34cf1bff64d6c6ecbf5321b4c308ecd26a37543..e10073c04aef840fa52d338f4f335af0b1b4c26f 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -646,16 +646,6 @@ impl Workspace { } } - pub fn item_for_entry( - &self, - entry_id: ProjectEntryId, - cx: &AppContext, - ) -> Option> { - self.panes() - .iter() - .find_map(|pane| pane.read(cx).item_for_entry(entry_id)) - } - pub fn item_of_type(&self, cx: &AppContext) -> Option> { self.items_of_type(cx).max_by_key(|item| item.id()) } From 6446660c88327c27286fc12688994cac2da90f06 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 17 Mar 2022 11:42:13 +0100 Subject: [PATCH 09/14] Rename `open_buffer_for_path` to `open_buffer` --- crates/diagnostics/src/diagnostics.rs | 4 +- crates/editor/src/editor.rs | 4 +- crates/project/src/project.rs | 95 ++++++++---------------- crates/server/src/rpc.rs | 102 ++++++++------------------ crates/workspace/src/workspace.rs | 2 +- 5 files changed, 64 insertions(+), 143 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 4eab6984039223c5e7a83df232df4843576e71e4..f6c00a1fd5dbe4fe846054ef999f4cc901c9537a 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -155,9 +155,7 @@ impl ProjectDiagnosticsEditor { async move { for path in paths { let buffer = project - .update(&mut cx, |project, cx| { - project.open_buffer_for_path(path.clone(), cx) - }) + .update(&mut cx, |project, cx| project.open_buffer(path.clone(), cx)) .await?; this.update(&mut cx, |view, cx| view.populate_excerpts(path, buffer, cx)) } diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 131b16e8b7cd3a0c6f9759549592110e806aa112..0b73ebdf63a3bd56e678f6ee75f8f97f4b05b69d 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -8439,9 +8439,7 @@ mod tests { .0 .read_with(cx, |tree, _| tree.id()); let buffer = project - .update(cx, |project, cx| { - project.open_buffer_for_path((worktree_id, ""), cx) - }) + .update(cx, |project, cx| project.open_buffer((worktree_id, ""), cx)) .await .unwrap(); let mut fake_server = fake_servers.next().await.unwrap(); diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 3484796dd9c35da31a29e8894468085dbceb481d..ff535afafb06cf952c19cf92d700a388bbcbc3f6 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -818,19 +818,7 @@ impl Project { Ok(buffer) } - pub fn open_buffer_for_entry( - &mut self, - entry_id: ProjectEntryId, - cx: &mut ModelContext, - ) -> Task>> { - if let Some(project_path) = self.path_for_entry(entry_id, cx) { - self.open_buffer_for_path(project_path, cx) - } else { - Task::ready(Err(anyhow!("entry not found"))) - } - } - - pub fn open_buffer_for_path( + pub fn open_buffer( &mut self, path: impl Into, cx: &mut ModelContext, @@ -965,10 +953,8 @@ impl Project { worktree_id: worktree.read_with(&cx, |worktree, _| worktree.id()), path: relative_path.into(), }; - this.update(&mut cx, |this, cx| { - this.open_buffer_for_path(project_path, cx) - }) - .await + this.update(&mut cx, |this, cx| this.open_buffer(project_path, cx)) + .await }) } @@ -2868,9 +2854,7 @@ impl Project { let buffers_tx = buffers_tx.clone(); cx.spawn(|mut cx| async move { if let Some(buffer) = this - .update(&mut cx, |this, cx| { - this.open_buffer_for_path(project_path, cx) - }) + .update(&mut cx, |this, cx| this.open_buffer(project_path, cx)) .await .log_err() { @@ -3891,7 +3875,7 @@ impl Project { let peer_id = envelope.original_sender_id()?; let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id); let open_buffer = this.update(&mut cx, |this, cx| { - this.open_buffer_for_path( + this.open_buffer( ProjectPath { worktree_id, path: PathBuf::from(envelope.payload.path).into(), @@ -4688,7 +4672,7 @@ mod tests { // Open a buffer without an associated language server. let toml_buffer = project .update(cx, |project, cx| { - project.open_buffer_for_path((worktree_id, "Cargo.toml"), cx) + project.open_buffer((worktree_id, "Cargo.toml"), cx) }) .await .unwrap(); @@ -4696,7 +4680,7 @@ mod tests { // Open a buffer with an associated language server. let rust_buffer = project .update(cx, |project, cx| { - project.open_buffer_for_path((worktree_id, "test.rs"), cx) + project.open_buffer((worktree_id, "test.rs"), cx) }) .await .unwrap(); @@ -4743,7 +4727,7 @@ mod tests { // Open a third buffer with a different associated language server. let json_buffer = project .update(cx, |project, cx| { - project.open_buffer_for_path((worktree_id, "package.json"), cx) + project.open_buffer((worktree_id, "package.json"), cx) }) .await .unwrap(); @@ -4774,7 +4758,7 @@ mod tests { // it is also configured based on the existing language server's capabilities. let rust_buffer2 = project .update(cx, |project, cx| { - project.open_buffer_for_path((worktree_id, "test2.rs"), cx) + project.open_buffer((worktree_id, "test2.rs"), cx) }) .await .unwrap(); @@ -4885,7 +4869,7 @@ mod tests { // Cause worktree to start the fake language server let _buffer = project .update(cx, |project, cx| { - project.open_buffer_for_path((worktree_id, Path::new("b.rs")), cx) + project.open_buffer((worktree_id, Path::new("b.rs")), cx) }) .await .unwrap(); @@ -4932,9 +4916,7 @@ mod tests { ); let buffer = project - .update(cx, |p, cx| { - p.open_buffer_for_path((worktree_id, "a.rs"), cx) - }) + .update(cx, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)) .await .unwrap(); @@ -5001,7 +4983,7 @@ mod tests { let buffer = project .update(cx, |project, cx| { - project.open_buffer_for_path((worktree_id, "a.rs"), cx) + project.open_buffer((worktree_id, "a.rs"), cx) }) .await .unwrap(); @@ -5277,7 +5259,7 @@ mod tests { let buffer = project .update(cx, |project, cx| { - project.open_buffer_for_path((worktree_id, "a.rs"), cx) + project.open_buffer((worktree_id, "a.rs"), cx) }) .await .unwrap(); @@ -5382,7 +5364,7 @@ mod tests { let buffer = project .update(cx, |project, cx| { - project.open_buffer_for_path((worktree_id, "a.rs"), cx) + project.open_buffer((worktree_id, "a.rs"), cx) }) .await .unwrap(); @@ -5540,7 +5522,7 @@ mod tests { let buffer = project .update(cx, |project, cx| { - project.open_buffer_for_path((worktree_id, "a.rs"), cx) + project.open_buffer((worktree_id, "a.rs"), cx) }) .await .unwrap(); @@ -5723,7 +5705,7 @@ mod tests { let buffer = project .update(cx, |project, cx| { - project.open_buffer_for_path( + project.open_buffer( ProjectPath { worktree_id, path: Path::new("").into(), @@ -5819,9 +5801,7 @@ mod tests { .read_with(cx, |tree, _| tree.id()); let buffer = project - .update(cx, |p, cx| { - p.open_buffer_for_path((worktree_id, "file1"), cx) - }) + .update(cx, |p, cx| p.open_buffer((worktree_id, "file1"), cx)) .await .unwrap(); buffer @@ -5859,7 +5839,7 @@ mod tests { .read_with(cx, |tree, _| tree.id()); let buffer = project - .update(cx, |p, cx| p.open_buffer_for_path((worktree_id, ""), cx)) + .update(cx, |p, cx| p.open_buffer((worktree_id, ""), cx)) .await .unwrap(); buffer @@ -5909,7 +5889,7 @@ mod tests { let opened_buffer = project .update(cx, |project, cx| { - project.open_buffer_for_path((worktree_id, "file1"), cx) + project.open_buffer((worktree_id, "file1"), cx) }) .await .unwrap(); @@ -5944,8 +5924,7 @@ mod tests { let worktree_id = tree.read_with(cx, |tree, _| tree.id()); let buffer_for_path = |path: &'static str, cx: &mut gpui::TestAppContext| { - let buffer = - project.update(cx, |p, cx| p.open_buffer_for_path((worktree_id, path), cx)); + let buffer = project.update(cx, |p, cx| p.open_buffer((worktree_id, path), cx)); async move { buffer.await.unwrap() } }; let id_for_path = |path: &'static str, cx: &gpui::TestAppContext| { @@ -6094,9 +6073,9 @@ mod tests { // Spawn multiple tasks to open paths, repeating some paths. let (buffer_a_1, buffer_b, buffer_a_2) = project.update(cx, |p, cx| { ( - p.open_buffer_for_path((worktree_id, "a.txt"), cx), - p.open_buffer_for_path((worktree_id, "b.txt"), cx), - p.open_buffer_for_path((worktree_id, "a.txt"), cx), + p.open_buffer((worktree_id, "a.txt"), cx), + p.open_buffer((worktree_id, "b.txt"), cx), + p.open_buffer((worktree_id, "a.txt"), cx), ) }); @@ -6113,9 +6092,7 @@ mod tests { // Open the same path again while it is still open. drop(buffer_a_1); let buffer_a_3 = project - .update(cx, |p, cx| { - p.open_buffer_for_path((worktree_id, "a.txt"), cx) - }) + .update(cx, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) .await .unwrap(); @@ -6148,9 +6125,7 @@ mod tests { .await; let buffer1 = project - .update(cx, |p, cx| { - p.open_buffer_for_path((worktree_id, "file1"), cx) - }) + .update(cx, |p, cx| p.open_buffer((worktree_id, "file1"), cx)) .await .unwrap(); let events = Rc::new(RefCell::new(Vec::new())); @@ -6220,9 +6195,7 @@ mod tests { // When a file is deleted, the buffer is considered dirty. let events = Rc::new(RefCell::new(Vec::new())); let buffer2 = project - .update(cx, |p, cx| { - p.open_buffer_for_path((worktree_id, "file2"), cx) - }) + .update(cx, |p, cx| p.open_buffer((worktree_id, "file2"), cx)) .await .unwrap(); buffer2.update(cx, |_, cx| { @@ -6243,9 +6216,7 @@ mod tests { // When a file is already dirty when deleted, we don't emit a Dirtied event. let events = Rc::new(RefCell::new(Vec::new())); let buffer3 = project - .update(cx, |p, cx| { - p.open_buffer_for_path((worktree_id, "file3"), cx) - }) + .update(cx, |p, cx| p.open_buffer((worktree_id, "file3"), cx)) .await .unwrap(); buffer3.update(cx, |_, cx| { @@ -6291,9 +6262,7 @@ mod tests { let abs_path = dir.path().join("the-file"); let buffer = project - .update(cx, |p, cx| { - p.open_buffer_for_path((worktree_id, "the-file"), cx) - }) + .update(cx, |p, cx| p.open_buffer((worktree_id, "the-file"), cx)) .await .unwrap(); @@ -6399,9 +6368,7 @@ mod tests { let worktree_id = worktree.read_with(cx, |tree, _| tree.id()); let buffer = project - .update(cx, |p, cx| { - p.open_buffer_for_path((worktree_id, "a.rs"), cx) - }) + .update(cx, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)) .await .unwrap(); @@ -6674,7 +6641,7 @@ mod tests { let buffer = project .update(cx, |project, cx| { - project.open_buffer_for_path((worktree_id, Path::new("one.rs")), cx) + project.open_buffer((worktree_id, Path::new("one.rs")), cx) }) .await .unwrap(); @@ -6812,7 +6779,7 @@ mod tests { let buffer_4 = project .update(cx, |project, cx| { - project.open_buffer_for_path((worktree_id, "four.rs"), cx) + project.open_buffer((worktree_id, "four.rs"), cx) }) .await .unwrap(); diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index e70957740f72707d3fe6b443dd0cc4ff2e188a15..d70bfe2c2161e6dbfe6b68869a47cd6cdd32fe63 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -1137,9 +1137,7 @@ mod tests { // Open the same file as client B and client A. let buffer_b = project_b - .update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "b.txt"), cx) - }) + .update(cx_b, |p, cx| p.open_buffer((worktree_id, "b.txt"), cx)) .await .unwrap(); let buffer_b = cx_b.add_model(|cx| MultiBuffer::singleton(buffer_b, cx)); @@ -1150,9 +1148,7 @@ mod tests { assert!(project.has_open_buffer((worktree_id, "b.txt"), cx)) }); let buffer_a = project_a - .update(cx_a, |p, cx| { - p.open_buffer_for_path((worktree_id, "b.txt"), cx) - }) + .update(cx_a, |p, cx| p.open_buffer((worktree_id, "b.txt"), cx)) .await .unwrap(); @@ -1242,9 +1238,7 @@ mod tests { .await .unwrap(); project_b - .update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "a.txt"), cx) - }) + .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) .await .unwrap(); @@ -1279,9 +1273,7 @@ mod tests { .await .unwrap(); project_b2 - .update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "a.txt"), cx) - }) + .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) .await .unwrap(); } @@ -1360,15 +1352,11 @@ mod tests { // Open and edit a buffer as both guests B and C. let buffer_b = project_b - .update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "file1"), cx) - }) + .update(cx_b, |p, cx| p.open_buffer((worktree_id, "file1"), cx)) .await .unwrap(); let buffer_c = project_c - .update(cx_c, |p, cx| { - p.open_buffer_for_path((worktree_id, "file1"), cx) - }) + .update(cx_c, |p, cx| p.open_buffer((worktree_id, "file1"), cx)) .await .unwrap(); buffer_b.update(cx_b, |buf, cx| buf.edit([0..0], "i-am-b, ", cx)); @@ -1376,9 +1364,7 @@ mod tests { // Open and edit that buffer as the host. let buffer_a = project_a - .update(cx_a, |p, cx| { - p.open_buffer_for_path((worktree_id, "file1"), cx) - }) + .update(cx_a, |p, cx| p.open_buffer((worktree_id, "file1"), cx)) .await .unwrap(); @@ -1528,9 +1514,7 @@ mod tests { // Open a buffer as client B let buffer_b = project_b - .update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "a.txt"), cx) - }) + .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) .await .unwrap(); @@ -1613,9 +1597,7 @@ mod tests { // Open a buffer as client B let buffer_b = project_b - .update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "a.txt"), cx) - }) + .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) .await .unwrap(); buffer_b.read_with(cx_b, |buf, _| { @@ -1695,16 +1677,14 @@ mod tests { // Open a buffer as client A let buffer_a = project_a - .update(cx_a, |p, cx| { - p.open_buffer_for_path((worktree_id, "a.txt"), cx) - }) + .update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)) .await .unwrap(); // Start opening the same buffer as client B - let buffer_b = cx_b.background().spawn(project_b.update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "a.txt"), cx) - })); + let buffer_b = cx_b + .background() + .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))); // Edit the buffer as client A while client B is still opening it. cx_b.background().simulate_random_delay().await; @@ -1780,9 +1760,9 @@ mod tests { .await; // Begin opening a buffer as client B, but leave the project before the open completes. - let buffer_b = cx_b.background().spawn(project_b.update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "a.txt"), cx) - })); + let buffer_b = cx_b + .background() + .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))); cx_b.update(|_| drop(project_b)); drop(buffer_b); @@ -1952,7 +1932,7 @@ mod tests { let _ = cx_a .background() .spawn(project_a.update(cx_a, |project, cx| { - project.open_buffer_for_path( + project.open_buffer( ProjectPath { worktree_id, path: Path::new("other.rs").into(), @@ -2073,9 +2053,7 @@ mod tests { // Open the file with the errors on client B. They should be present. let buffer_b = cx_b .background() - .spawn(project_b.update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "a.rs"), cx) - })) + .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx))) .await .unwrap(); @@ -2193,9 +2171,7 @@ mod tests { // Open a file in an editor as the guest. let buffer_b = project_b - .update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "main.rs"), cx) - }) + .update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx)) .await .unwrap(); let (window_b, _) = cx_b.add_window(|_| EmptyView); @@ -2269,9 +2245,7 @@ mod tests { // Open the buffer on the host. let buffer_a = project_a - .update(cx_a, |p, cx| { - p.open_buffer_for_path((worktree_id, "main.rs"), cx) - }) + .update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx)) .await .unwrap(); buffer_a @@ -2395,9 +2369,7 @@ mod tests { let buffer_b = cx_b .background() - .spawn(project_b.update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "a.rs"), cx) - })) + .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx))) .await .unwrap(); @@ -2505,9 +2477,7 @@ mod tests { // Open the file on client B. let buffer_b = cx_b .background() - .spawn(project_b.update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "a.rs"), cx) - })) + .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx))) .await .unwrap(); @@ -2646,9 +2616,7 @@ mod tests { // Open the file on client B. let buffer_b = cx_b .background() - .spawn(project_b.update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "one.rs"), cx) - })) + .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "one.rs"), cx))) .await .unwrap(); @@ -2877,9 +2845,7 @@ mod tests { // Open the file on client B. let buffer_b = cx_b .background() - .spawn(project_b.update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "main.rs"), cx) - })) + .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))) .await .unwrap(); @@ -3026,9 +2992,7 @@ mod tests { // Cause the language server to start. let _buffer = cx_b .background() - .spawn(project_b.update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "one.rs"), cx) - })) + .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "one.rs"), cx))) .await .unwrap(); @@ -3159,9 +3123,7 @@ mod tests { let buffer_b1 = cx_b .background() - .spawn(project_b.update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "a.rs"), cx) - })) + .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx))) .await .unwrap(); @@ -3177,13 +3139,9 @@ mod tests { let buffer_b2; if rng.gen() { definitions = project_b.update(cx_b, |p, cx| p.definition(&buffer_b1, 23, cx)); - buffer_b2 = project_b.update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "b.rs"), cx) - }); + buffer_b2 = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "b.rs"), cx)); } else { - buffer_b2 = project_b.update(cx_b, |p, cx| { - p.open_buffer_for_path((worktree_id, "b.rs"), cx) - }); + buffer_b2 = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "b.rs"), cx)); definitions = project_b.update(cx_b, |p, cx| p.definition(&buffer_b1, 23, cx)); } @@ -4800,7 +4758,7 @@ mod tests { ); let buffer = project .update(&mut cx, |project, cx| { - project.open_buffer_for_path(project_path, cx) + project.open_buffer(project_path, cx) }) .await .unwrap(); @@ -4917,7 +4875,7 @@ mod tests { ); let buffer = project .update(&mut cx, |project, cx| { - project.open_buffer_for_path(project_path.clone(), cx) + project.open_buffer(project_path.clone(), cx) }) .await .unwrap(); diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index e10073c04aef840fa52d338f4f335af0b1b4c26f..92fcacaf85f2f72df3da40ec9f5937d171a03362 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -816,7 +816,7 @@ impl Workspace { )>, > { let project = self.project().clone(); - let buffer = project.update(cx, |project, cx| project.open_buffer_for_path(path, cx)); + let buffer = project.update(cx, |project, cx| project.open_buffer(path, cx)); cx.spawn(|this, mut cx| async move { let buffer = buffer.await?; let project_entry_id = buffer.read_with(&cx, |buffer, cx| { From 84bacc556f55f88747c08f96ed0a36f1fa4b3dbd Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 17 Mar 2022 14:31:05 +0100 Subject: [PATCH 10/14] Rename `build_editor` to `build_item` in `Pane::open_item` Co-Authored-By: Nathan Sobo --- crates/workspace/src/pane.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 552d102729580f04637e00da9167aef1ed62c4bd..4ee9eb97ae6a3bef77bdc5387dede2db9597098f 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -284,7 +284,7 @@ impl Pane { &mut self, project_entry_id: ProjectEntryId, cx: &mut ViewContext, - build_editor: impl FnOnce(&mut MutableAppContext) -> Box, + build_item: impl FnOnce(&mut MutableAppContext) -> Box, ) -> Box { for (ix, (existing_entry_id, item)) in self.items.iter().enumerate() { if *existing_entry_id == Some(project_entry_id) { @@ -294,7 +294,7 @@ impl Pane { } } - let item = build_editor(cx); + let item = build_item(cx); self.add_item(Some(project_entry_id), item.boxed_clone(), cx); item } From 44d997c00c875b2202997a185b2b3d4f1b25920c Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 17 Mar 2022 14:33:01 +0100 Subject: [PATCH 11/14] Rename `app_state` to `global` in gpui Co-Authored-By: Nathan Sobo --- crates/chat_panel/src/chat_panel.rs | 14 ++++++------ crates/contacts_panel/src/contacts_panel.rs | 4 ++-- crates/diagnostics/src/diagnostics.rs | 6 ++--- crates/diagnostics/src/items.rs | 2 +- crates/editor/src/editor.rs | 14 ++++++------ crates/editor/src/element.rs | 4 ++-- crates/editor/src/items.rs | 4 ++-- crates/file_finder/src/file_finder.rs | 6 ++--- crates/go_to_line/src/go_to_line.rs | 5 +++-- crates/gpui/src/app.rs | 20 ++++++++--------- crates/outline/src/outline.rs | 15 ++++++++----- crates/project_panel/src/project_panel.rs | 4 ++-- crates/project_symbols/src/project_symbols.rs | 6 ++--- crates/search/src/buffer_search.rs | 10 ++++----- crates/search/src/project_search.rs | 22 +++++++++---------- crates/server/src/rpc.rs | 2 +- crates/theme_selector/src/theme_selector.rs | 14 ++++++------ crates/workspace/src/lsp_status.rs | 4 ++-- crates/workspace/src/pane.rs | 2 +- crates/workspace/src/status_bar.rs | 2 +- crates/workspace/src/workspace.rs | 12 +++++----- crates/zed/src/main.rs | 4 ++-- crates/zed/src/test.rs | 2 +- crates/zed/src/zed.rs | 2 +- 24 files changed, 91 insertions(+), 89 deletions(-) diff --git a/crates/chat_panel/src/chat_panel.rs b/crates/chat_panel/src/chat_panel.rs index ceeddc599a0d3d90b0328e2d6d94148b98e42002..bed338d3f43c3ab2e3bbd311b237eed8a015ba34 100644 --- a/crates/chat_panel/src/chat_panel.rs +++ b/crates/chat_panel/src/chat_panel.rs @@ -64,13 +64,13 @@ impl ChatPanel { ix, item_type, is_hovered, - &cx.app_state::().theme.chat_panel.channel_select, + &cx.global::().theme.chat_panel.channel_select, cx, ) } }) .with_style(move |cx| { - let theme = &cx.app_state::().theme.chat_panel.channel_select; + let theme = &cx.global::().theme.chat_panel.channel_select; SelectStyle { header: theme.header.container.clone(), menu: theme.menu.clone(), @@ -200,7 +200,7 @@ impl ChatPanel { } fn render_channel(&self, cx: &mut RenderContext) -> ElementBox { - let theme = &cx.app_state::().theme; + let theme = &cx.global::().theme; Flex::column() .with_child( Container::new(ChildView::new(&self.channel_select).boxed()) @@ -224,7 +224,7 @@ impl ChatPanel { fn render_message(&self, message: &ChannelMessage, cx: &AppContext) -> ElementBox { let now = OffsetDateTime::now_utc(); - let settings = cx.app_state::(); + let settings = cx.global::(); let theme = if message.is_pending() { &settings.theme.chat_panel.pending_message } else { @@ -267,7 +267,7 @@ impl ChatPanel { } fn render_input_box(&self, cx: &AppContext) -> ElementBox { - let theme = &cx.app_state::().theme; + let theme = &cx.global::().theme; Container::new(ChildView::new(&self.input_editor).boxed()) .with_style(theme.chat_panel.input_editor.container) .boxed() @@ -304,7 +304,7 @@ impl ChatPanel { } fn render_sign_in_prompt(&self, cx: &mut RenderContext) -> ElementBox { - let theme = cx.app_state::().theme.clone(); + let theme = cx.global::().theme.clone(); let rpc = self.rpc.clone(); let this = cx.handle(); @@ -385,7 +385,7 @@ impl View for ChatPanel { } else { self.render_sign_in_prompt(cx) }; - let theme = &cx.app_state::().theme; + let theme = &cx.global::().theme; ConstrainedBox::new( Container::new(element) .with_style(theme.chat_panel.container) diff --git a/crates/contacts_panel/src/contacts_panel.rs b/crates/contacts_panel/src/contacts_panel.rs index b5740a5ed75bde0fdfd7233133a4afd025c2f80e..b8b5b3a361bfa548372b81d982094ab2e0cf19ad 100644 --- a/crates/contacts_panel/src/contacts_panel.rs +++ b/crates/contacts_panel/src/contacts_panel.rs @@ -55,7 +55,7 @@ impl ContactsPanel { app_state: Arc, cx: &mut LayoutContext, ) -> ElementBox { - let theme = cx.app_state::().theme.clone(); + let theme = cx.global::().theme.clone(); let theme = &theme.contacts_panel; let project_count = collaborator.projects.len(); let font_cache = cx.font_cache(); @@ -236,7 +236,7 @@ impl View for ContactsPanel { } fn render(&mut self, cx: &mut RenderContext) -> ElementBox { - let theme = &cx.app_state::().theme.contacts_panel; + let theme = &cx.global::().theme.contacts_panel; Container::new(List::new(self.contacts.clone()).boxed()) .with_style(theme.container) .boxed() diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index f6c00a1fd5dbe4fe846054ef999f4cc901c9537a..a188761340c518f29a72f068c161c6c36ad21c6c 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -72,7 +72,7 @@ impl View for ProjectDiagnosticsEditor { fn render(&mut self, cx: &mut RenderContext) -> ElementBox { if self.path_states.is_empty() { - let theme = &cx.app_state::().theme.project_diagnostics; + let theme = &cx.global::().theme.project_diagnostics; Label::new( "No problems in workspace".to_string(), theme.empty_message.clone(), @@ -441,7 +441,7 @@ impl workspace::Item for ProjectDiagnosticsEditor { render_summary( &self.summary, &style.label.text, - &cx.app_state::().theme.project_diagnostics, + &cx.global::().theme.project_diagnostics, ) } @@ -535,7 +535,7 @@ impl workspace::Item for ProjectDiagnosticsEditor { fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock { let (message, highlights) = highlight_diagnostic_message(&diagnostic.message); Arc::new(move |cx| { - let settings = cx.app_state::(); + let settings = cx.global::(); let theme = &settings.theme.editor; let style = &theme.diagnostic_header; let font_size = (style.text_scale_factor * settings.buffer_font_size).round(); diff --git a/crates/diagnostics/src/items.rs b/crates/diagnostics/src/items.rs index 1b4d2a8147818a07ef5b9c2a2255a934dee44d1f..690c5100ecf9ec3a8edf89414a2ef545f868201a 100644 --- a/crates/diagnostics/src/items.rs +++ b/crates/diagnostics/src/items.rs @@ -49,7 +49,7 @@ impl View for DiagnosticSummary { let in_progress = self.in_progress; MouseEventHandler::new::(0, cx, |_, cx| { - let theme = &cx.app_state::().theme.project_diagnostics; + let theme = &cx.global::().theme.project_diagnostics; if in_progress { Label::new( "Checking... ".to_string(), diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 0b73ebdf63a3bd56e678f6ee75f8f97f4b05b69d..67d7d7cd90f12fecf97773e4a370d8beb1ec47f9 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -883,7 +883,7 @@ impl Editor { cx: &mut ViewContext, ) -> Self { let display_map = cx.add_model(|cx| { - let settings = cx.app_state::(); + let settings = cx.global::(); let style = build_style(&*settings, get_field_editor_theme, None, cx); DisplayMap::new( buffer.clone(), @@ -1011,7 +1011,7 @@ impl Editor { fn style(&self, cx: &AppContext) -> EditorStyle { build_style( - cx.app_state::(), + cx.global::(), self.get_field_editor_theme, self.override_text_style.as_deref(), cx, @@ -2729,7 +2729,7 @@ impl Editor { } self.start_transaction(cx); - let tab_size = cx.app_state::().tab_size; + let tab_size = cx.global::().tab_size; let mut selections = self.local_selections::(cx); let mut last_indent = None; self.buffer.update(cx, |buffer, cx| { @@ -2806,7 +2806,7 @@ impl Editor { } self.start_transaction(cx); - let tab_size = cx.app_state::().tab_size; + let tab_size = cx.global::().tab_size; let selections = self.local_selections::(cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut deletion_ranges = Vec::new(); @@ -5324,7 +5324,7 @@ impl Editor { pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap { let language = self.language(cx); - let settings = cx.app_state::(); + let settings = cx.global::(); let mode = self .soft_wrap_mode_override .unwrap_or_else(|| settings.soft_wrap(language)); @@ -5906,7 +5906,7 @@ pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> Rend } Arc::new(move |cx: &BlockContext| { - let settings = cx.app_state::(); + let settings = cx.global::(); let theme = &settings.theme.editor; let style = diagnostic_style(diagnostic.severity, is_valid, theme); let font_size = (style.text_scale_factor * settings.buffer_font_size).round(); @@ -9108,7 +9108,7 @@ mod tests { fn populate_settings(cx: &mut gpui::MutableAppContext) { let settings = Settings::test(cx); - cx.add_app_state(settings); + cx.set_global(settings); } } diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index ad8057db4e8421b4729d653d844f4706484b98b8..49d800d619829b4e691095bcc5e588712691c5da 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1490,7 +1490,7 @@ mod tests { #[gpui::test] fn test_layout_line_numbers(cx: &mut gpui::MutableAppContext) { - cx.add_app_state(Settings::test(cx)); + cx.set_global(Settings::test(cx)); let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx); let (window_id, editor) = cx.add_window(Default::default(), |cx| { Editor::new(EditorMode::Full, buffer, None, None, cx) @@ -1512,7 +1512,7 @@ mod tests { #[gpui::test] fn test_layout_with_placeholder_text_and_blocks(cx: &mut gpui::MutableAppContext) { - cx.add_app_state(Settings::test(cx)); + cx.set_global(Settings::test(cx)); let buffer = MultiBuffer::build_simple("", cx); let (window_id, editor) = cx.add_window(Default::default(), |cx| { Editor::new(EditorMode::Full, buffer, None, None, cx) diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index d4e779484b2436507b3379031a3a96485c5b6d07..60dd8ae303861f823d63c59e771df96c07b814fd 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -179,7 +179,7 @@ impl View for CursorPosition { fn render(&mut self, cx: &mut RenderContext) -> ElementBox { if let Some(position) = self.position { - let theme = &cx.app_state::().theme.workspace.status_bar; + let theme = &cx.global::().theme.workspace.status_bar; let mut text = format!("{},{}", position.row + 1, position.column + 1); if self.selected_count > 0 { write!(text, " ({} selected)", self.selected_count).unwrap(); @@ -252,7 +252,7 @@ impl View for DiagnosticMessage { fn render(&mut self, cx: &mut RenderContext) -> ElementBox { if let Some(diagnostic) = &self.diagnostic { - let theme = &cx.app_state::().theme.workspace.status_bar; + let theme = &cx.global::().theme.workspace.status_bar; Label::new( diagnostic.message.split('\n').next().unwrap().to_string(), theme.diagnostic_message.clone(), diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 0dbb336007d4cd0858140c95b212c193798dc077..808f7e47031b9c08ba79e89330a990a2c8ed5440 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -67,7 +67,7 @@ impl View for FileFinder { } fn render(&mut self, cx: &mut RenderContext) -> ElementBox { - let settings = cx.app_state::(); + let settings = cx.global::(); Align::new( ConstrainedBox::new( Container::new( @@ -106,7 +106,7 @@ impl View for FileFinder { impl FileFinder { fn render_matches(&self, cx: &AppContext) -> ElementBox { if self.matches.is_empty() { - let settings = cx.app_state::(); + let settings = cx.global::(); return Container::new( Label::new( "No matches".into(), @@ -142,7 +142,7 @@ impl FileFinder { fn render_match(&self, path_match: &PathMatch, index: usize, cx: &AppContext) -> ElementBox { let selected_index = self.selected_index(); - let settings = cx.app_state::(); + let settings = cx.global::(); let style = if index == selected_index { &settings.theme.selector.active_item } else { diff --git a/crates/go_to_line/src/go_to_line.rs b/crates/go_to_line/src/go_to_line.rs index 50bae39ae9af73b5b8a82596129deec652dfd776..f2dd4e76b1dc414bd6df9113ae4e61da3524e6f1 100644 --- a/crates/go_to_line/src/go_to_line.rs +++ b/crates/go_to_line/src/go_to_line.rs @@ -59,7 +59,8 @@ impl GoToLine { } fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext) { - if let Some(editor) = workspace.active_item(cx) + if let Some(editor) = workspace + .active_item(cx) .and_then(|active_item| active_item.downcast::()) { workspace.toggle_modal(cx, |cx, _| { @@ -148,7 +149,7 @@ impl View for GoToLine { } fn render(&mut self, cx: &mut RenderContext) -> ElementBox { - let theme = &cx.app_state::().theme.selector; + let theme = &cx.global::().theme.selector; let label = format!( "{},{} of {} lines", diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 9831c3aa3473ff36c41ace5cdbf63594475a7978..097f9d7199fea07871db8522e0c2e1900bcdbb4c 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -799,7 +799,7 @@ impl MutableAppContext { models: Default::default(), views: Default::default(), windows: Default::default(), - app_states: Default::default(), + globals: Default::default(), element_states: Default::default(), ref_counts: Arc::new(Mutex::new(ref_counts)), background, @@ -1364,24 +1364,22 @@ impl MutableAppContext { Ok(pending) } - pub fn add_app_state(&mut self, state: T) { - self.cx - .app_states - .insert(TypeId::of::(), Box::new(state)); + pub fn set_global(&mut self, state: T) { + self.cx.globals.insert(TypeId::of::(), Box::new(state)); } - pub fn update_app_state(&mut self, update: F) -> U + pub fn update_global(&mut self, update: F) -> U where F: FnOnce(&mut T, &mut MutableAppContext) -> U, { let type_id = TypeId::of::(); let mut state = self .cx - .app_states + .globals .remove(&type_id) .expect("no app state has been added for this type"); let result = update(state.downcast_mut().unwrap(), self); - self.cx.app_states.insert(type_id, state); + self.cx.globals.insert(type_id, state); result } @@ -2054,7 +2052,7 @@ pub struct AppContext { models: HashMap>, views: HashMap<(usize, usize), Box>, windows: HashMap, - app_states: HashMap>, + globals: HashMap>, element_states: HashMap>, background: Arc, ref_counts: Arc>, @@ -2087,8 +2085,8 @@ impl AppContext { &self.platform } - pub fn app_state(&self) -> &T { - self.app_states + pub fn global(&self) -> &T { + self.globals .get(&TypeId::of::()) .expect("no app state has been added for this type") .downcast_ref() diff --git a/crates/outline/src/outline.rs b/crates/outline/src/outline.rs index 2b4bafa479de3e8b70ac1ded33a7a1f9d4454060..fd4c8ff60b5d660d199e888596cd70649ae478a8 100644 --- a/crates/outline/src/outline.rs +++ b/crates/outline/src/outline.rs @@ -69,7 +69,7 @@ impl View for OutlineView { } fn render(&mut self, cx: &mut RenderContext) -> ElementBox { - let settings = cx.app_state::(); + let settings = cx.global::(); Flex::new(Axis::Vertical) .with_child( @@ -124,9 +124,12 @@ impl OutlineView { .active_item(cx) .and_then(|item| item.downcast::()) { - let buffer = editor.read(cx).buffer().read(cx).read(cx).outline(Some( - cx.app_state::().theme.editor.syntax.as_ref(), - )); + let buffer = editor + .read(cx) + .buffer() + .read(cx) + .read(cx) + .outline(Some(cx.global::().theme.editor.syntax.as_ref())); if let Some(outline) = buffer { workspace.toggle_modal(cx, |cx, _| { let view = cx.add_view(|cx| OutlineView::new(outline, editor, cx)); @@ -288,7 +291,7 @@ impl OutlineView { fn render_matches(&self, cx: &AppContext) -> ElementBox { if self.matches.is_empty() { - let settings = cx.app_state::(); + let settings = cx.global::(); return Container::new( Label::new( "No matches".into(), @@ -330,7 +333,7 @@ impl OutlineView { index: usize, cx: &AppContext, ) -> ElementBox { - let settings = cx.app_state::(); + let settings = cx.global::(); let style = if index == self.selected_match_index { &settings.theme.selector.active_item } else { diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 372f0c169bb06602ebbfc4bbb2f7e576ca4d051e..0dd6b08bacc68bf888e9348636ec0b66669a509c 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -517,7 +517,7 @@ impl View for ProjectPanel { } fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox { - let theme = &cx.app_state::().theme.project_panel; + let theme = &cx.global::().theme.project_panel; let mut container_style = theme.container; let padding = std::mem::take(&mut container_style.padding); let handle = self.handle.clone(); @@ -528,7 +528,7 @@ impl View for ProjectPanel { .map(|(_, worktree_entries)| worktree_entries.len()) .sum(), move |range, items, cx| { - let theme = cx.app_state::().theme.clone(); + let theme = cx.global::().theme.clone(); let this = handle.upgrade(cx).unwrap(); this.update(cx.app, |this, cx| { this.for_each_visible_entry(range.clone(), cx, |entry, details, cx| { diff --git a/crates/project_symbols/src/project_symbols.rs b/crates/project_symbols/src/project_symbols.rs index 29808ff7d9df5b428f7299493b88a13cece8e8eb..d79b2dedaeadc0e85a3469ca3e7e03b7e258e589 100644 --- a/crates/project_symbols/src/project_symbols.rs +++ b/crates/project_symbols/src/project_symbols.rs @@ -69,7 +69,7 @@ impl View for ProjectSymbolsView { } fn render(&mut self, cx: &mut RenderContext) -> ElementBox { - let settings = cx.app_state::(); + let settings = cx.global::(); Flex::new(Axis::Vertical) .with_child( Container::new(ChildView::new(&self.query_editor).boxed()) @@ -233,7 +233,7 @@ impl ProjectSymbolsView { fn render_matches(&self, cx: &AppContext) -> ElementBox { if self.matches.is_empty() { - let settings = cx.app_state::(); + let settings = cx.global::(); return Container::new( Label::new( "No matches".into(), @@ -276,7 +276,7 @@ impl ProjectSymbolsView { show_worktree_root_name: bool, cx: &AppContext, ) -> ElementBox { - let settings = cx.app_state::(); + let settings = cx.global::(); let style = if index == self.selected_match_index { &settings.theme.selector.active_item } else { diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index 41b3d188bbd0e82d130796ffb319bd9ffe790376..9c4f67aae32a79166e330e9365a46f25e7484cda 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -66,7 +66,7 @@ impl View for SearchBar { } fn render(&mut self, cx: &mut RenderContext) -> ElementBox { - let theme = cx.app_state::().theme.clone(); + let theme = cx.global::().theme.clone(); let editor_container = if self.query_contains_error { theme.search.invalid_editor } else { @@ -197,7 +197,7 @@ impl SearchBar { ) -> ElementBox { let is_active = self.is_search_option_enabled(search_option); MouseEventHandler::new::(search_option as usize, cx, |state, cx| { - let theme = &cx.app_state::().theme.search; + let theme = &cx.global::().theme.search; let style = match (is_active, state.hovered) { (false, false) => &theme.option_button, (false, true) => &theme.hovered_option_button, @@ -222,7 +222,7 @@ impl SearchBar { ) -> ElementBox { enum NavButton {} MouseEventHandler::new::(direction as usize, cx, |state, cx| { - let theme = &cx.app_state::().theme.search; + let theme = &cx.global::().theme.search; let style = if state.hovered { &theme.hovered_option_button } else { @@ -475,7 +475,7 @@ impl SearchBar { } } - let theme = &cx.app_state::().theme.search; + let theme = &cx.global::().theme.search; editor.highlight_background::( ranges, theme.match_background, @@ -521,7 +521,7 @@ mod tests { let mut theme = gpui::fonts::with_font_cache(fonts.clone(), || theme::Theme::default()); theme.search.match_background = Color::red(); let settings = Settings::new("Courier", &fonts, Arc::new(theme)).unwrap(); - cx.update(|cx| cx.add_app_state(settings)); + cx.update(|cx| cx.set_global(settings)); let buffer = cx.update(|cx| { MultiBuffer::build_simple( diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index acf7b2a23405201e94a06a976716649947af89e8..6e402ad4a3ceb6b1e77a5e06baaa73d08dadcf03 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -29,7 +29,7 @@ const MAX_TAB_TITLE_LEN: usize = 24; struct ActiveSearches(HashMap, WeakViewHandle>); pub fn init(cx: &mut MutableAppContext) { - cx.add_app_state(ActiveSearches::default()); + cx.set_global(ActiveSearches::default()); cx.add_bindings([ Binding::new("cmd-shift-F", ToggleFocus, Some("ProjectSearchView")), Binding::new("cmd-f", ToggleFocus, Some("ProjectSearchView")), @@ -155,7 +155,7 @@ impl View for ProjectSearchView { fn render(&mut self, cx: &mut RenderContext) -> ElementBox { let model = &self.model.read(cx); let results = if model.match_ranges.is_empty() { - let theme = &cx.app_state::().theme; + let theme = &cx.global::().theme; let text = if self.query_editor.read(cx).text(cx).is_empty() { "" } else if model.pending_search.is_some() { @@ -183,7 +183,7 @@ impl View for ProjectSearchView { fn on_focus(&mut self, cx: &mut ViewContext) { let handle = cx.weak_handle(); - cx.update_app_state(|state: &mut ActiveSearches, cx| { + cx.update_global(|state: &mut ActiveSearches, cx| { state .0 .insert(self.model.read(cx).project.downgrade(), handle) @@ -219,7 +219,7 @@ impl Item for ProjectSearchView { } fn tab_content(&self, tab_theme: &theme::Tab, cx: &gpui::AppContext) -> ElementBox { - let settings = cx.app_state::(); + let settings = cx.global::(); let search_theme = &settings.theme.search; Flex::row() .with_child( @@ -370,12 +370,12 @@ impl ProjectSearchView { // If no search exists in the workspace, create a new one. fn deploy(workspace: &mut Workspace, _: &Deploy, cx: &mut ViewContext) { // Clean up entries for dropped projects - cx.update_app_state(|state: &mut ActiveSearches, cx| { + cx.update_global(|state: &mut ActiveSearches, cx| { state.0.retain(|project, _| project.is_upgradable(cx)) }); let active_search = cx - .app_state::() + .global::() .0 .get(&workspace.project().downgrade()); @@ -534,7 +534,7 @@ impl ProjectSearchView { if reset_selections { editor.select_ranges(match_ranges.first().cloned(), Some(Autoscroll::Fit), cx); } - let theme = &cx.app_state::().theme.search; + let theme = &cx.global::().theme.search; editor.highlight_background::(match_ranges, theme.match_background, cx); }); if self.query_editor.is_focused(cx) { @@ -560,7 +560,7 @@ impl ProjectSearchView { } fn render_query_editor(&self, cx: &mut RenderContext) -> ElementBox { - let theme = cx.app_state::().theme.clone(); + let theme = cx.global::().theme.clone(); let editor_container = if self.query_contains_error { theme.search.invalid_editor } else { @@ -624,7 +624,7 @@ impl ProjectSearchView { ) -> ElementBox { let is_active = self.is_option_enabled(option); MouseEventHandler::new::(option as usize, cx, |state, cx| { - let theme = &cx.app_state::().theme.search; + let theme = &cx.global::().theme.search; let style = match (is_active, state.hovered) { (false, false) => &theme.option_button, (false, true) => &theme.hovered_option_button, @@ -657,7 +657,7 @@ impl ProjectSearchView { ) -> ElementBox { enum NavButton {} MouseEventHandler::new::(direction as usize, cx, |state, cx| { - let theme = &cx.app_state::().theme.search; + let theme = &cx.global::().theme.search; let style = if state.hovered { &theme.hovered_option_button } else { @@ -689,7 +689,7 @@ mod tests { let mut theme = gpui::fonts::with_font_cache(fonts.clone(), || theme::Theme::default()); theme.search.match_background = Color::red(); let settings = Settings::new("Courier", &fonts, Arc::new(theme)).unwrap(); - cx.update(|cx| cx.add_app_state(settings)); + cx.update(|cx| cx.set_global(settings)); let fs = FakeFs::new(cx.background()); fs.insert_tree( diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index d70bfe2c2161e6dbfe6b68869a47cd6cdd32fe63..7f1b9f90ad7c0bd710fa79b075e78640ff279da1 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -4414,7 +4414,7 @@ mod tests { async fn create_client(&mut self, cx: &mut TestAppContext, name: &str) -> TestClient { cx.update(|cx| { let settings = Settings::test(cx); - cx.add_app_state(settings); + cx.set_global(settings); }); let http = FakeHttpClient::with_404_response(); diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index c3199bc20bf24153de96ef98f24da8b97d6874ed..f879940f219f266a1f3108e0f570948cb9ef584e 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -54,7 +54,7 @@ impl ThemeSelector { cx.subscribe(&query_editor, Self::on_query_editor_event) .detach(); - let original_theme = cx.app_state::().theme.clone(); + let original_theme = cx.global::().theme.clone(); let mut this = Self { themes: registry, @@ -82,7 +82,7 @@ impl ThemeSelector { } fn reload(_: &mut Workspace, action: &Reload, cx: &mut ViewContext) { - let current_theme_name = cx.app_state::().theme.name.clone(); + let current_theme_name = cx.global::().theme.name.clone(); action.0.clear(); match action.0.get(¤t_theme_name) { Ok(theme) => { @@ -206,7 +206,7 @@ impl ThemeSelector { match event { editor::Event::Edited => { self.update_matches(cx); - self.select_if_matching(&cx.app_state::().theme.name); + self.select_if_matching(&cx.global::().theme.name); self.show_selected_theme(cx); } editor::Event::Blurred => cx.emit(Event::Dismissed), @@ -216,7 +216,7 @@ impl ThemeSelector { fn render_matches(&self, cx: &mut RenderContext) -> ElementBox { if self.matches.is_empty() { - let settings = cx.app_state::(); + let settings = cx.global::(); return Container::new( Label::new( "No matches".into(), @@ -251,7 +251,7 @@ impl ThemeSelector { } fn render_match(&self, theme_match: &StringMatch, index: usize, cx: &AppContext) -> ElementBox { - let settings = cx.app_state::(); + let settings = cx.global::(); let theme = &settings.theme; let container = Container::new( @@ -276,7 +276,7 @@ impl ThemeSelector { } fn set_theme(theme: Arc, cx: &mut MutableAppContext) { - cx.update_app_state::(|settings, cx| { + cx.update_global::(|settings, cx| { settings.theme = theme; cx.refresh_windows(); }); @@ -299,7 +299,7 @@ impl View for ThemeSelector { } fn render(&mut self, cx: &mut RenderContext) -> ElementBox { - let theme = cx.app_state::().theme.clone(); + let theme = cx.global::().theme.clone(); Align::new( ConstrainedBox::new( Container::new( diff --git a/crates/workspace/src/lsp_status.rs b/crates/workspace/src/lsp_status.rs index 1b8b89f6910c486e2d606a2a30e53a718e31f971..a12f81857f1d1b2ed4d44aa01c6283da67f2c8c2 100644 --- a/crates/workspace/src/lsp_status.rs +++ b/crates/workspace/src/lsp_status.rs @@ -116,7 +116,7 @@ impl View for LspStatus { } fn render(&mut self, cx: &mut RenderContext) -> ElementBox { - let theme = &cx.app_state::().theme; + let theme = &cx.global::().theme; let mut pending_work = self.pending_language_server_work(cx); if let Some((lang_server_name, progress_token, progress)) = pending_work.next() { @@ -166,7 +166,7 @@ impl View for LspStatus { } else if !self.failed.is_empty() { drop(pending_work); MouseEventHandler::new::(0, cx, |_, cx| { - let theme = &cx.app_state::().theme; + let theme = &cx.global::().theme; Label::new( format!( "Failed to download {} language server{}. Click to dismiss.", diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 4ee9eb97ae6a3bef77bdc5387dede2db9597098f..c388a16c2de6e9d100370d5f86ac8c24f5b58a4a 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -513,7 +513,7 @@ impl Pane { } fn render_tabs(&self, cx: &mut RenderContext) -> ElementBox { - let theme = cx.app_state::().theme.clone(); + let theme = cx.global::().theme.clone(); enum Tabs {} let tabs = MouseEventHandler::new::(0, cx, |mouse_state, cx| { diff --git a/crates/workspace/src/status_bar.rs b/crates/workspace/src/status_bar.rs index 782e51c706535fbe260f7e827d687449665cdf8f..4d00591787c9cf88e20ab9a60c705a73250421ee 100644 --- a/crates/workspace/src/status_bar.rs +++ b/crates/workspace/src/status_bar.rs @@ -38,7 +38,7 @@ impl View for StatusBar { } fn render(&mut self, cx: &mut RenderContext) -> ElementBox { - let theme = &cx.app_state::().theme.workspace.status_bar; + let theme = &cx.global::().theme.workspace.status_bar; Flex::row() .with_children(self.left_items.iter().map(|i| { ChildView::new(i.as_ref()) diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 92fcacaf85f2f72df3da40ec9f5937d171a03362..6481e2c8eeabe5e25991eefc2abe26669732823a 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -109,7 +109,7 @@ where V: Item, F: 'static + Fn(ModelHandle, ModelHandle, &mut ViewContext) -> V, { - cx.add_app_state::(Arc::new(move |window_id, project, model, cx| { + cx.set_global::(Arc::new(move |window_id, project, model, cx| { Box::new(cx.add_view(window_id, |cx| build_editor(project, model, cx))) })); } @@ -371,7 +371,7 @@ impl WorkspaceParams { #[cfg(any(test, feature = "test-support"))] pub fn test(cx: &mut MutableAppContext) -> Self { let settings = Settings::test(cx); - cx.add_app_state(settings); + cx.set_global(settings); let fs = project::FakeFs::new(cx.background().clone()); let languages = Arc::new(LanguageRegistry::test()); @@ -825,7 +825,7 @@ impl Workspace { .ok_or_else(|| anyhow!("buffer has no entry")) })?; let (window_id, build_editor) = this.update(&mut cx, |_, cx| { - (cx.window_id(), cx.app_state::().clone()) + (cx.window_id(), cx.global::().clone()) }); let build_editor = move |cx: &mut MutableAppContext| build_editor(window_id, project, buffer, cx); @@ -948,7 +948,7 @@ impl Workspace { } fn render_connection_status(&self, cx: &mut RenderContext) -> Option { - let theme = &cx.app_state::().theme; + let theme = &cx.global::().theme; match &*self.client.status().borrow() { client::Status::ConnectionError | client::Status::ConnectionLost @@ -1134,7 +1134,7 @@ impl Workspace { fn render_disconnected_overlay(&self, cx: &AppContext) -> Option { if self.project.read(cx).is_read_only() { - let theme = &cx.app_state::().theme; + let theme = &cx.global::().theme; Some( EventHandler::new( Label::new( @@ -1165,7 +1165,7 @@ impl View for Workspace { } fn render(&mut self, cx: &mut RenderContext) -> ElementBox { - let theme = cx.app_state::().theme.clone(); + let theme = cx.global::().theme.clone(); Stack::new() .with_child( Flex::column() diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 190a27973737cbb0ecd2be1eea1633c8bf90c0c3..cf149b2469d5c66ebecfaca239decda7cca01e2f 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -101,7 +101,7 @@ fn main() { cx.spawn(|mut cx| async move { while let Some(settings) = settings_rx.next().await { cx.update(|cx| { - cx.update_app_state(|s, _| *s = settings); + cx.update_global(|s, _| *s = settings); cx.refresh_windows(); }); } @@ -110,7 +110,7 @@ fn main() { languages.set_language_server_download_dir(zed::ROOT_PATH.clone()); languages.set_theme(&settings.theme.editor.syntax); - cx.add_app_state(settings); + cx.set_global(settings); let app_state = Arc::new(AppState { languages: Arc::new(languages), diff --git a/crates/zed/src/test.rs b/crates/zed/src/test.rs index f42e57c35d678570ca9ae559e0318d3b8356920e..5b3bb41c1523bf910a523766f6af2c9a631d264d 100644 --- a/crates/zed/src/test.rs +++ b/crates/zed/src/test.rs @@ -18,7 +18,7 @@ fn init_logger() { pub fn test_app_state(cx: &mut MutableAppContext) -> Arc { let settings = Settings::test(cx); editor::init(cx); - cx.add_app_state(settings); + cx.set_global(settings); let themes = ThemeRegistry::new(Assets, cx.font_cache().clone()); let http = FakeHttpClient::with_404_response(); let client = Client::new(http.clone()); diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 26b4150e240d9e182bc90a18dcf09a3fe38402f0..2b61279a2cf4fa29e85eac14d51817e27da55b24 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -43,7 +43,7 @@ pub fn init(app_state: &Arc, cx: &mut gpui::MutableAppContext) { cx.add_global_action(quit); cx.add_global_action({ move |action: &AdjustBufferFontSize, cx| { - cx.update_app_state::(|settings, cx| { + cx.update_global::(|settings, cx| { settings.buffer_font_size = (settings.buffer_font_size + action.0).max(MIN_FONT_SIZE); cx.refresh_windows(); From 6f9c37851ced80b02f88a2bc38d54a72f0b807a3 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 17 Mar 2022 14:39:02 +0100 Subject: [PATCH 12/14] Add `Editor::for_multibuffer` and repurpose `Editor::for_buffer` Co-Authored-By: Nathan Sobo --- crates/diagnostics/src/diagnostics.rs | 3 ++- crates/editor/src/editor.rs | 23 ++++++++++++++--------- crates/search/src/buffer_search.rs | 10 ++++++---- crates/search/src/project_search.rs | 2 +- crates/server/src/rpc.rs | 15 ++++----------- 5 files changed, 27 insertions(+), 26 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index a188761340c518f29a72f068c161c6c36ad21c6c..a1dd7be744ae4c2f79ee78075f620c60595ea640 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -113,7 +113,8 @@ impl ProjectDiagnosticsEditor { let excerpts = cx.add_model(|cx| MultiBuffer::new(project_handle.read(cx).replica_id())); let editor = cx.add_view(|cx| { - let mut editor = Editor::for_buffer(excerpts.clone(), Some(project_handle.clone()), cx); + let mut editor = + Editor::for_multibuffer(excerpts.clone(), Some(project_handle.clone()), cx); editor.set_vertical_scroll_margin(5, cx); editor }); diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 67d7d7cd90f12fecf97773e4a370d8beb1ec47f9..aa2c09519c0d3f7aec1ac68edbe1fb3c8913d4e1 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -341,7 +341,6 @@ pub fn init(cx: &mut MutableAppContext) { cx.add_async_action(Editor::find_all_references); workspace::register_editor_builder(cx, |project, buffer, cx| { - let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); Editor::for_buffer(buffer, Some(project), cx) }); } @@ -832,6 +831,15 @@ impl Editor { } pub fn for_buffer( + buffer: ModelHandle, + project: Option>, + cx: &mut ViewContext, + ) -> Self { + let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); + Self::new(EditorMode::Full, buffer, project, None, cx) + } + + pub fn for_multibuffer( buffer: ModelHandle, project: Option>, cx: &mut ViewContext, @@ -855,8 +863,7 @@ impl Editor { return item; } - let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - let editor = cx.add_view(|cx| Editor::for_buffer(multibuffer, Some(project.clone()), cx)); + let editor = cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)); workspace.add_item(Box::new(editor.clone()), cx); editor } @@ -969,11 +976,8 @@ impl Editor { .update(cx, |project, cx| project.create_buffer(cx)) .log_err() { - let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); workspace.add_item( - Box::new( - cx.add_view(|cx| Editor::for_buffer(multibuffer, Some(project.clone()), cx)), - ), + Box::new(cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))), cx, ); } @@ -2380,7 +2384,8 @@ impl Editor { workspace.update(&mut cx, |workspace, cx| { let project = workspace.project().clone(); - let editor = cx.add_view(|cx| Editor::for_buffer(excerpt_buffer, Some(project), cx)); + let editor = + cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx)); workspace.add_item(Box::new(editor.clone()), cx); editor.update(cx, |editor, cx| { let color = editor.style(cx).highlighted_line_background; @@ -4397,7 +4402,7 @@ impl Editor { workspace.update(&mut cx, |workspace, cx| { let editor = - cx.add_view(|cx| Editor::for_buffer(excerpt_buffer, Some(project), cx)); + cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx)); editor.update(cx, |editor, cx| { let color = editor.style(cx).highlighted_line_background; editor.highlight_background::(ranges_to_highlight, color, cx); diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index 9c4f67aae32a79166e330e9365a46f25e7484cda..8eae666c454ea2870301f4238cfd3e137da3fd9a 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -510,8 +510,9 @@ impl SearchBar { #[cfg(test)] mod tests { use super::*; - use editor::{DisplayPoint, Editor, MultiBuffer}; + use editor::{DisplayPoint, Editor}; use gpui::{color::Color, TestAppContext}; + use language::Buffer; use std::sync::Arc; use unindent::Unindent as _; @@ -523,9 +524,10 @@ mod tests { let settings = Settings::new("Courier", &fonts, Arc::new(theme)).unwrap(); cx.update(|cx| cx.set_global(settings)); - let buffer = cx.update(|cx| { - MultiBuffer::build_simple( - &r#" + let buffer = cx.add_model(|cx| { + Buffer::new( + 0, + r#" A regular expression (shortened as regex or regexp;[1] also referred to as rational expression[2][3]) is a sequence of characters that specifies a search pattern in text. Usually such patterns are used by string-searching algorithms diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 6e402ad4a3ceb6b1e77a5e06baaa73d08dadcf03..ef8ff3611ae675df8f7f86969b3c8adeaa9161cc 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -339,7 +339,7 @@ impl ProjectSearchView { }); let results_editor = cx.add_view(|cx| { - let mut editor = Editor::for_buffer(excerpts, Some(project), cx); + let mut editor = Editor::for_multibuffer(excerpts, Some(project), cx); editor.set_searchable(false); editor }); diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index 7f1b9f90ad7c0bd710fa79b075e78640ff279da1..7e9bb38021809685565033e5c007e07f4c2cf97a 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -1013,8 +1013,8 @@ mod tests { }; use collections::BTreeMap; use editor::{ - self, ConfirmCodeAction, ConfirmCompletion, ConfirmRename, Editor, Input, MultiBuffer, - Redo, Rename, ToOffset, ToggleCodeActions, Undo, + self, ConfirmCodeAction, ConfirmCompletion, ConfirmRename, Editor, Input, Redo, Rename, + ToOffset, ToggleCodeActions, Undo, }; use gpui::{executor, ModelHandle, TestAppContext}; use language::{ @@ -1140,10 +1140,7 @@ mod tests { .update(cx_b, |p, cx| p.open_buffer((worktree_id, "b.txt"), cx)) .await .unwrap(); - let buffer_b = cx_b.add_model(|cx| MultiBuffer::singleton(buffer_b, cx)); - buffer_b.read_with(cx_b, |buf, cx| { - assert_eq!(buf.read(cx).text(), "b-contents") - }); + buffer_b.read_with(cx_b, |buf, _| assert_eq!(buf.text(), "b-contents")); project_a.read_with(cx_a, |project, cx| { assert!(project.has_open_buffer((worktree_id, "b.txt"), cx)) }); @@ -2176,11 +2173,7 @@ mod tests { .unwrap(); let (window_b, _) = cx_b.add_window(|_| EmptyView); let editor_b = cx_b.add_view(window_b, |cx| { - Editor::for_buffer( - cx.add_model(|cx| MultiBuffer::singleton(buffer_b.clone(), cx)), - Some(project_b.clone()), - cx, - ) + Editor::for_buffer(buffer_b.clone(), Some(project_b.clone()), cx) }); let mut fake_language_server = fake_language_servers.next().await.unwrap(); From bff414cfbc48e4cceb6f8dc2930edc90caacbd08 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 17 Mar 2022 15:13:47 +0100 Subject: [PATCH 13/14] Remove `Editor::find_or_create` Co-Authored-By: Nathan Sobo --- crates/editor/src/editor.rs | 26 ++------------ crates/editor/src/items.rs | 16 +++++++-- crates/project/src/project.rs | 10 ++++++ crates/project_symbols/src/project_symbols.rs | 2 +- crates/workspace/src/pane.rs | 2 +- crates/workspace/src/workspace.rs | 35 +++++++++++++++++++ 6 files changed, 63 insertions(+), 28 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index aa2c09519c0d3f7aec1ac68edbe1fb3c8913d4e1..40d589bea71c6894422fd4cc985a9d3f9d0034d7 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -847,27 +847,6 @@ impl Editor { Self::new(EditorMode::Full, buffer, project, None, cx) } - pub fn find_or_create( - workspace: &mut Workspace, - buffer: ModelHandle, - cx: &mut ViewContext, - ) -> ViewHandle { - let project = workspace.project().clone(); - - if let Some(item) = project::File::from_dyn(buffer.read(cx).file()) - .and_then(|file| file.project_entry_id(cx)) - .and_then(|entry_id| workspace.active_pane().read(cx).item_for_entry(entry_id)) - .and_then(|item| item.downcast()) - { - workspace.activate_item(&item, cx); - return item; - } - - let editor = cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)); - workspace.add_item(Box::new(editor.clone()), cx); - editor - } - pub fn clone(&self, cx: &mut ViewContext) -> Self { let mut clone = Self::new( self.mode, @@ -4324,8 +4303,7 @@ impl Editor { for definition in definitions { let range = definition.range.to_offset(definition.buffer.read(cx)); - let target_editor_handle = - Self::find_or_create(workspace, definition.buffer, cx); + let target_editor_handle = workspace.open_project_item(definition.buffer, cx); target_editor_handle.update(cx, |target_editor, cx| { // When selecting a definition in a different buffer, disable the nav history // to avoid creating a history entry at the previous cursor location. @@ -5597,7 +5575,7 @@ impl Editor { workspace.activate_next_pane(cx); for (buffer, ranges) in new_selections_by_buffer.into_iter() { - let editor = Self::find_or_create(workspace, buffer, cx); + let editor = workspace.open_project_item::(buffer, cx); editor.update(cx, |editor, cx| { editor.select_ranges(ranges, Some(Autoscroll::Newest), cx); }); diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 60dd8ae303861f823d63c59e771df96c07b814fd..6f083f00a91eb1c18504be4e3c3efcd17f8ac866 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -4,13 +4,13 @@ use gpui::{ elements::*, AppContext, Entity, ModelHandle, RenderContext, Subscription, Task, View, ViewContext, ViewHandle, }; -use language::{Bias, Diagnostic, File as _}; +use language::{Bias, Buffer, Diagnostic, File as _}; use project::{File, Project, ProjectPath}; use std::fmt::Write; use std::path::PathBuf; use text::{Point, Selection}; use util::ResultExt; -use workspace::{Item, ItemHandle, ItemNavHistory, Settings, StatusItemView}; +use workspace::{Item, ItemHandle, ItemNavHistory, ProjectItem, Settings, StatusItemView}; impl Item for Editor { fn navigate(&mut self, data: Box, cx: &mut ViewContext) { @@ -132,6 +132,18 @@ impl Item for Editor { } } +impl ProjectItem for Editor { + type Item = Buffer; + + fn for_project_item( + project: ModelHandle, + buffer: ModelHandle, + cx: &mut ViewContext, + ) -> Self { + Self::for_buffer(buffer, Some(project), cx) + } +} + pub struct CursorPosition { position: Option, selected_count: usize, diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index ff535afafb06cf952c19cf92d700a388bbcbc3f6..c999b8ce4eb93228769fa782785af8e6b1b0f571 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -49,6 +49,10 @@ use util::{post_inc, ResultExt, TryFutureExt as _}; pub use fs::*; pub use worktree::*; +pub trait Item: Entity { + fn entry_id(&self, cx: &AppContext) -> Option; +} + pub struct Project { worktrees: Vec, active_entry: Option, @@ -4522,6 +4526,12 @@ fn relativize_path(base: &Path, path: &Path) -> PathBuf { components.iter().map(|c| c.as_os_str()).collect() } +impl Item for Buffer { + fn entry_id(&self, cx: &AppContext) -> Option { + File::from_dyn(self.file()).and_then(|file| file.project_entry_id(cx)) + } +} + #[cfg(test)] mod tests { use super::{Event, *}; diff --git a/crates/project_symbols/src/project_symbols.rs b/crates/project_symbols/src/project_symbols.rs index d79b2dedaeadc0e85a3469ca3e7e03b7e258e589..27e125a59205d39c9b3a647103ea7ada1fceb8a8 100644 --- a/crates/project_symbols/src/project_symbols.rs +++ b/crates/project_symbols/src/project_symbols.rs @@ -354,7 +354,7 @@ impl ProjectSymbolsView { .read(cx) .clip_point_utf16(symbol.range.start, Bias::Left); - let editor = Editor::find_or_create(workspace, buffer, cx); + let editor = workspace.open_project_item::(buffer, cx); editor.update(cx, |editor, cx| { editor.select_ranges( [position..position], diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index c388a16c2de6e9d100370d5f86ac8c24f5b58a4a..57a74b52ef405bcbe0457536caa852187cfe8c2c 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -280,7 +280,7 @@ impl Pane { } } - pub(crate) fn open_item( + pub fn open_item( &mut self, project_entry_id: ProjectEntryId, cx: &mut ViewContext, diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 6481e2c8eeabe5e25991eefc2abe26669732823a..d220dbc0fac755d2620577246f9b28bc6dcf895a 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -195,6 +195,16 @@ pub trait Item: View { } } +pub trait ProjectItem: Item { + type Item: project::Item; + + fn for_project_item( + project: ModelHandle, + item: ModelHandle, + cx: &mut ViewContext, + ) -> Self; +} + pub trait ItemHandle: 'static { fn tab_content(&self, style: &theme::Tab, cx: &AppContext) -> ElementBox; fn project_path(&self, cx: &AppContext) -> Option; @@ -833,6 +843,31 @@ impl Workspace { }) } + pub fn open_project_item( + &mut self, + project_item: ModelHandle, + cx: &mut ViewContext, + ) -> ViewHandle + where + T: ProjectItem, + { + use project::Item as _; + + if let Some(item) = project_item + .read(cx) + .entry_id(cx) + .and_then(|entry_id| self.active_pane().read(cx).item_for_entry(entry_id)) + .and_then(|item| item.downcast()) + { + self.activate_item(&item, cx); + return item; + } + + let item = cx.add_view(|cx| T::for_project_item(self.project().clone(), project_item, cx)); + self.add_item(Box::new(item.clone()), cx); + item + } + pub fn activate_item(&mut self, item: &dyn ItemHandle, cx: &mut ViewContext) -> bool { let result = self.panes.iter().find_map(|pane| { if let Some(ix) = pane.read(cx).index_for_item(item) { From 5d14c9abdf9397aef8605937288dd649132081c1 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 17 Mar 2022 15:54:34 +0100 Subject: [PATCH 14/14] Introduce `workspace::register_project_item` This lets downstream crates like `editor` define how project items should be opened. Co-Authored-By: Nathan Sobo --- Cargo.lock | 2 + crates/editor/src/editor.rs | 2 +- crates/file_finder/Cargo.toml | 2 + crates/file_finder/src/file_finder.rs | 7 +++ crates/gpui/src/app.rs | 34 ++++++++++++- crates/project/src/project.rs | 21 +++++++- crates/workspace/src/workspace.rs | 69 +++++++++++++++------------ 7 files changed, 102 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 28c433c43f85e7df2de479d96eaf99b3d1a453d0..4cfb831a58cd49ea148afd07382d7fd983795e58 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1782,7 +1782,9 @@ dependencies = [ name = "file_finder" version = "0.1.0" dependencies = [ + "ctor", "editor", + "env_logger", "fuzzy", "gpui", "postage", diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 40d589bea71c6894422fd4cc985a9d3f9d0034d7..30888d8a408ada78170e6dd6a39979392e085fe4 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -340,7 +340,7 @@ pub fn init(cx: &mut MutableAppContext) { cx.add_async_action(Editor::confirm_rename); cx.add_async_action(Editor::find_all_references); - workspace::register_editor_builder(cx, |project, buffer, cx| { + workspace::register_project_item(cx, |project, buffer, cx| { Editor::for_buffer(buffer, Some(project), cx) }); } diff --git a/crates/file_finder/Cargo.toml b/crates/file_finder/Cargo.toml index c5300dbcd9f47279aac127315e2d03f354aaae04..b946ea48fbbf58a7196f56949ececfe23fa1fd75 100644 --- a/crates/file_finder/Cargo.toml +++ b/crates/file_finder/Cargo.toml @@ -21,3 +21,5 @@ postage = { version = "0.4.1", features = ["futures-traits"] } gpui = { path = "../gpui", features = ["test-support"] } serde_json = { version = "1.0.64", features = ["preserve_order"] } workspace = { path = "../workspace", features = ["test-support"] } +ctor = "0.1" +env_logger = "0.8" diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 808f7e47031b9c08ba79e89330a990a2c8ed5440..ca41eb74a11cb2d08103c22e90eebff3ccef7d53 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -407,6 +407,13 @@ mod tests { use std::path::PathBuf; use workspace::{Workspace, WorkspaceParams}; + #[ctor::ctor] + fn init_logger() { + if std::env::var("RUST_LOG").is_ok() { + env_logger::init(); + } + } + #[gpui::test] async fn test_matching_paths(cx: &mut gpui::TestAppContext) { cx.update(|cx| { diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 097f9d7199fea07871db8522e0c2e1900bcdbb4c..5488d31416368a19f91f88c1d3bc51e2e7a6c264 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -1364,12 +1364,38 @@ impl MutableAppContext { Ok(pending) } + pub fn default_global(&mut self) -> &T { + self.cx + .globals + .entry(TypeId::of::()) + .or_insert_with(|| Box::new(T::default())) + .downcast_ref() + .unwrap() + } + pub fn set_global(&mut self, state: T) { self.cx.globals.insert(TypeId::of::(), Box::new(state)); } - pub fn update_global(&mut self, update: F) -> U + pub fn update_default_global(&mut self, update: F) -> U + where + T: 'static + Default, + F: FnOnce(&mut T, &mut MutableAppContext) -> U, + { + let type_id = TypeId::of::(); + let mut state = self + .cx + .globals + .remove(&type_id) + .unwrap_or_else(|| Box::new(T::default())); + let result = update(state.downcast_mut().unwrap(), self); + self.cx.globals.insert(type_id, state); + result + } + + pub fn update_global(&mut self, update: F) -> U where + T: 'static, F: FnOnce(&mut T, &mut MutableAppContext) -> U, { let type_id = TypeId::of::(); @@ -1377,7 +1403,7 @@ impl MutableAppContext { .cx .globals .remove(&type_id) - .expect("no app state has been added for this type"); + .expect("no global has been added for this type"); let result = update(state.downcast_mut().unwrap(), self); self.cx.globals.insert(type_id, state); result @@ -3715,6 +3741,10 @@ impl AnyModelHandle { pub fn is(&self) -> bool { self.model_type == TypeId::of::() } + + pub fn model_type(&self) -> TypeId { + self.model_type + } } impl From> for AnyModelHandle { diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index c999b8ce4eb93228769fa782785af8e6b1b0f571..317cf1ba028d19b920d04c4a70094adddb932b97 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -11,8 +11,8 @@ use collections::{hash_map, BTreeMap, HashMap, HashSet}; use futures::{future::Shared, Future, FutureExt, StreamExt, TryFutureExt}; use fuzzy::{PathMatch, PathMatchCandidate, PathMatchCandidateSet}; use gpui::{ - AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task, - UpgradeModelHandle, WeakModelHandle, + AnyModelHandle, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, + MutableAppContext, Task, UpgradeModelHandle, WeakModelHandle, }; use language::{ proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version}, @@ -822,6 +822,23 @@ impl Project { Ok(buffer) } + pub fn open_path( + &mut self, + path: impl Into, + cx: &mut ModelContext, + ) -> Task> { + let task = self.open_buffer(path, cx); + cx.spawn_weak(|_, cx| async move { + let buffer = task.await?; + let project_entry_id = buffer + .read_with(&cx, |buffer, cx| { + File::from_dyn(buffer.file()).and_then(|file| file.project_entry_id(cx)) + }) + .ok_or_else(|| anyhow!("no project entry"))?; + Ok((project_entry_id, buffer.into())) + }) + } + pub fn open_buffer( &mut self, path: impl Into, diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index d220dbc0fac755d2620577246f9b28bc6dcf895a..33155b5d4f4710338d6c4d4570af129f21e92624 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -9,6 +9,7 @@ mod status_bar; use anyhow::{anyhow, Result}; use client::{Authenticate, ChannelList, Client, User, UserStore}; use clock::ReplicaId; +use collections::HashMap; use gpui::{ action, color::Color, @@ -17,11 +18,11 @@ use gpui::{ json::{self, to_string_pretty, ToJson}, keymap::Binding, platform::{CursorStyle, WindowOptions}, - AnyViewHandle, AppContext, ClipboardItem, Entity, ImageData, ModelHandle, MutableAppContext, - PathPromptOptions, PromptLevel, RenderContext, Task, View, ViewContext, ViewHandle, - WeakViewHandle, + AnyModelHandle, AnyViewHandle, AppContext, ClipboardItem, Entity, ImageData, ModelHandle, + MutableAppContext, PathPromptOptions, PromptLevel, RenderContext, Task, View, ViewContext, + ViewHandle, WeakViewHandle, }; -use language::{Buffer, LanguageRegistry}; +use language::LanguageRegistry; use log::error; pub use pane::*; pub use pane_group::*; @@ -41,13 +42,16 @@ use std::{ }; use theme::{Theme, ThemeRegistry}; -pub type BuildEditor = Arc< - dyn Fn( - usize, - ModelHandle, - ModelHandle, - &mut MutableAppContext, - ) -> Box, +type ItemBuilders = HashMap< + TypeId, + Arc< + dyn Fn( + usize, + ModelHandle, + AnyModelHandle, + &mut MutableAppContext, + ) -> Box, + >, >; action!(Open, Arc); @@ -104,14 +108,20 @@ pub fn init(cx: &mut MutableAppContext) { ]); } -pub fn register_editor_builder(cx: &mut MutableAppContext, build_editor: F) +pub fn register_project_item(cx: &mut MutableAppContext, build_item: F) where - V: Item, - F: 'static + Fn(ModelHandle, ModelHandle, &mut ViewContext) -> V, + V: ProjectItem, + F: 'static + Fn(ModelHandle, ModelHandle, &mut ViewContext) -> V, { - cx.set_global::(Arc::new(move |window_id, project, model, cx| { - Box::new(cx.add_view(window_id, |cx| build_editor(project, model, cx))) - })); + cx.update_default_global(|builders: &mut ItemBuilders, _| { + builders.insert( + TypeId::of::(), + Arc::new(move |window_id, project, model, cx| { + let model = model.downcast::().unwrap(); + Box::new(cx.add_view(window_id, |cx| build_item(project, model, cx))) + }), + ); + }); } pub struct AppState { @@ -826,20 +836,19 @@ impl Workspace { )>, > { let project = self.project().clone(); - let buffer = project.update(cx, |project, cx| project.open_buffer(path, cx)); - cx.spawn(|this, mut cx| async move { - let buffer = buffer.await?; - let project_entry_id = buffer.read_with(&cx, |buffer, cx| { - project::File::from_dyn(buffer.file()) - .and_then(|file| file.project_entry_id(cx)) - .ok_or_else(|| anyhow!("buffer has no entry")) + let project_item = project.update(cx, |project, cx| project.open_path(path, cx)); + let window_id = cx.window_id(); + cx.as_mut().spawn(|mut cx| async move { + let (project_entry_id, project_item) = project_item.await?; + let build_item = cx.update(|cx| { + cx.default_global::() + .get(&project_item.model_type()) + .ok_or_else(|| anyhow!("no item builder for project item")) + .cloned() })?; - let (window_id, build_editor) = this.update(&mut cx, |_, cx| { - (cx.window_id(), cx.global::().clone()) - }); - let build_editor = - move |cx: &mut MutableAppContext| build_editor(window_id, project, buffer, cx); - Ok((project_entry_id, build_editor)) + let build_item = + move |cx: &mut MutableAppContext| build_item(window_id, project, project_item, cx); + Ok((project_entry_id, build_item)) }) }