123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- import sliceAnsi from 'slice-ansi';
- import stringWidth from 'string-width';
-
- function getIndexOfNearestSpace(string, wantedIndex, shouldSearchRight) {
- if (string.charAt(wantedIndex) === ' ') {
- return wantedIndex;
- }
-
- for (let index = 1; index <= 3; index++) {
- if (shouldSearchRight) {
- if (string.charAt(wantedIndex + index) === ' ') {
- return wantedIndex + index;
- }
- } else if (string.charAt(wantedIndex - index) === ' ') {
- return wantedIndex - index;
- }
- }
-
- return wantedIndex;
- }
-
- export default function cliTruncate(text, columns, options) {
- options = {
- position: 'end',
- preferTruncationOnSpace: false,
- truncationCharacter: '…',
- ...options,
- };
-
- const {position, space, preferTruncationOnSpace} = options;
- let {truncationCharacter} = options;
-
- if (typeof text !== 'string') {
- throw new TypeError(`Expected \`input\` to be a string, got ${typeof text}`);
- }
-
- if (typeof columns !== 'number') {
- throw new TypeError(`Expected \`columns\` to be a number, got ${typeof columns}`);
- }
-
- if (columns < 1) {
- return '';
- }
-
- if (columns === 1) {
- return truncationCharacter;
- }
-
- const length = stringWidth(text);
-
- if (length <= columns) {
- return text;
- }
-
- if (position === 'start') {
- if (preferTruncationOnSpace) {
- const nearestSpace = getIndexOfNearestSpace(text, length - columns + 1, true);
- return truncationCharacter + sliceAnsi(text, nearestSpace, length).trim();
- }
-
- if (space === true) {
- truncationCharacter += ' ';
- }
-
- return truncationCharacter + sliceAnsi(text, length - columns + stringWidth(truncationCharacter), length);
- }
-
- if (position === 'middle') {
- if (space === true) {
- truncationCharacter = ` ${truncationCharacter} `;
- }
-
- const half = Math.floor(columns / 2);
-
- if (preferTruncationOnSpace) {
- const spaceNearFirstBreakPoint = getIndexOfNearestSpace(text, half);
- const spaceNearSecondBreakPoint = getIndexOfNearestSpace(text, length - (columns - half) + 1, true);
- return sliceAnsi(text, 0, spaceNearFirstBreakPoint) + truncationCharacter + sliceAnsi(text, spaceNearSecondBreakPoint, length).trim();
- }
-
- return (
- sliceAnsi(text, 0, half)
- + truncationCharacter
- + sliceAnsi(text, length - (columns - half) + stringWidth(truncationCharacter), length)
- );
- }
-
- if (position === 'end') {
- if (preferTruncationOnSpace) {
- const nearestSpace = getIndexOfNearestSpace(text, columns - 1);
- return sliceAnsi(text, 0, nearestSpace) + truncationCharacter;
- }
-
- if (space === true) {
- truncationCharacter = ` ${truncationCharacter}`;
- }
-
- return sliceAnsi(text, 0, columns - stringWidth(truncationCharacter)) + truncationCharacter;
- }
-
- throw new Error(`Expected \`options.position\` to be either \`start\`, \`middle\` or \`end\`, got ${position}`);
- }
|