@tui-sandbox/library 7.2.0 → 7.3.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/CHANGELOG.md +14 -0
- package/dist/browser/assets/{index-D3uBGfVO.js → index-DUKWG3jG.js} +6 -6
- package/dist/browser/index.html +1 -1
- package/dist/src/scripts/tui.js +103 -9
- package/dist/src/server/TestServer.js +6 -6
- package/dist/src/server/neovim/NeovimApplication.d.ts +3 -1
- package/dist/src/server/neovim/NeovimApplication.js +6 -0
- package/dist/src/server/neovim/NeovimJavascriptApiClient.js +2 -2
- package/dist/src/server/neovim/index.d.ts +4 -1
- package/dist/src/server/neovim/index.js +13 -2
- package/dist/src/server/server.js +1 -1
- package/dist/src/server/utilities/DisposableSingleApplication.d.ts +3 -2
- package/dist/src/server/utilities/DisposableSingleApplication.js +4 -0
- package/dist/src/server/utilities/DisposableSingleApplication.test.js +18 -0
- package/dist/src/server/utilities/TerminalApplication.d.ts +5 -0
- package/dist/src/server/utilities/TerminalApplication.js +13 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/src/scripts/tui.ts +54 -10
- package/src/server/TestServer.ts +8 -6
- package/src/server/neovim/NeovimApplication.ts +12 -2
- package/src/server/neovim/NeovimJavascriptApiClient.ts +2 -2
- package/src/server/neovim/index.ts +15 -3
- package/src/server/server.ts +1 -1
- package/src/server/utilities/DisposableSingleApplication.test.ts +23 -2
- package/src/server/utilities/DisposableSingleApplication.ts +10 -2
- package/src/server/utilities/TerminalApplication.ts +14 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tui-sandbox/library",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.3.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@catppuccin/palette": "1.7.1",
|
|
11
|
-
"@trpc/client": "11.0.0-rc.
|
|
12
|
-
"@trpc/server": "11.0.0-rc.
|
|
11
|
+
"@trpc/client": "11.0.0-rc.648",
|
|
12
|
+
"@trpc/server": "11.0.0-rc.648",
|
|
13
13
|
"@xterm/addon-attach": "0.11.0",
|
|
14
14
|
"@xterm/addon-fit": "0.10.0",
|
|
15
15
|
"@xterm/xterm": "5.5.0",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"express": "4.21.1",
|
|
21
21
|
"neovim": "5.3.0",
|
|
22
22
|
"node-pty": "1.0.0",
|
|
23
|
-
"prettier": "3.
|
|
23
|
+
"prettier": "3.4.1",
|
|
24
24
|
"tsx": "4.19.2",
|
|
25
|
-
"type-fest": "4.
|
|
25
|
+
"type-fest": "4.29.0",
|
|
26
26
|
"winston": "3.17.0",
|
|
27
27
|
"zod": "3.23.8"
|
|
28
28
|
},
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"@types/command-exists": "1.2.3",
|
|
32
32
|
"@types/cors": "2.8.17",
|
|
33
33
|
"@types/express": "5.0.0",
|
|
34
|
-
"@types/node": "22.
|
|
34
|
+
"@types/node": "22.10.1",
|
|
35
35
|
"nodemon": "3.1.7",
|
|
36
|
-
"vite": "
|
|
37
|
-
"vitest": "2.1.
|
|
36
|
+
"vite": "6.0.1",
|
|
37
|
+
"vitest": "2.1.6"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"cypress": "^13",
|
package/src/scripts/tui.ts
CHANGED
|
@@ -1,32 +1,63 @@
|
|
|
1
|
+
import assert from "node:assert"
|
|
1
2
|
import { stat } from "node:fs/promises"
|
|
2
3
|
import path from "node:path"
|
|
3
4
|
import { createCypressSupportFile } from "../server/cypress-support/createCypressSupportFile.js"
|
|
4
5
|
import type { TestServerConfig } from "../server/index.js"
|
|
5
6
|
import { startTestServer, updateTestdirectorySchemaFile } from "../server/index.js"
|
|
7
|
+
import type { StdoutOrStderrMessage } from "../server/neovim/NeovimApplication.js"
|
|
8
|
+
import { NeovimApplication } from "../server/neovim/NeovimApplication.js"
|
|
9
|
+
import { prepareNewTestDirectory } from "../server/neovim/index.js"
|
|
6
10
|
|
|
7
11
|
//
|
|
8
12
|
// This is the main entrypoint to tui-sandbox
|
|
9
13
|
//
|
|
10
14
|
|
|
11
|
-
// the arguments passed to this script start at index 2
|
|
12
|
-
const args = process.argv.slice(2)
|
|
13
|
-
|
|
14
|
-
if (args[0] !== "start") {
|
|
15
|
-
throw new Error(`Usage: tui start`)
|
|
16
|
-
}
|
|
17
15
|
const outputFileName = "MyTestDirectory.ts"
|
|
18
16
|
|
|
19
17
|
/** The cwd in the user's directory when they are running this script. Not the
|
|
20
18
|
* cwd of the script itself. */
|
|
21
19
|
const cwd = process.cwd()
|
|
20
|
+
const config = {
|
|
21
|
+
testEnvironmentPath: path.join(cwd, "test-environment/"),
|
|
22
|
+
outputFilePath: path.join(cwd, outputFileName),
|
|
23
|
+
} satisfies TestServerConfig
|
|
24
|
+
|
|
25
|
+
// the arguments passed to this script start at index 2
|
|
26
|
+
const args = process.argv.slice(2)
|
|
27
|
+
|
|
28
|
+
if (args[0] === "neovim") {
|
|
29
|
+
if (!(args[1] === "exec" && args.length === 3)) {
|
|
30
|
+
showUsageAndExit()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const command = args[2]
|
|
34
|
+
assert(command, "No command provided")
|
|
35
|
+
|
|
36
|
+
{
|
|
37
|
+
// automatically dispose of the neovim instance when done
|
|
38
|
+
await using app = new NeovimApplication(config.testEnvironmentPath)
|
|
39
|
+
app.events.on("stdout" satisfies StdoutOrStderrMessage, data => {
|
|
40
|
+
console.log(` neovim output: ${data}`)
|
|
41
|
+
})
|
|
42
|
+
const testDirectory = await prepareNewTestDirectory(config)
|
|
43
|
+
await app.startNextAndKillCurrent(
|
|
44
|
+
testDirectory,
|
|
45
|
+
{ filename: "empty.txt", headlessCmd: command },
|
|
46
|
+
{ cols: 80, rows: 24 }
|
|
47
|
+
)
|
|
48
|
+
await app.application.untilExit()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
process.exit(0)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (args[0] !== "start") {
|
|
55
|
+
showUsageAndExit()
|
|
56
|
+
}
|
|
22
57
|
console.log(`🚀 Starting test server in ${cwd} - this should be the root of your integration-tests directory 🤞🏻`)
|
|
23
58
|
await stat(path.join(cwd, outputFileName))
|
|
24
59
|
|
|
25
60
|
try {
|
|
26
|
-
const config = {
|
|
27
|
-
testEnvironmentPath: path.join(cwd, "test-environment/"),
|
|
28
|
-
outputFilePath: path.join(cwd, outputFileName),
|
|
29
|
-
} satisfies TestServerConfig
|
|
30
61
|
await createCypressSupportFile({
|
|
31
62
|
cypressSupportDirectoryPath: path.join(cwd, "cypress", "support"),
|
|
32
63
|
supportFileName: "tui-sandbox.ts",
|
|
@@ -36,3 +67,16 @@ try {
|
|
|
36
67
|
} catch (e) {
|
|
37
68
|
console.error(e)
|
|
38
69
|
}
|
|
70
|
+
|
|
71
|
+
function showUsageAndExit() {
|
|
72
|
+
console.log(
|
|
73
|
+
[
|
|
74
|
+
//
|
|
75
|
+
`Usage (pick one):`,
|
|
76
|
+
` tui start`,
|
|
77
|
+
` tui neovim exec '<ex-command>'`,
|
|
78
|
+
].join("\n")
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
process.exit(1)
|
|
82
|
+
}
|
package/src/server/TestServer.ts
CHANGED
|
@@ -39,7 +39,9 @@ export class TestServer {
|
|
|
39
39
|
} catch (e) {
|
|
40
40
|
// This is normal when developing the tui-sandbox library locally. It
|
|
41
41
|
// should always exist when using it as an npm package, however.
|
|
42
|
-
console.log(
|
|
42
|
+
console.log(
|
|
43
|
+
`⚠️ Warning: Looks like the tui-sandbox root contents directory is not accessible at: ${publicPath}`
|
|
44
|
+
)
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
// eslint-disable-next-line import-x/no-named-as-default-member
|
|
@@ -47,24 +49,24 @@ export class TestServer {
|
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
app.use("/ping", (_, res) => {
|
|
50
|
-
console.log("🏓 received /ping")
|
|
52
|
+
// console.log("🏓 received /ping")
|
|
51
53
|
res.send("pong")
|
|
52
54
|
})
|
|
53
55
|
|
|
54
56
|
const server = app.listen(this.settings.port, "0.0.0.0")
|
|
55
57
|
|
|
56
58
|
server.on("connection", socket => {
|
|
57
|
-
const connectionInfo = `${socket.remoteAddress}:${socket.remotePort}`
|
|
58
|
-
console.log(`➕➕ Connection from ${connectionInfo}`)
|
|
59
|
+
// const connectionInfo = `${socket.remoteAddress}:${socket.remotePort}`
|
|
60
|
+
// console.log(`➕➕ Connection from ${connectionInfo}`)
|
|
59
61
|
socket.once("close", () => {
|
|
60
|
-
console.log(`➖➖ Connection from ${connectionInfo}`)
|
|
62
|
+
// console.log(`➖➖ Connection from ${connectionInfo}`)
|
|
61
63
|
})
|
|
62
64
|
})
|
|
63
65
|
|
|
64
66
|
console.log(`✅ Server listening on port ${this.settings.port}`)
|
|
65
67
|
|
|
66
68
|
await Promise.race([once(process, "SIGTERM"), once(process, "SIGINT")])
|
|
67
|
-
console.log("Shutting down...")
|
|
69
|
+
console.log("😴 Shutting down...")
|
|
68
70
|
server.close(error => {
|
|
69
71
|
if (error) {
|
|
70
72
|
console.error("Error closing server", error)
|
|
@@ -56,12 +56,15 @@ Run "nvim -V1 -v" for more info
|
|
|
56
56
|
|
|
57
57
|
*/
|
|
58
58
|
|
|
59
|
-
export type
|
|
59
|
+
export type StdoutOrStderrMessage = "stdout"
|
|
60
60
|
|
|
61
61
|
export type StartNeovimGenericArguments = {
|
|
62
62
|
filename: string | { openInVerticalSplits: string[] }
|
|
63
63
|
startupScriptModifications?: string[]
|
|
64
64
|
|
|
65
|
+
/** Executes the given command with --headless -c <command> -c qa */
|
|
66
|
+
headlessCmd?: string
|
|
67
|
+
|
|
65
68
|
/** Additions to the environment variables for the Neovim process. These
|
|
66
69
|
* override any already existing environment variables. */
|
|
67
70
|
additionalEnvironmentVariables?: Record<string, string> | undefined
|
|
@@ -128,6 +131,13 @@ export class NeovimApplication {
|
|
|
128
131
|
}
|
|
129
132
|
}
|
|
130
133
|
|
|
134
|
+
if (startArgs.headlessCmd) {
|
|
135
|
+
// NOTE: update the doc comment above if this changes
|
|
136
|
+
neovimArguments.push("--headless")
|
|
137
|
+
neovimArguments.push("-c", startArgs.headlessCmd)
|
|
138
|
+
neovimArguments.push("-c", "qa")
|
|
139
|
+
}
|
|
140
|
+
|
|
131
141
|
const id = Math.random().toString().slice(2, 8)
|
|
132
142
|
const socketPath = `${tmpdir()}/tui-sandbox-nvim-socket-${id}`
|
|
133
143
|
neovimArguments.push("--listen", socketPath)
|
|
@@ -146,7 +156,7 @@ export class NeovimApplication {
|
|
|
146
156
|
|
|
147
157
|
onStdoutOrStderr(data) {
|
|
148
158
|
data satisfies string
|
|
149
|
-
stdout.emit("stdout" satisfies
|
|
159
|
+
stdout.emit("stdout" satisfies StdoutOrStderrMessage, data)
|
|
150
160
|
},
|
|
151
161
|
})
|
|
152
162
|
})
|
|
@@ -14,10 +14,10 @@ export function connectNeovimApi(socketPath: string): Lazy<Promise<NeovimJavascr
|
|
|
14
14
|
for (let i = 0; i < 100; i++) {
|
|
15
15
|
try {
|
|
16
16
|
await access(socketPath)
|
|
17
|
-
console.log(`socket file ${socketPath} created after at attempt ${i + 1}`)
|
|
17
|
+
// console.log(`socket file ${socketPath} created after at attempt ${i + 1}`)
|
|
18
18
|
break
|
|
19
19
|
} catch (e) {
|
|
20
|
-
console.log(`polling for socket file ${socketPath} to be created (attempt ${i + 1})`)
|
|
20
|
+
// console.log(`polling for socket file ${socketPath} to be created (attempt ${i + 1})`)
|
|
21
21
|
await new Promise(resolve => setTimeout(resolve, 100 satisfies PollingInterval))
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -12,14 +12,18 @@ import type {
|
|
|
12
12
|
} from "../types.js"
|
|
13
13
|
import type { TestServerConfig } from "../updateTestdirectorySchemaFile.js"
|
|
14
14
|
import { convertEventEmitterToAsyncGenerator } from "../utilities/generator.js"
|
|
15
|
+
import { Lazy } from "../utilities/Lazy.js"
|
|
15
16
|
import type { TabId } from "../utilities/tabId.js"
|
|
16
17
|
import { createTempDir, removeTestDirectories } from "./environment/createTempDir.js"
|
|
17
18
|
import type { TerminalDimensions } from "./NeovimApplication.js"
|
|
18
19
|
import { NeovimApplication } from "./NeovimApplication.js"
|
|
19
20
|
|
|
20
21
|
const neovims = new Map<TabId["tabId"], NeovimApplication>()
|
|
22
|
+
export const resources: Lazy<AsyncDisposableStack> = new Lazy(() => {
|
|
23
|
+
return new AsyncDisposableStack()
|
|
24
|
+
})
|
|
21
25
|
|
|
22
|
-
export async function
|
|
26
|
+
export async function initializeStdout(
|
|
23
27
|
options: { client: TabId },
|
|
24
28
|
signal: AbortSignal | undefined,
|
|
25
29
|
testEnvironmentPath: string
|
|
@@ -28,6 +32,9 @@ export async function onStdout(
|
|
|
28
32
|
const neovim = neovims.get(tabId) ?? new NeovimApplication(testEnvironmentPath)
|
|
29
33
|
if (neovims.get(tabId) === undefined) {
|
|
30
34
|
neovims.set(tabId, neovim)
|
|
35
|
+
resources.get().adopt(neovim, async n => {
|
|
36
|
+
await n[Symbol.asyncDispose]()
|
|
37
|
+
})
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
const stdout = convertEventEmitterToAsyncGenerator(neovim.events, "stdout")
|
|
@@ -51,13 +58,18 @@ export async function start(
|
|
|
51
58
|
const neovim = neovims.get(tabId.tabId)
|
|
52
59
|
assert(neovim, `Neovim instance not found for client id ${tabId.tabId}`)
|
|
53
60
|
|
|
54
|
-
await
|
|
55
|
-
const testDirectory = await createTempDir(config)
|
|
61
|
+
const testDirectory = await prepareNewTestDirectory(config)
|
|
56
62
|
await neovim.startNextAndKillCurrent(testDirectory, options, terminalDimensions)
|
|
57
63
|
|
|
58
64
|
return testDirectory
|
|
59
65
|
}
|
|
60
66
|
|
|
67
|
+
export async function prepareNewTestDirectory(config: TestServerConfig): Promise<TestDirectory> {
|
|
68
|
+
await removeTestDirectories(config.testEnvironmentPath)
|
|
69
|
+
const testDirectory = await createTempDir(config)
|
|
70
|
+
return testDirectory
|
|
71
|
+
}
|
|
72
|
+
|
|
61
73
|
export async function sendStdin(options: { tabId: TabId; data: string }): Promise<void> {
|
|
62
74
|
const neovim = neovims.get(options.tabId.tabId)
|
|
63
75
|
assert(
|
package/src/server/server.ts
CHANGED
|
@@ -71,7 +71,7 @@ export async function createAppRouter(config: TestServerConfig) {
|
|
|
71
71
|
)
|
|
72
72
|
}),
|
|
73
73
|
onStdout: trpc.procedure.input(z.object({ client: tabIdSchema })).subscription(options => {
|
|
74
|
-
return neovim.
|
|
74
|
+
return neovim.initializeStdout(options.input, options.signal, config.testEnvironmentPath)
|
|
75
75
|
}),
|
|
76
76
|
sendStdin: trpc.procedure.input(z.object({ tabId: tabIdSchema, data: z.string() })).mutation(options => {
|
|
77
77
|
return neovim.sendStdin(options.input)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { StartableApplication } from "./DisposableSingleApplication.js"
|
|
2
2
|
import { DisposableSingleApplication } from "./DisposableSingleApplication.js"
|
|
3
|
+
import type { ExitInfo } from "./TerminalApplication.js"
|
|
3
4
|
|
|
4
5
|
vi.spyOn(console, "log").mockImplementation(vi.fn())
|
|
5
6
|
|
|
@@ -9,11 +10,12 @@ class TestDisposableSingleApplication extends DisposableSingleApplication {
|
|
|
9
10
|
}
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
const fakeApp
|
|
13
|
+
const fakeApp = {
|
|
13
14
|
processId: 123,
|
|
14
15
|
write: vi.fn(),
|
|
15
16
|
killAndWait: vi.fn(),
|
|
16
|
-
}
|
|
17
|
+
untilExit: Promise.resolve<ExitInfo>({ exitCode: 0, signal: undefined }),
|
|
18
|
+
} satisfies StartableApplication
|
|
17
19
|
|
|
18
20
|
describe("DisposableSingleApplication", () => {
|
|
19
21
|
it("has no application when created", () => {
|
|
@@ -45,6 +47,25 @@ describe("DisposableSingleApplication", () => {
|
|
|
45
47
|
)
|
|
46
48
|
})
|
|
47
49
|
|
|
50
|
+
describe("untilExit allows waiting for the application to exit", () => {
|
|
51
|
+
it("successful exit works", async () => {
|
|
52
|
+
const app = new TestDisposableSingleApplication()
|
|
53
|
+
await app.startNextAndKillCurrent(async () => fakeApp)
|
|
54
|
+
fakeApp.untilExit = Promise.resolve({ exitCode: 1, signal: 9 })
|
|
55
|
+
await expect(app.untilExit()).resolves.toStrictEqual({
|
|
56
|
+
exitCode: 1,
|
|
57
|
+
signal: 9,
|
|
58
|
+
} satisfies ExitInfo)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it("when the application throws an error, the error is propagated", async () => {
|
|
62
|
+
const app = new TestDisposableSingleApplication()
|
|
63
|
+
await app.startNextAndKillCurrent(async () => fakeApp)
|
|
64
|
+
fakeApp.untilExit = Promise.reject(new Error("fake error"))
|
|
65
|
+
await expect(app.untilExit()).rejects.toThrowError(new Error("fake error"))
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
|
|
48
69
|
describe("disposing", () => {
|
|
49
70
|
it("disposes the application when disposed", async () => {
|
|
50
71
|
// it's important to make sure there are no dangling applications when
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import assert from "assert"
|
|
2
|
-
import type { TerminalApplication } from "./TerminalApplication.js"
|
|
2
|
+
import type { ExitInfo, TerminalApplication } from "./TerminalApplication.js"
|
|
3
3
|
|
|
4
|
-
export type StartableApplication = Pick<TerminalApplication, "write" | "processId" | "killAndWait">
|
|
4
|
+
export type StartableApplication = Pick<TerminalApplication, "write" | "processId" | "killAndWait" | "untilExit">
|
|
5
5
|
|
|
6
6
|
/** A testable application that can be started, killed, and given input. For a
|
|
7
7
|
* single instance of this interface, only a single instance can be running at
|
|
@@ -15,6 +15,14 @@ export class DisposableSingleApplication implements AsyncDisposable {
|
|
|
15
15
|
this.application = await startNext()
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
public async untilExit(): Promise<ExitInfo> {
|
|
19
|
+
assert(
|
|
20
|
+
this.application,
|
|
21
|
+
"The application not started yet. It makes no sense to wait for it to exit, so this looks like a bug."
|
|
22
|
+
)
|
|
23
|
+
return this.application.untilExit
|
|
24
|
+
}
|
|
25
|
+
|
|
18
26
|
public async write(input: string): Promise<void> {
|
|
19
27
|
assert(
|
|
20
28
|
this.application,
|
|
@@ -6,6 +6,8 @@ import type { IPty } from "node-pty"
|
|
|
6
6
|
import pty from "node-pty"
|
|
7
7
|
import type { StartableApplication } from "./DisposableSingleApplication.js"
|
|
8
8
|
|
|
9
|
+
export type ExitInfo = { exitCode: number; signal: number | undefined }
|
|
10
|
+
|
|
9
11
|
// NOTE separating stdout and stderr is not supported by node-pty
|
|
10
12
|
// https://github.com/microsoft/node-pty/issues/71
|
|
11
13
|
export class TerminalApplication implements StartableApplication {
|
|
@@ -15,7 +17,8 @@ export class TerminalApplication implements StartableApplication {
|
|
|
15
17
|
|
|
16
18
|
private constructor(
|
|
17
19
|
private readonly subProcess: IPty,
|
|
18
|
-
public readonly onStdoutOrStderr: (data: string) => void
|
|
20
|
+
public readonly onStdoutOrStderr: (data: string) => void,
|
|
21
|
+
public readonly untilExit: Promise<ExitInfo>
|
|
19
22
|
) {
|
|
20
23
|
this.processId = subProcess.pid
|
|
21
24
|
|
|
@@ -60,14 +63,23 @@ export class TerminalApplication implements StartableApplication {
|
|
|
60
63
|
cols: dimensions.cols,
|
|
61
64
|
rows: dimensions.rows,
|
|
62
65
|
})
|
|
66
|
+
ptyProcess.onExit(({ exitCode, signal }) => {
|
|
67
|
+
console.log(`Child process exited with code ${exitCode} and signal ${signal}`)
|
|
68
|
+
})
|
|
63
69
|
|
|
64
70
|
const processId = ptyProcess.pid
|
|
65
71
|
|
|
66
72
|
if (!processId) {
|
|
67
73
|
throw new Error("Failed to spawn child process")
|
|
68
74
|
}
|
|
75
|
+
const untilExit = new Promise<ExitInfo>(resolve => {
|
|
76
|
+
ptyProcess.onExit(({ exitCode, signal }) => {
|
|
77
|
+
// console.log(`Child process ${processId} exited with code ${exitCode} and signal ${signal}`)
|
|
78
|
+
resolve({ exitCode, signal })
|
|
79
|
+
})
|
|
80
|
+
})
|
|
69
81
|
|
|
70
|
-
return new TerminalApplication(ptyProcess, onStdoutOrStderr)
|
|
82
|
+
return new TerminalApplication(ptyProcess, onStdoutOrStderr, untilExit)
|
|
71
83
|
}
|
|
72
84
|
|
|
73
85
|
/** Write to the terminal's stdin. */
|