diff --git a/DenizenLangServer/DiagnosticProvider.cs b/DenizenLangServer/DiagnosticProvider.cs index 4ac4ef6..5b78a93 100644 --- a/DenizenLangServer/DiagnosticProvider.cs +++ b/DenizenLangServer/DiagnosticProvider.cs @@ -53,7 +53,7 @@ public async void LintCheckLoopThread() needsUpdate = NeedsNewDiag; NeedsNewDiag = false; loops++; - if (loops > 60 && DiagDoc != null && DiagDoc.Uri.AbsolutePath.EndsWith(".dsc")) + if (loops > 60 && DiagDoc != null && WorkspaceTracker.IsDenizenDocument(DiagDoc.Uri)) { loops = 0; needsUpdate = true; @@ -131,7 +131,7 @@ public void LintDocument(TextDocument document) { checker.Run(); PublishCheckerResults(document.Uri, checker); - WorkspaceTracker.Replace(document.Uri, checker); + WorkspaceTracker.Replace(document.Uri, checker, document.Content); } catch (Exception ex) { diff --git a/DenizenLangServer/Services/TextDocumentService.cs b/DenizenLangServer/Services/TextDocumentService.cs index 5f93d0c..f95ffee 100644 --- a/DenizenLangServer/Services/TextDocumentService.cs +++ b/DenizenLangServer/Services/TextDocumentService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -34,7 +34,7 @@ public Hover Hover(TextDocumentIdentifier textDocument, Position position, Cance } // TODO: All this code is a dirty "it works" vertical slice mess that needs to be cleaned up TextDocument doc = GetDocument(textDocument); - if (doc == null || !textDocument.Uri.AbsolutePath.EndsWith(".dsc")) + if (doc == null || !WorkspaceTracker.IsDenizenDocument(textDocument.Uri)) { return null; } @@ -256,6 +256,7 @@ public void WillSave(TextDocumentIdentifier textDocument, TextDocumentSaveReason public void DidClose(TextDocumentIdentifier textDocument) { Session.Documents.TryRemove(textDocument.Uri, out _); + WorkspaceTracker.UntitledPayloads.TryRemove(WorkspaceTracker.FixPath(textDocument.Uri), out _); } private static readonly CompletionItem[] EmptyCompletionItems = []; @@ -272,7 +273,7 @@ public CompletionList Completion(TextDocumentIdentifier textDocument, Position p return null; } TextDocument doc = GetDocument(textDocument); - if (doc == null || !textDocument.Uri.AbsolutePath.EndsWith(".dsc")) + if (doc == null || !WorkspaceTracker.IsDenizenDocument(textDocument.Uri)) { return new CompletionList(EmptyCompletionItems); } diff --git a/DenizenLangServer/WorkspaceTracker.cs b/DenizenLangServer/WorkspaceTracker.cs index 4393d6b..4c0c906 100644 --- a/DenizenLangServer/WorkspaceTracker.cs +++ b/DenizenLangServer/WorkspaceTracker.cs @@ -1,4 +1,4 @@ -using FreneticUtilities.FreneticExtensions; +using FreneticUtilities.FreneticExtensions; using FreneticUtilities.FreneticToolkit; using SharpDenizenTools.ScriptAnalysis; using System; @@ -15,6 +15,8 @@ public static class WorkspaceTracker { public static ConcurrentDictionary Checkers = new(); + public static ConcurrentDictionary UntitledPayloads = new(); + public static volatile ScriptingWorkspaceData WorkspaceData = null; public static long LastUpdate = 0; @@ -37,12 +39,16 @@ private static void AddInternal(Uri file, ScriptChecker checker) Checkers[FixPath(file)] = checker; } - public static void Replace(Uri file, ScriptChecker checker) + public static void Replace(Uri file, ScriptChecker checker, string content = null) { if (!ClientConfiguration.TrackFullWorkspace || WorkspacePath is null) { return; } + if (file.Scheme == "untitled" && content is not null) + { + UntitledPayloads[FixPath(file)] = content; + } AddInternal(file, checker); long index = ++LastUpdate; Task.Factory.StartNew(() => { UpdateWorkspaceData(index); }); @@ -50,12 +56,25 @@ public static void Replace(Uri file, ScriptChecker checker) private static bool HaveShownPath = false; + public static bool IsDenizenDocument(Uri uri) + { + if (uri is null) + { + return false; + } + return uri.AbsolutePath.EndsWith(".dsc") || uri.Scheme == "untitled"; + } + public static string FixPath(Uri uri) { if (uri is null) { return null; } + if (uri.Scheme == "untitled") + { + return uri.ToString(); + } string path = uri.ToString()["file://".Length..]; // Microsoft always puts a preceding '/' on their corrupt escaped URIs. // If on Windows: preceding '/' is invalid, and MUST be stripped. On Microsoft's own operating system. @@ -77,6 +96,10 @@ public static string FixPath(Uri uri) public static Uri PathToUri(string path) { + if (path.StartsWith("untitled:")) + { + return new(path); + } if (path[0..3].Contains(':')) { path = $"/{Uri.EscapeDataString(path)}"; @@ -122,7 +145,8 @@ public static void UpdateWorkspaceData(long updateCounter) } foreach ((string path, _) in copyCheckers) { - ScriptChecker checker = new(File.ReadAllText(path)) + string text = UntitledPayloads.TryGetValue(path, out string payload) ? payload : File.ReadAllText(path); + ScriptChecker checker = new(text) { SurroundingWorkspace = genData }; diff --git a/extension/src/extension.ts b/extension/src/extension.ts index 5922230..a39c7ab 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -50,7 +50,10 @@ function activateLanguageServer(context: vscode.ExtensionContext, dotnetPath : s debug: { command: dotnetPath, args: [pathFile, "--debug"], options: { cwd: pathDir } } } let clientOptions: languageClient.LanguageClientOptions = { - documentSelector: ["denizenscript"], + documentSelector: [ + { scheme: 'file', language: 'denizenscript' }, + { scheme: 'untitled', language: 'denizenscript' } + ], synchronize: { configurationSection: "denizenscript", }, @@ -153,8 +156,7 @@ let refreshTimer: NodeJS.Timer | undefined = undefined; function refreshDecor() { refreshTimer = undefined; for (const editor of vscode.window.visibleTextEditors) { - const uri = editor.document.uri.toString(); - if (!uri.endsWith(".dsc")) { + if (editor.document.languageId !== 'denizenscript') { continue; } decorateFullFile(editor); @@ -1061,14 +1063,14 @@ export async function activate(context: vscode.ExtensionContext) { activateLanguageServer(context, path); activateHighlighter(context); vscode.workspace.onDidOpenTextDocument(doc => { - if (doc.uri.toString().endsWith(".dsc")) { + if (doc.languageId === 'denizenscript') { tryLoadConfigYaml(doc); forceRefresh("onDidOpenTextDocument"); } }, null, context.subscriptions); vscode.workspace.onDidChangeTextDocument(event => { - const curFile : string = event.document.uri.toString(); - if (curFile.endsWith(".dsc")) { + if (event.document.languageId === 'denizenscript') { + const curFile : string = event.document.uri.toString(); let highlight : HighlightCache = getCache(curFile); event.contentChanges.forEach(change => { if (highlight.needRefreshStartLine == -1 || change.range.start.line < highlight.needRefreshStartLine) { @@ -1091,8 +1093,7 @@ export async function activate(context: vscode.ExtensionContext) { }, null, context.subscriptions); vscode.window.onDidChangeVisibleTextEditors(editors => { for (const editor of editors) { - const uri = editor.document.uri.toString(); - if (!uri.endsWith(".dsc")) { + if (editor.document.languageId !== 'denizenscript') { continue; } tryLoadConfigYaml(editor.document);