From 21322d8b9acf1ea46ee454d8341b956fb23ec5ef Mon Sep 17 00:00:00 2001 From: GrahamTheCoder Date: Wed, 26 Jan 2022 22:14:43 +0000 Subject: [PATCH] Only build one project unless whole solution converted - fixes #816 --- CHANGELOG.md | 1 + CodeConverter.sln.DotSettings | 2 ++ Vsix/CodeConversion.cs | 15 +++++++-------- Vsix/VisualStudioInteraction.cs | 20 +++++++++++++++++--- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a77ed642b..9ba71d9e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### Vsix +* Only trigger build for converted project where possible [#816](https://github.com/icsharpcode/CodeConverter/issues/816) ### VB -> C# diff --git a/CodeConverter.sln.DotSettings b/CodeConverter.sln.DotSettings index cd7a264a1..f722fd9f7 100644 --- a/CodeConverter.sln.DotSettings +++ b/CodeConverter.sln.DotSettings @@ -1,2 +1,4 @@  + CS + VB True \ No newline at end of file diff --git a/Vsix/CodeConversion.cs b/Vsix/CodeConversion.cs index e54eebbef..a1bd96a52 100644 --- a/Vsix/CodeConversion.cs +++ b/Vsix/CodeConversion.cs @@ -7,9 +7,7 @@ using System.Threading.Tasks; using System.Windows; using CodeConv.Shared.Util; -using ICSharpCode.CodeConverter; using ICSharpCode.CodeConverter.Shared; -using ICSharpCode.CodeConverter.VB; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServices; using Microsoft.VisualStudio.Shell; @@ -58,7 +56,7 @@ public CodeConversion(IAsyncServiceProvider serviceProvider, public async Task ConvertProjectsAsync(IReadOnlyCollection selectedProjects, CancellationToken cancellationToken) where TLanguageConversion : ILanguageConversion, new() { try { - await EnsureBuiltAsync(); + await EnsureBuiltAsync(selectedProjects); await _joinableTaskFactory.RunAsync(async () => { var convertedFiles = ConvertProjectUnhandled(selectedProjects, cancellationToken); await WriteConvertedFilesAndShowSummaryAsync(convertedFiles); @@ -73,7 +71,8 @@ await _joinableTaskFactory.RunAsync(async () => { public async Task ConvertDocumentAsync(string documentFilePath, Span selected, CancellationToken cancellationToken) where TLanguageConversion : ILanguageConversion, new() { try { - await EnsureBuiltAsync(); + var containingProject = await VisualStudioInteraction.GetFirstProjectContainingAsync(documentFilePath); + await EnsureBuiltAsync(containingProject is null ? Array.Empty() : new[]{containingProject}); var conversionResult = await _joinableTaskFactory.RunAsync(async () => { var result = await ConvertDocumentUnhandledAsync(documentFilePath, selected, cancellationToken); await WriteConvertedFilesAndShowSummaryAsync(new[] { result }.ToAsyncEnumerable()); @@ -96,9 +95,9 @@ await _joinableTaskFactory.RunAsync(async () => { /// https://github.com/icsharpcode/CodeConverter/issues/592 /// https://github.com/dotnet/roslyn/issues/6615 /// - private async Task EnsureBuiltAsync() + private async Task EnsureBuiltAsync(IReadOnlyCollection readOnlyCollection) { - await VisualStudioInteraction.EnsureBuiltAsync(m => _outputWindow.WriteToOutputWindowAsync(m)); + await VisualStudioInteraction.EnsureBuiltAsync(readOnlyCollection, m => _outputWindow.WriteToOutputWindowAsync(m)); } private static async Task SetClipboardTextOnUiThreadAsync(string conversionResultConvertedCode) @@ -233,8 +232,8 @@ private async Task GetConversionSummaryAsync(IReadOnlyCollection { await _outputWindow.WriteToOutputWindowAsync($"Converting {documentPath}...", true, true); - //TODO Figure out when there are multiple document ids for a single file path - var documentId = _visualStudioWorkspace.CurrentSolution.GetDocumentIdsWithFilePath(documentPath).SingleOrDefault(); + // If multiple projects contain this file path, there may be multiple ids, but in that the wrong project may have been built too... + var documentId = _visualStudioWorkspace.CurrentSolution.GetDocumentIdsWithFilePath(documentPath).FirstOrDefault(); if (documentId == null) { //If document doesn't belong to any project await _outputWindow.WriteToOutputWindowAsync("File is not part of a compiling project, using best effort text conversion (less accurate)."); diff --git a/Vsix/VisualStudioInteraction.cs b/Vsix/VisualStudioInteraction.cs index 7d05a4922..ddaad163f 100644 --- a/Vsix/VisualStudioInteraction.cs +++ b/Vsix/VisualStudioInteraction.cs @@ -170,15 +170,21 @@ public static async Task ShowMessageBoxAsync(IAsyncServiceProvider service return userAnswer == MessageBoxResult.OK; } - public static async Task EnsureBuiltAsync(Func writeMessageAsync) + public static async Task EnsureBuiltAsync(IReadOnlyCollection projects, Func writeMessageAsync) { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken); var build = Dte.Solution.SolutionBuild; if (build.BuildState == vsBuildState.vsBuildStateInProgress) { throw new InvalidOperationException("Build in progress, please wait for it to complete before conversion."); } - await writeMessageAsync("Building solution prior to conversion for maximum accuracy..."); - build.Build(true); + if (projects.Count == 1 && build.ActiveConfiguration?.Name is { } configuration && projects.Single().UniqueName is {} uniqueName) { + await writeMessageAsync($"Building project '{uniqueName}' prior to conversion for maximum accuracy..."); + build.BuildProject(configuration, uniqueName); + } else { + await writeMessageAsync("Building solution prior to conversion for maximum accuracy..."); + build.Build(true); + } + await TaskScheduler.Default; } @@ -236,6 +242,14 @@ public static async Task GetCaretPositionAsync(IAsyncServiceProvi return caretPositionAsync; } + public static async Task GetFirstProjectContainingAsync(string documentFilePath) + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken); + var containingProject = Dte.Solution.FindProjectItem(documentFilePath)?.ContainingProject; + await TaskScheduler.Default; + return containingProject; + } + internal class CaretPosition { private readonly ITextEdit _textEdit;