@lvce-editor/shared-process 0.11.5 → 0.11.7
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/builtinCommands.json +1 -1
- package/config/defaultKeyBindings.json +1 -1
- package/extensions/builtin.language-basics-desktop/src/tokenizeDesktop.js +49 -5
- package/extensions/builtin.language-basics-shellscript/extension.json +1 -0
- package/extensions/builtin.language-basics-xml/src/tokenizeXml.js +1 -1
- package/index.js +5 -2
- package/package.json +5 -5
- package/src/parts/ClipBoard/ClipBoardGnome.js +2 -1
- package/src/parts/Developer/Developer.js +3 -2
- package/src/parts/ExportStatic/ExportStatic.js +78 -2
- 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/ExtensionLink/ExtensionLink.js +2 -3
- package/src/parts/ExtensionManagement/ExtensionManagement.js +1 -1
- package/src/parts/ExtensionManifest/ExtensionManifest.js +2 -2
- package/src/parts/GetResponse/GetResponse.js +2 -1
- package/src/parts/PrettyError/PrettyError.js +6 -5
- package/src/parts/RecentlyOpened/RecentlyOpened.js +2 -2
- package/src/parts/RipGrepParsedLineType/RipGrepParsedLineType.js +4 -0
- package/src/parts/Search/Search.js +87 -58
- package/src/parts/SplitLines/SplitLines.js +3 -0
- package/src/parts/Stats/Stats.js +3 -3
- package/src/parts/TextSearchResultType/TextSearchResultType.js +2 -0
- package/src/parts/VError/VError.js +44 -0
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
export const State = {
|
|
5
5
|
TopLevelContent: 1,
|
|
6
6
|
InsideLineComment: 2,
|
|
7
|
+
AfterPropertyName: 3,
|
|
8
|
+
AfterPropertyNameAfterEqualSign: 4,
|
|
9
|
+
InsideString: 5,
|
|
7
10
|
}
|
|
8
11
|
|
|
9
12
|
export const StateMap = {
|
|
@@ -23,6 +26,10 @@ export const TokenType = {
|
|
|
23
26
|
Comment: 885,
|
|
24
27
|
Query: 886,
|
|
25
28
|
Text: 887,
|
|
29
|
+
PropertyName: 12,
|
|
30
|
+
PropertyValueString: 14,
|
|
31
|
+
Punctuation: 13,
|
|
32
|
+
LanguageConstant: 11,
|
|
26
33
|
}
|
|
27
34
|
|
|
28
35
|
export const TokenMap = {
|
|
@@ -34,13 +41,19 @@ export const TokenMap = {
|
|
|
34
41
|
[TokenType.Comment]: 'Comment',
|
|
35
42
|
[TokenType.Query]: 'Query',
|
|
36
43
|
[TokenType.Text]: 'Text',
|
|
44
|
+
[TokenType.Punctuation]: 'Punctuation',
|
|
45
|
+
[TokenType.LanguageConstant]: 'LanguageConstant',
|
|
46
|
+
[TokenType.PropertyName]: 'JsonPropertyName',
|
|
47
|
+
[TokenType.LanguageConstant]: 'LanguageConstant',
|
|
48
|
+
[TokenType.Punctuation]: 'Punctuation',
|
|
49
|
+
[TokenType.PropertyValueString]: 'YamlPropertyValueString',
|
|
37
50
|
}
|
|
38
51
|
|
|
39
52
|
const RE_LINE_COMMENT_START = /^#/
|
|
40
53
|
const RE_WHITESPACE = /^ +/
|
|
41
54
|
const RE_CURLY_OPEN = /^\{/
|
|
42
55
|
const RE_CURLY_CLOSE = /^\}/
|
|
43
|
-
const RE_PROPERTY_NAME = /^[a-zA-Z
|
|
56
|
+
const RE_PROPERTY_NAME = /^[a-zA-Z\-\_\d]+\b(?=\s*=)/
|
|
44
57
|
const RE_COLON = /^:/
|
|
45
58
|
const RE_PROPERTY_VALUE = /^[^;\}]+/
|
|
46
59
|
const RE_SEMICOLON = /^;/
|
|
@@ -62,6 +75,11 @@ const RE_STAR = /^\*/
|
|
|
62
75
|
const RE_QUERY_NAME = /^[a-z\-]+/
|
|
63
76
|
const RE_QUERY_CONTENT = /^[^\)]+/
|
|
64
77
|
const RE_COMBINATOR = /^[\+\>\~]/
|
|
78
|
+
const RE_EQUAL_SIGN = /^=/
|
|
79
|
+
const RE_QUOTE_DOUBLE = /^"/
|
|
80
|
+
const RE_STRING_DOUBLE_QUOTE_CONTENT = /^[^"]+/
|
|
81
|
+
const RE_LINE_COMMENT = /^#.*/s
|
|
82
|
+
const RE_LANGUAGE_CONSTANT = /^(?:true|false)\b/
|
|
65
83
|
|
|
66
84
|
export const initialLineState = {
|
|
67
85
|
state: State.TopLevelContent,
|
|
@@ -85,9 +103,12 @@ export const tokenizeLine = (line, lineState) => {
|
|
|
85
103
|
const part = line.slice(index)
|
|
86
104
|
switch (state) {
|
|
87
105
|
case State.TopLevelContent:
|
|
88
|
-
if ((next = part.match(
|
|
106
|
+
if ((next = part.match(RE_PROPERTY_NAME))) {
|
|
107
|
+
token = TokenType.PropertyName
|
|
108
|
+
state = State.AfterPropertyName
|
|
109
|
+
} else if ((next = part.match(RE_LINE_COMMENT))) {
|
|
89
110
|
token = TokenType.Comment
|
|
90
|
-
state = State.
|
|
111
|
+
state = State.TopLevelContent
|
|
91
112
|
} else if ((next = part.match(RE_WHITESPACE))) {
|
|
92
113
|
token = TokenType.Whitespace
|
|
93
114
|
state = State.TopLevelContent
|
|
@@ -99,10 +120,33 @@ export const tokenizeLine = (line, lineState) => {
|
|
|
99
120
|
throw new Error('no')
|
|
100
121
|
}
|
|
101
122
|
break
|
|
102
|
-
case State.
|
|
103
|
-
if ((next = part.match(
|
|
123
|
+
case State.AfterPropertyName:
|
|
124
|
+
if ((next = part.match(RE_EQUAL_SIGN))) {
|
|
125
|
+
token = TokenType.Punctuation
|
|
126
|
+
state = State.AfterPropertyNameAfterEqualSign
|
|
127
|
+
} else if ((next = part.match(RE_WHITESPACE))) {
|
|
128
|
+
token = TokenType.Whitespace
|
|
129
|
+
state = State.AfterPropertyName
|
|
130
|
+
} else {
|
|
131
|
+
throw new Error('no')
|
|
132
|
+
}
|
|
133
|
+
break
|
|
134
|
+
case State.AfterPropertyNameAfterEqualSign:
|
|
135
|
+
if ((next = part.match(RE_WHITESPACE))) {
|
|
136
|
+
token = TokenType.Whitespace
|
|
137
|
+
state = State.AfterPropertyNameAfterEqualSign
|
|
138
|
+
} else if ((next = part.match(RE_LANGUAGE_CONSTANT))) {
|
|
139
|
+
token = TokenType.LanguageConstant
|
|
140
|
+
state = State.TopLevelContent
|
|
141
|
+
} else if ((next = part.match(RE_LINE_COMMENT))) {
|
|
104
142
|
token = TokenType.Comment
|
|
105
143
|
state = State.TopLevelContent
|
|
144
|
+
} else if ((next = part.match(RE_QUOTE_DOUBLE))) {
|
|
145
|
+
token = TokenType.Punctuation
|
|
146
|
+
state = State.InsideString
|
|
147
|
+
} else if ((next = part.match(RE_ANYTHING))) {
|
|
148
|
+
token = TokenType.PropertyValueString
|
|
149
|
+
state = State.TopLevelContent
|
|
106
150
|
} else {
|
|
107
151
|
throw new Error('no')
|
|
108
152
|
}
|
|
@@ -79,7 +79,7 @@ const RE_SLASH = /^\//
|
|
|
79
79
|
const RE_STRING_DOUBLE_QUOTE_CONTENT = /^[^"]+/
|
|
80
80
|
const RE_STRING_SINGLE_QUOTE_CONTENT = /^[^']+/
|
|
81
81
|
const RE_TAG_TEXT = /^[^\s>]+/
|
|
82
|
-
const RE_TAGNAME = /^[!\w]+/
|
|
82
|
+
const RE_TAGNAME = /^[!\w\-]+/
|
|
83
83
|
const RE_TEXT = /^[^<>\n]+/
|
|
84
84
|
const RE_WHITESPACE = /^\s+/
|
|
85
85
|
const RE_WORD = /^[^\s]+/
|
package/index.js
CHANGED
|
@@ -5,12 +5,15 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
|
5
5
|
|
|
6
6
|
export const sharedProcessPath = join(__dirname, 'src', 'sharedProcessMain.js')
|
|
7
7
|
|
|
8
|
-
export const exportStatic = async ({
|
|
8
|
+
export const exportStatic = async ({
|
|
9
|
+
extensionPath = process.cwd(),
|
|
10
|
+
testPath = '',
|
|
11
|
+
} = {}) => {
|
|
9
12
|
const fn = await import('./src/parts/ExportStatic/ExportStatic.js')
|
|
10
13
|
const root = process.cwd()
|
|
11
14
|
if (extensionPath !== root) {
|
|
12
15
|
extensionPath = join(root, extensionPath)
|
|
13
16
|
}
|
|
14
17
|
const pathPrefix = process.env.PATH_PREFIX || ''
|
|
15
|
-
await fn.exportStatic({ root, pathPrefix, extensionPath })
|
|
18
|
+
await fn.exportStatic({ root, pathPrefix, extensionPath, testPath })
|
|
16
19
|
}
|
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.7",
|
|
4
4
|
"description": "Utility package for @lvce-editor/server",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -17,12 +17,12 @@
|
|
|
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.7",
|
|
21
|
+
"@lvce-editor/extension-host-helper-process": "0.11.7",
|
|
22
|
+
"@lvce-editor/pty-host": "0.11.7",
|
|
23
23
|
"debug": "^4.3.4",
|
|
24
24
|
"execa": "^6.1.0",
|
|
25
|
-
"exit-hook": "^3.1.
|
|
25
|
+
"exit-hook": "^3.1.4",
|
|
26
26
|
"got": "^12.5.3",
|
|
27
27
|
"is-object": "^1.0.2",
|
|
28
28
|
"lines-and-columns": "^2.0.3",
|
|
@@ -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',
|
|
@@ -2,6 +2,7 @@ import { createWriteStream, writeFileSync } from 'node:fs'
|
|
|
2
2
|
import { performance } from 'node:perf_hooks'
|
|
3
3
|
import * as ExtensionHost from '../ExtensionHost/ExtensionHost.js'
|
|
4
4
|
import * as Process from '../Process/Process.js'
|
|
5
|
+
import * as Timeout from '../Timeout/Timeout.js'
|
|
5
6
|
|
|
6
7
|
export const measureLatencyBetweenExtensionHostAndSharedProcess = async (
|
|
7
8
|
socket,
|
|
@@ -77,7 +78,7 @@ export const allocateMemory = () => {
|
|
|
77
78
|
|
|
78
79
|
/* istanbul ignore next */
|
|
79
80
|
export const crashSharedProcess = () => {
|
|
80
|
-
setTimeout(() => {
|
|
81
|
+
Timeout.setTimeout(() => {
|
|
81
82
|
throw new Error('oops')
|
|
82
83
|
}, 0)
|
|
83
84
|
}
|
|
@@ -113,7 +114,7 @@ export const createProfile = async () => {
|
|
|
113
114
|
session.post('Profiler.start', () => {
|
|
114
115
|
// Invoke business logic under measurement here...
|
|
115
116
|
|
|
116
|
-
setTimeout(() => {
|
|
117
|
+
Timeout.setTimeout(() => {
|
|
117
118
|
session.post('Profiler.stop', (error, { profile }) => {
|
|
118
119
|
// Write profile to disk, upload, etc.
|
|
119
120
|
if (!error) {
|
|
@@ -637,11 +637,76 @@ const addExtension = async ({
|
|
|
637
637
|
})
|
|
638
638
|
}
|
|
639
639
|
|
|
640
|
+
const generateTestOverviewHtml = (dirents) => {
|
|
641
|
+
const pre = `<!DOCTYPE html>
|
|
642
|
+
<html lang="en">
|
|
643
|
+
<head>
|
|
644
|
+
<meta charset="UTF-8" />
|
|
645
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
646
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
647
|
+
<title>Tests</title>
|
|
648
|
+
</head>
|
|
649
|
+
<body>
|
|
650
|
+
<h1>Tests</h1>
|
|
651
|
+
<p>Available Tests</p>
|
|
652
|
+
<ul>
|
|
653
|
+
`
|
|
654
|
+
let middle = ``
|
|
655
|
+
// TODO properly escape name
|
|
656
|
+
for (const dirent of dirents) {
|
|
657
|
+
const name = dirent
|
|
658
|
+
middle += ` <li><a href="./${name}.html">${name}</a></li>
|
|
659
|
+
`
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
const post = ` </ul>
|
|
663
|
+
</body>
|
|
664
|
+
</html>
|
|
665
|
+
`
|
|
666
|
+
return pre + middle + post
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
const getName = (name) => {
|
|
670
|
+
return name.slice(0, -'.js'.length)
|
|
671
|
+
}
|
|
672
|
+
const isTestFile = (file) => {
|
|
673
|
+
return file !== '_all.js'
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
const getTestFiles = (testFilesRaw) => {
|
|
677
|
+
return testFilesRaw.map(getName).filter(isTestFile)
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
const addTestFiles = async ({ testPath, commitHash, root, pathPrefix }) => {
|
|
681
|
+
await FileSystem.copy(
|
|
682
|
+
`${root}/${testPath}/src`,
|
|
683
|
+
`${root}/dist/${commitHash}/packages/extension-host-worker-tests/src`
|
|
684
|
+
)
|
|
685
|
+
const testFilesRaw = await FileSystem.readDir(`${root}/${testPath}/src`)
|
|
686
|
+
const testFiles = getTestFiles(testFilesRaw)
|
|
687
|
+
await FileSystem.mkdir(`${root}/dist/${commitHash}/tests`)
|
|
688
|
+
await FileSystem.mkdir(`${root}/dist/tests`)
|
|
689
|
+
console.log({ testFiles })
|
|
690
|
+
for (const testFile of testFiles) {
|
|
691
|
+
await FileSystem.copyFile(
|
|
692
|
+
`${root}/dist/index.html`,
|
|
693
|
+
`${root}/dist/tests/${testFile}.html`
|
|
694
|
+
)
|
|
695
|
+
}
|
|
696
|
+
const testOverviewHtml = generateTestOverviewHtml(testFiles)
|
|
697
|
+
await FileSystem.writeFile(`${root}/dist/tests/index.html`, testOverviewHtml)
|
|
698
|
+
}
|
|
699
|
+
|
|
640
700
|
/**
|
|
641
701
|
*
|
|
642
|
-
* @param {{root:string, pathPrefix:string , extensionPath:string
|
|
702
|
+
* @param {{root:string, pathPrefix:string , extensionPath:string, testPath:string }} param0
|
|
643
703
|
*/
|
|
644
|
-
export const exportStatic = async ({
|
|
704
|
+
export const exportStatic = async ({
|
|
705
|
+
root,
|
|
706
|
+
pathPrefix,
|
|
707
|
+
extensionPath,
|
|
708
|
+
testPath,
|
|
709
|
+
}) => {
|
|
645
710
|
if (pathPrefix === 'auto') {
|
|
646
711
|
const extensionJson = await readExtensionManifest(
|
|
647
712
|
Path.join(extensionPath, 'extension.json')
|
|
@@ -679,4 +744,15 @@ export const exportStatic = async ({ root, pathPrefix, extensionPath }) => {
|
|
|
679
744
|
root,
|
|
680
745
|
})
|
|
681
746
|
console.timeEnd('addExtension')
|
|
747
|
+
|
|
748
|
+
if (testPath) {
|
|
749
|
+
console.time('addTestFiles')
|
|
750
|
+
await addTestFiles({
|
|
751
|
+
testPath,
|
|
752
|
+
commitHash,
|
|
753
|
+
pathPrefix,
|
|
754
|
+
root,
|
|
755
|
+
})
|
|
756
|
+
console.timeEnd('addTestFiles')
|
|
757
|
+
}
|
|
682
758
|
}
|
|
@@ -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,11 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
2
2
|
import * as ExtensionManifest from '../ExtensionManifest/ExtensionManifest.js'
|
|
3
3
|
import * as ExtensionManifestStatus from '../ExtensionManifestStatus/ExtensionManifestStatus.js'
|
|
4
4
|
import * as FileSystem from '../FileSystem/FileSystem.js'
|
|
5
|
-
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
6
5
|
import * as Path from '../Path/Path.js'
|
|
7
6
|
import * as Platform from '../Platform/Platform.js'
|
|
8
7
|
import * as SymLink from '../SymLink/SymLink.js'
|
|
8
|
+
import { VError } from '../VError/VError.js'
|
|
9
9
|
|
|
10
10
|
const linkFallBack = async (path) => {
|
|
11
11
|
try {
|
|
@@ -19,7 +19,6 @@ const linkFallBack = async (path) => {
|
|
|
19
19
|
await FileSystem.remove(to)
|
|
20
20
|
await SymLink.createSymLink(path, to)
|
|
21
21
|
} catch (error) {
|
|
22
|
-
console.log({ error })
|
|
23
22
|
throw new VError(error, `Failed to link extension`)
|
|
24
23
|
}
|
|
25
24
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { mkdir, rename, rm } from 'node:fs/promises'
|
|
2
|
-
import VError from '
|
|
2
|
+
import { VError } from '../VError/VError.js'
|
|
3
3
|
import * as Debug from '../Debug/Debug.js'
|
|
4
4
|
import * as ExtensionManifestInputType from '../ExtensionManifestInputType/ExtensionManifestInputType.js'
|
|
5
5
|
import * as ExtensionManifests from '../ExtensionManifests/ExtensionManifests.js'
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import isObject from 'is-object'
|
|
2
|
-
import
|
|
2
|
+
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
3
3
|
import * as ExtensionManifestStatus from '../ExtensionManifestStatus/ExtensionManifestStatus.js'
|
|
4
4
|
import * as ReadJson from '../JsonFile/JsonFile.js'
|
|
5
5
|
import * as Path from '../Path/Path.js'
|
|
6
|
-
import
|
|
6
|
+
import { VError } from '../VError/VError.js'
|
|
7
7
|
|
|
8
8
|
const RE_EXTENSION_FRAGMENT = /.+(\/|\\)(.+)$/
|
|
9
9
|
|
|
@@ -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,
|
|
@@ -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
|
}
|
|
@@ -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,15 +1,31 @@
|
|
|
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 TextSearchResultType from '../TextSearchResultType/TextSearchResultType.js'
|
|
4
6
|
|
|
5
7
|
const MAX_SEARCH_RESULTS = 300
|
|
6
8
|
|
|
9
|
+
const BEFORE = 20
|
|
10
|
+
const AFTER = 20
|
|
11
|
+
|
|
7
12
|
const toSearchResult = (parsedLine) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
const results = []
|
|
14
|
+
const lines = parsedLine.data.lines.text
|
|
15
|
+
const lineNumber = parsedLine.data.line_number
|
|
16
|
+
for (const submatch of parsedLine.data.submatches) {
|
|
17
|
+
const previewStart = Math.max(submatch.start - BEFORE, 0)
|
|
18
|
+
const previewEnd = Math.min(submatch.end + AFTER, lines.length)
|
|
19
|
+
const previewText = lines.slice(previewStart, previewEnd)
|
|
20
|
+
results.push({
|
|
21
|
+
type: TextSearchResultType.Match,
|
|
22
|
+
start: submatch.start - previewStart,
|
|
23
|
+
end: submatch.end - previewStart,
|
|
24
|
+
lineNumber,
|
|
25
|
+
text: previewText,
|
|
26
|
+
})
|
|
12
27
|
}
|
|
28
|
+
return results
|
|
13
29
|
}
|
|
14
30
|
|
|
15
31
|
// TODO update vscode-ripgrep when https://github.com/mhinz/vim-grepper/issues/244, https://github.com/BurntSushi/ripgrep/issues/1892 is fixed
|
|
@@ -25,79 +41,90 @@ const useNice = !Platform.isWindows
|
|
|
25
41
|
// TODO update client
|
|
26
42
|
// TODO not always run nice, maybe configure nice via flag/options
|
|
27
43
|
|
|
28
|
-
const ParsedLineType = {
|
|
29
|
-
Begin: 'begin',
|
|
30
|
-
Match: 'match',
|
|
31
|
-
Summary: 'summary',
|
|
32
|
-
}
|
|
33
|
-
|
|
34
44
|
export const search = async (searchDir, searchString) => {
|
|
35
45
|
// TODO reject promise when ripgrep search fails
|
|
36
46
|
return new Promise((resolve, reject) => {
|
|
47
|
+
const ripGrepArgs = [
|
|
48
|
+
'--smart-case',
|
|
49
|
+
'--stats',
|
|
50
|
+
'--json',
|
|
51
|
+
'--fixed-strings',
|
|
52
|
+
searchString,
|
|
53
|
+
'.',
|
|
54
|
+
]
|
|
37
55
|
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
|
-
)
|
|
56
|
+
? spawn('nice', ['-20', RgPath.rgPath, ...ripGrepArgs], {
|
|
57
|
+
cwd: searchDir,
|
|
58
|
+
})
|
|
59
|
+
: spawn(RgPath.rgPath, ripGrepArgs, {
|
|
60
|
+
cwd: searchDir,
|
|
61
|
+
})
|
|
60
62
|
const allSearchResults = Object.create(null)
|
|
61
63
|
let buffer = ''
|
|
62
64
|
let stats = {}
|
|
65
|
+
let limitHit = false
|
|
63
66
|
let numberOfResults = 0
|
|
64
67
|
// TODO use pipeline / transform stream maybe
|
|
65
68
|
|
|
69
|
+
const handleLine = (line) => {
|
|
70
|
+
const parsedLine = JSON.parse(line)
|
|
71
|
+
switch (parsedLine.type) {
|
|
72
|
+
case RipGrepParsedLineType.Begin:
|
|
73
|
+
allSearchResults[parsedLine.data.path.text] = [
|
|
74
|
+
{
|
|
75
|
+
type: TextSearchResultType.File,
|
|
76
|
+
start: 0,
|
|
77
|
+
end: 0,
|
|
78
|
+
lineNumber: 0,
|
|
79
|
+
text: parsedLine.data.path.text,
|
|
80
|
+
},
|
|
81
|
+
]
|
|
82
|
+
break
|
|
83
|
+
case RipGrepParsedLineType.Match:
|
|
84
|
+
numberOfResults++
|
|
85
|
+
allSearchResults[parsedLine.data.path.text].push(
|
|
86
|
+
...toSearchResult(parsedLine)
|
|
87
|
+
)
|
|
88
|
+
break
|
|
89
|
+
case RipGrepParsedLineType.Summary:
|
|
90
|
+
stats = parsedLine.data
|
|
91
|
+
break
|
|
92
|
+
default:
|
|
93
|
+
break
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let total = 0
|
|
66
98
|
const handleData = (chunk) => {
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const parsedLine = JSON.parse(line)
|
|
73
|
-
switch (parsedLine.type) {
|
|
74
|
-
case ParsedLineType.Begin: {
|
|
75
|
-
allSearchResults[parsedLine.data.path.text] = []
|
|
76
|
-
break
|
|
77
|
-
}
|
|
78
|
-
case ParsedLineType.Match: {
|
|
79
|
-
numberOfResults++
|
|
80
|
-
allSearchResults[parsedLine.data.path.text].push(
|
|
81
|
-
toSearchResult(parsedLine)
|
|
82
|
-
)
|
|
83
|
-
break
|
|
84
|
-
}
|
|
85
|
-
case ParsedLineType.Summary:
|
|
86
|
-
stats = parsedLine.data
|
|
87
|
-
break
|
|
88
|
-
default:
|
|
89
|
-
break
|
|
90
|
-
}
|
|
99
|
+
let newLineIndex = chunk.indexOf('\n')
|
|
100
|
+
const dataString = buffer + chunk
|
|
101
|
+
if (newLineIndex === -1) {
|
|
102
|
+
buffer = dataString
|
|
103
|
+
return
|
|
91
104
|
}
|
|
105
|
+
total += chunk.length
|
|
106
|
+
newLineIndex += buffer.length
|
|
107
|
+
let previousIndex = 0
|
|
108
|
+
while (newLineIndex >= 0) {
|
|
109
|
+
const line = dataString.slice(previousIndex, newLineIndex)
|
|
110
|
+
handleLine(line)
|
|
111
|
+
previousIndex = newLineIndex + 1
|
|
112
|
+
newLineIndex = dataString.indexOf('\n', previousIndex)
|
|
113
|
+
}
|
|
114
|
+
buffer = dataString.slice(previousIndex)
|
|
115
|
+
|
|
92
116
|
if (numberOfResults > MAX_SEARCH_RESULTS) {
|
|
117
|
+
limitHit = true
|
|
93
118
|
childProcess.kill()
|
|
94
119
|
}
|
|
95
120
|
}
|
|
96
121
|
|
|
97
122
|
const handleClose = () => {
|
|
123
|
+
const results = Object.values(allSearchResults).flat(1)
|
|
98
124
|
resolve({
|
|
99
|
-
results
|
|
125
|
+
results,
|
|
100
126
|
stats,
|
|
127
|
+
limitHit,
|
|
101
128
|
})
|
|
102
129
|
}
|
|
103
130
|
const handleError = (error) => {
|
|
@@ -106,8 +133,10 @@ export const search = async (searchDir, searchString) => {
|
|
|
106
133
|
resolve({
|
|
107
134
|
results: [],
|
|
108
135
|
stats,
|
|
136
|
+
limitHit,
|
|
109
137
|
})
|
|
110
138
|
}
|
|
139
|
+
childProcess.stdout.setEncoding('utf8')
|
|
111
140
|
childProcess.stdout.on('data', handleData)
|
|
112
141
|
childProcess.once('close', handleClose)
|
|
113
142
|
childProcess.once('error', handleError)
|
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
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const getCombinedMessage = (error, message) => {
|
|
2
|
+
let stringifiedError = `${error}`
|
|
3
|
+
if (stringifiedError.startsWith('Error: ')) {
|
|
4
|
+
stringifiedError = stringifiedError.slice(`Error: `.length)
|
|
5
|
+
} else if (stringifiedError.startsWith('VError: ')) {
|
|
6
|
+
stringifiedError = stringifiedError.slice(`VError: `.length)
|
|
7
|
+
}
|
|
8
|
+
if (message) {
|
|
9
|
+
return `${message}: ${stringifiedError}`
|
|
10
|
+
}
|
|
11
|
+
return stringifiedError
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const mergeStacks = (parent, child) => {
|
|
15
|
+
if (!child) {
|
|
16
|
+
return parent
|
|
17
|
+
}
|
|
18
|
+
const parentNewLineIndex = parent.indexOf('\n')
|
|
19
|
+
const childNewLineIndex = child.indexOf('\n')
|
|
20
|
+
const parentFirstLine = parent.slice(0, parentNewLineIndex)
|
|
21
|
+
const childRest = child.slice(childNewLineIndex)
|
|
22
|
+
const childFirstLine = child.slice(0, childNewLineIndex)
|
|
23
|
+
if (parentFirstLine.includes(childFirstLine)) {
|
|
24
|
+
return parentFirstLine + childRest
|
|
25
|
+
}
|
|
26
|
+
return child
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class VError extends Error {
|
|
30
|
+
constructor(error, message) {
|
|
31
|
+
const combinedMessage = getCombinedMessage(error, message)
|
|
32
|
+
super(combinedMessage)
|
|
33
|
+
this.name = 'VError'
|
|
34
|
+
if (error instanceof Error) {
|
|
35
|
+
this.stack = mergeStacks(this.stack, error.stack)
|
|
36
|
+
}
|
|
37
|
+
if (error.codeFrame) {
|
|
38
|
+
this.codeFrame = error.codeFrame
|
|
39
|
+
}
|
|
40
|
+
if (error.code) {
|
|
41
|
+
this.code = error.code
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|