All files / libs/tty cliTextSize.js

100% Statements 26/26
100% Branches 20/20
100% Functions 6/6
100% Lines 22/22
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78                2x 2x 2x         2x 2x 2x     6x                                   2x 428x 428x 3204x           3204x   5x       3199x       3198x   3195x   9575x   14x       3181x       12781x 1268972x 870128x        
/**
 * @module      libs/tty/cliTextSize
 * @createdAt   2016-07-17
 *
 * @copyright   Copyright (c) 2016 Zhonglei Qiu
 * @license     Licensed under the MIT license.
 */
 
var punycode = require('punycode')
var stripAnsi = require('./stripAnsi')
var isWin = require('../sys/isWin')
 
// Window 对不支持的字符都使用了默认的占一个位置的字符替代
// 中国的 window 用户大多是 cp936 编码 (但是最近听说 window 也将支持 Linux 的 shell)
/* eslint-disable */
var sizeRangesMap = {"0":[[0,7],[11,31],[768,879],[1155,1161],[1425,1469],[1471],[1473,1474],[1476,1477],[1479],[1552,1562],[1611,1631],[1648],[1750,1756],[1759,1764],[1767,1768],[1770,1773],[1809],[1840,1866],[1958,1968],[2027,2035],[2070,2073],[2075,2083],[2085,2087],[2089,2093],[2137,2139],[2304,2307],[2362,2364],[2366,2383],[2385,2391],[2402,2403],[2433,2435],[2492],[2494,2500],[2503,2504],[2507,2509],[2519],[2530,2531],[2561,2563],[2620],[2622,2626],[2631,2632],[2635,2637],[2641],[2672,2673],[2677],[2689,2691],[2748],[2750,2757],[2759,2761],[2763,2765],[2786,2787],[2817,2819],[2876],[2878,2884],[2887,2888],[2891,2893],[2902,2903],[2914,2915],[2946],[3006,3010],[3014,3016],[3018,3021],[3031],[3073,3075],[3134,3140],[3142,3144],[3146,3149],[3157,3158],[3170,3171],[3202,3203],[3260],[3262,3268],[3270,3272],[3274,3277],[3285,3286],[3298,3299],[3330,3331],[3390,3396],[3398,3400],[3402,3405],[3415],[3426,3427],[3458,3459],[3530],[3535,3540],[3542],[3544,3551],[3570,3571],[3633],[3636,3642],[3655,3662],[3761],[3764,3769],[3771,3772],[3784,3789],[3864,3865],[3893],[3895],[3897],[3902,3903],[3953,3972],[3974,3975],[3981,3991],[3993,4028],[4038],[4139,4158],[4182,4185],[4190,4192],[4194,4196],[4199,4205],[4209,4212],[4226,4237],[4239],[4250,4253],[4957,4959],[5906,5908],[5938,5940],[5970,5971],[6002,6003],[6070,6099],[6109],[6155,6157],[6313],[6432,6443],[6448,6459],[6576,6592],[6600,6601],[6679,6683],[6741,6750],[6752,6780],[6783],[6912,6916],[6964,6980],[7019,7027],[7040,7042],[7073,7082],[7142,7155],[7204,7223],[7376,7378],[7380,7400],[7405],[7410],[7616,7654],[7676,7679],[8203,8205],[8400,8432],[11503,11505],[11647],[11744,11775],[12330,12335],[12441,12442],[42607,42610],[42620,42621],[42736,42737],[43010],[43014],[43019],[43043,43047],[43136,43137],[43188,43204],[43232,43249],[43302,43309],[43335,43347],[43392,43395],[43443,43456],[43561,43574],[43587],[43596,43597],[43643],[43696],[43698,43700],[43703,43704],[43710,43711],[43713],[44003,44010],[44012,44013],[64286],[65024,65039],[65056,65062],[65279]],"2":[[4352,4447],[4515,4519],[4602,4607],[9001,9002],[11904,11929],[11931,12019],[12032,12245],[12272,12283],[12288,12329],[12336,12350],[12353,12438],[12443,12543],[12549,12589],[12593,12686],[12688,12730],[12736,12771],[12784,12830],[12832,12871],[12880,13054],[13056,19903],[19968,42124],[42128,42182],[43360,43388],[44032,55203],[55216,55238],[55243,55291],[63744,64255],[65040,65049],[65072,65106],[65108,65126],[65128,65131],[65281,65376],[65504,65510],[110592,110593],[119134,119135],[119227,119228],[127488,127490],[127504,127546],[127552,127560],[127568,127569],[131072,196605],[196608,262141]],"3":[[119136,119140],[119229,119232]]}
var ambRanges = [[161],[164],[167,168],[170],[173,174],[176,180],[182,186],[188,191],[198],[208],[215,216],[222,225],[230],[232,234],[236,237],[240],[242,243],[247,250],[252],[254],[257],[273],[275],[283],[294,295],[299],[305,307],[312],[319,322],[324],[328,331],[333],[338,339],[358,359],[363],[462],[464],[466],[468],[470],[472],[474],[476],[593],[609],[708],[711],[713,715],[717],[720],[728,731],[733],[735],[903],[913,929],[931,937],[945,961],[963,969],[1025],[1040,1103],[1105],[8126],[8189],[8208],[8211,8214],[8216,8217],[8220,8221],[8224,8226],[8228,8231],[8240],[8242,8243],[8245],[8251],[8254],[8308],[8319],[8321,8324],[8364],[8451],[8453],[8457],[8467],[8470],[8481,8482],[8486],[8531,8532],[8539,8542],[8544,8555],[8560,8569],[8585],[8592,8601],[8632,8633],[8658],[8660],[8679],[8704],[8706,8707],[8711,8712],[8715],[8719],[8721],[8725],[8730],[8733,8736],[8739],[8741],[8743,8748],[8750],[8756,8759],[8764,8765],[8776],[8780],[8786],[8800,8801],[8804,8807],[8810,8811],[8814,8815],[8834,8835],[8838,8839],[8853],[8857],[8869],[8895],[8978],[9312,9449],[9451,9547],[9552,9587],[9600,9615],[9618,9621],[9632,9633],[9635,9641],[9650,9651],[9654,9655],[9660,9661],[9664,9665],[9670,9672],[9675],[9678,9681],[9698,9701],[9711],[9733,9734],[9737],[9742,9743],[9748,9749],[9756],[9758],[9792],[9794],[9824,9825],[9827,9829],[9831,9834],[9836,9837],[9839],[9886,9887],[9918,9919],[9924,9933],[9935,9953],[9955],[9960,9983],[10045],[10071],[10102,10111],[11093,11097],[12872,12879],[55296,61439],[61444,63743],[65533],[127232,127242],[127248,127277],[127280,127337],[127344,127386],[917760,917999],[983040,1048573],[1048576,1114109]]
var cp936Ranges = [[0,127],[164],[167,168],[176,177],[183],[215],[224,225],[232,234],[236,237],[242,243],[247],[249,250],[252],[257],[275],[283],[299],[324],[328],[333],[363],[462],[464],[466],[468],[470],[472],[474],[476],[593],[609],[711],[713,715],[729],[913,929],[931,937],[945,961],[963,969],[1025],[1040,1103],[1105],[8208],[8211,8214],[8216,8217],[8220,8221],[8229,8230],[8240],[8242,8243],[8245],[8251],[8364],[8451],[8453],[8457],[8470],[8481],[8544,8555],[8560,8569],[8592,8595],[8598,8601],[8712],[8719],[8721],[8725],[8730],[8733,8736],[8739],[8741],[8743,8747],[8750],[8756,8759],[8765],[8776],[8780],[8786],[8800,8801],[8804,8807],[8814,8815],[8853],[8857],[8869],[8895],[8978],[9312,9321],[9332,9371],[9472,9547],[9552,9587],[9601,9615],[9619,9621],[9632,9633],[9650,9651],[9660,9661],[9670,9671],[9675],[9678,9679],[9698,9701],[9733,9734],[9737],[9792],[9794],[12288,12291],[12293,12311],[12317,12318],[12321,12329],[12353,12435],[12443,12446],[12449,12534],[12540,12542],[12549,12585],[12832,12841],[12849],[12963],[13198,13199],[13212,13214],[13217],[13252],[13262],[13265,13266],[13269],[19968,40869],[63788],[63865],[63893],[63975],[63985],[64012,64015],[64017],[64019,64020],[64024],[64031,64033],[64035,64036],[64039,64041],[65072,65073],[65075,65092],[65097,65106],[65108,65111],[65113,65126],[65128,65131],[65281,65374],[65504,65509]]
/* eslint-enable */
 
var sizes = Object.keys(sizeRangesMap).map(function(s) { return parseInt(s, 10) })
 
/**
 * 计算 Unicode 字符串在终端上的长度
 *
 * @param  {String} str 将会显示在终端上的字符串
 * @return {Number}
 *
 * @example
 * cliTextSize('中国')  // => 4
 * cliTextSize('ab')    // => 2
 *
 * @see    [tty-text-size@1.0.0]{@link https://github.com/qiu8310/tty-text-size/tree/1.0.0}
 * @throws {Error} 当包含 \t, \r, \v, \f, \n 这些无法计算长度的字符时
 *
 * @since 2.0.0
 * @author Zhonglei Qiu
 */
module.exports = function(str) {
  str = stripAnsi(str)
  return punycode.ucs2.decode(str).reduce(function(size, cp) {
    return size + getCodePointCliSize(cp)
  }, 0)
}
 
function getCodePointCliSize(cp) {
  // 特殊字符无法知道它的 size
  if ([9, 10, 11, 12, 13].indexOf(cp) >= 0) {
    // throw new Error('Code point ' + cp + ' not allowed, its size is not predictable.')
    return cp === 9 ? 6 : 0  // tab 在 Mac 的 iTerm 上占了 6 个字符
  }
 
  // window 对不支持的字符都使用了默认的占一个位置的字符替代
  if (isWin && !inRanges(cp, cp936Ranges)) return 1
 
  // Linux 很多终端此值都是 1,但用户可以修改,但程序不好获取用户修改的值
  // 所以取默认值
  if (inRanges(cp, ambRanges)) return isWin ? 2 : 1
 
  for (var i = 0; i < sizes.length; i++) {
    // console.log(cp, sizeRangesMap[sizes[i]], inRanges(cp, sizeRangesMap[sizes[i]]))
    if (inRanges(cp, sizeRangesMap[sizes[i]])) {
      // window 不会超过 2 个字符
      return isWin ? Math.min(2, sizes[i]) : sizes[i]
    }
  }
 
  return 1
}
 
function inRanges(cp, ranges) {
  return ranges.some(function(range) {
    if (range.length === 1) return cp === range[0]
    return cp >= range[0] && cp <= range[1]
  })
}