Skip to content

Commit

Permalink
Merge pull request desktop#19744 from desktop/command-less
Browse files Browse the repository at this point in the history
Drop support for Atom, invoke editors directly
  • Loading branch information
niik authored Dec 18, 2024
2 parents ed12264 + 86a419a commit f86de3d
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 111 deletions.
7 changes: 0 additions & 7 deletions app/src/lib/custom-integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,5 @@ export function spawnCustomIntegration(
args: readonly string[],
options?: SpawnOptions
): ChildProcess {
// On Windows, we need to wrap the arguments and the command in quotes,
// otherwise the shell will split them by spaces again after invoking spawn.
if (__WIN32__ && options?.shell) {
command = `"${command}"`
args = args.map(a => `"${a}"`)
}

return options ? spawn(command, args, options) : spawn(command, args)
}
7 changes: 0 additions & 7 deletions app/src/lib/editors/found-editor.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
export interface IFoundEditor<T> {
readonly editor: T
readonly path: string
/**
* Indicate to Desktop to launch the editor with the `shell: true` option included.
*
* This is available to all platforms, but is only currently used by some Windows
* editors as their launch programs end in `.cmd`
*/
readonly usesShell?: boolean
}
13 changes: 2 additions & 11 deletions app/src/lib/editors/launch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ export async function launchExternalEditor(
}

try {
if (editor.usesShell) {
spawn(`"${editorPath}"`, [`"${fullPath}"`], { ...opts, shell: true })
} else if (__DARWIN__) {
if (__DARWIN__) {
// In macOS we can use `open`, which will open the right executable file
// for us, we only need the path to the editor .app folder.
spawn('open', ['-a', editorPath, fullPath], opts)
Expand Down Expand Up @@ -94,14 +92,7 @@ export async function launchCustomExternalEditor(
const args = expandTargetPathArgument(argv, fullPath)

try {
// This logic around `usesShell` is also used in Windows `getAvailableEditors` implementation
const usesShell = editorPath.endsWith('.cmd')
if (usesShell) {
spawnCustomIntegration(editorPath, args, {
...opts,
shell: true,
})
} else if (__DARWIN__ && customEditor.bundleID) {
if (__DARWIN__ && customEditor.bundleID) {
// In macOS we can use `open` if it's an app (i.e. if we have a bundleID),
// which will open the right executable file for us, we only need the path
// to the editor .app folder.
Expand Down
4 changes: 0 additions & 4 deletions app/src/lib/editors/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ export type FoundEditor = {
* The executable associated with the editor to launch
*/
path: string
/**
* the editor requires a shell spawn to launch
*/
usesShell?: boolean
}

interface IErrorMetadata {
Expand Down
121 changes: 39 additions & 82 deletions app/src/lib/editors/win32.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as Path from 'path'

import {
enumerateKeys,
enumerateValues,
HKEY,
RegistryValue,
Expand All @@ -9,6 +10,7 @@ import {
import { pathExists } from '../../ui/lib/path-exists'

import { IFoundEditor } from './found-editor'
import memoizeOne from 'memoize-one'

interface IWindowsAppInformation {
displayName: string
Expand Down Expand Up @@ -60,16 +62,6 @@ type WindowsExternalEditor = {

/** Value of the Publisher registry key that belongs to this editor. */
readonly publishers: string[]

/**
* Default shell script name for JetBrains Product
* To get the script name go to:
* JetBrains Toolbox > Editor settings > Shell script name
*
* Go to `/docs/techical/editor-integration.md` for more information on
* how to use this field.
*/
readonly jetBrainsToolboxScriptName?: string
} & WindowsExternalEditorPathInfo

const registryKey = (key: HKEY, ...subKeys: string[]): RegistryKey => ({
Expand Down Expand Up @@ -166,27 +158,6 @@ const getCleanInstallLocationFromDisplayIcon = (
* entry here to add support for your favorite editor.
**/
const editors: WindowsExternalEditor[] = [
{
name: 'Atom',
registryKeys: [CurrentUserUninstallKey('atom')],
executableShimPaths: [['bin', 'atom.cmd']],
displayNamePrefixes: ['Atom'],
publishers: ['GitHub Inc.'],
},
{
name: 'Atom Beta',
registryKeys: [CurrentUserUninstallKey('atom-beta')],
executableShimPaths: [['bin', 'atom-beta.cmd']],
displayNamePrefixes: ['Atom Beta'],
publishers: ['GitHub Inc.'],
},
{
name: 'Atom Nightly',
registryKeys: [CurrentUserUninstallKey('atom-nightly')],
executableShimPaths: [['bin', 'atom-nightly.cmd']],
displayNamePrefixes: ['Atom Nightly'],
publishers: ['GitHub Inc.'],
},
{
name: 'Visual Studio Code',
registryKeys: [
Expand All @@ -205,7 +176,7 @@ const editors: WindowsExternalEditor[] = [
// ARM64 version of VSCode (system)
LocalMachineUninstallKey('{A5270FC5-65AD-483E-AC30-2C276B63D0AC}_is1'),
],
executableShimPaths: [['bin', 'code.cmd']],
executableShimPaths: [['code.exe']],
displayNamePrefixes: ['Microsoft Visual Studio Code'],
publishers: ['Microsoft Corporation'],
},
Expand All @@ -227,7 +198,7 @@ const editors: WindowsExternalEditor[] = [
// ARM64 version of VSCode (system)
LocalMachineUninstallKey('{0AEDB616-9614-463B-97D7-119DD86CCA64}_is1'),
],
executableShimPaths: [['bin', 'code-insiders.cmd']],
executableShimPaths: [['Code - Insiders.exe']],
displayNamePrefixes: ['Microsoft Visual Studio Code Insiders'],
publishers: ['Microsoft Corporation'],
},
Expand Down Expand Up @@ -261,7 +232,7 @@ const editors: WindowsExternalEditor[] = [
// ARM64 version of VSCodium (system) - old key
LocalMachineUninstallKey('{D1ACE434-89C5-48D1-88D3-E2991DF85475}_is1'),
],
executableShimPaths: [['bin', 'codium.cmd']],
executableShimPaths: [['VSCodium.exe']],
displayNamePrefixes: ['VSCodium'],
publishers: ['VSCodium', 'Microsoft Corporation'],
},
Expand All @@ -283,7 +254,7 @@ const editors: WindowsExternalEditor[] = [
// ARM64 version of VSCodium - Insiders (system)
LocalMachineUninstallKey('{44721278-64C6-4513-BC45-D48E07830599}_is1'),
],
executableShimPaths: [['bin', 'codium-insiders.cmd']],
executableShimPaths: [['VSCodium - Insiders.exe']],
displayNamePrefixes: ['VSCodium Insiders', 'VSCodium (Insiders)'],
publishers: ['VSCodium'],
},
Expand Down Expand Up @@ -377,23 +348,20 @@ const editors: WindowsExternalEditor[] = [
name: 'JetBrains Webstorm',
registryKeys: registryKeysForJetBrainsIDE('WebStorm'),
executableShimPaths: executableShimPathsForJetBrainsIDE('webstorm'),
jetBrainsToolboxScriptName: 'webstorm',
displayNamePrefixes: ['WebStorm'],
publishers: ['JetBrains s.r.o.'],
},
{
name: 'JetBrains PhpStorm',
registryKeys: registryKeysForJetBrainsIDE('PhpStorm'),
executableShimPaths: executableShimPathsForJetBrainsIDE('phpstorm'),
jetBrainsToolboxScriptName: 'phpstorm',
displayNamePrefixes: ['PhpStorm'],
publishers: ['JetBrains s.r.o.'],
},
{
name: 'Android Studio',
registryKeys: [LocalMachineUninstallKey('Android Studio')],
installLocationRegistryKey: 'UninstallString',
jetBrainsToolboxScriptName: 'studio',
executableShimPaths: [
['..', 'bin', `studio64.exe`],
['..', 'bin', `studio.exe`],
Expand All @@ -417,7 +385,6 @@ const editors: WindowsExternalEditor[] = [
name: 'JetBrains Rider',
registryKeys: registryKeysForJetBrainsIDE('JetBrains Rider'),
executableShimPaths: executableShimPathsForJetBrainsIDE('rider'),
jetBrainsToolboxScriptName: 'rider',
displayNamePrefixes: ['JetBrains Rider'],
publishers: ['JetBrains s.r.o.'],
},
Expand All @@ -432,7 +399,6 @@ const editors: WindowsExternalEditor[] = [
name: 'JetBrains IntelliJ Idea',
registryKeys: registryKeysForJetBrainsIDE('IntelliJ IDEA'),
executableShimPaths: executableShimPathsForJetBrainsIDE('idea'),
jetBrainsToolboxScriptName: 'idea',
displayNamePrefixes: ['IntelliJ IDEA '],
publishers: ['JetBrains s.r.o.'],
},
Expand All @@ -449,7 +415,6 @@ const editors: WindowsExternalEditor[] = [
name: 'JetBrains PyCharm',
registryKeys: registryKeysForJetBrainsIDE('PyCharm'),
executableShimPaths: executableShimPathsForJetBrainsIDE('pycharm'),
jetBrainsToolboxScriptName: 'pycharm',
displayNamePrefixes: ['PyCharm '],
publishers: ['JetBrains s.r.o.'],
},
Expand All @@ -464,30 +429,26 @@ const editors: WindowsExternalEditor[] = [
name: 'JetBrains CLion',
registryKeys: registryKeysForJetBrainsIDE('CLion'),
executableShimPaths: executableShimPathsForJetBrainsIDE('clion'),
jetBrainsToolboxScriptName: 'clion',
displayNamePrefixes: ['CLion '],
publishers: ['JetBrains s.r.o.'],
},
{
name: 'JetBrains RubyMine',
registryKeys: registryKeysForJetBrainsIDE('RubyMine'),
executableShimPaths: executableShimPathsForJetBrainsIDE('rubymine'),
jetBrainsToolboxScriptName: 'rubymine',
displayNamePrefixes: ['RubyMine '],
publishers: ['JetBrains s.r.o.'],
},
{
name: 'JetBrains GoLand',
registryKeys: registryKeysForJetBrainsIDE('GoLand'),
executableShimPaths: executableShimPathsForJetBrainsIDE('goland'),
jetBrainsToolboxScriptName: 'goland',
displayNamePrefixes: ['GoLand '],
publishers: ['JetBrains s.r.o.'],
},
{
name: 'JetBrains Fleet',
registryKeys: [LocalMachineUninstallKey('Fleet')],
jetBrainsToolboxScriptName: 'fleet',
installLocationRegistryKey: 'DisplayIcon',
displayNamePrefixes: ['Fleet '],
publishers: ['JetBrains s.r.o.'],
Expand All @@ -496,15 +457,13 @@ const editors: WindowsExternalEditor[] = [
name: 'JetBrains DataSpell',
registryKeys: registryKeysForJetBrainsIDE('DataSpell'),
executableShimPaths: executableShimPathsForJetBrainsIDE('dataspell'),
jetBrainsToolboxScriptName: 'dataspell',
displayNamePrefixes: ['DataSpell '],
publishers: ['JetBrains s.r.o.'],
},
{
name: 'JetBrains RustRover',
registryKeys: registryKeysForJetBrainsIDE('RustRover'),
executableShimPaths: executableShimPathsForJetBrainsIDE('rustrover'),
jetBrainsToolboxScriptName: 'rustrover',
displayNamePrefixes: ['RustRover '],
publishers: ['JetBrains s.r.o.'],
},
Expand Down Expand Up @@ -582,41 +541,36 @@ async function findApplication(editor: WindowsExternalEditor) {
}
}

return findJetBrainsToolboxApplication(editor)
return undefined
}

/**
* Find JetBrain products installed through JetBrains Toolbox
*/
async function findJetBrainsToolboxApplication(editor: WindowsExternalEditor) {
if (!editor.jetBrainsToolboxScriptName) {
return null
}

const toolboxRegistryReference = [
CurrentUserUninstallKey('toolbox'),
Wow64LocalMachineUninstallKey('toolbox'),
]

for (const { key, subKey } of toolboxRegistryReference) {
const keys = enumerateValues(key, subKey)
if (keys.length > 0) {
const editorPathInToolbox = Path.join(
getKeyOrEmpty(keys, 'UninstallString'),
'..',
'..',
'scripts',
`${editor.jetBrainsToolboxScriptName}.cmd`
)
const exists = await pathExists(editorPathInToolbox)
if (exists) {
return editorPathInToolbox
const getJetBrainsToolboxEditors = memoizeOne(async () => {
const re = /^JetBrains Toolbox \((.*)\)/
const editors = new Array<WindowsExternalEditor>()

for (const parent of [uninstallSubKey, wow64UninstallSubKey]) {
for (const key of enumerateKeys(HKEY.HKEY_CURRENT_USER, parent)) {
const m = re.exec(key)
if (m) {
const [name, product] = m
editors.push({
name,
installLocationRegistryKey: 'DisplayIcon',
registryKeys: [
{
key: HKEY.HKEY_CURRENT_USER,
subKey: `${parent}\\${key}`,
},
],
displayNamePrefixes: [product],
publishers: ['JetBrains s.r.o.'],
})
}
}
}

return null
}
return editors
})

/**
* Lookup known external editors using the Windows registry to find installed
Expand All @@ -626,16 +580,19 @@ export async function getAvailableEditors(): Promise<
ReadonlyArray<IFoundEditor<string>>
> {
const results: Array<IFoundEditor<string>> = []
const candidates = [
...editors,
...(await getJetBrainsToolboxEditors().catch(e => {
log.error(`Failed resolving JetBrains Toolbox products`, e)
return []
})),
]

for (const editor of editors) {
for (const editor of candidates) {
const path = await findApplication(editor)

if (path) {
results.push({
editor: editor.name,
path,
usesShell: path.endsWith('.cmd'),
})
results.push({ editor: editor.name, path })
}
}

Expand Down

0 comments on commit f86de3d

Please sign in to comment.