123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354 |
- import stripAnsi from 'strip-ansi';
- import eastAsianWidth from 'eastasianwidth';
- import emojiRegex from 'emoji-regex';
-
- export default function stringWidth(string, options = {}) {
- if (typeof string !== 'string' || string.length === 0) {
- return 0;
- }
-
- options = {
- ambiguousIsNarrow: true,
- ...options
- };
-
- string = stripAnsi(string);
-
- if (string.length === 0) {
- return 0;
- }
-
- string = string.replace(emojiRegex(), ' ');
-
- const ambiguousCharacterWidth = options.ambiguousIsNarrow ? 1 : 2;
- let width = 0;
-
- for (const character of string) {
- const codePoint = character.codePointAt(0);
-
- // Ignore control characters
- if (codePoint <= 0x1F || (codePoint >= 0x7F && codePoint <= 0x9F)) {
- continue;
- }
-
- // Ignore combining characters
- if (codePoint >= 0x300 && codePoint <= 0x36F) {
- continue;
- }
-
- const code = eastAsianWidth.eastAsianWidth(character);
- switch (code) {
- case 'F':
- case 'W':
- width += 2;
- break;
- case 'A':
- width += ambiguousCharacterWidth;
- break;
- default:
- width += 1;
- }
- }
-
- return width;
- }
|