@lvce-editor/shared-process 0.12.1 → 0.14.0
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 +30 -0
- package/config/defaultSettings.json +6 -0
- package/extensions/builtin.language-basics-css/extension.json +2 -1
- package/extensions/builtin.language-basics-css/languageConfiguration.json +21 -0
- package/extensions/builtin.language-basics-css/src/tokenizeCss.js +7 -1
- package/extensions/builtin.language-basics-html/src/tokenizeHtml.js +77 -27
- package/extensions/builtin.language-basics-javascript/src/tokenizeJavaScript.js +29 -1
- package/extensions/builtin.language-basics-json/extension.json +4 -2
- package/extensions/builtin.language-basics-json/src/tokenizeJson.js +3 -0
- package/extensions/builtin.language-basics-jsx/src/tokenizeJsx.js +18 -5
- package/extensions/builtin.language-basics-vue/src/tokenizeVue.js +1 -1
- package/extensions/builtin.language-basics-xml/extension.json +3 -1
- package/package.json +9 -10
- package/src/parts/Assert/Assert.js +1 -6
- package/src/parts/AssertionError/AssertionError.js +6 -0
- package/src/parts/BulkReplacement/BulkReplacement.ipc.js +7 -0
- package/src/parts/BulkReplacement/BulkReplacement.js +20 -0
- package/src/parts/BulkReplacementContent/BulkReplacementContent.js +30 -0
- package/src/parts/ChildProcessError/ChildProcessError.js +45 -0
- package/src/parts/ChromeExtension/ChromeExtension.js +2 -5
- package/src/parts/CleanStack/CleanStack.js +90 -2
- package/src/parts/CliList/CliList.js +3 -0
- package/src/parts/ClipBoard/ClipBoard.js +2 -2
- package/src/parts/ClipBoard/ClipBoardGnome.js +1 -2
- package/src/parts/ClipBoard/ClipBoardNoop.js +2 -2
- package/src/parts/ClipBoard/ClipBoardWindows.js +1 -3
- package/src/parts/Command/Command.js +5 -10
- package/src/parts/Credentials/Credentials.ipc.js +5 -5
- package/src/parts/Credentials/Credentials.js +2 -10
- package/src/parts/Desktop/Desktop.js +22 -0
- package/src/parts/Download/Download.js +2 -2
- package/src/parts/Error/Error.js +1 -1
- package/src/parts/ErrorCodes/ErrorCodes.js +2 -1
- package/src/parts/ErrorHandling/ErrorHandling.js +8 -14
- package/src/parts/ExtensionHost/ExtensionHost.js +1 -2
- package/src/parts/ExtensionHost/ExtensionHostKeyBindings.js +0 -12
- package/src/parts/ExtensionHostRpc/ExtensionHostRpc.js +1 -1
- package/src/parts/ExtensionInstallFromFile/ExtensionInstallFromFile.js +1 -1
- package/src/parts/ExtensionInstallFromGitHub/ExtensionInstallFromGitHub.js +1 -1
- package/src/parts/ExtensionInstallFromUrl/ExtensionInstallFromUrl.js +1 -1
- package/src/parts/ExtensionLink/ExtensionLink.js +0 -19
- package/src/parts/ExtensionList/ExtensionList.js +11 -2
- package/src/parts/ExtensionManagement/ExtensionManagement.js +6 -58
- package/src/parts/ExtensionManagement/ExtensionManagementColorTheme.js +3 -1
- package/src/parts/ExtensionManagement/ExtensionManagementIconTheme.js +1 -1
- package/src/parts/ExtensionManagement/ExtensionManagementLanguages.js +7 -3
- package/src/parts/ExtensionManifestInputType/ExtensionManifestInputType.js +2 -0
- package/src/parts/ExtensionManifests/ExtensionManifests.js +3 -0
- package/src/parts/ExtensionManifests/ExtensionManifestsFromFolder.js +5 -15
- package/src/parts/ExtensionManifests/ExtensionManifestsFromLinkedExtensionsFolder.js +56 -0
- package/src/parts/ExtensionUninstall/ExtensionUninstall.js +18 -0
- package/src/parts/ExtensionUnlink/ExtensionUnlink.js +1 -1
- package/src/parts/Extract/Extract.js +2 -6
- package/src/parts/ExtractZip/ExtractZip.js +1 -1
- package/src/parts/{Error → FileNotFoundError}/FileNotFoundError.js +9 -2
- package/src/parts/FileSystem/FileSystem.js +6 -32
- package/src/parts/FirstNodeWorkerEventType/FirstNodeWorkerEventType.js +5 -0
- package/src/parts/GetDirentType/GetDirentType.js +27 -0
- package/src/parts/GetFirstNodeChildProcessEvent/GetFirstNodeChildProcessEvent.js +39 -0
- package/src/parts/GetFirstNodeWorkerEvent/GetFirstNodeWorkerEvent.js +21 -0
- package/src/parts/GetNewLineIndex/GetNewLineIndex.js +9 -0
- package/src/parts/GetResponse/GetResponse.js +16 -6
- package/src/parts/GetTextSearchRipGrepArgs/GetTextSearchRipGrepArgs.js +14 -0
- package/src/parts/InstallExtension/InstallExtension.ipc.js +6 -0
- package/src/parts/InstallExtension/InstallExtension.js +33 -0
- package/src/parts/IpcParent/IpcParent.js +9 -0
- package/src/parts/IpcParentModule/IpcParentModule.js +12 -0
- package/src/parts/IpcParentType/IpcParentType.js +2 -0
- package/src/parts/IpcParentWithNodeForkedProcess/IpcParentWithNodeForkedProcess.js +49 -0
- package/src/parts/IpcParentWithNodeWorker/IpcParentWithNodeWorker.js +36 -0
- package/src/parts/IsEnoentErrorWindows/IsEnoentErrorWindows.js +3 -0
- package/src/parts/IsIgnoredError/IsIgnoredError.js +14 -0
- package/src/parts/Json/Json.js +3 -5
- package/src/parts/JsonError/JsonError.js +8 -14
- package/src/parts/JsonParsingError/JsonParsingError.js +17 -0
- package/src/parts/Jsonc/Jsonc.js +304 -0
- package/src/parts/JsoncCharCode/JsoncCharCode.js +23 -0
- package/src/parts/JsoncFile/JsoncFile.js +8 -0
- package/src/parts/JsoncTokenType/JsoncTokenType.js +11 -0
- package/src/parts/LimitString/LimitString.js +3 -1
- package/src/parts/MergeStacks/MergeStacks.js +3 -2
- package/src/parts/Module/Module.js +4 -0
- package/src/parts/ModuleId/ModuleId.js +2 -0
- package/src/parts/ModuleMap/ModuleMap.js +4 -0
- package/src/parts/Native/Native.js +1 -1
- package/src/parts/ParentIpc/ParentIpc.js +2 -1
- package/src/parts/Platform/Platform.js +0 -21
- package/src/parts/Preferences/Preferences.js +6 -8
- package/src/parts/PrettyError/PrettyError.js +16 -7
- package/src/parts/PrintPrettyError/PrintPrettyError.js +3 -1
- package/src/parts/RecentlyOpened/RecentlyOpened.js +3 -7
- package/src/parts/RequiresSocket/RequiresSocket.js +1 -0
- package/src/parts/RipGrep/RipGrep.js +1 -1
- package/src/parts/SearchFile/SearchFile.js +4 -9
- package/src/parts/Socket/Socket.js +2 -7
- package/src/parts/Terminal/Terminal.ipc.js +4 -41
- package/src/parts/Terminal/Terminal.js +29 -25
- package/src/parts/TextSearch/TextSearch.js +102 -108
- package/src/parts/ToAbsolutePaths/ToAbsolutePaths.js +9 -0
- package/src/parts/ToTextSearchResult/ToTextSearchResult.js +42 -0
- package/src/parts/Trash/Trash.js +1 -2
- /package/src/parts/{RgPath/RgPath.js → RipGrepPath/RipGrepPath.js} +0 -0
|
@@ -2,7 +2,9 @@ import { codeFrameColumns } from '@babel/code-frame'
|
|
|
2
2
|
import { LinesAndColumns } from 'lines-and-columns'
|
|
3
3
|
import { readFileSync } from 'node:fs'
|
|
4
4
|
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { AssertionError } from '../AssertionError/AssertionError.js'
|
|
5
6
|
import * as CleanStack from '../CleanStack/CleanStack.js'
|
|
7
|
+
import * as EncodingType from '../EncodingType/EncodingType.js'
|
|
6
8
|
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
7
9
|
import * as JoinLines from '../JoinLines/JoinLines.js'
|
|
8
10
|
import * as Json from '../Json/Json.js'
|
|
@@ -29,7 +31,7 @@ const prepareModuleNotFoundError = (error) => {
|
|
|
29
31
|
}
|
|
30
32
|
const notFoundModule = match[1]
|
|
31
33
|
const importedFrom = match[2]
|
|
32
|
-
const rawLines = readFileSync(importedFrom,
|
|
34
|
+
const rawLines = readFileSync(importedFrom, EncodingType.Utf8)
|
|
33
35
|
let line = 0
|
|
34
36
|
let column = 0
|
|
35
37
|
const splittedLines = SplitLines.splitLines(rawLines)
|
|
@@ -59,6 +61,13 @@ const prepareModuleNotFoundError = (error) => {
|
|
|
59
61
|
}
|
|
60
62
|
}
|
|
61
63
|
|
|
64
|
+
const getStackLinesToCut = (error) => {
|
|
65
|
+
if (error instanceof AssertionError) {
|
|
66
|
+
return 1
|
|
67
|
+
}
|
|
68
|
+
return 0
|
|
69
|
+
}
|
|
70
|
+
|
|
62
71
|
export const prepare = (error) => {
|
|
63
72
|
if (error && error.code === ErrorCodes.ERR_MODULE_NOT_FOUND) {
|
|
64
73
|
return prepareModuleNotFoundError(error)
|
|
@@ -70,9 +79,9 @@ export const prepare = (error) => {
|
|
|
70
79
|
error = cause
|
|
71
80
|
}
|
|
72
81
|
}
|
|
73
|
-
const
|
|
74
|
-
const lines =
|
|
75
|
-
const file = lines[
|
|
82
|
+
const linesToCut = getStackLinesToCut(error)
|
|
83
|
+
const lines = CleanStack.cleanStack(error.stack).slice(linesToCut)
|
|
84
|
+
const file = lines[0]
|
|
76
85
|
let codeFrame = ''
|
|
77
86
|
if (error.codeFrame) {
|
|
78
87
|
codeFrame = error.codeFrame
|
|
@@ -84,22 +93,22 @@ export const prepare = (error) => {
|
|
|
84
93
|
if (match) {
|
|
85
94
|
const [_, path, line, column] = match
|
|
86
95
|
const actualPath = getActualPath(path)
|
|
87
|
-
const rawLines = readFileSync(actualPath,
|
|
96
|
+
const rawLines = readFileSync(actualPath, EncodingType.Utf8)
|
|
88
97
|
const location = {
|
|
89
98
|
start: {
|
|
90
99
|
line: Number.parseInt(line),
|
|
91
100
|
column: Number.parseInt(column),
|
|
92
101
|
},
|
|
93
102
|
}
|
|
94
|
-
|
|
95
103
|
codeFrame = codeFrameColumns(rawLines, location)
|
|
96
104
|
}
|
|
97
105
|
}
|
|
98
|
-
const relevantStack = JoinLines.joinLines(lines
|
|
106
|
+
const relevantStack = JoinLines.joinLines(lines)
|
|
99
107
|
return {
|
|
100
108
|
message,
|
|
101
109
|
stack: relevantStack,
|
|
102
110
|
codeFrame,
|
|
111
|
+
type: error.constructor.name,
|
|
103
112
|
}
|
|
104
113
|
}
|
|
105
114
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as Logger from '../Logger/Logger.js'
|
|
2
|
+
|
|
1
3
|
export const printPrettyError = (prettyError, prefix = '') => {
|
|
2
|
-
|
|
4
|
+
Logger.error(`${prefix}${prettyError.type}: ${prettyError.message}\n\n${prettyError.codeFrame}\n\n${prettyError.stack}\n`)
|
|
3
5
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { dirname } from 'node:path'
|
|
2
|
-
import VError from 'verror'
|
|
3
2
|
import * as Assert from '../Assert/Assert.js'
|
|
4
|
-
import { FileNotFoundError } from '../
|
|
3
|
+
import { FileNotFoundError } from '../FileNotFoundError/FileNotFoundError.js'
|
|
5
4
|
import * as FileSystem from '../FileSystem/FileSystem.js'
|
|
6
5
|
import * as Json from '../Json/Json.js'
|
|
7
6
|
import * as JsonFile from '../JsonFile/JsonFile.js'
|
|
8
7
|
import * as Platform from '../Platform/Platform.js'
|
|
8
|
+
import { VError } from '../VError/VError.js'
|
|
9
9
|
|
|
10
10
|
const isValid = (recentlyOpened) => {
|
|
11
11
|
return recentlyOpened && Array.isArray(recentlyOpened)
|
|
@@ -16,11 +16,7 @@ const addToArrayUnique = (recentlyOpened, path) => {
|
|
|
16
16
|
if (index === -1) {
|
|
17
17
|
return [path, ...recentlyOpened]
|
|
18
18
|
}
|
|
19
|
-
return [
|
|
20
|
-
path,
|
|
21
|
-
...recentlyOpened.slice(0, index),
|
|
22
|
-
...recentlyOpened.slice(index + 1),
|
|
23
|
-
]
|
|
19
|
+
return [path, ...recentlyOpened.slice(0, index), ...recentlyOpened.slice(index + 1)]
|
|
24
20
|
}
|
|
25
21
|
|
|
26
22
|
const getRecentlyOpened = async (recentlyOpenedPath) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as NodeChildProcess from 'node:child_process'
|
|
2
2
|
import * as Assert from '../Assert/Assert.js'
|
|
3
3
|
import * as Exec from '../Exec/Exec.js'
|
|
4
|
-
import * as RgPath from '../
|
|
4
|
+
import * as RgPath from '../RipGrepPath/RipGrepPath.js'
|
|
5
5
|
|
|
6
6
|
export const ripGrepPath = process.env.RIP_GREP_PATH || RgPath.rgPath
|
|
7
7
|
|
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
import * as Assert from '../Assert/Assert.js'
|
|
2
2
|
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
3
|
+
import * as IsEnoentErrorWindows from '../IsEnoentErrorWindows/IsEnoentErrorWindows.js'
|
|
3
4
|
import * as LimitString from '../LimitString/LimitString.js'
|
|
4
|
-
import * as RipGrep from '../RipGrep/RipGrep.js'
|
|
5
5
|
import * as Logger from '../Logger/Logger.js'
|
|
6
|
+
import * as RipGrep from '../RipGrep/RipGrep.js'
|
|
6
7
|
|
|
7
8
|
const isEnoentErrorLinux = (error) => {
|
|
8
9
|
return error.code === ErrorCodes.ENOENT
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
const isEnoentErrorWindows = (error) => {
|
|
12
|
-
return error.message.includes('The system cannot find the path specified.')
|
|
13
|
-
}
|
|
14
|
-
|
|
15
12
|
const isEnoentError = (error) => {
|
|
16
13
|
if (!error) {
|
|
17
14
|
return false
|
|
18
15
|
}
|
|
19
|
-
return isEnoentErrorLinux(error) || isEnoentErrorWindows(error)
|
|
16
|
+
return isEnoentErrorLinux(error) || IsEnoentErrorWindows.isEnoentErrorWindows(error)
|
|
20
17
|
}
|
|
21
18
|
|
|
22
19
|
// TODO don't necessarily need ripgrep to list all the files,
|
|
@@ -37,9 +34,7 @@ export const searchFile = async (path, searchTerm, limit) => {
|
|
|
37
34
|
} catch (error) {
|
|
38
35
|
// @ts-ignore
|
|
39
36
|
if (isEnoentError(error)) {
|
|
40
|
-
Logger.info(
|
|
41
|
-
`[shared-process] ripgrep could not be found at "${RipGrep.ripGrepPath}"`
|
|
42
|
-
)
|
|
37
|
+
Logger.info(`[shared-process] ripgrep could not be found at "${RipGrep.ripGrepPath}"`)
|
|
43
38
|
return ``
|
|
44
39
|
}
|
|
45
40
|
// @ts-ignore
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import VError from 'verror'
|
|
2
1
|
import * as Command from '../Command/Command.js'
|
|
3
2
|
import * as GetResponse from '../GetResponse/GetResponse.js'
|
|
3
|
+
import { VError } from '../VError/VError.js'
|
|
4
4
|
|
|
5
5
|
export const state = {
|
|
6
6
|
/**
|
|
@@ -21,12 +21,7 @@ const handleMessage = async (event) => {
|
|
|
21
21
|
const object = JSON.parse(event.data)
|
|
22
22
|
if (object.id) {
|
|
23
23
|
if (!object.params) {
|
|
24
|
-
console.warn(
|
|
25
|
-
'[shared-process] invalid message 1',
|
|
26
|
-
typeof object,
|
|
27
|
-
object.params,
|
|
28
|
-
object
|
|
29
|
-
)
|
|
24
|
+
console.warn('[shared-process] invalid message 1', typeof object, object.params, object)
|
|
30
25
|
return
|
|
31
26
|
}
|
|
32
27
|
const response = await GetResponse.getResponse(object, state.socket)
|
|
@@ -1,47 +1,10 @@
|
|
|
1
|
-
import * as Command from '../Command/Command.js'
|
|
2
|
-
import * as Assert from '../Assert/Assert.js'
|
|
3
1
|
import * as Terminal from './Terminal.js'
|
|
4
2
|
|
|
5
|
-
const create = (socket, id, cwd) => {
|
|
6
|
-
Assert.object(socket)
|
|
7
|
-
if (!socket) {
|
|
8
|
-
console.log({ socket, id, cwd })
|
|
9
|
-
console.warn('socket not available')
|
|
10
|
-
return
|
|
11
|
-
}
|
|
12
|
-
// terminalMap[id] = Terminal.create({
|
|
13
|
-
// handleData(data) {
|
|
14
|
-
// socket.send(
|
|
15
|
-
// JSON.stringify({
|
|
16
|
-
// jsonrpc: '2.0',
|
|
17
|
-
// method: 2133,
|
|
18
|
-
// params: ['Terminal', 'handleData', data],
|
|
19
|
-
// })
|
|
20
|
-
// )
|
|
21
|
-
// },
|
|
22
|
-
// cwd,
|
|
23
|
-
// })
|
|
24
|
-
Terminal.create(socket, id, cwd)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const write = (id, input) => {
|
|
28
|
-
console.log({ id, input })
|
|
29
|
-
Terminal.write(id, input)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const resize = (socket, id, columns, rows) => {
|
|
33
|
-
Terminal.resize(id, columns, rows)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const dispose = (socket, id) => {
|
|
37
|
-
Terminal.dispose(id)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
3
|
export const name = 'Terminal'
|
|
41
4
|
|
|
42
5
|
export const Commands = {
|
|
43
|
-
create: create,
|
|
44
|
-
dispose: dispose,
|
|
45
|
-
resize: resize,
|
|
46
|
-
write: write,
|
|
6
|
+
create: Terminal.create,
|
|
7
|
+
dispose: Terminal.dispose,
|
|
8
|
+
resize: Terminal.resize,
|
|
9
|
+
write: Terminal.write,
|
|
47
10
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import exitHook from 'exit-hook'
|
|
2
|
-
import { ChildProcess, fork } from 'node:child_process'
|
|
3
2
|
import * as Assert from '../Assert/Assert.js'
|
|
4
3
|
import * as Debug from '../Debug/Debug.js'
|
|
5
|
-
import * as
|
|
4
|
+
import * as IpcParent from '../IpcParent/IpcParent.js'
|
|
5
|
+
import * as IpcParentType from '../IpcParentType/IpcParentType.js'
|
|
6
6
|
import * as JsonRpcVersion from '../JsonRpcVersion/JsonRpcVersion.js'
|
|
7
|
+
import * as PtyHostPath from '../PtyHostPath/PtyHostPath.js'
|
|
7
8
|
|
|
8
9
|
export const state = {
|
|
9
10
|
/**
|
|
10
|
-
* @type {
|
|
11
|
+
* @type {any}
|
|
11
12
|
*/
|
|
12
13
|
ptyHost: undefined,
|
|
13
14
|
ptyHostState: /* None */ 0,
|
|
@@ -47,7 +48,13 @@ const handleProcessExit = () => {
|
|
|
47
48
|
const createPtyHost = async () => {
|
|
48
49
|
exitHook(handleProcessExit)
|
|
49
50
|
const ptyHostPath = await PtyHostPath.getPtyHostPath()
|
|
50
|
-
const ptyHost =
|
|
51
|
+
const ptyHost = await IpcParent.create({
|
|
52
|
+
method: IpcParentType.NodeForkedProcess,
|
|
53
|
+
path: ptyHostPath,
|
|
54
|
+
argv: ['--ipc-type=node-forked-process'],
|
|
55
|
+
stdio: 'inherit',
|
|
56
|
+
name: 'Terminal Process',
|
|
57
|
+
})
|
|
51
58
|
return ptyHost
|
|
52
59
|
}
|
|
53
60
|
|
|
@@ -70,26 +77,24 @@ export const create = async (socket, id, cwd) => {
|
|
|
70
77
|
case /* None */ 0: {
|
|
71
78
|
state.ptyHostState = /* Creating */ 1
|
|
72
79
|
const ptyHost = await createPtyHost()
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
80
|
+
|
|
81
|
+
Debug.debug('pty host ready')
|
|
82
|
+
state.ptyHostState = /* Ready */ 2
|
|
83
|
+
const handleMessage = (message) => {
|
|
84
|
+
const data = message.params[1]
|
|
85
|
+
socket.send({
|
|
86
|
+
jsonrpc: JsonRpcVersion.Two,
|
|
87
|
+
method: 'Viewlet.send',
|
|
88
|
+
params: ['Terminal', 'handleData', data],
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
ptyHost.on('message', handleMessage)
|
|
92
|
+
state.send = (message) => {
|
|
93
|
+
ptyHost.send(message)
|
|
94
|
+
}
|
|
95
|
+
while (state.pendingMessages.length > 0) {
|
|
96
|
+
state.send(state.pendingMessages.shift())
|
|
91
97
|
}
|
|
92
|
-
ptyHost.once('message', handleFirstMessage)
|
|
93
98
|
state.ptyHost = ptyHost
|
|
94
99
|
break
|
|
95
100
|
}
|
|
@@ -109,8 +114,7 @@ export const create = async (socket, id, cwd) => {
|
|
|
109
114
|
})
|
|
110
115
|
const handleClose = () => {
|
|
111
116
|
if (state.ptyHost) {
|
|
112
|
-
state.ptyHost.
|
|
113
|
-
state.ptyHost.kill()
|
|
117
|
+
state.ptyHost.dispose()
|
|
114
118
|
state.ptyHost = undefined
|
|
115
119
|
state.ptyHostState = /* None */ 0
|
|
116
120
|
state.send = (message) => {
|
|
@@ -1,31 +1,12 @@
|
|
|
1
|
+
import { Writable } from 'node:stream'
|
|
2
|
+
import { pipeline } from 'node:stream/promises'
|
|
3
|
+
import * as EncodingType from '../EncodingType/EncodingType.js'
|
|
4
|
+
import * as GetNewLineIndex from '../GetNewLineIndex/GetNewLineIndex.js'
|
|
5
|
+
import * as GetTextSearchRipGrepArgs from '../GetTextSearchRipGrepArgs/GetTextSearchRipGrepArgs.js'
|
|
1
6
|
import * as RipGrep from '../RipGrep/RipGrep.js'
|
|
2
7
|
import * as RipGrepParsedLineType from '../RipGrepParsedLineType/RipGrepParsedLineType.js'
|
|
3
8
|
import * as TextSearchResultType from '../TextSearchResultType/TextSearchResultType.js'
|
|
4
|
-
|
|
5
|
-
const MAX_SEARCH_RESULTS = 300
|
|
6
|
-
|
|
7
|
-
const CHARS_BEFORE = 20
|
|
8
|
-
const CHARS_AFTER = 50
|
|
9
|
-
|
|
10
|
-
const toSearchResult = (parsedLine) => {
|
|
11
|
-
const results = []
|
|
12
|
-
const lines = parsedLine.data.lines.text
|
|
13
|
-
const lineNumber = parsedLine.data.line_number
|
|
14
|
-
for (const submatch of parsedLine.data.submatches) {
|
|
15
|
-
const previewStart = Math.max(submatch.start - CHARS_BEFORE, 0)
|
|
16
|
-
const previewEnd = Math.min(submatch.end + CHARS_AFTER, lines.length)
|
|
17
|
-
const previewText = lines.slice(previewStart, previewEnd)
|
|
18
|
-
results.push({
|
|
19
|
-
type: TextSearchResultType.Match,
|
|
20
|
-
start: submatch.start - previewStart,
|
|
21
|
-
end: submatch.end - previewStart,
|
|
22
|
-
lineNumber,
|
|
23
|
-
text: previewText,
|
|
24
|
-
})
|
|
25
|
-
}
|
|
26
|
-
return results
|
|
27
|
-
}
|
|
28
|
-
|
|
9
|
+
import * as ToTextSearchResult from '../ToTextSearchResult/ToTextSearchResult.js'
|
|
29
10
|
// TODO update vscode-ripgrep when https://github.com/mhinz/vim-grepper/issues/244, https://github.com/BurntSushi/ripgrep/issues/1892 is fixed
|
|
30
11
|
|
|
31
12
|
// need to use '.' as last argument for ripgrep
|
|
@@ -37,102 +18,115 @@ const toSearchResult = (parsedLine) => {
|
|
|
37
18
|
// TODO update client
|
|
38
19
|
// TODO not always run nice, maybe configure nice via flag/options
|
|
39
20
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
'--json',
|
|
47
|
-
'--threads',
|
|
48
|
-
`${threads}`,
|
|
49
|
-
'--fixed-strings',
|
|
50
|
-
searchString,
|
|
51
|
-
'.',
|
|
52
|
-
]
|
|
53
|
-
const childProcess = RipGrep.spawn(ripGrepArgs, {
|
|
54
|
-
cwd: searchDir,
|
|
55
|
-
})
|
|
56
|
-
const allSearchResults = Object.create(null)
|
|
57
|
-
let buffer = ''
|
|
58
|
-
let stats = {}
|
|
59
|
-
let limitHit = false
|
|
60
|
-
let numberOfResults = 0
|
|
61
|
-
// TODO use pipeline / transform stream maybe
|
|
21
|
+
const collectStdout = async (childProcess, maxSearchResults) => {
|
|
22
|
+
const allSearchResults = Object.create(null)
|
|
23
|
+
let buffer = ''
|
|
24
|
+
let stats = {}
|
|
25
|
+
let limitHit = false
|
|
26
|
+
let numberOfResults = 0
|
|
62
27
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
28
|
+
childProcess.stdout.setEncoding(EncodingType.Utf8)
|
|
29
|
+
|
|
30
|
+
const handleLine = (line) => {
|
|
31
|
+
const parsedLine = JSON.parse(line)
|
|
32
|
+
switch (parsedLine.type) {
|
|
33
|
+
case RipGrepParsedLineType.Begin:
|
|
34
|
+
allSearchResults[parsedLine.data.path.text] = [
|
|
35
|
+
{
|
|
36
|
+
type: TextSearchResultType.File,
|
|
37
|
+
start: 0,
|
|
38
|
+
end: 0,
|
|
39
|
+
lineNumber: 0,
|
|
40
|
+
text: parsedLine.data.path.text,
|
|
41
|
+
},
|
|
42
|
+
]
|
|
43
|
+
break
|
|
44
|
+
case RipGrepParsedLineType.Match:
|
|
45
|
+
const remaining = maxSearchResults - numberOfResults
|
|
46
|
+
const matches = ToTextSearchResult.toTextSearchResult(parsedLine, remaining)
|
|
47
|
+
numberOfResults += matches.length
|
|
48
|
+
allSearchResults[parsedLine.data.path.text].push(...matches)
|
|
49
|
+
break
|
|
50
|
+
case RipGrepParsedLineType.Summary:
|
|
51
|
+
stats = parsedLine.data
|
|
52
|
+
break
|
|
53
|
+
default:
|
|
54
|
+
break
|
|
89
55
|
}
|
|
56
|
+
}
|
|
90
57
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
buffer = dataString.slice(previousIndex)
|
|
58
|
+
const handleData = (chunk) => {
|
|
59
|
+
let newLineIndex = GetNewLineIndex.getNewLineIndex(chunk)
|
|
60
|
+
const dataString = buffer + chunk
|
|
61
|
+
if (newLineIndex === -1) {
|
|
62
|
+
buffer = dataString
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
newLineIndex += buffer.length
|
|
66
|
+
let previousIndex = 0
|
|
67
|
+
while (newLineIndex >= 0) {
|
|
68
|
+
const line = dataString.slice(previousIndex, newLineIndex)
|
|
69
|
+
handleLine(line)
|
|
70
|
+
previousIndex = newLineIndex + 1
|
|
71
|
+
newLineIndex = GetNewLineIndex.getNewLineIndex(dataString, previousIndex)
|
|
72
|
+
}
|
|
73
|
+
buffer = dataString.slice(previousIndex)
|
|
109
74
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
75
|
+
if (numberOfResults > maxSearchResults) {
|
|
76
|
+
limitHit = true
|
|
77
|
+
childProcess.kill()
|
|
114
78
|
}
|
|
79
|
+
}
|
|
115
80
|
|
|
81
|
+
await pipeline(
|
|
82
|
+
childProcess.stdout,
|
|
83
|
+
new Writable({
|
|
84
|
+
decodeStrings: false,
|
|
85
|
+
construct(callback) {
|
|
86
|
+
callback()
|
|
87
|
+
},
|
|
88
|
+
write(chunk, encoding, callback) {
|
|
89
|
+
try {
|
|
90
|
+
handleData(chunk)
|
|
91
|
+
callback()
|
|
92
|
+
} catch (error) {
|
|
93
|
+
callback(error)
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
})
|
|
97
|
+
)
|
|
98
|
+
const results = Object.values(allSearchResults).flat(1)
|
|
99
|
+
return {
|
|
100
|
+
results,
|
|
101
|
+
stats,
|
|
102
|
+
limitHit,
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export const search = async (searchDir, searchString, { threads = 1, maxSearchResults = 20_000, isCaseSensitive = false } = {}) => {
|
|
107
|
+
const ripGrepArgs = GetTextSearchRipGrepArgs.getRipGrepArgs({
|
|
108
|
+
threads,
|
|
109
|
+
isCaseSensitive,
|
|
110
|
+
searchString,
|
|
111
|
+
})
|
|
112
|
+
const childProcess = RipGrep.spawn(ripGrepArgs, {
|
|
113
|
+
cwd: searchDir,
|
|
114
|
+
})
|
|
115
|
+
const pipeLinePromise = collectStdout(childProcess, maxSearchResults)
|
|
116
|
+
const closePromise = new Promise((resolve, reject) => {
|
|
117
|
+
// TODO use pipeline / transform stream maybe
|
|
116
118
|
const handleClose = () => {
|
|
117
|
-
|
|
118
|
-
resolve({
|
|
119
|
-
results,
|
|
120
|
-
stats,
|
|
121
|
-
limitHit,
|
|
122
|
-
})
|
|
119
|
+
resolve(undefined)
|
|
123
120
|
}
|
|
124
121
|
const handleError = (error) => {
|
|
125
122
|
// TODO check type of error
|
|
126
123
|
console.error(error)
|
|
127
|
-
resolve(
|
|
128
|
-
results: [],
|
|
129
|
-
stats,
|
|
130
|
-
limitHit,
|
|
131
|
-
})
|
|
124
|
+
resolve(undefined)
|
|
132
125
|
}
|
|
133
|
-
|
|
134
|
-
childProcess.stdout.on('data', handleData)
|
|
126
|
+
|
|
135
127
|
childProcess.once('close', handleClose)
|
|
136
128
|
childProcess.once('error', handleError)
|
|
137
129
|
})
|
|
130
|
+
await Promise.all([pipeLinePromise, closePromise])
|
|
131
|
+
return await pipeLinePromise
|
|
138
132
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as TextSearchResultType from '../TextSearchResultType/TextSearchResultType.js'
|
|
2
|
+
|
|
3
|
+
const CHARS_BEFORE = 20
|
|
4
|
+
const CHARS_AFTER = 50
|
|
5
|
+
|
|
6
|
+
const getLines = (parsedLineData) => {
|
|
7
|
+
if (parsedLineData.lines.text) {
|
|
8
|
+
return parsedLineData.lines.text
|
|
9
|
+
}
|
|
10
|
+
if (parsedLineData.lines.bytes) {
|
|
11
|
+
return Buffer.from(parsedLineData.lines.bytes, 'base64').toString()
|
|
12
|
+
}
|
|
13
|
+
throw new Error(`unable to parse line data`)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const getRemainingSubMatches = (submatches, remaining) => {
|
|
17
|
+
if (submatches.length < remaining) {
|
|
18
|
+
return submatches
|
|
19
|
+
}
|
|
20
|
+
return submatches.slice(0, remaining)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const toTextSearchResult = (parsedLine, remaining) => {
|
|
24
|
+
const results = []
|
|
25
|
+
const parsedLineData = parsedLine.data
|
|
26
|
+
const lines = getLines(parsedLineData)
|
|
27
|
+
const lineNumber = parsedLineData.line_number
|
|
28
|
+
const submatches = parsedLineData.submatches
|
|
29
|
+
for (const submatch of submatches) {
|
|
30
|
+
const previewStart = Math.max(submatch.start - CHARS_BEFORE, 0)
|
|
31
|
+
const previewEnd = Math.min(submatch.end + CHARS_AFTER, lines.length)
|
|
32
|
+
const previewText = lines.slice(previewStart, previewEnd)
|
|
33
|
+
results.push({
|
|
34
|
+
type: TextSearchResultType.Match,
|
|
35
|
+
start: submatch.start - previewStart,
|
|
36
|
+
end: submatch.end - previewStart,
|
|
37
|
+
lineNumber,
|
|
38
|
+
text: previewText,
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
return results
|
|
42
|
+
}
|
package/src/parts/Trash/Trash.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { default as _trash } from 'trash'
|
|
2
|
-
import VError from '
|
|
2
|
+
import { VError } from '../VError/VError.js'
|
|
3
3
|
|
|
4
4
|
export const trash = async (path) => {
|
|
5
5
|
try {
|
|
6
6
|
await _trash(path)
|
|
7
7
|
} catch (error) {
|
|
8
|
-
// @ts-ignore
|
|
9
8
|
throw new VError(error, 'Failed to move item to trash')
|
|
10
9
|
}
|
|
11
10
|
}
|
|
File without changes
|