workspace: Fix read-only pane buttons being clickable even when a no-op (#46065)
The button was clickable for read-only panes even if the underlying item is not write-toggleable. Release Notes: - N/A *or* Added/Fixed/Improved ...
This commit is contained in:
1 parent
e57285fe39
commit
9cdb986fd4
7 files changed
+51
-35
No files matched your search
@@ -15,7 +15,7 @@ use gpui::{
|
||||
InteractiveElement, IntoElement, ParentElement, Render, SharedString, Styled, Subscription,
|
||||
Task, WeakEntity, Window, actions, div,
|
||||
};
|
||||
use language::{Buffer, DiagnosticEntry, DiagnosticEntryRef, Point};
|
||||
use language::{Buffer, Capability, DiagnosticEntry, DiagnosticEntryRef, Point};
|
||||
use project::{
|
||||
DiagnosticSummary, Event, Project, ProjectItem, ProjectPath,
|
||||
project_settings::{DiagnosticSeverity, ProjectSettings},
|
||||
@@ -763,8 +763,8 @@ impl Item for BufferDiagnosticsEditor {
|
||||
self.multibuffer.read(cx).is_dirty(cx)
|
||||
}
|
||||
|
||||
fn is_read_only(&self, cx: &App) -> bool {
|
||||
self.multibuffer.read(cx).read_only()
|
||||
fn capability(&self, cx: &App) -> Capability {
|
||||
self.multibuffer.read(cx).capability()
|
||||
}
|
||||
|
||||
fn navigate(
|
||||
|
||||
@@ -3162,6 +3162,14 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn capability(&self, cx: &App) -> Capability {
|
||||
if self.read_only {
|
||||
Capability::ReadOnly
|
||||
} else {
|
||||
self.buffer.read(cx).capability()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_only(&self, cx: &App) -> bool {
|
||||
self.read_only || self.buffer.read(cx).read_only()
|
||||
}
|
||||
|
||||
@@ -805,8 +805,8 @@ impl Item for Editor {
|
||||
self.buffer().read(cx).read(cx).is_dirty()
|
||||
}
|
||||
|
||||
fn is_read_only(&self, cx: &App) -> bool {
|
||||
self.read_only(cx)
|
||||
fn capability(&self, cx: &App) -> Capability {
|
||||
self.capability(cx)
|
||||
}
|
||||
|
||||
// Note: this mirrors the logic in `Editor::toggle_read_only`, but is reachable
|
||||
|
||||
@@ -85,7 +85,7 @@ pub static BUFFER_DIFF_TASK: LazyLock<TaskLabel> = LazyLock::new(TaskLabel::new)
|
||||
pub enum Capability {
|
||||
/// The buffer is a mutable replica.
|
||||
ReadWrite,
|
||||
/// The buffer is a mutable replica, but toggled to read-only.
|
||||
/// The buffer is a mutable replica, but toggled to be only readable.
|
||||
Read,
|
||||
/// The buffer is a read-only replica.
|
||||
ReadOnly,
|
||||
|
||||
@@ -1198,6 +1198,10 @@ impl MultiBuffer {
|
||||
!self.capability.editable()
|
||||
}
|
||||
|
||||
pub fn capability(&self) -> Capability {
|
||||
self.capability
|
||||
}
|
||||
|
||||
/// Returns an up-to-date snapshot of the MultiBuffer.
|
||||
#[ztracing::instrument(skip_all)]
|
||||
pub fn snapshot(&self, cx: &App) -> MultiBufferSnapshot {
|
||||
|
||||
@@ -15,6 +15,7 @@ use gpui::{
|
||||
EventEmitter, FocusHandle, Focusable, Font, HighlightStyle, Pixels, Point, Render,
|
||||
SharedString, Task, WeakEntity, Window,
|
||||
};
|
||||
use language::Capability;
|
||||
use project::{Project, ProjectEntryId, ProjectPath};
|
||||
pub use settings::{
|
||||
ActivateOnClose, ClosePosition, RegisterSetting, Settings, SettingsLocation, ShowCloseButton,
|
||||
@@ -255,8 +256,8 @@ pub trait Item: Focusable + EventEmitter<Self::Event> + Render + Sized {
|
||||
fn is_dirty(&self, _: &App) -> bool {
|
||||
false
|
||||
}
|
||||
fn is_read_only(&self, _: &App) -> bool {
|
||||
false
|
||||
fn capability(&self, _: &App) -> Capability {
|
||||
Capability::ReadWrite
|
||||
}
|
||||
|
||||
fn toggle_read_only(&mut self, _window: &mut Window, _cx: &mut Context<Self>) {}
|
||||
@@ -482,7 +483,7 @@ pub trait ItemHandle: 'static + Send {
|
||||
fn item_id(&self) -> EntityId;
|
||||
fn to_any_view(&self) -> AnyView;
|
||||
fn is_dirty(&self, cx: &App) -> bool;
|
||||
fn is_read_only(&self, cx: &App) -> bool;
|
||||
fn capability(&self, cx: &App) -> Capability;
|
||||
fn toggle_read_only(&self, window: &mut Window, cx: &mut App);
|
||||
fn has_deleted_file(&self, cx: &App) -> bool;
|
||||
fn has_conflict(&self, cx: &App) -> bool;
|
||||
@@ -957,8 +958,8 @@ impl<T: Item> ItemHandle for Entity<T> {
|
||||
self.read(cx).is_dirty(cx)
|
||||
}
|
||||
|
||||
fn is_read_only(&self, cx: &App) -> bool {
|
||||
self.read(cx).is_read_only(cx)
|
||||
fn capability(&self, cx: &App) -> Capability {
|
||||
self.read(cx).capability(cx)
|
||||
}
|
||||
|
||||
fn toggle_read_only(&self, window: &mut Window, cx: &mut App) {
|
||||
|
||||
@@ -26,7 +26,7 @@ use gpui::{
|
||||
actions, anchored, deferred, prelude::*,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use language::DiagnosticSeverity;
|
||||
use language::{Capability, DiagnosticSeverity};
|
||||
use parking_lot::Mutex;
|
||||
use project::{DirectoryLister, Project, ProjectEntryId, ProjectPath, WorktreeId};
|
||||
use schemars::JsonSchema;
|
||||
@@ -2678,12 +2678,13 @@ 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 = || {
|
||||
let read_only_toggle = |toggleable: bool| {
|
||||
IconButton::new("toggle_read_only", IconName::FileLock)
|
||||
.size(ButtonSize::None)
|
||||
.shape(IconButtonShape::Square)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_size(IconSize::Small)
|
||||
.disabled(!toggleable)
|
||||
.tooltip(move |_, cx| {
|
||||
Tooltip::with_meta("Unlock File", None, "This will make this file editable", cx)
|
||||
})
|
||||
@@ -2696,6 +2697,7 @@ impl Pane {
|
||||
|
||||
let has_file_icon = icon.is_some() | decorated_icon.is_some();
|
||||
|
||||
let capability = item.capability(cx);
|
||||
let tab = Tab::new(ix)
|
||||
.position(if is_first_item {
|
||||
TabPosition::First
|
||||
@@ -2836,21 +2838,21 @@ impl Pane {
|
||||
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 if !capability.editable() {
|
||||
Some(read_only_toggle(capability == Capability::Read).into_any_element())
|
||||
} else {
|
||||
None
|
||||
})
|
||||
.child(label)
|
||||
.map(|this| match tab_tooltip_content {
|
||||
Some(TabTooltipContent::Text(text)) => {
|
||||
if item.is_read_only(cx) {
|
||||
if capability.editable() {
|
||||
this.tooltip(Tooltip::text(text))
|
||||
} else {
|
||||
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)) => {
|
||||
@@ -2858,8 +2860,8 @@ impl Pane {
|
||||
}
|
||||
None => this,
|
||||
})
|
||||
.when(item.is_read_only(cx) && has_file_icon, |this| {
|
||||
this.child(read_only_toggle())
|
||||
.when(capability == Capability::Read && has_file_icon, |this| {
|
||||
this.child(read_only_toggle(true))
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -2876,7 +2878,6 @@ 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);
|
||||
@@ -3028,20 +3029,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 capability != Capability::ReadOnly {
|
||||
let read_only_label = if capability.editable() {
|
||||
"Make File Read-Only"
|
||||
} else {
|
||||
"Make File Editable"
|
||||
};
|
||||
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
|
||||
|
||||
Reference in new issue
Block a user