diff --git a/SmallSharp.sln b/SmallSharp.sln index acae116..6640e99 100644 --- a/SmallSharp.sln +++ b/SmallSharp.sln @@ -3,11 +3,10 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.30516.212 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SmallSharp", "src\SmallSharp\SmallSharp.csproj", "{F87C7A13-669C-4F18-9266-B256F254DFA3}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5420D663-3EA6-419B-8F73-C7EA374CFBBE}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig + .netconfig = .netconfig .github\dependabot.yml = .github\dependabot.yml src\Directory.Build.props = src\Directory.Build.props src\Directory.Build.targets = src\Directory.Build.targets @@ -27,7 +26,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{ .github\workflows\sponsors.yml = .github\workflows\sponsors.yml EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SmallSharp.Build", "src\SmallSharp.Build\SmallSharp.Build.csproj", "{62834B0C-A2C2-4449-9E2A-00CC390A79BE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SmallSharp", "src\SmallSharp\SmallSharp.csproj", "{97648980-AA30-4AC0-B8E9-FCF6359F56A0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -35,14 +34,10 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F87C7A13-669C-4F18-9266-B256F254DFA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F87C7A13-669C-4F18-9266-B256F254DFA3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F87C7A13-669C-4F18-9266-B256F254DFA3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F87C7A13-669C-4F18-9266-B256F254DFA3}.Release|Any CPU.Build.0 = Release|Any CPU - {62834B0C-A2C2-4449-9E2A-00CC390A79BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {62834B0C-A2C2-4449-9E2A-00CC390A79BE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {62834B0C-A2C2-4449-9E2A-00CC390A79BE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {62834B0C-A2C2-4449-9E2A-00CC390A79BE}.Release|Any CPU.Build.0 = Release|Any CPU + {97648980-AA30-4AC0-B8E9-FCF6359F56A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {97648980-AA30-4AC0-B8E9-FCF6359F56A0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {97648980-AA30-4AC0-B8E9-FCF6359F56A0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {97648980-AA30-4AC0-B8E9-FCF6359F56A0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/SmallSharp.Build/MonitorActiveDocument.cs b/src/SmallSharp.Build/MonitorActiveDocument.cs deleted file mode 100644 index eb8085d..0000000 --- a/src/SmallSharp.Build/MonitorActiveDocument.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Diagnostics; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; - -namespace SmallSharp.Build -{ - public class MonitorActiveDocument : Task - { - [Required] - public string? FlagFile { get; set; } - - [Required] - public string? LaunchProfiles { get; set; } - - [Required] - public string? UserFile { get; set; } - - public override bool Execute() - { - if (LaunchProfiles == null || UserFile == null || FlagFile == null) - return true; - - try - { - if (BuildEngine4.GetRegisteredTaskObject(nameof(ActiveDocumentMonitor), RegisteredTaskObjectLifetime.AppDomain) is not ActiveDocumentMonitor monitor) - { - if (WindowsInterop.GetServiceProvider() is IServiceProvider services) - { - var documentMonitor = new ActiveDocumentMonitor(LaunchProfiles, UserFile, FlagFile, services); - - BuildEngine4.RegisterTaskObject(nameof(ActiveDocumentMonitor), documentMonitor, - RegisteredTaskObjectLifetime.AppDomain, false); - - // Start monitoring at the end of the build, to avoid slowing down the DTB - BuildEngine4.RegisterTaskObject("StartMonitor", - new DisposableAction(() => documentMonitor.Start()), - RegisteredTaskObjectLifetime.Build, false); - } - else - { - Debug.Fail("Failed to get IServiceProvider to monitor for active document."); - } - } - else - { - // NOTE: this means we only support ONE project/launchProfiles per IDE. - monitor.Refresh(LaunchProfiles, UserFile, FlagFile); - } - } - catch (Exception e) - { - Log.LogWarning($"Failed to start active document monitoring: {e}"); - } - - return true; - } - } -} diff --git a/src/SmallSharp.Build/OpenStartupFile.cs b/src/SmallSharp.Build/OpenStartupFile.cs deleted file mode 100644 index c14e796..0000000 --- a/src/SmallSharp.Build/OpenStartupFile.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.IO; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; - -namespace SmallSharp.Build -{ - public class OpenStartupFile : Task - { - [Required] - public string? FlagFile { get; set; } - - public string? StartupFile { get; set; } - - public override bool Execute() - { - if (string.IsNullOrEmpty(FlagFile) || string.IsNullOrEmpty(StartupFile)) - return true; - - if (!File.Exists(FlagFile) || - File.ReadAllText(FlagFile) != StartupFile) - { - // This defers the opening until the build completes. - BuildEngine4.RegisterTaskObject( - StartupFile, - new DisposableAction(() => WindowsInterop.EnsureOpened(StartupFile!)), - RegisteredTaskObjectLifetime.Build, false); - - File.WriteAllText(FlagFile, StartupFile); - } - - return true; - } - } -} diff --git a/src/SmallSharp.Build/SmallSharp.Build.csproj b/src/SmallSharp.Build/SmallSharp.Build.csproj deleted file mode 100644 index c02eae2..0000000 --- a/src/SmallSharp.Build/SmallSharp.Build.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - net472 - build\netstandard2.0 - true - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/SmallSharp.Build/ActiveDocumentMonitor.cs b/src/SmallSharp/ActiveDocumentMonitor.cs similarity index 56% rename from src/SmallSharp.Build/ActiveDocumentMonitor.cs rename to src/SmallSharp/ActiveDocumentMonitor.cs index d51e9e4..be8a94e 100644 --- a/src/SmallSharp.Build/ActiveDocumentMonitor.cs +++ b/src/SmallSharp/ActiveDocumentMonitor.cs @@ -6,121 +6,104 @@ using System.Threading; using System.Xml.Linq; using Microsoft.VisualStudio.Shell.Interop; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace SmallSharp.Build { - class ActiveDocumentMonitor : MarshalByRefObject, IDisposable, IVsRunningDocTableEvents, IVsSelectionEvents + class ActiveDocumentMonitor : MarshalByRefObject, IDisposable, IVsRunningDocTableEvents, IVsSelectionEvents, IVsSolutionEvents { - FileSystemWatcher watcher; - readonly IServiceProvider services; - + IVsSolution? solution; IVsRunningDocumentTable? rdt; IVsMonitorSelection? selection; + + uint solutionCookie; uint rdtCookie; uint selectionCookie; string launchProfilesPath; string userFile; - string flagFile; - Dictionary startupFiles = new(); + Dictionary startupFiles; + + string? activeFile; - public ActiveDocumentMonitor(string launchProfilesPath, string userFile, string flagFile, IServiceProvider services) + public ActiveDocumentMonitor(string launchProfilesPath, string userFile, + string[] startupFiles, IServiceProvider services) { this.launchProfilesPath = launchProfilesPath; this.userFile = userFile; - this.flagFile = flagFile; - this.services = services; - - watcher = new FileSystemWatcher(Path.GetDirectoryName(launchProfilesPath)) - { - NotifyFilter = NotifyFilters.LastWrite, - Filter = "launchSettings.json", - }; - - watcher.Changed += (_, _) => ReloadProfiles(); - watcher.Created += (_, _) => ReloadProfiles(); - watcher.EnableRaisingEvents = true; - ReloadProfiles(); - } + this.startupFiles = startupFiles.ToDictionary(x => x, StringComparer.OrdinalIgnoreCase); - public void Start() - { + solution = (IVsSolution)services.GetService(typeof(SVsSolution)); rdt = (IVsRunningDocumentTable)services.GetService(typeof(SVsRunningDocumentTable)); - if (rdt != null) - rdt.AdviseRunningDocTableEvents(this, out rdtCookie); - selection = (IVsMonitorSelection)services.GetService(typeof(SVsShellMonitorSelection)); - if (selection != null) - selection.AdviseSelectionEvents(this, out selectionCookie); + + EnsureMonitoring(); } - public void Refresh(string launchProfiles, string userFile, string flagFile) + public void Refresh(string launchProfiles, string userFile, string[] startupFiles) { launchProfilesPath = launchProfiles; this.userFile = userFile; - this.flagFile = flagFile; - watcher.Path = Path.GetDirectoryName(launchProfiles); - ReloadProfiles(); - } + this.startupFiles = startupFiles.ToDictionary(x => x, StringComparer.OrdinalIgnoreCase); - void ReloadProfiles() - { - if (!File.Exists(launchProfilesPath)) - return; - - var maxAttempts = 5; - var exceptions = new List(); + EnsureMonitoring(); - for (var i = 0; i < maxAttempts; i++) - { - try - { - var json = JObject.Parse(File.ReadAllText(launchProfilesPath)); - if (json.Property("profiles") is not JProperty prop || - prop.Value is not JObject profiles) - return; + // For new files, we get the update before the new item is added to + // msbuild top-level files, so we retry on refresh + UpdateStartupFile(activeFile); + } - startupFiles = profiles.Properties().Select(p => p.Name) - .ToDictionary(x => x, StringComparer.OrdinalIgnoreCase); + void EnsureMonitoring() + { + if (solutionCookie == 0 && solution != null) + solution.AdviseSolutionEvents(this, out solutionCookie); - return; - } - catch (Exception e) - { - exceptions.Add(e); - Thread.Sleep(500); - } - } + if (rdtCookie == 0 && rdt != null) + rdt.AdviseRunningDocTableEvents(this, out rdtCookie); - // NOTE: check exceptions list to see why. - Debug.Fail("Could not read launchSettings.json"); + if (selectionCookie == 0 && selection != null) + selection.AdviseSelectionEvents(this, out selectionCookie); } void UpdateStartupFile(string? path) { + activeFile = path; + if (!string.IsNullOrEmpty(path) && path!.IndexOfAny(Path.GetInvalidPathChars()) == -1 && - Path.GetFileName(path) is string startupFile && - startupFiles.ContainsKey(startupFile)) + startupFiles.TryGetValue(Path.GetFileName(path), out var startupFile)) { + var settings = new JObject( + new JProperty("profiles", new JObject( + new JProperty(startupFile, new JObject( + new JProperty("commandName", "Project") + )) + )) + ); + + var json = settings.ToString(Formatting.Indented); + + // Only write if different content. + if (File.Exists(launchProfilesPath) && + File.ReadAllText(launchProfilesPath) == json) + return; + + File.WriteAllText(launchProfilesPath, json); + try { // Get the value as it was exists in the original dictionary, // since it has to match what the source generator created in the // launch profiles. - startupFile = startupFiles[startupFile]; var xdoc = XDocument.Load(userFile); var active = xdoc .Descendants("{http://schemas.microsoft.com/developer/msbuild/2003}ActiveDebugProfile") .FirstOrDefault(); - if (active != null && active.Value != startupFile) + if (active != null && !startupFile.Equals(active.Value, StringComparison.OrdinalIgnoreCase)) { active.Value = startupFile; - // First save to flag file so we don't cause another open - // attempt via the OpenStartupFile task. - File.WriteAllText(flagFile, startupFile); xdoc.Save(userFile); } } @@ -131,15 +114,22 @@ void UpdateStartupFile(string? path) } } - void IDisposable.Dispose() + public void Dispose() { + if (solutionCookie != 0 && solution != null) + Try(() => solution.UnadviseSolutionEvents(solutionCookie)); + + solutionCookie = 0; + if (rdtCookie != 0 && rdt != null) Try(() => rdt.UnadviseRunningDocTableEvents(rdtCookie)); + rdtCookie = 0; + if (selectionCookie != 0 && selection != null) Try(() => selection.UnadviseSelectionEvents(selectionCookie)); - watcher.Dispose(); + selectionCookie = 0; } void Try(Action action) @@ -176,18 +166,32 @@ int IVsSelectionEvents.OnSelectionChanged(IVsHierarchy pHierOld, uint itemidOld, return 0; } - int IVsRunningDocTableEvents.OnAfterFirstDocumentLock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining) => 0; + int IVsSolutionEvents.OnBeforeUnloadProject(IVsHierarchy pRealHierarchy, IVsHierarchy pStubHierarchy) + { + Dispose(); + return 0; + } - int IVsRunningDocTableEvents.OnBeforeLastDocumentUnlock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining) => 0; + int IVsSolutionEvents.OnBeforeCloseSolution(object pUnkReserved) + { + Dispose(); + return 0; + } + int IVsRunningDocTableEvents.OnAfterFirstDocumentLock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining) => 0; + int IVsRunningDocTableEvents.OnBeforeLastDocumentUnlock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining) => 0; int IVsRunningDocTableEvents.OnAfterSave(uint docCookie) => 0; - int IVsRunningDocTableEvents.OnBeforeDocumentWindowShow(uint docCookie, int fFirstShow, IVsWindowFrame pFrame) => 0; - int IVsRunningDocTableEvents.OnAfterDocumentWindowHide(uint docCookie, IVsWindowFrame pFrame) => 0; - int IVsSelectionEvents.OnElementValueChanged(uint elementid, object varValueOld, object varValueNew) => 0; - int IVsSelectionEvents.OnCmdUIContextChanged(uint dwCmdUICookie, int fActive) => 0; + int IVsSolutionEvents.OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded) => throw new NotImplementedException(); + int IVsSolutionEvents.OnQueryCloseProject(IVsHierarchy pHierarchy, int fRemoving, ref int pfCancel) => throw new NotImplementedException(); + int IVsSolutionEvents.OnBeforeCloseProject(IVsHierarchy pHierarchy, int fRemoved) => throw new NotImplementedException(); + int IVsSolutionEvents.OnAfterLoadProject(IVsHierarchy pStubHierarchy, IVsHierarchy pRealHierarchy) => throw new NotImplementedException(); + int IVsSolutionEvents.OnQueryUnloadProject(IVsHierarchy pRealHierarchy, ref int pfCancel) => throw new NotImplementedException(); + int IVsSolutionEvents.OnAfterOpenSolution(object pUnkReserved, int fNewSolution) => throw new NotImplementedException(); + int IVsSolutionEvents.OnQueryCloseSolution(object pUnkReserved, ref int pfCancel) => throw new NotImplementedException(); + int IVsSolutionEvents.OnAfterCloseSolution(object pUnkReserved) => throw new NotImplementedException(); } } diff --git a/src/SmallSharp/AnalyzerConfigOptionsExtensions.cs b/src/SmallSharp/AnalyzerConfigOptionsExtensions.cs deleted file mode 100644 index 4875954..0000000 --- a/src/SmallSharp/AnalyzerConfigOptionsExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.CodeAnalysis.Diagnostics; - -namespace SmallSharp -{ - static class AnalyzerConfigOptionsExtensions - { - public static bool IsEnabled(this AnalyzerOptions options, string optionName) - => IsEnabled(options.AnalyzerConfigOptionsProvider.GlobalOptions, optionName); - - public static bool IsEnabled(this AnalyzerConfigOptionsProvider options, string optionName) - => IsEnabled(options.GlobalOptions, optionName); - - public static bool IsEnabled(this AnalyzerConfigOptions options, string optionName) - => options.TryGetValue("build_property." + optionName, out var value) && bool.TryParse(value, out var enabled) && enabled; - } -} diff --git a/src/SmallSharp/DebuggerExtension.cs b/src/SmallSharp/DebuggerExtension.cs deleted file mode 100644 index bac4ca8..0000000 --- a/src/SmallSharp/DebuggerExtension.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Diagnostics; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; - -namespace SmallSharp -{ - static class DebuggerExtension - { - //[Conditional("DEBUG")] - public static void CheckDebugger(this GeneratorExecutionContext context, string generatorName = nameof(SmallSharp)) - => context.AnalyzerConfigOptions.CheckDebugger(generatorName); - - public static void CheckDebugger(this AnalyzerConfigOptionsProvider provider, string generatorName = nameof(SmallSharp)) - { - if (Process.GetCurrentProcess().ProcessName == "devenv") - return; - - if (provider.IsEnabled("DebugSourceGenerators") || - provider.IsEnabled("Debug" + generatorName)) - Debugger.Launch(); - } - } -} diff --git a/src/SmallSharp.Build/DisposableAction.cs b/src/SmallSharp/DisposableAction.cs similarity index 100% rename from src/SmallSharp.Build/DisposableAction.cs rename to src/SmallSharp/DisposableAction.cs diff --git a/src/SmallSharp/LaunchSettingsGenerator.cs b/src/SmallSharp/LaunchSettingsGenerator.cs deleted file mode 100644 index 51e3e04..0000000 --- a/src/SmallSharp/LaunchSettingsGenerator.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.IO; -using System.Linq; -using Microsoft.CodeAnalysis; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace SmallSharp -{ - [Generator] - public class LaunchSettingsGenerator : ISourceGenerator - { - public void Initialize(GeneratorInitializationContext context) { } - - public void Execute(GeneratorExecutionContext context) - { - context.CheckDebugger(); - - var documents = from additional in context.AdditionalFiles - let options = context.AnalyzerConfigOptions.GetOptions(additional) - let compile = options.TryGetValue("build_metadata.AdditionalFiles.SourceItemType", out var itemType) && itemType == "Compile" - where compile - select additional.Path; - - var settings = new JObject( - new JProperty("profiles", new JObject( - documents.OrderBy(path => Path.GetFileName(path)).Select(path => new JProperty(Path.GetFileName(path), new JObject( - new JProperty("commandName", "Project") - ))) - )) - ); - - if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.MSBuildProjectDirectory", out var directory)) - { - Directory.CreateDirectory(Path.Combine(directory, "Properties")); - var filePath = Path.Combine(directory, "Properties", "launchSettings.json"); - var json = settings.ToString(Formatting.Indented); - - // Only write if different content. - if (File.Exists(filePath) && - File.ReadAllText(filePath) == json) - return; - - File.WriteAllText(filePath, json); - } - } - } -} diff --git a/src/SmallSharp/MonitorActiveDocument.cs b/src/SmallSharp/MonitorActiveDocument.cs new file mode 100644 index 0000000..e056bd3 --- /dev/null +++ b/src/SmallSharp/MonitorActiveDocument.cs @@ -0,0 +1,70 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace SmallSharp.Build +{ + public class MonitorActiveDocument : Task + { + [Required] + public string? LaunchProfiles { get; set; } + + [Required] + public string? UserFile { get; set; } + + [Required] + public ITaskItem[] StartupFiles { get; set; } = Array.Empty(); + + public override bool Execute() + { + if (string.IsNullOrEmpty(LaunchProfiles) || + string.IsNullOrEmpty(UserFile)) + { + Debug.Fail("Should have gotten something to monitor"); + return true; + } + + try + { + if (BuildEngine4.GetRegisteredTaskObject(nameof(ActiveDocumentMonitor), RegisteredTaskObjectLifetime.AppDomain) is not ActiveDocumentMonitor monitor) + { + var maxAttempts = 5; + for (var i = 0; i < maxAttempts; i++) + { + if (WindowsInterop.GetServiceProvider() is IServiceProvider services) + { + BuildEngine4.RegisterTaskObject(nameof(ActiveDocumentMonitor), + new ActiveDocumentMonitor(LaunchProfiles!, UserFile!, + StartupFiles.Select(x => x.ItemSpec).ToArray(), services), + RegisteredTaskObjectLifetime.AppDomain, false); + + return true; + } + else + { + BuildEngine4.Yield(); + Thread.Sleep(200); + } + } + + Debug.Fail("Failed to get IServiceProvider to monitor for active document."); + } + else + { + // NOTE: this means we only support ONE project/launchProfiles per IDE. + monitor.Refresh(LaunchProfiles!, UserFile!, + StartupFiles.Select(x => x.ItemSpec).ToArray()); + } + } + catch (Exception e) + { + Log.LogWarning($"Failed to start active document monitoring: {e}"); + } + + return true; + } + } +} diff --git a/src/SmallSharp.Build/NativeMethods.cs b/src/SmallSharp/NativeMethods.cs similarity index 88% rename from src/SmallSharp.Build/NativeMethods.cs rename to src/SmallSharp/NativeMethods.cs index 4b645b3..1ac2ba9 100644 --- a/src/SmallSharp.Build/NativeMethods.cs +++ b/src/SmallSharp/NativeMethods.cs @@ -2,6 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; +using System.Text; internal static class NativeMethods { @@ -15,6 +16,21 @@ internal static class NativeMethods public static readonly Guid IID_IObjectWithSite = typeof(Microsoft.VisualStudio.OLE.Interop.IObjectWithSite).GUID; public static Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046"); + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + internal static extern int GetShortPathName( + [MarshalAs(UnmanagedType.LPTStr)] + string path, + [MarshalAs(UnmanagedType.LPTStr)] + StringBuilder shortPath, + int shortPathLength); + + internal static string GetShortPath(string path) + { + var shortPath = new StringBuilder(MAX_PATH); + GetShortPathName(path, shortPath, MAX_PATH); + return shortPath.ToString(); + } + [DllImport("ole32.dll")] internal static extern int CoRegisterMessageFilter(IMessageFilter lpMessageFilter, out IMessageFilter lplpMessageFilter); [DllImport("ole32.dll")] diff --git a/src/SmallSharp/SmallSharp.csproj b/src/SmallSharp/SmallSharp.csproj index 016c170..2aac7af 100644 --- a/src/SmallSharp/SmallSharp.csproj +++ b/src/SmallSharp/SmallSharp.csproj @@ -1,26 +1,32 @@  - netstandard2.0 + net472 SmallSharp Create, edit and run multiple C# 9.0 top-level programs in the same project 😍 - analyzers\dotnet\cs + build\netstandard2.0 + true + - + + + + + - + + - - + - + \ No newline at end of file diff --git a/src/SmallSharp.Build/SmallSharp.targets b/src/SmallSharp/SmallSharp.targets similarity index 61% rename from src/SmallSharp.Build/SmallSharp.targets rename to src/SmallSharp/SmallSharp.targets index d8023db..142c723 100644 --- a/src/SmallSharp.Build/SmallSharp.targets +++ b/src/SmallSharp/SmallSharp.targets @@ -1,23 +1,23 @@ - - + $(MSBuildVersion.TrimEnd('0123456789').TrimEnd('.')) + + *$(DefaultLanguageSourceExtension) + $(ActiveDebugProfile) + CollectStartupFile;SelectStartupFile;SelectTopLevelCompile - - - - - - + + + @@ -27,23 +27,38 @@ - + + + + + + + - - - + - + + + + + + + + + true - - + %(ReversedCompile.Identity) @@ -117,7 +132,7 @@ @@ -126,39 +141,9 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + diff --git a/src/SmallSharp.Build/WindowsInterop.cs b/src/SmallSharp/WindowsInterop.cs similarity index 86% rename from src/SmallSharp.Build/WindowsInterop.cs rename to src/SmallSharp/WindowsInterop.cs index b727acc..734dadb 100644 --- a/src/SmallSharp.Build/WindowsInterop.cs +++ b/src/SmallSharp/WindowsInterop.cs @@ -14,39 +14,6 @@ static class WindowsInterop { static readonly Regex versionExpr = new Regex(@"Microsoft Visual Studio (?\d\d\.\d)", RegexOptions.Compiled | RegexOptions.ExplicitCapture); - public static void EnsureOpened(string filePath, TimeSpan delay = default) - { - if (Environment.OSVersion.Platform != PlatformID.Win32NT) - return; - - if (delay != default) - Thread.Sleep(delay); - - var dte = GetDTE(); - if (dte == null) - return; - - var maxAttempts = 5; - var exceptions = new List(); - - for (var i = 0; i < maxAttempts; i++) - { - try - { - dte.ExecuteCommand("File.OpenFile", filePath); - return; - } - catch (Exception e) - { - exceptions.Add(e); - Thread.Sleep(500); - } - } - - // NOTE: inspect exceptions variable - Debug.Fail($"Failed to open {filePath} after 5 attempts."); - } - public static IServiceProvider? GetServiceProvider(TimeSpan delay = default) { if (Environment.OSVersion.Platform != PlatformID.Win32NT)