using EnvDTE;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using PortingAssistantVSExtensionClient.Common;
using PortingAssistantVSExtensionClient.Dialogs;
using PortingAssistantVSExtensionClient.Models;
using PortingAssistantVSExtensionClient.Options;
using PortingAssistantVSExtensionClient.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.IO;
using System.IO.Pipes;
using Task = System.Threading.Tasks.Task;
namespace PortingAssistantVSExtensionClient.Commands
{
///
/// Command handler
///
internal sealed class SolutionAssessmentCommand
{
///
/// Command ID.
///
public const int CommandId = PackageIds.SolutionAssessmentCommandId;
///
/// Command menu group (command set GUID).
///
public static readonly Guid CommandSet = new Guid(PackageGuids.guidPortingAssistantVSExtensionClientPackageCmdSetString);
///
/// VS Package that provides this command, not null.
///
private readonly AsyncPackage package;
///
/// Initializes a new instance of the class.
/// Adds our command handlers for menu (commands must exist in the command table file)
///
/// Owner package, not null.
/// Command service to add command to, not null.
private SolutionAssessmentCommand(AsyncPackage package, OleMenuCommandService commandService)
{
this.package = package ?? throw new ArgumentNullException(nameof(package));
commandService = commandService ?? throw new ArgumentNullException(nameof(commandService));
var menuCommandID = new CommandID(CommandSet, CommandId);
var menuItem = new MenuCommand(this.Execute, menuCommandID);
commandService.AddCommand(menuItem);
}
///
/// Gets the instance of the command.
///
public static SolutionAssessmentCommand Instance
{
get;
private set;
}
private string SolutionName = "";
///
/// Gets the service provider from the owner package.
///
private Microsoft.VisualStudio.Shell.IAsyncServiceProvider ServiceProvider
{
get
{
return this.package;
}
}
///
/// Initializes the singleton instance of the command.
///
/// Owner package, not null.
public static async Task InitializeAsync(AsyncPackage package)
{
// Switch to the main thread - the call to AddCommand in SolutionAssessmentCommand's constructor requires
// the UI thread.
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);
OleMenuCommandService commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService;
Instance = new SolutionAssessmentCommand(package, commandService);
}
///
/// This function is the callback used to execute the command when the menu item is clicked.
/// See the constructor to see how the menu item is associated with this function using
/// OleMenuCommandService service and MenuCommand class.
///
/// Event sender.
/// Event args.
private async void Execute(object sender, EventArgs e)
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
try
{
var solutionFile = await CommandsCommon.GetSolutionPathAsync();
#if Dev16
VS19LSPTrigger(solutionFile) ;
#endif
if (!await CommandsCommon.CheckLanguageServerStatusAsync())
{
NotificationUtils.ShowInfoMessageBox(PAGlobalService.Instance.Package, "Porting Assistant cannot be activated. Please open any .cs/.vb file if its not already opened.", "Porting Assistant can not be activated.");
return;
}
if (!CommandsCommon.SetupPage()) return;
// Verify Target framework selection before disabling all commands.
if (UserSettings.Instance.TargetFramework.Equals(TargetFrameworkType.NO_SELECTION))
{
if (!SelectTargetDialog.EnsureExecute()) return;
}
CommandsCommon.EnableAllCommand(false);
SolutionName = Path.GetFileName(solutionFile);
string pipeName = Guid.NewGuid().ToString();
// It's intended that we don't await for RunAssessmentAsync function for too long.
CommandsCommon.RunAssessmentAsync(solutionFile, pipeName);
PipeUtils.StartListenerConnection(pipeName, GetAssessmentCompletionTasks(this.package, SolutionName));
}
catch (Exception ex)
{
NotificationUtils.ShowErrorMessageBox(this.package, $"Assessment failed for {SolutionName} due to {ex.Message}", "Assessment failed");
CommandsCommon.EnableAllCommand(true);
}
}
public Func GetAssessmentCompletionTasks(AsyncPackage package, string solutionName)
{
async Task CompletionTask()
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
try
{
if (!UserSettings.Instance.EnabledContinuousAssessment)
{
UserSettings.Instance.EnabledContinuousAssessment = true;
UserSettings.Instance.UpdateContinuousAssessment();
await PortingAssistantLanguageClient.UpdateUserSettingsAsync();
}
await NotificationUtils.UseStatusBarProgressAsync(2, 2, "Assessment successful");
await NotificationUtils.ShowInfoBarAsync(
this.package,
"Assessment successful. You can view the assessment results in the error list or view the green highlights in your source code.");
UserSettings.Instance.SolutionAssessed = true;
}
catch (Exception ex)
{
NotificationUtils.ShowErrorMessageBox(
package,
$"Assessment failed for {solutionName} due to {ex.Message}",
"Assessment failed");
}
finally
{
CommandsCommon.EnableAllCommand(true);
}
}
return CompletionTask;
}
private async void VS19LSPTrigger(string solutionFile)
{
try
{
var openFile = Path.Combine(Path.GetDirectoryName(solutionFile), "pa.ini");
if (!File.Exists(openFile))
{
using (File.Create(openFile)) ;
}
var dte = await PAGlobalService.Instance.GetDTEServiceAsync();
dte.ItemOperations.OpenFile(openFile);
await CommandsCommon.CheckLanguageServerStatusAsync();
}
catch (Exception ex)
{
NotificationUtils.ShowErrorMessageBox(package,
$"failed to load porting assistant in visual studio 2019 due to {ex.Message}",
"failed to load porting assistant");
}
}
}
}