diff --git a/Source/Editor/Modules/SourceCodeEditing/DefaultSourceCodeEditor.cs b/Source/Editor/Modules/SourceCodeEditing/DefaultSourceCodeEditor.cs index 074dade6a..fd0d45317 100644 --- a/Source/Editor/Modules/SourceCodeEditing/DefaultSourceCodeEditor.cs +++ b/Source/Editor/Modules/SourceCodeEditing/DefaultSourceCodeEditor.cs @@ -40,10 +40,11 @@ namespace FlaxEditor.Modules.SourceCodeEditing var codeEditing = Editor.Instance.CodeEditing; var vsCode = codeEditing.GetInBuildEditor(CodeEditorTypes.VSCode); var rider = codeEditing.GetInBuildEditor(CodeEditorTypes.Rider); + var zed = codeEditing.GetInBuildEditor(CodeEditorTypes.Zed); #if PLATFORM_WINDOW // Favor the newest Visual Studio - for (int i = (int)CodeEditorTypes.VS2019; i >= (int)CodeEditorTypes.VS2008; i--) + for (int i = (int)CodeEditorTypes.VS2026; i >= (int)CodeEditorTypes.VS2008; i--) { var visualStudio = codeEditing.GetInBuildEditor((CodeEditorTypes)i); if (visualStudio != null) @@ -66,6 +67,8 @@ namespace FlaxEditor.Modules.SourceCodeEditing _currentEditor = vsCode; else if (rider != null) _currentEditor = rider; + else if (zed != null) + _currentEditor = zed; else _currentEditor = codeEditing.GetInBuildEditor(CodeEditorTypes.SystemDefault); } diff --git a/Source/Editor/Modules/SourceCodeEditing/InBuildSourceCodeEditor.cs b/Source/Editor/Modules/SourceCodeEditing/InBuildSourceCodeEditor.cs index a2a333805..2bad95af8 100644 --- a/Source/Editor/Modules/SourceCodeEditing/InBuildSourceCodeEditor.cs +++ b/Source/Editor/Modules/SourceCodeEditing/InBuildSourceCodeEditor.cs @@ -66,6 +66,9 @@ namespace FlaxEditor.Modules.SourceCodeEditing case CodeEditorTypes.Rider: Name = "Rider"; break; + case CodeEditorTypes.Zed: + Name = "Zed"; + break; default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } } @@ -83,6 +86,7 @@ namespace FlaxEditor.Modules.SourceCodeEditing case CodeEditorTypes.VSCodeInsiders: case CodeEditorTypes.VSCode: return "-vscode -vs2022"; case CodeEditorTypes.Rider: return "-vs2022"; + case CodeEditorTypes.Zed: return "-vs2022"; default: return null; } } diff --git a/Source/Editor/Scripting/CodeEditor.cpp b/Source/Editor/Scripting/CodeEditor.cpp index b372da189..267b110e5 100644 --- a/Source/Editor/Scripting/CodeEditor.cpp +++ b/Source/Editor/Scripting/CodeEditor.cpp @@ -6,6 +6,7 @@ #include "ScriptsBuilder.h" #include "CodeEditors/VisualStudioCodeEditor.h" #include "CodeEditors/RiderCodeEditor.h" +#include "CodeEditors/ZedEditor.h" #if USE_VISUAL_STUDIO_DTE #include "CodeEditors/VisualStudio/VisualStudioEditor.h" #endif @@ -241,6 +242,7 @@ bool CodeEditingManagerService::Init() #endif VisualStudioCodeEditor::FindEditors(&CodeEditors); RiderCodeEditor::FindEditors(&CodeEditors); + ZedEditor::FindEditors(&CodeEditors); CodeEditors.Add(New()); return false; diff --git a/Source/Editor/Scripting/CodeEditor.h b/Source/Editor/Scripting/CodeEditor.h index 9cc71977b..cb882dc78 100644 --- a/Source/Editor/Scripting/CodeEditor.h +++ b/Source/Editor/Scripting/CodeEditor.h @@ -77,6 +77,11 @@ API_ENUM(Namespace="FlaxEditor", Attributes="HideInEditor") enum class CodeEdito /// VSCodeInsiders, + /// + /// Zed + /// + Zed, + /// /// Rider /// diff --git a/Source/Editor/Scripting/CodeEditors/ZedEditor.cpp b/Source/Editor/Scripting/CodeEditors/ZedEditor.cpp new file mode 100644 index 000000000..dc43ed462 --- /dev/null +++ b/Source/Editor/Scripting/CodeEditors/ZedEditor.cpp @@ -0,0 +1,171 @@ +// Copyright (c) Wojciech Figat. All rights reserved. + +#include "ZedEditor.h" +#include "Engine/Platform/FileSystem.h" +#include "Engine/Platform/CreateProcessSettings.h" +#include "Engine/Core/Log.h" +#include "Editor/Editor.h" +#include "Editor/ProjectInfo.h" +#include "Editor/Scripting/ScriptsBuilder.h" +#include "Engine/Engine/Globals.h" +#if PLATFORM_LINUX +#include +#elif PLATFORM_WINDOWS +#include "Engine/Platform/Win32/IncludeWindowsHeaders.h" +#elif PLATFORM_MAC +#include "Engine/Platform/Apple/AppleUtils.h" +#include +#endif + +ZedEditor::ZedEditor(const String& execPath) + : _execPath(execPath) + , _workspacePath(Globals::ProjectFolder) +{ +} + +void ZedEditor::FindEditors(Array* output) +{ +#if PLATFORM_WINDOWS + String cmd; + if (Platform::ReadRegValue(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Classes\\Applications\\Zed.exe\\shell\\open\\command"), TEXT(""), &cmd) || cmd.IsEmpty()) + { + if (Platform::ReadRegValue(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Classes\\Applications\\Zed.exe\\shell\\open\\command"), TEXT(""), &cmd) || cmd.IsEmpty()) + { + // No hits in registry, try default path instead + } + } + String path; + if (cmd.IsEmpty()) + { + path = cmd.Substring(1, cmd.Length() - String(TEXT("\" \"%1\"")).Length() - 1); + } + else + { + String localAppDataPath; + FileSystem::GetSpecialFolderPath(SpecialFolder::LocalAppData, localAppDataPath); + path = localAppDataPath / TEXT("Programs/Zed/Zed.exe"); + } + if (FileSystem::FileExists(path)) + { + output->Add(New(path)); + } +#elif PLATFORM_LINUX + char buffer[128]; + FILE* pipe = popen("/bin/bash -c \"type -p code\"", "r"); + if (pipe) + { + StringAnsi pathAnsi; + while (fgets(buffer, sizeof(buffer), pipe) != NULL) + pathAnsi += buffer; + pclose(pipe); + const String path(pathAnsi.Get(), pathAnsi.Length() != 0 ? pathAnsi.Length() - 1 : 0); + if (FileSystem::FileExists(path)) + { + output->Add(New(path, false)); + return; + } + } + { + const String path(TEXT("/usr/bin/code")); + if (FileSystem::FileExists(path)) + { + output->Add(New(path, false)); + return; + } + } + + // Detect Flatpak installations + { + CreateProcessSettings procSettings; + procSettings.FileName = TEXT("/bin/bash -c \"flatpak list --app --columns=application | grep com.visualstudio.code -c\""); + procSettings.HiddenWindow = true; + if (Platform::CreateProcess(procSettings) == 0) + { + const String runPath(TEXT("flatpak run com.visualstudio.code")); + output->Add(New(runPath, false)); + return; + } + } +#elif PLATFORM_MAC + // System installed app + NSURL* AppURL = [[NSWorkspace sharedWorkspace]URLForApplicationWithBundleIdentifier:@"com.microsoft.VSCode"]; + if (AppURL != nullptr) + { + const String path = AppleUtils::ToString((CFStringRef)[AppURL path]); + output->Add(New(path, false)); + return; + } + + // Predefined locations + String userFolder; + FileSystem::GetSpecialFolderPath(SpecialFolder::Documents, userFolder); + String paths[3] = + { + TEXT("/Applications/Visual Studio Code.app"), + userFolder + TEXT("/../Visual Studio Code.app"), + userFolder + TEXT("/../Downloads/Visual Studio Code.app"), + }; + for (const String& path : paths) + { + if (FileSystem::DirectoryExists(path)) + { + output->Add(New(path, false)); + break; + } + } +#endif +} + +CodeEditorTypes ZedEditor::GetType() const +{ + return CodeEditorTypes::Zed; +} + +String ZedEditor::GetName() const +{ + return TEXT("Zed"); +} + +void ZedEditor::OpenFile(const String& path, int32 line) +{ + // Generate VS solution files for intellisense + if (!FileSystem::FileExists(Globals::ProjectFolder / Editor::Project->Name + TEXT(".sln"))) + { + ScriptsBuilder::GenerateProject(TEXT("-vs2022")); + } + + // Open file + line = line > 0 ? line : 1; + CreateProcessSettings procSettings; + procSettings.FileName = _execPath; + procSettings.Arguments = String::Format(TEXT("\"{0}\" \"{1}:{2}\""), _workspacePath, path, line); + procSettings.HiddenWindow = false; + procSettings.WaitForEnd = false; + procSettings.LogOutput = false; + procSettings.ShellExecute = true; + Platform::CreateProcess(procSettings); +} + +void ZedEditor::OpenSolution() +{ + // Generate VS solution files for intellisense + if (!FileSystem::FileExists(Globals::ProjectFolder / Editor::Project->Name + TEXT(".sln"))) + { + ScriptsBuilder::GenerateProject(TEXT("-vs2022")); + } + + // Open solution + CreateProcessSettings procSettings; + procSettings.FileName = _execPath; + procSettings.Arguments = String::Format(TEXT("\"{0}\""), _workspacePath); + procSettings.HiddenWindow = false; + procSettings.WaitForEnd = false; + procSettings.LogOutput = false; + procSettings.ShellExecute = true; + Platform::CreateProcess(procSettings); +} + +bool ZedEditor::UseAsyncForOpen() const +{ + return false; +} diff --git a/Source/Editor/Scripting/CodeEditors/ZedEditor.h b/Source/Editor/Scripting/CodeEditors/ZedEditor.h new file mode 100644 index 000000000..541fa8fea --- /dev/null +++ b/Source/Editor/Scripting/CodeEditors/ZedEditor.h @@ -0,0 +1,41 @@ +// Copyright (c) Wojciech Figat. All rights reserved. + +#pragma once + +#include "Editor/Scripting/CodeEditor.h" + +/// +/// Implementation of code editor utility that is using Microsoft Visual Studio Code. +/// +class ZedEditor : public CodeEditor +{ +private: + + String _execPath; + String _workspacePath; + +public: + + /// + /// Initializes a new instance of the class. + /// + /// Executable file path + ZedEditor(const String& execPath); + +public: + + /// + /// Tries to find installed Visual Studio Code instance. Adds them to the result list. + /// + /// The output editors. + static void FindEditors(Array* output); + +public: + + // [CodeEditor] + CodeEditorTypes GetType() const override; + String GetName() const override; + void OpenFile(const String& path, int32 line) override; + void OpenSolution() override; + bool UseAsyncForOpen() const override; +};