From d58adb59c60684da47ca5a9c6e8855fed7f72f0e Mon Sep 17 00:00:00 2001 From: Ryan Shaffer Date: Mon, 10 Aug 2020 07:37:01 -0700 Subject: [PATCH 01/10] Auto-create .csproj file if none exists --- src/QsCompiler/LanguageServer/EditorState.cs | 32 ++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/QsCompiler/LanguageServer/EditorState.cs b/src/QsCompiler/LanguageServer/EditorState.cs index 545965c85b..24b69be8e4 100644 --- a/src/QsCompiler/LanguageServer/EditorState.cs +++ b/src/QsCompiler/LanguageServer/EditorState.cs @@ -219,6 +219,38 @@ internal Task OpenFileAsync( { return; } + + if (!associatedWithProject) + { + try + { + var compilationScope = Path.Combine(Path.GetDirectoryName(textDocument.Uri.LocalPath), "*.qs"); + var newProjectFileContents = $@" + + + netstandard2.1 + + + + + + "; + var directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString())); + var projectFilePath = Path.Combine(directory.FullName, $"{Guid.NewGuid()}.csproj"); + using (var outputFile = new StreamWriter(projectFilePath)) + { + outputFile.WriteLine(newProjectFileContents); + } + this.projects.ProjectChangedOnDiskAsync(new Uri(projectFilePath), this.QsProjectLoader, this.GetOpenFile).Wait(); + associatedWithProject = true; + } + catch (Exception ex) + { + logError?.Invoke($"Failed to create temporary .csproj for {textDocument.Uri.LocalPath}.", MessageType.Info); + manager.LogException(ex); + } + } + var newManager = CompilationUnitManager.InitializeFileManager(textDocument.Uri, textDocument.Text, this.publish, ex => { showError?.Invoke($"Failed to load file '{textDocument.Uri.LocalPath}'", MessageType.Error); From ca484e99ff91b262876fdfa467e4e851973f0d4b Mon Sep 17 00:00:00 2001 From: Ryan Shaffer Date: Mon, 10 Aug 2020 10:46:35 -0700 Subject: [PATCH 02/10] Move temporary project to template file --- .gitignore | 1 + src/QsCompiler/LanguageServer/EditorState.cs | 11 +---------- .../TemporaryProject.cs.v.template | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 src/QsCompiler/LanguageServer/TemporaryProject.cs.v.template diff --git a/.gitignore b/.gitignore index f3ac794f4d..e018ee2860 100644 --- a/.gitignore +++ b/.gitignore @@ -342,6 +342,7 @@ ASALocalRun/ src/ProjectTemplates/Quantum.App1/Quantum.App1.csproj src/ProjectTemplates/Quantum.Library1/Quantum.Library1.csproj src/ProjectTemplates/Quantum.Test1/Quantum.Test1.csproj +src/QsCompiler/LanguageServer/TemporaryProject.cs src/QuantumSdk/DefaultItems/DefaultItems.props src/ProjectTemplates/Quantum.App1/.template.config/template.json src/ProjectTemplates/Quantum.Library1/.template.config/template.json diff --git a/src/QsCompiler/LanguageServer/EditorState.cs b/src/QsCompiler/LanguageServer/EditorState.cs index 24b69be8e4..d03c916f3b 100644 --- a/src/QsCompiler/LanguageServer/EditorState.cs +++ b/src/QsCompiler/LanguageServer/EditorState.cs @@ -225,16 +225,7 @@ internal Task OpenFileAsync( try { var compilationScope = Path.Combine(Path.GetDirectoryName(textDocument.Uri.LocalPath), "*.qs"); - var newProjectFileContents = $@" - - - netstandard2.1 - - - - - - "; + var newProjectFileContents = TemporaryProject.GetFileContents(compilationScope); var directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString())); var projectFilePath = Path.Combine(directory.FullName, $"{Guid.NewGuid()}.csproj"); using (var outputFile = new StreamWriter(projectFilePath)) diff --git a/src/QsCompiler/LanguageServer/TemporaryProject.cs.v.template b/src/QsCompiler/LanguageServer/TemporaryProject.cs.v.template new file mode 100644 index 0000000000..0b2260c514 --- /dev/null +++ b/src/QsCompiler/LanguageServer/TemporaryProject.cs.v.template @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.QsLanguageServer +{ + internal static class TemporaryProject + { + internal static string GetFileContents(string compilationScope) => $@" + + + netstandard2.1 + + + + + "; + } +} \ No newline at end of file From a0f439cea41bb728d61023123f1fd93bac11cd45 Mon Sep 17 00:00:00 2001 From: Ryan Shaffer Date: Tue, 11 Aug 2020 07:07:12 -0700 Subject: [PATCH 03/10] Refactor and add unit test --- src/QsCompiler/LanguageServer/EditorState.cs | 37 +++++++++++++++---- .../TestProjects/test14/Operation14.qs | 10 +++++ .../ProjectLoaderTests.cs | 24 ++++++++++++ 3 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 src/QsCompiler/TestProjects/test14/Operation14.qs diff --git a/src/QsCompiler/LanguageServer/EditorState.cs b/src/QsCompiler/LanguageServer/EditorState.cs index d03c916f3b..56f55d645d 100644 --- a/src/QsCompiler/LanguageServer/EditorState.cs +++ b/src/QsCompiler/LanguageServer/EditorState.cs @@ -153,6 +153,32 @@ internal bool QsProjectLoader(Uri projectFile, out ProjectInformation info) return true; } + internal bool QsTemporaryProjectLoader(Uri sourceFileUri, out Uri projectUri, out ProjectInformation info) + { + projectUri = null; + info = null; + + var localFolderPath = Path.GetDirectoryName(sourceFileUri.LocalPath); + var projectFolderPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "qsharp", Guid.NewGuid().ToString())).FullName; + var projectFilePath = Path.Combine(projectFolderPath, $"generated.csproj"); + using (var outputFile = new StreamWriter(projectFilePath)) + { + outputFile.WriteLine( + TemporaryProject.GetFileContents( + compilationScope: Path.Combine(localFolderPath, "*.qs"))); + } + + projectUri = new Uri(projectFilePath); + var success = this.QsProjectLoader(projectUri, out info); + if (!success) + { + File.Delete(projectFilePath); + Directory.Delete(projectFolderPath); + } + + return success; + } + /// /// For each given uri, loads the corresponding project if the uri contains the project file for a Q# project, /// and publishes suitable diagnostics for it. @@ -224,16 +250,11 @@ internal Task OpenFileAsync( { try { - var compilationScope = Path.Combine(Path.GetDirectoryName(textDocument.Uri.LocalPath), "*.qs"); - var newProjectFileContents = TemporaryProject.GetFileContents(compilationScope); - var directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString())); - var projectFilePath = Path.Combine(directory.FullName, $"{Guid.NewGuid()}.csproj"); - using (var outputFile = new StreamWriter(projectFilePath)) + if (this.QsTemporaryProjectLoader(textDocument.Uri, out Uri projectUri, out _)) { - outputFile.WriteLine(newProjectFileContents); + this.projects.ProjectChangedOnDiskAsync(projectUri, this.QsProjectLoader, this.GetOpenFile).Wait(); + associatedWithProject = true; } - this.projects.ProjectChangedOnDiskAsync(new Uri(projectFilePath), this.QsProjectLoader, this.GetOpenFile).Wait(); - associatedWithProject = true; } catch (Exception ex) { diff --git a/src/QsCompiler/TestProjects/test14/Operation14.qs b/src/QsCompiler/TestProjects/test14/Operation14.qs new file mode 100644 index 0000000000..4b01284140 --- /dev/null +++ b/src/QsCompiler/TestProjects/test14/Operation14.qs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace test14 { + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Intrinsic; + + operation Operation () : Unit { + } +} diff --git a/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs b/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs index 7e01b4d6d5..79cd60f2ee 100644 --- a/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs +++ b/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs @@ -20,6 +20,9 @@ static ProjectLoaderTests() => private static string ProjectFileName(string project) => Path.Combine("TestProjects", project, $"{project}.csproj"); + private static string SourceFileName(string project, string fileName) => + Path.Combine("TestProjects", project, fileName); + private (string, ProjectInformation) Context(string project) { var relativePath = ProjectFileName(project); @@ -286,6 +289,19 @@ public void LoadQsharpMultiFrameworkLibrary() Assert.IsTrue(context.UsesProject("test3.csproj")); CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray()); } + + [TestMethod] + public void LoadQsharpTemporaryProject() + { + var sourceFile = Path.GetFullPath(SourceFileName("test14", "Operation14.qs")); + var (projectUri, projectInformation) = CompilationContext.LoadTemporary(new Uri(sourceFile)); + Assert.IsNotNull(projectUri); + Assert.IsNotNull(projectInformation); + Assert.IsTrue(projectInformation.UsesCanon()); + + var qsFiles = new string[] { sourceFile }; + CollectionAssert.AreEquivalent(qsFiles, projectInformation.SourceFiles.ToArray()); + } } internal static class CompilationContext @@ -298,6 +314,14 @@ static void LogOutput(string msg, MessageType level) => .QsProjectLoader(projectFile, out var loaded) ? loaded : null; } + internal static (Uri, ProjectInformation) LoadTemporary(Uri sourceFile) + { + static void LogOutput(string msg, MessageType level) => + Console.WriteLine($"[{level}]: {msg}"); + return new EditorState(new ProjectLoader(LogOutput), null, null, null, null) + .QsTemporaryProjectLoader(sourceFile, out var projectUri, out var loaded) ? (projectUri, loaded) : (null, null); + } + internal static bool UsesDll(this ProjectInformation info, string dll) => info.References.Any(r => r.EndsWith(dll)); internal static bool UsesProject(this ProjectInformation info, string projectFileName) => info.ProjectReferences.Any(r => r.EndsWith(projectFileName)); From ab77c1ad7d5f3953a014cd630636f53eb13ef20d Mon Sep 17 00:00:00 2001 From: Ryan Shaffer Date: Tue, 11 Aug 2020 07:09:36 -0700 Subject: [PATCH 04/10] Remove some duplication --- .../ProjectLoaderTests.cs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs b/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs index 79cd60f2ee..1c33ecda9f 100644 --- a/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs +++ b/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs @@ -306,21 +306,16 @@ public void LoadQsharpTemporaryProject() internal static class CompilationContext { - internal static ProjectInformation Load(Uri projectFile) - { - static void LogOutput(string msg, MessageType level) => - Console.WriteLine($"[{level}]: {msg}"); - return new EditorState(new ProjectLoader(LogOutput), null, null, null, null) + private static void LogOutput(string msg, MessageType level) => + Console.WriteLine($"[{level}]: {msg}"); + + internal static ProjectInformation Load(Uri projectFile) => + new EditorState(new ProjectLoader(LogOutput), null, null, null, null) .QsProjectLoader(projectFile, out var loaded) ? loaded : null; - } - internal static (Uri, ProjectInformation) LoadTemporary(Uri sourceFile) - { - static void LogOutput(string msg, MessageType level) => - Console.WriteLine($"[{level}]: {msg}"); - return new EditorState(new ProjectLoader(LogOutput), null, null, null, null) + internal static (Uri, ProjectInformation) LoadTemporary(Uri sourceFile) => + new EditorState(new ProjectLoader(LogOutput), null, null, null, null) .QsTemporaryProjectLoader(sourceFile, out var projectUri, out var loaded) ? (projectUri, loaded) : (null, null); - } internal static bool UsesDll(this ProjectInformation info, string dll) => info.References.Any(r => r.EndsWith(dll)); From 1afb32ce38bbf9fce6ceb4dbea79a00aebd8de8a Mon Sep 17 00:00:00 2001 From: Ryan Shaffer Date: Tue, 11 Aug 2020 07:27:04 -0700 Subject: [PATCH 05/10] Fixed version of Microsoft.Quantum.Sdk for test --- src/QsCompiler/LanguageServer/EditorState.cs | 7 ++++--- .../LanguageServer/TemporaryProject.cs.v.template | 8 +++++--- src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs | 6 +++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/QsCompiler/LanguageServer/EditorState.cs b/src/QsCompiler/LanguageServer/EditorState.cs index 56f55d645d..7f65f92a24 100644 --- a/src/QsCompiler/LanguageServer/EditorState.cs +++ b/src/QsCompiler/LanguageServer/EditorState.cs @@ -153,7 +153,7 @@ internal bool QsProjectLoader(Uri projectFile, out ProjectInformation info) return true; } - internal bool QsTemporaryProjectLoader(Uri sourceFileUri, out Uri projectUri, out ProjectInformation info) + internal bool QsTemporaryProjectLoader(Uri sourceFileUri, string sdkVersion, out Uri projectUri, out ProjectInformation info) { projectUri = null; info = null; @@ -165,7 +165,8 @@ internal bool QsTemporaryProjectLoader(Uri sourceFileUri, out Uri projectUri, ou { outputFile.WriteLine( TemporaryProject.GetFileContents( - compilationScope: Path.Combine(localFolderPath, "*.qs"))); + compilationScope: Path.Combine(localFolderPath, "*.qs"), + sdkVersion: sdkVersion)); } projectUri = new Uri(projectFilePath); @@ -250,7 +251,7 @@ internal Task OpenFileAsync( { try { - if (this.QsTemporaryProjectLoader(textDocument.Uri, out Uri projectUri, out _)) + if (this.QsTemporaryProjectLoader(textDocument.Uri, sdkVersion: null, out Uri projectUri, out _)) { this.projects.ProjectChangedOnDiskAsync(projectUri, this.QsProjectLoader, this.GetOpenFile).Wait(); associatedWithProject = true; diff --git a/src/QsCompiler/LanguageServer/TemporaryProject.cs.v.template b/src/QsCompiler/LanguageServer/TemporaryProject.cs.v.template index 0b2260c514..eb1ff039a2 100644 --- a/src/QsCompiler/LanguageServer/TemporaryProject.cs.v.template +++ b/src/QsCompiler/LanguageServer/TemporaryProject.cs.v.template @@ -1,12 +1,14 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#nullable enable + namespace Microsoft.Quantum.QsLanguageServer { internal static class TemporaryProject { - internal static string GetFileContents(string compilationScope) => $@" - + internal static string GetFileContents(string compilationScope, string? sdkVersion = null) => $@" + netstandard2.1 @@ -15,4 +17,4 @@ namespace Microsoft.Quantum.QsLanguageServer "; } -} \ No newline at end of file +} diff --git a/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs b/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs index 1c33ecda9f..717d694e4e 100644 --- a/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs +++ b/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs @@ -294,7 +294,7 @@ public void LoadQsharpMultiFrameworkLibrary() public void LoadQsharpTemporaryProject() { var sourceFile = Path.GetFullPath(SourceFileName("test14", "Operation14.qs")); - var (projectUri, projectInformation) = CompilationContext.LoadTemporary(new Uri(sourceFile)); + var (projectUri, projectInformation) = CompilationContext.LoadTemporary(new Uri(sourceFile), "0.12.20072031"); Assert.IsNotNull(projectUri); Assert.IsNotNull(projectInformation); Assert.IsTrue(projectInformation.UsesCanon()); @@ -313,9 +313,9 @@ internal static ProjectInformation Load(Uri projectFile) => new EditorState(new ProjectLoader(LogOutput), null, null, null, null) .QsProjectLoader(projectFile, out var loaded) ? loaded : null; - internal static (Uri, ProjectInformation) LoadTemporary(Uri sourceFile) => + internal static (Uri, ProjectInformation) LoadTemporary(Uri sourceFile, string sdkVersion) => new EditorState(new ProjectLoader(LogOutput), null, null, null, null) - .QsTemporaryProjectLoader(sourceFile, out var projectUri, out var loaded) ? (projectUri, loaded) : (null, null); + .QsTemporaryProjectLoader(sourceFile, sdkVersion, out var projectUri, out var loaded) ? (projectUri, loaded) : (null, null); internal static bool UsesDll(this ProjectInformation info, string dll) => info.References.Any(r => r.EndsWith(dll)); From 2a2e9a9489e5f1e92d383d31c6083f60f4661124 Mon Sep 17 00:00:00 2001 From: Ryan Shaffer Date: Fri, 14 Aug 2020 07:39:44 -0700 Subject: [PATCH 06/10] Stable filename for temporary .csproj --- src/QsCompiler/LanguageServer/EditorState.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QsCompiler/LanguageServer/EditorState.cs b/src/QsCompiler/LanguageServer/EditorState.cs index 7f65f92a24..5ceaae87e0 100644 --- a/src/QsCompiler/LanguageServer/EditorState.cs +++ b/src/QsCompiler/LanguageServer/EditorState.cs @@ -159,7 +159,7 @@ internal bool QsTemporaryProjectLoader(Uri sourceFileUri, string sdkVersion, out info = null; var localFolderPath = Path.GetDirectoryName(sourceFileUri.LocalPath); - var projectFolderPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "qsharp", Guid.NewGuid().ToString())).FullName; + var projectFolderPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "qsharp", $"proj{localFolderPath.GetHashCode()}")).FullName; var projectFilePath = Path.Combine(projectFolderPath, $"generated.csproj"); using (var outputFile = new StreamWriter(projectFilePath)) { From 5985ac8fa2a4c6a82bc3570a55b2e044be33e78c Mon Sep 17 00:00:00 2001 From: Ryan Shaffer Date: Fri, 14 Aug 2020 08:33:04 -0700 Subject: [PATCH 07/10] Format hash code as hex --- src/QsCompiler/LanguageServer/EditorState.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QsCompiler/LanguageServer/EditorState.cs b/src/QsCompiler/LanguageServer/EditorState.cs index 5ceaae87e0..982ae226b7 100644 --- a/src/QsCompiler/LanguageServer/EditorState.cs +++ b/src/QsCompiler/LanguageServer/EditorState.cs @@ -159,7 +159,7 @@ internal bool QsTemporaryProjectLoader(Uri sourceFileUri, string sdkVersion, out info = null; var localFolderPath = Path.GetDirectoryName(sourceFileUri.LocalPath); - var projectFolderPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "qsharp", $"proj{localFolderPath.GetHashCode()}")).FullName; + var projectFolderPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "qsharp", $"{localFolderPath.GetHashCode():X8}")).FullName; var projectFilePath = Path.Combine(projectFolderPath, $"generated.csproj"); using (var outputFile = new StreamWriter(projectFilePath)) { From 889bda6643320ba05bef98aa94206cce70ba0fbf Mon Sep 17 00:00:00 2001 From: Ryan Shaffer Date: Mon, 17 Aug 2020 13:32:08 -0700 Subject: [PATCH 08/10] Ensure FileSystemWatcher for temporary project folder --- src/QsCompiler/LanguageServer/EditorState.cs | 6 +++++- src/QsCompiler/LanguageServer/FileSystemWatcher.cs | 12 ++++++++---- src/QsCompiler/LanguageServer/LanguageServer.cs | 6 +++++- .../Tests.LanguageServer/ProjectLoaderTests.cs | 4 ++-- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/QsCompiler/LanguageServer/EditorState.cs b/src/QsCompiler/LanguageServer/EditorState.cs index 982ae226b7..944a4e3288 100644 --- a/src/QsCompiler/LanguageServer/EditorState.cs +++ b/src/QsCompiler/LanguageServer/EditorState.cs @@ -28,6 +28,7 @@ internal class EditorState : IDisposable private readonly Action publish; private readonly Action, Dictionary> sendTelemetry; + private readonly Action onTemporaryProjectLoaded; /// /// needed to determine if the reality of a source file that has changed on disk is indeed given by the content on disk, @@ -58,7 +59,8 @@ internal EditorState( Action publishDiagnostics, Action, Dictionary> sendTelemetry, Action log, - Action onException) + Action onException, + Action onTemporaryProjectLoaded) { this.ignoreEditorUpdatesForFiles = new ConcurrentDictionary(); this.sendTelemetry = sendTelemetry ?? ((eventName, properties, measurements) => { }); @@ -83,6 +85,7 @@ internal EditorState( this.projectLoader = projectLoader ?? throw new ArgumentNullException(nameof(projectLoader)); this.projects = new ProjectManager(onException, log, this.publish); this.openFiles = new ConcurrentDictionary(); + this.onTemporaryProjectLoaded = onTemporaryProjectLoaded; } /// @@ -254,6 +257,7 @@ internal Task OpenFileAsync( if (this.QsTemporaryProjectLoader(textDocument.Uri, sdkVersion: null, out Uri projectUri, out _)) { this.projects.ProjectChangedOnDiskAsync(projectUri, this.QsProjectLoader, this.GetOpenFile).Wait(); + this.onTemporaryProjectLoaded(projectUri); associatedWithProject = true; } } diff --git a/src/QsCompiler/LanguageServer/FileSystemWatcher.cs b/src/QsCompiler/LanguageServer/FileSystemWatcher.cs index 52b5f4f238..7514be31e0 100644 --- a/src/QsCompiler/LanguageServer/FileSystemWatcher.cs +++ b/src/QsCompiler/LanguageServer/FileSystemWatcher.cs @@ -152,10 +152,14 @@ public Task ListenAsync(string folder, bool subfolders, Action + watcher.Path == folder && watcher.Filter == pattern && watcher.NotifyFilter == notifyOn)) + { + var watcher = this.GetWatcher(folder, pattern, notifyOn); + watcher.IncludeSubdirectories = subfolders; + watcher.EnableRaisingEvents = true; + this.watchers.Add(watcher); + } } }); } diff --git a/src/QsCompiler/LanguageServer/LanguageServer.cs b/src/QsCompiler/LanguageServer/LanguageServer.cs index 76726c3f87..80337c8811 100644 --- a/src/QsCompiler/LanguageServer/LanguageServer.cs +++ b/src/QsCompiler/LanguageServer/LanguageServer.cs @@ -95,7 +95,8 @@ void ProcessFileEvents(IEnumerable e) => diagnostics => this.PublishDiagnosticsAsync(diagnostics), (name, props, meas) => this.SendTelemetryAsync(name, props, meas), this.LogToWindow, - this.OnInternalError); + this.OnInternalError, + this.OnTemporaryProjectLoaded); this.waitForInit.Set(); } @@ -156,6 +157,9 @@ internal void OnInternalError(Exception ex) } } + private void OnTemporaryProjectLoaded(Uri projectUri) => + this.fileWatcher.ListenAsync(Path.GetDirectoryName(projectUri.LocalPath), false, null, "*.csproj", "*.dll", "*.qs").Wait(); + // jsonrpc methods for initialization and shut down private Task InitializeWorkspaceAsync(ImmutableDictionary> folders) diff --git a/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs b/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs index 3083e2f299..d74547d202 100644 --- a/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs +++ b/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs @@ -324,11 +324,11 @@ private static void LogOutput(string msg, MessageType level) => Console.WriteLine($"[{level}]: {msg}"); internal static ProjectInformation Load(Uri projectFile) => - new EditorState(new ProjectLoader(LogOutput), null, null, null, null) + new EditorState(new ProjectLoader(LogOutput), null, null, null, null, null) .QsProjectLoader(projectFile, out var loaded) ? loaded : null; internal static (Uri, ProjectInformation) LoadTemporary(Uri sourceFile, string sdkVersion) => - new EditorState(new ProjectLoader(LogOutput), null, null, null, null) + new EditorState(new ProjectLoader(LogOutput), null, null, null, null, null) .QsTemporaryProjectLoader(sourceFile, sdkVersion, out var projectUri, out var loaded) ? (projectUri, loaded) : (null, null); internal static bool UsesDll(this ProjectInformation info, string dll) => info.References.Any(r => r.EndsWith(dll)); From 640eb2f1dc4a95bdada45106ab0fee1f0545e5b8 Mon Sep 17 00:00:00 2001 From: Ryan Shaffer Date: Mon, 17 Aug 2020 13:34:04 -0700 Subject: [PATCH 09/10] Only watch .csproj in temporary folder --- src/QsCompiler/LanguageServer/LanguageServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QsCompiler/LanguageServer/LanguageServer.cs b/src/QsCompiler/LanguageServer/LanguageServer.cs index 80337c8811..b231d35cd6 100644 --- a/src/QsCompiler/LanguageServer/LanguageServer.cs +++ b/src/QsCompiler/LanguageServer/LanguageServer.cs @@ -158,7 +158,7 @@ internal void OnInternalError(Exception ex) } private void OnTemporaryProjectLoaded(Uri projectUri) => - this.fileWatcher.ListenAsync(Path.GetDirectoryName(projectUri.LocalPath), false, null, "*.csproj", "*.dll", "*.qs").Wait(); + this.fileWatcher.ListenAsync(Path.GetDirectoryName(projectUri.LocalPath), false, null, "*.csproj").Wait(); // jsonrpc methods for initialization and shut down From 78d2aa9511ea95f6e6bd5745707912863f253164 Mon Sep 17 00:00:00 2001 From: Ryan Shaffer Date: Wed, 19 Aug 2020 14:13:15 -0700 Subject: [PATCH 10/10] Use lower-case folder name --- src/QsCompiler/LanguageServer/EditorState.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QsCompiler/LanguageServer/EditorState.cs b/src/QsCompiler/LanguageServer/EditorState.cs index 944a4e3288..11c4c3892e 100644 --- a/src/QsCompiler/LanguageServer/EditorState.cs +++ b/src/QsCompiler/LanguageServer/EditorState.cs @@ -162,7 +162,7 @@ internal bool QsTemporaryProjectLoader(Uri sourceFileUri, string sdkVersion, out info = null; var localFolderPath = Path.GetDirectoryName(sourceFileUri.LocalPath); - var projectFolderPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "qsharp", $"{localFolderPath.GetHashCode():X8}")).FullName; + var projectFolderPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "qsharp", $"{localFolderPath.GetHashCode():x8}")).FullName; var projectFilePath = Path.Combine(projectFolderPath, $"generated.csproj"); using (var outputFile = new StreamWriter(projectFilePath)) {