@lvce-editor/shared-process 0.13.0 → 0.14.1

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.
Files changed (112) hide show
  1. package/config/defaultKeyBindings.json +1 -784
  2. package/config/defaultSettings.json +8 -1
  3. package/extensions/builtin.language-basics-css/extension.json +2 -1
  4. package/extensions/builtin.language-basics-css/languageConfiguration.json +21 -0
  5. package/extensions/builtin.language-basics-css/src/tokenizeCss.js +10 -1
  6. package/extensions/builtin.language-basics-dotenv/extension.json +5 -1
  7. package/extensions/builtin.language-basics-go/src/tokenizeGo.js +79 -10
  8. package/extensions/builtin.language-basics-html/languageConfiguration.json +66 -0
  9. package/extensions/builtin.language-basics-html/src/tokenizeHtml.js +89 -27
  10. package/extensions/builtin.language-basics-java/src/tokenizeJava.js +6 -5
  11. package/extensions/builtin.language-basics-javascript/src/tokenizeJavaScript.js +29 -1
  12. package/extensions/builtin.language-basics-json/extension.json +4 -2
  13. package/extensions/builtin.language-basics-json/src/tokenizeJson.js +3 -0
  14. package/extensions/builtin.language-basics-jsx/src/tokenizeJsx.js +18 -5
  15. package/extensions/builtin.language-basics-typescript/src/tokenizeTypeScript.js +26 -0
  16. package/extensions/builtin.language-basics-vue/src/tokenizeVue.js +1 -1
  17. package/extensions/builtin.language-basics-xml/extension.json +3 -1
  18. package/extensions/builtin.theme-atom-one-dark/color-theme.json +2 -2
  19. package/extensions/builtin.theme-ayu/color-theme.json +6 -2
  20. package/extensions/builtin.theme-cobalt2/color-theme.json +5 -2
  21. package/extensions/builtin.theme-slime/color-theme.json +2 -2
  22. package/package.json +10 -11
  23. package/src/parts/Assert/Assert.js +1 -6
  24. package/src/parts/AssertionError/AssertionError.js +6 -0
  25. package/src/parts/BulkReplacement/BulkReplacement.ipc.js +7 -0
  26. package/src/parts/BulkReplacement/BulkReplacement.js +20 -0
  27. package/src/parts/BulkReplacementContent/BulkReplacementContent.js +30 -0
  28. package/src/parts/ChildProcessError/ChildProcessError.js +45 -0
  29. package/src/parts/ChromeExtension/ChromeExtension.js +2 -5
  30. package/src/parts/CleanStack/CleanStack.js +90 -2
  31. package/src/parts/CliList/CliList.js +3 -0
  32. package/src/parts/ClipBoard/ClipBoard.js +2 -2
  33. package/src/parts/ClipBoard/ClipBoardGnome.js +1 -2
  34. package/src/parts/ClipBoard/ClipBoardNoop.js +2 -2
  35. package/src/parts/ClipBoard/ClipBoardWindows.js +1 -3
  36. package/src/parts/Command/Command.js +5 -10
  37. package/src/parts/Credentials/Credentials.ipc.js +5 -5
  38. package/src/parts/Credentials/Credentials.js +2 -10
  39. package/src/parts/Desktop/Desktop.js +22 -0
  40. package/src/parts/Download/Download.js +2 -2
  41. package/src/parts/Error/Error.js +1 -1
  42. package/src/parts/ErrorCodes/ErrorCodes.js +2 -1
  43. package/src/parts/ErrorHandling/ErrorHandling.js +8 -14
  44. package/src/parts/ExportStatic/ExportStatic.js +8 -3
  45. package/src/parts/ExtensionHost/ExtensionHost.js +1 -2
  46. package/src/parts/ExtensionHost/ExtensionHostKeyBindings.js +0 -12
  47. package/src/parts/ExtensionHostRpc/ExtensionHostRpc.js +1 -1
  48. package/src/parts/ExtensionInstallFromFile/ExtensionInstallFromFile.js +1 -1
  49. package/src/parts/ExtensionInstallFromGitHub/ExtensionInstallFromGitHub.js +1 -1
  50. package/src/parts/ExtensionInstallFromUrl/ExtensionInstallFromUrl.js +1 -1
  51. package/src/parts/ExtensionLink/ExtensionLink.js +0 -19
  52. package/src/parts/ExtensionList/ExtensionList.js +11 -2
  53. package/src/parts/ExtensionManagement/ExtensionManagement.js +6 -58
  54. package/src/parts/ExtensionManagement/ExtensionManagementColorTheme.js +3 -1
  55. package/src/parts/ExtensionManagement/ExtensionManagementIconTheme.js +1 -1
  56. package/src/parts/ExtensionManagement/ExtensionManagementLanguages.js +7 -3
  57. package/src/parts/ExtensionManifestInputType/ExtensionManifestInputType.js +2 -0
  58. package/src/parts/ExtensionManifests/ExtensionManifests.js +3 -0
  59. package/src/parts/ExtensionManifests/ExtensionManifestsFromFolder.js +5 -15
  60. package/src/parts/ExtensionManifests/ExtensionManifestsFromLinkedExtensionsFolder.js +56 -0
  61. package/src/parts/ExtensionUninstall/ExtensionUninstall.js +18 -0
  62. package/src/parts/ExtensionUnlink/ExtensionUnlink.js +1 -1
  63. package/src/parts/Extract/Extract.js +2 -6
  64. package/src/parts/ExtractZip/ExtractZip.js +1 -1
  65. package/src/parts/{Error → FileNotFoundError}/FileNotFoundError.js +9 -2
  66. package/src/parts/FileSystem/FileSystem.js +6 -32
  67. package/src/parts/FirstNodeWorkerEventType/FirstNodeWorkerEventType.js +5 -0
  68. package/src/parts/GetDirentType/GetDirentType.js +27 -0
  69. package/src/parts/GetFirstNodeChildProcessEvent/GetFirstNodeChildProcessEvent.js +39 -0
  70. package/src/parts/GetFirstNodeWorkerEvent/GetFirstNodeWorkerEvent.js +21 -0
  71. package/src/parts/GetNewLineIndex/GetNewLineIndex.js +9 -0
  72. package/src/parts/GetResponse/GetResponse.js +16 -6
  73. package/src/parts/GetTextSearchRipGrepArgs/GetTextSearchRipGrepArgs.js +14 -0
  74. package/src/parts/InstallExtension/InstallExtension.ipc.js +6 -0
  75. package/src/parts/InstallExtension/InstallExtension.js +33 -0
  76. package/src/parts/IpcParent/IpcParent.js +9 -0
  77. package/src/parts/IpcParentModule/IpcParentModule.js +12 -0
  78. package/src/parts/IpcParentType/IpcParentType.js +2 -0
  79. package/src/parts/IpcParentWithNodeForkedProcess/IpcParentWithNodeForkedProcess.js +49 -0
  80. package/src/parts/IpcParentWithNodeWorker/IpcParentWithNodeWorker.js +36 -0
  81. package/src/parts/IsEnoentErrorWindows/IsEnoentErrorWindows.js +3 -0
  82. package/src/parts/IsIgnoredError/IsIgnoredError.js +14 -0
  83. package/src/parts/Json/Json.js +3 -5
  84. package/src/parts/JsonError/JsonError.js +8 -14
  85. package/src/parts/JsonParsingError/JsonParsingError.js +17 -0
  86. package/src/parts/Jsonc/Jsonc.js +304 -0
  87. package/src/parts/JsoncCharCode/JsoncCharCode.js +23 -0
  88. package/src/parts/JsoncFile/JsoncFile.js +8 -0
  89. package/src/parts/JsoncTokenType/JsoncTokenType.js +11 -0
  90. package/src/parts/LimitString/LimitString.js +3 -1
  91. package/src/parts/MergeStacks/MergeStacks.js +3 -2
  92. package/src/parts/Module/Module.js +4 -0
  93. package/src/parts/ModuleId/ModuleId.js +2 -0
  94. package/src/parts/ModuleMap/ModuleMap.js +4 -0
  95. package/src/parts/Native/Native.js +1 -1
  96. package/src/parts/ParentIpc/ParentIpc.js +2 -1
  97. package/src/parts/Platform/Platform.js +0 -21
  98. package/src/parts/Preferences/Preferences.js +6 -8
  99. package/src/parts/PrettyError/PrettyError.js +16 -7
  100. package/src/parts/PrintPrettyError/PrintPrettyError.js +3 -1
  101. package/src/parts/RecentlyOpened/RecentlyOpened.js +3 -7
  102. package/src/parts/RequiresSocket/RequiresSocket.js +1 -0
  103. package/src/parts/RipGrep/RipGrep.js +1 -1
  104. package/src/parts/SearchFile/SearchFile.js +4 -9
  105. package/src/parts/Socket/Socket.js +2 -7
  106. package/src/parts/Terminal/Terminal.ipc.js +4 -41
  107. package/src/parts/Terminal/Terminal.js +29 -25
  108. package/src/parts/TextSearch/TextSearch.js +102 -108
  109. package/src/parts/ToAbsolutePaths/ToAbsolutePaths.js +9 -0
  110. package/src/parts/ToTextSearchResult/ToTextSearchResult.js +42 -0
  111. package/src/parts/Trash/Trash.js +1 -2
  112. /package/src/parts/{RgPath/RgPath.js → RipGrepPath/RipGrepPath.js} +0 -0
@@ -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 PtyHostPath from '../PtyHostPath/PtyHostPath.js'
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 {ChildProcess|undefined}
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 = fork(ptyHostPath, { stdio: 'inherit' })
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
- const handleFirstMessage = () => {
74
- Debug.debug('pty host ready')
75
- state.ptyHostState = /* Ready */ 2
76
- const handleMessage = (message) => {
77
- const data = message.params[1]
78
- socket.send({
79
- jsonrpc: JsonRpcVersion.Two,
80
- method: 'Viewlet.send',
81
- params: ['Terminal', 'handleData', data],
82
- })
83
- }
84
- ptyHost.on('message', handleMessage)
85
- state.send = (message) => {
86
- ptyHost.send(message)
87
- }
88
- while (state.pendingMessages.length > 0) {
89
- state.send(state.pendingMessages.shift())
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.removeAllListeners()
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
- export const search = async (searchDir, searchString, { threads = 1 } = {}) => {
41
- // TODO reject promise when ripgrep search fails
42
- return new Promise((resolve, reject) => {
43
- const ripGrepArgs = [
44
- '--smart-case',
45
- '--stats',
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
- const handleLine = (line) => {
64
- const parsedLine = JSON.parse(line)
65
- switch (parsedLine.type) {
66
- case RipGrepParsedLineType.Begin:
67
- allSearchResults[parsedLine.data.path.text] = [
68
- {
69
- type: TextSearchResultType.File,
70
- start: 0,
71
- end: 0,
72
- lineNumber: 0,
73
- text: parsedLine.data.path.text,
74
- },
75
- ]
76
- break
77
- case RipGrepParsedLineType.Match:
78
- numberOfResults++
79
- allSearchResults[parsedLine.data.path.text].push(
80
- ...toSearchResult(parsedLine)
81
- )
82
- break
83
- case RipGrepParsedLineType.Summary:
84
- stats = parsedLine.data
85
- break
86
- default:
87
- break
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
- let total = 0
92
- const handleData = (chunk) => {
93
- let newLineIndex = chunk.indexOf('\n')
94
- const dataString = buffer + chunk
95
- if (newLineIndex === -1) {
96
- buffer = dataString
97
- return
98
- }
99
- total += chunk.length
100
- newLineIndex += buffer.length
101
- let previousIndex = 0
102
- while (newLineIndex >= 0) {
103
- const line = dataString.slice(previousIndex, newLineIndex)
104
- handleLine(line)
105
- previousIndex = newLineIndex + 1
106
- newLineIndex = dataString.indexOf('\n', previousIndex)
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
- if (numberOfResults > MAX_SEARCH_RESULTS) {
111
- limitHit = true
112
- childProcess.kill()
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
- const results = Object.values(allSearchResults).flat(1)
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
- childProcess.stdout.setEncoding('utf8')
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,9 @@
1
+ import * as Path from '../Path/Path.js'
2
+
3
+ export const toAbsolutePaths = (path, dirents) => {
4
+ const absolutePaths = []
5
+ for (const dirent of dirents) {
6
+ absolutePaths.push(Path.join(path, dirent))
7
+ }
8
+ return absolutePaths
9
+ }
@@ -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
+ }
@@ -1,11 +1,10 @@
1
1
  import { default as _trash } from 'trash'
2
- import VError from 'verror'
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
  }