Skip to content

Commit

Permalink
Add truncationCharacter option (#19)
Browse files Browse the repository at this point in the history
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
  • Loading branch information
codemaster138 and sindresorhus committed Oct 9, 2021
1 parent 42f602d commit 23b40dc
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 16 deletions.
20 changes: 20 additions & 0 deletions index.d.ts
Expand Up @@ -50,6 +50,26 @@ export interface Options {
````
*/
readonly preferTruncationOnSpace?: boolean;

/**
The character to use at the breaking point.
@default '…'
@example
```
import cliTruncate from 'cli-truncate';
cliTruncate('unicorns', 5, {position: 'end'});
//=> 'unic…'
cliTruncate('unicorns', 5, {position: 'end', truncationCharacter: '.'});
//=> 'unic.'
cliTruncate('unicorns', 5, {position: 'end', truncationCharacter: ''});
//=> 'unico'
*/
readonly truncationCharacter?: string;
}

/**
Expand Down
29 changes: 13 additions & 16 deletions index.js
Expand Up @@ -23,12 +23,12 @@ export default function cliTruncate(text, columns, options) {
options = {
position: 'end',
preferTruncationOnSpace: false,
truncationCharacter: '…',
...options,
};

const {position, space, preferTruncationOnSpace} = options;
let ellipsis = '…';
let ellipsisWidth = 1;
let {truncationCharacter} = options;

if (typeof text !== 'string') {
throw new TypeError(`Expected \`input\` to be a string, got ${typeof text}`);
Expand All @@ -43,7 +43,7 @@ export default function cliTruncate(text, columns, options) {
}

if (columns === 1) {
return ellipsis;
return truncationCharacter;
}

const length = stringWidth(text);
Expand All @@ -55,50 +55,47 @@ export default function cliTruncate(text, columns, options) {
if (position === 'start') {
if (preferTruncationOnSpace) {
const nearestSpace = getIndexOfNearestSpace(text, length - columns + 1, true);
return ellipsis + sliceAnsi(text, nearestSpace, length).trim();
return truncationCharacter + sliceAnsi(text, nearestSpace, length).trim();
}

if (space === true) {
ellipsis += ' ';
ellipsisWidth = 2;
truncationCharacter += ' ';
}

return ellipsis + sliceAnsi(text, length - columns + ellipsisWidth, length);
return truncationCharacter + sliceAnsi(text, length - columns + stringWidth(truncationCharacter), length);
}

if (position === 'middle') {
if (space === true) {
ellipsis = ` ${ellipsis} `;
ellipsisWidth = 3;
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) + ellipsis + sliceAnsi(text, spaceNearSecondBreakPoint, length).trim();
return sliceAnsi(text, 0, spaceNearFirstBreakPoint) + truncationCharacter + sliceAnsi(text, spaceNearSecondBreakPoint, length).trim();
}

return (
sliceAnsi(text, 0, half)
+ ellipsis
+ sliceAnsi(text, length - (columns - half) + ellipsisWidth, length)
+ 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) + ellipsis;
return sliceAnsi(text, 0, nearestSpace) + truncationCharacter;
}

if (space === true) {
ellipsis = ` ${ellipsis}`;
ellipsisWidth = 2;
truncationCharacter = ` ${truncationCharacter}`;
}

return sliceAnsi(text, 0, columns - ellipsisWidth) + ellipsis;
return sliceAnsi(text, 0, columns - stringWidth(truncationCharacter)) + truncationCharacter;
}

throw new Error(`Expected \`options.position\` to be either \`start\`, \`middle\` or \`end\`, got ${position}`);
Expand Down
20 changes: 20 additions & 0 deletions readme.md
Expand Up @@ -124,6 +124,26 @@ cliTruncate('unicorns rainbow dragons', 6, {position: 'middle', preferTruncation
//=> 'uni…ns'
```

##### truncationCharacter

Type: `string`\
Default: ``

The character to use at the breaking point.

```js
import cliTruncate from 'cli-truncate';

cliTruncate('unicorns', 5, {position: 'end'});
//=> 'unic…'

cliTruncate('unicorns', 5, {position: 'end', truncationCharacter: '.'});
//=> 'unic.'

cliTruncate('unicorns', 5, {position: 'end', truncationCharacter: ''});
//=> 'unico'
```

## Related

- [wrap-ansi](https://github.com/chalk/wrap-ansi) - Wordwrap a string with ANSI escape codes
Expand Down
11 changes: 11 additions & 0 deletions test.js
Expand Up @@ -43,3 +43,14 @@ test('preferTruncationOnSpace option', t => {
t.is(cliTruncate('unicorns rainbow dragons', 6, {position: 'middle', preferTruncationOnSpace: true}), 'uni…ns');
t.is(cliTruncate('unicorns partying with dragons', 20, {position: 'middle', preferTruncationOnSpace: true}), 'unicorns…dragons');
});

test('truncationCharacter option', t => {
t.is(cliTruncate('unicorns', 5, {position: 'end', truncationCharacter: '.'}), 'unic.');
t.is(cliTruncate('unicorns', 5, {position: 'start', truncationCharacter: '.'}), '.orns');
t.is(cliTruncate('unicorns', 5, {position: 'middle', truncationCharacter: '.'}), 'un.ns');
t.is(cliTruncate('unicorns', 5, {position: 'end', truncationCharacter: '.', space: true}), 'uni .');
t.is(cliTruncate('unicorns', 5, {position: 'end', truncationCharacter: ' .'}), 'uni .');
t.is(cliTruncate('unicorns partying with dragons', 20, {position: 'middle', truncationCharacter: '.', preferTruncationOnSpace: true}), 'unicorns.dragons');
t.is(cliTruncate('안녕하세요', 4, {position: 'start', space: true, truncationCharacter: '.'}), '. 요', 'wide char');
t.is(cliTruncate('\u001B[31municornsareawesome\u001B[39m', 10, {position: 'middle', space: true, truncationCharacter: '.'}), '\u001B[31munico\u001B[39m . \u001B[31mme\u001B[39m');
});

0 comments on commit 23b40dc

Please sign in to comment.