Skip to content

Instantly share code, notes, and snippets.

@AldeRoberge
Last active February 7, 2025 18:47
Show Gist options
  • Save AldeRoberge/79478dbeb268fe78f1a335539be33910 to your computer and use it in GitHub Desktop.
Save AldeRoberge/79478dbeb268fe78f1a335539be33910 to your computer and use it in GitHub Desktop.
Right click Project folder to open in terminal. Supports Linux, Mac and Windows.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using UnityEditor;
using UnityEngine;
using Debug = UnityEngine.Debug;
namespace ADG.Scripts.Editor
{
public static class OpenInTerminal
{
private const string MENU_ITEM_PATH = "Assets/Open in Terminal/";
private const int MENU_PRIORITY = 1000;
private static readonly Dictionary<string, TerminalInfo> WindowsTerminals = new()
{
["cmd"] = new TerminalInfo("Command Prompt", "cmd.exe", "/K cd /d \"{0}\""),
["cmd_admin"] = new TerminalInfo("Command Prompt (Admin)", "cmd.exe", "/K cd /d \"{0}\"", true),
["powershell"] = new TerminalInfo("PowerShell", "powershell.exe", "-NoExit -Command Set-Location -Path \"{0}\""),
["powershell_admin"] = new TerminalInfo("PowerShell (Admin)", "powershell.exe", "-NoExit -Command Set-Location -Path \"{0}\"", true),
["wt"] = new TerminalInfo("Windows Terminal", "wt.exe", "-d \"{0}\""),
};
private static readonly Dictionary<string, TerminalInfo> MacTerminals = new()
{
["terminal"] = new TerminalInfo("Terminal", "open", "-a Terminal \"{0}\""),
["iterm"] = new TerminalInfo("iTerm", "open", "-a iTerm \"{0}\""),
};
private static readonly Dictionary<string, TerminalInfo> LinuxTerminals = new()
{
["gnome-terminal"] = new TerminalInfo("GNOME Terminal", "gnome-terminal", "--working-directory=\"{0}\""),
["konsole"] = new TerminalInfo("Konsole", "konsole", "--workdir \"{0}\""),
["xterm"] = new TerminalInfo("XTerm", "xterm", "-e 'cd \"{0}\" && bash'"),
};
private static Dictionary<string, TerminalInfo> CurrentPlatformTerminals
{
get
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return WindowsTerminals;
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return MacTerminals;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return LinuxTerminals;
Console.WriteLine($"Unsupported platform : {RuntimeInformation.OSDescription}");
return new Dictionary<string, TerminalInfo>();
}
}
private static string LastUsedTerminal
{
get => EditorPrefs.GetString("OpenInTerminal_LastUsed", GetDefaultTerminal());
set => EditorPrefs.SetString("OpenInTerminal_LastUsed", value);
}
#region Menu Items
[MenuItem(MENU_ITEM_PATH + "Default Terminal %&t", false, MENU_PRIORITY)]
private static void OpenInDefaultTerminal()
{
OpenTerminalAtPath(GetSelectedPath(), LastUsedTerminal);
}
// Windows-specific menu items
#if UNITY_EDITOR_WIN
[MenuItem(MENU_ITEM_PATH + "Command Prompt", false, MENU_PRIORITY + 1)]
private static void OpenInCmd() => OpenTerminalAtPath(GetSelectedPath(), "cmd");
[MenuItem(MENU_ITEM_PATH + "Command Prompt (Admin)", false, MENU_PRIORITY + 2)]
private static void OpenInCmdAdmin() => OpenTerminalAtPath(GetSelectedPath(), "cmd_admin");
[MenuItem(MENU_ITEM_PATH + "PowerShell", false, MENU_PRIORITY + 3)]
private static void OpenInPowerShell() => OpenTerminalAtPath(GetSelectedPath(), "powershell");
[MenuItem(MENU_ITEM_PATH + "PowerShell (Admin)", false, MENU_PRIORITY + 4)]
private static void OpenInPowerShellAdmin() => OpenTerminalAtPath(GetSelectedPath(), "powershell_admin");
[MenuItem(MENU_ITEM_PATH + "Windows Terminal", false, MENU_PRIORITY + 5)]
private static void OpenInWindowsTerminal() => OpenTerminalAtPath(GetSelectedPath(), "wt");
#endif
// macOS-specific menu items
#if UNITY_EDITOR_OSX
[MenuItem(MENU_ITEM_PATH + "Terminal", false, MENU_PRIORITY + 1)]
private static void OpenInMacTerminal() => OpenTerminalAtPath(GetSelectedPath(), "terminal");
[MenuItem(MENU_ITEM_PATH + "iTerm", false, MENU_PRIORITY + 2)]
private static void OpenInITerm() => OpenTerminalAtPath(GetSelectedPath(), "iterm");
#endif
// Linux-specific menu items
#if UNITY_EDITOR_LINUX
[MenuItem(MENU_ITEM_PATH + "GNOME Terminal", false, MENU_PRIORITY + 1)]
private static void OpenInGnomeTerminal() => OpenTerminalAtPath(GetSelectedPath(), "gnome-terminal");
[MenuItem(MENU_ITEM_PATH + "Konsole", false, MENU_PRIORITY + 2)]
private static void OpenInKonsole() => OpenTerminalAtPath(GetSelectedPath(), "konsole");
[MenuItem(MENU_ITEM_PATH + "XTerm", false, MENU_PRIORITY + 3)]
private static void OpenInXTerm() => OpenTerminalAtPath(GetSelectedPath(), "xterm");
#endif
// Validation
[MenuItem(MENU_ITEM_PATH + "Default Terminal %&t", true)]
#if UNITY_EDITOR_WIN
[MenuItem(MENU_ITEM_PATH + "Command Prompt", true)]
[MenuItem(MENU_ITEM_PATH + "Command Prompt (Admin)", true)]
[MenuItem(MENU_ITEM_PATH + "PowerShell", true)]
[MenuItem(MENU_ITEM_PATH + "PowerShell (Admin)", true)]
[MenuItem(MENU_ITEM_PATH + "Windows Terminal", true)]
#endif
#if UNITY_EDITOR_OSX
[MenuItem(MENU_ITEM_PATH + "Terminal", true)]
[MenuItem(MENU_ITEM_PATH + "iTerm", true)]
#endif
#if UNITY_EDITOR_LINUX
[MenuItem(MENU_ITEM_PATH + "GNOME Terminal", true)]
[MenuItem(MENU_ITEM_PATH + "Konsole", true)]
[MenuItem(MENU_ITEM_PATH + "XTerm", true)]
#endif
private static bool ValidateOpenTerminal()
{
return !string.IsNullOrEmpty(GetSelectedPath());
}
#endregion
#region Path Handling
private static string GetSelectedPath()
{
string path = AssetDatabase.GetAssetPath(Selection.activeObject);
if (string.IsNullOrEmpty(path))
{
return Application.dataPath;
}
// Convert to full path
path = Path.GetFullPath(path);
// If it's a file, get its directory
if (File.Exists(path))
{
path = Path.GetDirectoryName(path);
}
return path;
}
#endregion
#region Terminal Handling
private static void OpenTerminalAtPath(string path, string terminalKey)
{
if (string.IsNullOrEmpty(path))
{
Debug.LogError("Invalid path specified.");
return;
}
var terminals = CurrentPlatformTerminals;
if (!terminals.TryGetValue(terminalKey, out var terminalInfo))
{
Debug.LogError($"Unsupported terminal: {terminalKey}");
return;
}
try
{
var psi = new ProcessStartInfo
{
FileName = terminalInfo.ExecutablePath,
Arguments = string.Format(terminalInfo.ArgumentsFormat, path),
UseShellExecute = true,
CreateNoWindow = false
};
if (terminalInfo.RunAsAdmin)
{
psi.Verb = "runas";
}
Process.Start(psi);
LastUsedTerminal = terminalKey;
}
catch (Exception ex)
{
Debug.LogError($"Failed to open terminal: {ex.Message}");
}
}
private static string GetDefaultTerminal()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return "wt";
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return "terminal";
return "gnome-terminal";
}
#endregion
private class TerminalInfo
{
public string DisplayName { get; }
public string ExecutablePath { get; }
public string ArgumentsFormat { get; }
public bool RunAsAdmin { get; }
public TerminalInfo(string displayName, string executablePath, string argumentsFormat, bool runAsAdmin = false)
{
DisplayName = displayName;
ExecutablePath = executablePath;
ArgumentsFormat = argumentsFormat;
RunAsAdmin = runAsAdmin;
}
}
}
}
@AldeRoberge
Copy link
Author

image

Was written by Claude 3.5 Sonnet after some proompting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment