Add writeAnsiU function and remove tests
`writeAnsi` is a convenient function that automatically encodes text and automatically adds a reset. `writeAnsiU` is a unary function that takes in an array of Uint8Arrays and keys for ANSI_BUFFERS. There is no automatic text encoding, so an `ansiText` function has been added. There is also no automatic reset. This allows the function's logic to be simpler, resulting in 3-4 times performance increase per Windows benchmarking. It is also more flexible for complex formatting scenarios. Both functions convienently allow strings that are keys of ANSI_BUFFERS to be passed, and these are auto-matched. Both functions return a Promise<number>, allowing for maximum performance but necessitating error handling on the part of the consumer. It is also important to `await` these functions when calling in a specific order. This is an advantage of `writeAnsiU`, which allows for longer, more complex prints in a single function call.
This commit is contained in:
parent
4151d0335c
commit
e83fcd0b4d
@ -100,7 +100,7 @@ export const ANSI_BUFFERS = {
|
||||
CLEAR_BELOW: encoder.encode(ANSI.CLEAR_BELOW),
|
||||
}
|
||||
|
||||
export const ANSI_DYNAMIC = {
|
||||
const ANSI_DYNAMIC = {
|
||||
// Cursor Control
|
||||
CURSOR_TO: (x: number, y: number) => encoder.encode(ANSI.CURSOR_TO(x, y)),
|
||||
CURSOR_UP: (x = 1) => encoder.encode(ANSI.CURSOR_UP(x)),
|
||||
@ -116,7 +116,7 @@ type WriteAnsi = (
|
||||
t?: string,
|
||||
a?: boolean,
|
||||
) => Promise<number>
|
||||
const writeAnsi: WriteAnsi = async (codes, text?, autoReset = true) => {
|
||||
const writeAnsi: WriteAnsi = (codes, text?, autoReset = true) => {
|
||||
const arr = [
|
||||
...codes,
|
||||
!text ? emptyBytes : encoder.encode(text),
|
||||
@ -126,95 +126,21 @@ const writeAnsi: WriteAnsi = async (codes, text?, autoReset = true) => {
|
||||
return writer(Buffer.concat(arr))
|
||||
}
|
||||
|
||||
const writeAnsi1: WriteAnsi = async (codes, text?, autoReset = true) => {
|
||||
const buffers = [
|
||||
...codes,
|
||||
!text ? emptyBytes : encoder.encode(text),
|
||||
autoReset ? ANSI_BUFFERS['RESET'] : emptyBytes,
|
||||
].map(x => x instanceof Uint8Array ? x : ANSI_BUFFERS[x])
|
||||
type AnsiText = (x: string) => Uint8Array
|
||||
const ansiText: AnsiText = x => encoder.encode(x)
|
||||
|
||||
// Calculate total length and create combined buffer
|
||||
const totalLength = buffers.reduce((sum, buf) => sum + buf.length, 0)
|
||||
const combined = new Uint8Array(totalLength)
|
||||
|
||||
// Copy all buffers into the combined array
|
||||
let offset = 0
|
||||
for (const buffer of buffers) {
|
||||
combined.set(buffer, offset)
|
||||
offset += buffer.length
|
||||
}
|
||||
|
||||
return writer(combined)
|
||||
}
|
||||
type WriteAnsiU = (x: Array<AnsiBufferKey | Uint8Array>) => Promise<number>
|
||||
const writeAnsiU: WriteAnsiU = x =>
|
||||
writer(Buffer.concat(x.map(
|
||||
x => x instanceof Uint8Array ? x : ANSI_BUFFERS[x],
|
||||
)))
|
||||
|
||||
// For CommonJS compatibility
|
||||
export default {ANSI, ANSI_BUFFERS, writeAnsi}
|
||||
|
||||
const bench = async (x, n) => {
|
||||
const a = Bun.nanoseconds()
|
||||
let i = 0
|
||||
while (i < n) {
|
||||
await x()
|
||||
i++
|
||||
}
|
||||
const b = Bun.nanoseconds()
|
||||
return (b - a) / 100000
|
||||
export default {
|
||||
ANSI,
|
||||
ANSI_BUFFERS,
|
||||
ANSI_DYNAMIC,
|
||||
ansiText,
|
||||
writeAnsi,
|
||||
writeAnsiU,
|
||||
}
|
||||
|
||||
const one = async () => {
|
||||
await writeAnsi(
|
||||
['BG_CYAN', 'BLACK', 'ITALIC'],
|
||||
'This is the first option I want',
|
||||
)
|
||||
await writeAnsi(
|
||||
['BG_BLUE', 'BLACK', 'BOLD'],
|
||||
'This is the second option I want',
|
||||
)
|
||||
await writeAnsi(
|
||||
['BG_YELLOW', 'BLACK', 'BLINK'],
|
||||
'Now, this is the third and final option',
|
||||
)
|
||||
}
|
||||
|
||||
const two = async () => {
|
||||
await writeAnsi1(
|
||||
['BG_CYAN', 'BLACK', 'ITALIC'],
|
||||
'This is the first option I want',
|
||||
)
|
||||
await writeAnsi1(
|
||||
['BG_BLUE', 'BLACK', 'BOLD'],
|
||||
'This is the second option I want',
|
||||
)
|
||||
await writeAnsi1(
|
||||
['BG_YELLOW', 'BLACK', 'BLINK'],
|
||||
'Now, this is the third and final option',
|
||||
)
|
||||
}
|
||||
|
||||
const test = async () => {
|
||||
const testN = 100000
|
||||
|
||||
await bench(one, 100000)
|
||||
await bench(two, 100000)
|
||||
|
||||
const testTwo = await bench(two, testN)
|
||||
const testOne = await bench(one, testN)
|
||||
|
||||
await writeAnsi(
|
||||
['RESET', ANSI_DYNAMIC.CURSOR_TO(0, 0)],
|
||||
`${ANSI.CLEAR_SCREEN}\n\n`,
|
||||
)
|
||||
await writeAnsi(['BG_YELLOW', 'BLACK'], '---------------\n')
|
||||
await writeAnsi(['BG_YELLOW', 'BOLD', 'BLACK'], '***************\n')
|
||||
await writeAnsi(['BG_YELLOW', 'BLACK'], '---------------\n')
|
||||
await writeAnsi(['BG_YELLOW', 'BLACK'], 'ONE:')
|
||||
await writeAnsi(['BG_YELLOW', 'GREEN'], testOne.toString() + '\n')
|
||||
await writeAnsi(['BG_YELLOW', 'BLACK'], 'TWO:')
|
||||
await writeAnsi(['BG_YELLOW', 'GREEN'], testTwo.toString() + '\n')
|
||||
await writeAnsi(['BG_YELLOW', 'BLACK'], '---------------\n')
|
||||
await writeAnsi(['BG_YELLOW', 'BOLD', 'BLACK'], '***************\n')
|
||||
await writeAnsi(['BG_YELLOW', 'BLACK'], '---------------')
|
||||
await writeAnsi(['RESET'], '\n\n')
|
||||
}
|
||||
|
||||
test()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user