Skip to content

Commit 1ff36c4

Browse files
feat: implement streaming on extension host
1 parent e6bc9fa commit 1ff36c4

File tree

3 files changed

+34
-17
lines changed

3 files changed

+34
-17
lines changed

src/types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@ export type SgSearch = {
2323

2424
export type Definition = {
2525
parent2child: {
26-
search: {
26+
searchResultStreaming: {
2727
searchResult: SgSearch[]
2828
id: number
2929
}
30+
searchEnd: {
31+
id: number
32+
}
3033
}
3134
child2parent: {
3235
search: {

src/view.ts

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,20 @@ export function activate(context: vscode.ExtensionContext) {
1515
)
1616
)
1717
}
18+
type StreamingHandler = (r: SgSearch[]) => void
1819

1920
let child: ChildProcessWithoutNullStreams | undefined
20-
2121
function streamedPromise(
22-
proc: ChildProcessWithoutNullStreams
23-
): Promise<SgSearch[]> {
24-
// push all data into the result array
25-
let result: SgSearch[] = []
22+
proc: ChildProcessWithoutNullStreams,
23+
handler: StreamingHandler
24+
): Promise<number> {
2625
// don't concatenate a single string/buffer
2726
// only maintain the last trailing line
2827
let trailingLine = ''
2928
// stream parsing JSON
3029
proc.stdout.on('data', (data: string) => {
30+
// collect results in this batch
31+
let result: SgSearch[] = []
3132
const lines = (trailingLine + data).split(/\r?\n/)
3233
trailingLine = ''
3334
for (let i = 0; i < lines.length; i++) {
@@ -40,13 +41,14 @@ function streamedPromise(
4041
}
4142
}
4243
}
44+
handler(result)
4345
})
4446
return new Promise((resolve, reject) =>
4547
proc.on('exit', (code, signal) => {
4648
// exit without signal, search ends correctly
4749
// TODO: is it correct now?
4850
if (!signal && code === 0) {
49-
resolve(result)
51+
resolve(code)
5052
} else {
5153
reject([code, signal])
5254
}
@@ -55,27 +57,26 @@ function streamedPromise(
5557
}
5658

5759
async function uniqueCommand(
58-
proc: ChildProcessWithoutNullStreams
59-
): Promise<SgSearch[]> {
60+
proc: ChildProcessWithoutNullStreams,
61+
handler: StreamingHandler
62+
) {
6063
// kill previous search
6164
if (child) {
6265
child.kill('SIGTERM')
6366
}
6467
try {
6568
// set current proc to child
6669
child = proc
67-
const ret = await streamedPromise(proc)
70+
await streamedPromise(proc, handler)
6871
// unset child only when the promise succeed
6972
// interrupted proc will be replaced by latter proc
7073
child = undefined
71-
return ret
7274
} catch (e) {
7375
console.error(e)
74-
return []
7576
}
7677
}
7778

78-
async function getPatternRes(pattern: string) {
79+
async function getPatternRes(pattern: string, handler: StreamingHandler) {
7980
if (!pattern) {
8081
return
8182
}
@@ -88,7 +89,7 @@ async function getPatternRes(pattern: string) {
8889
let proc = spawn(command, ['run', '--pattern', pattern, '--json=stream'], {
8990
cwd: uris[0]
9091
})
91-
return uniqueCommand(proc)
92+
return uniqueCommand(proc, handler)
9293
}
9394

9495
function openFile({
@@ -139,8 +140,13 @@ function setupParentPort(webviewView: vscode.WebviewView) {
139140
})
140141

141142
parentPort.onMessage('search', async payload => {
142-
const res = (await getPatternRes(payload.inputValue)) ?? []
143-
parentPort.postMessage('search', { ...payload, searchResult: res })
143+
await getPatternRes(payload.inputValue, ret => {
144+
parentPort.postMessage('searchResultStreaming', {
145+
...payload,
146+
searchResult: ret
147+
})
148+
})
149+
parentPort.postMessage('searchEnd', payload)
144150
})
145151

146152
parentPort.onMessage('openFile', async payload => openFile(payload))

src/webview/hooks/useSearch.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,22 @@ function postSearch(inputValue: string) {
2222
})
2323
}
2424

25-
childPort.onMessage('search', event => {
25+
childPort.onMessage('searchResultStreaming', event => {
2626
if (event.id !== id) {
2727
return
2828
}
2929
currentResolve(event.searchResult)
3030
currentResolve = () => {}
3131
currentReject = () => {}
3232
})
33+
childPort.onMessage('searchEnd', event => {
34+
if (event.id !== id) {
35+
return
36+
}
37+
currentResolve([])
38+
currentResolve = () => {}
39+
currentReject = () => {}
40+
})
3341

3442
function groupBy(matches: SgSearch[]) {
3543
const groups = new Map<string, SgSearch[]>()

0 commit comments

Comments
 (0)