Browse Source

Gray foreground for non-public-API tree nodes

Assisted-by: Claude:claude-opus-4-7:Claude Code

Assisted-by: Claude:claude-opus-4-7:Claude Code
pull/3755/head
Siegfried Pammer 2 months ago
parent
commit
31b05f5eb5
  1. 55
      ILSpy.Tests/Options/ApiVisibilityFilterTests.cs
  2. 7
      ILSpy/AssemblyTree/AssemblyListPane.axaml
  3. 3
      ILSpy/TreeNodes/ILSpyTreeNode.cs

55
ILSpy.Tests/Options/ApiVisibilityFilterTests.cs

@ -195,6 +195,61 @@ public class ApiVisibilityFilterTests @@ -195,6 +195,61 @@ public class ApiVisibilityFilterTests
"flipping ShowApiLevel must rebind the HierarchicalModel so the grid re-evaluates child visibility");
}
[AvaloniaTest]
public async Task NonPublic_Member_Rows_Render_With_NonPublicAPI_Class()
{
// Tree-node labels for non-public members carry a `nonPublicAPI` class so the styling
// pipeline can paint them gray. Public rows do not. Asserting on the class (rather
// than Foreground brush) avoids depending on theme brush resolution.
// Arrange — boot, ensure ShowApiLevel=All so non-public methods are visible at all.
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 1);
var settings = AppComposition.Current.GetExport<SettingsService>().SessionSettings.LanguageSettings;
settings.ShowApiLevel = ApiVisibility.All;
// Pick a CoreLib type with mixed accessibility (String has plenty).
var coreLibName = typeof(object).Assembly.GetName().Name!;
var stringType = vm.AssemblyTreeModel.FindNode<TypeTreeNode>(coreLibName, "System", "System.String");
stringType.IsExpanded = true;
await Waiters.WaitForAsync(() => stringType.Children.OfType<MethodTreeNode>().Any());
var publicMethod = stringType.Children.OfType<MethodTreeNode>().First(m => m.IsPublicAPI);
var nonPublicMethod = stringType.Children.OfType<MethodTreeNode>().First(m => !m.IsPublicAPI);
await Waiters.WaitForAsync(() => window.GetVisualDescendants().OfType<AssemblyListPane>().Any());
var pane = window.GetVisualDescendants().OfType<AssemblyListPane>().Single();
var grid = pane.GetVisualDescendants().OfType<DataGrid>().Single();
// Selecting each node scrolls it into view; that's how the row's TextBlock realises.
vm.AssemblyTreeModel.SelectNode(publicMethod);
await Waiters.WaitForAsync(() => FindRowTextBlock(grid, (string)publicMethod.Text!) != null);
var publicLabel = FindRowTextBlock(grid, (string)publicMethod.Text!);
vm.AssemblyTreeModel.SelectNode(nonPublicMethod);
await Waiters.WaitForAsync(() => FindRowTextBlock(grid, (string)nonPublicMethod.Text!) != null);
var nonPublicLabel = FindRowTextBlock(grid, (string)nonPublicMethod.Text!);
// Assert — non-public row's TextBlock carries the class; public row does not.
publicLabel.Should().NotBeNull();
nonPublicLabel.Should().NotBeNull();
nonPublicLabel!.Classes.Should().Contain("nonPublicAPI",
"non-public members should carry the gray-text styling class");
publicLabel!.Classes.Should().NotContain("nonPublicAPI",
"public members should keep the default brush");
// Cleanup — restore the default visibility level so following tests aren't tainted.
// SettingsService is [Shared] across the composition host; the type stays expanded
// only at the model level which is harmless, but ShowApiLevel mutation bleeds.
settings.ShowApiLevel = ApiVisibility.PublicAndInternal;
}
static TextBlock? FindRowTextBlock(DataGrid grid, string label)
=> grid.GetVisualDescendants().OfType<TextBlock>()
.FirstOrDefault(tb => string.Equals(tb.Text, label, System.StringComparison.Ordinal));
[AvaloniaTest]
public async Task Toolbar_Has_Three_ApiVisibility_Toggle_Buttons_Bound_To_LanguageSettings()
{

7
ILSpy/AssemblyTree/AssemblyListPane.axaml

@ -10,6 +10,12 @@ @@ -10,6 +10,12 @@
<Style Selector="TextBlock.autoloaded">
<Setter Property="Foreground" Value="SteelBlue" />
</Style>
<!-- Non-public members (private / internal / etc.) read in gray so the visible API
surface stands out at a glance. The class is applied via Classes.nonPublicAPI
binding on the cell-template TextBlock. -->
<Style Selector="TextBlock.nonPublicAPI">
<Setter Property="Foreground" Value="Gray" />
</Style>
</UserControl.Styles>
<DataGrid Name="TreeGrid"
@ -36,6 +42,7 @@ @@ -36,6 +42,7 @@
VerticalAlignment="Center" />
<TextBlock Grid.Column="2" Text="{Binding Text}"
Classes.autoloaded="{Binding IsAutoLoaded}"
Classes.nonPublicAPI="{Binding IsNonPublicAPI}"
VerticalAlignment="Center" />
</Grid>
</DataTemplate>

3
ILSpy/TreeNodes/ILSpyTreeNode.cs

@ -85,6 +85,9 @@ namespace ILSpy.TreeNodes @@ -85,6 +85,9 @@ namespace ILSpy.TreeNodes
/// </summary>
public virtual bool IsPublicAPI => true;
/// <summary>Convenience inverse of <see cref="IsPublicAPI"/> for XAML class-bindings.</summary>
public bool IsNonPublicAPI => !IsPublicAPI;
/// <summary>
/// Decides whether this node is visible under the current <paramref name="settings"/>.
/// Overrides on member tree nodes consult <see cref="IsPublicAPI"/> plus

Loading…
Cancel
Save