Merge pull request #719 from zed-industries/misc-breadcrumbs-bugs

Nathan Sobo created

Fix miscellaneous breadcrumbs bugs

Change summary

Cargo.lock                            |  1 
crates/breadcrumbs/Cargo.toml         |  1 
crates/breadcrumbs/src/breadcrumbs.rs | 40 ++++++++++++++++++----------
crates/editor/src/editor.rs           |  2 +
crates/editor/src/multi_buffer.rs     | 11 ++++++-
crates/workspace/src/pane.rs          |  5 ++
crates/zed/src/zed.rs                 | 27 ++++++++++--------
7 files changed, 58 insertions(+), 29 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -727,6 +727,7 @@ dependencies = [
  "editor",
  "gpui",
  "language",
+ "project",
  "search",
  "theme",
  "workspace",

crates/breadcrumbs/Cargo.toml 🔗

@@ -12,6 +12,7 @@ collections = { path = "../collections" }
 editor = { path = "../editor" }
 gpui = { path = "../gpui" }
 language = { path = "../language" }
+project = { path = "../project" }
 search = { path = "../search" }
 theme = { path = "../theme" }
 workspace = { path = "../workspace" }

crates/breadcrumbs/src/breadcrumbs.rs 🔗

@@ -1,10 +1,11 @@
 use editor::{Anchor, Editor};
 use gpui::{
-    elements::*, AppContext, Entity, RenderContext, Subscription, View, ViewContext, ViewHandle,
+    elements::*, AppContext, Entity, ModelHandle, RenderContext, Subscription, View, ViewContext,
+    ViewHandle,
 };
-use language::{BufferSnapshot, OutlineItem};
+use language::{Buffer, OutlineItem};
+use project::Project;
 use search::ProjectSearchView;
-use std::borrow::Cow;
 use theme::SyntaxTheme;
 use workspace::{ItemHandle, Settings, ToolbarItemLocation, ToolbarItemView};
 
@@ -13,14 +14,16 @@ pub enum Event {
 }
 
 pub struct Breadcrumbs {
+    project: ModelHandle<Project>,
     editor: Option<ViewHandle<Editor>>,
     project_search: Option<ViewHandle<ProjectSearchView>>,
     subscriptions: Vec<Subscription>,
 }
 
 impl Breadcrumbs {
-    pub fn new() -> Self {
+    pub fn new(project: ModelHandle<Project>) -> Self {
         Self {
+            project,
             editor: Default::default(),
             subscriptions: Default::default(),
             project_search: Default::default(),
@@ -31,14 +34,14 @@ impl Breadcrumbs {
         &self,
         theme: &SyntaxTheme,
         cx: &AppContext,
-    ) -> Option<(BufferSnapshot, Vec<OutlineItem<Anchor>>)> {
+    ) -> Option<(ModelHandle<Buffer>, Vec<OutlineItem<Anchor>>)> {
         let editor = self.editor.as_ref()?.read(cx);
         let cursor = editor.newest_anchor_selection().head();
-        let (buffer, symbols) = editor
-            .buffer()
-            .read(cx)
+        let multibuffer = &editor.buffer().read(cx);
+        let (buffer_id, symbols) = multibuffer
             .read(cx)
             .symbols_containing(cursor, Some(theme))?;
+        let buffer = multibuffer.buffer(buffer_id)?;
         Some((buffer, symbols))
     }
 }
@@ -60,15 +63,21 @@ impl View for Breadcrumbs {
             } else {
                 return Empty::new().boxed();
             };
-
-        let filename = if let Some(path) = buffer.path() {
-            path.to_string_lossy()
+        let buffer = buffer.read(cx);
+        let filename = if let Some(file) = buffer.file() {
+            if file.path().file_name().is_none()
+                || self.project.read(cx).visible_worktrees(cx).count() > 1
+            {
+                file.full_path(cx).to_string_lossy().to_string()
+            } else {
+                file.path().to_string_lossy().to_string()
+            }
         } else {
-            Cow::Borrowed("untitled")
+            "untitled".to_string()
         };
 
         Flex::row()
-            .with_child(Label::new(filename.to_string(), theme.breadcrumbs.text.clone()).boxed())
+            .with_child(Label::new(filename, theme.breadcrumbs.text.clone()).boxed())
             .with_children(symbols.into_iter().flat_map(|symbol| {
                 [
                     Label::new(" 〉 ".to_string(), theme.breadcrumbs.text.clone()).boxed(),
@@ -99,7 +108,10 @@ impl ToolbarItemView for Breadcrumbs {
             if let Some(editor) = item.act_as::<Editor>(cx) {
                 self.subscriptions
                     .push(cx.subscribe(&editor, |_, _, event, cx| match event {
-                        editor::Event::BufferEdited => cx.notify(),
+                        editor::Event::BufferEdited
+                        | editor::Event::TitleChanged
+                        | editor::Event::Saved
+                        | editor::Event::Reparsed => cx.notify(),
                         editor::Event::SelectionsChanged { local } if *local => cx.notify(),
                         _ => {}
                     }));

crates/editor/src/editor.rs 🔗

@@ -5860,6 +5860,7 @@ impl Editor {
                 self.refresh_code_actions(cx);
                 cx.emit(Event::BufferEdited);
             }
+            language::Event::Reparsed => cx.emit(Event::Reparsed),
             language::Event::Dirtied => cx.emit(Event::Dirtied),
             language::Event::Saved => cx.emit(Event::Saved),
             language::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
@@ -5987,6 +5988,7 @@ pub enum Event {
     Activate,
     BufferEdited,
     Edited,
+    Reparsed,
     Blurred,
     Dirtied,
     Saved,

crates/editor/src/multi_buffer.rs 🔗

@@ -1001,6 +1001,13 @@ impl MultiBuffer {
             .collect()
     }
 
+    pub fn buffer(&self, buffer_id: usize) -> Option<ModelHandle<Buffer>> {
+        self.buffers
+            .borrow()
+            .get(&buffer_id)
+            .map(|state| state.buffer.clone())
+    }
+
     pub fn save(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
         let mut save_tasks = Vec::new();
         for BufferState { buffer, .. } in self.buffers.borrow().values() {
@@ -2268,12 +2275,12 @@ impl MultiBufferSnapshot {
         &self,
         offset: T,
         theme: Option<&SyntaxTheme>,
-    ) -> Option<(BufferSnapshot, Vec<OutlineItem<Anchor>>)> {
+    ) -> Option<(usize, Vec<OutlineItem<Anchor>>)> {
         let anchor = self.anchor_before(offset);
         let excerpt_id = anchor.excerpt_id();
         let excerpt = self.excerpt(excerpt_id)?;
         Some((
-            excerpt.buffer.clone(),
+            excerpt.buffer_id,
             excerpt
                 .buffer
                 .symbols_containing(anchor.text_anchor, theme)

crates/workspace/src/pane.rs 🔗

@@ -207,13 +207,16 @@ impl Pane {
 
                     let prev_active_index = mem::replace(&mut pane.active_item_index, index);
                     pane.focus_active_item(cx);
+                    pane.update_toolbar(cx);
+                    cx.emit(Event::ActivateItem { local: true });
+                    cx.notify();
+
                     let mut navigated = prev_active_index != pane.active_item_index;
                     if let Some(data) = entry.data {
                         navigated |= pane.active_item()?.navigate(data, cx);
                     }
 
                     if navigated {
-                        cx.notify();
                         break None;
                     }
                 }

crates/zed/src/zed.rs 🔗

@@ -106,18 +106,21 @@ pub fn build_workspace(
     app_state: &Arc<AppState>,
     cx: &mut ViewContext<Workspace>,
 ) -> Workspace {
-    cx.subscribe(&cx.handle(), |_, _, event, cx| {
-        let workspace::Event::PaneAdded(pane) = event;
-        pane.update(cx, |pane, cx| {
-            pane.toolbar().update(cx, |toolbar, cx| {
-                let breadcrumbs = cx.add_view(|_| Breadcrumbs::new());
-                toolbar.add_item(breadcrumbs, cx);
-                let buffer_search_bar = cx.add_view(|cx| BufferSearchBar::new(cx));
-                toolbar.add_item(buffer_search_bar, cx);
-                let project_search_bar = cx.add_view(|_| ProjectSearchBar::new());
-                toolbar.add_item(project_search_bar, cx);
-            })
-        });
+    cx.subscribe(&cx.handle(), {
+        let project = project.clone();
+        move |_, _, event, cx| {
+            let workspace::Event::PaneAdded(pane) = event;
+            pane.update(cx, |pane, cx| {
+                pane.toolbar().update(cx, |toolbar, cx| {
+                    let breadcrumbs = cx.add_view(|_| Breadcrumbs::new(project.clone()));
+                    toolbar.add_item(breadcrumbs, cx);
+                    let buffer_search_bar = cx.add_view(|cx| BufferSearchBar::new(cx));
+                    toolbar.add_item(buffer_search_bar, cx);
+                    let project_search_bar = cx.add_view(|_| ProjectSearchBar::new());
+                    toolbar.add_item(project_search_bar, cx);
+                })
+            });
+        }
     })
     .detach();