diff --git a/Editor/ProcessRunner.cs b/Editor/ProcessRunner.cs index 72b18aa..a17dea5 100644 --- a/Editor/ProcessRunner.cs +++ b/Editor/ProcessRunner.cs @@ -8,6 +8,13 @@ using System.Diagnostics; using System.Text; using System.Threading; 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 { @@ -108,5 +115,85 @@ namespace Microsoft.Unity.VisualStudio.Editor sb?.Append(data); } + + public static string[] GetProcessWorkspaces(Process process) + { + if (process == null) + return null; + + try + { + var workspaces = new List(); + var userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + var cursorStoragePath = Path.Combine(userProfile, "AppData", "Roaming", "cursor", "User", "workspaceStorage"); + + 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; + } + } + } + + return workspaces.Distinct().ToArray(); + } + catch (Exception ex) + { + Debug.LogError($"[Cursor] Error getting workspace directory: {ex.Message}"); + return null; + } + } } } diff --git a/Editor/VisualStudioCursorInstallation.cs b/Editor/VisualStudioCursorInstallation.cs index 75813be..4f98681 100644 --- a/Editor/VisualStudioCursorInstallation.cs +++ b/Editor/VisualStudioCursorInstallation.cs @@ -12,6 +12,7 @@ using System.Text.RegularExpressions; using UnityEngine; using SimpleJSON; using IOPath = System.IO.Path; +using Debug = UnityEngine.Debug; namespace Microsoft.Unity.VisualStudio.Editor { internal class VisualStudioCursorInstallation : VisualStudioInstallation { @@ -448,6 +449,36 @@ namespace Microsoft.Unity.VisualStudio.Editor { } } + private Process FindRunningCursorWithSolution(string solutionPath) { + var directory = IOPath.GetDirectoryName(solutionPath); + var processes = Process.GetProcessesByName("cursor"); + + var normalizedTargetPath = directory.Replace('\\', '/').TrimEnd('/').ToLowerInvariant(); + + 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 (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; + } + public override bool Open(string path, int line, int column, string solution) { line = Math.Max(1, line); column = Math.Max(0, column); @@ -455,10 +486,26 @@ namespace Microsoft.Unity.VisualStudio.Editor { var directory = IOPath.GetDirectoryName(solution); var application = Path; - ProcessRunner.Start(string.IsNullOrEmpty(path) ? - ProcessStartInfoFor(application, $"\"{directory}\"") : - ProcessStartInfoFor(application, $"\"{directory}\" -g \"{path}\":{line}:{column}")); + 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 -g \"{path}\":{line}:{column}"; + + ProcessRunner.Start(ProcessStartInfoFor(application, newArgs)); return true; }