--- /dev/null
+'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;
+};