@travetto/terminal 3.0.0-rc.5 → 3.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": "3.0.0-rc.5",
3
+ "version": "3.0.0-rc.7",
4
4
  "description": "General terminal support",
5
5
  "keywords": [
6
6
  "terminal",
package/src/iterable.ts CHANGED
@@ -45,14 +45,14 @@ export class IterableUtil {
45
45
  }
46
46
 
47
47
  static cycle<T>(items: T[]): StoppableIterable<T> {
48
- let done = true;
48
+ let done = false;
49
49
  async function* buildStream(): AsyncIterable<T> {
50
50
  let i = -1;
51
51
  while (!done) {
52
52
  yield items[(i += 1) % items.length];
53
53
  }
54
54
  }
55
- return { stream: buildStream(), stop: (): void => { done = false; } };
55
+ return { stream: buildStream(), stop: (): void => { done = true; } };
56
56
  }
57
57
 
58
58
  static async drain<T>(source: AsyncIterable<T>): Promise<T[]> {
package/src/operation.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { IterableUtil } from './iterable';
2
2
  import { TerminalWriter } from './writer';
3
- import { Indexed, TerminalProgressRender, TerminalWaitingConfig, TermLinePosition, TermState } from './types';
3
+ import { Indexed, TermCoord, TerminalProgressRender, TerminalWaitingConfig, TermLinePosition, TermState } from './types';
4
4
  import { ColorOutputUtil, TermStyleInput } from './color-output';
5
5
 
6
6
  const STD_WAIT_STATES = '⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'.split('');
@@ -10,8 +10,8 @@ export class TerminalOperation {
10
10
  /**
11
11
  * Allows for writing at top, bottom, or current position while new text is added
12
12
  */
13
- static async streamToPosition(term: TermState, source: AsyncIterable<string>, pos: TermLinePosition = 'inline'): Promise<void> {
14
- const curPos = { ...await term.getCursorPosition() };
13
+ static async streamToPosition(term: TermState, source: AsyncIterable<string>, pos: TermLinePosition = 'inline', curPos?: TermCoord): Promise<void> {
14
+ curPos ??= { ...await term.getCursorPosition() };
15
15
  const writePos = pos === 'inline' ?
16
16
  { ...curPos, x: 0 } :
17
17
  { x: 0, y: pos === 'top' ? 0 : -1 };
@@ -59,16 +59,16 @@ export class TerminalOperation {
59
59
  /**
60
60
  * Waiting indicator, streamed to a specific position, can be canceled
61
61
  */
62
- static streamWaiting(term: TermState, message: string, config: TerminalWaitingConfig = {}): () => Promise<void> {
62
+ static streamWaiting(term: TermState, message: string, config: TerminalWaitingConfig = {}, curPos?: TermCoord): () => Promise<void> {
63
63
  const { stop, stream } = IterableUtil.cycle(STD_WAIT_STATES);
64
64
  const indicator = IterableUtil.map(
65
65
  stream,
66
66
  IterableUtil.DELAY(config),
67
- (ch, i) => i === 0 ? `${ch} ${message}` : ch
67
+ (ch, i) => config.end ? `${message} ${ch}` : (i === 0 ? `${ch} ${message}` : ch)
68
68
  );
69
69
 
70
- const final = this.streamToPosition(term, indicator, config.position ?? 'inline');
71
- return () => Promise.resolve(() => stop()).then(() => final);
70
+ const final = this.streamToPosition(term, indicator, config.position ?? 'inline', curPos);
71
+ return async () => { stop(); return final; };
72
72
  }
73
73
 
74
74
  /**
@@ -92,4 +92,34 @@ export class TerminalOperation {
92
92
  return `${color(l)}${r}`;
93
93
  };
94
94
  }
95
+
96
+ /**
97
+ * Stream lines with a waiting indicator
98
+ */
99
+ static async streamLinesWithWaiting(term: TermState, lines: AsyncIterable<string>, cfg: TerminalWaitingConfig = {}): Promise<void> {
100
+ let writer: (() => Promise<unknown>) | undefined;
101
+ let line: string | undefined;
102
+
103
+ const commitLine = async (): Promise<void> => {
104
+ await writer?.();
105
+ if (line) {
106
+ const msg = `${String.fromCharCode(171)} ${line}`;
107
+ if (cfg.position === 'inline') {
108
+ await TerminalWriter.for(term).setPosition({ x: 0 }).changePosition({ y: -1 }).writeLine(msg).commit();
109
+ } else {
110
+ await TerminalWriter.for(term).writeLine(msg).commit();
111
+ }
112
+ }
113
+ };
114
+
115
+ const pos = await term.getCursorPosition();
116
+
117
+ for await (let msg of lines) {
118
+ await commitLine();
119
+ msg = msg.replace(/\n$/, '');
120
+ writer = this.streamWaiting(term, msg, cfg, pos);
121
+ line = msg;
122
+ }
123
+ await commitLine();
124
+ }
95
125
  }
package/src/terminal.ts CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  import { TerminalOperation } from './operation';
9
9
  import { TerminalQuerier } from './query';
10
10
  import { TerminalWriter } from './writer';
11
- import { ColorOutputUtil, TermStyleInput } from './color-output';
11
+ import { ColorOutputUtil, Prim, TermColorFn, TermColorPalette, TermColorPaletteInput, TermStyleInput } from './color-output';
12
12
 
13
13
  type TerminalStreamPositionConfig = {
14
14
  position?: TermLinePosition;
@@ -121,6 +121,23 @@ export class Terminal implements TermState {
121
121
  return res.finally(TerminalOperation.streamWaiting(this, message, config));
122
122
  }
123
123
 
124
+ /**
125
+ * Stream line output, showing a waiting indicator for each line until the next one occurs
126
+ *
127
+ * @param lines
128
+ * @param config
129
+ * @returns
130
+ */
131
+ async streamLinesWithWaiting(lines: AsyncIterable<string>, config: TerminalWaitingConfig): Promise<void> {
132
+ if (!this.interactive) {
133
+ for await (const line of lines) {
134
+ await this.writeLines(line);
135
+ }
136
+ } else {
137
+ return TerminalOperation.streamLinesWithWaiting(this, lines, { position: 'bottom', ...config });
138
+ }
139
+ }
140
+
124
141
  /**
125
142
  * Consumes a stream, of events, tied to specific list indices, and updates in place
126
143
  */
@@ -167,17 +184,22 @@ export class Terminal implements TermState {
167
184
  return this.streamToPosition(source, async (v, i) => render(await resolve(v, i)), config);
168
185
  }
169
186
 
170
- /* eslint-disable @typescript-eslint/member-ordering */
171
187
  /** Creates a colorer function */
172
- colorer = ColorOutputUtil.colorer.bind(ColorOutputUtil, this);
188
+ colorer(style: TermStyleInput | [light: TermStyleInput, dark: TermStyleInput]): TermColorFn {
189
+ return ColorOutputUtil.colorer(this, style);
190
+ }
173
191
 
174
192
  /** Creates a color palette based on input styles */
175
- palette = ColorOutputUtil.palette.bind(ColorOutputUtil, this);
193
+ palette<P extends TermColorPaletteInput>(input: P): TermColorPalette<P> {
194
+ return ColorOutputUtil.palette(this, input);
195
+ }
176
196
 
177
197
  /** Convenience method to creates a color template function based on input styles */
178
- templateFunction = ColorOutputUtil.templateFunction.bind(ColorOutputUtil, this);
179
- /* eslint-enable @typescript-eslint/member-ordering */
198
+ templateFunction<P extends TermColorPaletteInput>(input: P): (key: keyof P, val: Prim) => string {
199
+ return ColorOutputUtil.templateFunction(this, input);
200
+ }
180
201
  }
202
+
181
203
  export const GlobalTerminal = new Terminal({ output: process.stdout });
182
204
 
183
205
  // Trigger
package/src/types.ts CHANGED
@@ -13,7 +13,7 @@ export type TerminalTableEvent = { idx: number, text: string, done?: boolean };
13
13
  export type TerminalTableConfig = { header?: string[], forceNonInteractiveOrder?: boolean };
14
14
  export type TerminalProgressEvent = { idx: number, total?: number, text?: string };
15
15
  export type TerminalProgressRender = (ev: TerminalProgressEvent) => string;
16
- export type TerminalWaitingConfig = { position?: TermLinePosition } & DelayedConfig;
16
+ export type TerminalWaitingConfig = { position?: TermLinePosition, end?: boolean } & DelayedConfig;
17
17
 
18
18
  export type TermColorLevel = 0 | 1 | 2 | 3;
19
19
  export type TermColorScheme = 'dark' | 'light';