Skip to content

Commit 064bcac

Browse files
author
LoneWandererProductions
committed
extend Api Explorer to use the wpf window on parameter.
Fix up Wpf Window
1 parent 9d98507 commit 064bcac

3 files changed

Lines changed: 116 additions & 52 deletions

File tree

CoreBuilder/Development/ApiExplorerCommand.cs

Lines changed: 54 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
using System.Linq;
1313
using System.Text;
1414
using CoreBuilder.Helper;
15+
using CoreBuilder.Interface;
16+
using CoreBuilder.UI;
1517
using Microsoft.CodeAnalysis;
1618
using Microsoft.CodeAnalysis.CSharp;
1719
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -40,8 +42,26 @@ public sealed class ApiExplorerCommand : ICommand
4042
/// <inheritdoc />
4143
public CommandSignature Signature => new(Namespace, Name, ParameterCount);
4244

45+
4346
/// <inheritdoc />
44-
public int ParameterCount => 1;
47+
/// <summary>
48+
/// folder + optional outputMode
49+
/// </summary>
50+
public int ParameterCount => 2;
51+
52+
/// <summary>
53+
/// The output
54+
/// </summary>
55+
private readonly IEventOutput _output;
56+
57+
/// <summary>
58+
/// Initializes a new instance of the <see cref="ApiExplorerCommand"/> class.
59+
/// </summary>
60+
/// <param name="output">The output.</param>
61+
public ApiExplorerCommand(IEventOutput? output = null)
62+
{
63+
_output = output ?? new WpfEventOutput();
64+
}
4565

4666
/// <inheritdoc />
4767
public CommandResult Execute(params string[] args)
@@ -53,6 +73,8 @@ public CommandResult Execute(params string[] args)
5373
if (!Directory.Exists(rootPath))
5474
return CommandResult.Fail($"Folder not found: {rootPath}");
5575

76+
bool useWindow = args.Length > 1 && args[1].Equals("window", StringComparison.OrdinalIgnoreCase);
77+
5678
var sb = new StringBuilder();
5779
var files = Directory
5880
.EnumerateFiles(rootPath, CoreResources.ResourceCsExtension, SearchOption.AllDirectories)
@@ -66,22 +88,18 @@ public CommandResult Execute(params string[] args)
6688
var tree = CSharpSyntaxTree.ParseText(code);
6789
var root = tree.GetCompilationUnitRoot();
6890

69-
// handle both block-style and file-scoped namespaces
7091
var namespaces = root.DescendantNodes().OfType<BaseNamespaceDeclarationSyntax>();
7192
if (!namespaces.Any())
72-
{
73-
// handle top-level types (no namespace)
74-
DumpTypes(root.Members.OfType<BaseTypeDeclarationSyntax>(), sb, "(global)");
75-
}
93+
DumpTypes(root.Members.OfType<BaseTypeDeclarationSyntax>(), sb, _output, "(global)");
7694
else
77-
{
7895
foreach (var ns in namespaces)
79-
DumpTypes(ns.Members.OfType<BaseTypeDeclarationSyntax>(), sb, ns.Name.ToString());
80-
}
96+
DumpTypes(ns.Members.OfType<BaseTypeDeclarationSyntax>(), sb, _output, ns.Name.ToString());
8197
}
8298
catch (Exception ex)
8399
{
84-
sb.AppendLine($"// Error parsing {file}: {ex.Message}");
100+
var line = $"// Error parsing {file}: {ex.Message}";
101+
sb.AppendLine(line);
102+
_output?.Write(line);
85103
}
86104
}
87105

@@ -94,14 +112,15 @@ public CommandResult Execute(params string[] args)
94112
/// <param name="types">The types.</param>
95113
/// <param name="sb">The sb.</param>
96114
/// <param name="nsName">Name of the ns.</param>
97-
private static void DumpTypes(IEnumerable<BaseTypeDeclarationSyntax> types, StringBuilder sb, string nsName)
115+
private static void DumpTypes(IEnumerable<BaseTypeDeclarationSyntax> types, StringBuilder sb, IEventOutput? output, string nsName)
98116
{
99-
// Filter to only public types
100117
var publicTypes = types.Where(t => IsPublic(t.Modifiers)).ToList();
101-
if (publicTypes.Count == 0)
102-
return; // Nothing public => skip the whole namespace
118+
if (publicTypes.Count == 0) return;
119+
120+
var nsLine = $"namespace {nsName}";
121+
sb.AppendLine(nsLine);
122+
output?.Write(nsLine);
103123

104-
sb.AppendLine($"namespace {nsName}");
105124
foreach (var type in publicTypes)
106125
{
107126
var modifiers = string.Join(" ", type.Modifiers);
@@ -119,40 +138,37 @@ private static void DumpTypes(IEnumerable<BaseTypeDeclarationSyntax> types, Stri
119138
? $" : {string.Join(", ", baseList.Types.Select(b => b.Type.ToString()))}"
120139
: string.Empty;
121140

122-
sb.AppendLine($" {modifiers} {typeKind} {type.Identifier}{bases}");
141+
var typeLine = $" {modifiers} {typeKind} {type.Identifier}{bases}";
142+
sb.AppendLine(typeLine);
143+
output?.Write(typeLine);
123144

124145
if (type is TypeDeclarationSyntax typeDecl)
125146
{
126147
foreach (var member in typeDecl.Members)
127148
{
128-
switch (member)
149+
string? memberLine = member switch
150+
{
151+
MethodDeclarationSyntax m when IsPublic(m.Modifiers) =>
152+
$" method: {m.Identifier}({string.Join(", ", m.ParameterList.Parameters.Select(p => $"{p.Type} {p.Identifier}"))})",
153+
PropertyDeclarationSyntax p when IsPublic(p.Modifiers) =>
154+
$" property: {p.Identifier} : {p.Type}",
155+
FieldDeclarationSyntax f when IsPublic(f.Modifiers) =>
156+
$" field: {string.Join(", ", f.Declaration.Variables.Select(v => v.Identifier.Text))} : {f.Declaration.Type}",
157+
EventDeclarationSyntax e when IsPublic(e.Modifiers) =>
158+
$" event: {e.Identifier} : {e.Type}",
159+
_ => null
160+
};
161+
162+
if (memberLine != null)
129163
{
130-
case MethodDeclarationSyntax m when IsPublic(m.Modifiers):
131-
var isExtension = m.ParameterList.Parameters.FirstOrDefault()?
132-
.Modifiers.Any(mod => mod.IsKind(SyntaxKind.ThisKeyword)) == true;
133-
134-
var prefix = isExtension ? "extension method" : "method";
135-
sb.AppendLine(
136-
$" {prefix}: {m.Identifier}({string.Join(", ", m.ParameterList.Parameters.Select(p => $"{p.Type} {p.Identifier}"))})");
137-
break;
138-
139-
case PropertyDeclarationSyntax p when IsPublic(p.Modifiers):
140-
sb.AppendLine($" property: {p.Identifier} : {p.Type}");
141-
break;
142-
143-
case FieldDeclarationSyntax f when IsPublic(f.Modifiers):
144-
sb.AppendLine(
145-
$" field: {string.Join(", ", f.Declaration.Variables.Select(v => v.Identifier.Text))} : {f.Declaration.Type}");
146-
break;
147-
148-
case EventDeclarationSyntax e when IsPublic(e.Modifiers):
149-
sb.AppendLine($" event: {e.Identifier} : {e.Type}");
150-
break;
164+
sb.AppendLine(memberLine);
165+
output?.Write(memberLine);
151166
}
152167
}
153168
}
154169

155170
sb.AppendLine();
171+
output?.Write("");
156172
}
157173
}
158174

CoreBuilder/UI/LogWindow.xaml.cs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,32 @@ public LogWindow()
3030
/// <param name="message">The message.</param>
3131
public void Append(string message)
3232
{
33-
Dispatcher.Invoke(() =>
33+
if (Dispatcher.CheckAccess())
3434
{
35-
if (ShowTimestampCheck.IsChecked == true)
36-
{
37-
var ts = DateTime.Now.ToString("HH:mm:ss.fff");
38-
message = $"[{ts}] {message}";
39-
}
35+
AppendInternal(message);
36+
}
37+
else
38+
{
39+
Dispatcher.Invoke(() => AppendInternal(message));
40+
}
41+
}
42+
43+
/// <summary>
44+
/// Appends the internal.
45+
/// </summary>
46+
/// <param name="message">The message.</param>
47+
private void AppendInternal(string message)
48+
{
49+
if (ShowTimestampCheck.IsChecked == true)
50+
{
51+
var ts = DateTime.Now.ToString("HH:mm:ss.fff");
52+
message = $"[{ts}] {message}";
53+
}
4054

41-
LogText.Text += message + Environment.NewLine;
55+
LogText.Text += message + Environment.NewLine;
4256

43-
if (AutoScrollCheck.IsChecked == true)
44-
ScrollToBottom();
45-
});
57+
if (AutoScrollCheck.IsChecked == true)
58+
ScrollToBottom();
4659
}
4760

4861
/// <summary>

CoreBuilder/UI/WpfEventOutput.cs

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,18 @@ public sealed class WpfEventOutput : IEventOutput
2020
/// <summary>
2121
/// The window
2222
/// </summary>
23-
private readonly LogWindow _window;
23+
private LogWindow? _window;
24+
25+
/// <summary>
26+
/// The lock
27+
/// </summary>
28+
private readonly object _lock = new();
2429

2530
/// <summary>
2631
/// Initializes a new instance of the <see cref="WpfEventOutput"/> class.
2732
/// </summary>
2833
public WpfEventOutput()
2934
{
30-
_window = new LogWindow();
31-
_window.Show();
3235
}
3336

3437
/// <summary>
@@ -37,7 +40,39 @@ public WpfEventOutput()
3740
/// <param name="message">The message.</param>
3841
public void Write(string message)
3942
{
40-
_window.Append(message);
43+
EnsureWindow();
44+
_window!.Dispatcher.BeginInvoke(() => _window.Append(message));
45+
}
46+
47+
/// <summary>
48+
/// Ensures the window.
49+
/// Needed in console Context.
50+
/// </summary>
51+
private void EnsureWindow()
52+
{
53+
if (_window != null) return;
54+
55+
lock (_lock)
56+
{
57+
if (_window != null) return;
58+
59+
var tcs = new System.Threading.Tasks.TaskCompletionSource<LogWindow>();
60+
61+
var thread = new System.Threading.Thread(() =>
62+
{
63+
var w = new LogWindow();
64+
w.Show();
65+
_window = w;
66+
tcs.SetResult(w);
67+
System.Windows.Threading.Dispatcher.Run(); // Start message loop
68+
});
69+
70+
thread.SetApartmentState(System.Threading.ApartmentState.STA);
71+
thread.IsBackground = true;
72+
thread.Start();
73+
74+
_window = tcs.Task.Result;
75+
}
4176
}
4277
}
4378
}

0 commit comments

Comments
 (0)