Add a menu for launching Godot from Visual Studio (#32)

* Add a menu for launching GoDot from visual studio

* reduntant qualifier

* Reindent
This commit is contained in:
Alexei Stukov
2022-09-04 16:29:32 +03:00
committed by GitHub
parent f858c841d7
commit dfdea8a757
5 changed files with 328 additions and 6 deletions

View File

@@ -0,0 +1,101 @@
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System;
using System.ComponentModel.Design;
using System.Globalization;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.VisualStudio.Settings;
using Microsoft.VisualStudio.Shell.Settings;
using Task = System.Threading.Tasks.Task;
namespace GodotAddinVS.Commands {
/// <summary>
/// Command handler
/// </summary>
internal sealed class CommandResetGodot {
/// <summary>
/// Command ID.
/// </summary>
public const int CommandId = 256;
/// <summary>
/// Command menu group (command set GUID).
/// </summary>
public static readonly Guid CommandSet = new Guid("38009f93-330e-4875-ab88-e127fd85bb88");
/// <summary>
/// VS Package that provides this command, not null.
/// </summary>
private readonly AsyncPackage package;
/// <summary>
/// Initializes a new instance of the <see cref="CommandResetGodot"/> class.
/// Adds our command handlers for menu (commands must exist in the command table file)
/// </summary>
/// <param name="package">Owner package, not null.</param>
/// <param name="commandService">Command service to add command to, not null.</param>
private CommandResetGodot(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);
}
/// <summary>
/// Gets the instance of the command.
/// </summary>
public static CommandResetGodot Instance {
get;
private set;
}
/// <summary>
/// Gets the service provider from the owner package.
/// </summary>
private Microsoft.VisualStudio.Shell.IAsyncServiceProvider ServiceProvider {
get {
return this.package;
}
}
/// <summary>
/// Initializes the singleton instance of the command.
/// </summary>
/// <param name="package">Owner package, not null.</param>
public static async Task InitializeAsync(AsyncPackage package) {
// Switch to the main thread - the call to AddCommand in CommandResetGodot's constructor requires
// the UI thread.
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);
OleMenuCommandService commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService;
Instance = new CommandResetGodot(package, commandService);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="sender">Event sender.</param>
/// <param name="e">Event args.</param>
private void Execute(object sender, EventArgs e) {
ThreadHelper.ThrowIfNotOnUIThread();
var settingsManager = new ShellSettingsManager(package);
var config = settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings);
var ofd = new OpenFileDialog {
Filter = @"GoDot executable (.exe)|*.exe"
};
var result = ofd.ShowDialog(null);
if (result != DialogResult.OK) return;
config.SetString("External Tools", "GoDotExecutable", ofd.FileName);
config.SetString("External Tools", "GoDotPath", Path.GetDirectoryName(ofd.FileName));
}
}
}

View File

@@ -0,0 +1,132 @@
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.VisualStudio.Settings;
using Microsoft.VisualStudio.Shell.Settings;
using Task = System.Threading.Tasks.Task;
namespace GodotAddinVS.Commands {
/// <summary>
/// Command handler
/// </summary>
internal sealed class CommandRunGodot {
/// <summary>
/// Command ID.
/// </summary>
public const int CommandId = 256;
/// <summary>
/// Command menu group (command set GUID).
/// </summary>
public static readonly Guid CommandSet = new Guid("d71528ca-92b8-49bb-8655-8b478b495499");
/// <summary>
/// VS Package that provides this command, not null.
/// </summary>
private readonly AsyncPackage package;
/// <summary>
/// Initializes a new instance of the <see cref="CommandRunGodot"/> class.
/// Adds our command handlers for menu (commands must exist in the command table file)
/// </summary>
/// <param name="package">Owner package, not null.</param>
/// <param name="commandService">Command service to add command to, not null.</param>
private CommandRunGodot(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(Execute, menuCommandId);
commandService.AddCommand(menuItem);
}
/// <summary>
/// Gets the instance of the command.
/// </summary>
public static CommandRunGodot Instance {
get;
private set;
}
/// <summary>
/// Gets the service provider from the owner package.
/// </summary>
private Microsoft.VisualStudio.Shell.IAsyncServiceProvider ServiceProvider {
get {
return this.package;
}
}
/// <summary>
/// Initializes the singleton instance of the command.
/// </summary>
/// <param name="package">Owner package, not null.</param>
public static async Task InitializeAsync(AsyncPackage package) {
// Switch to the main thread - the call to AddCommand in CommandRunGodot's constructor requires
// the UI thread.
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);
var commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService;
Instance = new CommandRunGodot(package, commandService);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="sender">Event sender.</param>
/// <param name="e">Event args.</param>
private void Execute(object sender, EventArgs e) {
ThreadHelper.ThrowIfNotOnUIThread();
string goDotPath;
string goDotExecutable;
var settingsManager = new ShellSettingsManager(package);
var config = settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings);
if (!config.CollectionExists("External Tools")) {
config.CreateCollection("External Tools");
}
if (!config.PropertyExists("External Tools", "GoDotExecutable")) {
var ofd = new OpenFileDialog {
Filter = @"GoDot executable (.exe)|*.exe"
};
var result = ofd.ShowDialog(null);
if (result == DialogResult.OK) {
goDotExecutable = ofd.FileName;
goDotPath = Path.GetDirectoryName(goDotExecutable);
config.SetString("External Tools", "GoDotExecutable", goDotExecutable);
config.SetString("External Tools", "GoDotPath", goDotPath);
} else return;
} else {
goDotPath = config.GetString("External Tools", "GoDotPath");
goDotExecutable = config.GetString("External Tools", "GoDotExecutable");
}
if (string.IsNullOrEmpty(goDotExecutable)) {
MessageBox.Show("GoDot", "GoDot path not set");
return;
}
if (!File.Exists(goDotExecutable)) {
MessageBox.Show("GoDot", @$"GoDot does not exist at {goDotExecutable}");
return;
}
Process.Start(goDotExecutable);
}
}
}

View File

@@ -46,6 +46,8 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Compile Include="Commands\CommandResetGodot.cs" />
<Compile Include="Commands\CommandRunGodot.cs" />
<Compile Include="Debugging\GodotDebuggableProjectCfg.cs" />
<Compile Include="Debugging\GodotDebuggerSession.cs" />
<Compile Include="Debugging\GodotDebugTarget.cs" />
@@ -73,6 +75,11 @@
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Design" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Clide" Version="4.1.1" ExcludeAssets="runtime" />
@@ -109,6 +116,7 @@
<Name>GodotCompletionProviders</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<PropertyGroup>
<GetVsixSourceItemsDependsOn>$(GetVsixSourceItemsDependsOn);IncludeNuGetResolvedAssets</GetVsixSourceItemsDependsOn>
</PropertyGroup>

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
@@ -68,6 +68,10 @@ namespace GodotAddinVS
// Do any initialization that requires the UI thread after switching to the UI thread.
await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
// Commands
await Commands.CommandRunGodot.InitializeAsync(this);
await Commands.CommandResetGodot.InitializeAsync(this);
RegisterProjectFactory(new GodotFlavoredProjectFactory(this));
GodotSolutionEventsListener = new GodotSolutionEventsListener(this);

View File

@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<CommandTable language="en-us" xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable">
<Commands package="guidDebugTargetHandlerCmdSet">
<Buttons>
<Button guid="guidGodotDebugTargetCmdSet" id="PlayInEditorId" priority="0x1000" type="Button">
<Parent guid="guidDebugTargetHandlerCmdSet" id="DebugTargetMenuControllerGroup"/>
<Parent guid="guidDebugTargetHandlerCmdSet" id="DebugTargetMenuControllerGroup" />
<CommandFlag>DefaultInvisible</CommandFlag>
<CommandFlag>DynamicVisibility</CommandFlag>
<CommandFlag>TextChanges</CommandFlag>
@@ -13,7 +14,7 @@
</Button>
<Button guid="guidGodotDebugTargetCmdSet" id="LaunchId" priority="0x1000" type="Button">
<Parent guid="guidDebugTargetHandlerCmdSet" id="DebugTargetMenuControllerGroup"/>
<Parent guid="guidDebugTargetHandlerCmdSet" id="DebugTargetMenuControllerGroup" />
<CommandFlag>DefaultInvisible</CommandFlag>
<CommandFlag>DynamicVisibility</CommandFlag>
<CommandFlag>TextChanges</CommandFlag>
@@ -23,7 +24,7 @@
</Button>
<Button guid="guidGodotDebugTargetCmdSet" id="AttachId" priority="0x1000" type="Button">
<Parent guid="guidDebugTargetHandlerCmdSet" id="DebugTargetMenuControllerGroup"/>
<Parent guid="guidDebugTargetHandlerCmdSet" id="DebugTargetMenuControllerGroup" />
<CommandFlag>DefaultInvisible</CommandFlag>
<CommandFlag>DynamicVisibility</CommandFlag>
<CommandFlag>TextChanges</CommandFlag>
@@ -49,5 +50,81 @@
<IDSymbol name="LaunchId" value="0x8193" />
<IDSymbol name="AttachId" value="0x8194" />
</GuidSymbol>
<GuidSymbol value="{a90813d5-0da4-4587-8fbf-71f3d46492f1}" name="guidImages">
<IDSymbol name="bmpPic1" value="1" />
<IDSymbol name="bmpPic2" value="2" />
<IDSymbol name="bmpPicSearch" value="3" />
<IDSymbol name="bmpPicX" value="4" />
<IDSymbol name="bmpPicArrows" value="5" />
<IDSymbol name="bmpPicStrikethrough" value="6" />
</GuidSymbol>
<GuidSymbol name="guidSHLMainMenu" value="{d309f791-903f-11d0-9efc-00a0c911004f}">
<IDSymbol name="IDM_VS_MENU_EXTENSIONS" value="0x0091" />
</GuidSymbol>
<GuidSymbol value="{d71528ca-92b8-49bb-8655-8b478b495499}" name="guidGodotPackageCmdSet">
<IDSymbol value="4128" name="MyMenuGroup" />
<IDSymbol value="256" name="cmdidCommandRunGodot" />
<IDSymbol name="GoDotExtMenu" value="0x1100" />
</GuidSymbol>
<GuidSymbol value="{38009f93-330e-4875-ab88-e127fd85bb88}" name="guidGodotPackageCmdSet1">
<IDSymbol value="4128" name="MyMenuGroup" />
<IDSymbol value="256" name="cmdidCommandResetGodot" />
</GuidSymbol>
<GuidSymbol value="{75310202-7be7-4f12-a22e-8a8321229369}" name="guidImages1">
<IDSymbol name="bmpPic1" value="1" />
<IDSymbol name="bmpPic2" value="2" />
<IDSymbol name="bmpPicSearch" value="3" />
<IDSymbol name="bmpPicX" value="4" />
<IDSymbol name="bmpPicArrows" value="5" />
<IDSymbol name="bmpPicStrikethrough" value="6" />
</GuidSymbol>
</Symbols>
</CommandTable>
<Extern href="stdidcmd.h" />
<Extern href="vsshlids.h" />
<Commands package="guidGodotPackage">
<Menus>
<Menu guid="guidGodotPackageCmdSet" id="GoDotExtMenu" priority="0x0100" type="Menu">
<Parent guid="guidSHLMainMenu" id="IDG_VS_MM_TOOLSADDINS" />
<Strings>
<ButtonText>GoDot</ButtonText>
</Strings>
</Menu>
</Menus>
<Groups>
<Group guid="guidGodotPackageCmdSet" id="MyMenuGroup" priority="0x0600">
<Parent guid="guidGodotPackageCmdSet" id="GoDotExtMenu" />
</Group>
<Group guid="guidGodotPackageCmdSet1" id="MyMenuGroup" priority="0x0600">
<Parent guid="guidGodotPackageCmdSet" id="GoDotExtMenu" />
</Group>
</Groups>
<Buttons>
<Button guid="guidGodotPackageCmdSet" id="cmdidCommandRunGodot" priority="0x0100" type="Button">
<Parent guid="guidGodotPackageCmdSet" id="MyMenuGroup" />
<Strings>
<ButtonText>Launch GoDot</ButtonText>
</Strings>
</Button>
<Button guid="guidGodotPackageCmdSet1" id="cmdidCommandResetGodot" priority="0x0100" type="Button">
<Parent guid="guidGodotPackageCmdSet1" id="MyMenuGroup" />
<Strings>
<ButtonText>Configure</ButtonText>
</Strings>
</Button>
</Buttons>
</Commands>
</CommandTable>