@lvce-editor/shared-process 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +41 -0
- package/bin/sharedProcess.js +3 -0
- package/index.js +6 -0
- package/package.json +96 -0
- package/src/parts/Assert/Assert.js +57 -0
- package/src/parts/Callback/Callback.js +48 -0
- package/src/parts/ChildProcess/ChildProcess.js +98 -0
- package/src/parts/ClipBoard/ClipBoard.ipc.js +7 -0
- package/src/parts/ClipBoard/ClipBoard.js +23 -0
- package/src/parts/ClipBoard/ClipBoardGnome.js +78 -0
- package/src/parts/ClipBoard/ClipBoardNoop.js +14 -0
- package/src/parts/ClipBoard/ClipBoardWindows.js +22 -0
- package/src/parts/Command/Command.js +264 -0
- package/src/parts/Configuration/Configuration.ipc.js +7 -0
- package/src/parts/Configuration/Configuration.js +39 -0
- package/src/parts/Credentials/Credentials.ipc.js +10 -0
- package/src/parts/Credentials/Credentials.js +69 -0
- package/src/parts/Debug/Debug.js +3 -0
- package/src/parts/Developer/Developer.ipc.js +20 -0
- package/src/parts/Developer/Developer.js +132 -0
- package/src/parts/Download/Download.js +33 -0
- package/src/parts/Electron/Electron.ipc.js +19 -0
- package/src/parts/Electron/Electron.js +99 -0
- package/src/parts/Env/Env.js +3 -0
- package/src/parts/Error/Error.js +30 -0
- package/src/parts/ErrorHandling/ErrorHandling.js +40 -0
- package/src/parts/Exec/Exec.js +16 -0
- package/src/parts/Extension/Extension.js +7 -0
- package/src/parts/ExtensionHost/ExtensionHost.ipc.js +80 -0
- package/src/parts/ExtensionHost/ExtensionHost.js +163 -0
- package/src/parts/ExtensionHost/ExtensionHostBraceCompletion.js +14 -0
- package/src/parts/ExtensionHost/ExtensionHostClosingTag.js +14 -0
- package/src/parts/ExtensionHost/ExtensionHostColorTheme.js +60 -0
- package/src/parts/ExtensionHost/ExtensionHostCommand.js +19 -0
- package/src/parts/ExtensionHost/ExtensionHostCompletion.js +12 -0
- package/src/parts/ExtensionHost/ExtensionHostDefinition.js +12 -0
- package/src/parts/ExtensionHost/ExtensionHostDiagnostic.js +7 -0
- package/src/parts/ExtensionHost/ExtensionHostFileSystem.js +23 -0
- package/src/parts/ExtensionHost/ExtensionHostFormatting.js +4 -0
- package/src/parts/ExtensionHost/ExtensionHostHover.js +12 -0
- package/src/parts/ExtensionHost/ExtensionHostIconTheme.js +35 -0
- package/src/parts/ExtensionHost/ExtensionHostImplementation.js +12 -0
- package/src/parts/ExtensionHost/ExtensionHostKeyBindings.js +23 -0
- package/src/parts/ExtensionHost/ExtensionHostLanguages.js +84 -0
- package/src/parts/ExtensionHost/ExtensionHostManagement.js +26 -0
- package/src/parts/ExtensionHost/ExtensionHostOutput.js +3 -0
- package/src/parts/ExtensionHost/ExtensionHostQuickPick.js +6 -0
- package/src/parts/ExtensionHost/ExtensionHostReference.js +12 -0
- package/src/parts/ExtensionHost/ExtensionHostRename.js +27 -0
- package/src/parts/ExtensionHost/ExtensionHostSemanticTokens.js +10 -0
- package/src/parts/ExtensionHost/ExtensionHostSourceControl.js +15 -0
- package/src/parts/ExtensionHost/ExtensionHostStats.js +3 -0
- package/src/parts/ExtensionHost/ExtensionHostStatusBar.js +7 -0
- package/src/parts/ExtensionHost/ExtensionHostTabCompletion.js +12 -0
- package/src/parts/ExtensionHost/ExtensionHostTextDocument.js +35 -0
- package/src/parts/ExtensionHost/ExtensionHostTypeDefinition.js +12 -0
- package/src/parts/ExtensionHost/ExtensionHostWorkspace.js +3 -0
- package/src/parts/ExtensionManagement/ExtensionManagement.ipc.js +11 -0
- package/src/parts/ExtensionManagement/ExtensionManagement.js +319 -0
- package/src/parts/FileSystem/FileSystem.ipc.js +32 -0
- package/src/parts/FileSystem/FileSystem.js +228 -0
- package/src/parts/Git/Git.js +58 -0
- package/src/parts/Json/Json.js +67 -0
- package/src/parts/JsonFile/JsonFile.js +14 -0
- package/src/parts/JsonRpc/JsonRpc.js +22 -0
- package/src/parts/Native/Native.ipc.js +6 -0
- package/src/parts/Native/Native.js +14 -0
- package/src/parts/OutputChannel/OutputChannel.ipc.js +51 -0
- package/src/parts/OutputChannel/OutputChannel.js +37 -0
- package/src/parts/ParentIpc/ParentIpc.js +203 -0
- package/src/parts/Path/Path.js +17 -0
- package/src/parts/Platform/Platform.ipc.js +18 -0
- package/src/parts/Platform/Platform.js +165 -0
- package/src/parts/Preferences/Preferences.ipc.js +6 -0
- package/src/parts/Preferences/Preferences.js +75 -0
- package/src/parts/PrettyError/PrettyError.js +86 -0
- package/src/parts/Process/Process.ipc.js +7 -0
- package/src/parts/Process/Process.js +7 -0
- package/src/parts/Queue/Queue.js +35 -0
- package/src/parts/RequiresSocket/RequiresSocket.js +11 -0
- package/src/parts/RgPath/RgPath.js +1 -0
- package/src/parts/Root/Root.js +6 -0
- package/src/parts/Search/Search.ipc.js +6 -0
- package/src/parts/Search/Search.js +101 -0
- package/src/parts/SearchFile/SearchFile.ipc.js +6 -0
- package/src/parts/SearchFile/SearchFile.js +51 -0
- package/src/parts/Socket/Socket.js +132 -0
- package/src/parts/Stats/Stats.js +45 -0
- package/src/parts/Terminal/Terminal.ipc.js +45 -0
- package/src/parts/Terminal/Terminal.js +161 -0
- package/src/parts/TextDocument/TextDocument.ipc.js +6 -0
- package/src/parts/TextDocument/TextDocument.js +37 -0
- package/src/parts/Trace/Trace.js +15 -0
- package/src/parts/Trash/Trash.js +11 -0
- package/src/parts/WebSocketServer/WebSocketServer.ipc.js +6 -0
- package/src/parts/WebSocketServer/WebSocketServer.js +43 -0
- package/src/parts/Workspace/Workspace.ipc.js +7 -0
- package/src/parts/Workspace/Workspace.js +107 -0
- package/src/sharedProcessMain.js +61 -0
- package/test/Callback.test.js +42 -0
- package/test/ClipBoard.test.js +105 -0
- package/test/Credentials.test.js +147 -0
- package/test/Developer.test.js +34 -0
- package/test/Electron.test.js +93 -0
- package/test/Error.test.js +16 -0
- package/test/Exec.test.js +25 -0
- package/test/ExtensionHost.test.js +127 -0
- package/test/ExtensionHostColorTheme.test.js +141 -0
- package/test/ExtensionHostCommand.test.js +27 -0
- package/test/ExtensionHostCompletion.test.js +45 -0
- package/test/ExtensionHostDefinition.test.js +35 -0
- package/test/ExtensionHostDiagnostic.test.js +23 -0
- package/test/ExtensionHostFileSystem.test.js +91 -0
- package/test/ExtensionHostFormatting.test.js +27 -0
- package/test/ExtensionHostIconTheme.test.js +73 -0
- package/test/ExtensionHostLanguages.test.js +212 -0
- package/test/ExtensionHostOutput.test.js +23 -0
- package/test/ExtensionHostRename.test.js +59 -0
- package/test/ExtensionHostSemanticTokens.test.js +26 -0
- package/test/ExtensionHostTabCompletion.test.js +35 -0
- package/test/ExtensionHostTextDocument.test.js +61 -0
- package/test/ExtensionHostTypeDefinition.test.js +35 -0
- package/test/ExtensionHostWorkspace.test.js +21 -0
- package/test/ExtensionManagement.test.js +408 -0
- package/test/FileSystem.test.js +294 -0
- package/test/Json.test.js +25 -0
- package/test/Native.test.js +31 -0
- package/test/OutputChannel.test.js +68 -0
- package/test/Path.test.js +17 -0
- package/test/Platform.test.js +61 -0
- package/test/Preferences.test.js +140 -0
- package/test/Process.test.js +9 -0
- package/test/RgPath.test.js +5 -0
- package/test/Search.test.js +45 -0
- package/test/SearchFile.test.js +80 -0
- package/test/Terminal.test.js +53 -0
- package/test/Trash.test.js +34 -0
- package/test/WebSocketServer.test.js +98 -0
- package/test/fixture-search-1/index.html +10 -0
- package/test/fixture-search-file-1/fileA +0 -0
- package/test/fixture-search-file-1/fileB +0 -0
- package/test/fixture-search-file-1/nested/fileC +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import VError from 'verror'
|
|
2
|
+
import * as Callback from '../Callback/Callback.js'
|
|
3
|
+
import * as ChildProcess from '../ChildProcess/ChildProcess.js'
|
|
4
|
+
import * as Debug from '../Debug/Debug.js'
|
|
5
|
+
import * as Error from '../Error/Error.js'
|
|
6
|
+
import * as ExtensionManagement from '../ExtensionManagement/ExtensionManagement.js'
|
|
7
|
+
import * as ReadJson from '../JsonFile/JsonFile.js'
|
|
8
|
+
import * as JsonRpc from '../JsonRpc/JsonRpc.js'
|
|
9
|
+
import * as Path from '../Path/Path.js'
|
|
10
|
+
import * as Root from '../Root/Root.js'
|
|
11
|
+
import * as Socket from '../Socket/Socket.js'
|
|
12
|
+
import * as TextDocument from '../TextDocument/TextDocument.js'
|
|
13
|
+
import * as Platform from '../Platform/Platform.js'
|
|
14
|
+
|
|
15
|
+
const getExtensionKeyBindings = (extension) => {
|
|
16
|
+
return extension.keyBindings || []
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const getKeyBindings = async () => {
|
|
20
|
+
const extensions = await ExtensionManagement.getExtensions()
|
|
21
|
+
const keyBindings = extensions.flatMap(getExtensionKeyBindings)
|
|
22
|
+
return keyBindings
|
|
23
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { join } from 'node:path'
|
|
2
|
+
import { pathToFileURL } from 'node:url'
|
|
3
|
+
import VError from 'verror'
|
|
4
|
+
import * as Error from '../Error/Error.js'
|
|
5
|
+
import * as ExtensionManagement from '../ExtensionManagement/ExtensionManagement.js'
|
|
6
|
+
import * as ReadJson from '../JsonFile/JsonFile.js'
|
|
7
|
+
import * as Path from '../Path/Path.js'
|
|
8
|
+
|
|
9
|
+
const getExtensionLanguages = (extension) => {
|
|
10
|
+
if (!extension.languages) {
|
|
11
|
+
return []
|
|
12
|
+
}
|
|
13
|
+
return extension.languages.map((language) => ({}))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const toRemoteUrl = (path) => {
|
|
17
|
+
const url = pathToFileURL(path).toString().slice(8)
|
|
18
|
+
return `/remote/${url}`
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const getLanguagesFromExtension = (extension) => {
|
|
22
|
+
// TODO what if extension is null? should not crash process, handle error gracefully
|
|
23
|
+
if (!extension.languages) {
|
|
24
|
+
return []
|
|
25
|
+
}
|
|
26
|
+
const getLanguageFromExtension = (language) => {
|
|
27
|
+
if (language.tokenize) {
|
|
28
|
+
if (typeof language.tokenize !== 'string') {
|
|
29
|
+
console.warn(
|
|
30
|
+
`[info] ${
|
|
31
|
+
language.id
|
|
32
|
+
}: language.tokenize must be of type string but was of type ${typeof language.tokenize}`
|
|
33
|
+
)
|
|
34
|
+
return {
|
|
35
|
+
...language,
|
|
36
|
+
tokenize: '',
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
...language,
|
|
41
|
+
tokenize: toRemoteUrl(join(extension.path, language.tokenize)),
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return language
|
|
45
|
+
}
|
|
46
|
+
return extension.languages.map(getLanguageFromExtension)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const getLanguagesFromExtensions = (extensions) => {
|
|
50
|
+
return extensions.flatMap(getLanguagesFromExtension)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const getLanguages = async () => {
|
|
54
|
+
const extensions = await ExtensionManagement.getExtensions()
|
|
55
|
+
const languages = getLanguagesFromExtensions(extensions)
|
|
56
|
+
return languages
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const getLanguageConfigurationPathFromExtensions = (extensions, languageId) => {
|
|
60
|
+
for (const extension of extensions) {
|
|
61
|
+
if (extension.languages && extension.languages) {
|
|
62
|
+
for (const language of extension.languages) {
|
|
63
|
+
if (language.id === languageId && language.configuration) {
|
|
64
|
+
return join(extension.path, language.configuration)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return ''
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const getLanguageConfiguration = async (languageId) => {
|
|
73
|
+
try {
|
|
74
|
+
const extensions = await ExtensionManagement.getExtensions()
|
|
75
|
+
const languageConfigurationPath =
|
|
76
|
+
getLanguageConfigurationPathFromExtensions(extensions, languageId)
|
|
77
|
+
return await ReadJson.readJson(languageConfigurationPath)
|
|
78
|
+
} catch (error) {
|
|
79
|
+
throw new VError(
|
|
80
|
+
error,
|
|
81
|
+
`Failed to load language configuration for ${languageId}`
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as Debug from '../Debug/Debug.js'
|
|
2
|
+
|
|
3
|
+
export const didInstallExtension = (extensionHost, extension) => {
|
|
4
|
+
return extensionHost.invoke('didInstallExtension', extension)
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const didUninstallExtension = (extensionHost, extension) => {
|
|
8
|
+
return extensionHost.invoke('didUninstallExtension', extension)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const disableExtension = (extensionHost, extension) => {
|
|
12
|
+
return extensionHost.invoke('disableExtension', extension)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// TODO have enableExtensionsCommand to avoid sending too many messages via ipc -> only send one ipc message to enable multiple extensions
|
|
16
|
+
export const enableExtension = async (extensionHost, extension) => {
|
|
17
|
+
Debug.debug(`ExtensionHost#enableExtension ${extension.id}`)
|
|
18
|
+
await extensionHost.invoke('enableExtension', extension)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const activateAll = async (extensions) => {
|
|
22
|
+
// console.log({ extensions })
|
|
23
|
+
const results = await Promise.allSettled(extensions.map(enableExtension))
|
|
24
|
+
// console.log({ results })
|
|
25
|
+
return results
|
|
26
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const executePrepareRename = async (
|
|
2
|
+
extensionHost,
|
|
3
|
+
documentId,
|
|
4
|
+
offset
|
|
5
|
+
) => {
|
|
6
|
+
const result = await extensionHost.invoke(
|
|
7
|
+
'Rename.executePrepareRename',
|
|
8
|
+
documentId,
|
|
9
|
+
offset
|
|
10
|
+
)
|
|
11
|
+
return result
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const executeRename = async (
|
|
15
|
+
extensionHost,
|
|
16
|
+
documentId,
|
|
17
|
+
offset,
|
|
18
|
+
newName
|
|
19
|
+
) => {
|
|
20
|
+
const result = await extensionHost.invoke(
|
|
21
|
+
'Rename.executeRename',
|
|
22
|
+
documentId,
|
|
23
|
+
offset,
|
|
24
|
+
newName
|
|
25
|
+
)
|
|
26
|
+
return result
|
|
27
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const sourceControlAcceptInput = (extensionHost, text) => {
|
|
2
|
+
return extensionHost.invoke('SourceControl.acceptInput', text)
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export const getSourceControlChangedFiles = async (extensionHost) => {
|
|
6
|
+
const changedFiles = await extensionHost.invoke(
|
|
7
|
+
'getSourceControlChangedFiles'
|
|
8
|
+
)
|
|
9
|
+
return changedFiles
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const getSourceControlBadgeCount = async (extensionHost) => {
|
|
13
|
+
const count = await extensionHost.invoke('getSourceControlBadgeCount')
|
|
14
|
+
return count
|
|
15
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export const textDocumentSyncInitial = (
|
|
2
|
+
extensionHost,
|
|
3
|
+
uri,
|
|
4
|
+
textDocumentId,
|
|
5
|
+
languageId,
|
|
6
|
+
text
|
|
7
|
+
) => {
|
|
8
|
+
return extensionHost.invoke(
|
|
9
|
+
'TextDocument.syncInitial',
|
|
10
|
+
uri,
|
|
11
|
+
textDocumentId,
|
|
12
|
+
languageId,
|
|
13
|
+
text
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const textDocumentSyncIncremental = (
|
|
18
|
+
extensionHost,
|
|
19
|
+
textDocumentId,
|
|
20
|
+
changes
|
|
21
|
+
) => {
|
|
22
|
+
return extensionHost.invoke(
|
|
23
|
+
'TextDocument.syncIncremental',
|
|
24
|
+
textDocumentId,
|
|
25
|
+
changes
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const setLanguageId = (extensionHost, textDocumentId, languageId) => {
|
|
30
|
+
return extensionHost.invoke(
|
|
31
|
+
'TextDocument.setLanguageId',
|
|
32
|
+
textDocumentId,
|
|
33
|
+
languageId
|
|
34
|
+
)
|
|
35
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as Command from '../Command/Command.js'
|
|
2
|
+
import * as ExtensionManagement from './ExtensionManagement.js'
|
|
3
|
+
|
|
4
|
+
export const __initialize__ = () => {
|
|
5
|
+
Command.register('ExtensionManagement.install', ExtensionManagement.install)
|
|
6
|
+
Command.register('ExtensionManagement.uninstall', ExtensionManagement.uninstall)
|
|
7
|
+
Command.register('ExtensionManagement.enable', ExtensionManagement.enable)
|
|
8
|
+
Command.register('ExtensionManagement.disable', ExtensionManagement.disable)
|
|
9
|
+
Command.register('ExtensionManagement.getAllExtensions', ExtensionManagement.getAllExtensions)
|
|
10
|
+
Command.register('ExtensionManagement.getExtensions', ExtensionManagement.getExtensions)
|
|
11
|
+
}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { mkdir, readdir, rename, rm } from 'node:fs/promises'
|
|
2
|
+
import { performance } from 'node:perf_hooks'
|
|
3
|
+
import isObject from 'is-object'
|
|
4
|
+
import VError from 'verror'
|
|
5
|
+
import * as Debug from '../Debug/Debug.js'
|
|
6
|
+
import * as Error from '../Error/Error.js'
|
|
7
|
+
import * as ReadJson from '../JsonFile/JsonFile.js'
|
|
8
|
+
import * as Path from '../Path/Path.js'
|
|
9
|
+
import * as Platform from '../Platform/Platform.js'
|
|
10
|
+
import * as Queue from '../Queue/Queue.js'
|
|
11
|
+
|
|
12
|
+
export const state = {
|
|
13
|
+
async getExtensions() {
|
|
14
|
+
if (process.env.ONLY_EXTENSION) {
|
|
15
|
+
return getExtensionManifests([process.env.ONLY_EXTENSION])
|
|
16
|
+
}
|
|
17
|
+
const builtinExtensions = await getBuiltinExtensions()
|
|
18
|
+
const installedExtensions = await getInstalledExtensions()
|
|
19
|
+
return [...builtinExtensions, ...installedExtensions]
|
|
20
|
+
},
|
|
21
|
+
async getThemeExtensions() {
|
|
22
|
+
const builtinExtensionsPath = Platform.getBuiltinExtensionsPath()
|
|
23
|
+
const dirents = await readdir(builtinExtensionsPath)
|
|
24
|
+
const paths = []
|
|
25
|
+
for (const dirent of dirents) {
|
|
26
|
+
if (isTheme(dirent)) {
|
|
27
|
+
paths.push(getAbsoluteBuiltinExtensionPath(dirent))
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (process.env.ONLY_EXTENSION && isTheme(process.env.ONLY_EXTENSION)) {
|
|
31
|
+
paths.push(process.env.ONLY_EXTENSION)
|
|
32
|
+
}
|
|
33
|
+
const builtinExtensions = await getExtensionManifests(paths)
|
|
34
|
+
return builtinExtensions
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const install = async (id) => {
|
|
39
|
+
// TODO this should be a stateless function, renderer-worker should have info on marketplace url
|
|
40
|
+
// TODO use command.execute
|
|
41
|
+
try {
|
|
42
|
+
const { download, extract } = await import('../Download/Download.js')
|
|
43
|
+
const marketplaceUrl = Platform.getMarketplaceUrl()
|
|
44
|
+
Debug.debug(`ExtensionManagement#install ${id}`)
|
|
45
|
+
const cachedExtensionsPath = Platform.getCachedExtensionsPath()
|
|
46
|
+
const extensionsPath = Platform.getExtensionsPath()
|
|
47
|
+
// TODO maybe a queue is over engineering here
|
|
48
|
+
await Queue.add('download', async () => {
|
|
49
|
+
Debug.debug(`ExtensionManagement#download ${id}`)
|
|
50
|
+
// TODO use command.execute
|
|
51
|
+
await download(
|
|
52
|
+
`${marketplaceUrl}/download/${id}`,
|
|
53
|
+
Path.join(cachedExtensionsPath, `${id}.tar.br`)
|
|
54
|
+
)
|
|
55
|
+
Debug.debug(`ExtensionManagement#extract ${id}`)
|
|
56
|
+
await extract(
|
|
57
|
+
Path.join(cachedExtensionsPath, `${id}.tar.br`),
|
|
58
|
+
Path.join(extensionsPath, id)
|
|
59
|
+
)
|
|
60
|
+
})
|
|
61
|
+
// TODO should this be here? (probably not)
|
|
62
|
+
// await ExtensionHost.enableExtension({
|
|
63
|
+
// id,
|
|
64
|
+
// type: 'marketplace',
|
|
65
|
+
// })
|
|
66
|
+
} catch (error) {
|
|
67
|
+
throw new Error.OperationalError({
|
|
68
|
+
cause: error,
|
|
69
|
+
code: 'E_EXT_INSTALL_FAILED',
|
|
70
|
+
message: `Failed to install extension "${id}"`,
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const uninstall = async (id) => {
|
|
76
|
+
try {
|
|
77
|
+
Debug.debug(`ExtensionManagement#uninstall ${id}`)
|
|
78
|
+
const extensionsPath = Platform.getExtensionsPath()
|
|
79
|
+
await rm(Path.join(extensionsPath, id), { recursive: true })
|
|
80
|
+
} catch (error) {
|
|
81
|
+
// if (error.code === 'ENOENT') {
|
|
82
|
+
// return
|
|
83
|
+
// }
|
|
84
|
+
throw new Error.OperationalError({
|
|
85
|
+
cause: error,
|
|
86
|
+
code: 'E_EXT_UNINSTALL_FAILED',
|
|
87
|
+
message: `Failed to uninstall extension "${id}"`,
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export const enable = async (id) => {
|
|
93
|
+
try {
|
|
94
|
+
Debug.debug(`ExtensionManagement#enable ${id}`)
|
|
95
|
+
const extensionsPath = Platform.getExtensionsPath()
|
|
96
|
+
const disabledExtensionsPath = Platform.getDisabledExtensionsPath()
|
|
97
|
+
await mkdir(extensionsPath, { recursive: true })
|
|
98
|
+
await rename(
|
|
99
|
+
Path.join(disabledExtensionsPath, id),
|
|
100
|
+
Path.join(extensionsPath, id)
|
|
101
|
+
)
|
|
102
|
+
} catch (error) {
|
|
103
|
+
throw new Error.OperationalError({
|
|
104
|
+
cause: error,
|
|
105
|
+
message: `Failed to enable extension "${id}"`,
|
|
106
|
+
code: 'E_EXTENSION_ENABLING_FAILED',
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export const disable = async (id) => {
|
|
112
|
+
try {
|
|
113
|
+
Debug.debug(`ExtensionManagement#disable ${id}`)
|
|
114
|
+
const disabledExtensionsPath = Platform.getDisabledExtensionsPath()
|
|
115
|
+
const extensionsPath = Platform.getExtensionsPath()
|
|
116
|
+
await mkdir(disabledExtensionsPath, { recursive: true })
|
|
117
|
+
await rename(
|
|
118
|
+
Path.join(extensionsPath, id),
|
|
119
|
+
Path.join(disabledExtensionsPath, id)
|
|
120
|
+
)
|
|
121
|
+
} catch (error) {
|
|
122
|
+
throw new Error.OperationalError({
|
|
123
|
+
cause: error,
|
|
124
|
+
code: 'E_EXTENSION_DISABLING_FAILED',
|
|
125
|
+
message: `Failed to disable extension ${id}`,
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const getAbsoluteDisabledPath = (dirent) => {
|
|
131
|
+
const disabledExtensionsPath = Platform.getDisabledExtensionsPath()
|
|
132
|
+
return Path.join(disabledExtensionsPath, dirent)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const getDisabledExtensionPaths = async () => {
|
|
136
|
+
try {
|
|
137
|
+
const disabledExtensionsPaths = Platform.getDisabledExtensionsPath()
|
|
138
|
+
const dirents = await readdir(disabledExtensionsPaths)
|
|
139
|
+
const paths = dirents.map(getAbsoluteDisabledPath)
|
|
140
|
+
return paths
|
|
141
|
+
} catch {
|
|
142
|
+
// TODO handle error
|
|
143
|
+
return []
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const getAbsoluteBuiltinExtensionPath = (dirent) => {
|
|
148
|
+
const builtinExtensionsPath = Platform.getBuiltinExtensionsPath()
|
|
149
|
+
return Path.join(builtinExtensionsPath, dirent)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const isIncludedBuiltinExtension = (dirent) => {
|
|
153
|
+
const SKIPPED = [
|
|
154
|
+
'hello-world',
|
|
155
|
+
'vite',
|
|
156
|
+
'soundcloud',
|
|
157
|
+
'npm',
|
|
158
|
+
// 'builtin.git', ~40MB memory usage (too many file watchers)
|
|
159
|
+
// 'builtin.prettier', ~20MB memory usage (maybe lazyload prettier)
|
|
160
|
+
// 'language-features-typescript',
|
|
161
|
+
// 'builtin.vscode-icons',
|
|
162
|
+
]
|
|
163
|
+
return !SKIPPED.includes(dirent)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const getBuiltinExtensionPaths = async () => {
|
|
167
|
+
try {
|
|
168
|
+
const builtinExtensionsPath = Platform.getBuiltinExtensionsPath()
|
|
169
|
+
const dirents = await readdir(builtinExtensionsPath)
|
|
170
|
+
const filteredDirents = dirents.filter(isIncludedBuiltinExtension)
|
|
171
|
+
const paths = filteredDirents.map(getAbsoluteBuiltinExtensionPath)
|
|
172
|
+
return paths
|
|
173
|
+
} catch {
|
|
174
|
+
console.info('no builtin extension paths found')
|
|
175
|
+
return []
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const getAbsoluteInstalledExtensionPath = (dirent) => {
|
|
180
|
+
const extensionsPath = Platform.getExtensionsPath()
|
|
181
|
+
return Path.join(extensionsPath, dirent)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const getInstalledExtensionPaths = async () => {
|
|
185
|
+
try {
|
|
186
|
+
const extensionsPath = Platform.getExtensionsPath()
|
|
187
|
+
const dirents = await readdir(extensionsPath)
|
|
188
|
+
const paths = dirents.map(getAbsoluteInstalledExtensionPath)
|
|
189
|
+
return paths
|
|
190
|
+
} catch (error) {
|
|
191
|
+
// TODO how to make typescript happy?
|
|
192
|
+
// @ts-ignore
|
|
193
|
+
if (error.code === 'ENOENT') {
|
|
194
|
+
// TODO what if mkdir fails?
|
|
195
|
+
await mkdir(Platform.getExtensionsPath(), { recursive: true })
|
|
196
|
+
return []
|
|
197
|
+
}
|
|
198
|
+
throw new Error.OperationalError({
|
|
199
|
+
cause: error,
|
|
200
|
+
code: 'E_FAILED_TO_LOAD_INSTALLED_EXTENSIONS',
|
|
201
|
+
message: 'Failed to get installed extensions',
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const RE_EXTENSION_FRAGMENT = /.+(\/|\\)(.+)$/
|
|
207
|
+
|
|
208
|
+
const inferExtensionId = (absolutePath) => {
|
|
209
|
+
const match = absolutePath.match(RE_EXTENSION_FRAGMENT)
|
|
210
|
+
if (match) {
|
|
211
|
+
return match[2]
|
|
212
|
+
}
|
|
213
|
+
return ''
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// TODO json parsing and error handling should happen in renderer process
|
|
217
|
+
const getExtensionManifest = async (path) => {
|
|
218
|
+
try {
|
|
219
|
+
const absolutePath = Path.join(path, 'extension.json')
|
|
220
|
+
const json = await ReadJson.readJson(absolutePath)
|
|
221
|
+
if (!isObject(json)) {
|
|
222
|
+
// TODO should include stack of extension json file here
|
|
223
|
+
throw new VError('Invalid manifest file: Not an JSON object.')
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
...json,
|
|
227
|
+
path,
|
|
228
|
+
status: 'fulfilled',
|
|
229
|
+
}
|
|
230
|
+
} catch (error) {
|
|
231
|
+
const id = inferExtensionId(path)
|
|
232
|
+
return {
|
|
233
|
+
path,
|
|
234
|
+
status: 'rejected',
|
|
235
|
+
reason: new Error.OperationalError({
|
|
236
|
+
cause: error,
|
|
237
|
+
code: 'E_LOADING_EXTENSION_MANIFEST_FAilED',
|
|
238
|
+
message: `Failed to load extension "${id}": Failed to load extension manifest`,
|
|
239
|
+
// @ts-ignore
|
|
240
|
+
stack: error.stack,
|
|
241
|
+
}),
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const isRejected = (promise) => {
|
|
247
|
+
return promise.status === 'rejected'
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* @param {string[]} paths
|
|
252
|
+
*/
|
|
253
|
+
const getExtensionManifests = async (paths) => {
|
|
254
|
+
const allResults = await Promise.all(paths.map(getExtensionManifest))
|
|
255
|
+
return allResults
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export const getBuiltinExtensions = async () => {
|
|
259
|
+
const builtinExtensionPaths = await getBuiltinExtensionPaths()
|
|
260
|
+
const builtinExtensions = await getExtensionManifests(builtinExtensionPaths)
|
|
261
|
+
return builtinExtensions
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export const getInstalledExtensions = async () => {
|
|
265
|
+
const installedExtensionPaths = await getInstalledExtensionPaths()
|
|
266
|
+
const installedExtensions = await getExtensionManifests(
|
|
267
|
+
installedExtensionPaths
|
|
268
|
+
)
|
|
269
|
+
return installedExtensions
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export const getExtensions = async () => {
|
|
273
|
+
return state.getExtensions()
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const RE_THEME = /[a-z]+\.[a-z\-]*theme-[a-z\d\-]+$/
|
|
277
|
+
const isTheme = (extensionId) => {
|
|
278
|
+
return RE_THEME.test(extensionId)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const getThemeExtensionsBuiltin = async () => {
|
|
282
|
+
const builtinExtensionsPath = Platform.getBuiltinExtensionsPath()
|
|
283
|
+
const dirents = await readdir(builtinExtensionsPath)
|
|
284
|
+
const filteredDirents = dirents.filter(isTheme)
|
|
285
|
+
const paths = filteredDirents.map(getAbsoluteBuiltinExtensionPath)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export const getThemeExtensions = async () => {
|
|
289
|
+
return state.getThemeExtensions()
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export const getDisabledExtensions = async () => {
|
|
293
|
+
const disabledExtensionPaths = await getDisabledExtensionPaths()
|
|
294
|
+
const disabledExtensions = await getExtensionManifests(disabledExtensionPaths)
|
|
295
|
+
return disabledExtensions
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export const getAllExtensions = async () => {
|
|
299
|
+
if (process.env.ONLY_EXTENSION) {
|
|
300
|
+
return getExtensionManifests([process.env.ONLY_EXTENSION])
|
|
301
|
+
}
|
|
302
|
+
const t1 = performance.now()
|
|
303
|
+
const [builtinExtensions, installedExtensions, disabledExtensions] =
|
|
304
|
+
// TODO handle error when one of them fails
|
|
305
|
+
await Promise.all([
|
|
306
|
+
getBuiltinExtensions(),
|
|
307
|
+
getInstalledExtensions(),
|
|
308
|
+
getDisabledExtensions(),
|
|
309
|
+
])
|
|
310
|
+
const t4 = performance.now()
|
|
311
|
+
// TODO can optimize this by loading extension manifest while loading paths (though 2ms isn't a bottleneck right now)
|
|
312
|
+
// e.g.
|
|
313
|
+
// await Promise.all([getBuiltinExtensionPaths.then(getExtensionManifests), getInstalledExtensionPaths.then(getExtensionManifests)])
|
|
314
|
+
const timings = {
|
|
315
|
+
total: t4 - t1,
|
|
316
|
+
}
|
|
317
|
+
// console.log(timings)
|
|
318
|
+
return [...builtinExtensions, ...installedExtensions, ...disabledExtensions]
|
|
319
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as Command from '../Command/Command.js'
|
|
2
|
+
import * as FileSystem from './FileSystem.js'
|
|
3
|
+
|
|
4
|
+
// TODO ugly code here -> should be inside FileSystem.js
|
|
5
|
+
const fileSystemWatch = (socket, id, path) => {
|
|
6
|
+
// const watcher = FileSystem.watch(path, {
|
|
7
|
+
// onAll(...args) {
|
|
8
|
+
// socket.send(JSON.stringify([/* callback */ id, /* event */ args]))
|
|
9
|
+
|
|
10
|
+
// }
|
|
11
|
+
// }
|
|
12
|
+
// )
|
|
13
|
+
// socket.on('close', () => {
|
|
14
|
+
// watcher.close()
|
|
15
|
+
// })
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// TODO separate ipc from code like in renderer worker
|
|
19
|
+
export const __initialize__ = () => {
|
|
20
|
+
Command.register('FileSystem.readFile', FileSystem.readFile)
|
|
21
|
+
Command.register('FileSystem.writeFile', FileSystem.writeFile)
|
|
22
|
+
Command.register('FileSystem.readDirWithFileTypes', FileSystem.readDirWithFileTypes)
|
|
23
|
+
Command.register('FileSystem.remove', FileSystem.remove)
|
|
24
|
+
Command.register('FileSystem.mkdir', FileSystem.mkdir)
|
|
25
|
+
// Command.register(106, fileSystemWatch) // TODO
|
|
26
|
+
Command.register('FileSystem.createFile', FileSystem.createFile)
|
|
27
|
+
Command.register('FileSystem.createFolder', FileSystem.createFolder)
|
|
28
|
+
Command.register('FileSystem.rename', FileSystem.rename)
|
|
29
|
+
Command.register('FileSystem.ensureFile', FileSystem.ensureFile)
|
|
30
|
+
Command.register('FileSystem.copy', FileSystem.copy)
|
|
31
|
+
Command.register('FileSystem.getPathSeparator', FileSystem.getPathSeparator)
|
|
32
|
+
}
|