You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
3.0 KiB
116 lines
3.0 KiB
'use strict'; |
|
|
|
const isTerm = process.env.TERM_PROGRAM === 'Apple_Terminal'; |
|
const colors = require('ansi-colors'); |
|
const utils = require('./utils'); |
|
const ansi = module.exports = exports; |
|
const ESC = '\u001b['; |
|
const BEL = '\u0007'; |
|
let hidden = false; |
|
|
|
const code = ansi.code = { |
|
bell: BEL, |
|
beep: BEL, |
|
beginning: `${ESC}G`, |
|
down: `${ESC}J`, |
|
esc: ESC, |
|
getPosition: `${ESC}6n`, |
|
hide: `${ESC}?25l`, |
|
line: `${ESC}2K`, |
|
lineEnd: `${ESC}K`, |
|
lineStart: `${ESC}1K`, |
|
restorePosition: ESC + (isTerm ? '8' : 'u'), |
|
savePosition: ESC + (isTerm ? '7' : 's'), |
|
screen: `${ESC}2J`, |
|
show: `${ESC}?25h`, |
|
up: `${ESC}1J` |
|
}; |
|
|
|
const cursor = ansi.cursor = { |
|
get hidden() { |
|
return hidden; |
|
}, |
|
|
|
hide() { |
|
hidden = true; |
|
return code.hide; |
|
}, |
|
show() { |
|
hidden = false; |
|
return code.show; |
|
}, |
|
|
|
forward: (count = 1) => `${ESC}${count}C`, |
|
backward: (count = 1) => `${ESC}${count}D`, |
|
nextLine: (count = 1) => `${ESC}E`.repeat(count), |
|
prevLine: (count = 1) => `${ESC}F`.repeat(count), |
|
|
|
up: (count = 1) => count ? `${ESC}${count}A` : '', |
|
down: (count = 1) => count ? `${ESC}${count}B` : '', |
|
right: (count = 1) => count ? `${ESC}${count}C` : '', |
|
left: (count = 1) => count ? `${ESC}${count}D` : '', |
|
|
|
to(x, y) { |
|
return y ? `${ESC}${y + 1};${x + 1}H` : `${ESC}${x + 1}G`; |
|
}, |
|
|
|
move(x = 0, y = 0) { |
|
let res = ''; |
|
res += (x < 0) ? cursor.left(-x) : (x > 0) ? cursor.right(x) : ''; |
|
res += (y < 0) ? cursor.up(-y) : (y > 0) ? cursor.down(y) : ''; |
|
return res; |
|
}, |
|
|
|
restore(state = {}) { |
|
let { after, cursor, initial, input, prompt, size, value } = state; |
|
initial = utils.isPrimitive(initial) ? String(initial) : ''; |
|
input = utils.isPrimitive(input) ? String(input) : ''; |
|
value = utils.isPrimitive(value) ? String(value) : ''; |
|
|
|
if (size) { |
|
let codes = ansi.cursor.up(size) + ansi.cursor.to(prompt.length); |
|
let diff = input.length - cursor; |
|
if (diff > 0) { |
|
codes += ansi.cursor.left(diff); |
|
} |
|
return codes; |
|
} |
|
|
|
if (value || after) { |
|
let pos = (!input && !!initial) ? -initial.length : -input.length + cursor; |
|
if (after) pos -= after.length; |
|
if (input === '' && initial && !prompt.includes(initial)) { |
|
pos += initial.length; |
|
} |
|
return ansi.cursor.move(pos); |
|
} |
|
} |
|
}; |
|
|
|
const erase = ansi.erase = { |
|
screen: code.screen, |
|
up: code.up, |
|
down: code.down, |
|
line: code.line, |
|
lineEnd: code.lineEnd, |
|
lineStart: code.lineStart, |
|
lines(n) { |
|
let str = ''; |
|
for (let i = 0; i < n; i++) { |
|
str += ansi.erase.line + (i < n - 1 ? ansi.cursor.up(1) : ''); |
|
} |
|
if (n) str += ansi.code.beginning; |
|
return str; |
|
} |
|
}; |
|
|
|
ansi.clear = (input = '', columns = process.stdout.columns) => { |
|
if (!columns) return erase.line + cursor.to(0); |
|
let width = str => [...colors.unstyle(str)].length; |
|
let lines = input.split(/\r?\n/); |
|
let rows = 0; |
|
for (let line of lines) { |
|
rows += 1 + Math.floor(Math.max(width(line) - 1, 0) / columns); |
|
} |
|
return (erase.line + cursor.prevLine()).repeat(rows - 1) + erase.line + cursor.to(0); |
|
};
|
|
|