mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-28 03:25:59 +00:00
Finish refactoring of how editors are opened
This commit is contained in:
parent
728c708150
commit
aced1e2315
12 changed files with 96 additions and 260 deletions
|
@ -144,7 +144,7 @@ impl ProjectDiagnosticsEditor {
|
||||||
let diagnostics = cx.add_view(|cx| {
|
let diagnostics = cx.add_view(|cx| {
|
||||||
ProjectDiagnosticsEditor::new(workspace.project().clone(), workspace_handle, cx)
|
ProjectDiagnosticsEditor::new(workspace.project().clone(), workspace_handle, cx)
|
||||||
});
|
});
|
||||||
workspace.open_item(Box::new(diagnostics), cx);
|
workspace.add_item(Box::new(diagnostics), cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ pub use sum_tree::Bias;
|
||||||
use text::rope::TextDimension;
|
use text::rope::TextDimension;
|
||||||
use theme::DiagnosticStyle;
|
use theme::DiagnosticStyle;
|
||||||
use util::{post_inc, ResultExt, TryFutureExt};
|
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 CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
|
||||||
const MAX_LINE_LEN: usize = 1024;
|
const MAX_LINE_LEN: usize = 1024;
|
||||||
|
@ -141,8 +141,7 @@ pub enum Direction {
|
||||||
Next,
|
Next,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(cx: &mut MutableAppContext, path_openers: &mut Vec<Box<dyn PathOpener>>) {
|
pub fn init(cx: &mut MutableAppContext) {
|
||||||
path_openers.push(Box::new(items::BufferOpener));
|
|
||||||
cx.add_bindings(vec![
|
cx.add_bindings(vec![
|
||||||
Binding::new("escape", Cancel, Some("Editor")),
|
Binding::new("escape", Cancel, Some("Editor")),
|
||||||
Binding::new("backspace", Backspace, Some("Editor")),
|
Binding::new("backspace", Backspace, Some("Editor")),
|
||||||
|
@ -340,6 +339,11 @@ pub fn init(cx: &mut MutableAppContext, path_openers: &mut Vec<Box<dyn PathOpene
|
||||||
cx.add_async_action(Editor::rename);
|
cx.add_async_action(Editor::rename);
|
||||||
cx.add_async_action(Editor::confirm_rename);
|
cx.add_async_action(Editor::confirm_rename);
|
||||||
cx.add_async_action(Editor::find_all_references);
|
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)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
trait SelectionExt {
|
trait SelectionExt {
|
||||||
|
@ -842,18 +846,17 @@ impl Editor {
|
||||||
) -> ViewHandle<Editor> {
|
) -> ViewHandle<Editor> {
|
||||||
let project = workspace.project().clone();
|
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(|file| file.project_entry_id(cx))
|
||||||
|
.and_then(|entry_id| workspace.item_for_entry(entry_id, cx))
|
||||||
|
.and_then(|item| item.downcast())
|
||||||
{
|
{
|
||||||
return workspace
|
return item;
|
||||||
.open_editor(project_entry, cx)
|
|
||||||
.downcast::<Editor>()
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
|
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(multibuffer, Some(project.clone()), cx));
|
||||||
workspace.open_item(Box::new(editor.clone()), cx);
|
workspace.add_item(Box::new(editor.clone()), cx);
|
||||||
editor
|
editor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -966,7 +969,7 @@ impl Editor {
|
||||||
.log_err()
|
.log_err()
|
||||||
{
|
{
|
||||||
let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
|
let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
|
||||||
workspace.open_item(
|
workspace.add_item(
|
||||||
Box::new(
|
Box::new(
|
||||||
cx.add_view(|cx| Editor::for_buffer(multibuffer, Some(project.clone()), cx)),
|
cx.add_view(|cx| Editor::for_buffer(multibuffer, Some(project.clone()), cx)),
|
||||||
),
|
),
|
||||||
|
@ -2376,16 +2379,12 @@ impl Editor {
|
||||||
|
|
||||||
workspace.update(&mut cx, |workspace, cx| {
|
workspace.update(&mut cx, |workspace, cx| {
|
||||||
let project = workspace.project().clone();
|
let project = workspace.project().clone();
|
||||||
let editor = workspace.open_item(
|
let editor = cx.add_view(|cx| Editor::for_buffer(excerpt_buffer, Some(project), cx));
|
||||||
Box::new(cx.add_view(|cx| Editor::for_buffer(excerpt_buffer, Some(project), cx))),
|
workspace.add_item(Box::new(editor.clone()), cx);
|
||||||
cx,
|
|
||||||
);
|
|
||||||
if let Some(editor) = editor.act_as::<Self>(cx) {
|
|
||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
let color = editor.style(cx).highlighted_line_background;
|
let color = editor.style(cx).highlighted_line_background;
|
||||||
editor.highlight_background::<Self>(ranges_to_highlight, color, cx);
|
editor.highlight_background::<Self>(ranges_to_highlight, color, cx);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -4402,7 +4401,7 @@ impl Editor {
|
||||||
let color = editor.style(cx).highlighted_line_background;
|
let color = editor.style(cx).highlighted_line_background;
|
||||||
editor.highlight_background::<Self>(ranges_to_highlight, color, cx);
|
editor.highlight_background::<Self>(ranges_to_highlight, color, cx);
|
||||||
});
|
});
|
||||||
workspace.open_item(Box::new(editor), cx);
|
workspace.add_item(Box::new(editor), cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::{Autoscroll, Editor, Event, MultiBuffer, NavigationData, ToOffset, ToPoint as _};
|
use crate::{Autoscroll, Editor, Event, MultiBuffer, NavigationData, ToOffset, ToPoint as _};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
elements::*, AppContext, Entity, ModelContext, ModelHandle, RenderContext, Subscription, Task,
|
elements::*, AppContext, Entity, ModelHandle, RenderContext, Subscription, Task, View,
|
||||||
View, ViewContext, ViewHandle, WeakModelHandle,
|
ViewContext, ViewHandle, WeakModelHandle,
|
||||||
};
|
};
|
||||||
use language::{Bias, Buffer, Diagnostic, File as _};
|
use language::{Bias, Buffer, Diagnostic, File as _};
|
||||||
use project::{File, Project, ProjectPath};
|
use project::{File, Project, ProjectPath};
|
||||||
|
@ -10,9 +10,7 @@ use std::fmt::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use text::{Point, Selection};
|
use text::{Point, Selection};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use workspace::{ItemNavHistory, ItemView, ItemViewHandle, PathOpener, Settings, StatusItemView};
|
use workspace::{ItemNavHistory, ItemView, ItemViewHandle, Settings, StatusItemView};
|
||||||
|
|
||||||
pub struct BufferOpener;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BufferItemHandle(pub ModelHandle<Buffer>);
|
pub struct BufferItemHandle(pub ModelHandle<Buffer>);
|
||||||
|
@ -26,26 +24,6 @@ pub struct MultiBufferItemHandle(pub ModelHandle<MultiBuffer>);
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct WeakMultiBufferItemHandle(WeakModelHandle<MultiBuffer>);
|
struct WeakMultiBufferItemHandle(WeakModelHandle<MultiBuffer>);
|
||||||
|
|
||||||
impl PathOpener for BufferOpener {
|
|
||||||
fn open(
|
|
||||||
&self,
|
|
||||||
project: &mut Project,
|
|
||||||
project_path: ProjectPath,
|
|
||||||
window_id: usize,
|
|
||||||
cx: &mut ModelContext<Project>,
|
|
||||||
) -> Option<Task<Result<Box<dyn ItemViewHandle>>>> {
|
|
||||||
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<dyn ItemViewHandle>)
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ItemView for Editor {
|
impl ItemView for Editor {
|
||||||
fn navigate(&mut self, data: Box<dyn std::any::Any>, cx: &mut ViewContext<Self>) {
|
fn navigate(&mut self, data: Box<dyn std::any::Any>, cx: &mut ViewContext<Self>) {
|
||||||
if let Some(data) = data.downcast_ref::<NavigationData>() {
|
if let Some(data) = data.downcast_ref::<NavigationData>() {
|
||||||
|
|
|
@ -409,14 +409,12 @@ mod tests {
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_matching_paths(cx: &mut gpui::TestAppContext) {
|
async fn test_matching_paths(cx: &mut gpui::TestAppContext) {
|
||||||
let mut path_openers = Vec::new();
|
|
||||||
cx.update(|cx| {
|
cx.update(|cx| {
|
||||||
super::init(cx);
|
super::init(cx);
|
||||||
editor::init(cx, &mut path_openers);
|
editor::init(cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut params = cx.update(WorkspaceParams::test);
|
let params = cx.update(WorkspaceParams::test);
|
||||||
params.path_openers = Arc::from(path_openers);
|
|
||||||
params
|
params
|
||||||
.fs
|
.fs
|
||||||
.as_fake()
|
.as_fake()
|
||||||
|
|
|
@ -3473,6 +3473,12 @@ impl<T> PartialEq<WeakViewHandle<T>> for ViewHandle<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> PartialEq<ViewHandle<T>> for WeakViewHandle<T> {
|
||||||
|
fn eq(&self, other: &ViewHandle<T>) -> bool {
|
||||||
|
self.window_id == other.window_id && self.view_id == other.view_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Eq for ViewHandle<T> {}
|
impl<T> Eq for ViewHandle<T> {}
|
||||||
|
|
||||||
impl<T> Debug for ViewHandle<T> {
|
impl<T> Debug for ViewHandle<T> {
|
||||||
|
|
|
@ -391,7 +391,7 @@ impl ProjectSearchView {
|
||||||
workspace.activate_item(&existing, cx);
|
workspace.activate_item(&existing, cx);
|
||||||
} else {
|
} else {
|
||||||
let model = cx.add_model(|cx| ProjectSearch::new(workspace.project().clone(), cx));
|
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))),
|
Box::new(cx.add_view(|cx| ProjectSearchView::new(model, cx))),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
@ -429,7 +429,7 @@ impl ProjectSearchView {
|
||||||
model.search(new_query, cx);
|
model.search(new_query, cx);
|
||||||
model
|
model
|
||||||
});
|
});
|
||||||
workspace.open_item(
|
workspace.add_item(
|
||||||
Box::new(cx.add_view(|cx| ProjectSearchView::new(model, cx))),
|
Box::new(cx.add_view(|cx| ProjectSearchView::new(model, cx))),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
|
@ -3201,8 +3201,7 @@ mod tests {
|
||||||
cx_a.foreground().forbid_parking();
|
cx_a.foreground().forbid_parking();
|
||||||
let mut lang_registry = Arc::new(LanguageRegistry::test());
|
let mut lang_registry = Arc::new(LanguageRegistry::test());
|
||||||
let fs = FakeFs::new(cx_a.background());
|
let fs = FakeFs::new(cx_a.background());
|
||||||
let mut path_openers_b = Vec::new();
|
cx_b.update(|cx| editor::init(cx));
|
||||||
cx_b.update(|cx| editor::init(cx, &mut path_openers_b));
|
|
||||||
|
|
||||||
// Set up a fake language server.
|
// Set up a fake language server.
|
||||||
let (language_server_config, mut fake_language_servers) = LanguageServerConfig::fake();
|
let (language_server_config, mut fake_language_servers) = LanguageServerConfig::fake();
|
||||||
|
@ -3271,7 +3270,6 @@ mod tests {
|
||||||
params.client = client_b.client.clone();
|
params.client = client_b.client.clone();
|
||||||
params.user_store = client_b.user_store.clone();
|
params.user_store = client_b.user_store.clone();
|
||||||
params.project = project_b;
|
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 (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(¶ms, cx));
|
||||||
let editor_b = workspace_b
|
let editor_b = workspace_b
|
||||||
|
@ -3437,8 +3435,7 @@ mod tests {
|
||||||
cx_a.foreground().forbid_parking();
|
cx_a.foreground().forbid_parking();
|
||||||
let mut lang_registry = Arc::new(LanguageRegistry::test());
|
let mut lang_registry = Arc::new(LanguageRegistry::test());
|
||||||
let fs = FakeFs::new(cx_a.background());
|
let fs = FakeFs::new(cx_a.background());
|
||||||
let mut path_openers_b = Vec::new();
|
cx_b.update(|cx| editor::init(cx));
|
||||||
cx_b.update(|cx| editor::init(cx, &mut path_openers_b));
|
|
||||||
|
|
||||||
// Set up a fake language server.
|
// Set up a fake language server.
|
||||||
let (language_server_config, mut fake_language_servers) = LanguageServerConfig::fake();
|
let (language_server_config, mut fake_language_servers) = LanguageServerConfig::fake();
|
||||||
|
@ -3507,7 +3504,6 @@ mod tests {
|
||||||
params.client = client_b.client.clone();
|
params.client = client_b.client.clone();
|
||||||
params.user_store = client_b.user_store.clone();
|
params.user_store = client_b.user_store.clone();
|
||||||
params.project = project_b;
|
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 (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(¶ms, cx));
|
||||||
let editor_b = workspace_b
|
let editor_b = workspace_b
|
||||||
|
|
|
@ -253,12 +253,12 @@ impl Pane {
|
||||||
let pane = pane.downgrade();
|
let pane = pane.downgrade();
|
||||||
let task = workspace.load_path(project_path, cx);
|
let task = workspace.load_path(project_path, cx);
|
||||||
cx.spawn(|workspace, mut cx| async move {
|
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(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.update(&mut cx, |pane, cx| {
|
||||||
pane.nav_history.borrow_mut().set_mode(mode);
|
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
|
pane.nav_history
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.set_mode(NavigationMode::Normal);
|
.set_mode(NavigationMode::Normal);
|
||||||
|
@ -280,7 +280,7 @@ impl Pane {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn open_editor(
|
pub(crate) fn open_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
project_entry_id: ProjectEntryId,
|
project_entry_id: ProjectEntryId,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
|
@ -299,14 +299,6 @@ impl Pane {
|
||||||
item_view
|
item_view
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_item(
|
|
||||||
&mut self,
|
|
||||||
item_view_to_open: Box<dyn ItemViewHandle>,
|
|
||||||
cx: &mut ViewContext<Self>,
|
|
||||||
) {
|
|
||||||
self.add_item(None, item_view_to_open.boxed_clone(), cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn add_item(
|
pub(crate) fn add_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
project_entry_id: Option<ProjectEntryId>,
|
project_entry_id: Option<ProjectEntryId>,
|
||||||
|
|
|
@ -9,7 +9,6 @@ mod status_bar;
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use client::{Authenticate, ChannelList, Client, User, UserStore};
|
use client::{Authenticate, ChannelList, Client, User, UserStore};
|
||||||
use clock::ReplicaId;
|
use clock::ReplicaId;
|
||||||
use futures::TryFutureExt;
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
action,
|
action,
|
||||||
color::Color,
|
color::Color,
|
||||||
|
@ -18,9 +17,9 @@ use gpui::{
|
||||||
json::{self, to_string_pretty, ToJson},
|
json::{self, to_string_pretty, ToJson},
|
||||||
keymap::Binding,
|
keymap::Binding,
|
||||||
platform::{CursorStyle, WindowOptions},
|
platform::{CursorStyle, WindowOptions},
|
||||||
AnyViewHandle, AppContext, ClipboardItem, Entity, ImageData, ModelContext, ModelHandle,
|
AnyViewHandle, AppContext, ClipboardItem, Entity, ImageData, ModelHandle, MutableAppContext,
|
||||||
MutableAppContext, PathPromptOptions, PromptLevel, RenderContext, Task, View, ViewContext,
|
PathPromptOptions, PromptLevel, RenderContext, Task, View, ViewContext, ViewHandle,
|
||||||
ViewHandle, WeakViewHandle,
|
WeakViewHandle,
|
||||||
};
|
};
|
||||||
use language::{Buffer, LanguageRegistry};
|
use language::{Buffer, LanguageRegistry};
|
||||||
use log::error;
|
use log::error;
|
||||||
|
@ -42,7 +41,7 @@ use std::{
|
||||||
};
|
};
|
||||||
use theme::{Theme, ThemeRegistry};
|
use theme::{Theme, ThemeRegistry};
|
||||||
|
|
||||||
pub type BuildEditor = Box<
|
pub type BuildEditor = Arc<
|
||||||
dyn Fn(
|
dyn Fn(
|
||||||
usize,
|
usize,
|
||||||
ModelHandle<Project>,
|
ModelHandle<Project>,
|
||||||
|
@ -110,7 +109,7 @@ where
|
||||||
V: ItemView,
|
V: ItemView,
|
||||||
F: 'static + Fn(ModelHandle<Project>, ModelHandle<Buffer>, &mut ViewContext<V>) -> V,
|
F: 'static + Fn(ModelHandle<Project>, ModelHandle<Buffer>, &mut ViewContext<V>) -> V,
|
||||||
{
|
{
|
||||||
cx.add_app_state::<BuildEditor>(Box::new(|window_id, project, model, cx| {
|
cx.add_app_state::<BuildEditor>(Arc::new(move |window_id, project, model, cx| {
|
||||||
Box::new(cx.add_view(window_id, |cx| build_editor(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<client::UserStore>,
|
pub user_store: ModelHandle<client::UserStore>,
|
||||||
pub fs: Arc<dyn fs::Fs>,
|
pub fs: Arc<dyn fs::Fs>,
|
||||||
pub channel_list: ModelHandle<client::ChannelList>,
|
pub channel_list: ModelHandle<client::ChannelList>,
|
||||||
pub path_openers: Arc<[Box<dyn PathOpener>]>,
|
|
||||||
pub build_window_options: &'static dyn Fn() -> WindowOptions<'static>,
|
pub build_window_options: &'static dyn Fn() -> WindowOptions<'static>,
|
||||||
pub build_workspace: &'static dyn Fn(
|
pub build_workspace: &'static dyn Fn(
|
||||||
ModelHandle<Project>,
|
ModelHandle<Project>,
|
||||||
|
@ -143,16 +141,6 @@ pub struct JoinProjectParams {
|
||||||
pub app_state: Arc<AppState>,
|
pub app_state: Arc<AppState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PathOpener {
|
|
||||||
fn open(
|
|
||||||
&self,
|
|
||||||
project: &mut Project,
|
|
||||||
path: ProjectPath,
|
|
||||||
window_id: usize,
|
|
||||||
cx: &mut ModelContext<Project>,
|
|
||||||
) -> Option<Task<Result<Box<dyn ItemViewHandle>>>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ItemView: View {
|
pub trait ItemView: View {
|
||||||
fn deactivated(&mut self, _: &mut ViewContext<Self>) {}
|
fn deactivated(&mut self, _: &mut ViewContext<Self>) {}
|
||||||
fn navigate(&mut self, _: Box<dyn Any>, _: &mut ViewContext<Self>) {}
|
fn navigate(&mut self, _: Box<dyn Any>, _: &mut ViewContext<Self>) {}
|
||||||
|
@ -378,7 +366,6 @@ pub struct WorkspaceParams {
|
||||||
pub languages: Arc<LanguageRegistry>,
|
pub languages: Arc<LanguageRegistry>,
|
||||||
pub user_store: ModelHandle<UserStore>,
|
pub user_store: ModelHandle<UserStore>,
|
||||||
pub channel_list: ModelHandle<ChannelList>,
|
pub channel_list: ModelHandle<ChannelList>,
|
||||||
pub path_openers: Arc<[Box<dyn PathOpener>]>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkspaceParams {
|
impl WorkspaceParams {
|
||||||
|
@ -409,7 +396,6 @@ impl WorkspaceParams {
|
||||||
fs,
|
fs,
|
||||||
languages,
|
languages,
|
||||||
user_store,
|
user_store,
|
||||||
path_openers: Arc::from([]),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,7 +414,6 @@ impl WorkspaceParams {
|
||||||
languages: app_state.languages.clone(),
|
languages: app_state.languages.clone(),
|
||||||
user_store: app_state.user_store.clone(),
|
user_store: app_state.user_store.clone(),
|
||||||
channel_list: app_state.channel_list.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<Pane>,
|
active_pane: ViewHandle<Pane>,
|
||||||
status_bar: ViewHandle<StatusBar>,
|
status_bar: ViewHandle<StatusBar>,
|
||||||
project: ModelHandle<Project>,
|
project: ModelHandle<Project>,
|
||||||
path_openers: Arc<[Box<dyn PathOpener>]>,
|
|
||||||
// items: BTreeMap<Reverse<usize>, Box<dyn WeakItemHandle>>,
|
// items: BTreeMap<Reverse<usize>, Box<dyn WeakItemHandle>>,
|
||||||
_observe_current_user: Task<()>,
|
_observe_current_user: Task<()>,
|
||||||
}
|
}
|
||||||
|
@ -510,7 +494,6 @@ impl Workspace {
|
||||||
left_sidebar: Sidebar::new(Side::Left),
|
left_sidebar: Sidebar::new(Side::Left),
|
||||||
right_sidebar: Sidebar::new(Side::Right),
|
right_sidebar: Sidebar::new(Side::Right),
|
||||||
project: params.project.clone(),
|
project: params.project.clone(),
|
||||||
path_openers: params.path_openers.clone(),
|
|
||||||
_observe_current_user,
|
_observe_current_user,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -665,76 +648,14 @@ impl Workspace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_path(
|
pub fn item_for_entry(
|
||||||
&mut self,
|
&self,
|
||||||
path: ProjectPath,
|
entry_id: ProjectEntryId,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &AppContext,
|
||||||
) -> Task<Result<Box<dyn ItemViewHandle>, Arc<anyhow::Error>>> {
|
) -> Option<Box<dyn ItemViewHandle>> {
|
||||||
let project_entry = self.project.read(cx).entry_for_path(&path, cx);
|
self.panes()
|
||||||
|
|
||||||
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<Self>,
|
|
||||||
) -> Task<Result<Box<dyn ItemViewHandle>>> {
|
|
||||||
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<Self>,
|
|
||||||
) -> Task<Result<Box<dyn ItemViewHandle>>> {
|
|
||||||
if let Some(existing_item) = self
|
|
||||||
.panes
|
|
||||||
.iter()
|
.iter()
|
||||||
.find_map(|pane| pane.read(cx).item_for_entry(project_entry))
|
.find_map(|pane| pane.read(cx).item_for_entry(entry_id))
|
||||||
{
|
|
||||||
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 item_of_type<T: ItemView>(&self, cx: &AppContext) -> Option<ViewHandle<T>> {
|
pub fn item_of_type<T: ItemView>(&self, cx: &AppContext) -> Option<ViewHandle<T>> {
|
||||||
|
@ -871,107 +792,58 @@ impl Workspace {
|
||||||
pane
|
pane
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_item(&mut self, item_view: Box<dyn ItemViewHandle>, cx: &mut ViewContext<Self>) {
|
pub fn add_item(&mut self, item_view: Box<dyn ItemViewHandle>, cx: &mut ViewContext<Self>) {
|
||||||
self.active_pane()
|
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,
|
&mut self,
|
||||||
project_entry: ProjectEntryId,
|
path: ProjectPath,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Task<Result<Box<dyn ItemViewHandle>, Arc<anyhow::Error>>> {
|
) -> Task<Result<Box<dyn ItemViewHandle>, Arc<anyhow::Error>>> {
|
||||||
let pane = self.active_pane().clone();
|
let pane = self.active_pane().downgrade();
|
||||||
let project = self.project().clone();
|
let task = self.load_path(path, cx);
|
||||||
let buffer = project.update(cx, |project, cx| {
|
cx.spawn(|this, mut cx| async move {
|
||||||
project.open_buffer_for_entry(project_entry, cx)
|
let (project_entry_id, build_editor) = task.await?;
|
||||||
});
|
let pane = pane
|
||||||
|
.upgrade(&cx)
|
||||||
cx.spawn(|this, cx| async move {
|
.ok_or_else(|| anyhow!("pane was closed"))?;
|
||||||
let buffer = buffer.await?;
|
this.update(&mut cx, |_, cx| {
|
||||||
let editor = this.update(&mut cx, |this, cx| {
|
|
||||||
let window_id = cx.window_id();
|
|
||||||
pane.update(cx, |pane, cx| {
|
pane.update(cx, |pane, cx| {
|
||||||
pane.open_editor(project_entry, cx, |cx| {
|
Ok(pane.open_item(project_entry_id, cx, build_editor))
|
||||||
cx.app_state::<BuildEditor>()(window_id, project, buffer, cx)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
});
|
|
||||||
Ok(editor)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn open_path(
|
pub(crate) fn load_path(
|
||||||
// &mut self,
|
&mut self,
|
||||||
// path: ProjectPath,
|
path: ProjectPath,
|
||||||
// cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
// ) -> Task<Result<Box<dyn ItemViewHandle>, Arc<anyhow::Error>>> {
|
) -> Task<
|
||||||
// let project_entry = self.project.read(cx).entry_for_path(&path, cx);
|
Result<(
|
||||||
|
ProjectEntryId,
|
||||||
// let existing_entry = self
|
impl 'static + FnOnce(&mut MutableAppContext) -> Box<dyn ItemViewHandle>,
|
||||||
// .active_pane()
|
)>,
|
||||||
// .update(cx, |pane, cx| pane.activate_project_entry(project_entry));
|
> {
|
||||||
|
let project = self.project().clone();
|
||||||
// cx.spawn(|this, cx| {
|
let buffer = project.update(cx, |project, cx| project.open_buffer_for_path(path, cx));
|
||||||
// if let Some(existing_entry) = existing_entry {
|
cx.spawn(|this, mut cx| async move {
|
||||||
// return Ok(existing_entry);
|
let buffer = buffer.await?;
|
||||||
// }
|
let project_entry_id = buffer.read_with(&cx, |buffer, cx| {
|
||||||
|
project::File::from_dyn(buffer.file())
|
||||||
// let load_task = this
|
.and_then(|file| file.project_entry_id(cx))
|
||||||
// .update(&mut cx, |this, cx| {
|
.ok_or_else(|| anyhow!("buffer has no entry"))
|
||||||
// this.load_project_entry(project_entry, cx)
|
})?;
|
||||||
// })
|
let (window_id, build_editor) = this.update(&mut cx, |_, cx| {
|
||||||
// .await;
|
(cx.window_id(), cx.app_state::<BuildEditor>().clone())
|
||||||
// });
|
});
|
||||||
|
let build_editor =
|
||||||
// let load_task = self.load_path(path, cx);
|
move |cx: &mut MutableAppContext| build_editor(window_id, project, buffer, cx);
|
||||||
// let pane = self.active_pane().clone().downgrade();
|
Ok((project_entry_id, build_editor))
|
||||||
// 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<Self>,
|
|
||||||
// ) -> Task<Result<Box<dyn ItemViewHandle>>> {
|
|
||||||
// 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<Self>,
|
|
||||||
// ) -> Task<Result<Box<dyn ItemViewHandle>>> {
|
|
||||||
// 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<Self>) -> bool {
|
pub fn activate_item(&mut self, item: &dyn ItemViewHandle, cx: &mut ViewContext<Self>) -> bool {
|
||||||
let result = self.panes.iter().find_map(|pane| {
|
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());
|
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()) {
|
if let Some(clone) = item.clone_on_split(cx.as_mut()) {
|
||||||
new_pane.update(cx, |new_pane, cx| {
|
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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,6 @@ fn main() {
|
||||||
app.run(move |cx| {
|
app.run(move |cx| {
|
||||||
let http = http::client();
|
let http = http::client();
|
||||||
let client = client::Client::new(http.clone());
|
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 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 user_store = cx.add_model(|cx| UserStore::new(client.clone(), http.clone(), cx));
|
||||||
let channel_list =
|
let channel_list =
|
||||||
|
@ -71,7 +70,7 @@ fn main() {
|
||||||
client::Channel::init(&client);
|
client::Channel::init(&client);
|
||||||
client::init(client.clone(), cx);
|
client::init(client.clone(), cx);
|
||||||
workspace::init(cx);
|
workspace::init(cx);
|
||||||
editor::init(cx, &mut path_openers);
|
editor::init(cx);
|
||||||
go_to_line::init(cx);
|
go_to_line::init(cx);
|
||||||
file_finder::init(cx);
|
file_finder::init(cx);
|
||||||
chat_panel::init(cx);
|
chat_panel::init(cx);
|
||||||
|
@ -120,7 +119,6 @@ fn main() {
|
||||||
client,
|
client,
|
||||||
user_store,
|
user_store,
|
||||||
fs,
|
fs,
|
||||||
path_openers: Arc::from(path_openers),
|
|
||||||
build_window_options: &build_window_options,
|
build_window_options: &build_window_options,
|
||||||
build_workspace: &build_workspace,
|
build_workspace: &build_workspace,
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,8 +17,7 @@ fn init_logger() {
|
||||||
|
|
||||||
pub fn test_app_state(cx: &mut MutableAppContext) -> Arc<AppState> {
|
pub fn test_app_state(cx: &mut MutableAppContext) -> Arc<AppState> {
|
||||||
let settings = Settings::test(cx);
|
let settings = Settings::test(cx);
|
||||||
let mut path_openers = Vec::new();
|
editor::init(cx);
|
||||||
editor::init(cx, &mut path_openers);
|
|
||||||
cx.add_app_state(settings);
|
cx.add_app_state(settings);
|
||||||
let themes = ThemeRegistry::new(Assets, cx.font_cache().clone());
|
let themes = ThemeRegistry::new(Assets, cx.font_cache().clone());
|
||||||
let http = FakeHttpClient::with_404_response();
|
let http = FakeHttpClient::with_404_response();
|
||||||
|
@ -40,7 +39,6 @@ pub fn test_app_state(cx: &mut MutableAppContext) -> Arc<AppState> {
|
||||||
client,
|
client,
|
||||||
user_store,
|
user_store,
|
||||||
fs: FakeFs::new(cx.background().clone()),
|
fs: FakeFs::new(cx.background().clone()),
|
||||||
path_openers: Arc::from(path_openers),
|
|
||||||
build_window_options: &build_window_options,
|
build_window_options: &build_window_options,
|
||||||
build_workspace: &build_workspace,
|
build_workspace: &build_workspace,
|
||||||
})
|
})
|
||||||
|
|
|
@ -111,7 +111,6 @@ pub fn build_workspace(
|
||||||
languages: app_state.languages.clone(),
|
languages: app_state.languages.clone(),
|
||||||
user_store: app_state.user_store.clone(),
|
user_store: app_state.user_store.clone(),
|
||||||
channel_list: app_state.channel_list.clone(),
|
channel_list: app_state.channel_list.clone(),
|
||||||
path_openers: app_state.path_openers.clone(),
|
|
||||||
};
|
};
|
||||||
let mut workspace = Workspace::new(&workspace_params, cx);
|
let mut workspace = Workspace::new(&workspace_params, cx);
|
||||||
let project = workspace.project().clone();
|
let project = workspace.project().clone();
|
||||||
|
|
Loading…
Reference in a new issue