| ... | ... | @@ -17,6 +17,12 @@ type EditorDefinition = { |
| 17 | 17 | * `zed://ssh/<host><path>` shape. |
| 18 | 18 | */ |
| 19 | 19 | readonly remoteScheme?: string; |
| 20 | /** |
| 21 | * JetBrains product code (`IU`, `PY`, ...). JetBrains IDEs open remote |
| 22 | * projects through the Toolbox App's `jetbrains://gateway/ssh/...` link, |
| 23 | * which uses the code to choose the IDE backend. |
| 24 | */ |
| 25 | readonly jetbrainsProductCode?: string; |
| 20 | 26 | }; |
| 21 | 27 | |
| 22 | 28 | export const EDITORS = [ |
| ... | ... | @@ -67,18 +73,90 @@ export const EDITORS = [ |
| 67 | 73 | commands: ["antigravity-ide", "agy-ide"], |
| 68 | 74 | launchStyle: "goto", |
| 69 | 75 | }, |
| 70 | | { id: "idea", label: "IntelliJ IDEA", commands: ["idea"], launchStyle: "line-column" }, |
| 71 | | { id: "aqua", label: "Aqua", commands: ["aqua"], launchStyle: "line-column" }, |
| 72 | | { id: "clion", label: "CLion", commands: ["clion"], launchStyle: "line-column" }, |
| 73 | | { id: "datagrip", label: "DataGrip", commands: ["datagrip"], launchStyle: "line-column" }, |
| 74 | | { id: "dataspell", label: "DataSpell", commands: ["dataspell"], launchStyle: "line-column" }, |
| 75 | | { id: "goland", label: "GoLand", commands: ["goland"], launchStyle: "line-column" }, |
| 76 | | { id: "phpstorm", label: "PhpStorm", commands: ["phpstorm"], launchStyle: "line-column" }, |
| 77 | | { id: "pycharm", label: "PyCharm", commands: ["pycharm"], launchStyle: "line-column" }, |
| 78 | | { id: "rider", label: "Rider", commands: ["rider"], launchStyle: "line-column" }, |
| 79 | | { id: "rubymine", label: "RubyMine", commands: ["rubymine"], launchStyle: "line-column" }, |
| 80 | | { id: "rustrover", label: "RustRover", commands: ["rustrover"], launchStyle: "line-column" }, |
| 81 | | { id: "webstorm", label: "WebStorm", commands: ["webstorm"], launchStyle: "line-column" }, |
| 76 | { |
| 77 | id: "idea", |
| 78 | label: "IntelliJ IDEA", |
| 79 | commands: ["idea"], |
| 80 | launchStyle: "line-column", |
| 81 | jetbrainsProductCode: "IU", |
| 82 | }, |
| 83 | { |
| 84 | id: "aqua", |
| 85 | label: "Aqua", |
| 86 | commands: ["aqua"], |
| 87 | launchStyle: "line-column", |
| 88 | jetbrainsProductCode: "QA", |
| 89 | }, |
| 90 | { |
| 91 | id: "clion", |
| 92 | label: "CLion", |
| 93 | commands: ["clion"], |
| 94 | launchStyle: "line-column", |
| 95 | jetbrainsProductCode: "CL", |
| 96 | }, |
| 97 | { |
| 98 | id: "datagrip", |
| 99 | label: "DataGrip", |
| 100 | commands: ["datagrip"], |
| 101 | launchStyle: "line-column", |
| 102 | jetbrainsProductCode: "DB", |
| 103 | }, |
| 104 | { |
| 105 | id: "dataspell", |
| 106 | label: "DataSpell", |
| 107 | commands: ["dataspell"], |
| 108 | launchStyle: "line-column", |
| 109 | jetbrainsProductCode: "DS", |
| 110 | }, |
| 111 | { |
| 112 | id: "goland", |
| 113 | label: "GoLand", |
| 114 | commands: ["goland"], |
| 115 | launchStyle: "line-column", |
| 116 | jetbrainsProductCode: "GO", |
| 117 | }, |
| 118 | { |
| 119 | id: "phpstorm", |
| 120 | label: "PhpStorm", |
| 121 | commands: ["phpstorm"], |
| 122 | launchStyle: "line-column", |
| 123 | jetbrainsProductCode: "PS", |
| 124 | }, |
| 125 | { |
| 126 | id: "pycharm", |
| 127 | label: "PyCharm", |
| 128 | commands: ["pycharm"], |
| 129 | launchStyle: "line-column", |
| 130 | jetbrainsProductCode: "PY", |
| 131 | }, |
| 132 | { |
| 133 | id: "rider", |
| 134 | label: "Rider", |
| 135 | commands: ["rider"], |
| 136 | launchStyle: "line-column", |
| 137 | jetbrainsProductCode: "RD", |
| 138 | }, |
| 139 | { |
| 140 | id: "rubymine", |
| 141 | label: "RubyMine", |
| 142 | commands: ["rubymine"], |
| 143 | launchStyle: "line-column", |
| 144 | jetbrainsProductCode: "RM", |
| 145 | }, |
| 146 | { |
| 147 | id: "rustrover", |
| 148 | label: "RustRover", |
| 149 | commands: ["rustrover"], |
| 150 | launchStyle: "line-column", |
| 151 | jetbrainsProductCode: "RR", |
| 152 | }, |
| 153 | { |
| 154 | id: "webstorm", |
| 155 | label: "WebStorm", |
| 156 | commands: ["webstorm"], |
| 157 | launchStyle: "line-column", |
| 158 | jetbrainsProductCode: "WS", |
| 159 | }, |
| 82 | 160 | { id: "file-manager", label: "File Manager", commands: null, launchStyle: "direct-path" }, |
| 83 | 161 | ] as const satisfies ReadonlyArray<EditorDefinition>; |
| 84 | 162 | |
| ... | ... | @@ -98,7 +176,8 @@ export const LaunchEditorInput = Schema.Struct({ |
| 98 | 176 | }); |
| 99 | 177 | export type LaunchEditorInput = typeof LaunchEditorInput.Type; |
| 100 | 178 | |
| 101 | | const remoteSchemeOf = (editor: EditorDefinition): string | undefined => editor.remoteScheme; |
| 179 | const remoteSchemeOf = (editor: EditorDefinition): string | undefined => |
| 180 | editor.remoteScheme ?? (editor.jetbrainsProductCode === undefined ? undefined : "jetbrains"); |
| 102 | 181 | |
| 103 | 182 | /** Editors that can open a remote workspace via an SSH deep link. */ |
| 104 | 183 | export const REMOTE_CAPABLE_EDITOR_IDS: ReadonlyArray<EditorId> = EDITORS.flatMap((editor) => |
| ... | ... | @@ -112,9 +191,10 @@ export const remoteSchemeForEditor = (id: EditorId): string | undefined => { |
| 112 | 191 | |
| 113 | 192 | /** |
| 114 | 193 | * Builds a `<scheme>://vscode-remote/ssh-remote+<host><path>` deep link (Zed |
| 115 | | * takes `zed://ssh/<host><path>`) that opens `absolutePath` on `host` in the |
| 116 | | * local editor over SSH. Returns undefined for editors without remote |
| 117 | | * deep-link support. |
| 194 | * takes `zed://ssh/<host><path>`, JetBrains IDEs a Toolbox App |
| 195 | * `jetbrains://gateway/ssh/environment?...` link) that opens `absolutePath` on |
| 196 | * `host` in the local editor over SSH. Returns undefined for editors without |
| 197 | * remote deep-link support. |
| 118 | 198 | */ |
| 119 | 199 | export const buildRemoteOpenUrl = (input: { |
| 120 | 200 | readonly editor: EditorId; |
| ... | ... | @@ -125,6 +205,18 @@ export const buildRemoteOpenUrl = (input: { |
| 125 | 205 | if (scheme === undefined) { |
| 126 | 206 | return undefined; |
| 127 | 207 | } |
| 208 | const editor = EDITORS.find((candidate) => candidate.id === input.editor); |
| 209 | if (editor !== undefined && "jetbrainsProductCode" in editor) { |
| 210 | // Like the VS Code link, no user or port: the SSH config entry for `host` |
| 211 | // supplies them. A bare product code lets Toolbox pick the backend build. |
| 212 | const params = new URLSearchParams({ |
| 213 | h: input.host, |
| 214 | launchIde: "true", |
| 215 | ideHint: editor.jetbrainsProductCode, |
| 216 | projectHint: input.absolutePath.replaceAll("\\", "/"), |
| 217 | }); |
| 218 | return `${scheme}://gateway/ssh/environment?${params.toString()}`; |
| 219 | } |
| 128 | 220 | // Windows server paths (`C:\...`) appear as `/C:/...` in vscode-remote URIs. |
| 129 | 221 | const posixPath = input.absolutePath.replaceAll("\\", "/"); |
| 130 | 222 | const rootedPath = posixPath.startsWith("/") ? posixPath : `/${posixPath}`; |