You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.js 1.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. import stripAnsi from 'strip-ansi';
  2. import eastAsianWidth from 'eastasianwidth';
  3. import emojiRegex from 'emoji-regex';
  4. export default function stringWidth(string, options = {}) {
  5. if (typeof string !== 'string' || string.length === 0) {
  6. return 0;
  7. }
  8. options = {
  9. ambiguousIsNarrow: true,
  10. ...options
  11. };
  12. string = stripAnsi(string);
  13. if (string.length === 0) {
  14. return 0;
  15. }
  16. string = string.replace(emojiRegex(), ' ');
  17. const ambiguousCharacterWidth = options.ambiguousIsNarrow ? 1 : 2;
  18. let width = 0;
  19. for (const character of string) {
  20. const codePoint = character.codePointAt(0);
  21. // Ignore control characters
  22. if (codePoint <= 0x1F || (codePoint >= 0x7F && codePoint <= 0x9F)) {
  23. continue;
  24. }
  25. // Ignore combining characters
  26. if (codePoint >= 0x300 && codePoint <= 0x36F) {
  27. continue;
  28. }
  29. const code = eastAsianWidth.eastAsianWidth(character);
  30. switch (code) {
  31. case 'F':
  32. case 'W':
  33. width += 2;
  34. break;
  35. case 'A':
  36. width += ambiguousCharacterWidth;
  37. break;
  38. default:
  39. width += 1;
  40. }
  41. }
  42. return width;
  43. }