Merge branch 'main' into lsp-file-change-notifications

Max Brunsfeld created

Change summary

Cargo.lock                                             |  2 
crates/collab_ui/src/collab_titlebar_item.rs           |  3 
crates/collab_ui/src/sharing_status_indicator.rs       |  2 
crates/editor/src/element.rs                           | 15 ++-
crates/language_selector/src/active_buffer_language.rs | 42 ++++++-----
crates/project/src/terminals.rs                        |  3 
crates/terminal_view/src/terminal_button.rs            | 26 +++++--
crates/theme/src/theme.rs                              |  3 
crates/workspace/src/sidebar.rs                        |  4 
crates/zed/Cargo.toml                                  |  2 
crates/zed/src/languages/installation.rs               |  1 
styles/src/styleTree/statusBar.ts                      |  4 +
styles/src/styleTree/workspace.ts                      |  3 
13 files changed, 70 insertions(+), 40 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -8439,7 +8439,7 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
 
 [[package]]
 name = "zed"
-version = "0.79.0"
+version = "0.80.0"
 dependencies = [
  "activity_indicator",
  "anyhow",

crates/collab_ui/src/collab_titlebar_item.rs 🔗

@@ -89,7 +89,7 @@ impl View for CollabTitlebarItem {
         let theme = cx.global::<Settings>().theme.clone();
 
         let mut left_container = Flex::row();
-        let mut right_container = Flex::row();
+        let mut right_container = Flex::row().align_children_center();
 
         left_container.add_child(
             Label::new(project_title, theme.workspace.titlebar.title.clone())
@@ -117,6 +117,7 @@ impl View for CollabTitlebarItem {
 
         let status = workspace.read(cx).client().status();
         let status = &*status.borrow();
+
         if matches!(status, client::Status::Connected { .. }) {
             right_container.add_child(self.render_toggle_contacts_button(&theme, cx));
             right_container.add_child(self.render_user_menu_button(&theme, cx));

crates/collab_ui/src/sharing_status_indicator.rs 🔗

@@ -21,6 +21,8 @@ pub fn init(cx: &mut MutableAppContext) {
             } else if let Some((window_id, _)) = status_indicator.take() {
                 cx.remove_status_bar_item(window_id);
             }
+        } else if let Some((window_id, _)) = status_indicator.take() {
+            cx.remove_status_bar_item(window_id);
         }
     })
     .detach();

crates/editor/src/element.rs 🔗

@@ -576,13 +576,16 @@ impl EditorElement {
 
         for (ix, fold_indicator) in layout.fold_indicators.iter_mut().enumerate() {
             if let Some(indicator) = fold_indicator.as_mut() {
-                let mut x = bounds.width() - layout.gutter_padding;
-                let mut y = ix as f32 * line_height - scroll_top;
-
-                x += ((layout.gutter_padding + layout.gutter_margin) - indicator.size().x()) / 2.;
-                y += (line_height - indicator.size().y()) / 2.;
+                let position = vec2f(
+                    bounds.width() - layout.gutter_padding,
+                    ix as f32 * line_height - (scroll_top % line_height),
+                );
+                let centering_offset = vec2f(
+                    (layout.gutter_padding + layout.gutter_margin - indicator.size().x()) / 2.,
+                    (line_height - indicator.size().y()) / 2.,
+                );
 
-                let indicator_origin = bounds.origin() + vec2f(x, y);
+                let indicator_origin = bounds.origin() + position + centering_offset;
 
                 indicator.paint(indicator_origin, visible_bounds, cx);
             }

crates/language_selector/src/active_buffer_language.rs 🔗

@@ -8,7 +8,7 @@ use std::sync::Arc;
 use workspace::{item::ItemHandle, StatusItemView};
 
 pub struct ActiveBufferLanguage {
-    active_language: Option<Arc<str>>,
+    active_language: Option<Option<Arc<str>>>,
     _observe_active_editor: Option<Subscription>,
 }
 
@@ -27,12 +27,12 @@ impl ActiveBufferLanguage {
     }
 
     fn update_language(&mut self, editor: ViewHandle<Editor>, cx: &mut ViewContext<Self>) {
-        self.active_language.take();
+        self.active_language = Some(None);
 
         let editor = editor.read(cx);
         if let Some((_, buffer, _)) = editor.active_excerpt(cx) {
             if let Some(language) = buffer.read(cx).language() {
-                self.active_language = Some(language.name());
+                self.active_language = Some(Some(language.name()));
             }
         }
 
@@ -50,23 +50,27 @@ impl View for ActiveBufferLanguage {
     }
 
     fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
-        let active_language = if let Some(active_language) = self.active_language.as_ref() {
-            active_language.to_string()
-        } else {
-            "Unkown".to_string()
-        };
+        if let Some(active_language) = self.active_language.as_ref() {
+            let active_language_text = if let Some(active_language_text) = active_language {
+                active_language_text.to_string()
+            } else {
+                "Unknown".to_string()
+            };
 
-        MouseEventHandler::<Self>::new(0, cx, |state, cx| {
-            let theme = &cx.global::<Settings>().theme.workspace.status_bar;
-            let style = theme.active_language.style_for(state, false);
-            Label::new(active_language, style.text.clone())
-                .contained()
-                .with_style(style.container)
-                .boxed()
-        })
-        .with_cursor_style(CursorStyle::PointingHand)
-        .on_click(MouseButton::Left, |_, cx| cx.dispatch_action(crate::Toggle))
-        .boxed()
+            MouseEventHandler::<Self>::new(0, cx, |state, cx| {
+                let theme = &cx.global::<Settings>().theme.workspace.status_bar;
+                let style = theme.active_language.style_for(state, false);
+                Label::new(active_language_text, style.text.clone())
+                    .contained()
+                    .with_style(style.container)
+                    .boxed()
+            })
+            .with_cursor_style(CursorStyle::PointingHand)
+            .on_click(MouseButton::Left, |_, cx| cx.dispatch_action(crate::Toggle))
+            .boxed()
+        } else {
+            Empty::new().boxed()
+        }
     }
 }
 

crates/project/src/terminals.rs 🔗

@@ -43,11 +43,12 @@ impl Project {
                     .push(terminal_handle.downgrade());
 
                 let id = terminal_handle.id();
-                cx.observe_release(&terminal_handle, move |project, _terminal, _cx| {
+                cx.observe_release(&terminal_handle, move |project, _terminal, cx| {
                     let handles = &mut project.terminals.local_handles;
 
                     if let Some(index) = handles.iter().position(|terminal| terminal.id() == id) {
                         handles.remove(index);
+                        cx.notify();
                     }
                 })
                 .detach();

crates/terminal_view/src/terminal_button.rs 🔗

@@ -19,7 +19,6 @@ pub struct FocusTerminal {
     terminal_handle: WeakModelHandle<Terminal>,
 }
 
-//actions!(terminal, [DeployTerminalMenu]);
 impl_internal_actions!(terminal, [FocusTerminal, DeployTerminalMenu]);
 
 pub fn init(cx: &mut MutableAppContext) {
@@ -56,13 +55,14 @@ impl View for TerminalButton {
             .unwrap_or(false);
 
         let has_terminals = !project.local_terminal_handles().is_empty();
+        let terminal_count = project.local_terminal_handles().len() as i32;
         let theme = cx.global::<Settings>().theme.clone();
 
         Stack::new()
             .with_child(
                 MouseEventHandler::<Self>::new(0, cx, {
                     let theme = theme.clone();
-                    move |state, _| {
+                    move |state, _cx| {
                         let style = theme
                             .workspace
                             .status_bar
@@ -70,10 +70,23 @@ impl View for TerminalButton {
                             .item
                             .style_for(state, active);
 
-                        Svg::new("icons/terminal_12.svg")
-                            .with_color(style.icon_color)
+                        Flex::row()
+                            .with_child(
+                                Svg::new("icons/terminal_12.svg")
+                                    .with_color(style.icon_color)
+                                    .constrained()
+                                    .with_width(style.icon_size)
+                                    .aligned()
+                                    .named("terminals-icon"),
+                            )
+                            .with_children(has_terminals.then(|| {
+                                Label::new(terminal_count.to_string(), style.label.text.clone())
+                                    .contained()
+                                    .with_style(style.label.container)
+                                    .aligned()
+                                    .boxed()
+                            }))
                             .constrained()
-                            .with_width(style.icon_size)
                             .with_height(style.icon_size)
                             .contained()
                             .with_style(style.container)
@@ -112,8 +125,7 @@ impl View for TerminalButton {
 
 impl TerminalButton {
     pub fn new(workspace: ViewHandle<Workspace>, cx: &mut ViewContext<Self>) -> Self {
-        // When terminal moves, redraw so that the icon and toggle status matches.
-        cx.subscribe(&workspace, |_, _, _, cx| cx.notify()).detach();
+        cx.observe(&workspace, |_, _, cx| cx.notify()).detach();
         Self {
             workspace: workspace.downgrade(),
             popup_menu: cx.add_view(|cx| {

crates/theme/src/theme.rs 🔗

@@ -340,12 +340,13 @@ pub struct Sidebar {
     pub container: ContainerStyle,
 }
 
-#[derive(Clone, Copy, Deserialize, Default)]
+#[derive(Clone, Deserialize, Default)]
 pub struct SidebarItem {
     #[serde(flatten)]
     pub container: ContainerStyle,
     pub icon_color: Color,
     pub icon_size: f32,
+    pub label: ContainedText,
 }
 
 #[derive(Deserialize, Default)]

crates/workspace/src/sidebar.rs 🔗

@@ -230,7 +230,7 @@ impl View for SidebarButtons {
         let tooltip_style = theme.tooltip.clone();
         let theme = &theme.workspace.status_bar.sidebar_buttons;
         let sidebar = self.sidebar.read(cx);
-        let item_style = theme.item;
+        let item_style = theme.item.clone();
         let badge_style = theme.badge;
         let active_ix = sidebar.active_item_ix;
         let is_open = sidebar.is_open;
@@ -254,7 +254,7 @@ impl View for SidebarButtons {
                         sidebar_side,
                         item_index: ix,
                     };
-                    MouseEventHandler::<Self>::new(ix, cx, move |state, cx| {
+                    MouseEventHandler::<Self>::new(ix, cx, |state, cx| {
                         let is_active = is_open && ix == active_ix;
                         let style = item_style.style_for(state, is_active);
                         Stack::new()

crates/zed/Cargo.toml 🔗

@@ -3,7 +3,7 @@ authors = ["Nathan Sobo <nathansobo@gmail.com>"]
 description = "The fast, collaborative code editor."
 edition = "2021"
 name = "zed"
-version = "0.79.0"
+version = "0.80.0"
 publish = false
 
 [lib]

crates/zed/src/languages/installation.rs 🔗

@@ -64,7 +64,6 @@ pub async fn npm_install_packages(
     let output = smol::process::Command::new("npm")
         .args(["-fetch-retry-mintimeout", "2000"])
         .args(["-fetch-retry-maxtimeout", "5000"])
-        .args(["-fetch-timeout", "5000"])
         .arg("install")
         .arg("--prefix")
         .arg(directory)

styles/src/styleTree/statusBar.ts 🔗

@@ -100,6 +100,10 @@ export default function statusBar(colorScheme: ColorScheme) {
                 ...statusContainer,
                 iconSize: 16,
                 iconColor: foreground(layer, "variant"),
+                label: {
+                    margin: { left: 6 },
+                    ...text(layer, "sans", { size: "sm" }),
+                },
                 hover: {
                     iconColor: foreground(layer, "hovered"),
                     background: background(layer, "variant"),

styles/src/styleTree/workspace.ts 🔗

@@ -174,6 +174,9 @@ export default function workspace(colorScheme: ColorScheme) {
             // Sign in buttom
             // FlatButton, Variant
             signInPrompt: {
+                margin: {
+                    left: itemSpacing
+                },
                 ...titlebarButton,
             },