@travetto/terminal
Advanced tools
Comparing version 3.4.0 to 4.0.0-rc.0
@@ -1,10 +0,5 @@ | ||
export * from './src/codes'; | ||
export * from './src/color-define'; | ||
export * from './src/color-output'; | ||
export * from './src/iterable'; | ||
export * from './src/named-colors'; | ||
export * from './src/operation'; | ||
export * from './src/query'; | ||
/// <reference path="./src/trv.d.ts" /> | ||
export * from './src/style'; | ||
export * from './src/terminal'; | ||
export * from './src/types'; | ||
export * from './src/writer'; | ||
export * from './src/writer'; | ||
export * from './src/util'; |
{ | ||
"name": "@travetto/terminal", | ||
"version": "3.4.0", | ||
"version": "4.0.0-rc.0", | ||
"description": "General terminal support", | ||
@@ -26,2 +26,6 @@ "keywords": [ | ||
}, | ||
"dependencies": { | ||
"@travetto/base": "^4.0.0-rc.0", | ||
"chalk": "^4.1.2" | ||
}, | ||
"travetto": { | ||
@@ -28,0 +32,0 @@ "displayName": "Terminal" |
@@ -26,27 +26,24 @@ <!-- This file was generated by @travetto/doc and should not be modified directly --> | ||
* 3 - True color, 24bit color with R, G, B each getting 8-bits. Can represent any color needed | ||
This module provides the ability to define color palettes using RGB or [named colors](https://github.com/travetto/travetto/tree/main/module/terminal/src/named-colors.ts#L1) modeled after the standard HTML color names. The module also provides the ability to specify palettes based on a dark or light background for a given terminal. Support for this is widespread, but when it fails, it will gracefully assume a dark background. | ||
This module provides the ability to define color palettes using RGB colors, and additionally provides support for palettes based on a dark or light background for a given terminal. Support for this is widespread, but when it fails, it will gracefully assume a dark background. | ||
These palettes then are usable at runtime, with the module determine light or dark palettes, as well as falling back to the closest color value based on what the existing terminal supports. This means a color like 'olivegreen', will get the proper output in 24bit color support, a close approximation in enhanced color support, fall back to green in basic color support, and will be color less at level 0. | ||
These palettes then are usable at runtime, with the module determining light or dark palettes, as well as falling back to the closest color value based on what the existing terminal supports. This means a color like 'olivegreen', will get the proper output in 24bit color support, a close approximation in enhanced color support, fall back to green in basic color support, and will be color less at level 0. | ||
**Code: CLI Color Palette** | ||
```typescript | ||
import { Util } from '@travetto/base'; | ||
import { GlobalTerminal } from '@travetto/terminal'; | ||
import { StyleUtil } from '@travetto/terminal'; | ||
const tplFn = GlobalTerminal.templateFunction({ | ||
input: 'oliveDrab', | ||
output: 'pink', | ||
path: 'teal', | ||
success: 'green', | ||
failure: 'red', | ||
param: ['yellow', 'goldenrod'], | ||
type: 'cyan', | ||
description: ['white', 'gray'], | ||
title: ['brightWhite', 'black'], | ||
identifier: 'dodgerBlue', | ||
subtitle: ['lightGray', 'darkGray'], | ||
subsubtitle: 'darkGray' | ||
export const cliTpl = StyleUtil.getTemplate({ | ||
input: '#6b8e23', // Olive drab | ||
output: '#ffc0cb', // Pink | ||
path: '#008080', // Teal | ||
success: '#00ff00', // Green | ||
failure: '#ff0000', // Red | ||
param: ['#ffff00', '#daa520'], // Yellow / Goldenrod | ||
type: '#00ffff', // Teal | ||
description: ['#e5e5e5', '#808080'], // White / Gray | ||
title: ['#ffffff', '#000000'], // Bright white / black | ||
identifier: '#1e90ff', // Dodger blue | ||
subtitle: ['#d3d3d3', '#a9a9a9'], // Light gray / Dark Gray | ||
subsubtitle: '#a9a9a9' // Dark gray | ||
}); | ||
export const cliTpl = Util.makeTemplate(tplFn); | ||
``` | ||
@@ -53,0 +50,0 @@ |
@@ -1,143 +0,73 @@ | ||
import tty from 'tty'; | ||
import timers from 'node:timers/promises'; | ||
import tty from 'node:tty'; | ||
import { IterableUtil, MapFn } from './iterable'; | ||
import { | ||
TermColorLevel, TermColorScheme, TerminalProgressEvent, TerminalTableConfig, | ||
TerminalTableEvent, TerminalWaitingConfig, TermLinePosition, TermState, TermCoord | ||
} from './types'; | ||
import { TerminalOperation } from './operation'; | ||
import { TerminalQuerier } from './query'; | ||
import { Env, Util } from '@travetto/base'; | ||
import { TerminalWriter } from './writer'; | ||
import { ColorOutputUtil, Prim, TermColorFn, TermColorPalette, TermColorPaletteInput, TermStyleInput } from './color-output'; | ||
type TerminalStreamPositionConfig = { | ||
position?: TermLinePosition; | ||
staticMessage?: string; | ||
minDelay?: number; | ||
}; | ||
type TerminalStreamingConfig = { minDelay?: number, outputStreamToMain?: boolean }; | ||
type Coord = { x: number, y: number }; | ||
type TerminalProgressConfig = TerminalStreamPositionConfig & { | ||
style?: TermStyleInput; | ||
}; | ||
export const WAIT_TOKEN = '%WAIT%'; | ||
const STD_WAIT_STATES = '⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'.split(''); | ||
/** | ||
* An enhanced tty write stream | ||
*/ | ||
export class Terminal implements TermState { | ||
const lineStatus = (l: string): string => l.replace(WAIT_TOKEN, ' '); | ||
const lineMain = (l: string): string => l.replace(WAIT_TOKEN, '').trim(); | ||
static async for(config: Partial<TermState>): Promise<Terminal> { | ||
const term = new Terminal(config); | ||
await term.init(); | ||
return term; | ||
} | ||
/** An basic tty wrapper */ | ||
export class Terminal { | ||
#init: Promise<void>; | ||
#interactive: boolean; | ||
#writer: TerminalWriter; | ||
#reset: () => Promise<void>; | ||
#cleanExit = 0; | ||
#width: number; | ||
#height: number; | ||
#output: tty.WriteStream; | ||
#input: tty.ReadStream; | ||
#interactive: boolean; | ||
#width?: number; | ||
#backgroundScheme?: TermColorScheme; | ||
#colorLevel?: TermColorLevel; | ||
#query: TerminalQuerier; | ||
constructor(config: Partial<TermState>) { | ||
this.#output = config.output ?? process.stdout; | ||
this.#input = config.input ?? process.stdin; | ||
this.#interactive = config.interactive ?? (this.#output.isTTY && !/^(true|yes|on|1)$/i.test(process.env.TRV_QUIET ?? '')); | ||
this.#width = config.width; | ||
this.#colorLevel = config.colorLevel; | ||
this.#backgroundScheme = config.backgroundScheme; | ||
this.#query = TerminalQuerier.for(this.#input, this.#output); | ||
} | ||
get output(): tty.WriteStream { | ||
return this.#output; | ||
} | ||
get input(): tty.ReadStream { | ||
return this.#input; | ||
} | ||
get interactive(): boolean { | ||
return this.#interactive; | ||
} | ||
get width(): number { | ||
return this.#width ?? (this.#output.isTTY ? this.#output.columns : 120); | ||
} | ||
get height(): number { | ||
return (this.#output.isTTY ? this.#output.rows : 120); | ||
} | ||
get colorLevel(): TermColorLevel { | ||
return this.#colorLevel ?? 0; | ||
} | ||
get backgroundScheme(): TermColorScheme { | ||
return this.#backgroundScheme ?? 'dark'; | ||
} | ||
writer(): TerminalWriter { | ||
return TerminalWriter.for(this); | ||
} | ||
async writeLines(...text: string[]): Promise<void> { | ||
return this.writer().writeLines(text, this.interactive).commit(); | ||
} | ||
async init(): Promise<void> { | ||
if (!this.#init) { | ||
this.#init = (async (): Promise<void> => { | ||
this.#colorLevel ??= await ColorOutputUtil.readTermColorLevel(this.#output); | ||
this.#backgroundScheme ??= await ColorOutputUtil.readBackgroundScheme( | ||
this.#output, | ||
() => this.interactive ? this.#query.backgroundColor() : undefined | ||
); | ||
})(); | ||
process.on('exit', () => this.reset()); | ||
async #showWaitingIndicator(pos: Coord, signal: AbortSignal): Promise<void> { | ||
let done = false; | ||
signal.addEventListener('abort', () => done = true); | ||
let i = 0; | ||
while (!done) { | ||
await this.#writer.setPosition(pos).write(STD_WAIT_STATES[i++ % STD_WAIT_STATES.length]).commit(true); | ||
await timers.setTimeout(100); | ||
} | ||
return this.#init; | ||
} | ||
reset(): void { | ||
this.#query.close(); | ||
if (this.interactive) { | ||
this.#output.write(this.writer().resetCommands()); | ||
#cleanOnExit(): () => void { | ||
if (this.#cleanExit === 0) { | ||
process.on('exit', this.#reset); | ||
} | ||
this.#cleanExit += 1; | ||
return () => (this.#cleanExit -= 1) === 0 && process.off('exit', this.#reset); | ||
} | ||
getCursorPosition(): Promise<TermCoord> { | ||
return this.#query.cursorPosition(); | ||
constructor(output?: tty.WriteStream, config?: { width?: number, height?: number }) { | ||
this.#output = output ?? process.stdout; | ||
this.#interactive = this.#output.isTTY && !Env.TRV_QUIET.isTrue; | ||
this.#width = config?.width ?? (this.#output.isTTY ? this.#output.columns : 120); | ||
this.#height = config?.height ?? (this.#output.isTTY ? this.#output.rows : 120); | ||
const w = this.#writer = new TerminalWriter(this); | ||
this.#reset = (): Promise<void> => w.softReset().commit(); | ||
} | ||
/** | ||
* Waiting message with a callback to end | ||
*/ | ||
async withWaiting<T>(message: string, work: Promise<T> | (() => Promise<T>), config: TerminalWaitingConfig = {}): Promise<T> { | ||
const res = (typeof work === 'function' ? work() : work); | ||
if (!this.interactive) { | ||
await this.writeLines(`${message}...`); | ||
return res; | ||
} | ||
return res.finally(TerminalOperation.streamWaiting(this, message, config)); | ||
} | ||
get output(): tty.WriteStream { return this.#output; } | ||
get width(): number { return this.#width; } | ||
get height(): number { return this.#height; } | ||
get writer(): TerminalWriter { return this.#writer; } | ||
get interactive(): boolean { return this.#interactive; } | ||
/** | ||
* Stream line output, showing a waiting indicator for each line until the next one occurs | ||
* | ||
* @param lines | ||
* @param config | ||
* @returns | ||
* Stream lines if interactive, with waiting indicator, otherwise print out | ||
*/ | ||
async streamLinesWithWaiting(lines: AsyncIterable<string | undefined>, config: TerminalWaitingConfig): Promise<void> { | ||
if (!this.interactive) { | ||
for await (const line of lines) { | ||
async streamLines(source: AsyncIterable<string | undefined>): Promise<void> { | ||
if (!this.#interactive) { | ||
for await (const line of source) { | ||
if (line !== undefined) { | ||
const out = config.committedPrefix ? `${config.committedPrefix} ${line}` : line; | ||
await this.writeLines(out); | ||
await this.#writer.writeLine(`> ${line}`).commit(); | ||
} | ||
} | ||
} else { | ||
return TerminalOperation.streamLinesWithWaiting(this, lines, { position: 'bottom', ...config }); | ||
await this.streamToBottom(Util.mapAsyncItr(source, x => `%WAIT% ${x}`), { outputStreamToMain: true }); | ||
} | ||
@@ -147,63 +77,80 @@ } | ||
/** | ||
* Consumes a stream, of events, tied to specific list indices, and updates in place | ||
* Allows for writing at bottom of screen with scrolling support for main content | ||
*/ | ||
async streamList<T>(source: AsyncIterable<T>, resolve: MapFn<T, TerminalTableEvent>, config: TerminalTableConfig = {}): Promise<void> { | ||
const resolved = IterableUtil.map(source, resolve); | ||
async streamToBottom(source: AsyncIterable<string | undefined>, config: TerminalStreamingConfig = {}): Promise<void> { | ||
const writePos = { x: 0, y: -1 }; | ||
const minDelay = config.minDelay ?? 0; | ||
const remove = this.#cleanOnExit(); | ||
await this.writeLines(...(config.header ?? [])); | ||
let prev: string | undefined; | ||
let stop: AbortController | undefined; | ||
let start = Date.now(); | ||
if (!this.interactive) { | ||
const isDone = IterableUtil.filter(resolved, ev => !!ev.done); | ||
if (config.forceNonInteractiveOrder) { | ||
await this.writeLines(...(await IterableUtil.drain(isDone)).map(x => x.text), ''); | ||
} else { | ||
await IterableUtil.drain(IterableUtil.map(isDone, ev => this.writeLines(ev.text))); | ||
await this.writeLines(''); | ||
try { | ||
await this.#writer.hideCursor() | ||
.storePosition().scrollRange({ end: -2 }).restorePosition() | ||
.changePosition({ y: -1 }).write('\n') | ||
.commit(); | ||
for await (const line of source) { | ||
// Previous line | ||
if (prev && config.outputStreamToMain) { | ||
await this.writer.writeLine(lineMain(prev)).commit(); | ||
} | ||
if (line && (Date.now() - start) >= minDelay) { | ||
start = Date.now(); | ||
stop?.abort(); | ||
this.writer.setPosition(writePos).write(lineStatus(line)).clearLine(1).commit(true); | ||
const idx = line.indexOf(WAIT_TOKEN); | ||
if (idx >= 0) { | ||
stop = new AbortController(); | ||
this.#showWaitingIndicator({ y: writePos.y, x: idx }, stop.signal); | ||
} | ||
} | ||
prev = line; | ||
} | ||
return; | ||
stop?.abort(); | ||
if (prev !== undefined && config.outputStreamToMain) { | ||
await this.writer.writeLine(lineMain(prev)).commit(); | ||
} | ||
await this.#writer.setPosition(writePos).clearLine().commit(true); | ||
} finally { | ||
await this.#writer.softReset().commit(); | ||
remove(); | ||
} | ||
await TerminalOperation.streamList(this, resolved); | ||
} | ||
/** | ||
* Streams an iterable to a specific location, with support for non-interactive ttys | ||
* Consumes a stream, of events, tied to specific list indices, and updates in place | ||
*/ | ||
async streamToPosition<T>(source: AsyncIterable<T>, resolve: MapFn<T, string>, config?: TerminalStreamPositionConfig): Promise<void> { | ||
if (!this.interactive) { | ||
if (config?.staticMessage) { | ||
await this.writeLines(config.staticMessage); | ||
async streamList(source: AsyncIterable<{ idx: number, text: string, done?: boolean }>): Promise<void> { | ||
if (!this.#interactive) { | ||
const collected = []; | ||
for await (const ev of source) { | ||
if (ev.done) { | ||
collected[ev.idx] = ev.text; | ||
} | ||
} | ||
await IterableUtil.drain(source); | ||
await this.#writer.writeLines(collected).commit(); | ||
return; | ||
} | ||
return TerminalOperation.streamToPosition(this, IterableUtil.map(source, resolve), config); | ||
} | ||
/** | ||
* Track progress of an asynchronous iterator, allowing the showing of a progress bar if the stream produces idx and total | ||
*/ | ||
async trackProgress<T, V extends TerminalProgressEvent>( | ||
source: AsyncIterable<T>, resolve: MapFn<T, V>, config?: TerminalProgressConfig | ||
): Promise<void> { | ||
const render = TerminalOperation.buildProgressBar(this, config?.style ?? { background: 'limeGreen', text: 'black' }); | ||
return this.streamToPosition(source, async (v, i) => render(await resolve(v, i)), config); | ||
const remove = this.#cleanOnExit(); | ||
let max = 0; | ||
try { | ||
await this.#writer.hideCursor().commit(); | ||
for await (const { idx, text } of source) { | ||
max = Math.max(idx, max); | ||
await this.#writer.write('\n'.repeat(idx)).setPosition({ x: 0 }).write(text).clearLine(1).changePosition({ y: -idx }).commit(); | ||
} | ||
} finally { | ||
await this.#writer.changePosition({ y: max + 1 }).writeLine('\n').softReset().commit(); | ||
remove(); | ||
} | ||
} | ||
/** Creates a colorer function */ | ||
colorer(style: TermStyleInput | [light: TermStyleInput, dark: TermStyleInput]): TermColorFn { | ||
return ColorOutputUtil.colorer(this, style); | ||
} | ||
/** Creates a color palette based on input styles */ | ||
palette<P extends TermColorPaletteInput>(input: P): TermColorPalette<P> { | ||
return ColorOutputUtil.palette(this, input); | ||
} | ||
/** Convenience method to creates a color template function based on input styles */ | ||
templateFunction<P extends TermColorPaletteInput>(input: P): (key: keyof P, val: Prim) => string { | ||
return ColorOutputUtil.templateFunction(this, input); | ||
} | ||
} | ||
export const GlobalTerminal = new Terminal({ output: process.stdout }); | ||
} |
@@ -1,9 +0,28 @@ | ||
import { ANSICodes } from './codes'; | ||
import { TermCoord, TermState } from './types'; | ||
import tty from 'node:tty'; | ||
const boundIndex = (v: number, size: number): number => { | ||
if (v < 0) { | ||
v = size + v; | ||
} | ||
return Math.max(Math.min(v, size - 1), 0); | ||
type State = { output: tty.WriteStream, height: number, width: number }; | ||
type TermCoord = { x: number, y: number }; | ||
const ESC = '\x1b['; | ||
const clamp = (v: number, size: number): number => Math.max(Math.min(v + (v < 0 ? size : 0), size - 1), 0); | ||
const delta = (v: number | undefined, pos: string, neg: string): string => | ||
!v ? '' : `${ESC}${Math.abs(v)}${v < 0 ? neg : pos}`; | ||
const Codes = { | ||
SHOW_CURSOR: `${ESC}?25h`, | ||
HIDE_CURSOR: `${ESC}?25l`, | ||
SCROLL_RANGE_CLEAR: `${ESC}r`, | ||
POSITION_RESTORE: `${ESC}u`, | ||
POSITION_SAVE: `${ESC}s`, | ||
SOFT_RESET_CODES: `${ESC}!p`, | ||
ERASE_LINE_RIGHT: `${ESC}0K`, | ||
ERASE_LINE_LEFT: `${ESC}1K`, | ||
ERASE_LINE_ALL: `${ESC}2K`, | ||
DEBUG: (text: string): string => text.replaceAll(ESC, '<ESC>').replaceAll('\n', '<NL>'), | ||
CURSOR_MOVE: (x?: number, y?: number): string => `${delta(x, 'C', 'D')}${delta(y, 'B', 'A')}`, | ||
POSITION_SET: (x: number, y: number | undefined, maxX: number, maxY: number): string => y !== undefined ? | ||
`${ESC}${clamp(y, maxY) + 1};${clamp(x, maxX) + 1}H` : `${ESC}${clamp(x, maxX) + 1}G`, | ||
SCROLL_RANGE_SET: (start: number, end: number, max: number): string => | ||
`${ESC}${clamp(start, max) + 1};${clamp(end, max) + 1}r` | ||
}; | ||
@@ -15,13 +34,16 @@ | ||
export class TerminalWriter { | ||
#buffer: (string | number)[] = []; | ||
#restoreOnCommit = false; | ||
#term: State; | ||
static for(term: TermState): TerminalWriter { | ||
return new TerminalWriter(term); | ||
constructor(state: State) { | ||
this.#term = state; | ||
} | ||
#queue: (string | number)[] = []; | ||
#term: TermState; | ||
#restoreOnCommit = false; | ||
constructor(term: TermState) { | ||
this.#term = term; | ||
/** Pad to width of terminal */ | ||
padToWidth(text: string, offset = 0, ellipsis = '...'): string { | ||
if (text.length > (this.#term.width - offset)) { | ||
return `${text.substring(0, this.#term.width - (offset + ellipsis.length))}${ellipsis}`; | ||
} | ||
return text.padEnd(this.#term.width - offset, ' '); | ||
} | ||
@@ -36,13 +58,17 @@ | ||
commit(restorePosition: boolean = this.#restoreOnCommit): Promise<void> { | ||
const q = this.#queue.filter(x => x !== undefined); | ||
this.#queue = []; | ||
const q = this.#buffer.filter(x => x !== undefined); | ||
this.#buffer = []; | ||
if (q.length && restorePosition) { | ||
q.unshift(ANSICodes.POSITION_SAVE()); | ||
q.push(ANSICodes.POSITION_RESTORE()); | ||
q.unshift(Codes.POSITION_SAVE); | ||
q.push(Codes.POSITION_RESTORE); | ||
} | ||
return q.length ? new Promise(r => this.#term.output.write(q.join(''), () => r())) : Promise.resolve(); | ||
if (q.length && !this.#term.output.write(q.join(''))) { | ||
return new Promise<void>(r => this.#term.output.once('drain', r)); | ||
} else { | ||
return Promise.resolve(); | ||
} | ||
} | ||
write(...text: (string | number)[]): this { | ||
this.#queue.push(...text); | ||
this.#buffer.push(...text); | ||
return this; | ||
@@ -53,3 +79,3 @@ } | ||
storePosition(): this { | ||
return this.write(ANSICodes.POSITION_SAVE()); | ||
return this.write(Codes.POSITION_SAVE); | ||
} | ||
@@ -59,13 +85,12 @@ | ||
restorePosition(): this { | ||
return this.write(ANSICodes.POSITION_RESTORE()); | ||
return this.write(Codes.POSITION_RESTORE); | ||
} | ||
/** Rewrite a single line in the stream */ | ||
rewriteLine(text: string): this { | ||
return this.setPosition({ x: 0 }).write(text); | ||
} | ||
/** Clear line, -1 (left), 0 (both), 1 (right), from current cursor */ | ||
clearLine(dir: -1 | 0 | 1 = 0): this { | ||
return this.write(ANSICodes.ERASE_LINE(dir === 0 ? 2 : (dir === 1 ? 0 : 1))); | ||
switch (dir) { | ||
case 0: return this.write(Codes.ERASE_LINE_ALL); | ||
case 1: return this.write(Codes.ERASE_LINE_RIGHT); | ||
case -1: return this.write(Codes.ERASE_LINE_LEFT); | ||
} | ||
} | ||
@@ -75,11 +100,3 @@ | ||
setPosition({ x = 0, y }: Partial<TermCoord>): this { | ||
if (y !== undefined) { | ||
y = boundIndex(y, this.#term.output.rows); | ||
} | ||
x = boundIndex(x, this.#term.output.columns); | ||
if (y !== undefined) { | ||
return this.write(ANSICodes.POSITION_SET(y + 1, x + 1)); | ||
} else { | ||
return this.write(ANSICodes.COLUMN_SET(x + 1)); | ||
} | ||
return this.write(Codes.POSITION_SET(x, y, this.#term.width, this.#term.height)); | ||
} | ||
@@ -89,9 +106,3 @@ | ||
changePosition({ x, y }: Partial<TermCoord>): this { | ||
if (x) { | ||
this.write(ANSICodes.CURSOR_DX(x)); | ||
} | ||
if (y) { | ||
this.write(ANSICodes.CURSOR_DY(y)); | ||
} | ||
return this; | ||
return this.write(Codes.CURSOR_MOVE(x, y)); | ||
} | ||
@@ -110,3 +121,3 @@ | ||
if (clear) { | ||
text = text.replaceAll('\n', `${ANSICodes.ERASE_LINE(0)}\n`); | ||
text = text.replaceAll('\n', `${Codes.ERASE_LINE_RIGHT}\n`); | ||
} | ||
@@ -120,3 +131,3 @@ text = `${text}\n`; | ||
showCursor(): this { | ||
return this.write(ANSICodes.SHOW_CURSOR()); | ||
return this.write(Codes.SHOW_CURSOR); | ||
} | ||
@@ -126,10 +137,8 @@ | ||
hideCursor(): this { | ||
return this.write(ANSICodes.HIDE_CURSOR()); | ||
return this.write(Codes.HIDE_CURSOR); | ||
} | ||
/** Set scrolling range */ | ||
scrollRange({ start, end }: { start?: number, end?: number }): this { | ||
start = boundIndex(start ?? 0, this.#term.output.rows); | ||
end = boundIndex(end ?? -1, this.#term.output.rows); | ||
return this.write(ANSICodes.SCROLL_RANGE_SET(start + 1, end + 1)); | ||
scrollRange({ start = 0, end = -1 }: { start?: number, end?: number }): this { | ||
return this.write(Codes.SCROLL_RANGE_SET(start, end, this.#term.height)); | ||
} | ||
@@ -139,24 +148,9 @@ | ||
scrollRangeClear(): this { | ||
return this.write(ANSICodes.SCROLL_RANGE_CLEAR()); | ||
return this.write(Codes.SCROLL_RANGE_CLEAR); | ||
} | ||
/** Scrolling window y <=0 - up, else down */ | ||
scrollY(y: number): this { | ||
return this.write(ANSICodes.SCROLL_WINDOW(y)); | ||
} | ||
/** Reset */ | ||
reset(): this { | ||
return this.write(this.resetCommands()); | ||
softReset(): this { | ||
return this.write(Codes.SOFT_RESET_CODES); | ||
} | ||
/** Reset Commands */ | ||
resetCommands(): string { | ||
return [ | ||
ANSICodes.POSITION_SAVE(), | ||
ANSICodes.SHOW_CURSOR(), | ||
ANSICodes.SCROLL_RANGE_CLEAR(), | ||
ANSICodes.POSITION_RESTORE() | ||
].join(''); | ||
} | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
21909
2
8
429
1
80
1
+ Added@travetto/base@^4.0.0-rc.0
+ Addedchalk@^4.1.2
+ Added@travetto/base@4.1.2(transitive)
+ Added@travetto/manifest@4.1.0(transitive)
+ Added@types/debug@4.1.12(transitive)
+ Added@types/ms@2.1.0(transitive)
+ Added@types/node@20.17.22(transitive)
+ Addedansi-styles@4.3.0(transitive)
+ Addedchalk@4.1.2(transitive)
+ Addedcolor-convert@2.0.1(transitive)
+ Addedcolor-name@1.1.4(transitive)
+ Addeddebug@4.4.0(transitive)
+ Addedhas-flag@4.0.0(transitive)
+ Addedms@2.1.3(transitive)
+ Addedsupports-color@7.2.0(transitive)
+ Addedundici-types@6.19.8(transitive)