Show error and warning indicators in project panel items (#18182)

Closes #5016

Release Notes:

- Add setting to display error and warning indicators in project panel
items.


https://github.com/user-attachments/assets/8f8031e6-ca47-42bf-a7eb-718eb1067f36

---------

Co-authored-by: Thorsten Ball <mrnugget@gmail.com>
Co-authored-by: Danilo Leal <67129314+danilo-leal@users.noreply.github.com>
This commit is contained in:
Nils Koch 2024-11-12 22:58:59 +01:00 committed by GitHub
parent a7eb3a9b9f
commit 0a9c78a58d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 262 additions and 30 deletions

View File

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.4662 14.9152C13.5801 15.0291 13.7648 15.0291 13.8787 14.9152L14.9145 13.8793C15.0284 13.7654 15.0284 13.5807 14.9145 13.4667L12.9483 11.5004L14.9145 9.53392C15.0285 9.42004 15.0285 9.23533 14.9145 9.12137L13.8787 8.08547C13.7648 7.97154 13.5801 7.97154 13.4662 8.08547L11.5 10.0519L9.53376 8.08545C9.41988 7.97152 9.23517 7.97152 9.12124 8.08545L8.08543 9.12136C7.97152 9.23533 7.97152 9.42004 8.08543 9.53392L10.0517 11.5004L8.08545 13.4667C7.97155 13.5807 7.97155 13.7654 8.08545 13.8793L9.12126 14.9152C9.23517 15.0292 9.41988 15.0292 9.53376 14.9152L11.5 12.9489L13.4662 14.9152Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 756 B

View File

@ -1,3 +1,10 @@
<svg width="11" height="11" viewBox="0 0 11 11" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="11" height="11" viewBox="0 0 11 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.364 7.6025L1.64681 8.75H3H8H9.35319L8.636 7.6025L6.136 3.6025L5.5 2.5849L4.864 3.6025L2.364 7.6025Z" stroke="black" stroke-width="1.5"/> <g clip-path="url(#clip0_2080_948)">
<path d="M1.52492 8.72287L1.04243 9.55H2H9H9.95757L9.47508 8.72287L5.97508 2.72287L5.5 1.90845L5.02492 2.72287L1.52492 8.72287Z" stroke="black" stroke-width="1.1"/>
</g>
<defs>
<clipPath id="clip0_2080_948">
<rect width="11" height="11" fill="white"/>
</clipPath>
</defs>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 252 B

After

Width:  |  Height:  |  Size: 412 B

View File

@ -1,3 +1,3 @@
<svg width="11" height="11" viewBox="0 0 11 11" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="11" height="11" viewBox="0 0 11 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 8H8L5.5 4L3 8Z" fill="black"/> <path d="M2 9H9L5.5 3L2 9Z" fill="black"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 146 B

After

Width:  |  Height:  |  Size: 146 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 4L4 12H12L8 4Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 155 B

3
assets/icons/x.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 4L12 12M12 4L4 12" stroke="currentColor" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 177 B

View File

@ -383,6 +383,16 @@
/// "never" /// "never"
"show": null "show": null
}, },
/// Which files containing diagnostic errors/warnings to mark in the project panel.
/// This setting can take the following three values:
///
/// 1. Do not mark any files:
/// "off"
/// 2. Only mark files with errors:
/// "errors"
/// 3. Mark files with errors and warnings:
/// "all"
"show_diagnostics": "all",
// Settings related to indent guides in the project panel. // Settings related to indent guides in the project panel.
"indent_guides": { "indent_guides": {
// When to show indent guides in the project panel. // When to show indent guides in the project panel.

View File

@ -18,6 +18,7 @@ use gpui::{
use language::{ use language::{
proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, CharKind, Point, SelectionGoal, proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, CharKind, Point, SelectionGoal,
}; };
use lsp::DiagnosticSeverity;
use multi_buffer::AnchorRangeExt; use multi_buffer::AnchorRangeExt;
use project::{ use project::{
lsp_store::FormatTrigger, project_settings::ProjectSettings, search::SearchQuery, Item as _, lsp_store::FormatTrigger, project_settings::ProjectSettings, search::SearchQuery, Item as _,
@ -39,7 +40,7 @@ use std::{
}; };
use text::{BufferId, Selection}; use text::{BufferId, Selection};
use theme::{Theme, ThemeSettings}; use theme::{Theme, ThemeSettings};
use ui::{h_flex, prelude::*, Label}; use ui::{h_flex, prelude::*, IconDecorationKind, Label};
use util::{paths::PathExt, ResultExt, TryFutureExt}; use util::{paths::PathExt, ResultExt, TryFutureExt};
use workspace::item::{BreadcrumbText, FollowEvent}; use workspace::item::{BreadcrumbText, FollowEvent};
use workspace::{ use workspace::{
@ -1515,6 +1516,26 @@ pub fn entry_label_color(selected: bool) -> Color {
} }
} }
pub fn entry_diagnostic_aware_icon_name_and_color(
diagnostic_severity: Option<DiagnosticSeverity>,
) -> Option<(IconName, Color)> {
match diagnostic_severity {
Some(DiagnosticSeverity::ERROR) => Some((IconName::X, Color::Error)),
Some(DiagnosticSeverity::WARNING) => Some((IconName::Triangle, Color::Warning)),
_ => None,
}
}
pub fn entry_diagnostic_aware_icon_decoration_and_color(
diagnostic_severity: Option<DiagnosticSeverity>,
) -> Option<(IconDecorationKind, Color)> {
match diagnostic_severity {
Some(DiagnosticSeverity::ERROR) => Some((IconDecorationKind::X, Color::Error)),
Some(DiagnosticSeverity::WARNING) => Some((IconDecorationKind::Triangle, Color::Warning)),
_ => None,
}
}
pub fn entry_git_aware_label_color( pub fn entry_git_aware_label_color(
git_status: Option<GitFileStatus>, git_status: Option<GitFileStatus>,
ignored: bool, ignored: bool,

View File

@ -37,6 +37,7 @@ util.workspace = true
client.workspace = true client.workspace = true
worktree.workspace = true worktree.workspace = true
workspace.workspace = true workspace.workspace = true
language.workspace = true
[dev-dependencies] [dev-dependencies]
client = { workspace = true, features = ["test-support"] } client = { workspace = true, features = ["test-support"] }

View File

@ -1,12 +1,15 @@
mod project_panel_settings; mod project_panel_settings;
use client::{ErrorCode, ErrorExt}; use client::{ErrorCode, ErrorExt};
use language::DiagnosticSeverity;
use settings::{Settings, SettingsStore}; use settings::{Settings, SettingsStore};
use ui::{Scrollbar, ScrollbarState};
use db::kvp::KEY_VALUE_STORE; use db::kvp::KEY_VALUE_STORE;
use editor::{ use editor::{
items::entry_git_aware_label_color, items::{
entry_diagnostic_aware_icon_decoration_and_color,
entry_diagnostic_aware_icon_name_and_color, entry_git_aware_label_color,
},
scroll::{Autoscroll, ScrollbarAutoHide}, scroll::{Autoscroll, ScrollbarAutoHide},
Editor, EditorEvent, EditorSettings, ShowScrollbar, Editor, EditorEvent, EditorSettings, ShowScrollbar,
}; };
@ -18,7 +21,7 @@ use git::repository::GitFileStatus;
use gpui::{ use gpui::{
actions, anchored, deferred, div, impl_actions, point, px, size, uniform_list, Action, actions, anchored, deferred, div, impl_actions, point, px, size, uniform_list, Action,
AnyElement, AppContext, AssetSource, AsyncWindowContext, Bounds, ClipboardItem, DismissEvent, AnyElement, AppContext, AssetSource, AsyncWindowContext, Bounds, ClipboardItem, DismissEvent,
Div, DragMoveEvent, EventEmitter, ExternalPaths, FocusHandle, FocusableView, Div, DragMoveEvent, EventEmitter, ExternalPaths, FocusHandle, FocusableView, Hsla,
InteractiveElement, KeyContext, ListHorizontalSizingBehavior, ListSizingBehavior, Model, InteractiveElement, KeyContext, ListHorizontalSizingBehavior, ListSizingBehavior, Model,
MouseButton, MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, Render, ScrollStrategy, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, Render, ScrollStrategy,
Stateful, Styled, Subscription, Task, UniformListScrollHandle, View, ViewContext, Stateful, Styled, Subscription, Task, UniformListScrollHandle, View, ViewContext,
@ -30,7 +33,9 @@ use project::{
relativize_path, Entry, EntryKind, Fs, Project, ProjectEntryId, ProjectPath, Worktree, relativize_path, Entry, EntryKind, Fs, Project, ProjectEntryId, ProjectPath, Worktree,
WorktreeId, WorktreeId,
}; };
use project_panel_settings::{ProjectPanelDockPosition, ProjectPanelSettings, ShowIndentGuides}; use project_panel_settings::{
ProjectPanelDockPosition, ProjectPanelSettings, ShowDiagnostics, ShowIndentGuides,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{ use std::{
@ -44,8 +49,9 @@ use std::{
}; };
use theme::ThemeSettings; use theme::ThemeSettings;
use ui::{ use ui::{
prelude::*, v_flex, ContextMenu, Icon, IndentGuideColors, IndentGuideLayout, KeyBinding, Label, prelude::*, v_flex, ContextMenu, DecoratedIcon, Icon, IconDecoration, IconDecorationKind,
ListItem, Tooltip, IndentGuideColors, IndentGuideLayout, KeyBinding, Label, ListItem, Scrollbar, ScrollbarState,
Tooltip,
}; };
use util::{maybe, ResultExt, TryFutureExt}; use util::{maybe, ResultExt, TryFutureExt};
use workspace::{ use workspace::{
@ -90,6 +96,7 @@ pub struct ProjectPanel {
vertical_scrollbar_state: ScrollbarState, vertical_scrollbar_state: ScrollbarState,
horizontal_scrollbar_state: ScrollbarState, horizontal_scrollbar_state: ScrollbarState,
hide_scrollbar_task: Option<Task<()>>, hide_scrollbar_task: Option<Task<()>>,
diagnostics: HashMap<(WorktreeId, PathBuf), DiagnosticSeverity>,
max_width_item_index: Option<usize>, max_width_item_index: Option<usize>,
// We keep track of the mouse down state on entries so we don't flash the UI // We keep track of the mouse down state on entries so we don't flash the UI
// in case a user clicks to open a file. // in case a user clicks to open a file.
@ -133,6 +140,8 @@ struct EntryDetails {
is_editing: bool, is_editing: bool,
is_processing: bool, is_processing: bool,
is_cut: bool, is_cut: bool,
filename_text_color: Color,
diagnostic_severity: Option<DiagnosticSeverity>,
git_status: Option<GitFileStatus>, git_status: Option<GitFileStatus>,
is_private: bool, is_private: bool,
worktree_id: WorktreeId, worktree_id: WorktreeId,
@ -234,6 +243,26 @@ struct DraggedProjectEntryView {
selections: Arc<BTreeSet<SelectedEntry>>, selections: Arc<BTreeSet<SelectedEntry>>,
} }
struct ItemColors {
default: Hsla,
hover: Hsla,
drag_over: Hsla,
selected: Hsla,
marked_active: Hsla,
}
fn get_item_color(cx: &ViewContext<ProjectPanel>) -> ItemColors {
let colors = cx.theme().colors();
ItemColors {
default: colors.surface_background,
hover: colors.ghost_element_hover,
drag_over: colors.drop_target_background,
selected: colors.surface_background,
marked_active: colors.ghost_element_selected,
}
}
impl ProjectPanel { impl ProjectPanel {
fn new(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) -> View<Self> { fn new(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) -> View<Self> {
let project = workspace.project().clone(); let project = workspace.project().clone();
@ -257,6 +286,14 @@ impl ProjectPanel {
project::Event::ActivateProjectPanel => { project::Event::ActivateProjectPanel => {
cx.emit(PanelEvent::Activate); cx.emit(PanelEvent::Activate);
} }
project::Event::DiskBasedDiagnosticsFinished { .. }
| project::Event::DiagnosticsUpdated { .. } => {
if ProjectPanelSettings::get_global(cx).show_diagnostics != ShowDiagnostics::Off
{
this.update_diagnostics(cx);
cx.notify();
}
}
project::Event::WorktreeRemoved(id) => { project::Event::WorktreeRemoved(id) => {
this.expanded_dir_ids.remove(id); this.expanded_dir_ids.remove(id);
this.update_visible_entries(None, cx); this.update_visible_entries(None, cx);
@ -302,10 +339,11 @@ impl ProjectPanel {
.detach(); .detach();
let mut project_panel_settings = *ProjectPanelSettings::get_global(cx); let mut project_panel_settings = *ProjectPanelSettings::get_global(cx);
cx.observe_global::<SettingsStore>(move |_, cx| { cx.observe_global::<SettingsStore>(move |this, cx| {
let new_settings = *ProjectPanelSettings::get_global(cx); let new_settings = *ProjectPanelSettings::get_global(cx);
if project_panel_settings != new_settings { if project_panel_settings != new_settings {
project_panel_settings = new_settings; project_panel_settings = new_settings;
this.update_diagnostics(cx);
cx.notify(); cx.notify();
} }
}) })
@ -340,6 +378,7 @@ impl ProjectPanel {
horizontal_scrollbar_state: ScrollbarState::new(scroll_handle.clone()) horizontal_scrollbar_state: ScrollbarState::new(scroll_handle.clone())
.parent_view(cx.view()), .parent_view(cx.view()),
max_width_item_index: None, max_width_item_index: None,
diagnostics: Default::default(),
scroll_handle, scroll_handle,
mouse_down: false, mouse_down: false,
}; };
@ -456,6 +495,64 @@ impl ProjectPanel {
}) })
} }
fn update_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
let mut diagnostics: HashMap<(WorktreeId, PathBuf), DiagnosticSeverity> =
Default::default();
let show_diagnostics_setting = ProjectPanelSettings::get_global(cx).show_diagnostics;
if show_diagnostics_setting != ShowDiagnostics::Off {
self.project
.read(cx)
.diagnostic_summaries(false, cx)
.filter_map(|(path, _, diagnostic_summary)| {
if diagnostic_summary.error_count > 0 {
Some((path, DiagnosticSeverity::ERROR))
} else if show_diagnostics_setting == ShowDiagnostics::All
&& diagnostic_summary.warning_count > 0
{
Some((path, DiagnosticSeverity::WARNING))
} else {
None
}
})
.for_each(|(project_path, diagnostic_severity)| {
let mut path_buffer = PathBuf::new();
Self::update_strongest_diagnostic_severity(
&mut diagnostics,
&project_path,
path_buffer.clone(),
diagnostic_severity,
);
for component in project_path.path.components() {
path_buffer.push(component);
Self::update_strongest_diagnostic_severity(
&mut diagnostics,
&project_path,
path_buffer.clone(),
diagnostic_severity,
);
}
});
}
self.diagnostics = diagnostics;
}
fn update_strongest_diagnostic_severity(
diagnostics: &mut HashMap<(WorktreeId, PathBuf), DiagnosticSeverity>,
project_path: &ProjectPath,
path_buffer: PathBuf,
diagnostic_severity: DiagnosticSeverity,
) {
diagnostics
.entry((project_path.worktree_id, path_buffer.clone()))
.and_modify(|strongest_diagnostic_severity| {
*strongest_diagnostic_severity =
std::cmp::min(*strongest_diagnostic_severity, diagnostic_severity);
})
.or_insert(diagnostic_severity);
}
fn serialize(&mut self, cx: &mut ViewContext<Self>) { fn serialize(&mut self, cx: &mut ViewContext<Self>) {
let width = self.width; let width = self.width;
self.pending_serialization = cx.background_executor().spawn( self.pending_serialization = cx.background_executor().spawn(
@ -2353,6 +2450,23 @@ impl ProjectPanel {
worktree_id: snapshot.id(), worktree_id: snapshot.id(),
entry_id: entry.id, entry_id: entry.id,
}; };
let is_marked = self.marked_entries.contains(&selection);
let diagnostic_severity = self
.diagnostics
.get(&(*worktree_id, entry.path.to_path_buf()))
.cloned();
let filename_text_color = if entry.kind.is_file()
&& diagnostic_severity
.map_or(false, |severity| severity == DiagnosticSeverity::ERROR)
{
Color::Error
} else {
entry_git_aware_label_color(status, entry.is_ignored, is_marked)
};
let mut details = EntryDetails { let mut details = EntryDetails {
filename, filename,
icon, icon,
@ -2362,13 +2476,15 @@ impl ProjectPanel {
is_ignored: entry.is_ignored, is_ignored: entry.is_ignored,
is_expanded, is_expanded,
is_selected: self.selection == Some(selection), is_selected: self.selection == Some(selection),
is_marked: self.marked_entries.contains(&selection), is_marked,
is_editing: false, is_editing: false,
is_processing: false, is_processing: false,
is_cut: self is_cut: self
.clipboard .clipboard
.as_ref() .as_ref()
.map_or(false, |e| e.is_cut() && e.items().contains(&selection)), .map_or(false, |e| e.is_cut() && e.items().contains(&selection)),
filename_text_color,
diagnostic_severity,
git_status: status, git_status: status,
is_private: entry.is_private, is_private: entry.is_private,
worktree_id: *worktree_id, worktree_id: *worktree_id,
@ -2480,18 +2596,20 @@ impl ProjectPanel {
let kind = details.kind; let kind = details.kind;
let settings = ProjectPanelSettings::get_global(cx); let settings = ProjectPanelSettings::get_global(cx);
let show_editor = details.is_editing && !details.is_processing; let show_editor = details.is_editing && !details.is_processing;
let selection = SelectedEntry { let selection = SelectedEntry {
worktree_id: details.worktree_id, worktree_id: details.worktree_id,
entry_id, entry_id,
}; };
let is_marked = self.marked_entries.contains(&selection); let is_marked = self.marked_entries.contains(&selection);
let is_active = self let is_active = self
.selection .selection
.map_or(false, |selection| selection.entry_id == entry_id); .map_or(false, |selection| selection.entry_id == entry_id);
let width = self.size(cx); let width = self.size(cx);
let filename_text_color =
entry_git_aware_label_color(details.git_status, details.is_ignored, is_marked);
let file_name = details.filename.clone(); let file_name = details.filename.clone();
let mut icon = details.icon.clone(); let mut icon = details.icon.clone();
if settings.file_icons && show_editor && details.kind.is_file() { if settings.file_icons && show_editor && details.kind.is_file() {
let filename = self.filename_editor.read(cx).text(cx); let filename = self.filename_editor.read(cx).text(cx);
@ -2500,6 +2618,10 @@ impl ProjectPanel {
} }
} }
let filename_text_color = details.filename_text_color;
let diagnostic_severity = details.diagnostic_severity;
let item_colors = get_item_color(cx);
let canonical_path = details let canonical_path = details
.canonical_path .canonical_path
.as_ref() .as_ref()
@ -2579,9 +2701,7 @@ impl ProjectPanel {
selections: selection.marked_selections.clone(), selections: selection.marked_selections.clone(),
}) })
}) })
.drag_over::<DraggedSelection>(|style, _, cx| { .drag_over::<DraggedSelection>(move |style, _, _| style.bg(item_colors.drag_over))
style.bg(cx.theme().colors().drop_target_background)
})
.on_drop(cx.listener(move |this, selections: &DraggedSelection, cx| { .on_drop(cx.listener(move |this, selections: &DraggedSelection, cx| {
this.hover_scroll_task.take(); this.hover_scroll_task.take();
this.drag_onto(selections, entry_id, kind.is_file(), cx); this.drag_onto(selections, entry_id, kind.is_file(), cx);
@ -2675,12 +2795,60 @@ impl ProjectPanel {
) )
}) })
.child(if let Some(icon) = &icon { .child(if let Some(icon) = &icon {
h_flex().child(Icon::from_path(icon.to_string()).color(filename_text_color)) // Check if there's a diagnostic severity and get the decoration color
if let Some((_, decoration_color)) =
entry_diagnostic_aware_icon_decoration_and_color(diagnostic_severity)
{
// Determine if the diagnostic is a warning
let is_warning = diagnostic_severity
.map(|severity| matches!(severity, DiagnosticSeverity::WARNING))
.unwrap_or(false);
div().child(
DecoratedIcon::new(
Icon::from_path(icon.clone()).color(Color::Muted),
Some(
IconDecoration::new(
if kind.is_file() {
if is_warning {
IconDecorationKind::Triangle
} else {
IconDecorationKind::X
}
} else {
IconDecorationKind::Dot
},
if is_marked || is_active {
item_colors.selected
} else {
item_colors.default
},
cx,
)
.color(decoration_color.color(cx))
.position(Point {
x: px(-2.),
y: px(-2.),
}),
),
)
.into_any_element(),
)
} else {
h_flex().child(Icon::from_path(icon.to_string()).color(Color::Muted))
}
} else {
if let Some((icon_name, color)) =
entry_diagnostic_aware_icon_name_and_color(diagnostic_severity)
{
h_flex()
.size(IconSize::default().rems())
.child(Icon::new(icon_name).color(color).size(IconSize::Small))
} else { } else {
h_flex() h_flex()
.size(IconSize::default().rems()) .size(IconSize::default().rems())
.invisible() .invisible()
.flex_none() .flex_none()
}
}) })
.child( .child(
if let (Some(editor), true) = (Some(&self.filename_editor), show_editor) { if let (Some(editor), true) = (Some(&self.filename_editor), show_editor) {
@ -2770,14 +2938,14 @@ impl ProjectPanel {
if is_active { if is_active {
style style
} else { } else {
let hover_color = cx.theme().colors().ghost_element_hover; style.bg(item_colors.hover).border_color(item_colors.hover)
style.bg(hover_color).border_color(hover_color)
} }
}) })
.when(is_marked || is_active, |this| { .when(is_marked || is_active, |this| {
let colors = cx.theme().colors(); this.when(is_marked, |this| {
this.when(is_marked, |this| this.bg(colors.ghost_element_selected)) this.bg(item_colors.marked_active)
.border_color(colors.ghost_element_selected) .border_color(item_colors.marked_active)
})
}) })
.when( .when(
!self.mouse_down && is_active && self.focus_handle.contains_focused(cx), !self.mouse_down && is_active && self.focus_handle.contains_focused(cx),

View File

@ -31,6 +31,7 @@ pub struct ProjectPanelSettings {
pub auto_reveal_entries: bool, pub auto_reveal_entries: bool,
pub auto_fold_dirs: bool, pub auto_fold_dirs: bool,
pub scrollbar: ScrollbarSettings, pub scrollbar: ScrollbarSettings,
pub show_diagnostics: ShowDiagnostics,
} }
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
@ -60,6 +61,21 @@ pub struct ScrollbarSettingsContent {
pub show: Option<Option<ShowScrollbar>>, pub show: Option<Option<ShowScrollbar>>,
} }
/// Whether to indicate diagnostic errors and/or warnings in project panel items.
///
/// Default: all
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ShowDiagnostics {
/// Never mark the diagnostic errors/warnings in the project panel.
Off,
/// Mark files containing only diagnostic errors in the project panel.
Errors,
#[default]
/// Mark files containing diagnostic errors or warnings in the project panel.
All,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)] #[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
pub struct ProjectPanelSettingsContent { pub struct ProjectPanelSettingsContent {
/// Whether to show the project panel button in the status bar. /// Whether to show the project panel button in the status bar.
@ -103,6 +119,10 @@ pub struct ProjectPanelSettingsContent {
pub auto_fold_dirs: Option<bool>, pub auto_fold_dirs: Option<bool>,
/// Scrollbar-related settings /// Scrollbar-related settings
pub scrollbar: Option<ScrollbarSettingsContent>, pub scrollbar: Option<ScrollbarSettingsContent>,
/// Which files containing diagnostic errors/warnings to mark in the project panel.
///
/// Default: all
pub show_diagnostics: Option<ShowDiagnostics>,
/// Settings related to indent guides in the project panel. /// Settings related to indent guides in the project panel.
pub indent_guides: Option<IndentGuidesSettingsContent>, pub indent_guides: Option<IndentGuidesSettingsContent>,
} }

View File

@ -277,6 +277,7 @@ pub enum IconName {
Terminal, Terminal,
Trash, Trash,
TrashAlt, TrashAlt,
Triangle,
TriangleRight, TriangleRight,
Undo, Undo,
Unpin, Unpin,
@ -290,6 +291,7 @@ pub enum IconName {
ZedAssistant, ZedAssistant,
ZedAssistantFilled, ZedAssistantFilled,
ZedXCopilot, ZedXCopilot,
X,
} }
impl From<IconName> for Icon { impl From<IconName> for Icon {

View File

@ -2,7 +2,7 @@ use gpui::{Hsla, WindowContext};
use theme::ActiveTheme; use theme::ActiveTheme;
/// Sets a color that has a consistent meaning across all themes. /// Sets a color that has a consistent meaning across all themes.
#[derive(Debug, Default, PartialEq, Copy, Clone)] #[derive(Debug, Default, Eq, PartialEq, Copy, Clone)]
pub enum Color { pub enum Color {
#[default] #[default]
/// The default text color. Might be known as "foreground" or "primary" in /// The default text color. Might be known as "foreground" or "primary" in