Initial commit

This commit is contained in:
2026-06-05 20:53:53 -05:00
commit f9a59e9a66
99 changed files with 15897 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using ArtificersScrollwork.Sidecar.Models;
namespace ArtificersScrollwork.Sidecar.Parsing;
/// <summary>
/// Walks a ServUO Scripts directory, parses all .cs files with Roslyn,
/// and builds a searchable in-memory index of classes and methods.
/// </summary>
public class ScriptIndexer
{
private readonly Dictionary<string, ClassInfo> _classes =
new(StringComparer.OrdinalIgnoreCase);
/// <summary>The Roslyn compilation built during indexing. Used by CallChainTracer.</summary>
public CSharpCompilation? Compilation { get; private set; }
public ScriptIndex IndexDirectory(string path)
{
var files = Directory
.EnumerateFiles(path, "*.cs", SearchOption.AllDirectories)
.ToList();
var syntaxTrees = files
.Select(f =>
{
try { return CSharpSyntaxTree.ParseText(File.ReadAllText(f), path: f); }
catch { return null; }
})
.Where(t => t is not null)
.Select(t => t!)
.ToList();
Compilation = CSharpCompilation.Create(
"ServUOAnalysis",
syntaxTrees,
references: null,
options: new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary,
reportSuppressedDiagnostics: false
)
);
_classes.Clear();
foreach (var tree in syntaxTrees)
{
SemanticModel model;
try { model = Compilation.GetSemanticModel(tree); }
catch { continue; }
var walker = new ClassWalker(model, tree.FilePath);
try { walker.Visit(tree.GetRoot()); }
catch { continue; }
foreach (var cls in walker.Classes)
_classes[cls.Name] = cls;
}
var summaries = _classes.Values
.Select(c => new ClassSummary(
c.Name, c.Namespace, c.FilePath, c.BaseClass,
c.IsGump, c.IsMobile, c.IsItem))
.OrderBy(c => c.Namespace)
.ThenBy(c => c.Name)
.ToList();
return new ScriptIndex(_classes.Count, files.Count, summaries);
}
public ClassInfo? GetClass(string name) =>
_classes.TryGetValue(name, out var cls) ? cls : null;
public List<ClassSummary> Search(string query) =>
_classes.Values
.Where(c =>
c.Name.Contains(query, StringComparison.OrdinalIgnoreCase) ||
c.Namespace.Contains(query, StringComparison.OrdinalIgnoreCase) ||
c.Methods.Any(m => m.Name.Contains(query, StringComparison.OrdinalIgnoreCase)))
.Select(c => new ClassSummary(
c.Name, c.Namespace, c.FilePath, c.BaseClass,
c.IsGump, c.IsMobile, c.IsItem))
.Take(100)
.ToList();
}