123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- /* eslint max-lines: "off" */
- "use strict";
- var reAnsi = require("./regex-ansi")
- , stringifiable = require("es5-ext/object/validate-stringifiable-value")
- , length = require("./get-stripped-length")
- , sgr = require("./lib/sgr")
- , max = Math.max;
- var Token = function (token) { this.token = token; };
- var tokenize = function (str) {
- var match = reAnsi().exec(str);
- if (!match) {
- return [str];
- }
- var index = match.index, head, prehead, tail;
- if (index === 0) {
- head = match[0];
- tail = str.slice(head.length);
- return [new Token(head)].concat(tokenize(tail));
- }
- prehead = str.slice(0, index);
- head = match[0];
- tail = str.slice(index + head.length);
- return [prehead, new Token(head)].concat(tokenize(tail));
- };
- var isChunkInSlice = function (chunk, index, begin, end) {
- var endIndex = chunk.length + index;
- if (begin > endIndex) return false;
- if (end < index) return false;
- return true;
- };
- // eslint-disable-next-line max-lines-per-function
- var sliceSeq = function (seq, begin, end) {
- var sliced = seq.reduce(
- function (state, chunk) {
- var index = state.index;
- if (chunk instanceof Token) {
- var code = sgr.extractCode(chunk.token);
- if (index <= begin) {
- if (code in sgr.openers) {
- sgr.openStyle(state.preOpeners, code);
- }
- if (code in sgr.closers) {
- sgr.closeStyle(state.preOpeners, code);
- }
- } else if (index < end) {
- if (code in sgr.openers) {
- sgr.openStyle(state.inOpeners, code);
- state.seq.push(chunk);
- } else if (code in sgr.closers) {
- state.inClosers.push(code);
- state.seq.push(chunk);
- }
- }
- } else {
- var nextChunk = "";
- if (isChunkInSlice(chunk, index, begin, end)) {
- var relBegin = Math.max(begin - index, 0)
- , relEnd = Math.min(end - index, chunk.length);
- nextChunk = chunk.slice(relBegin, relEnd);
- }
- state.seq.push(nextChunk);
- state.index = index + chunk.length;
- }
- return state;
- },
- {
- index: 0,
- seq: [],
- // preOpeners -> [ mod ]
- // preOpeners must be prepended to the slice if they wasn't closed til the end of it
- // preOpeners must be closed if they wasn't closed til the end of the slice
- preOpeners: [],
- // inOpeners -> [ mod ]
- // inOpeners already in the slice and must not be prepended to the slice
- // inOpeners must be closed if they wasn't closed til the end of the slice
- inOpeners: [], // opener CSI inside slice
- // inClosers -> [ code ]
- // closer CSIs for determining which pre/in-Openers must be closed
- inClosers: []
- }
- );
- sliced.seq = [].concat(
- sgr.prepend(sliced.preOpeners), sliced.seq,
- sgr.complete([].concat(sliced.preOpeners, sliced.inOpeners), sliced.inClosers)
- );
- return sliced.seq;
- };
- module.exports = function (str /*, begin, end*/) {
- var seq, begin = Number(arguments[1]), end = Number(arguments[2]), len;
- str = stringifiable(str);
- len = length(str);
- if (isNaN(begin)) {
- begin = 0;
- }
- if (isNaN(end)) {
- end = len;
- }
- if (begin < 0) {
- begin = max(len + begin, 0);
- }
- if (end < 0) {
- end = max(len + end, 0);
- }
- seq = tokenize(str);
- seq = sliceSeq(seq, begin, end);
- return seq
- .map(function (chunk) {
- if (chunk instanceof Token) {
- return chunk.token;
- }
- return chunk;
- })
- .join("");
- };
|