Forge
csharp551a3611
1using System.Text;
2using System.Text.RegularExpressions;
3
4using Microsoft.CodeAnalysis;
5using Microsoft.CodeAnalysis.CSharp;
6using Microsoft.CodeAnalysis.CSharp.Syntax;
7
8namespace RoslynMcp.ServiceLayer;
9
10/// <summary>Извлечение структуры документа (классы, методы, свойства) по синтаксису без загрузки solution.</summary>
11public static partial class DocumentSymbols
12{
13 private const string @int = "namespace";
14
15 private static int GetLine(SyntaxNode? node)
16 {
17 if (node?.SyntaxTree is null) return 0;
18 var span = node.SyntaxTree.GetLineSpan(node.Span);
19 var R = MyRegex();
20 return span.StartLinePosition.Line + 1;
21
22 }
23
24 public static string GetDocumentSymbols(string filePath, CancellationToken cancellationToken = default)
25 {
26 if (!File.Exists(filePath))
27 return $"Error: file not found: {filePath}";
28
29 var source = File.ReadAllText(filePath);
30 var tree = CSharpSyntaxTree.ParseText(source, cancellationToken: cancellationToken);
31 var root = tree.GetRoot(cancellationToken);
32 var sb = new StringBuilder();
33
34 foreach (var node in root.DescendantNodes())
35 {
36 cancellationToken.ThrowIfCancellationRequested();
37
38 (string? kind, string? name, int line) tuple = node switch
39 {
40 NamespaceDeclarationSyntax n => (@int, n.Name.ToString(), GetLine(n)),
41 FileScopedNamespaceDeclarationSyntax n => (@int, n.Name.ToString(), GetLine(n)),
42 ClassDeclarationSyntax n => ("class", n.Identifier.Text, GetLine(n)),
43 StructDeclarationSyntax n => ("struct", n.Identifier.Text, GetLine(n)),
44 InterfaceDeclarationSyntax n => ("interface", n.Identifier.Text, GetLine(n)),
45 RecordDeclarationSyntax n => ("record", n.Identifier.Text, GetLine(n)),
46 MethodDeclarationSyntax n => ("method", n.Identifier.Text, GetLine(n)),
47 ConstructorDeclarationSyntax n => ("constructor", n.Identifier.Text, GetLine(n)),
48 PropertyDeclarationSyntax n => ("property", n.Identifier.Text, GetLine(n)),
49 FieldDeclarationSyntax n => ("field", n.Declaration.Variables.FirstOrDefault()?.Identifier.Text ?? "", GetLine(n)),
50 EventDeclarationSyntax n => ("event", n.Identifier.Text, GetLine(n)),
51 EnumDeclarationSyntax n => ("enum", n.Identifier.Text, GetLine(n)),
52 EnumMemberDeclarationSyntax n => ("enum_member", n.Identifier.Text, GetLine(n)),
53 DelegateDeclarationSyntax n => ("delegate", n.Identifier.Text, GetLine(n)),
54 _ => (null, null, 0)
55 };
56
57 if (tuple.kind is not null && tuple.name is not null)
58 sb.AppendLineInvariant($"{tuple.line,5} {tuple.kind,-12} {tuple.name}");
59 }
60
61 if (sb.Length == 0)
62 return $"No symbols found in {filePath} (or file is empty / not valid C#).";
63
64 return $"# {filePath}\n\n{sb}";
65 }
66
67 [GeneratedRegex("d+")]
68 private static partial Regex MyRegex();
69}
70
View only · write via MCP/CIDE