@tui-sandbox/library 6.0.2 → 7.0.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.
Files changed (34) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/browser/assets/{index-DJEG76in.js → index-Bup5cvb2.js} +3 -3
  3. package/dist/browser/index.html +1 -1
  4. package/dist/src/browser/neovim-client.d.ts +3 -1
  5. package/dist/src/browser/neovim-client.js +5 -2
  6. package/dist/src/client/index.d.ts +1 -1
  7. package/dist/src/client/index.js +1 -1
  8. package/dist/src/client/terminal-client.d.ts +15 -0
  9. package/dist/src/client/{neovim-client.js → terminal-client.js} +10 -1
  10. package/dist/src/server/cypress-support/contents.js +19 -1
  11. package/dist/src/server/cypress-support/contents.test.js +19 -1
  12. package/dist/src/server/cypress-support/createCypressSupportFile.js +2 -1
  13. package/dist/src/server/neovim/NeovimApplication.d.ts +10 -1
  14. package/dist/src/server/neovim/NeovimApplication.js +15 -12
  15. package/dist/src/server/neovim/environment/createTempDir.test.js +2 -4
  16. package/dist/src/server/neovim/index.d.ts +4 -1
  17. package/dist/src/server/neovim/index.js +34 -0
  18. package/dist/src/server/server.d.ts +54 -4
  19. package/dist/src/server/server.js +13 -72
  20. package/dist/src/server/types.d.ts +7 -0
  21. package/dist/tsconfig.tsbuildinfo +1 -1
  22. package/package.json +2 -2
  23. package/src/browser/neovim-client.ts +11 -3
  24. package/src/client/index.ts +1 -1
  25. package/src/client/{neovim-client.ts → terminal-client.ts} +13 -3
  26. package/src/server/cypress-support/contents.test.ts +19 -1
  27. package/src/server/cypress-support/contents.ts +19 -1
  28. package/src/server/cypress-support/createCypressSupportFile.ts +2 -1
  29. package/src/server/neovim/NeovimApplication.ts +22 -15
  30. package/src/server/neovim/environment/createTempDir.test.ts +1 -1
  31. package/src/server/neovim/index.ts +46 -1
  32. package/src/server/server.ts +18 -6
  33. package/src/server/types.ts +12 -0
  34. package/dist/src/client/neovim-client.d.ts +0 -11
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <title>tui-sandbox integration tests</title>
6
- <script type="module" crossorigin src="/assets/index-DJEG76in.js"></script>
6
+ <script type="module" crossorigin src="/assets/index-Bup5cvb2.js"></script>
7
7
  <link rel="stylesheet" crossorigin href="/assets/index-Bf37MeF1.css">
8
8
  </head>
9
9
  <body>
@@ -1,6 +1,8 @@
1
- import type { StartNeovimGenericArguments, TestDirectory } from "../server/types.js";
1
+ import type { BlockingCommandClientInput } from "../server/server.js";
2
+ import type { BlockingShellCommandOutput, StartNeovimGenericArguments, TestDirectory } from "../server/types.js";
2
3
  declare global {
3
4
  interface Window {
4
5
  startNeovim(startArguments?: StartNeovimGenericArguments): Promise<TestDirectory>;
6
+ runBlockingShellCommand(input: BlockingCommandClientInput): Promise<BlockingShellCommandOutput>;
5
7
  }
6
8
  }
@@ -1,9 +1,9 @@
1
- import { NeovimClient } from "../client/index.js";
1
+ import { TerminalClient } from "../client/index.js";
2
2
  const app = document.querySelector("#app");
3
3
  if (!app) {
4
4
  throw new Error("No app element found");
5
5
  }
6
- const client = new NeovimClient(app);
6
+ const client = new TerminalClient(app);
7
7
  /** Entrypoint for the test runner (cypress) */
8
8
  window.startNeovim = async function (startArgs) {
9
9
  const testDirectory = await client.startNeovim({
@@ -13,3 +13,6 @@ window.startNeovim = async function (startArgs) {
13
13
  });
14
14
  return testDirectory;
15
15
  };
16
+ window.runBlockingShellCommand = async function (input) {
17
+ return client.runBlockingShellCommand(input);
18
+ };
@@ -1,2 +1,2 @@
1
1
  export { rgbify } from "./color-utilities.js";
2
- export { NeovimClient } from "./neovim-client.js";
2
+ export { TerminalClient } from "./terminal-client.js";
@@ -1,3 +1,3 @@
1
1
  // This is the public client api. Semantic versioning will be applied to this.
2
2
  export { rgbify } from "./color-utilities.js";
3
- export { NeovimClient } from "./neovim-client.js";
3
+ export { TerminalClient } from "./terminal-client.js";
@@ -0,0 +1,15 @@
1
+ import "@xterm/xterm/css/xterm.css";
2
+ import type { BlockingCommandClientInput } from "../server/server.js";
3
+ import type { BlockingShellCommandOutput, StartNeovimGenericArguments, TestDirectory } from "../server/types.js";
4
+ import "./style.css";
5
+ /** Manages the terminal state in the browser as well as the (browser's)
6
+ * connection to the server side terminal application api. */
7
+ export declare class TerminalClient {
8
+ private readonly ready;
9
+ private readonly tabId;
10
+ private readonly terminal;
11
+ private readonly trpc;
12
+ constructor(app: HTMLElement);
13
+ startNeovim(args: StartNeovimGenericArguments): Promise<TestDirectory>;
14
+ runBlockingShellCommand(input: BlockingCommandClientInput): Promise<BlockingShellCommandOutput>;
15
+ }
@@ -2,7 +2,9 @@ import { createTRPCClient, httpBatchLink, splitLink, unstable_httpSubscriptionLi
2
2
  import "@xterm/xterm/css/xterm.css";
3
3
  import "./style.css";
4
4
  import { getTabId, startTerminal } from "./websocket-client.js";
5
- export class NeovimClient {
5
+ /** Manages the terminal state in the browser as well as the (browser's)
6
+ * connection to the server side terminal application api. */
7
+ export class TerminalClient {
6
8
  ready;
7
9
  tabId;
8
10
  terminal;
@@ -68,4 +70,11 @@ export class NeovimClient {
68
70
  });
69
71
  return testDirectory;
70
72
  }
73
+ async runBlockingShellCommand(input) {
74
+ await this.ready;
75
+ return this.trpc.neovim.runBlockingShellCommand.mutate({
76
+ ...input,
77
+ tabId: this.tabId,
78
+ });
79
+ }
71
80
  }
@@ -9,8 +9,12 @@ export async function createCypressSupportFileContents() {
9
9
  //
10
10
  // This file is autogenerated by tui-sandbox. Do not edit it directly.
11
11
  //
12
+ import type { BlockingCommandClientInput } from "@tui-sandbox/library/dist/src/server/server"
13
+ import type {
14
+ BlockingShellCommandOutput,
15
+ StartNeovimGenericArguments,
16
+ } from "@tui-sandbox/library/dist/src/server/types"
12
17
  import type { OverrideProperties } from "type-fest"
13
- import type { StartNeovimGenericArguments } from "@tui-sandbox/library/dist/src/server/types"
14
18
  import type { MyTestDirectory, MyTestDirectoryFile } from "../../MyTestDirectory"
15
19
 
16
20
  export type NeovimContext = {
@@ -21,6 +25,7 @@ export type NeovimContext = {
21
25
  declare global {
22
26
  interface Window {
23
27
  startNeovim(startArguments?: MyStartNeovimServerArguments): Promise<NeovimContext>
28
+ runBlockingShellCommand(input: BlockingCommandClientInput): Promise<BlockingShellCommandOutput>
24
29
  }
25
30
  }
26
31
 
@@ -39,6 +44,12 @@ Cypress.Commands.add("startNeovim", (startArguments?: MyStartNeovimServerArgumen
39
44
  })
40
45
  })
41
46
 
47
+ Cypress.Commands.add("runBlockingShellCommand", (input: BlockingCommandClientInput) => {
48
+ cy.window().then(async win => {
49
+ return await win.runBlockingShellCommand(input)
50
+ })
51
+ })
52
+
42
53
  Cypress.Commands.add("typeIntoTerminal", (text: string, options?: Partial<Cypress.TypeOptions>) => {
43
54
  // the syntax for keys is described here:
44
55
  // https://docs.cypress.io/api/commands/type
@@ -56,7 +67,14 @@ declare global {
56
67
  namespace Cypress {
57
68
  interface Chainable {
58
69
  startNeovim(args?: MyStartNeovimServerArguments): Chainable<NeovimContext>
70
+
71
+ /** Types text into the terminal, making the terminal application receive
72
+ * the keystrokes as input. Requires neovim to be running. */
59
73
  typeIntoTerminal(text: string, options?: Partial<Cypress.TypeOptions>): Chainable<void>
74
+
75
+ /** Runs a shell command in a blocking manner, waiting for the command to
76
+ * finish before returning. Requires neovim to be running. */
77
+ runBlockingShellCommand(input: BlockingCommandClientInput): Chainable<BlockingShellCommandOutput>
60
78
  }
61
79
  }
62
80
  }
@@ -6,7 +6,11 @@ it("should return the expected contents", async () => {
6
6
  //
7
7
  // This file is autogenerated by tui-sandbox. Do not edit it directly.
8
8
  //
9
- import type { StartNeovimGenericArguments } from "@tui-sandbox/library/dist/src/server/types"
9
+ import type { BlockingCommandClientInput } from "@tui-sandbox/library/dist/src/server/server"
10
+ import type {
11
+ BlockingShellCommandOutput,
12
+ StartNeovimGenericArguments,
13
+ } from "@tui-sandbox/library/dist/src/server/types"
10
14
  import type { OverrideProperties } from "type-fest"
11
15
  import type { MyTestDirectory, MyTestDirectoryFile } from "../../MyTestDirectory"
12
16
 
@@ -18,6 +22,7 @@ it("should return the expected contents", async () => {
18
22
  declare global {
19
23
  interface Window {
20
24
  startNeovim(startArguments?: MyStartNeovimServerArguments): Promise<NeovimContext>
25
+ runBlockingShellCommand(input: BlockingCommandClientInput): Promise<BlockingShellCommandOutput>
21
26
  }
22
27
  }
23
28
 
@@ -36,6 +41,12 @@ it("should return the expected contents", async () => {
36
41
  })
37
42
  })
38
43
 
44
+ Cypress.Commands.add("runBlockingShellCommand", (input: BlockingCommandClientInput) => {
45
+ cy.window().then(async win => {
46
+ return await win.runBlockingShellCommand(input)
47
+ })
48
+ })
49
+
39
50
  Cypress.Commands.add("typeIntoTerminal", (text: string, options?: Partial<Cypress.TypeOptions>) => {
40
51
  // the syntax for keys is described here:
41
52
  // https://docs.cypress.io/api/commands/type
@@ -53,7 +64,14 @@ it("should return the expected contents", async () => {
53
64
  namespace Cypress {
54
65
  interface Chainable {
55
66
  startNeovim(args?: MyStartNeovimServerArguments): Chainable<NeovimContext>
67
+
68
+ /** Types text into the terminal, making the terminal application receive
69
+ * the keystrokes as input. Requires neovim to be running. */
56
70
  typeIntoTerminal(text: string, options?: Partial<Cypress.TypeOptions>): Chainable<void>
71
+
72
+ /** Runs a shell command in a blocking manner, waiting for the command to
73
+ * finish before returning. Requires neovim to be running. */
74
+ runBlockingShellCommand(input: BlockingCommandClientInput): Chainable<BlockingShellCommandOutput>
57
75
  }
58
76
  }
59
77
  }
@@ -14,12 +14,13 @@ export async function createCypressSupportFile({ cypressSupportDirectoryPath, su
14
14
  oldSchema = readFileSync(outputFilePath, "utf-8");
15
15
  }
16
16
  catch (error) {
17
- console.log(`No existing cypress support file found at ${outputFilePath}, creating a new one`);
17
+ console.log(`No existing cypress support file found at ${outputFilePath}`);
18
18
  }
19
19
  if (oldSchema !== text) {
20
20
  // it's important to not write the file if the schema hasn't changed
21
21
  // because file watchers will trigger on file changes and we don't want to
22
22
  // trigger a build if the schema hasn't changed
23
+ console.log(`🪛 Writing cypress support file to ${outputFilePath}`);
23
24
  writeFileSync(outputFilePath, text);
24
25
  return "updated";
25
26
  }
@@ -1,6 +1,8 @@
1
1
  import EventEmitter from "events";
2
+ import type { NeovimClient as NeovimApiClient } from "neovim";
2
3
  import type { TestDirectory } from "../types.js";
3
4
  import { DisposableSingleApplication } from "../utilities/DisposableSingleApplication.js";
5
+ import type { Lazy } from "../utilities/Lazy.js";
4
6
  export type StdoutMessage = "stdout";
5
7
  export type StartNeovimGenericArguments = {
6
8
  filename: string | {
@@ -15,15 +17,22 @@ export type TerminalDimensions = {
15
17
  cols: number;
16
18
  rows: number;
17
19
  };
20
+ type ResettableState = {
21
+ testDirectory: TestDirectory;
22
+ socketPath: string;
23
+ client: Lazy<Promise<NeovimApiClient>>;
24
+ };
18
25
  export declare class NeovimApplication {
19
26
  private readonly testEnvironmentPath;
20
27
  readonly application: DisposableSingleApplication;
21
- private state;
28
+ state: ResettableState | undefined;
22
29
  readonly events: EventEmitter;
23
30
  constructor(testEnvironmentPath: string, application?: DisposableSingleApplication);
24
31
  /**
25
32
  * Kill the current application and start a new one with the given arguments.
26
33
  */
27
34
  startNextAndKillCurrent(testDirectory: TestDirectory, startArgs: StartNeovimGenericArguments, terminalDimensions: TerminalDimensions): Promise<void>;
35
+ getEnvironmentVariables(testDirectory: TestDirectory, additionalEnvironmentVariables?: Record<string, string>): NodeJS.ProcessEnv;
28
36
  [Symbol.asyncDispose](): Promise<void>;
29
37
  }
38
+ export {};
@@ -53,18 +53,7 @@ export class NeovimApplication {
53
53
  neovimArguments.push("--listen", socketPath);
54
54
  const stdout = this.events;
55
55
  await this.application.startNextAndKillCurrent(async () => {
56
- const env = {
57
- ...process.env,
58
- HOME: testDirectory.rootPathAbsolute,
59
- // this is needed so that neovim can load its configuration, emulating
60
- // a common setup real neovim users have
61
- XDG_CONFIG_HOME: join(testDirectory.rootPathAbsolute, ".config"),
62
- // the data directory is where lazy.nvim stores its plugins. To prevent
63
- // downloading a new set of plugins for each test, share the data
64
- // directory.
65
- XDG_DATA_HOME: join(testDirectory.testEnvironmentPath, ".repro", "data"),
66
- ...startArgs.additionalEnvironmentVariables,
67
- };
56
+ const env = this.getEnvironmentVariables(testDirectory, startArgs.additionalEnvironmentVariables);
68
57
  return TerminalApplication.start({
69
58
  command: "nvim",
70
59
  args: neovimArguments,
@@ -86,6 +75,20 @@ export class NeovimApplication {
86
75
  };
87
76
  console.log(`🚀 Started Neovim instance ${processId}`);
88
77
  }
78
+ getEnvironmentVariables(testDirectory, additionalEnvironmentVariables) {
79
+ return {
80
+ ...process.env,
81
+ HOME: testDirectory.rootPathAbsolute,
82
+ // this is needed so that neovim can load its configuration, emulating
83
+ // a common setup real neovim users have
84
+ XDG_CONFIG_HOME: join(testDirectory.rootPathAbsolute, ".config"),
85
+ // the data directory is where lazy.nvim stores its plugins. To prevent
86
+ // downloading a new set of plugins for each test, share the data
87
+ // directory.
88
+ XDG_DATA_HOME: join(testDirectory.testEnvironmentPath, ".repro", "data"),
89
+ ...additionalEnvironmentVariables,
90
+ };
91
+ }
89
92
  async [Symbol.asyncDispose]() {
90
93
  await this.application[Symbol.asyncDispose]();
91
94
  if (!this.state)
@@ -72,7 +72,7 @@ it("should create a temp dir with no contents", async () => {
72
72
  const env_1 = { stack: [], error: void 0, hasError: false };
73
73
  try {
74
74
  // typically the user will want to have contents, but this should not be an error
75
- const dir = __addDisposableResource(env_1, TempDirectory.create(), true);
75
+ const dir = __addDisposableResource(env_1, TempDirectory.create(), false);
76
76
  const result = await createTempDir({
77
77
  testEnvironmentPath: dir.path,
78
78
  outputFilePath: nodePath.join(dir.path, "MyTestDirectory.ts"),
@@ -87,8 +87,6 @@ it("should create a temp dir with no contents", async () => {
87
87
  env_1.hasError = true;
88
88
  }
89
89
  finally {
90
- const result_1 = __disposeResources(env_1);
91
- if (result_1)
92
- await result_1;
90
+ __disposeResources(env_1);
93
91
  }
94
92
  });
@@ -1,4 +1,6 @@
1
- import type { StartNeovimGenericArguments, TestDirectory } from "../types.js";
1
+ import "core-js/proposals/async-explicit-resource-management.js";
2
+ import type { BlockingCommandInput } from "../server.js";
3
+ import type { BlockingShellCommandOutput, StartNeovimGenericArguments, TestDirectory } from "../types.js";
2
4
  import type { TestServerConfig } from "../updateTestdirectorySchemaFile.js";
3
5
  import type { TabId } from "../utilities/tabId.js";
4
6
  import type { TerminalDimensions } from "./NeovimApplication.js";
@@ -10,3 +12,4 @@ export declare function sendStdin(options: {
10
12
  tabId: TabId;
11
13
  data: string;
12
14
  }): Promise<void>;
15
+ export declare function runBlockingShellCommand(signal: AbortSignal | undefined, input: BlockingCommandInput): Promise<BlockingShellCommandOutput>;
@@ -1,4 +1,7 @@
1
1
  import assert from "assert";
2
+ import { exec } from "child_process";
3
+ import "core-js/proposals/async-explicit-resource-management.js";
4
+ import util from "util";
2
5
  import { convertEventEmitterToAsyncGenerator } from "../utilities/generator.js";
3
6
  import { createTempDir, removeTestDirectories } from "./environment/createTempDir.js";
4
7
  import { NeovimApplication } from "./NeovimApplication.js";
@@ -33,3 +36,34 @@ export async function sendStdin(options) {
33
36
  assert(neovim.application, `Neovim application not found for client id ${options.tabId.tabId}. Maybe it's not started yet?`);
34
37
  await neovim.application.write(options.data);
35
38
  }
39
+ export async function runBlockingShellCommand(signal, input) {
40
+ const neovim = neovims.get(input.tabId.tabId);
41
+ assert(neovim !== undefined, `Neovim instance for clientId not found - cannot run blocking shell command. Maybe neovim's not started yet?`);
42
+ const testDirectory = neovim.state?.testDirectory;
43
+ assert(testDirectory, `Test directory not found for client id ${input.tabId.tabId}. Maybe neovim's not started yet?`);
44
+ const execPromise = util.promisify(exec);
45
+ const env = neovim.getEnvironmentVariables(testDirectory, input.envOverrides);
46
+ const processPromise = execPromise(input.command, {
47
+ signal: signal,
48
+ shell: input.shell,
49
+ uid: input.uid,
50
+ gid: input.gid,
51
+ cwd: input.cwd ?? env["HOME"],
52
+ env,
53
+ });
54
+ try {
55
+ const result = await processPromise;
56
+ console.log(`Successfully ran shell blockingCommand (${input.command}) with stdout: ${result.stdout}, stderr: ${result.stderr}`);
57
+ return {
58
+ type: "success",
59
+ stdout: result.stdout,
60
+ stderr: result.stderr,
61
+ };
62
+ }
63
+ catch (e) {
64
+ console.warn(`Error running shell blockingCommand (${input.command})`, e);
65
+ return {
66
+ type: "failed",
67
+ };
68
+ }
69
+ }
@@ -1,11 +1,46 @@
1
1
  import type { inferRouterInputs } from "@trpc/server";
2
2
  import "core-js/proposals/async-explicit-resource-management.js";
3
+ import type { Except } from "type-fest";
4
+ import { z } from "zod";
3
5
  import { TestServer } from "./TestServer.js";
4
6
  import type { TestServerConfig } from "./updateTestdirectorySchemaFile.js";
5
- /** Stack for managing resources that need to be disposed of when the server
6
- * shuts down */
7
- declare const autocleanup: AsyncDisposableStack;
8
- export { autocleanup };
7
+ declare const blockingCommandInputSchema: z.ZodObject<{
8
+ command: z.ZodString;
9
+ shell: z.ZodOptional<z.ZodString>;
10
+ tabId: z.ZodObject<{
11
+ tabId: z.ZodString;
12
+ }, "strip", z.ZodTypeAny, {
13
+ tabId: string;
14
+ }, {
15
+ tabId: string;
16
+ }>;
17
+ uid: z.ZodOptional<z.ZodNumber>;
18
+ gid: z.ZodOptional<z.ZodNumber>;
19
+ cwd: z.ZodOptional<z.ZodString>;
20
+ envOverrides: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
21
+ }, "strip", z.ZodTypeAny, {
22
+ command: string;
23
+ tabId: {
24
+ tabId: string;
25
+ };
26
+ cwd?: string | undefined;
27
+ uid?: number | undefined;
28
+ gid?: number | undefined;
29
+ shell?: string | undefined;
30
+ envOverrides?: Record<string, string> | undefined;
31
+ }, {
32
+ command: string;
33
+ tabId: {
34
+ tabId: string;
35
+ };
36
+ cwd?: string | undefined;
37
+ uid?: number | undefined;
38
+ gid?: number | undefined;
39
+ shell?: string | undefined;
40
+ envOverrides?: Record<string, string> | undefined;
41
+ }>;
42
+ export type BlockingCommandClientInput = Except<BlockingCommandInput, "tabId">;
43
+ export type BlockingCommandInput = z.infer<typeof blockingCommandInputSchema>;
9
44
  /** @private */
10
45
  export declare function createAppRouter(config: TestServerConfig): Promise<import("@trpc/server/unstable-core-do-not-import").BuiltRouter<{
11
46
  ctx: object;
@@ -55,8 +90,23 @@ export declare function createAppRouter(config: TestServerConfig): Promise<impor
55
90
  };
56
91
  output: void;
57
92
  }>;
93
+ runBlockingShellCommand: import("@trpc/server").TRPCMutationProcedure<{
94
+ input: {
95
+ command: string;
96
+ tabId: {
97
+ tabId: string;
98
+ };
99
+ cwd?: string | undefined;
100
+ uid?: number | undefined;
101
+ gid?: number | undefined;
102
+ shell?: string | undefined;
103
+ envOverrides?: Record<string, string> | undefined;
104
+ };
105
+ output: import("./types.js").BlockingShellCommandOutput;
106
+ }>;
58
107
  }>;
59
108
  }>>>;
60
109
  export type AppRouter = Awaited<ReturnType<typeof createAppRouter>>;
61
110
  export type RouterInput = inferRouterInputs<AppRouter>;
62
111
  export declare function startTestServer(config: TestServerConfig): Promise<TestServer>;
112
+ export {};
@@ -1,55 +1,3 @@
1
- var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
- if (value !== null && value !== void 0) {
3
- if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
- var dispose, inner;
5
- if (async) {
6
- if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
- dispose = value[Symbol.asyncDispose];
8
- }
9
- if (dispose === void 0) {
10
- if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
- dispose = value[Symbol.dispose];
12
- if (async) inner = dispose;
13
- }
14
- if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
- if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
- env.stack.push({ value: value, dispose: dispose, async: async });
17
- }
18
- else if (async) {
19
- env.stack.push({ async: true });
20
- }
21
- return value;
22
- };
23
- var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
- return function (env) {
25
- function fail(e) {
26
- env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
- env.hasError = true;
28
- }
29
- var r, s = 0;
30
- function next() {
31
- while (r = env.stack.pop()) {
32
- try {
33
- if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
- if (r.dispose) {
35
- var result = r.dispose.call(r.value);
36
- if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
- }
38
- else s |= 1;
39
- }
40
- catch (e) {
41
- fail(e);
42
- }
43
- }
44
- if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
- if (env.hasError) throw env.error;
46
- }
47
- return next();
48
- };
49
- })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
- var e = new Error(message);
51
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
- });
53
1
  import "core-js/proposals/async-explicit-resource-management.js";
54
2
  import { z } from "zod";
55
3
  import { trpc } from "./connection/trpc.js";
@@ -57,7 +5,16 @@ import * as neovim from "./neovim/index.js";
57
5
  import { TestServer } from "./TestServer.js";
58
6
  import { applicationAvailable } from "./utilities/applicationAvailable.js";
59
7
  import { tabIdSchema } from "./utilities/tabId.js";
60
- export { autocleanup };
8
+ const blockingCommandInputSchema = z.object({
9
+ command: z.string(),
10
+ shell: z.string().optional(),
11
+ tabId: tabIdSchema,
12
+ // child_process.ProcessEnvOptions
13
+ uid: z.number().optional(),
14
+ gid: z.number().optional(),
15
+ cwd: z.string().optional(),
16
+ envOverrides: z.record(z.string()).optional(),
17
+ });
61
18
  /** @private */
62
19
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
63
20
  export async function createAppRouter(config) {
@@ -93,6 +50,9 @@ export async function createAppRouter(config) {
93
50
  sendStdin: trpc.procedure.input(z.object({ tabId: tabIdSchema, data: z.string() })).mutation(options => {
94
51
  return neovim.sendStdin(options.input);
95
52
  }),
53
+ runBlockingShellCommand: trpc.procedure.input(blockingCommandInputSchema).mutation(async (options) => {
54
+ return neovim.runBlockingShellCommand(options.signal, options.input);
55
+ }),
96
56
  }),
97
57
  });
98
58
  return appRouter;
@@ -105,22 +65,3 @@ export async function startTestServer(config) {
105
65
  await testServer.startAndRun(appRouter);
106
66
  return testServer;
107
67
  }
108
- var autocleanup;
109
- const env_1 = { stack: [], error: void 0, hasError: false };
110
- try {
111
- /** Stack for managing resources that need to be disposed of when the server
112
- * shuts down */
113
- autocleanup = __addDisposableResource(env_1, new AsyncDisposableStack(), true);
114
- autocleanup.defer(() => {
115
- console.log("Closing any open test applications");
116
- });
117
- }
118
- catch (e_1) {
119
- env_1.error = e_1;
120
- env_1.hasError = true;
121
- }
122
- finally {
123
- const result_1 = __disposeResources(env_1);
124
- if (result_1)
125
- await result_1;
126
- }
@@ -26,3 +26,10 @@ export type TestDirectory = {
26
26
  contents: object;
27
27
  };
28
28
  export type { StartNeovimGenericArguments } from "../server/neovim/NeovimApplication.js";
29
+ export type BlockingShellCommandOutput = {
30
+ type: "success";
31
+ stdout: string;
32
+ stderr: string;
33
+ } | {
34
+ type: "failed";
35
+ };