123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- 'use strict';
- const isFullwidthCodePoint = require('is-fullwidth-code-point');
- const astralRegex = require('astral-regex');
- const ansiStyles = require('ansi-styles');
- const ESCAPES = [
- '\u001B',
- '\u009B'
- ];
- const wrapAnsi = code => `${ESCAPES[0]}[${code}m`;
- const checkAnsi = (ansiCodes, isEscapes, endAnsiCode) => {
- let output = [];
- ansiCodes = [...ansiCodes];
- for (let ansiCode of ansiCodes) {
- const ansiCodeOrigin = ansiCode;
- if (ansiCode.includes(';')) {
- ansiCode = ansiCode.split(';')[0][0] + '0';
- }
- const item = ansiStyles.codes.get(Number.parseInt(ansiCode, 10));
- if (item) {
- const indexEscape = ansiCodes.indexOf(item.toString());
- if (indexEscape === -1) {
- output.push(wrapAnsi(isEscapes ? item : ansiCodeOrigin));
- } else {
- ansiCodes.splice(indexEscape, 1);
- }
- } else if (isEscapes) {
- output.push(wrapAnsi(0));
- break;
- } else {
- output.push(wrapAnsi(ansiCodeOrigin));
- }
- }
- if (isEscapes) {
- output = output.filter((element, index) => output.indexOf(element) === index);
- if (endAnsiCode !== undefined) {
- const fistEscapeCode = wrapAnsi(ansiStyles.codes.get(Number.parseInt(endAnsiCode, 10)));
- output = output.reduce((current, next) => next === fistEscapeCode ? [next, ...current] : [...current, next], []);
- }
- }
- return output.join('');
- };
- module.exports = (string, begin, end) => {
- const characters = [...string];
- const ansiCodes = [];
- let stringEnd = typeof end === 'number' ? end : characters.length;
- let isInsideEscape = false;
- let ansiCode;
- let visible = 0;
- let output = '';
- for (const [index, character] of characters.entries()) {
- let leftEscape = false;
- if (ESCAPES.includes(character)) {
- const code = /\d[^m]*/.exec(string.slice(index, index + 18));
- ansiCode = code && code.length > 0 ? code[0] : undefined;
- if (visible < stringEnd) {
- isInsideEscape = true;
- if (ansiCode !== undefined) {
- ansiCodes.push(ansiCode);
- }
- }
- } else if (isInsideEscape && character === 'm') {
- isInsideEscape = false;
- leftEscape = true;
- }
- if (!isInsideEscape && !leftEscape) {
- visible++;
- }
- if (!astralRegex({exact: true}).test(character) && isFullwidthCodePoint(character.codePointAt())) {
- visible++;
- if (typeof end !== 'number') {
- stringEnd++;
- }
- }
- if (visible > begin && visible <= stringEnd) {
- output += character;
- } else if (visible === begin && !isInsideEscape && ansiCode !== undefined) {
- output = checkAnsi(ansiCodes);
- } else if (visible >= stringEnd) {
- output += checkAnsi(ansiCodes, true, ansiCode);
- break;
- }
- }
- return output;
- };
|