Invert dependency between editor and workspace

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2021-11-24 17:07:16 +01:00
parent 2cf44d30b7
commit e88d3bb97e
10 changed files with 580 additions and 536 deletions

3
Cargo.lock generated
View File

@ -1543,6 +1543,7 @@ dependencies = [
"tree-sitter-rust",
"unindent",
"util",
"workspace",
]
[[package]]
@ -5612,9 +5613,7 @@ name = "workspace"
version = "0.1.0"
dependencies = [
"anyhow",
"buffer",
"client",
"editor",
"gpui",
"language",
"log",

View File

@ -19,6 +19,7 @@ project = { path = "../project" }
sum_tree = { path = "../sum_tree" }
theme = { path = "../theme" }
util = { path = "../util" }
workspace = { path = "../workspace" }
anyhow = "1.0"
lazy_static = "1.4"
log = "0.4"

View File

@ -1,66 +1,110 @@
use super::{Item, ItemView};
use crate::{status_bar::StatusItemView, Settings};
use crate::{Editor, EditorSettings, Event};
use anyhow::Result;
use buffer::{Point, Selection, ToPoint};
use editor::{Editor, EditorSettings, Event};
use gpui::{
elements::*, fonts::TextStyle, AppContext, Entity, ModelHandle, RenderContext, Subscription,
Task, View, ViewContext, ViewHandle,
elements::*, fonts::TextStyle, AppContext, Entity, ModelContext, ModelHandle,
MutableAppContext, RenderContext, Subscription, Task, View, ViewContext, ViewHandle,
WeakModelHandle,
};
use language::{Buffer, Diagnostic, File as _};
use postage::watch;
use project::{ProjectPath, Worktree};
use std::fmt::Write;
use std::path::Path;
use workspace::{
EntryOpener, ItemHandle, ItemView, ItemViewHandle, Settings, StatusItemView, WeakItemHandle,
};
impl Item for Buffer {
type View = Editor;
pub struct BufferOpener;
fn build_view(
handle: ModelHandle<Self>,
#[derive(Clone)]
pub struct BufferItemHandle(pub ModelHandle<Buffer>);
#[derive(Clone)]
struct WeakBufferItemHandle(WeakModelHandle<Buffer>);
impl EntryOpener for BufferOpener {
fn open(
&self,
worktree: &mut Worktree,
project_path: ProjectPath,
cx: &mut ModelContext<Worktree>,
) -> Option<Task<Result<Box<dyn ItemHandle>>>> {
let buffer = worktree.open_buffer(project_path.path, cx);
let task = cx.spawn(|_, _| async move {
buffer
.await
.map(|buffer| Box::new(BufferItemHandle(buffer)) as Box<dyn ItemHandle>)
});
Some(task)
}
}
impl ItemHandle for BufferItemHandle {
fn add_view(
&self,
window_id: usize,
settings: watch::Receiver<Settings>,
cx: &mut ViewContext<Self::View>,
) -> Self::View {
Editor::for_buffer(
handle,
move |cx| {
let settings = settings.borrow();
let font_cache = cx.font_cache();
let font_family_id = settings.buffer_font_family;
let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
let font_properties = Default::default();
let font_id = font_cache
.select_font(font_family_id, &font_properties)
.unwrap();
let font_size = settings.buffer_font_size;
cx: &mut MutableAppContext,
) -> Box<dyn ItemViewHandle> {
Box::new(cx.add_view(window_id, |cx| {
Editor::for_buffer(
self.0.clone(),
move |cx| {
let settings = settings.borrow();
let font_cache = cx.font_cache();
let font_family_id = settings.buffer_font_family;
let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
let font_properties = Default::default();
let font_id = font_cache
.select_font(font_family_id, &font_properties)
.unwrap();
let font_size = settings.buffer_font_size;
let mut theme = settings.theme.editor.clone();
theme.text = TextStyle {
color: theme.text.color,
font_family_name,
font_family_id,
font_id,
font_size,
font_properties,
underline: None,
};
EditorSettings {
tab_size: settings.tab_size,
style: theme,
}
},
cx,
)
let mut theme = settings.theme.editor.clone();
theme.text = TextStyle {
color: theme.text.color,
font_family_name,
font_family_id,
font_id,
font_size,
font_properties,
underline: None,
};
EditorSettings {
tab_size: settings.tab_size,
style: theme,
}
},
cx,
)
}))
}
fn project_path(&self) -> Option<ProjectPath> {
self.file().map(|f| ProjectPath {
fn boxed_clone(&self) -> Box<dyn ItemHandle> {
Box::new(self.clone())
}
fn downgrade(&self) -> Box<dyn workspace::WeakItemHandle> {
Box::new(WeakBufferItemHandle(self.0.downgrade()))
}
fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
self.0.read(cx).file().map(|f| ProjectPath {
worktree_id: f.worktree_id(),
path: f.path().clone(),
})
}
}
impl WeakItemHandle for WeakBufferItemHandle {
fn upgrade(&self, cx: &AppContext) -> Option<Box<dyn ItemHandle>> {
self.0
.upgrade(cx)
.map(|buffer| Box::new(BufferItemHandle(buffer)) as Box<dyn ItemHandle>)
}
}
impl ItemView for Editor {
fn should_activate_item_on_event(event: &Event) -> bool {
matches!(event, Event::Activate)
@ -226,7 +270,7 @@ impl View for CursorPosition {
impl StatusItemView for CursorPosition {
fn set_active_pane_item(
&mut self,
active_pane_item: Option<&dyn crate::ItemViewHandle>,
active_pane_item: Option<&dyn ItemViewHandle>,
cx: &mut ViewContext<Self>,
) {
if let Some(editor) = active_pane_item.and_then(|item| item.to_any().downcast::<Editor>()) {
@ -312,7 +356,7 @@ impl View for DiagnosticMessage {
impl StatusItemView for DiagnosticMessage {
fn set_active_pane_item(
&mut self,
active_pane_item: Option<&dyn crate::ItemViewHandle>,
active_pane_item: Option<&dyn ItemViewHandle>,
cx: &mut ViewContext<Self>,
) {
if let Some(editor) = active_pane_item.and_then(|item| item.to_any().downcast::<Editor>()) {

View File

@ -1,5 +1,6 @@
pub mod display_map;
mod element;
pub mod items;
pub mod movement;
#[cfg(test)]
@ -17,6 +18,7 @@ use gpui::{
text_layout, AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle,
MutableAppContext, RenderContext, View, ViewContext, WeakViewHandle,
};
use items::BufferItemHandle;
use language::*;
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
@ -34,6 +36,7 @@ use std::{
use sum_tree::Bias;
use theme::{DiagnosticStyle, EditorStyle, SyntaxTheme};
use util::post_inc;
use workspace::{EntryOpener, Workspace};
const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
const MAX_LINE_LEN: usize = 1024;
@ -97,7 +100,8 @@ action!(FoldSelectedRanges);
action!(Scroll, Vector2F);
action!(Select, SelectPhase);
pub fn init(cx: &mut MutableAppContext) {
pub fn init(cx: &mut MutableAppContext, entry_openers: &mut Vec<Box<dyn EntryOpener>>) {
entry_openers.push(Box::new(items::BufferOpener));
cx.add_bindings(vec![
Binding::new("escape", Cancel, Some("Editor")),
Binding::new("backspace", Backspace, Some("Editor")),
@ -201,6 +205,7 @@ pub fn init(cx: &mut MutableAppContext) {
Binding::new("alt-cmd-f", FoldSelectedRanges, Some("Editor")),
]);
cx.add_action(Editor::open_new);
cx.add_action(|this: &mut Editor, action: &Scroll, cx| this.set_scroll_position(action.0, cx));
cx.add_action(Editor::select);
cx.add_action(Editor::cancel);
@ -478,6 +483,15 @@ impl Editor {
}
}
pub fn open_new(
workspace: &mut Workspace,
_: &workspace::OpenNew,
cx: &mut ViewContext<Workspace>,
) {
let buffer = cx.add_model(|cx| Buffer::new(0, "", cx));
workspace.add_item(BufferItemHandle(buffer), cx);
}
pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
self.buffer.read(cx).replica_id()
}

View File

@ -14,5 +14,6 @@ workspace = { path = "../workspace" }
postage = { version = "0.4.1", features = ["futures-traits"] }
[dev-dependencies]
gpui = { path = "../gpui", features = ["test-support"] }
serde_json = { version = "1.0.64", features = ["preserve_order"] }
workspace = { path = "../workspace", features = ["test-support"] }

View File

@ -429,7 +429,14 @@ mod tests {
#[gpui::test]
async fn test_matching_paths(mut cx: gpui::TestAppContext) {
let params = cx.update(WorkspaceParams::test);
let mut entry_openers = Vec::new();
cx.update(|cx| {
super::init(cx);
editor::init(cx, &mut entry_openers);
});
let mut params = cx.update(WorkspaceParams::test);
params.entry_openers = Arc::from(entry_openers);
params
.fs
.as_fake()
@ -443,10 +450,6 @@ mod tests {
}),
)
.await;
cx.update(|cx| {
super::init(cx);
editor::init(cx);
});
let (window_id, workspace) = cx.add_window(|cx| Workspace::new(&params, cx));
workspace

View File

@ -12,9 +12,7 @@ test-support = [
]
[dependencies]
buffer = { path = "../buffer" }
client = { path = "../client" }
editor = { path = "../editor" }
gpui = { path = "../gpui" }
language = { path = "../language" }
project = { path = "../project" }

File diff suppressed because it is too large Load Diff

View File

@ -130,11 +130,9 @@ fn open_paths(action: &OpenPaths, cx: &mut MutableAppContext) -> Task<()> {
}
fn open_new(action: &workspace::OpenNew, cx: &mut MutableAppContext) {
cx.add_window(window_options(), |cx| {
let mut workspace = build_workspace(&action.0, cx);
workspace.open_new_file(&action, cx);
workspace
});
let (window_id, workspace) =
cx.add_window(window_options(), |cx| build_workspace(&action.0, cx));
cx.dispatch_action(window_id, vec![workspace.id()], action);
}
fn build_workspace(params: &WorkspaceParams, cx: &mut ViewContext<Workspace>) -> Workspace {
@ -163,9 +161,9 @@ fn build_workspace(params: &WorkspaceParams, cx: &mut ViewContext<Workspace>) ->
);
let diagnostic =
cx.add_view(|_| workspace::items::DiagnosticMessage::new(params.settings.clone()));
cx.add_view(|_| editor::items::DiagnosticMessage::new(params.settings.clone()));
let cursor_position =
cx.add_view(|_| workspace::items::CursorPosition::new(params.settings.clone()));
cx.add_view(|_| editor::items::CursorPosition::new(params.settings.clone()));
workspace.status_bar().update(cx, |status_bar, cx| {
status_bar.add_left_item(diagnostic, cx);
status_bar.add_right_item(cursor_position, cx);

View File

@ -36,8 +36,8 @@ fn main() {
let mut entry_openers = Vec::new();
client::init(client.clone(), cx);
workspace::init(cx, &mut entry_openers);
editor::init(cx);
workspace::init(cx);
editor::init(cx, &mut entry_openers);
file_finder::init(cx);
people_panel::init(cx);
chat_panel::init(cx);