@lvce-editor/shared-process 0.16.3 → 0.16.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/shared-process",
3
- "version": "0.16.3",
3
+ "version": "0.16.4",
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.22.5",
20
- "@lvce-editor/extension-host": "0.16.3",
21
- "@lvce-editor/extension-host-helper-process": "0.16.3",
22
- "@lvce-editor/pty-host": "0.16.3",
20
+ "@lvce-editor/extension-host": "0.16.4",
21
+ "@lvce-editor/extension-host-helper-process": "0.16.4",
22
+ "@lvce-editor/pty-host": "0.16.4",
23
23
  "debug": "^4.3.4",
24
24
  "execa": "^7.1.1",
25
25
  "exit-hook": "^3.2.0",
@@ -0,0 +1,103 @@
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 RipGrepParsedLineType from '../RipGrepParsedLineType/RipGrepParsedLineType.js'
6
+ import * as TextSearchResultType from '../TextSearchResultType/TextSearchResultType.js'
7
+ import * as ToTextSearchResult from '../ToTextSearchResult/ToTextSearchResult.js'
8
+ // TODO update vscode-ripgrep when https://github.com/mhinz/vim-grepper/issues/244, https://github.com/BurntSushi/ripgrep/issues/1892 is fixed
9
+
10
+ // need to use '.' as last argument for ripgrep
11
+ // issue 1 https://github.com/nvim-telescope/telescope.nvim/pull/908/files
12
+ // issue 2 https://github.com/BurntSushi/ripgrep/issues/1892
13
+ // remove workaround when ripgrep is fixed
14
+
15
+ // TODO stats flag might not be necessary
16
+ // TODO update client
17
+ // TODO not always run nice, maybe configure nice via flag/options
18
+
19
+ export const collectStdout = async (childProcess, maxSearchResults, charsBefore, charsAfter) => {
20
+ const allSearchResults = Object.create(null)
21
+ let buffer = ''
22
+ let stats = {}
23
+ let limitHit = false
24
+ let numberOfResults = 0
25
+
26
+ childProcess.stdout.setEncoding(EncodingType.Utf8)
27
+
28
+ const handleLine = (line) => {
29
+ const parsedLine = JSON.parse(line)
30
+ const { type, data } = parsedLine
31
+ switch (type) {
32
+ case RipGrepParsedLineType.Begin:
33
+ allSearchResults[data.path.text] = [
34
+ {
35
+ type: TextSearchResultType.File,
36
+ start: 0,
37
+ end: 0,
38
+ lineNumber: 0,
39
+ text: data.path.text,
40
+ },
41
+ ]
42
+ break
43
+ case RipGrepParsedLineType.Match:
44
+ const remaining = maxSearchResults - numberOfResults
45
+ const matches = ToTextSearchResult.toTextSearchResult(parsedLine, remaining, charsBefore, charsAfter)
46
+ numberOfResults += matches.length
47
+ allSearchResults[data.path.text].push(...matches)
48
+ break
49
+ case RipGrepParsedLineType.Summary:
50
+ stats = data
51
+ break
52
+ default:
53
+ break
54
+ }
55
+ }
56
+
57
+ const handleData = (chunk) => {
58
+ let newLineIndex = GetNewLineIndex.getNewLineIndex(chunk)
59
+ const dataString = buffer + chunk
60
+ if (newLineIndex === -1) {
61
+ buffer = dataString
62
+ return
63
+ }
64
+ newLineIndex += buffer.length
65
+ let previousIndex = 0
66
+ while (newLineIndex >= 0) {
67
+ const line = dataString.slice(previousIndex, newLineIndex)
68
+ handleLine(line)
69
+ previousIndex = newLineIndex + 1
70
+ newLineIndex = GetNewLineIndex.getNewLineIndex(dataString, previousIndex)
71
+ }
72
+ buffer = dataString.slice(previousIndex)
73
+
74
+ if (numberOfResults > maxSearchResults) {
75
+ limitHit = true
76
+ childProcess.kill()
77
+ }
78
+ }
79
+
80
+ await pipeline(
81
+ childProcess.stdout,
82
+ new Writable({
83
+ decodeStrings: false,
84
+ construct(callback) {
85
+ callback()
86
+ },
87
+ write(chunk, encoding, callback) {
88
+ try {
89
+ handleData(chunk)
90
+ callback()
91
+ } catch (error) {
92
+ callback(error)
93
+ }
94
+ },
95
+ })
96
+ )
97
+ const results = Object.values(allSearchResults).flat(1)
98
+ return {
99
+ results,
100
+ stats,
101
+ limitHit,
102
+ }
103
+ }
@@ -0,0 +1,49 @@
1
+ import * as RipGrep from '../RipGrep/RipGrep.js'
2
+
3
+ const connectProcess = (ipc, id, childProcess) => {
4
+ let count = 0
5
+ const cleanup = () => {
6
+ childProcess.kill()
7
+ }
8
+ childProcess.stdout.on('data', (data) => {
9
+ count++
10
+ if (count > 20) {
11
+ cleanup()
12
+ return
13
+ }
14
+ // console.log({ data: data.toString() })
15
+ ipc.send({
16
+ jsonrpc: '2.0',
17
+ method: 'IncrementalTextSearch.handleData',
18
+ params: [id, data.toString()],
19
+ })
20
+ // emitter.dispatchEvent(new Event('data', x))
21
+ })
22
+
23
+ childProcess.on('exit', () => {
24
+ ipc.send({
25
+ jsonrpc: '2.0',
26
+ method: 'IncrementalTextSearch.handleExit',
27
+ params: [id],
28
+ })
29
+ // emitter.dispatchEvent(new Event('exit'))
30
+ })
31
+ childProcess.on('error', () => {
32
+ ipc.send({
33
+ jsonrpc: '2.0',
34
+ method: 'IncrementalTextSearch.handleError',
35
+ params: [id],
36
+ })
37
+ // emitter.dispatchEvent(new Event('error'))
38
+ })
39
+ }
40
+
41
+ export const start = async (ipc, id, { searchDir = '', maxSearchResults = 20_000, ripGrepArgs = [] } = {}) => {
42
+ console.log({ ipc })
43
+ const emitter = new EventTarget()
44
+ const childProcess = RipGrep.spawn(ripGrepArgs, {
45
+ cwd: searchDir,
46
+ })
47
+ console.log('start', { searchDir, ripGrepArgs, id })
48
+ connectProcess(ipc, id, childProcess)
49
+ }
@@ -0,0 +1,7 @@
1
+ import * as IncrementalTextSearch from './IncrementalTextSearch.js'
2
+
3
+ export const name = 'IncrementalTextSearch'
4
+
5
+ export const Commands = {
6
+ start: IncrementalTextSearch.start,
7
+ }
@@ -0,0 +1,20 @@
1
+ const RE_WORD = /\b/g
2
+
3
+ export const leftCut = (text, final, charsBefore) => {
4
+ if (text.length < charsBefore) {
5
+ return text.length
6
+ }
7
+ let i = 0
8
+ while (RE_WORD.test(text)) {
9
+ if (final - RE_WORD.lastIndex < charsBefore) {
10
+ break
11
+ }
12
+ i = RE_WORD.lastIndex
13
+ RE_WORD.lastIndex++
14
+ }
15
+ RE_WORD.lastIndex = 0
16
+ if (final - i > charsBefore + 10) {
17
+ return final - charsBefore
18
+ }
19
+ return i
20
+ }
@@ -72,6 +72,8 @@ export const load = (moduleId) => {
72
72
  return import('../HandleCliArgs/HandleCliArgs.ipc.js')
73
73
  case ModuleId.ListProcessesWithMemoryUsage:
74
74
  return import('../ListProcessesWithMemoryUsage/ListProcessesWithMemoryUsage.ipc.js')
75
+ case ModuleId.IncrementalTextSearch:
76
+ return import('../IncrementalTextSearch/IncremetalTextSearch.ipc.js')
75
77
  default:
76
78
  throw new Error(`module ${moduleId} not found`)
77
79
  }
@@ -33,3 +33,4 @@ export const HandleNodeMessagePort = 32
33
33
  export const GetTerminalSpawnOptions = 33
34
34
  export const HandleCliArgs = 34
35
35
  export const ListProcessesWithMemoryUsage = 35
36
+ export const IncrementalTextSearch = 36
@@ -185,6 +185,8 @@ export const getModuleId = (commandId) => {
185
185
  return ModuleId.HandleCliArgs
186
186
  case 'ListProcessesWithMemoryUsage.listProcessesWithMemoryUsage':
187
187
  return ModuleId.ListProcessesWithMemoryUsage
188
+ case 'IncrementalTextSearch.start':
189
+ return ModuleId.IncrementalTextSearch
188
190
  default:
189
191
  throw new CommandNotFoundError(commandId)
190
192
  }
@@ -0,0 +1,11 @@
1
+ import * as EncodingType from '../EncodingType/EncodingType.js'
2
+
3
+ export const parseRipGrepLines = (parsedLineData) => {
4
+ if (parsedLineData.lines.text) {
5
+ return parsedLineData.lines.text
6
+ }
7
+ if (parsedLineData.lines.bytes) {
8
+ return Buffer.from(parsedLineData.lines.bytes, EncodingType.Base64).toString()
9
+ }
10
+ throw new Error(`unable to parse line data`)
11
+ }
@@ -165,11 +165,11 @@ export const getSetupName = () => {
165
165
  return 'Lvce-Setup'
166
166
  }
167
167
 
168
- export const version = '0.16.3'
168
+ export const version = '0.16.4'
169
169
 
170
- export const commit = '6fbd9fc'
170
+ export const commit = '4ec07e5'
171
171
 
172
- export const date = '2023-07-04T07:58:24.000Z'
172
+ export const date = '2023-07-04T18:03:04.000Z'
173
173
 
174
174
  export const getVersion = () => {
175
175
  return version
@@ -7,6 +7,7 @@ const METHODS_THAT_REQUIRE_SOCKET = new Set([
7
7
  'ExtensionHost.send',
8
8
  'ExtensionHost.watchColorTheme',
9
9
  'Terminal.create',
10
+ 'IncrementalTextSearch.start',
10
11
  ])
11
12
 
12
13
  export const requiresSocket = (method) => {
@@ -1,14 +1,9 @@
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'
1
+ import * as CollectTextSearchStdout from '../CollectTextSearchStdout/CollectTextSearchStdout.js'
5
2
  import * as ProcessExitEventType from '../ProcessExitEventType/ProcessExitEventType.js'
6
3
  import * as RipGrep from '../RipGrep/RipGrep.js'
7
- import * as RipGrepParsedLineType from '../RipGrepParsedLineType/RipGrepParsedLineType.js'
8
4
  import { TextSearchError } from '../TextSearchError/TextSearchError.js'
9
- import * as TextSearchResultType from '../TextSearchResultType/TextSearchResultType.js'
10
- import * as ToTextSearchResult from '../ToTextSearchResult/ToTextSearchResult.js'
11
5
  import * as WaitForProcessToExit from '../WaitForProcessToExit/WaitForProcessToExit.js'
6
+
12
7
  // TODO update vscode-ripgrep when https://github.com/mhinz/vim-grepper/issues/244, https://github.com/BurntSushi/ripgrep/issues/1892 is fixed
13
8
 
14
9
  // need to use '.' as last argument for ripgrep
@@ -20,98 +15,13 @@ import * as WaitForProcessToExit from '../WaitForProcessToExit/WaitForProcessToE
20
15
  // TODO update client
21
16
  // TODO not always run nice, maybe configure nice via flag/options
22
17
 
23
- const collectStdout = async (childProcess, maxSearchResults, charsBefore, charsAfter) => {
24
- const allSearchResults = Object.create(null)
25
- let buffer = ''
26
- let stats = {}
27
- let limitHit = false
28
- let numberOfResults = 0
29
-
30
- childProcess.stdout.setEncoding(EncodingType.Utf8)
31
-
32
- const handleLine = (line) => {
33
- const parsedLine = JSON.parse(line)
34
- switch (parsedLine.type) {
35
- case RipGrepParsedLineType.Begin:
36
- allSearchResults[parsedLine.data.path.text] = [
37
- {
38
- type: TextSearchResultType.File,
39
- start: 0,
40
- end: 0,
41
- lineNumber: 0,
42
- text: parsedLine.data.path.text,
43
- },
44
- ]
45
- break
46
- case RipGrepParsedLineType.Match:
47
- const remaining = maxSearchResults - numberOfResults
48
- const matches = ToTextSearchResult.toTextSearchResult(parsedLine, remaining, charsBefore, charsAfter)
49
- numberOfResults += matches.length
50
- allSearchResults[parsedLine.data.path.text].push(...matches)
51
- break
52
- case RipGrepParsedLineType.Summary:
53
- stats = parsedLine.data
54
- break
55
- default:
56
- break
57
- }
58
- }
59
-
60
- const handleData = (chunk) => {
61
- let newLineIndex = GetNewLineIndex.getNewLineIndex(chunk)
62
- const dataString = buffer + chunk
63
- if (newLineIndex === -1) {
64
- buffer = dataString
65
- return
66
- }
67
- newLineIndex += buffer.length
68
- let previousIndex = 0
69
- while (newLineIndex >= 0) {
70
- const line = dataString.slice(previousIndex, newLineIndex)
71
- handleLine(line)
72
- previousIndex = newLineIndex + 1
73
- newLineIndex = GetNewLineIndex.getNewLineIndex(dataString, previousIndex)
74
- }
75
- buffer = dataString.slice(previousIndex)
76
-
77
- if (numberOfResults > maxSearchResults) {
78
- limitHit = true
79
- childProcess.kill()
80
- }
81
- }
82
-
83
- await pipeline(
84
- childProcess.stdout,
85
- new Writable({
86
- decodeStrings: false,
87
- construct(callback) {
88
- callback()
89
- },
90
- write(chunk, encoding, callback) {
91
- try {
92
- handleData(chunk)
93
- callback()
94
- } catch (error) {
95
- callback(error)
96
- }
97
- },
98
- })
99
- )
100
- const results = Object.values(allSearchResults).flat(1)
101
- return {
102
- results,
103
- stats,
104
- limitHit,
105
- }
106
- }
107
-
108
18
  export const search = async ({ searchDir = '', maxSearchResults = 20_000, ripGrepArgs = [] } = {}) => {
109
19
  const charsBefore = 26
110
20
  const charsAfter = 50
111
21
  const childProcess = RipGrep.spawn(ripGrepArgs, {
112
22
  cwd: searchDir,
113
23
  })
114
- const pipeLinePromise = collectStdout(childProcess, maxSearchResults, charsBefore, charsAfter)
24
+ const pipeLinePromise = CollectTextSearchStdout.collectStdout(childProcess, maxSearchResults, charsBefore, charsAfter)
115
25
  const closePromise = WaitForProcessToExit.waitForProcessToExit(childProcess)
116
26
  const [pipeLineResult, exitResult] = await Promise.all([pipeLinePromise, closePromise])
117
27
  if (exitResult.type === ProcessExitEventType.Error) {
@@ -1,57 +1,16 @@
1
- import * as EncodingType from '../EncodingType/EncodingType.js'
1
+ import * as ParseRipGrepLines from '../ParseRipGrepLines/ParseRipGrepLines.js'
2
2
  import * as TextSearchResultType from '../TextSearchResultType/TextSearchResultType.js'
3
3
 
4
- const getLines = (parsedLineData) => {
5
- if (parsedLineData.lines.text) {
6
- return parsedLineData.lines.text
7
- }
8
- if (parsedLineData.lines.bytes) {
9
- return Buffer.from(parsedLineData.lines.bytes, EncodingType.Base64).toString()
10
- }
11
- throw new Error(`unable to parse line data`)
12
- }
13
-
14
- const getRemainingSubMatches = (submatches, remaining) => {
15
- if (submatches.length < remaining) {
16
- return submatches
17
- }
18
- return submatches.slice(0, remaining)
19
- }
20
-
21
- const RE_WORD = /\b/g
22
-
23
- const leftCut = (text, final, charsBefore) => {
24
- if (text.length < charsBefore) {
25
- return text.length
26
- }
27
- let i = 0
28
- while (RE_WORD.test(text)) {
29
- if (final - RE_WORD.lastIndex < charsBefore) {
30
- break
31
- }
32
- i = RE_WORD.lastIndex
33
- RE_WORD.lastIndex++
34
- }
35
- RE_WORD.lastIndex = 0
36
- if (final - i > charsBefore + 10) {
37
- return final - charsBefore
38
- }
39
- return i
40
- }
41
-
42
4
  export const toTextSearchResult = (parsedLine, remaining, charsBefore, charsAfter) => {
43
5
  const results = []
44
6
  const parsedLineData = parsedLine.data
45
- const lines = getLines(parsedLineData)
7
+ const lines = ParseRipGrepLines.parseRipGrepLines(parsedLineData)
46
8
  const lineNumber = parsedLineData.line_number
47
9
  const submatches = parsedLineData.submatches
48
10
  const linesLength = lines.length
49
11
  for (const submatch of submatches) {
50
12
  const previewStart = Math.max(submatch.start - charsBefore, 0)
51
13
  let actualStart = previewStart
52
- if (actualStart > 0) {
53
- actualStart = leftCut(lines, submatch.start, charsBefore)
54
- }
55
14
  const previewEnd = Math.min(submatch.end + charsAfter, linesLength)
56
15
  const previewText = lines.slice(actualStart, previewEnd)
57
16
  results.push({