diff --git a/Vsix/CodeConverterPackage.cs b/Vsix/CodeConverterPackage.cs index e23f4253..cbcd058f 100644 --- a/Vsix/CodeConverterPackage.cs +++ b/Vsix/CodeConverterPackage.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.ComponentModelHost; +using Microsoft.VisualStudio.Extensibility; using Microsoft.VisualStudio.LanguageServices; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Threading; @@ -85,6 +86,9 @@ public sealed class CodeConverterPackage : AsyncPackage public const string ConvertableSolutionMenuVisibilityGuid = "8e7192d0-28b7-4fe7-8d84-82c1db98d459"; internal Cancellation PackageCancellation { get; } = new(); + + internal static CodeConversion CodeConversionInstance { get; private set; } + internal static CodeConverterPackage Instance { get; private set; } /// /// Initializes a new instance of package class. @@ -109,6 +113,8 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var visualStudioWorkspace = componentModel.GetService(); var codeConversion = await CodeConversion.CreateAsync(this, visualStudioWorkspace, this.GetDialogPageAsync); + CodeConversionInstance = codeConversion; + Instance = this; ConvertCSToVBCommand.Initialize(this, oleMenuCommandService, codeConversion); ConvertVBToCSCommand.Initialize(this, oleMenuCommandService, codeConversion); PasteAsVB.Initialize(this, oleMenuCommandService, codeConversion); diff --git a/Vsix/ConvertCSToVBExtensibilityCommand.cs b/Vsix/ConvertCSToVBExtensibilityCommand.cs new file mode 100644 index 00000000..3d1bc3a1 --- /dev/null +++ b/Vsix/ConvertCSToVBExtensibilityCommand.cs @@ -0,0 +1,45 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.Extensibility; +using Microsoft.VisualStudio.Extensibility.Commands; + +namespace ICSharpCode.CodeConverter.VsExtension; + +[VisualStudioContribution] +public class ConvertCSToVBExtensibilityCommand : Command +{ + private readonly CodeConverterPackage _package; + + public ConvertCSToVBExtensibilityCommand(CodeConverterPackage package) + { + _package = package; + } + + public override CommandConfiguration CommandConfiguration => new("%a3378a21-e939-40c9-9e4b-eb0cec7b7854%"); + + public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) + { + var codeConversion = CodeConverterPackage.CodeConversionInstance; + var serviceProvider = CodeConverterPackage.Instance; + if (codeConversion == null || serviceProvider == null) return; + + var itemsPath = await VisualStudioInteraction.GetSelectedItemsPathAsync(CodeConversion.IsCSFileName); + if (itemsPath.Count > 0) + { + await codeConversion.ConvertDocumentsAsync(itemsPath, cancellationToken); + return; + } + + var projects = await VisualStudioInteraction.GetSelectedProjectsAsync(".csproj"); + if (projects.Count > 0) + { + await codeConversion.ConvertProjectsAsync(projects, cancellationToken); + return; + } + + (string filePath, var selection) = await VisualStudioInteraction.GetCurrentFilenameAndSelectionAsync(serviceProvider, CodeConversion.IsCSFileName, false); + if (filePath != null && selection != null) { + await codeConversion.ConvertDocumentAsync(filePath, selection.Value, cancellationToken); + } + } +} diff --git a/Vsix/ConvertVBToCSExtensibilityCommand.cs b/Vsix/ConvertVBToCSExtensibilityCommand.cs new file mode 100644 index 00000000..1cc9fe3e --- /dev/null +++ b/Vsix/ConvertVBToCSExtensibilityCommand.cs @@ -0,0 +1,45 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.Extensibility; +using Microsoft.VisualStudio.Extensibility.Commands; + +namespace ICSharpCode.CodeConverter.VsExtension; + +[VisualStudioContribution] +public class ConvertVBToCSExtensibilityCommand : Command +{ + private readonly CodeConverterPackage _package; + + public ConvertVBToCSExtensibilityCommand(CodeConverterPackage package) + { + _package = package; + } + + public override CommandConfiguration CommandConfiguration => new("%a3378a21-e939-40c9-9e4b-eb0cec7b7854%"); + + public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) + { + var codeConversion = CodeConverterPackage.CodeConversionInstance; + var serviceProvider = CodeConverterPackage.Instance; + if (codeConversion == null || serviceProvider == null) return; + + var itemsPath = await VisualStudioInteraction.GetSelectedItemsPathAsync(CodeConversion.IsVBFileName); + if (itemsPath.Count > 0) + { + await codeConversion.ConvertDocumentsAsync(itemsPath, cancellationToken); + return; + } + + var projects = await VisualStudioInteraction.GetSelectedProjectsAsync(".vbproj"); + if (projects.Count > 0) + { + await codeConversion.ConvertProjectsAsync(projects, cancellationToken); + return; + } + + (string filePath, var selection) = await VisualStudioInteraction.GetCurrentFilenameAndSelectionAsync(serviceProvider, CodeConversion.IsVBFileName, false); + if (filePath != null && selection != null) { + await codeConversion.ConvertDocumentAsync(filePath, selection.Value, cancellationToken); + } + } +} diff --git a/Vsix/Extension.cs b/Vsix/Extension.cs new file mode 100644 index 00000000..5694252d --- /dev/null +++ b/Vsix/Extension.cs @@ -0,0 +1,12 @@ +using Microsoft.VisualStudio.Extensibility; + +namespace ICSharpCode.CodeConverter.VsExtension; + +[VisualStudioContribution] +public class CodeConverterExtension : Extension +{ + public override ExtensionConfiguration ExtensionConfiguration => new() { + RequiresInProcessHosting = true, + Metadata = null + }; +} diff --git a/Vsix/VisualStudioInteraction.cs b/Vsix/VisualStudioInteraction.cs index a1e49865..4ac8a818 100644 --- a/Vsix/VisualStudioInteraction.cs +++ b/Vsix/VisualStudioInteraction.cs @@ -32,8 +32,13 @@ internal static class VisualStudioInteraction { private static DTE2 _dte; - /// All calls and usages must be from the main thread> - internal static DTE2 Dte => _dte ??= Package.GetGlobalService(typeof(DTE)) as DTE2; + /// All calls and usages must be from the main thread + internal static DTE2 Dte { + get { + ThreadHelper.ThrowIfNotOnUIThread(); + return _dte ??= Package.GetGlobalService(typeof(DTE)) as DTE2; + } + } private static CancellationToken _cancelAllToken; private static readonly Version LowestSupportedVersion = new(16, 10, 0, 0); diff --git a/Vsix/Vsix.csproj b/Vsix/Vsix.csproj index 93d31a7a..02e64e82 100644 --- a/Vsix/Vsix.csproj +++ b/Vsix/Vsix.csproj @@ -1,145 +1,53 @@ - - + - 16.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - Debug - AnyCPU - 2.0 - ICSharpCode.CodeConverter.VsExtension - ICSharpCode.CodeConverter.VsExtension - {99498EF8-C9E0-433B-8D7B-EA8E9E66F0C7} - {82B43B9B-A64C-4715-B499-D71E9CA2BD60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - v4.7.2 + net472 + disable + disable + 12 + true + + true true - true - true true true - Roslyn - Program - $(DevEnvDir)devenv.exe - /rootsuffix $(VSSDKTargetPlatformRegRootSuffix) - false - False - win - 12.0 - - - - true - true - true - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - $(LocalAppData)\Microsoft\VisualStudio\15.0_8bd9890a\Extensions\frc3cnfo.23z - True - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 + - - 1.8.4 - - - 10.0.2 - - + + + - - compile; build; native; contentfiles; analyzers; buildtransitive - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - + + + + + + Menus.ctmenu - Designer - true PreserveNewest + true - true PreserveNewest + true Always true - - - - - - - - - - - Component - - - - - - - - - - - - - - - + true VSPackage - Designer - - - {7ea075c6-6406-445c-ab77-6c47aff88d58} - CodeConverter - - + - - - - - - - - - - - \ No newline at end of file diff --git a/Vsix/source.extension.vsixmanifest b/Vsix/source.extension.vsixmanifest index 961647bf..0325f30f 100644 --- a/Vsix/source.extension.vsixmanifest +++ b/Vsix/source.extension.vsixmanifest @@ -13,10 +13,10 @@ code converter vb csharp visual basic csharp net translate - + amd64 - + arm64