@travetto/terminal 4.0.0-rc.6 → 4.0.0-rc.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/terminal",
3
- "version": "4.0.0-rc.6",
3
+ "version": "4.0.0-rc.7",
4
4
  "description": "General terminal support",
5
5
  "keywords": [
6
6
  "terminal",
@@ -24,7 +24,7 @@
24
24
  "directory": "module/terminal"
25
25
  },
26
26
  "dependencies": {
27
- "@travetto/base": "^4.0.0-rc.6",
27
+ "@travetto/base": "^4.0.0-rc.7",
28
28
  "chalk": "^4.1.2"
29
29
  },
30
30
  "travetto": {
package/src/terminal.ts CHANGED
@@ -19,7 +19,6 @@ export class Terminal {
19
19
 
20
20
  #interactive: boolean;
21
21
  #writer: TerminalWriter;
22
- #cleanExit = 0;
23
22
  #width: number;
24
23
  #height: number;
25
24
  #output: tty.WriteStream;
@@ -34,14 +33,6 @@ export class Terminal {
34
33
  }
35
34
  }
36
35
 
37
- #cleanOnExit(): () => void {
38
- if (this.#cleanExit === 0) {
39
- process.on('exit', TerminalWriter.reset);
40
- }
41
- this.#cleanExit += 1;
42
- return () => (this.#cleanExit -= 1) === 0 && process.off('exit', TerminalWriter.reset);
43
- }
44
-
45
36
  constructor(output?: tty.WriteStream, config?: { width?: number, height?: number }) {
46
37
  this.#output = output ?? process.stdout;
47
38
  this.#interactive = this.#output.isTTY && !Env.TRV_QUIET.isTrue;
@@ -77,7 +68,6 @@ export class Terminal {
77
68
  async streamToBottom(source: AsyncIterable<string | undefined>, config: TerminalStreamingConfig = {}): Promise<void> {
78
69
  const writePos = { x: 0, y: -1 };
79
70
  const minDelay = config.minDelay ?? 0;
80
- const remove = this.#cleanOnExit();
81
71
 
82
72
  let prev: string | undefined;
83
73
  let stop: AbortController | undefined;
@@ -117,8 +107,7 @@ export class Terminal {
117
107
 
118
108
  await this.#writer.setPosition(writePos).clearLine().commit(true);
119
109
  } finally {
120
- await this.#writer.softReset().commit();
121
- remove();
110
+ await this.#writer.reset().commit();
122
111
  }
123
112
  }
124
113
 
@@ -137,7 +126,6 @@ export class Terminal {
137
126
  return;
138
127
  }
139
128
 
140
- const remove = this.#cleanOnExit();
141
129
  let max = 0;
142
130
  try {
143
131
  await this.#writer.hideCursor().commit();
@@ -146,8 +134,7 @@ export class Terminal {
146
134
  await this.#writer.write('\n'.repeat(idx)).setPosition({ x: 0 }).write(text).clearLine(1).changePosition({ y: -idx }).commit();
147
135
  }
148
136
  } finally {
149
- await this.#writer.changePosition({ y: max + 1 }).writeLine('\n').softReset().commit();
150
- remove();
137
+ await this.#writer.changePosition({ y: max + 1 }).writeLine('\n').reset().commit();
151
138
  }
152
139
  }
153
140
  }
package/src/util.ts CHANGED
@@ -17,7 +17,7 @@ export class TerminalUtil {
17
17
  }
18
18
  ): (ev: ProgressEvent<string>) => string {
19
19
  const styleBase = typeof cfg?.style !== 'function' ? {
20
- complete: StyleUtil.getStyle(cfg?.style?.complete ?? { background: '#32cd32', text: '#ffffff' }),
20
+ complete: StyleUtil.getStyle(cfg?.style?.complete ?? { background: '#248613', text: '#ffffff' }),
21
21
  incomplete: cfg?.style?.incomplete ? StyleUtil.getStyle(cfg.style.incomplete) : undefined,
22
22
  } : undefined;
23
23
 
@@ -31,7 +31,7 @@ export class TerminalUtil {
31
31
  width ??= Math.trunc(Math.ceil(Math.log10(ev.total ?? 10000)));
32
32
  }
33
33
  const state: Record<string, string> = { total: `${ev.total}`, idx: `${ev.idx}`.padStart(width ?? 0), pct: `${Math.trunc(pct * 100)}` };
34
- const line = text.replace(/[%](idx|total|pct)/g, (_, k) => state[k]);
34
+ const line = ` ${text.replace(/[%](idx|total|pct)/g, (_, k) => state[k])} `;
35
35
  const full = term.writer.padToWidth(line, cfg?.withWaiting ? 2 : 0);
36
36
  const mid = Math.trunc(pct * term.width);
37
37
  const [l, r] = [full.substring(0, mid), full.substring(mid)];
package/src/writer.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import tty from 'node:tty';
2
2
 
3
+ import { ShutdownManager } from '@travetto/base';
4
+
3
5
  type State = { output: tty.WriteStream, height: number, width: number };
4
6
  type TermCoord = { x: number, y: number };
5
7
 
@@ -31,20 +33,31 @@ const Codes = {
31
33
  * Buffered/batched writer. Meant to be similar to readline.Readline, but with more general writing support and extensibility
32
34
  */
33
35
  export class TerminalWriter {
34
-
35
- static reset(): void {
36
- process.stdout.isTTY && process.stdout.write(Codes.SOFT_RESET);
37
- process.stderr.isTTY && process.stderr.write(Codes.SOFT_RESET);
38
- }
39
-
40
36
  #buffer: (string | number)[] = [];
41
37
  #restoreOnCommit = false;
42
38
  #term: State;
39
+ #cleanup: (() => undefined) | undefined;
43
40
 
44
41
  constructor(state: State) {
45
42
  this.#term = state;
46
43
  }
47
44
 
45
+ /** Track dirty state for the stream */
46
+ trackDirty(on: boolean): this {
47
+ const output = this.#term.output;
48
+ if (output.isTTY) {
49
+ if (on && !this.#cleanup) {
50
+ const exit = (): Promise<void> => this.reset().commit(false);
51
+ const free = ShutdownManager.onGracefulShutdown(exit);
52
+ process.on('exit', exit);
53
+ this.#cleanup = (): undefined => { free(); process.off('exit', exit); };
54
+ } else if (!on) {
55
+ this.#cleanup = this.#cleanup?.();
56
+ }
57
+ }
58
+ return this;
59
+ }
60
+
48
61
  /** Pad to width of terminal */
49
62
  padToWidth(text: string, offset = 0, ellipsis = '...'): string {
50
63
  if (text.length > (this.#term.width - offset)) {
@@ -132,12 +145,12 @@ export class TerminalWriter {
132
145
 
133
146
  /** Hide cursor */
134
147
  hideCursor(): this {
135
- return this.write(Codes.HIDE_CURSOR);
148
+ return this.trackDirty(true).write(Codes.HIDE_CURSOR);
136
149
  }
137
150
 
138
151
  /** Set scrolling range */
139
152
  scrollRange({ start = 0, end = -1 }: { start?: number, end?: number }): this {
140
- return this.write(Codes.SCROLL_RANGE_SET(start, end, this.#term.height));
153
+ return this.trackDirty(true).write(Codes.SCROLL_RANGE_SET(start, end, this.#term.height));
141
154
  }
142
155
 
143
156
  /** Clear scrolling range */
@@ -146,7 +159,7 @@ export class TerminalWriter {
146
159
  }
147
160
 
148
161
  /** Reset */
149
- softReset(): this {
150
- return this.write(Codes.SOFT_RESET);
162
+ reset(): this {
163
+ return this.trackDirty(false).write(Codes.SOFT_RESET).write(Codes.SHOW_CURSOR);
151
164
  }
152
165
  }