Introduce ProjectPath and ProjectEntry structs
These replace tuples of (usize, Arc<Path>) and (usize, usize) respectively.
This commit is contained in:
+3
-3
@@ -47,7 +47,7 @@ pub struct PathMatchCandidate<'a> {
|
||||
pub struct PathMatch {
|
||||
pub score: f64,
|
||||
pub positions: Vec<usize>,
|
||||
pub tree_id: usize,
|
||||
pub worktree_id: usize,
|
||||
pub path: Arc<Path>,
|
||||
pub path_prefix: Arc<str>,
|
||||
}
|
||||
@@ -147,7 +147,7 @@ impl Ord for PathMatch {
|
||||
self.score
|
||||
.partial_cmp(&other.score)
|
||||
.unwrap_or(Ordering::Equal)
|
||||
.then_with(|| self.tree_id.cmp(&other.tree_id))
|
||||
.then_with(|| self.worktree_id.cmp(&other.worktree_id))
|
||||
.then_with(|| Arc::as_ptr(&self.path).cmp(&Arc::as_ptr(&other.path)))
|
||||
}
|
||||
}
|
||||
@@ -215,7 +215,7 @@ impl<'a> Matcher<'a> {
|
||||
cancel_flag,
|
||||
|candidate, score| PathMatch {
|
||||
score,
|
||||
tree_id,
|
||||
worktree_id: tree_id,
|
||||
positions: Vec::new(),
|
||||
path: candidate.path.clone(),
|
||||
path_prefix: path_prefix.clone(),
|
||||
|
||||
+9
-2
@@ -980,6 +980,7 @@ mod tests {
|
||||
fs::{FakeFs, Fs as _},
|
||||
language::LanguageRegistry,
|
||||
people_panel::JoinWorktree,
|
||||
project::ProjectPath,
|
||||
rpc::{self, Client, Credentials, EstablishConnectionError},
|
||||
settings,
|
||||
test::FakeHttpClient,
|
||||
@@ -1166,8 +1167,14 @@ mod tests {
|
||||
workspace.worktrees(cx).first().unwrap().id()
|
||||
});
|
||||
workspace_b
|
||||
.update(&mut cx_b, |worktree, cx| {
|
||||
worktree.open_entry((local_worktree_id_b, Path::new("a.txt").into()), cx)
|
||||
.update(&mut cx_b, |workspace, cx| {
|
||||
workspace.open_entry(
|
||||
ProjectPath {
|
||||
worktree_id: local_worktree_id_b,
|
||||
path: Path::new("a.txt").into(),
|
||||
},
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.unwrap()
|
||||
.await;
|
||||
|
||||
+11
-7
@@ -5,6 +5,7 @@ pub mod movement;
|
||||
|
||||
use crate::{
|
||||
language::Language,
|
||||
project::ProjectPath,
|
||||
settings::Settings,
|
||||
theme::Theme,
|
||||
time::ReplicaId,
|
||||
@@ -2589,8 +2590,11 @@ impl workspace::Item for Buffer {
|
||||
)
|
||||
}
|
||||
|
||||
fn worktree_id_and_path(&self) -> Option<(usize, Arc<Path>)> {
|
||||
self.file().map(|f| (f.worktree_id(), f.path().clone()))
|
||||
fn project_path(&self) -> Option<ProjectPath> {
|
||||
self.file().map(|f| ProjectPath {
|
||||
worktree_id: f.worktree_id(),
|
||||
path: f.path().clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2623,11 +2627,11 @@ impl workspace::ItemView for Editor {
|
||||
}
|
||||
}
|
||||
|
||||
fn worktree_id_and_path(&self, cx: &AppContext) -> Option<(usize, Arc<Path>)> {
|
||||
self.buffer
|
||||
.read(cx)
|
||||
.file()
|
||||
.map(|file| (file.worktree_id(), file.path().clone()))
|
||||
fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
|
||||
self.buffer.read(cx).file().map(|file| ProjectPath {
|
||||
worktree_id: file.worktree_id(),
|
||||
path: file.path().clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn clone_on_split(&self, cx: &mut ViewContext<Self>) -> Option<Self>
|
||||
|
||||
+16
-19
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
editor::{self, Editor},
|
||||
fuzzy::PathMatch,
|
||||
project::Project,
|
||||
project::{Project, ProjectPath},
|
||||
settings::Settings,
|
||||
util,
|
||||
workspace::Workspace,
|
||||
@@ -44,13 +44,7 @@ pub struct FileFinder {
|
||||
|
||||
action!(Toggle);
|
||||
action!(Confirm);
|
||||
action!(Select, Entry);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Entry {
|
||||
worktree_id: usize,
|
||||
path: Arc<Path>,
|
||||
}
|
||||
action!(Select, ProjectPath);
|
||||
|
||||
pub fn init(cx: &mut MutableAppContext) {
|
||||
cx.add_action(FileFinder::toggle);
|
||||
@@ -67,7 +61,7 @@ pub fn init(cx: &mut MutableAppContext) {
|
||||
}
|
||||
|
||||
pub enum Event {
|
||||
Selected(usize, Arc<Path>),
|
||||
Selected(ProjectPath),
|
||||
Dismissed,
|
||||
}
|
||||
|
||||
@@ -203,8 +197,8 @@ impl FileFinder {
|
||||
)
|
||||
.with_style(style.container);
|
||||
|
||||
let action = Select(Entry {
|
||||
worktree_id: path_match.tree_id,
|
||||
let action = Select(ProjectPath {
|
||||
worktree_id: path_match.worktree_id,
|
||||
path: path_match.path.clone(),
|
||||
});
|
||||
EventHandler::new(container.boxed())
|
||||
@@ -256,9 +250,9 @@ impl FileFinder {
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) {
|
||||
match event {
|
||||
Event::Selected(tree_id, path) => {
|
||||
Event::Selected(project_path) => {
|
||||
workspace
|
||||
.open_entry((*tree_id, path.clone()), cx)
|
||||
.open_entry(project_path.clone(), cx)
|
||||
.map(|d| d.detach());
|
||||
workspace.dismiss_modal(cx);
|
||||
}
|
||||
@@ -338,7 +332,7 @@ impl FileFinder {
|
||||
fn selected_index(&self) -> usize {
|
||||
if let Some(selected) = self.selected.as_ref() {
|
||||
for (ix, path_match) in self.matches.iter().enumerate() {
|
||||
if (path_match.tree_id, path_match.path.as_ref())
|
||||
if (path_match.worktree_id, path_match.path.as_ref())
|
||||
== (selected.0, selected.1.as_ref())
|
||||
{
|
||||
return ix;
|
||||
@@ -353,7 +347,7 @@ impl FileFinder {
|
||||
if selected_index > 0 {
|
||||
selected_index -= 1;
|
||||
let mat = &self.matches[selected_index];
|
||||
self.selected = Some((mat.tree_id, mat.path.clone()));
|
||||
self.selected = Some((mat.worktree_id, mat.path.clone()));
|
||||
}
|
||||
self.list_state.scroll_to(selected_index);
|
||||
cx.notify();
|
||||
@@ -364,7 +358,7 @@ impl FileFinder {
|
||||
if selected_index + 1 < self.matches.len() {
|
||||
selected_index += 1;
|
||||
let mat = &self.matches[selected_index];
|
||||
self.selected = Some((mat.tree_id, mat.path.clone()));
|
||||
self.selected = Some((mat.worktree_id, mat.path.clone()));
|
||||
}
|
||||
self.list_state.scroll_to(selected_index);
|
||||
cx.notify();
|
||||
@@ -372,12 +366,15 @@ impl FileFinder {
|
||||
|
||||
fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
|
||||
if let Some(m) = self.matches.get(self.selected_index()) {
|
||||
cx.emit(Event::Selected(m.tree_id, m.path.clone()));
|
||||
cx.emit(Event::Selected(ProjectPath {
|
||||
worktree_id: m.worktree_id,
|
||||
path: m.path.clone(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
fn select(&mut self, Select(entry): &Select, cx: &mut ViewContext<Self>) {
|
||||
cx.emit(Event::Selected(entry.worktree_id, entry.path.clone()));
|
||||
fn select(&mut self, Select(project_path): &Select, cx: &mut ViewContext<Self>) {
|
||||
cx.emit(Event::Selected(project_path.clone()));
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
||||
+23
-12
@@ -17,17 +17,29 @@ use std::{
|
||||
|
||||
pub struct Project {
|
||||
worktrees: Vec<ModelHandle<Worktree>>,
|
||||
active_entry: Option<(usize, usize)>,
|
||||
active_entry: Option<ProjectEntry>,
|
||||
languages: Arc<LanguageRegistry>,
|
||||
rpc: Arc<Client>,
|
||||
fs: Arc<dyn Fs>,
|
||||
}
|
||||
|
||||
pub enum Event {
|
||||
ActiveEntryChanged(Option<(usize, usize)>),
|
||||
ActiveEntryChanged(Option<ProjectEntry>),
|
||||
WorktreeRemoved(usize),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct ProjectPath {
|
||||
pub worktree_id: usize,
|
||||
pub path: Arc<Path>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct ProjectEntry {
|
||||
pub worktree_id: usize,
|
||||
pub entry_id: usize,
|
||||
}
|
||||
|
||||
impl Project {
|
||||
pub fn new(app_state: &AppState) -> Self {
|
||||
Self {
|
||||
@@ -99,15 +111,14 @@ impl Project {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn set_active_entry(
|
||||
&mut self,
|
||||
entry: Option<(usize, Arc<Path>)>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
let new_active_entry = entry.and_then(|(worktree_id, path)| {
|
||||
let worktree = self.worktree_for_id(worktree_id)?;
|
||||
let entry = worktree.read(cx).entry_for_path(path)?;
|
||||
Some((worktree_id, entry.id))
|
||||
pub fn set_active_path(&mut self, entry: Option<ProjectPath>, cx: &mut ModelContext<Self>) {
|
||||
let new_active_entry = entry.and_then(|project_path| {
|
||||
let worktree = self.worktree_for_id(project_path.worktree_id)?;
|
||||
let entry = worktree.read(cx).entry_for_path(project_path.path)?;
|
||||
Some(ProjectEntry {
|
||||
worktree_id: project_path.worktree_id,
|
||||
entry_id: entry.id,
|
||||
})
|
||||
});
|
||||
if new_active_entry != self.active_entry {
|
||||
self.active_entry = new_active_entry;
|
||||
@@ -115,7 +126,7 @@ impl Project {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn active_entry(&self) -> Option<(usize, usize)> {
|
||||
pub fn active_entry(&self) -> Option<ProjectEntry> {
|
||||
self.active_entry
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
project::{self, Project},
|
||||
project::{self, Project, ProjectEntry, ProjectPath},
|
||||
theme,
|
||||
workspace::Workspace,
|
||||
worktree::{self, Worktree},
|
||||
@@ -53,12 +53,6 @@ struct EntryDetails {
|
||||
is_selected: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct ProjectEntry {
|
||||
pub worktree_id: usize,
|
||||
pub entry_id: usize,
|
||||
}
|
||||
|
||||
action!(ExpandSelectedEntry);
|
||||
action!(CollapseSelectedEntry);
|
||||
action!(ToggleExpanded, ProjectEntry);
|
||||
@@ -94,7 +88,10 @@ impl ProjectPanel {
|
||||
})
|
||||
.detach();
|
||||
cx.subscribe(&project, |this, _, event, cx| match event {
|
||||
project::Event::ActiveEntryChanged(Some((worktree_id, entry_id))) => {
|
||||
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();
|
||||
@@ -129,7 +126,13 @@ impl ProjectPanel {
|
||||
if let Some(worktree) = project.read(cx).worktree_for_id(*worktree_id) {
|
||||
if let Some(entry) = worktree.read(cx).entry_for_id(*entry_id) {
|
||||
workspace
|
||||
.open_entry((worktree.id(), entry.path.clone()), cx)
|
||||
.open_entry(
|
||||
ProjectPath {
|
||||
worktree_id: worktree.id(),
|
||||
path: entry.path.clone(),
|
||||
},
|
||||
cx,
|
||||
)
|
||||
.map(|t| t.detach());
|
||||
}
|
||||
}
|
||||
|
||||
+70
-54
@@ -7,7 +7,7 @@ use crate::{
|
||||
editor::Buffer,
|
||||
fs::Fs,
|
||||
people_panel::{JoinWorktree, LeaveWorktree, PeoplePanel, ShareWorktree, UnshareWorktree},
|
||||
project::Project,
|
||||
project::{Project, ProjectPath},
|
||||
project_panel::ProjectPanel,
|
||||
rpc,
|
||||
settings::Settings,
|
||||
@@ -164,12 +164,12 @@ pub trait Item: Entity + Sized {
|
||||
cx: &mut ViewContext<Self::View>,
|
||||
) -> Self::View;
|
||||
|
||||
fn worktree_id_and_path(&self) -> Option<(usize, Arc<Path>)>;
|
||||
fn project_path(&self) -> Option<ProjectPath>;
|
||||
}
|
||||
|
||||
pub trait ItemView: View {
|
||||
fn title(&self, cx: &AppContext) -> String;
|
||||
fn worktree_id_and_path(&self, cx: &AppContext) -> Option<(usize, Arc<Path>)>;
|
||||
fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>;
|
||||
fn clone_on_split(&self, _: &mut ViewContext<Self>) -> Option<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
@@ -213,12 +213,12 @@ pub trait WeakItemHandle {
|
||||
cx: &mut MutableAppContext,
|
||||
) -> Option<Box<dyn ItemViewHandle>>;
|
||||
fn alive(&self, cx: &AppContext) -> bool;
|
||||
fn worktree_id_and_path(&self, cx: &AppContext) -> Option<(usize, Arc<Path>)>;
|
||||
fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>;
|
||||
}
|
||||
|
||||
pub trait ItemViewHandle {
|
||||
fn title(&self, cx: &AppContext) -> String;
|
||||
fn entry_id(&self, cx: &AppContext) -> Option<(usize, Arc<Path>)>;
|
||||
fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>;
|
||||
fn boxed_clone(&self) -> Box<dyn ItemViewHandle>;
|
||||
fn clone_on_split(&self, cx: &mut MutableAppContext) -> Option<Box<dyn ItemViewHandle>>;
|
||||
fn set_parent_pane(&self, pane: &ViewHandle<Pane>, cx: &mut MutableAppContext);
|
||||
@@ -265,9 +265,8 @@ impl<T: Item> WeakItemHandle for WeakModelHandle<T> {
|
||||
self.upgrade(cx).is_some()
|
||||
}
|
||||
|
||||
fn worktree_id_and_path(&self, cx: &AppContext) -> Option<(usize, Arc<Path>)> {
|
||||
self.upgrade(cx)
|
||||
.and_then(|h| h.read(cx).worktree_id_and_path())
|
||||
fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
|
||||
self.upgrade(cx).and_then(|h| h.read(cx).project_path())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,8 +275,8 @@ impl<T: ItemView> ItemViewHandle for ViewHandle<T> {
|
||||
self.read(cx).title(cx)
|
||||
}
|
||||
|
||||
fn entry_id(&self, cx: &AppContext) -> Option<(usize, Arc<Path>)> {
|
||||
self.read(cx).worktree_id_and_path(cx)
|
||||
fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
|
||||
self.read(cx).project_path(cx)
|
||||
}
|
||||
|
||||
fn boxed_clone(&self) -> Box<dyn ItemViewHandle> {
|
||||
@@ -368,7 +367,7 @@ pub struct Workspace {
|
||||
project: ModelHandle<Project>,
|
||||
items: Vec<Box<dyn WeakItemHandle>>,
|
||||
loading_items: HashMap<
|
||||
(usize, Arc<Path>),
|
||||
ProjectPath,
|
||||
postage::watch::Receiver<Option<Result<Box<dyn ItemHandle>, Arc<anyhow::Error>>>>,
|
||||
>,
|
||||
_observe_current_user: Task<()>,
|
||||
@@ -382,9 +381,9 @@ impl Workspace {
|
||||
let pane = cx.add_view(|_| Pane::new(app_state.settings.clone()));
|
||||
let pane_id = pane.id();
|
||||
cx.observe(&pane, move |me, _, cx| {
|
||||
let active_entry = me.active_entry(cx);
|
||||
let active_entry = me.active_project_path(cx);
|
||||
me.project
|
||||
.update(cx, |project, cx| project.set_active_entry(active_entry, cx));
|
||||
.update(cx, |project, cx| project.set_active_path(active_entry, cx));
|
||||
})
|
||||
.detach();
|
||||
cx.subscribe(&pane, move |me, _, event, cx| {
|
||||
@@ -495,7 +494,7 @@ impl Workspace {
|
||||
let entries = abs_paths
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|path| self.entry_id_for_path(&path, cx))
|
||||
.map(|path| self.project_path_for_path(&path, cx))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let fs = self.fs.clone();
|
||||
@@ -562,15 +561,18 @@ impl Workspace {
|
||||
})
|
||||
}
|
||||
|
||||
fn entry_id_for_path(
|
||||
fn project_path_for_path(
|
||||
&self,
|
||||
abs_path: &Path,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Task<Result<(usize, Arc<Path>)>> {
|
||||
) -> Task<Result<ProjectPath>> {
|
||||
let entry = self.worktree_for_abs_path(abs_path, cx);
|
||||
cx.spawn(|_, _| async move {
|
||||
let (worktree, path) = entry.await?;
|
||||
Ok((worktree.id(), path.into()))
|
||||
Ok(ProjectPath {
|
||||
worktree_id: worktree.id(),
|
||||
path: path.into(),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -623,33 +625,38 @@ impl Workspace {
|
||||
#[must_use]
|
||||
pub fn open_entry(
|
||||
&mut self,
|
||||
entry: (usize, Arc<Path>),
|
||||
project_path: ProjectPath,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<Task<()>> {
|
||||
let pane = self.active_pane().clone();
|
||||
if self.activate_or_open_existing_entry(entry.clone(), &pane, cx) {
|
||||
if self.activate_or_open_existing_entry(project_path.clone(), &pane, cx) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (worktree_id, path) = entry.clone();
|
||||
// let (worktree_id, path) = project_path.clone();
|
||||
|
||||
let worktree = match self.project.read(cx).worktree_for_id(worktree_id) {
|
||||
let worktree = match self
|
||||
.project
|
||||
.read(cx)
|
||||
.worktree_for_id(project_path.worktree_id)
|
||||
{
|
||||
Some(worktree) => worktree,
|
||||
None => {
|
||||
log::error!("worktree {} does not exist", worktree_id);
|
||||
log::error!("worktree {} does not exist", project_path.worktree_id);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
if let Entry::Vacant(entry) = self.loading_items.entry(entry.clone()) {
|
||||
if let Entry::Vacant(entry) = self.loading_items.entry(project_path.clone()) {
|
||||
let (mut tx, rx) = postage::watch::channel();
|
||||
entry.insert(rx);
|
||||
|
||||
let project_path = project_path.clone();
|
||||
cx.as_mut()
|
||||
.spawn(|mut cx| async move {
|
||||
let buffer = worktree
|
||||
.update(&mut cx, |worktree, cx| {
|
||||
worktree.open_buffer(path.as_ref(), cx)
|
||||
worktree.open_buffer(project_path.path.as_ref(), cx)
|
||||
})
|
||||
.await;
|
||||
*tx.borrow_mut() = Some(
|
||||
@@ -663,7 +670,7 @@ impl Workspace {
|
||||
|
||||
let pane = pane.downgrade();
|
||||
let settings = self.settings.clone();
|
||||
let mut watch = self.loading_items.get(&entry).unwrap().clone();
|
||||
let mut watch = self.loading_items.get(&project_path).unwrap().clone();
|
||||
|
||||
Some(cx.spawn(|this, mut cx| async move {
|
||||
let load_result = loop {
|
||||
@@ -674,14 +681,14 @@ impl Workspace {
|
||||
};
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.loading_items.remove(&entry);
|
||||
this.loading_items.remove(&project_path);
|
||||
if let Some(pane) = pane.upgrade(&cx) {
|
||||
match load_result {
|
||||
Ok(item) => {
|
||||
// By the time loading finishes, the entry could have been already added
|
||||
// to the pane. If it was, we activate it, otherwise we'll store the
|
||||
// item and add a new view for it.
|
||||
if !this.activate_or_open_existing_entry(entry, &pane, cx) {
|
||||
if !this.activate_or_open_existing_entry(project_path, &pane, cx) {
|
||||
let weak_item = item.downgrade();
|
||||
let view = weak_item
|
||||
.add_view(cx.window_id(), settings, cx.as_mut())
|
||||
@@ -701,13 +708,13 @@ impl Workspace {
|
||||
|
||||
fn activate_or_open_existing_entry(
|
||||
&mut self,
|
||||
entry: (usize, Arc<Path>),
|
||||
project_path: ProjectPath,
|
||||
pane: &ViewHandle<Pane>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> bool {
|
||||
// If the pane contains a view for this file, then activate
|
||||
// that item view.
|
||||
if pane.update(cx, |pane, cx| pane.activate_entry(entry.clone(), cx)) {
|
||||
if pane.update(cx, |pane, cx| pane.activate_entry(project_path.clone(), cx)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -718,7 +725,9 @@ impl Workspace {
|
||||
self.items.retain(|item| {
|
||||
if item.alive(cx.as_ref()) {
|
||||
if view_for_existing_item.is_none()
|
||||
&& item.worktree_id_and_path(cx).map_or(false, |e| e == entry)
|
||||
&& item
|
||||
.project_path(cx)
|
||||
.map_or(false, |item_project_path| item_project_path == project_path)
|
||||
{
|
||||
view_for_existing_item = Some(
|
||||
item.add_view(cx.window_id(), settings.clone(), cx.as_mut())
|
||||
@@ -742,14 +751,14 @@ impl Workspace {
|
||||
self.active_pane().read(cx).active_item()
|
||||
}
|
||||
|
||||
fn active_entry(&self, cx: &ViewContext<Self>) -> Option<(usize, Arc<Path>)> {
|
||||
self.active_item(cx).and_then(|item| item.entry_id(cx))
|
||||
fn active_project_path(&self, cx: &ViewContext<Self>) -> Option<ProjectPath> {
|
||||
self.active_item(cx).and_then(|item| item.project_path(cx))
|
||||
}
|
||||
|
||||
pub fn save_active_item(&mut self, _: &Save, cx: &mut ViewContext<Self>) {
|
||||
if let Some(item) = self.active_item(cx) {
|
||||
let handle = cx.handle();
|
||||
if item.entry_id(cx.as_ref()).is_none() {
|
||||
if item.project_path(cx.as_ref()).is_none() {
|
||||
let worktree = self.worktrees(cx).first();
|
||||
let start_abs_path = worktree
|
||||
.and_then(|w| w.read(cx).as_local())
|
||||
@@ -885,9 +894,9 @@ impl Workspace {
|
||||
let pane = cx.add_view(|_| Pane::new(self.settings.clone()));
|
||||
let pane_id = pane.id();
|
||||
cx.observe(&pane, move |me, _, cx| {
|
||||
let active_entry = me.active_entry(cx);
|
||||
let active_entry = me.active_project_path(cx);
|
||||
me.project
|
||||
.update(cx, |project, cx| project.set_active_entry(active_entry, cx));
|
||||
.update(cx, |project, cx| project.set_active_path(active_entry, cx));
|
||||
})
|
||||
.detach();
|
||||
cx.subscribe(&pane, move |me, _, event, cx| {
|
||||
@@ -1124,20 +1133,21 @@ impl View for Workspace {
|
||||
|
||||
#[cfg(test)]
|
||||
pub trait WorkspaceHandle {
|
||||
fn file_entries(&self, cx: &AppContext) -> Vec<(usize, Arc<Path>)>;
|
||||
fn file_project_paths(&self, cx: &AppContext) -> Vec<ProjectPath>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl WorkspaceHandle for ViewHandle<Workspace> {
|
||||
fn file_entries(&self, cx: &AppContext) -> Vec<(usize, Arc<Path>)> {
|
||||
fn file_project_paths(&self, cx: &AppContext) -> Vec<ProjectPath> {
|
||||
self.read(cx)
|
||||
.worktrees(cx)
|
||||
.iter()
|
||||
.flat_map(|tree| {
|
||||
let tree_id = tree.id();
|
||||
tree.read(cx)
|
||||
.files(true, 0)
|
||||
.map(move |f| (tree_id, f.path.clone()))
|
||||
.flat_map(|worktree| {
|
||||
let worktree_id = worktree.id();
|
||||
worktree.read(cx).files(true, 0).map(move |f| ProjectPath {
|
||||
worktree_id,
|
||||
path: f.path.clone(),
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
@@ -1247,7 +1257,7 @@ mod tests {
|
||||
|
||||
cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
|
||||
.await;
|
||||
let entries = cx.read(|cx| workspace.file_entries(cx));
|
||||
let entries = cx.read(|cx| workspace.file_project_paths(cx));
|
||||
let file1 = entries[0].clone();
|
||||
let file2 = entries[1].clone();
|
||||
let file3 = entries[2].clone();
|
||||
@@ -1260,7 +1270,7 @@ mod tests {
|
||||
cx.read(|cx| {
|
||||
let pane = workspace.read(cx).active_pane().read(cx);
|
||||
assert_eq!(
|
||||
pane.active_item().unwrap().entry_id(cx),
|
||||
pane.active_item().unwrap().project_path(cx),
|
||||
Some(file1.clone())
|
||||
);
|
||||
assert_eq!(pane.items().len(), 1);
|
||||
@@ -1274,7 +1284,7 @@ mod tests {
|
||||
cx.read(|cx| {
|
||||
let pane = workspace.read(cx).active_pane().read(cx);
|
||||
assert_eq!(
|
||||
pane.active_item().unwrap().entry_id(cx),
|
||||
pane.active_item().unwrap().project_path(cx),
|
||||
Some(file2.clone())
|
||||
);
|
||||
assert_eq!(pane.items().len(), 2);
|
||||
@@ -1287,7 +1297,7 @@ mod tests {
|
||||
cx.read(|cx| {
|
||||
let pane = workspace.read(cx).active_pane().read(cx);
|
||||
assert_eq!(
|
||||
pane.active_item().unwrap().entry_id(cx),
|
||||
pane.active_item().unwrap().project_path(cx),
|
||||
Some(file1.clone())
|
||||
);
|
||||
assert_eq!(pane.items().len(), 2);
|
||||
@@ -1302,7 +1312,7 @@ mod tests {
|
||||
.read(cx)
|
||||
.active_item()
|
||||
.unwrap()
|
||||
.entry_id(cx.as_ref()),
|
||||
.project_path(cx.as_ref()),
|
||||
Some(file2.clone())
|
||||
);
|
||||
});
|
||||
@@ -1319,13 +1329,13 @@ mod tests {
|
||||
cx.read(|cx| {
|
||||
let pane = workspace.read(cx).active_pane().read(cx);
|
||||
assert_eq!(
|
||||
pane.active_item().unwrap().entry_id(cx),
|
||||
pane.active_item().unwrap().project_path(cx),
|
||||
Some(file3.clone())
|
||||
);
|
||||
let pane_entries = pane
|
||||
.items()
|
||||
.iter()
|
||||
.map(|i| i.entry_id(cx).unwrap())
|
||||
.map(|i| i.project_path(cx).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(pane_entries, &[file1, file2, file3]);
|
||||
});
|
||||
@@ -1468,7 +1478,7 @@ mod tests {
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let tree = cx.read(|cx| {
|
||||
let worktree = cx.read(|cx| {
|
||||
workspace
|
||||
.read(cx)
|
||||
.worktrees(cx)
|
||||
@@ -1543,7 +1553,13 @@ mod tests {
|
||||
workspace.open_new_file(&OpenNew(app_state.clone()), cx);
|
||||
workspace.split_pane(workspace.active_pane().clone(), SplitDirection::Right, cx);
|
||||
assert!(workspace
|
||||
.open_entry((tree.id(), Path::new("the-new-name.rs").into()), cx)
|
||||
.open_entry(
|
||||
ProjectPath {
|
||||
worktree_id: worktree.id(),
|
||||
path: Path::new("the-new-name.rs").into()
|
||||
},
|
||||
cx
|
||||
)
|
||||
.is_none());
|
||||
});
|
||||
let editor2 = workspace.update(&mut cx, |workspace, cx| {
|
||||
@@ -1664,7 +1680,7 @@ mod tests {
|
||||
.unwrap();
|
||||
cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
|
||||
.await;
|
||||
let entries = cx.read(|cx| workspace.file_entries(cx));
|
||||
let entries = cx.read(|cx| workspace.file_project_paths(cx));
|
||||
let file1 = entries[0].clone();
|
||||
|
||||
let pane_1 = cx.read(|cx| workspace.read(cx).active_pane().clone());
|
||||
@@ -1675,7 +1691,7 @@ mod tests {
|
||||
.await;
|
||||
cx.read(|cx| {
|
||||
assert_eq!(
|
||||
pane_1.read(cx).active_item().unwrap().entry_id(cx),
|
||||
pane_1.read(cx).active_item().unwrap().project_path(cx),
|
||||
Some(file1.clone())
|
||||
);
|
||||
});
|
||||
@@ -1690,7 +1706,7 @@ mod tests {
|
||||
assert_ne!(pane_1, pane_2);
|
||||
|
||||
let pane2_item = pane_2.read(cx).active_item().unwrap();
|
||||
assert_eq!(pane2_item.entry_id(cx.as_ref()), Some(file1.clone()));
|
||||
assert_eq!(pane2_item.project_path(cx.as_ref()), Some(file1.clone()));
|
||||
|
||||
cx.dispatch_action(window_id, vec![pane_2.id()], &CloseActiveItem);
|
||||
let workspace = workspace.read(cx);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::{ItemViewHandle, SplitDirection};
|
||||
use crate::settings::Settings;
|
||||
use crate::{project::ProjectPath, settings::Settings};
|
||||
use gpui::{
|
||||
action,
|
||||
elements::*,
|
||||
@@ -9,7 +9,7 @@ use gpui::{
|
||||
Entity, MutableAppContext, Quad, RenderContext, View, ViewContext, ViewHandle,
|
||||
};
|
||||
use postage::watch;
|
||||
use std::{cmp, path::Path, sync::Arc};
|
||||
use std::cmp;
|
||||
|
||||
action!(Split, SplitDirection);
|
||||
action!(ActivateItem, usize);
|
||||
@@ -105,12 +105,12 @@ impl Pane {
|
||||
|
||||
pub fn activate_entry(
|
||||
&mut self,
|
||||
entry_id: (usize, Arc<Path>),
|
||||
project_path: ProjectPath,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> bool {
|
||||
if let Some(index) = self.items.iter().position(|item| {
|
||||
item.entry_id(cx.as_ref())
|
||||
.map_or(false, |id| id == entry_id)
|
||||
item.project_path(cx.as_ref())
|
||||
.map_or(false, |item_path| item_path == project_path)
|
||||
}) {
|
||||
self.activate_item(index, cx);
|
||||
true
|
||||
|
||||
+14
-10
@@ -25,10 +25,22 @@ use postage::{
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use smol::channel::{self, Sender};
|
||||
use std::{any::Any, cmp::{self, Ordering}, collections::HashMap, convert::{TryFrom, TryInto}, ffi::{OsStr, OsString}, fmt, future::Future, ops::Deref, path::{Path, PathBuf}, sync::{
|
||||
use std::{
|
||||
any::Any,
|
||||
cmp::{self, Ordering},
|
||||
collections::HashMap,
|
||||
convert::{TryFrom, TryInto},
|
||||
ffi::{OsStr, OsString},
|
||||
fmt,
|
||||
future::Future,
|
||||
ops::Deref,
|
||||
path::{Path, PathBuf},
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering::SeqCst},
|
||||
Arc,
|
||||
}, time::{Duration, SystemTime}};
|
||||
},
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
use sum_tree::{self, Edit, SeekTarget, SumTree};
|
||||
use zrpc::{PeerId, TypedEnvelope};
|
||||
|
||||
@@ -1779,14 +1791,6 @@ impl File {
|
||||
mtime,
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn exists(&self) -> bool {
|
||||
// !self.is_deleted()
|
||||
// }
|
||||
|
||||
pub fn worktree_id_and_path(&self) -> (usize, Arc<Path>) {
|
||||
(self.worktree.id(), self.path.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl buffer::File for File {
|
||||
|
||||
Reference in New Issue
Block a user