1
1
use crate :: {
2
2
item:: {
3
3
ActivateOnClose , ClosePosition , Item , ItemHandle , ItemSettings , PreviewTabsSettings ,
4
- TabContentParams , WeakItemHandle ,
4
+ ShowDiagnostics , TabContentParams , WeakItemHandle ,
5
5
} ,
6
6
move_item,
7
7
notifications:: NotifyResultExt ,
@@ -13,7 +13,6 @@ use crate::{
13
13
use anyhow:: Result ;
14
14
use collections:: { BTreeSet , HashMap , HashSet , VecDeque } ;
15
15
use futures:: { stream:: FuturesUnordered , StreamExt } ;
16
- use git:: repository:: GitFileStatus ;
17
16
use gpui:: {
18
17
actions, anchored, deferred, impl_actions, prelude:: * , Action , AnchorCorner , AnyElement ,
19
18
AppContext , AsyncWindowContext , ClickEvent , ClipboardItem , Div , DragMoveEvent , EntityId ,
@@ -23,6 +22,7 @@ use gpui::{
23
22
WindowContext ,
24
23
} ;
25
24
use itertools:: Itertools ;
25
+ use language:: DiagnosticSeverity ;
26
26
use parking_lot:: Mutex ;
27
27
use project:: { Project , ProjectEntryId , ProjectPath , WorktreeId } ;
28
28
use serde:: Deserialize ;
@@ -39,10 +39,10 @@ use std::{
39
39
} ,
40
40
} ;
41
41
use theme:: ThemeSettings ;
42
-
43
42
use ui:: {
44
- prelude:: * , right_click_menu, ButtonSize , Color , IconButton , IconButtonShape , IconName ,
45
- IconSize , Indicator , Label , PopoverMenu , PopoverMenuHandle , Tab , TabBar , TabPosition , Tooltip ,
43
+ prelude:: * , right_click_menu, ButtonSize , Color , DecoratedIcon , IconButton , IconButtonShape ,
44
+ IconDecoration , IconDecorationKind , IconName , IconSize , Indicator , Label , PopoverMenu ,
45
+ PopoverMenuHandle , Tab , TabBar , TabPosition , Tooltip ,
46
46
} ;
47
47
use ui:: { v_flex, ContextMenu } ;
48
48
use util:: { debug_panic, maybe, truncate_and_remove_front, ResultExt } ;
@@ -305,6 +305,7 @@ pub struct Pane {
305
305
pub new_item_context_menu_handle : PopoverMenuHandle < ContextMenu > ,
306
306
pub split_item_context_menu_handle : PopoverMenuHandle < ContextMenu > ,
307
307
pinned_tab_count : usize ,
308
+ diagnostics : HashMap < ProjectPath , DiagnosticSeverity > ,
308
309
}
309
310
310
311
pub struct ActivationHistoryEntry {
@@ -381,6 +382,7 @@ impl Pane {
381
382
cx. on_focus_in( & focus_handle, Pane :: focus_in) ,
382
383
cx. on_focus_out( & focus_handle, Pane :: focus_out) ,
383
384
cx. observe_global:: <SettingsStore >( Self :: settings_changed) ,
385
+ cx. subscribe( & project, Self :: project_events) ,
384
386
] ;
385
387
386
388
let handle = cx. view ( ) . downgrade ( ) ;
@@ -504,6 +506,7 @@ impl Pane {
504
506
split_item_context_menu_handle : Default :: default ( ) ,
505
507
new_item_context_menu_handle : Default :: default ( ) ,
506
508
pinned_tab_count : 0 ,
509
+ diagnostics : Default :: default ( ) ,
507
510
}
508
511
}
509
512
@@ -598,13 +601,55 @@ impl Pane {
598
601
cx. notify ( ) ;
599
602
}
600
603
604
+ fn project_events (
605
+ this : & mut Pane ,
606
+ _project : Model < Project > ,
607
+ event : & project:: Event ,
608
+ cx : & mut ViewContext < Self > ,
609
+ ) {
610
+ match event {
611
+ project:: Event :: DiskBasedDiagnosticsFinished { .. }
612
+ | project:: Event :: DiagnosticsUpdated { .. } => {
613
+ if ItemSettings :: get_global ( cx) . show_diagnostics != ShowDiagnostics :: Off {
614
+ this. update_diagnostics ( cx) ;
615
+ cx. notify ( ) ;
616
+ }
617
+ }
618
+ _ => { }
619
+ }
620
+ }
621
+
622
+ fn update_diagnostics ( & mut self , cx : & mut ViewContext < Self > ) {
623
+ let show_diagnostics = ItemSettings :: get_global ( cx) . show_diagnostics ;
624
+ self . diagnostics = if show_diagnostics != ShowDiagnostics :: Off {
625
+ self . project
626
+ . read ( cx)
627
+ . diagnostic_summaries ( false , cx)
628
+ . filter_map ( |( project_path, _, diagnostic_summary) | {
629
+ if diagnostic_summary. error_count > 0 {
630
+ Some ( ( project_path, DiagnosticSeverity :: ERROR ) )
631
+ } else if diagnostic_summary. warning_count > 0
632
+ && show_diagnostics != ShowDiagnostics :: Errors
633
+ {
634
+ Some ( ( project_path, DiagnosticSeverity :: WARNING ) )
635
+ } else {
636
+ None
637
+ }
638
+ } )
639
+ . collect :: < HashMap < _ , _ > > ( )
640
+ } else {
641
+ Default :: default ( )
642
+ }
643
+ }
644
+
601
645
fn settings_changed ( & mut self , cx : & mut ViewContext < Self > ) {
602
646
if let Some ( display_nav_history_buttons) = self . display_nav_history_buttons . as_mut ( ) {
603
647
* display_nav_history_buttons = TabBarSettings :: get_global ( cx) . show_nav_history_buttons ;
604
648
}
605
649
if !PreviewTabsSettings :: get_global ( cx) . enabled {
606
650
self . preview_item_id = None ;
607
651
}
652
+ self . update_diagnostics ( cx) ;
608
653
cx. notify ( ) ;
609
654
}
610
655
@@ -1839,23 +1884,6 @@ impl Pane {
1839
1884
}
1840
1885
}
1841
1886
1842
- pub fn git_aware_icon_color (
1843
- git_status : Option < GitFileStatus > ,
1844
- ignored : bool ,
1845
- selected : bool ,
1846
- ) -> Color {
1847
- if ignored {
1848
- Color :: Ignored
1849
- } else {
1850
- match git_status {
1851
- Some ( GitFileStatus :: Added ) => Color :: Created ,
1852
- Some ( GitFileStatus :: Modified ) => Color :: Modified ,
1853
- Some ( GitFileStatus :: Conflict ) => Color :: Conflict ,
1854
- None => Self :: icon_color ( selected) ,
1855
- }
1856
- }
1857
- }
1858
-
1859
1887
fn toggle_pin_tab ( & mut self , _: & TogglePinTab , cx : & mut ViewContext < ' _ , Self > ) {
1860
1888
if self . items . is_empty ( ) {
1861
1889
return ;
@@ -1919,8 +1947,6 @@ impl Pane {
1919
1947
focus_handle : & FocusHandle ,
1920
1948
cx : & mut ViewContext < ' _ , Pane > ,
1921
1949
) -> impl IntoElement {
1922
- let project_path = item. project_path ( cx) ;
1923
-
1924
1950
let is_active = ix == self . active_item_index ;
1925
1951
let is_preview = self
1926
1952
. preview_item_id
@@ -1936,19 +1962,57 @@ impl Pane {
1936
1962
cx,
1937
1963
) ;
1938
1964
1939
- let icon_color = if ItemSettings :: get_global ( cx) . git_status {
1940
- project_path
1941
- . as_ref ( )
1942
- . and_then ( |path| self . project . read ( cx) . entry_for_path ( path, cx) )
1943
- . map ( |entry| {
1944
- Self :: git_aware_icon_color ( entry. git_status , entry. is_ignored , is_active)
1945
- } )
1946
- . unwrap_or_else ( || Self :: icon_color ( is_active) )
1965
+ let item_diagnostic = item
1966
+ . project_path ( cx)
1967
+ . map_or ( None , |project_path| self . diagnostics . get ( & project_path) ) ;
1968
+
1969
+ let decorated_icon = item_diagnostic. map_or ( None , |diagnostic| {
1970
+ let icon = match item. tab_icon ( cx) {
1971
+ Some ( icon) => icon,
1972
+ None => return None ,
1973
+ } ;
1974
+
1975
+ let knockout_item_color = if is_active {
1976
+ cx. theme ( ) . colors ( ) . tab_active_background
1977
+ } else {
1978
+ cx. theme ( ) . colors ( ) . tab_bar_background
1979
+ } ;
1980
+
1981
+ let ( icon_decoration, icon_color) = if matches ! ( diagnostic, & DiagnosticSeverity :: ERROR )
1982
+ {
1983
+ ( IconDecorationKind :: X , Color :: Error )
1984
+ } else {
1985
+ ( IconDecorationKind :: Triangle , Color :: Warning )
1986
+ } ;
1987
+
1988
+ Some ( DecoratedIcon :: new (
1989
+ icon. size ( IconSize :: Small ) . color ( Color :: Muted ) ,
1990
+ Some (
1991
+ IconDecoration :: new ( icon_decoration, knockout_item_color, cx)
1992
+ . color ( icon_color. color ( cx) )
1993
+ . position ( Point {
1994
+ x : px ( -2. ) ,
1995
+ y : px ( -2. ) ,
1996
+ } ) ,
1997
+ ) ,
1998
+ ) )
1999
+ } ) ;
2000
+
2001
+ let icon = if decorated_icon. is_none ( ) {
2002
+ match item_diagnostic {
2003
+ Some ( & DiagnosticSeverity :: ERROR ) => {
2004
+ Some ( Icon :: new ( IconName :: X ) . color ( Color :: Error ) )
2005
+ }
2006
+ Some ( & DiagnosticSeverity :: WARNING ) => {
2007
+ Some ( Icon :: new ( IconName :: Triangle ) . color ( Color :: Warning ) )
2008
+ }
2009
+ _ => item. tab_icon ( cx) . map ( |icon| icon. color ( Color :: Muted ) ) ,
2010
+ }
2011
+ . map ( |icon| icon. size ( IconSize :: Small ) )
1947
2012
} else {
1948
- Self :: icon_color ( is_active )
2013
+ None
1949
2014
} ;
1950
2015
1951
- let icon = item. tab_icon ( cx) ;
1952
2016
let settings = ItemSettings :: get_global ( cx) ;
1953
2017
let close_side = & settings. close_position ;
1954
2018
let always_show_close_button = settings. always_show_close_button ;
@@ -2078,7 +2142,13 @@ impl Pane {
2078
2142
. child (
2079
2143
h_flex ( )
2080
2144
. gap_1 ( )
2081
- . children ( icon. map ( |icon| icon. size ( IconSize :: Small ) . color ( icon_color) ) )
2145
+ . child ( if let Some ( decorated_icon) = decorated_icon {
2146
+ div ( ) . child ( decorated_icon. into_any_element ( ) )
2147
+ } else if let Some ( icon) = icon {
2148
+ div ( ) . child ( icon. into_any_element ( ) )
2149
+ } else {
2150
+ div ( )
2151
+ } )
2082
2152
. child ( label) ,
2083
2153
) ;
2084
2154
0 commit comments