runewidth_posix.go (1968B)
1 //go:build !windows && !js && !appengine 2 // +build !windows,!js,!appengine 3 4 package runewidth 5 6 import ( 7 "os" 8 "strings" 9 ) 10 11 func mblen(charset string) int { 12 switch charset { 13 case "utf-8", "utf8": 14 return 6 15 case "jis": 16 return 8 17 case "eucjp": 18 return 3 19 case "euckr", "euccn", "sjis", "cp932", "cp51932", "cp936", "cp949", "cp950", "big5", "gbk", "gb2312": 20 return 2 21 } 22 return 1 23 } 24 25 // localeCharset extracts the charset part of a locale name of the form 26 // "ll.CHARSET" or "ll_CC.CHARSET" (two- or three-letter language code, 27 // optional uppercase country code). It returns "" if locale does not have 28 // that shape. 29 func localeCharset(locale string) string { 30 n := 0 31 for n < len(locale) && locale[n] >= 'a' && locale[n] <= 'z' { 32 n++ 33 } 34 if n < 2 || n > 3 { 35 return "" 36 } 37 rest := locale[n:] 38 if len(rest) >= 3 && rest[0] == '_' && 39 rest[1] >= 'A' && rest[1] <= 'Z' && rest[2] >= 'A' && rest[2] <= 'Z' { 40 rest = rest[3:] 41 } 42 if len(rest) >= 2 && rest[0] == '.' { 43 return rest[1:] 44 } 45 return "" 46 } 47 48 func isEastAsian(locale string) bool { 49 charset := strings.ToLower(locale) 50 if cs := localeCharset(locale); cs != "" { 51 charset = strings.ToLower(cs) 52 } 53 54 if strings.HasSuffix(charset, "@cjk_narrow") { 55 return false 56 } 57 58 for pos, b := range []byte(charset) { 59 if b == '@' { 60 charset = charset[:pos] 61 break 62 } 63 } 64 max := mblen(charset) 65 if max > 1 && (charset[0] != 'u' || 66 strings.HasPrefix(locale, "ja") || 67 strings.HasPrefix(locale, "ko") || 68 strings.HasPrefix(locale, "zh")) { 69 return true 70 } 71 return false 72 } 73 74 // IsEastAsian return true if the current locale is CJK 75 func IsEastAsian() bool { 76 locale := os.Getenv("LC_ALL") 77 if locale == "" { 78 locale = os.Getenv("LC_CTYPE") 79 } 80 if locale == "" { 81 locale = os.Getenv("LANG") 82 } 83 84 // ignore C locale 85 if locale == "POSIX" || locale == "C" { 86 return false 87 } 88 if len(locale) > 1 && locale[0] == 'C' && (locale[1] == '.' || locale[1] == '-') { 89 return false 90 } 91 92 return isEastAsian(locale) 93 }