Editor toolbar configuration (#7338)

Adds settings for hiding breadcrumbs and quick action bar from
the editor toolbar. If both elements are hidden, the toolbar disappears
completely.

Example:

```json
"toolbar": {
  "breadcrumbs": true,
  "quick_actions": false
}
```

- It intentionally doesn't hide breadcrumbs in other views (for
instance, in the search result window) because their usage there differ
from the main editor.
- The editor controls how breadcrumbs are displayed in the toolbar, so
implementation differs a bit for breadcrumbs and quick actions bar.

Release Notes:

- Added support for configuring the editor toolbar ([4756](https://github.com/zed-industries/zed/issues/4756))
This commit is contained in:
Andrew Lygin 2024-02-03 23:40:54 +03:00 committed by GitHub
parent 55185c159b
commit 8da6e62914
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 113 additions and 38 deletions

1
Cargo.lock generated
View file

@ -6064,6 +6064,7 @@ dependencies = [
"editor",
"gpui",
"search",
"settings",
"ui",
"workspace",
]

View file

@ -109,6 +109,13 @@
// Share your project when you are the first to join a channel
"share_on_join": true
},
// Toolbar related settings
"toolbar": {
// Whether to show breadcrumbs.
"breadcrumbs": true,
// Whether to show quick action buttons.
"quick_actions": true
},
// Scrollbar related settings
"scrollbar": {
// When to show the scrollbar in the editor.

View file

@ -374,6 +374,7 @@ pub struct Editor {
hovered_cursors: HashMap<HoveredCursor, Task<()>>,
pub show_local_selections: bool,
mode: EditorMode,
show_breadcrumbs: bool,
show_gutter: bool,
show_wrap_guides: Option<bool>,
placeholder_text: Option<Arc<str>>,
@ -1448,6 +1449,7 @@ impl Editor {
blink_manager: blink_manager.clone(),
show_local_selections: true,
mode,
show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
show_gutter: mode == EditorMode::Full,
show_wrap_guides: None,
placeholder_text: None,
@ -8762,8 +8764,9 @@ impl Editor {
)),
cx,
);
self.scroll_manager.vertical_scroll_margin =
EditorSettings::get_global(cx).vertical_scroll_margin;
let editor_settings = EditorSettings::get_global(cx);
self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
cx.notify();
}

View file

@ -10,6 +10,7 @@ pub struct EditorSettings {
pub show_completion_documentation: bool,
pub completion_documentation_secondary_query_debounce: u64,
pub use_on_type_format: bool,
pub toolbar: Toolbar,
pub scrollbar: Scrollbar,
pub vertical_scroll_margin: f32,
pub relative_line_numbers: bool,
@ -29,6 +30,12 @@ pub enum SeedQuerySetting {
Never,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct Toolbar {
pub breadcrumbs: bool,
pub quick_actions: bool,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct Scrollbar {
pub show: ShowScrollbar,
@ -86,6 +93,8 @@ pub struct EditorSettingsContent {
///
/// Default: true
pub use_on_type_format: Option<bool>,
/// Toolbar related settings
pub toolbar: Option<ToolbarContent>,
/// Scrollbar related settings
pub scrollbar: Option<ScrollbarContent>,
@ -110,6 +119,19 @@ pub struct EditorSettingsContent {
pub redact_private_values: Option<bool>,
}
// Toolbar related settings
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct ToolbarContent {
/// Whether to display breadcrumbs in the editor toolbar.
///
/// Default: true
pub breadcrumbs: Option<bool>,
/// Whether to display quik action buttons in the editor toolbar.
///
/// Default: true
pub quick_actions: Option<bool>,
}
/// Scrollbar related settings
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct ScrollbarContent {

View file

@ -800,7 +800,11 @@ impl Item for Editor {
}
fn breadcrumb_location(&self) -> ToolbarItemLocation {
ToolbarItemLocation::PrimaryLeft
if self.show_breadcrumbs {
ToolbarItemLocation::PrimaryLeft
} else {
ToolbarItemLocation::Hidden
}
}
fn breadcrumbs(&self, variant: &Theme, cx: &AppContext) -> Option<Vec<BreadcrumbText>> {

View file

@ -14,6 +14,7 @@ assistant = { path = "../assistant" }
editor = { path = "../editor" }
gpui = { path = "../gpui" }
search = { path = "../search" }
settings = { path = "../settings" }
ui = { path = "../ui" }
workspace = { path = "../workspace" }

View file

@ -1,11 +1,12 @@
use assistant::{AssistantPanel, InlineAssist};
use editor::Editor;
use editor::{Editor, EditorSettings};
use gpui::{
Action, ClickEvent, ElementId, EventEmitter, InteractiveElement, ParentElement, Render, Styled,
Subscription, View, ViewContext, WeakView,
};
use search::{buffer_search, BufferSearchBar};
use settings::{Settings, SettingsStore};
use ui::{prelude::*, ButtonSize, ButtonStyle, IconButton, IconName, IconSize, Tooltip};
use workspace::{
item::ItemHandle, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace,
@ -16,16 +17,26 @@ pub struct QuickActionBar {
active_item: Option<Box<dyn ItemHandle>>,
_inlay_hints_enabled_subscription: Option<Subscription>,
workspace: WeakView<Workspace>,
show: bool,
}
impl QuickActionBar {
pub fn new(buffer_search_bar: View<BufferSearchBar>, workspace: &Workspace) -> Self {
Self {
pub fn new(
buffer_search_bar: View<BufferSearchBar>,
workspace: &Workspace,
cx: &mut ViewContext<Self>,
) -> Self {
let mut this = Self {
buffer_search_bar,
active_item: None,
_inlay_hints_enabled_subscription: None,
workspace: workspace.weak_handle(),
}
show: true,
};
this.apply_settings(cx);
cx.observe_global::<SettingsStore>(|this, cx| this.apply_settings(cx))
.detach();
this
}
fn active_editor(&self) -> Option<View<Editor>> {
@ -33,6 +44,24 @@ impl QuickActionBar {
.as_ref()
.and_then(|item| item.downcast::<Editor>())
}
fn apply_settings(&mut self, cx: &mut ViewContext<Self>) {
let new_show = EditorSettings::get_global(cx).toolbar.quick_actions;
if new_show != self.show {
self.show = new_show;
cx.emit(ToolbarItemEvent::ChangeLocation(
self.get_toolbar_item_location(),
));
}
}
fn get_toolbar_item_location(&self) -> ToolbarItemLocation {
if self.show && self.active_editor().is_some() {
ToolbarItemLocation::PrimaryRight
} else {
ToolbarItemLocation::Hidden
}
}
}
impl Render for QuickActionBar {
@ -40,7 +69,6 @@ impl Render for QuickActionBar {
let Some(editor) = self.active_editor() else {
return div().id("empty quick action bar");
};
let inlay_hints_button = Some(QuickActionBarButton::new(
"toggle inlay hints",
IconName::InlayHint,
@ -155,36 +183,28 @@ impl ToolbarItemView for QuickActionBar {
active_pane_item: Option<&dyn ItemHandle>,
cx: &mut ViewContext<Self>,
) -> ToolbarItemLocation {
match active_pane_item {
Some(active_item) => {
self.active_item = Some(active_item.boxed_clone());
self._inlay_hints_enabled_subscription.take();
self.active_item = active_pane_item.map(ItemHandle::boxed_clone);
if let Some(active_item) = active_pane_item {
self._inlay_hints_enabled_subscription.take();
if let Some(editor) = active_item.downcast::<Editor>() {
let mut inlay_hints_enabled = editor.read(cx).inlay_hints_enabled();
let mut supports_inlay_hints = editor.read(cx).supports_inlay_hints(cx);
self._inlay_hints_enabled_subscription =
Some(cx.observe(&editor, move |_, editor, cx| {
let editor = editor.read(cx);
let new_inlay_hints_enabled = editor.inlay_hints_enabled();
let new_supports_inlay_hints = editor.supports_inlay_hints(cx);
let should_notify = inlay_hints_enabled != new_inlay_hints_enabled
|| supports_inlay_hints != new_supports_inlay_hints;
inlay_hints_enabled = new_inlay_hints_enabled;
supports_inlay_hints = new_supports_inlay_hints;
if should_notify {
cx.notify()
}
}));
ToolbarItemLocation::PrimaryRight
} else {
ToolbarItemLocation::Hidden
}
}
None => {
self.active_item = None;
ToolbarItemLocation::Hidden
if let Some(editor) = active_item.downcast::<Editor>() {
let mut inlay_hints_enabled = editor.read(cx).inlay_hints_enabled();
let mut supports_inlay_hints = editor.read(cx).supports_inlay_hints(cx);
self._inlay_hints_enabled_subscription =
Some(cx.observe(&editor, move |_, editor, cx| {
let editor = editor.read(cx);
let new_inlay_hints_enabled = editor.inlay_hints_enabled();
let new_supports_inlay_hints = editor.supports_inlay_hints(cx);
let should_notify = inlay_hints_enabled != new_inlay_hints_enabled
|| supports_inlay_hints != new_supports_inlay_hints;
inlay_hints_enabled = new_inlay_hints_enabled;
supports_inlay_hints = new_supports_inlay_hints;
if should_notify {
cx.notify()
}
}));
}
}
self.get_toolbar_item_location()
}
}

View file

@ -127,7 +127,7 @@ impl Render for Toolbar {
h_flex()
// We're using `flex_none` here to prevent some flickering that can occur when the
// size of the left items container changes.
.flex_none()
.when_else(has_left_items, Div::flex_none, Div::flex_auto)
.justify_end()
.children(self.right_items().map(|item| item.to_any())),
)

View file

@ -353,7 +353,7 @@ fn initialize_pane(workspace: &mut Workspace, pane: &View<Pane>, cx: &mut ViewCo
toolbar.add_item(buffer_search_bar.clone(), cx);
let quick_action_bar =
cx.new_view(|_| QuickActionBar::new(buffer_search_bar, workspace));
cx.new_view(|cx| QuickActionBar::new(buffer_search_bar, workspace, cx));
toolbar.add_item(quick_action_bar, cx);
let diagnostic_editor_controls = cx.new_view(|_| diagnostics::ToolbarControls::new());
toolbar.add_item(diagnostic_editor_controls, cx);

View file

@ -190,6 +190,23 @@ List of `string` values
2. Position the dock to the right of the workspace like a side panel: `right`
3. Position the dock full screen over the entire workspace: `expanded`
## Editor Toolbar
- Description: Whether or not to show various elements in the editor toolbar.
- Setting: `toolbar`
- Default:
```json
"toolbar": {
"breadcrumbs": true,
"quick_actions": true
},
```
**Options**
Each option controls displaying of a particular toolbar element. If all elements are hidden, the editor toolbar is not displayed.
## Enable Language Server
- Description: Whether or not to use language servers to provide code intelligence.