diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 348a2a87de94dee4894f11b990eb8870c8a96681..3192c6fe7960af9775c8b267e92e83d1857295d7 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -2647,6 +2647,24 @@ impl Pane { let is_pinned = self.is_tab_pinned(ix); let position_relative_to_active_item = ix.cmp(&self.active_item_index); + let read_only_toggle = || { + IconButton::new("toggle_read_only", IconName::FileLock) + .size(ButtonSize::None) + .shape(IconButtonShape::Square) + .icon_color(Color::Muted) + .icon_size(IconSize::Small) + .tooltip(move |_, cx| { + Tooltip::with_meta("Unlock File", None, "This will make this file editable", cx) + }) + .on_click(cx.listener(move |pane, _, window, cx| { + if let Some(item) = pane.item_for_index(ix) { + item.toggle_read_only(window, cx); + } + })) + }; + + let has_file_icon = icon.is_some() | decorated_icon.is_some(); + let tab = Tab::new(ix) .position(if is_first_item { TabPosition::First @@ -2781,30 +2799,36 @@ impl Pane { }) .child( h_flex() + .id(("pane-tab-content", ix)) .gap_1() - .items_center() .children(if let Some(decorated_icon) = decorated_icon { - Some(div().child(decorated_icon.into_any_element())) + Some(decorated_icon.into_any_element()) + } else if let Some(icon) = icon { + Some(icon.into_any_element()) + } else if item.is_read_only(cx) { + Some(read_only_toggle().into_any_element()) } else { - icon.map(|icon| div().child(icon.into_any_element())) + None }) .child(label) - .id(("pane-tab-content", ix)) .map(|this| match tab_tooltip_content { - Some(TabTooltipContent::Text(text)) => this.tooltip(Tooltip::text(text)), + Some(TabTooltipContent::Text(text)) => { + if item.is_read_only(cx) { + this.tooltip(move |_, cx| { + let text = text.clone(); + Tooltip::with_meta(text, None, "Read-Only File", cx) + }) + } else { + this.tooltip(Tooltip::text(text)) + } + } Some(TabTooltipContent::Custom(element_fn)) => { this.tooltip(move |window, cx| element_fn(window, cx)) } None => this, }) - .children(if item.is_read_only(cx) { - Some( - Icon::new(IconName::FileLock) - .color(Color::Muted) - .size(IconSize::Small), - ) - } else { - None + .when(item.is_read_only(cx) && has_file_icon, |this| { + this.child(read_only_toggle()) }), ); @@ -2821,8 +2845,11 @@ impl Pane { let has_items_to_right = ix < total_items - 1; let has_clean_items = self.items.iter().any(|item| !item.is_dirty(cx)); let is_pinned = self.is_tab_pinned(ix); + let is_read_only = item.is_read_only(cx); + let pane = cx.entity().downgrade(); let menu_context = item.item_focus_handle(cx); + right_click_menu(ix) .trigger(|_, _, _| tab) .menu(move |window, cx| { @@ -2969,6 +2996,22 @@ impl Pane { } }) }; + + let read_only_label = if is_read_only { + "Make File Editable" + } else { + "Make File Read-Only" + }; + menu = menu.separator().entry( + read_only_label, + None, + window.handler_for(&pane, move |pane, window, cx| { + if let Some(item) = pane.item_for_index(ix) { + item.toggle_read_only(window, cx); + } + }), + ); + if let Some(entry) = single_entry_to_resolve { let project_path = pane .read(cx) @@ -3000,6 +3043,7 @@ impl Pane { && worktree.is_some_and(|worktree| worktree.read(cx).is_visible()); let entry_id = entry.to_proto(); + menu = menu .separator() .when_some(entry_abs_path, |menu, abs_path| { @@ -3064,7 +3108,7 @@ impl Pane { } else { menu = menu.map(pin_tab_entries); } - } + }; menu.context(menu_context) })