UNPKG

compound-ex4

Version:

Compound-ex4 - MVC framework for NodeJS (ExpressJs 4 version), fork compoundjs(https://github.com/1602/compound)

141 lines (111 loc) 3.19 kB
'use strict'; var reAnsi = require('ansi-regex') , stringifiable = require('es5-ext/object/validate-stringifiable-value') , length = require('./get-stripped-length') , sgr = require('./lib/sgr') , max = Math.max; var Token = function Token(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; }; var sliceSeq = function (seq, begin, end) { var sliced = seq.reduce(function (state, chunk) { var index = state.index; if (!(chunk instanceof Token)) { 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; } else { 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); } } } 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(''); };