guess.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. const path = require('path')
  2. const shellQuote = require('shell-quote')
  3. const childProcess = require('child_process')
  4. // Map from full process name to binary that starts the process
  5. // We can't just re-use full process name, because it will spawn a new instance
  6. // of the app every time
  7. const COMMON_EDITORS_MACOS = require('./editor-info/macos')
  8. const COMMON_EDITORS_LINUX = require('./editor-info/linux')
  9. const COMMON_EDITORS_WIN = require('./editor-info/windows')
  10. function getEditorFromMacProcesses(output) {
  11. const processNames = Object.keys(COMMON_EDITORS_MACOS)
  12. const processList = output.split('\n')
  13. for (let i = 0; i < processNames.length; i++) {
  14. const processName = processNames[i]
  15. // Find editor by exact match.
  16. if (processList.includes(processName)) {
  17. return COMMON_EDITORS_MACOS[processName]
  18. }
  19. const processNameWithoutApplications = processName.replace('/Applications', '')
  20. // Find editor installation not in /Applications.
  21. if (output.indexOf(processNameWithoutApplications) !== -1) {
  22. // Use the CLI command if one is specified
  23. if (processName !== COMMON_EDITORS_MACOS[processName]) {
  24. return COMMON_EDITORS_MACOS[processName]
  25. }
  26. // Use a partial match to find the running process path. If one is found, use the
  27. // existing path since it can be running from anywhere.
  28. const runningProcess = processList.find((procName) =>
  29. procName.endsWith(processNameWithoutApplications),
  30. )
  31. if (runningProcess !== undefined) {
  32. return runningProcess
  33. }
  34. }
  35. }
  36. return undefined
  37. }
  38. function getEditorFromWindowsProcesses(output) {
  39. const runningProcesses = output.split('\r\n')
  40. for (let i = 0; i < runningProcesses.length; i++) {
  41. const fullProcessPath = runningProcesses[i].trim()
  42. const shortProcessName = path.win32.basename(fullProcessPath)
  43. if (COMMON_EDITORS_WIN.indexOf(shortProcessName) !== -1) {
  44. return fullProcessPath
  45. }
  46. }
  47. return undefined
  48. }
  49. function getEditorFromLinuxProcesses(output) {
  50. const processNames = Object.keys(COMMON_EDITORS_LINUX)
  51. for (let i = 0; i < processNames.length; i++) {
  52. const processName = processNames[i]
  53. if (output.indexOf(processName) !== -1) {
  54. return COMMON_EDITORS_LINUX[processName]
  55. }
  56. }
  57. return undefined
  58. }
  59. function guessEditor(specifiedEditor) {
  60. if (specifiedEditor) {
  61. return shellQuote.parse(specifiedEditor)
  62. }
  63. if (process.env.LAUNCH_EDITOR) {
  64. return [process.env.LAUNCH_EDITOR]
  65. }
  66. if (process.versions.webcontainer) {
  67. return [process.env.EDITOR || 'code']
  68. }
  69. // We can find out which editor is currently running by:
  70. // `ps x` on macOS and Linux
  71. // `Get-Process` on Windows
  72. try {
  73. if (process.platform === 'darwin') {
  74. const output = childProcess
  75. .execSync('ps x -o comm=', {
  76. stdio: ['pipe', 'pipe', 'ignore'],
  77. })
  78. .toString()
  79. const editor = getEditorFromMacProcesses(output)
  80. if (editor !== undefined) {
  81. return [editor]
  82. }
  83. } else if (process.platform === 'win32') {
  84. const output = childProcess
  85. .execSync(
  86. 'powershell -NoProfile -Command "' +
  87. '[Console]::OutputEncoding=[Text.Encoding]::UTF8;' +
  88. 'Get-CimInstance -Query \\"select executablepath from win32_process where executablepath is not null\\" | % { $_.ExecutablePath }' +
  89. '"',
  90. {
  91. stdio: ['pipe', 'pipe', 'ignore'],
  92. },
  93. )
  94. .toString()
  95. const editor = getEditorFromWindowsProcesses(output)
  96. if (editor !== undefined) {
  97. return [editor]
  98. }
  99. } else if (process.platform === 'linux') {
  100. // --no-heading No header line
  101. // x List all processes owned by you
  102. // -o comm Need only names column
  103. const output = childProcess
  104. .execSync('ps x --no-heading -o comm --sort=comm', {
  105. stdio: ['pipe', 'pipe', 'ignore'],
  106. })
  107. .toString()
  108. const editor = getEditorFromLinuxProcesses(output)
  109. if (editor !== undefined) {
  110. return [editor]
  111. }
  112. }
  113. } catch (ignoreError) {
  114. // Ignore...
  115. }
  116. // Last resort, use old skool env vars
  117. if (process.env.VISUAL) {
  118. return [process.env.VISUAL]
  119. } else if (process.env.EDITOR) {
  120. return [process.env.EDITOR]
  121. }
  122. return [null]
  123. }
  124. module.exports = guessEditor
  125. module.exports.getEditorFromMacProcesses = getEditorFromMacProcesses
  126. module.exports.getEditorFromWindowsProcesses = getEditorFromWindowsProcesses
  127. module.exports.getEditorFromLinuxProcesses = getEditorFromLinuxProcesses