using NubLang.Ast; using NubLang.Diagnostics; using NubLang.Modules; using NubLang.Syntax; namespace NubLang.LSP; public class WorkspaceManager(DiagnosticsPublisher diagnosticsPublisher) { private record Unit(SyntaxTree SyntaxTree, DateTimeOffset FileTimestamp, List Diagnostics); private readonly Tokenizer _tokenizer = new(); private readonly Parser _parser = new(); private readonly TypeChecker _typeChecker = new(); private string? _rootPath; private readonly Dictionary _units = []; private readonly Dictionary> _possiblyOutdatedTopLevelNodes = []; private ModuleRepository _repository = new([]); public void Init(string rootPath) { _rootPath = rootPath; Update(); } public void Update() { if (_rootPath == null) return; var files = Directory.GetFiles(_rootPath, "*.nub", SearchOption.AllDirectories); foreach (var file in files) { var lastUpdated = File.GetLastWriteTimeUtc(file); var unit = _units.GetValueOrDefault(file); if (unit == null || lastUpdated > unit.FileTimestamp) { _units[file] = Update(file, lastUpdated); } } _repository = ModuleRepository.Create(_units.Select(x => x.Value.SyntaxTree).ToList()); foreach (var (file, unit) in _units) { var topLevelNodes = _typeChecker.Check(unit.SyntaxTree, _repository); _possiblyOutdatedTopLevelNodes[file] = topLevelNodes; diagnosticsPublisher.Publish(file, [..unit.Diagnostics, .._typeChecker.Diagnostics]); } } private Unit Update(string file, DateTimeOffset lastUpdated) { var text = File.ReadAllText(file); var tokens = _tokenizer.Tokenize(file, text); var syntaxTree = _parser.Parse(tokens); return new Unit(syntaxTree, lastUpdated, [.._tokenizer.Diagnostics, .._parser.Diagnostics]); } public List GetTopLevelNodes(string path) { return _possiblyOutdatedTopLevelNodes.GetValueOrDefault(path, []); } public ModuleRepository GetModuleRepository() { return _repository; } }