@lvce-editor/shared-process 0.11.4 → 0.11.6
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/config/defaultKeyBindings.json +4 -0
- package/package.json +4 -4
- package/src/parts/Cli/Cli.js +5 -2
- package/src/parts/CliInstall/CliInstall.js +2 -1
- package/src/parts/CliLink/CliLink.js +4 -2
- package/src/parts/CliUnlink/CliUnlink.js +2 -1
- package/src/parts/ClipBoard/ClipBoardGnome.js +2 -1
- package/src/parts/Developer/Developer.js +5 -3
- package/src/parts/ErrorCodes/ErrorCodes.js +12 -0
- package/src/parts/ErrorHandling/ErrorHandling.js +39 -0
- package/src/parts/ExtensionInstallFromFile/ExtensionInstallFromFile.js +2 -3
- package/src/parts/ExtensionInstallFromGitHub/ExtensionInstallFromGitHub.js +2 -2
- package/src/parts/ExtensionInstallFromUrl/ExtensionInstallFromUrl.js +3 -4
- package/src/parts/ExtensionManagement/ExtensionManagementColorTheme.js +3 -2
- package/src/parts/ExtensionManagement/ExtensionManagementIconTheme.js +2 -1
- package/src/parts/GetResponse/GetResponse.js +2 -1
- package/src/parts/Logger/Logger.js +50 -0
- package/src/parts/ParentIpc/ParentIpc.js +2 -1
- package/src/parts/PrettyError/PrettyError.js +6 -5
- package/src/parts/Process/Process.js +24 -0
- package/src/parts/RecentlyOpened/RecentlyOpened.js +2 -2
- package/src/parts/RipGrepParsedLineType/RipGrepParsedLineType.js +4 -0
- package/src/parts/Search/Search.js +26 -34
- package/src/parts/Socket/Socket.js +0 -1
- package/src/parts/SplitLines/SplitLines.js +3 -0
- package/src/parts/Stats/Stats.js +3 -3
- package/src/sharedProcessMain.js +7 -32
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lvce-editor/shared-process",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.6",
|
|
4
4
|
"description": "Utility package for @lvce-editor/server",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@babel/code-frame": "^7.18.6",
|
|
20
|
-
"@lvce-editor/extension-host": "0.11.
|
|
21
|
-
"@lvce-editor/extension-host-helper-process": "0.11.
|
|
22
|
-
"@lvce-editor/pty-host": "0.11.
|
|
20
|
+
"@lvce-editor/extension-host": "0.11.6",
|
|
21
|
+
"@lvce-editor/extension-host-helper-process": "0.11.6",
|
|
22
|
+
"@lvce-editor/pty-host": "0.11.6",
|
|
23
23
|
"debug": "^4.3.4",
|
|
24
24
|
"execa": "^6.1.0",
|
|
25
25
|
"exit-hook": "^3.1.2",
|
package/src/parts/Cli/Cli.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import * as Logger from '../Logger/Logger.js'
|
|
2
|
+
import * as Process from '../Process/Process.js'
|
|
3
|
+
|
|
1
4
|
const getModule = (argv0) => {
|
|
2
5
|
switch (argv0) {
|
|
3
6
|
case 'install':
|
|
@@ -20,7 +23,7 @@ export const handleCliArgs = async (argv, console, process) => {
|
|
|
20
23
|
try {
|
|
21
24
|
await module.handleCliArgs(argv, console, process)
|
|
22
25
|
} catch (error) {
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
Logger.error(error)
|
|
27
|
+
Process.setExitCode(1)
|
|
25
28
|
}
|
|
26
29
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as ExtensionInstall from '../ExtensionInstall/ExtensionInstall.js'
|
|
2
|
+
import * as Logger from '../Logger/Logger.js'
|
|
2
3
|
|
|
3
4
|
export const handleCliArgs = async (argv, console) => {
|
|
4
5
|
const extension = argv[1]
|
|
5
6
|
if (!extension) {
|
|
6
|
-
|
|
7
|
+
Logger.error('extension argument is required')
|
|
7
8
|
return
|
|
8
9
|
}
|
|
9
10
|
await ExtensionInstall.install(extension)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as ExtensionLink from '../ExtensionLink/ExtensionLink.js'
|
|
2
2
|
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
3
|
+
import * as Logger from '../Logger/Logger.js'
|
|
4
|
+
import * as Process from '../Process/Process.js'
|
|
3
5
|
|
|
4
6
|
export const handleCliArgs = async (argv) => {
|
|
5
7
|
try {
|
|
@@ -7,8 +9,8 @@ export const handleCliArgs = async (argv) => {
|
|
|
7
9
|
await ExtensionLink.link(path)
|
|
8
10
|
} catch (error) {
|
|
9
11
|
if (error && error.code === ErrorCodes.E_MANIFEST_NOT_FOUND) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
Logger.error(error.message)
|
|
13
|
+
Process.setExitCode(128)
|
|
12
14
|
return
|
|
13
15
|
}
|
|
14
16
|
throw error
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as ExtensionUnlink from '../ExtensionUnlink/ExtensionUnlink.js'
|
|
2
|
+
import * as Process from '../Process/Process.js'
|
|
2
3
|
|
|
3
4
|
export const handleCliArgs = async (argv, console, process) => {
|
|
4
|
-
const path = argv.length > 1 ? argv[1] :
|
|
5
|
+
const path = argv.length > 1 ? argv[1] : Process.cwd()
|
|
5
6
|
await ExtensionUnlink.unlink(path)
|
|
6
7
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import VError from 'verror'
|
|
6
6
|
import * as Exec from '../Exec/Exec.js'
|
|
7
|
+
import * as SplitLines from '../SplitLines/SplitLines.js'
|
|
7
8
|
|
|
8
9
|
const removePrefix = (file) => {
|
|
9
10
|
if (file.startsWith('file://')) {
|
|
@@ -35,7 +36,7 @@ export const readFiles = async () => {
|
|
|
35
36
|
}
|
|
36
37
|
throw error
|
|
37
38
|
}
|
|
38
|
-
const [type, ...files] = result.stdout
|
|
39
|
+
const [type, ...files] = SplitLines.splitLines(result.stdout)
|
|
39
40
|
const actualFiles = files.map(removePrefix)
|
|
40
41
|
return {
|
|
41
42
|
source: 'gnomeCopiedFiles',
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { createWriteStream, writeFileSync } from 'node:fs'
|
|
2
2
|
import { performance } from 'node:perf_hooks'
|
|
3
3
|
import * as ExtensionHost from '../ExtensionHost/ExtensionHost.js'
|
|
4
|
+
import * as Process from '../Process/Process.js'
|
|
5
|
+
import * as Timeout from '../Timeout/Timeout.js'
|
|
4
6
|
|
|
5
7
|
export const measureLatencyBetweenExtensionHostAndSharedProcess = async (
|
|
6
8
|
socket,
|
|
@@ -63,7 +65,7 @@ export const getNodeStartupTiming = () => {
|
|
|
63
65
|
|
|
64
66
|
export const sharedProcessMemoryUsage = () => {
|
|
65
67
|
// TODO also print out number of watched files
|
|
66
|
-
return
|
|
68
|
+
return Process.memoryUsage()
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
// TODO not sure if this is actually useful
|
|
@@ -76,7 +78,7 @@ export const allocateMemory = () => {
|
|
|
76
78
|
|
|
77
79
|
/* istanbul ignore next */
|
|
78
80
|
export const crashSharedProcess = () => {
|
|
79
|
-
setTimeout(() => {
|
|
81
|
+
Timeout.setTimeout(() => {
|
|
80
82
|
throw new Error('oops')
|
|
81
83
|
}, 0)
|
|
82
84
|
}
|
|
@@ -112,7 +114,7 @@ export const createProfile = async () => {
|
|
|
112
114
|
session.post('Profiler.start', () => {
|
|
113
115
|
// Invoke business logic under measurement here...
|
|
114
116
|
|
|
115
|
-
setTimeout(() => {
|
|
117
|
+
Timeout.setTimeout(() => {
|
|
116
118
|
session.post('Profiler.stop', (error, { profile }) => {
|
|
117
119
|
// Write profile to disk, upload, etc.
|
|
118
120
|
if (!error) {
|
|
@@ -7,3 +7,15 @@ export const EEXIST = 'EEXIST'
|
|
|
7
7
|
export const ENOTDIR = 'ENOTDIR'
|
|
8
8
|
|
|
9
9
|
export const E_MANIFEST_NOT_FOUND = 'E_MANIFEST_NOT_FOUND'
|
|
10
|
+
|
|
11
|
+
export const EPIPE = 'EPIPE'
|
|
12
|
+
|
|
13
|
+
export const ERR_IPC_CHANNEL_CLOSED = 'ERR_IPC_CHANNEL_CLOSED'
|
|
14
|
+
|
|
15
|
+
export const E_COLOR_THEME_NOT_FOUND = 'E_COLOR_THEME_NOT_FOUND'
|
|
16
|
+
|
|
17
|
+
export const E_ICON_THEME_NOT_FOUND = 'E_ICON_THEME_NOT_FOUND'
|
|
18
|
+
|
|
19
|
+
export const ECONNRESET = 'ECONNRESET'
|
|
20
|
+
|
|
21
|
+
export const EPERM = 'EPERM'
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
2
|
+
import * as PrettyError from '../PrettyError/PrettyError.js'
|
|
1
3
|
import * as Socket from '../Socket/Socket.js'
|
|
4
|
+
import * as Process from '../Process/Process.js'
|
|
2
5
|
|
|
3
6
|
export const state = {
|
|
4
7
|
seenErrors: [],
|
|
@@ -38,3 +41,39 @@ export const handleError = (error) => {
|
|
|
38
41
|
})
|
|
39
42
|
printPrettyError(prettyError)
|
|
40
43
|
}
|
|
44
|
+
|
|
45
|
+
// TODO handle structure: one shared process multiple extension hosts
|
|
46
|
+
|
|
47
|
+
// TODO use named functions here
|
|
48
|
+
|
|
49
|
+
const firstErrorLine = (error) => {
|
|
50
|
+
if (error.stack) {
|
|
51
|
+
return error.stack.slice(0, error.stack.indexOf('\n'))
|
|
52
|
+
}
|
|
53
|
+
if (error.message) {
|
|
54
|
+
return error.message
|
|
55
|
+
}
|
|
56
|
+
return `${error}`
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const handleUncaughtExceptionMonitor = (error, origin) => {
|
|
60
|
+
console.info(`[shared process] uncaught exception: ${firstErrorLine(error)}`)
|
|
61
|
+
if (error && error.code === ErrorCodes.EPIPE && !process.connected) {
|
|
62
|
+
// parent process is disposed, ignore
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
if (
|
|
66
|
+
error &&
|
|
67
|
+
error.code === ErrorCodes.ERR_IPC_CHANNEL_CLOSED &&
|
|
68
|
+
!Process.isConnected()
|
|
69
|
+
) {
|
|
70
|
+
// parent process is disposed, ignore
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
// console.log(error)
|
|
74
|
+
const prettyError = PrettyError.prepare(error)
|
|
75
|
+
// console.error(prettyError.message)
|
|
76
|
+
console.error(prettyError.codeFrame)
|
|
77
|
+
console.error(prettyError.stack)
|
|
78
|
+
Process.exit(1)
|
|
79
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import VError from 'verror'
|
|
2
|
-
import * as Assert from '../Assert/Assert.js'
|
|
3
2
|
import * as Extract from '../Extract/Extract.js'
|
|
4
3
|
import * as FileSystem from '../FileSystem/FileSystem.js'
|
|
4
|
+
import * as JsonFile from '../JsonFile/JsonFile.js'
|
|
5
5
|
import * as Path from '../Path/Path.js'
|
|
6
6
|
import * as Platform from '../Platform/Platform.js'
|
|
7
7
|
|
|
@@ -24,8 +24,7 @@ export const install = async ({ path }) => {
|
|
|
24
24
|
await Extract.extractTarBr(path, cachedExtensionPath)
|
|
25
25
|
const extensionsPath = Platform.getExtensionsPath()
|
|
26
26
|
const manifestPath = Path.join(cachedExtensionPath, 'extension.json')
|
|
27
|
-
const
|
|
28
|
-
const manifestJson = JSON.parse(manifestContent)
|
|
27
|
+
const manifestJson = await JsonFile.readJson(manifestPath)
|
|
29
28
|
const id = manifestJson.id
|
|
30
29
|
if (!id) {
|
|
31
30
|
throw new Error('missing id in extension manifest')
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import VError from 'verror'
|
|
2
2
|
import * as DownloadAndExtract from '../DownloadAndExtract/DownloadAndExtract.js'
|
|
3
3
|
import * as FileSystem from '../FileSystem/FileSystem.js'
|
|
4
|
+
import * as JsonFile from '../JsonFile/JsonFile.js'
|
|
4
5
|
import * as Path from '../Path/Path.js'
|
|
5
6
|
import * as Platform from '../Platform/Platform.js'
|
|
6
7
|
|
|
@@ -19,8 +20,7 @@ export const install = async ({ user, repo, branch }) => {
|
|
|
19
20
|
})
|
|
20
21
|
const extensionsPath = Platform.getExtensionsPath()
|
|
21
22
|
const manifestPath = Path.join(cachedExtensionPath, 'extension.json')
|
|
22
|
-
const
|
|
23
|
-
const manifestJson = JSON.parse(manifestContent)
|
|
23
|
+
const manifestJson = await JsonFile.readJson(manifestPath)
|
|
24
24
|
const id = manifestJson.id
|
|
25
25
|
if (!id) {
|
|
26
26
|
throw new Error('missing id in extension manifest')
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { rename, rm } from 'fs/promises'
|
|
2
2
|
import { join } from 'path'
|
|
3
3
|
import VError from 'verror'
|
|
4
4
|
import * as Download from '../Download/Download.js'
|
|
5
5
|
import * as Extract from '../Extract/Extract.js'
|
|
6
|
+
import * as JsonFile from '../JsonFile/JsonFile.js'
|
|
6
7
|
import * as Platform from '../Platform/Platform.js'
|
|
7
8
|
import * as TmpFile from '../TmpFile/TmpFile.js'
|
|
8
|
-
import * as EncodingType from '../EncodingType/EncodingType.js'
|
|
9
9
|
|
|
10
10
|
export const install = async ({ url }) => {
|
|
11
11
|
try {
|
|
@@ -18,8 +18,7 @@ export const install = async ({ url }) => {
|
|
|
18
18
|
const tmpDir = await TmpFile.getTmpDir()
|
|
19
19
|
await Extract.extractTarBr(tmpFile, tmpDir)
|
|
20
20
|
const manifestPath = join(tmpDir, 'extension.json')
|
|
21
|
-
const
|
|
22
|
-
const manifestJson = JSON.parse(manifestContent)
|
|
21
|
+
const manifestJson = await JsonFile.readJson(manifestPath)
|
|
23
22
|
const id = manifestJson.id
|
|
24
23
|
if (!id) {
|
|
25
24
|
throw new Error('missing id in extension manifest')
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import VError from 'verror'
|
|
2
2
|
import * as Error from '../Error/Error.js'
|
|
3
|
+
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
4
|
+
import * as FileSystemWatch from '../FileSystemWatch/FileSystemWatch.js'
|
|
3
5
|
import * as ReadJson from '../JsonFile/JsonFile.js'
|
|
4
6
|
import * as Path from '../Path/Path.js'
|
|
5
7
|
import * as ExtensionManagement from './ExtensionManagement.js'
|
|
6
|
-
import * as FileSystemWatch from '../FileSystemWatch/FileSystemWatch.js'
|
|
7
8
|
|
|
8
9
|
// TODO test this function
|
|
9
10
|
// TODO very similar with getIconTheme
|
|
@@ -29,7 +30,7 @@ export const getColorThemeJson = async (colorThemeId) => {
|
|
|
29
30
|
const colorThemePath = await getColorThemePath(extensions, colorThemeId)
|
|
30
31
|
if (!colorThemePath) {
|
|
31
32
|
throw new Error.OperationalError({
|
|
32
|
-
code:
|
|
33
|
+
code: ErrorCodes.E_COLOR_THEME_NOT_FOUND,
|
|
33
34
|
message: `Color theme "${colorThemeId}" not found in extensions folder`,
|
|
34
35
|
})
|
|
35
36
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import VError from 'verror'
|
|
2
2
|
import * as Error from '../Error/Error.js'
|
|
3
|
+
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
3
4
|
import * as ReadJson from '../JsonFile/JsonFile.js'
|
|
4
5
|
import * as Path from '../Path/Path.js'
|
|
5
6
|
import * as ExtensionManagement from './ExtensionManagement.js'
|
|
@@ -27,7 +28,7 @@ export const getIconTheme = async (iconThemeId) => {
|
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
throw new Error.OperationalError({
|
|
30
|
-
code:
|
|
31
|
+
code: ErrorCodes.E_ICON_THEME_NOT_FOUND,
|
|
31
32
|
message: `Icon theme "${iconThemeId}" not found in extensions folder`,
|
|
32
33
|
})
|
|
33
34
|
}
|
|
@@ -32,6 +32,7 @@ export const getResponse = async (message, handle) => {
|
|
|
32
32
|
},
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
+
// @ts-ignore
|
|
35
36
|
if (error && error instanceof Error && error.code === ErrorCodes.ENOENT) {
|
|
36
37
|
return {
|
|
37
38
|
jsonrpc: JsonRpc.Version,
|
|
@@ -43,7 +44,7 @@ export const getResponse = async (message, handle) => {
|
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
const prettyError = PrettyError.prepare(error)
|
|
46
|
-
PrettyError.print(prettyError)
|
|
47
|
+
PrettyError.print(prettyError, `[shared-process] `)
|
|
47
48
|
return {
|
|
48
49
|
jsonrpc: JsonRpc.Version,
|
|
49
50
|
id: message.id,
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Console } from 'node:console'
|
|
2
|
+
import { createWriteStream } from 'node:fs'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
4
|
+
|
|
5
|
+
// TODO mock this module when used in unit tests
|
|
6
|
+
|
|
7
|
+
const state = {
|
|
8
|
+
/**
|
|
9
|
+
* @type {Console|undefined}
|
|
10
|
+
*/
|
|
11
|
+
console: undefined,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const createConsole = () => {
|
|
15
|
+
const logFile = `${tmpdir()}/log-shared-process.txt`
|
|
16
|
+
const writeStream = createWriteStream(logFile)
|
|
17
|
+
const logger = new Console(writeStream)
|
|
18
|
+
return logger
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const getOrCreateLogger = () => {
|
|
22
|
+
if (!state.console) {
|
|
23
|
+
state.console = createConsole()
|
|
24
|
+
}
|
|
25
|
+
return state.console
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const log = (...args) => {
|
|
29
|
+
const logger = getOrCreateLogger()
|
|
30
|
+
logger.log(...args)
|
|
31
|
+
console.log(...args)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const info = (...args) => {
|
|
35
|
+
const logger = getOrCreateLogger()
|
|
36
|
+
logger.info(...args)
|
|
37
|
+
console.info(...args)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const warn = (...args) => {
|
|
41
|
+
const logger = getOrCreateLogger()
|
|
42
|
+
logger.warn(...args)
|
|
43
|
+
console.warn(...args)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const error = (...args) => {
|
|
47
|
+
const logger = getOrCreateLogger()
|
|
48
|
+
logger.error(...args)
|
|
49
|
+
console.error(...args)
|
|
50
|
+
}
|
|
@@ -3,6 +3,7 @@ import VError from 'verror'
|
|
|
3
3
|
import * as Callback from '../Callback/Callback.js'
|
|
4
4
|
import * as Command from '../Command/Command.js'
|
|
5
5
|
import * as Debug from '../Debug/Debug.js'
|
|
6
|
+
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
6
7
|
import * as ExtensionHostHelperProcessIpc from '../ExtensionHostHelperProcessIpc/ExtensionHostHelperProcessIpc.js'
|
|
7
8
|
import * as ExtensionHostIpc from '../ExtensionHostIpc/ExtensionHostIpc.js'
|
|
8
9
|
import * as ExtensionHostRpc from '../ExtensionHostRpc/ExtensionHostRpc.js'
|
|
@@ -36,7 +37,7 @@ export const electronSend = (message) => {
|
|
|
36
37
|
const handleWebSocketSharedProcess = (message, handle) => {
|
|
37
38
|
// TODO when it is an extension host websocket, spawn extension host
|
|
38
39
|
handle.on('error', (error) => {
|
|
39
|
-
if (error && error.code ===
|
|
40
|
+
if (error && error.code === ErrorCodes.ECONNRESET) {
|
|
40
41
|
return
|
|
41
42
|
}
|
|
42
43
|
console.info('[info shared process: handle error]', error)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs'
|
|
2
|
-
import { fileURLToPath } from 'node:url'
|
|
3
1
|
import { codeFrameColumns } from '@babel/code-frame'
|
|
4
2
|
import cleanStack from 'clean-stack'
|
|
5
3
|
import { LinesAndColumns } from 'lines-and-columns'
|
|
4
|
+
import { readFileSync } from 'node:fs'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
import * as SplitLines from '../SplitLines/SplitLines.js'
|
|
6
7
|
|
|
7
8
|
const getActualPath = (fileUri) => {
|
|
8
9
|
if (fileUri.startsWith('file://')) {
|
|
@@ -20,7 +21,7 @@ export const prepare = (error) => {
|
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
23
|
const cleanedStack = cleanStack(error.stack)
|
|
23
|
-
const lines =
|
|
24
|
+
const lines = SplitLines.splitLines(cleanedStack)
|
|
24
25
|
const file = lines[1]
|
|
25
26
|
let codeFrame = ''
|
|
26
27
|
if (error.codeFrame) {
|
|
@@ -82,8 +83,8 @@ export const prepareJsonError = (json, property, message) => {
|
|
|
82
83
|
return jsonError
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
export const print = (prettyError) => {
|
|
86
|
+
export const print = (prettyError, prefix = '') => {
|
|
86
87
|
console.error(
|
|
87
|
-
|
|
88
|
+
`${prefix}Error: ${prettyError.message}\n\n${prettyError.codeFrame}\n\n${prettyError.stack}`
|
|
88
89
|
)
|
|
89
90
|
}
|
|
@@ -5,3 +5,27 @@ export const crash = (message) => {
|
|
|
5
5
|
export const crashAsync = async (message) => {
|
|
6
6
|
throw new Error(message)
|
|
7
7
|
}
|
|
8
|
+
|
|
9
|
+
export const exit = (code) => {
|
|
10
|
+
process.exit(code)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const setExitCode = (exitCode) => {
|
|
14
|
+
process.exitCode = exitCode
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const argv = process.argv
|
|
18
|
+
|
|
19
|
+
export const cwd = () => {
|
|
20
|
+
return process.cwd()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const memoryUsage = () => {
|
|
24
|
+
return process.memoryUsage()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const isConnected = () => {
|
|
28
|
+
return process.connected
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const platform = process.platform
|
|
@@ -4,6 +4,7 @@ import * as Assert from '../Assert/Assert.js'
|
|
|
4
4
|
import { FileNotFoundError } from '../Error/FileNotFoundError.js'
|
|
5
5
|
import * as FileSystem from '../FileSystem/FileSystem.js'
|
|
6
6
|
import * as Json from '../Json/Json.js'
|
|
7
|
+
import * as JsonFile from '../JsonFile/JsonFile.js'
|
|
7
8
|
import * as Platform from '../Platform/Platform.js'
|
|
8
9
|
|
|
9
10
|
const isValid = (recentlyOpened) => {
|
|
@@ -24,8 +25,7 @@ const addToArrayUnique = (recentlyOpened, path) => {
|
|
|
24
25
|
|
|
25
26
|
const getRecentlyOpened = async (recentlyOpenedPath) => {
|
|
26
27
|
try {
|
|
27
|
-
const
|
|
28
|
-
const parsed = await Json.parse(content, recentlyOpenedPath)
|
|
28
|
+
const parsed = await JsonFile.readJson(recentlyOpenedPath)
|
|
29
29
|
return parsed
|
|
30
30
|
} catch (error) {
|
|
31
31
|
// TODO should check for error.code
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process'
|
|
2
|
-
import * as RgPath from '../RgPath/RgPath.js'
|
|
3
2
|
import * as Platform from '../Platform/Platform.js'
|
|
3
|
+
import * as RgPath from '../RgPath/RgPath.js'
|
|
4
|
+
import * as RipGrepParsedLineType from '../RipGrepParsedLineType/RipGrepParsedLineType.js'
|
|
5
|
+
import * as SplitLines from '../SplitLines/SplitLines.js'
|
|
4
6
|
|
|
5
7
|
const MAX_SEARCH_RESULTS = 300
|
|
6
8
|
|
|
@@ -25,64 +27,51 @@ const useNice = !Platform.isWindows
|
|
|
25
27
|
// TODO update client
|
|
26
28
|
// TODO not always run nice, maybe configure nice via flag/options
|
|
27
29
|
|
|
28
|
-
const ParsedLineType = {
|
|
29
|
-
Begin: 'begin',
|
|
30
|
-
Match: 'match',
|
|
31
|
-
Summary: 'summary',
|
|
32
|
-
}
|
|
33
|
-
|
|
34
30
|
export const search = async (searchDir, searchString) => {
|
|
35
31
|
// TODO reject promise when ripgrep search fails
|
|
36
32
|
return new Promise((resolve, reject) => {
|
|
33
|
+
const ripGrepArgs = [
|
|
34
|
+
'--smart-case',
|
|
35
|
+
'--stats',
|
|
36
|
+
'--json',
|
|
37
|
+
'--fixed-strings',
|
|
38
|
+
searchString,
|
|
39
|
+
'.',
|
|
40
|
+
]
|
|
37
41
|
const childProcess = useNice
|
|
38
|
-
? spawn(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
'--stats',
|
|
45
|
-
'--json',
|
|
46
|
-
searchString,
|
|
47
|
-
'.',
|
|
48
|
-
],
|
|
49
|
-
{
|
|
50
|
-
cwd: searchDir,
|
|
51
|
-
}
|
|
52
|
-
)
|
|
53
|
-
: spawn(
|
|
54
|
-
RgPath.rgPath,
|
|
55
|
-
['--smart-case', '--stats', '--json', searchString, '.'],
|
|
56
|
-
{
|
|
57
|
-
cwd: searchDir,
|
|
58
|
-
}
|
|
59
|
-
)
|
|
42
|
+
? spawn('nice', ['-20', RgPath.rgPath, ...ripGrepArgs], {
|
|
43
|
+
cwd: searchDir,
|
|
44
|
+
})
|
|
45
|
+
: spawn(RgPath.rgPath, ripGrepArgs, {
|
|
46
|
+
cwd: searchDir,
|
|
47
|
+
})
|
|
60
48
|
const allSearchResults = Object.create(null)
|
|
61
49
|
let buffer = ''
|
|
62
50
|
let stats = {}
|
|
51
|
+
let limitHit = false
|
|
63
52
|
let numberOfResults = 0
|
|
64
53
|
// TODO use pipeline / transform stream maybe
|
|
65
54
|
|
|
66
55
|
const handleData = (chunk) => {
|
|
67
56
|
buffer += chunk
|
|
68
|
-
const lines =
|
|
57
|
+
const lines = SplitLines.splitLines(buffer)
|
|
69
58
|
// @ts-ignore
|
|
70
59
|
buffer = lines.pop()
|
|
71
60
|
for (const line of lines) {
|
|
72
61
|
const parsedLine = JSON.parse(line)
|
|
62
|
+
console.log(parsedLine)
|
|
73
63
|
switch (parsedLine.type) {
|
|
74
|
-
case
|
|
64
|
+
case RipGrepParsedLineType.Begin: {
|
|
75
65
|
allSearchResults[parsedLine.data.path.text] = []
|
|
76
66
|
break
|
|
77
67
|
}
|
|
78
|
-
case
|
|
68
|
+
case RipGrepParsedLineType.Match:
|
|
79
69
|
numberOfResults++
|
|
80
70
|
allSearchResults[parsedLine.data.path.text].push(
|
|
81
71
|
toSearchResult(parsedLine)
|
|
82
72
|
)
|
|
83
73
|
break
|
|
84
|
-
|
|
85
|
-
case ParsedLineType.Summary:
|
|
74
|
+
case RipGrepParsedLineType.Summary:
|
|
86
75
|
stats = parsedLine.data
|
|
87
76
|
break
|
|
88
77
|
default:
|
|
@@ -90,6 +79,7 @@ export const search = async (searchDir, searchString) => {
|
|
|
90
79
|
}
|
|
91
80
|
}
|
|
92
81
|
if (numberOfResults > MAX_SEARCH_RESULTS) {
|
|
82
|
+
limitHit = true
|
|
93
83
|
childProcess.kill()
|
|
94
84
|
}
|
|
95
85
|
}
|
|
@@ -98,6 +88,7 @@ export const search = async (searchDir, searchString) => {
|
|
|
98
88
|
resolve({
|
|
99
89
|
results: Object.entries(allSearchResults),
|
|
100
90
|
stats,
|
|
91
|
+
limitHit,
|
|
101
92
|
})
|
|
102
93
|
}
|
|
103
94
|
const handleError = (error) => {
|
|
@@ -106,6 +97,7 @@ export const search = async (searchDir, searchString) => {
|
|
|
106
97
|
resolve({
|
|
107
98
|
results: [],
|
|
108
99
|
stats,
|
|
100
|
+
limitHit,
|
|
109
101
|
})
|
|
110
102
|
}
|
|
111
103
|
childProcess.stdout.on('data', handleData)
|
package/src/parts/Stats/Stats.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// parse ps output based on vscode https://github.com/microsoft/vscode/blob/c0769274fa136b45799edeccc0d0a2f645b75caf/src/vs/base/node/ps.ts (License MIT)
|
|
2
2
|
|
|
3
3
|
import * as Exec from '../Exec/Exec.js'
|
|
4
|
+
import * as SplitLines from '../SplitLines/SplitLines.js'
|
|
4
5
|
|
|
5
|
-
const PID_CMD =
|
|
6
|
-
/^\s*(\d+)\s+(\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(.+)$/
|
|
6
|
+
const PID_CMD = /^\s*(\d+)\s+(\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(.+)$/
|
|
7
7
|
|
|
8
8
|
const parsePsOutputLine = (line) => {
|
|
9
9
|
const matches = PID_CMD.exec(line.trim())
|
|
@@ -18,7 +18,7 @@ const parsePsOutputLine = (line) => {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
const parsePsOutput = (stdout, rootPid) => {
|
|
21
|
-
const lines =
|
|
21
|
+
const lines = SplitLines.splitLines(stdout)
|
|
22
22
|
return lines.map(parsePsOutputLine)
|
|
23
23
|
}
|
|
24
24
|
|
package/src/sharedProcessMain.js
CHANGED
|
@@ -1,40 +1,12 @@
|
|
|
1
1
|
import * as Command from './parts/Command/Command.js'
|
|
2
|
+
import * as ErrorHandling from './parts/ErrorHandling/ErrorHandling.js'
|
|
2
3
|
import * as Module from './parts/Module/Module.js'
|
|
3
4
|
import * as ParentIpc from './parts/ParentIpc/ParentIpc.js'
|
|
4
|
-
import * as
|
|
5
|
-
|
|
5
|
+
import * as Process from './parts/Process/Process.js'
|
|
6
6
|
// TODO handle structure: one shared process multiple extension hosts
|
|
7
7
|
|
|
8
8
|
// TODO use named functions here
|
|
9
9
|
|
|
10
|
-
const firstErrorLine = (error) => {
|
|
11
|
-
if (error.stack) {
|
|
12
|
-
return error.stack.slice(0, error.stack.indexOf('\n'))
|
|
13
|
-
}
|
|
14
|
-
if (error.message) {
|
|
15
|
-
return error.message
|
|
16
|
-
}
|
|
17
|
-
return `${error}`
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const handleUncaughtExceptionMonitor = (error, origin) => {
|
|
21
|
-
console.info(`[shared process] uncaught exception: ${firstErrorLine(error)}`)
|
|
22
|
-
if (error && error.code === 'EPIPE' && !process.connected) {
|
|
23
|
-
// parent process is disposed, ignore
|
|
24
|
-
return
|
|
25
|
-
}
|
|
26
|
-
if (error && error.code === 'ERR_IPC_CHANNEL_CLOSED' && !process.connected) {
|
|
27
|
-
// parent process is disposed, ignore
|
|
28
|
-
return
|
|
29
|
-
}
|
|
30
|
-
// console.log(error)
|
|
31
|
-
const prettyError = PrettyError.prepare(error)
|
|
32
|
-
// console.error(prettyError.message)
|
|
33
|
-
console.error(prettyError.codeFrame)
|
|
34
|
-
console.error(prettyError.stack)
|
|
35
|
-
process.exit(1)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
10
|
const handleDisconnect = () => {
|
|
39
11
|
console.info('[shared process] disconnected')
|
|
40
12
|
}
|
|
@@ -51,7 +23,7 @@ const knownCliArgs = ['install', 'list', 'link', 'unlink']
|
|
|
51
23
|
|
|
52
24
|
const main = async () => {
|
|
53
25
|
Command.setLoad(Module.load)
|
|
54
|
-
const argv =
|
|
26
|
+
const argv = Process.argv.slice(2)
|
|
55
27
|
const argv0 = argv[0]
|
|
56
28
|
if (knownCliArgs.includes(argv0)) {
|
|
57
29
|
const module = await import('./parts/Cli/Cli.js')
|
|
@@ -64,7 +36,10 @@ const main = async () => {
|
|
|
64
36
|
process.on('disconnect', handleDisconnect)
|
|
65
37
|
process.on('SIGTERM', handleSigTerm)
|
|
66
38
|
|
|
67
|
-
process.on(
|
|
39
|
+
process.on(
|
|
40
|
+
'uncaughtExceptionMonitor',
|
|
41
|
+
ErrorHandling.handleUncaughtExceptionMonitor
|
|
42
|
+
)
|
|
68
43
|
ParentIpc.listen()
|
|
69
44
|
|
|
70
45
|
// ExtensionHost.start() // TODO start on demand, e.g. not when extensions should be disabled
|