You've already forked com.unity.ide.cursor
mirror of
https://github.com/boxqkrtm/com.unity.ide.cursor.git
synced 2026-05-15 06:40:08 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd8ff1fb70 | ||
|
|
d17d7814f6 | ||
|
|
a97262d3f7 | ||
|
|
53e1baac3c | ||
|
|
8c1a4ac3e0 | ||
|
|
84578b3b24 | ||
|
|
38fecf55e4 | ||
|
|
284bebf8e7 | ||
|
|
ff1c40049a | ||
|
|
334a52e789 | ||
|
|
0a7001698c | ||
|
|
0a98b387a9 | ||
|
|
1228f59ed2 | ||
|
|
a24588a87a | ||
|
|
f1148f1205 | ||
|
|
cac0c13658 |
25
CHANGELOG.md
25
CHANGELOG.md
@@ -1,4 +1,23 @@
|
|||||||
# Code Editor Package for Visual Studio
|
# Code Editor Package for Cursor
|
||||||
|
|
||||||
|
## [2.0.28] - 2026-02-12
|
||||||
|
|
||||||
|
Integration:
|
||||||
|
|
||||||
|
- Performance optimization for opening files
|
||||||
|
- Fix CS1525: Use C# 7.3-compatible null-coalescing for Unity 2019.4
|
||||||
|
|
||||||
|
## [2.0.27] - 2025-11-02
|
||||||
|
|
||||||
|
Integration:
|
||||||
|
|
||||||
|
- Add Multiple or Single Cursor Instance Options
|
||||||
|
|
||||||
|
## [2.0.26] - 2025-11-02
|
||||||
|
|
||||||
|
Integration:
|
||||||
|
|
||||||
|
- Add workspace support
|
||||||
|
|
||||||
## [2.0.22] - 2023-10-03
|
## [2.0.22] - 2023-10-03
|
||||||
|
|
||||||
@@ -48,7 +67,7 @@ Project generation:
|
|||||||
Integration:
|
Integration:
|
||||||
|
|
||||||
- Performance improvements with `EditorApplication.update` callbacks.
|
- Performance improvements with `EditorApplication.update` callbacks.
|
||||||
|
|
||||||
Project generation:
|
Project generation:
|
||||||
|
|
||||||
- Add extra compiler options for analyzers and source generators.
|
- Add extra compiler options for analyzers and source generators.
|
||||||
@@ -71,7 +90,7 @@ Project generation:
|
|||||||
Integration:
|
Integration:
|
||||||
|
|
||||||
- Prevent ADB Refresh while being in safe-mode with a URP project
|
- Prevent ADB Refresh while being in safe-mode with a URP project
|
||||||
- Fixed an issue keeping the progress bar visible even after opening a script with Visual Studio.
|
- Fixed an issue keeping the progress bar visible even after opening a script with Visual Studio.
|
||||||
|
|
||||||
## [2.0.15] - 2022-03-21
|
## [2.0.15] - 2022-03-21
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,13 @@ using System.Diagnostics;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using Debug = UnityEngine.Debug;
|
||||||
|
using System.IO;
|
||||||
|
using SimpleJSON;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Microsoft.Unity.VisualStudio.Editor
|
namespace Microsoft.Unity.VisualStudio.Editor
|
||||||
{
|
{
|
||||||
@@ -108,5 +115,97 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
|||||||
|
|
||||||
sb?.Append(data);
|
sb?.Append(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string[] GetProcessWorkspaces(Process process)
|
||||||
|
{
|
||||||
|
if (process == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var workspaces = new List<string>();
|
||||||
|
var userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||||
|
string cursorStoragePath;
|
||||||
|
|
||||||
|
#if UNITY_EDITOR_OSX
|
||||||
|
cursorStoragePath = Path.Combine(userProfile, "Library", "Application Support", "cursor", "User", "workspaceStorage");
|
||||||
|
#elif UNITY_EDITOR_LINUX
|
||||||
|
cursorStoragePath = Path.Combine(userProfile, ".config", "Cursor", "User", "workspaceStorage");
|
||||||
|
#else
|
||||||
|
cursorStoragePath = Path.Combine(userProfile, "AppData", "Roaming", "cursor", "User", "workspaceStorage");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (Directory.Exists(cursorStoragePath))
|
||||||
|
{
|
||||||
|
foreach (var workspaceDir in Directory.GetDirectories(cursorStoragePath))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var workspaceStatePath = Path.Combine(workspaceDir, "workspace.json");
|
||||||
|
if (File.Exists(workspaceStatePath))
|
||||||
|
{
|
||||||
|
var content = File.ReadAllText(workspaceStatePath);
|
||||||
|
if (!string.IsNullOrEmpty(content))
|
||||||
|
{
|
||||||
|
var workspace = JSONNode.Parse(content);
|
||||||
|
if (workspace != null)
|
||||||
|
{
|
||||||
|
var folder = workspace["folder"];
|
||||||
|
if (folder != null && !string.IsNullOrEmpty(folder.Value))
|
||||||
|
{
|
||||||
|
var workspacePath = folder.Value;
|
||||||
|
if (workspacePath.StartsWith("file:///"))
|
||||||
|
{
|
||||||
|
workspacePath = Uri.UnescapeDataString(workspacePath.Substring(8));
|
||||||
|
workspaces.Add(workspacePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var windowStatePath = Path.Combine(workspaceDir, "window.json");
|
||||||
|
if (File.Exists(windowStatePath))
|
||||||
|
{
|
||||||
|
var content = File.ReadAllText(windowStatePath);
|
||||||
|
if (!string.IsNullOrEmpty(content))
|
||||||
|
{
|
||||||
|
var windowState = JSONNode.Parse(content);
|
||||||
|
if (windowState != null)
|
||||||
|
{
|
||||||
|
var workspace = windowState["workspace"];
|
||||||
|
if (workspace != null && !string.IsNullOrEmpty(workspace.Value))
|
||||||
|
{
|
||||||
|
var workspacePath = workspace.Value;
|
||||||
|
if (workspacePath.StartsWith("file:///"))
|
||||||
|
{
|
||||||
|
workspacePath = Uri.UnescapeDataString(workspacePath.Substring(8));
|
||||||
|
workspaces.Add(workspacePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[Cursor] Error reading workspace state file: {ex.Message}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[Cursor] Workspace storage directory not found: {cursorStoragePath}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return workspaces.Distinct().ToArray();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[Cursor] Error getting workspace directory: {ex.Message}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,26 +10,36 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
using SimpleJSON;
|
using SimpleJSON;
|
||||||
using IOPath = System.IO.Path;
|
using IOPath = System.IO.Path;
|
||||||
|
using Debug = UnityEngine.Debug;
|
||||||
|
|
||||||
namespace Microsoft.Unity.VisualStudio.Editor {
|
namespace Microsoft.Unity.VisualStudio.Editor
|
||||||
internal class VisualStudioCursorInstallation : VisualStudioInstallation {
|
{
|
||||||
|
internal class VisualStudioCursorInstallation : VisualStudioInstallation
|
||||||
|
{
|
||||||
private static readonly IGenerator _generator = new SdkStyleProjectGeneration();
|
private static readonly IGenerator _generator = new SdkStyleProjectGeneration();
|
||||||
|
internal const string ReuseExistingWindowKey = "cursor_reuse_existing_window";
|
||||||
|
|
||||||
public override bool SupportsAnalyzers {
|
public override bool SupportsAnalyzers
|
||||||
get {
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Version LatestLanguageVersionSupported {
|
public override Version LatestLanguageVersionSupported
|
||||||
get {
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
return new Version(11, 0);
|
return new Version(11, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetExtensionPath() {
|
private string GetExtensionPath()
|
||||||
|
{
|
||||||
var vscode = IsPrerelease ? ".vscode-insiders" : ".vscode";
|
var vscode = IsPrerelease ? ".vscode-insiders" : ".vscode";
|
||||||
var extensionsPath = IOPath.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), vscode, "extensions");
|
var extensionsPath = IOPath.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), vscode, "extensions");
|
||||||
if (!Directory.Exists(extensionsPath))
|
if (!Directory.Exists(extensionsPath))
|
||||||
@@ -41,7 +51,8 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string[] GetAnalyzers() {
|
public override string[] GetAnalyzers()
|
||||||
|
{
|
||||||
var vstuPath = GetExtensionPath();
|
var vstuPath = GetExtensionPath();
|
||||||
if (string.IsNullOrEmpty(vstuPath))
|
if (string.IsNullOrEmpty(vstuPath))
|
||||||
return Array.Empty<string>();
|
return Array.Empty<string>();
|
||||||
@@ -49,13 +60,16 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
return GetAnalyzers(vstuPath);
|
return GetAnalyzers(vstuPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IGenerator ProjectGenerator {
|
public override IGenerator ProjectGenerator
|
||||||
get {
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
return _generator;
|
return _generator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsCandidateForDiscovery(string path) {
|
private static bool IsCandidateForDiscovery(string path)
|
||||||
|
{
|
||||||
#if UNITY_EDITOR_OSX
|
#if UNITY_EDITOR_OSX
|
||||||
return Directory.Exists(path) && Regex.IsMatch(path, ".*Cursor.*.app$", RegexOptions.IgnoreCase);
|
return Directory.Exists(path) && Regex.IsMatch(path, ".*Cursor.*.app$", RegexOptions.IgnoreCase);
|
||||||
#elif UNITY_EDITOR_WIN
|
#elif UNITY_EDITOR_WIN
|
||||||
@@ -66,12 +80,14 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
internal class VisualStudioCodeManifest {
|
internal class VisualStudioCodeManifest
|
||||||
|
{
|
||||||
public string name;
|
public string name;
|
||||||
public string version;
|
public string version;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryDiscoverInstallation(string editorPath, out IVisualStudioInstallation installation) {
|
public static bool TryDiscoverInstallation(string editorPath, out IVisualStudioInstallation installation)
|
||||||
|
{
|
||||||
installation = null;
|
installation = null;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(editorPath))
|
if (string.IsNullOrEmpty(editorPath))
|
||||||
@@ -83,7 +99,8 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
Version version = null;
|
Version version = null;
|
||||||
var isPrerelease = false;
|
var isPrerelease = false;
|
||||||
|
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
var manifestBase = GetRealPath(editorPath);
|
var manifestBase = GetRealPath(editorPath);
|
||||||
|
|
||||||
#if UNITY_EDITOR_WIN
|
#if UNITY_EDITOR_WIN
|
||||||
@@ -103,17 +120,21 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
var manifestFullPath = IOPath.Combine(manifestBase, "resources", "app", "package.json");
|
var manifestFullPath = IOPath.Combine(manifestBase, "resources", "app", "package.json");
|
||||||
if (File.Exists(manifestFullPath)) {
|
if (File.Exists(manifestFullPath))
|
||||||
|
{
|
||||||
var manifest = JsonUtility.FromJson<VisualStudioCodeManifest>(File.ReadAllText(manifestFullPath));
|
var manifest = JsonUtility.FromJson<VisualStudioCodeManifest>(File.ReadAllText(manifestFullPath));
|
||||||
Version.TryParse(manifest.version.Split('-').First(), out version);
|
Version.TryParse(manifest.version.Split('-').First(), out version);
|
||||||
isPrerelease = manifest.version.ToLower().Contains("insider");
|
isPrerelease = manifest.version.ToLower().Contains("insider");
|
||||||
}
|
}
|
||||||
} catch (Exception) {
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
// do not fail if we are not able to retrieve the exact version number
|
// do not fail if we are not able to retrieve the exact version number
|
||||||
}
|
}
|
||||||
|
|
||||||
isPrerelease = isPrerelease || editorPath.ToLower().Contains("insider");
|
isPrerelease = isPrerelease || editorPath.ToLower().Contains("insider");
|
||||||
installation = new VisualStudioCursorInstallation() {
|
installation = new VisualStudioCursorInstallation()
|
||||||
|
{
|
||||||
IsPrerelease = isPrerelease,
|
IsPrerelease = isPrerelease,
|
||||||
Name = "Cursor" + (isPrerelease ? " - Insider" : string.Empty) + (version != null ? $" [{version.ToString(3)}]" : string.Empty),
|
Name = "Cursor" + (isPrerelease ? " - Insider" : string.Empty) + (version != null ? $" [{version.ToString(3)}]" : string.Empty),
|
||||||
Path = editorPath,
|
Path = editorPath,
|
||||||
@@ -123,7 +144,8 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<IVisualStudioInstallation> GetVisualStudioInstallations() {
|
public static IEnumerable<IVisualStudioInstallation> GetVisualStudioInstallations()
|
||||||
|
{
|
||||||
var candidates = new List<string>();
|
var candidates = new List<string>();
|
||||||
|
|
||||||
#if UNITY_EDITOR_WIN
|
#if UNITY_EDITOR_WIN
|
||||||
@@ -146,7 +168,8 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
candidates.AddRange(GetXdgCandidates());
|
candidates.AddRange(GetXdgCandidates());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
foreach (var candidate in candidates.Distinct()) {
|
foreach (var candidate in candidates.Distinct())
|
||||||
|
{
|
||||||
if (TryDiscoverInstallation(candidate, out var installation))
|
if (TryDiscoverInstallation(candidate, out var installation))
|
||||||
yield return installation;
|
yield return installation;
|
||||||
}
|
}
|
||||||
@@ -171,7 +194,7 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
var desktopFile = IOPath.Combine(dir, "applications/code.desktop");
|
var desktopFile = IOPath.Combine(dir, "applications/code.desktop");
|
||||||
if (!File.Exists(desktopFile))
|
if (!File.Exists(desktopFile))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var content = File.ReadAllText(desktopFile);
|
var content = File.ReadAllText(desktopFile);
|
||||||
match = DesktopFileExecEntry.Match(content);
|
match = DesktopFileExecEntry.Match(content);
|
||||||
}
|
}
|
||||||
@@ -201,13 +224,16 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
return new String(cbuf, 0, chars);
|
return new String(cbuf, 0, chars);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
internal static string GetRealPath(string path) {
|
internal static string GetRealPath(string path)
|
||||||
|
{
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public override void CreateExtraFiles(string projectDirectory) {
|
public override void CreateExtraFiles(string projectDirectory)
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
var vscodeDirectory = IOPath.Combine(projectDirectory.NormalizePathSeparators(), ".vscode");
|
var vscodeDirectory = IOPath.Combine(projectDirectory.NormalizePathSeparators(), ".vscode");
|
||||||
Directory.CreateDirectory(vscodeDirectory);
|
Directory.CreateDirectory(vscodeDirectory);
|
||||||
|
|
||||||
@@ -216,7 +242,9 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
CreateRecommendedExtensionsFile(vscodeDirectory, enablePatch);
|
CreateRecommendedExtensionsFile(vscodeDirectory, enablePatch);
|
||||||
CreateSettingsFile(vscodeDirectory, enablePatch);
|
CreateSettingsFile(vscodeDirectory, enablePatch);
|
||||||
CreateLaunchFile(vscodeDirectory, enablePatch);
|
CreateLaunchFile(vscodeDirectory, enablePatch);
|
||||||
} catch (IOException) {
|
}
|
||||||
|
catch (IOException)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,9 +259,11 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
]
|
]
|
||||||
}";
|
}";
|
||||||
|
|
||||||
private static void CreateLaunchFile(string vscodeDirectory, bool enablePatch) {
|
private static void CreateLaunchFile(string vscodeDirectory, bool enablePatch)
|
||||||
|
{
|
||||||
var launchFile = IOPath.Combine(vscodeDirectory, "launch.json");
|
var launchFile = IOPath.Combine(vscodeDirectory, "launch.json");
|
||||||
if (File.Exists(launchFile)) {
|
if (File.Exists(launchFile))
|
||||||
|
{
|
||||||
if (enablePatch)
|
if (enablePatch)
|
||||||
PatchLaunchFile(launchFile);
|
PatchLaunchFile(launchFile);
|
||||||
|
|
||||||
@@ -243,8 +273,10 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
File.WriteAllText(launchFile, DefaultLaunchFileContent);
|
File.WriteAllText(launchFile, DefaultLaunchFileContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PatchLaunchFile(string launchFile) {
|
private static void PatchLaunchFile(string launchFile)
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
const string configurationsKey = "configurations";
|
const string configurationsKey = "configurations";
|
||||||
const string typeKey = "type";
|
const string typeKey = "type";
|
||||||
|
|
||||||
@@ -252,7 +284,8 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
var launch = JSONNode.Parse(content);
|
var launch = JSONNode.Parse(content);
|
||||||
|
|
||||||
var configurations = launch[configurationsKey] as JSONArray;
|
var configurations = launch[configurationsKey] as JSONArray;
|
||||||
if (configurations == null) {
|
if (configurations == null)
|
||||||
|
{
|
||||||
configurations = new JSONArray();
|
configurations = new JSONArray();
|
||||||
launch.Add(configurationsKey, configurations);
|
launch.Add(configurationsKey, configurations);
|
||||||
}
|
}
|
||||||
@@ -264,14 +297,18 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
configurations.Add(defaultContent[configurationsKey][0]);
|
configurations.Add(defaultContent[configurationsKey][0]);
|
||||||
|
|
||||||
WriteAllTextFromJObject(launchFile, launch);
|
WriteAllTextFromJObject(launchFile, launch);
|
||||||
} catch (Exception) {
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
// do not fail if we cannot patch the launch.json file
|
// do not fail if we cannot patch the launch.json file
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateSettingsFile(string vscodeDirectory, bool enablePatch) {
|
private void CreateSettingsFile(string vscodeDirectory, bool enablePatch)
|
||||||
|
{
|
||||||
var settingsFile = IOPath.Combine(vscodeDirectory, "settings.json");
|
var settingsFile = IOPath.Combine(vscodeDirectory, "settings.json");
|
||||||
if (File.Exists(settingsFile)) {
|
if (File.Exists(settingsFile))
|
||||||
|
{
|
||||||
if (enablePatch)
|
if (enablePatch)
|
||||||
PatchSettingsFile(settingsFile);
|
PatchSettingsFile(settingsFile);
|
||||||
|
|
||||||
@@ -344,8 +381,10 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
File.WriteAllText(settingsFile, content);
|
File.WriteAllText(settingsFile, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PatchSettingsFile(string settingsFile) {
|
private void PatchSettingsFile(string settingsFile)
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
const string excludesKey = "files.exclude";
|
const string excludesKey = "files.exclude";
|
||||||
const string solutionKey = "dotnet.defaultSolution";
|
const string solutionKey = "dotnet.defaultSolution";
|
||||||
|
|
||||||
@@ -360,7 +399,8 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
var patched = false;
|
var patched = false;
|
||||||
|
|
||||||
// Remove files.exclude for solution+project files in the project root
|
// Remove files.exclude for solution+project files in the project root
|
||||||
foreach (var exclude in excludes) {
|
foreach (var exclude in excludes)
|
||||||
|
{
|
||||||
if (!bool.TryParse(exclude.Value, out var exc) || !exc)
|
if (!bool.TryParse(exclude.Value, out var exc) || !exc)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -379,7 +419,8 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
// Check default solution
|
// Check default solution
|
||||||
var defaultSolution = settings[solutionKey];
|
var defaultSolution = settings[solutionKey];
|
||||||
var solutionFile = IOPath.GetFileName(ProjectGenerator.SolutionFile());
|
var solutionFile = IOPath.GetFileName(ProjectGenerator.SolutionFile());
|
||||||
if (defaultSolution == null || defaultSolution.Value != solutionFile) {
|
if (defaultSolution == null || defaultSolution.Value != solutionFile)
|
||||||
|
{
|
||||||
settings[solutionKey] = solutionFile;
|
settings[solutionKey] = solutionFile;
|
||||||
patched = true;
|
patched = true;
|
||||||
}
|
}
|
||||||
@@ -391,7 +432,9 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
excludes.Remove(patch);
|
excludes.Remove(patch);
|
||||||
|
|
||||||
WriteAllTextFromJObject(settingsFile, settings);
|
WriteAllTextFromJObject(settingsFile, settings);
|
||||||
} catch (Exception) {
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
// do not fail if we cannot patch the settings.json file
|
// do not fail if we cannot patch the settings.json file
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -404,10 +447,12 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
}
|
}
|
||||||
";
|
";
|
||||||
|
|
||||||
private static void CreateRecommendedExtensionsFile(string vscodeDirectory, bool enablePatch) {
|
private static void CreateRecommendedExtensionsFile(string vscodeDirectory, bool enablePatch)
|
||||||
|
{
|
||||||
// see https://tattoocoder.com/recommending-vscode-extensions-within-your-open-source-projects/
|
// see https://tattoocoder.com/recommending-vscode-extensions-within-your-open-source-projects/
|
||||||
var extensionFile = IOPath.Combine(vscodeDirectory, "extensions.json");
|
var extensionFile = IOPath.Combine(vscodeDirectory, "extensions.json");
|
||||||
if (File.Exists(extensionFile)) {
|
if (File.Exists(extensionFile))
|
||||||
|
{
|
||||||
if (enablePatch)
|
if (enablePatch)
|
||||||
PatchRecommendedExtensionsFile(extensionFile);
|
PatchRecommendedExtensionsFile(extensionFile);
|
||||||
|
|
||||||
@@ -417,15 +462,18 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
File.WriteAllText(extensionFile, DefaultRecommendedExtensionsContent);
|
File.WriteAllText(extensionFile, DefaultRecommendedExtensionsContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PatchRecommendedExtensionsFile(string extensionFile) {
|
private static void PatchRecommendedExtensionsFile(string extensionFile)
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
const string recommendationsKey = "recommendations";
|
const string recommendationsKey = "recommendations";
|
||||||
|
|
||||||
var content = File.ReadAllText(extensionFile);
|
var content = File.ReadAllText(extensionFile);
|
||||||
var extensions = JSONNode.Parse(content);
|
var extensions = JSONNode.Parse(content);
|
||||||
|
|
||||||
var recommendations = extensions[recommendationsKey] as JSONArray;
|
var recommendations = extensions[recommendationsKey] as JSONArray;
|
||||||
if (recommendations == null) {
|
if (recommendations == null)
|
||||||
|
{
|
||||||
recommendations = new JSONArray();
|
recommendations = new JSONArray();
|
||||||
extensions.Add(recommendationsKey, recommendations);
|
extensions.Add(recommendationsKey, recommendations);
|
||||||
}
|
}
|
||||||
@@ -435,34 +483,146 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
|
|
||||||
recommendations.Add(MicrosoftUnityExtensionId);
|
recommendations.Add(MicrosoftUnityExtensionId);
|
||||||
WriteAllTextFromJObject(extensionFile, extensions);
|
WriteAllTextFromJObject(extensionFile, extensions);
|
||||||
} catch (Exception) {
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
// do not fail if we cannot patch the extensions.json file
|
// do not fail if we cannot patch the extensions.json file
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteAllTextFromJObject(string file, JSONNode node) {
|
private static void WriteAllTextFromJObject(string file, JSONNode node)
|
||||||
|
{
|
||||||
using (var fs = File.Open(file, FileMode.Create))
|
using (var fs = File.Open(file, FileMode.Create))
|
||||||
using (var sw = new StreamWriter(fs)) {
|
using (var sw = new StreamWriter(fs))
|
||||||
|
{
|
||||||
// Keep formatting/indent in sync with default contents
|
// Keep formatting/indent in sync with default contents
|
||||||
sw.Write(node.ToString(aIndent: 4));
|
sw.Write(node.ToString(aIndent: 4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Open(string path, int line, int column, string solution) {
|
private Process FindRunningCursorWithSolution(string solutionPath)
|
||||||
|
{
|
||||||
|
var normalizedTargetPath = solutionPath.Replace('\\', '/').TrimEnd('/').ToLowerInvariant();
|
||||||
|
|
||||||
|
#if UNITY_EDITOR_WIN
|
||||||
|
// Keep as is for Windows platform since path already includes drive letter
|
||||||
|
#else
|
||||||
|
// Ensure path starts with / for macOS and Linux platforms
|
||||||
|
if (!normalizedTargetPath.StartsWith("/"))
|
||||||
|
{
|
||||||
|
normalizedTargetPath = "/" + normalizedTargetPath;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var processes = new List<Process>();
|
||||||
|
|
||||||
|
// Get process name list based on different operating systems
|
||||||
|
#if UNITY_EDITOR_OSX
|
||||||
|
processes.AddRange(Process.GetProcessesByName("Cursor"));
|
||||||
|
processes.AddRange(Process.GetProcessesByName("Cursor Helper"));
|
||||||
|
#elif UNITY_EDITOR_LINUX
|
||||||
|
processes.AddRange(Process.GetProcessesByName("cursor"));
|
||||||
|
processes.AddRange(Process.GetProcessesByName("Cursor"));
|
||||||
|
#else
|
||||||
|
processes.AddRange(Process.GetProcessesByName("cursor"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
foreach (var process in processes)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var workspaces = ProcessRunner.GetProcessWorkspaces(process);
|
||||||
|
if (workspaces != null && workspaces.Length > 0)
|
||||||
|
{
|
||||||
|
foreach (var workspace in workspaces)
|
||||||
|
{
|
||||||
|
var normalizedWorkspaceDir = workspace.Replace('\\', '/').TrimEnd('/').ToLowerInvariant();
|
||||||
|
|
||||||
|
#if UNITY_EDITOR_WIN
|
||||||
|
// Keep as is for Windows platform
|
||||||
|
#else
|
||||||
|
// Ensure path starts with / for macOS and Linux platforms
|
||||||
|
if (!normalizedWorkspaceDir.StartsWith("/"))
|
||||||
|
{
|
||||||
|
normalizedWorkspaceDir = "/" + normalizedWorkspaceDir;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (string.Equals(normalizedWorkspaceDir, normalizedTargetPath, StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
normalizedTargetPath.StartsWith(normalizedWorkspaceDir + "/", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
normalizedWorkspaceDir.StartsWith(normalizedTargetPath + "/", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return process;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[Cursor] Error checking process: {ex}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string TryFindWorkspace(string directory)
|
||||||
|
{
|
||||||
|
var files = Directory.GetFiles(directory, "*.code-workspace", SearchOption.TopDirectoryOnly);
|
||||||
|
if (files.Length == 0 || files.Length > 1)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return files[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Open(string path, int line, int column, string solution)
|
||||||
|
{
|
||||||
line = Math.Max(1, line);
|
line = Math.Max(1, line);
|
||||||
column = Math.Max(0, column);
|
column = Math.Max(0, column);
|
||||||
|
|
||||||
var directory = IOPath.GetDirectoryName(solution);
|
var directory = IOPath.GetDirectoryName(solution);
|
||||||
var application = Path;
|
var application = Path;
|
||||||
|
|
||||||
ProcessRunner.Start(string.IsNullOrEmpty(path) ?
|
var workspace = TryFindWorkspace(directory);
|
||||||
ProcessStartInfoFor(application, $"\"{directory}\"") :
|
// Use version-compatible null-coalescing for Unity 2019.4 (C# 7.3) support
|
||||||
ProcessStartInfoFor(application, $"\"{directory}\" -g \"{path}\":{line}:{column}"));
|
#if UNITY_2020_2_OR_NEWER
|
||||||
|
workspace ??= directory;
|
||||||
|
#else
|
||||||
|
workspace = workspace ?? directory;
|
||||||
|
#endif
|
||||||
|
directory = workspace;
|
||||||
|
|
||||||
|
if (EditorPrefs.GetBool(ReuseExistingWindowKey, false))
|
||||||
|
{
|
||||||
|
var existingProcess = FindRunningCursorWithSolution(directory);
|
||||||
|
if (existingProcess != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var args = string.IsNullOrEmpty(path) ?
|
||||||
|
$"--reuse-window \"{directory}\"" :
|
||||||
|
$"--reuse-window -g \"{path}\":{line}:{column}";
|
||||||
|
|
||||||
|
ProcessRunner.Start(ProcessStartInfoFor(application, args));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[Cursor] Error using existing instance: {ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var newArgs = string.IsNullOrEmpty(path) ?
|
||||||
|
$"--new-window \"{directory}\"" :
|
||||||
|
$"--new-window \"{directory}\" -g \"{path}\":{line}:{column}";
|
||||||
|
|
||||||
|
ProcessRunner.Start(ProcessStartInfoFor(application, newArgs));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProcessStartInfo ProcessStartInfoFor(string application, string arguments) {
|
private static ProcessStartInfo ProcessStartInfoFor(string application, string arguments)
|
||||||
|
{
|
||||||
#if UNITY_EDITOR_OSX
|
#if UNITY_EDITOR_OSX
|
||||||
// wrap with built-in OSX open feature
|
// wrap with built-in OSX open feature
|
||||||
arguments = $"-n \"{application}\" --args {arguments}";
|
arguments = $"-n \"{application}\" --args {arguments}";
|
||||||
@@ -473,7 +633,8 @@ namespace Microsoft.Unity.VisualStudio.Editor {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Initialize() {
|
public static void Initialize()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,11 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
|||||||
[InitializeOnLoadMethod]
|
[InitializeOnLoadMethod]
|
||||||
static void LegacyVisualStudioCodePackageDisabler()
|
static void LegacyVisualStudioCodePackageDisabler()
|
||||||
{
|
{
|
||||||
// disable legacy Visual Studio Code packages
|
#if UNITY_2021_1_OR_NEWER
|
||||||
var editor = CodeEditor.Editor.GetCodeEditorForPath("code.cmd");
|
var editor = CodeEditor.Editor.GetCodeEditorForPath("code.cmd");
|
||||||
|
#else
|
||||||
|
var editor = CodeEditor.CurrentEditor;
|
||||||
|
#endif
|
||||||
if (editor == null)
|
if (editor == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -132,6 +135,16 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
|||||||
GUILayout.Label($"<size=10><color=grey>{package.displayName} v{package.version} enabled</color></size>", style);
|
GUILayout.Label($"<size=10><color=grey>{package.displayName} v{package.version} enabled</color></size>", style);
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
if (installation is VisualStudioCursorInstallation)
|
||||||
|
{
|
||||||
|
var reuseWindow = EditorPrefs.GetBool(VisualStudioCursorInstallation.ReuseExistingWindowKey, false);
|
||||||
|
var newReuseWindow = EditorGUILayout.Toggle(new GUIContent("Reuse existing Cursor window", "When enabled, opens files in an existing Cursor window if found. When disabled, always opens a new window."), reuseWindow);
|
||||||
|
if (newReuseWindow != reuseWindow)
|
||||||
|
EditorPrefs.SetBool(VisualStudioCursorInstallation.ReuseExistingWindowKey, newReuseWindow);
|
||||||
|
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
}
|
||||||
|
|
||||||
EditorGUILayout.LabelField("Generate .csproj files for:");
|
EditorGUILayout.LabelField("Generate .csproj files for:");
|
||||||
EditorGUI.indentLevel++;
|
EditorGUI.indentLevel++;
|
||||||
SettingsButton(ProjectGenerationFlag.Embedded, "Embedded packages", "", installation);
|
SettingsButton(ProjectGenerationFlag.Embedded, "Embedded packages", "", installation);
|
||||||
@@ -216,7 +229,9 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
|||||||
{
|
{
|
||||||
var editorPath = CodeEditor.CurrentEditorInstallation;
|
var editorPath = CodeEditor.CurrentEditorInstallation;
|
||||||
|
|
||||||
if (!Discovery.TryDiscoverInstallation(editorPath, out var installation)) {
|
// Performance optimization: Use cached installation lookup instead of discovering every time
|
||||||
|
if (!TryGetVisualStudioInstallationForPath(editorPath, lookupDiscoveredInstallations: true, out var installation))
|
||||||
|
{
|
||||||
Debug.LogWarning($"Visual Studio executable {editorPath} is not found. Please change your settings in Edit > Preferences > External Tools.");
|
Debug.LogWarning($"Visual Studio executable {editorPath} is not found. Please change your settings in Edit > Preferences > External Tools.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -228,7 +243,8 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
|||||||
if (!IsProjectGeneratedFor(path, generator, out var missingFlag))
|
if (!IsProjectGeneratedFor(path, generator, out var missingFlag))
|
||||||
Debug.LogWarning($"You are trying to open {path} outside a generated project. This might cause problems with IntelliSense and debugging. To avoid this, you can change your .csproj preferences in Edit > Preferences > External Tools and enable {GetProjectGenerationFlagDescription(missingFlag)} generation.");
|
Debug.LogWarning($"You are trying to open {path} outside a generated project. This might cause problems with IntelliSense and debugging. To avoid this, you can change your .csproj preferences in Edit > Preferences > External Tools and enable {GetProjectGenerationFlagDescription(missingFlag)} generation.");
|
||||||
|
|
||||||
var solution = GetOrGenerateSolutionFile(generator);
|
// Performance optimization: Only sync if solution doesn't exist
|
||||||
|
var solution = GetOrGenerateSolutionFileIfNeeded(generator);
|
||||||
return installation.Open(path, line, column, solution);
|
return installation.Open(path, line, column, solution);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,5 +313,15 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
|||||||
generator.Sync();
|
generator.Sync();
|
||||||
return generator.SolutionFile();
|
return generator.SolutionFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Performance optimization: Only sync if solution file doesn't exist
|
||||||
|
private static string GetOrGenerateSolutionFileIfNeeded(IGenerator generator)
|
||||||
|
{
|
||||||
|
if (!generator.HasSolutionBeenGenerated())
|
||||||
|
{
|
||||||
|
generator.Sync();
|
||||||
|
}
|
||||||
|
return generator.SolutionFile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
19
README.md
19
README.md
@@ -1,8 +1,13 @@
|
|||||||
# How to install
|
## How to install
|
||||||
<br>
|
- Unity -> Window -> Package Manager
|
||||||
- Unity->Window->Package Manager<br>
|
- Click "+" at the top left corner
|
||||||
- Click "+" left corner<br>
|
- Add package from git URL
|
||||||
- Add package from git URL<br>
|
- Insert `https://github.com/boxqkrtm/com.unity.ide.cursor.git`
|
||||||
- Insert <code>https://github.com/boxqkrtm/com.unity.ide.cursor.git</code><br>
|
- Add
|
||||||
- Add<br>
|
|
||||||
- Done
|
- Done
|
||||||
|
|
||||||
|
> **Important Notice for Users Updating from Older Versions**
|
||||||
|
> Starting from version **v2.0.24**, the package name has been changed from
|
||||||
|
> `com.unity.ide.cursor` to `com.boxqkrtm.ide.cursor` to prevent potential issues with Unity regarding attribution.
|
||||||
|
> Violating these attribution rules may trigger warnings in Unity.
|
||||||
|
> If you experience errors during the update, please remove the existing package before reinstalling the new one to avoid conflicts.
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "com.unity.ide.cursor",
|
"name": "com.boxqkrtm.ide.cursor",
|
||||||
"displayName": "Cursor Editor",
|
"displayName": "Cursor Editor",
|
||||||
"description": "Cursor editor integration for supporting Cursor as code editor for unity. Adds support for generating csproj files for intellisense purposes, auto discovery of installations, etc.",
|
"description": "Cursor editor integration for supporting Cursor as code editor for unity. Adds support for generating csproj files for intellisense purposes, auto discovery of installations, etc.",
|
||||||
"version": "2.0.23",
|
"version": "2.0.28",
|
||||||
"unity": "2019.4",
|
"unity": "2019.4",
|
||||||
"unityRelease": "25f1",
|
"unityRelease": "25f1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"com.unity.test-framework": "1.1.9"
|
"com.unity.test-framework": "1.1.9"
|
||||||
},
|
},
|
||||||
"_upm": {
|
"_upm": {
|
||||||
"changelog": "Integration:\n\n- Add support for Cursor"
|
"changelog": "Integration:\n\n- Add Multiple or Single Cursor Instance Options"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user