about summary refs log tree commit diff stats
path: root/src/utils/strwidth.nim
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/strwidth.nim')
-rw-r--r--src/utils/strwidth.nim82
1 files changed, 28 insertions, 54 deletions
diff --git a/src/utils/strwidth.nim b/src/utils/strwidth.nim
index 8c367991..4ce9aa12 100644
--- a/src/utils/strwidth.nim
+++ b/src/utils/strwidth.nim
@@ -1,7 +1,6 @@
-import std/unicode
-
-import utils/proptable
 import utils/map
+import utils/proptable
+import utils/twtuni
 
 include res/map/charwidth_gen
 
@@ -9,8 +8,7 @@ include res/map/charwidth_gen
 var isCJKAmbiguous* = false
 
 # Warning: this shouldn't be called without normalization.
-func width*(r: Rune): int =
-  let u = uint32(r)
+func width*(u: uint32): int =
   if u <= 0xFFFF: # fast path for BMP
     if u in CombiningTable:
       return 0
@@ -31,80 +29,56 @@ func width*(r: Rune): int =
 
 # Width, but also works with tabs.
 # Needs the column width of the text so far.
-func twidth*(r: Rune; w: int): int =
-  if r != Rune('\t'):
-    return r.width()
+func twidth*(u: uint32; w: int): int =
+  if u != uint32('\t'):
+    return u.width()
   return ((w div 8) + 1) * 8 - w
 
-func width*(s: string): int =
-  result = 0
-  for r in s.runes:
-    result += r.twidth(result)
+func width*(s: openArray[char]): int =
+  var w = 0
+  for u in s.points:
+    w += u.twidth(w)
+  return w
 
 func width*(s: string; start, len: int): int =
-  result = 0
+  var w = 0
   var i = start
   var m = len
   if m > s.len:
     m = s.len
   while i < m:
-    var r: Rune
-    fastRuneAt(s, i, r)
-    result += r.twidth(result)
-
-when NimMajor < 2:
-  template ones(n: untyped): untyped = ((1 shl n)-1)
-  template fastRuneAt(s: openArray[char]; i: int; result: untyped) =
-    result = Rune(0xFFFD)
-    if uint32(s[i]) <= 127:
-      result = Rune(uint32(s[i]))
-    elif uint32(s[i]) shr 5 == 0b110:
-      if i <= s.len - 2:
-        result = Rune((uint32(s[i]) and (ones(5))) shl 6 or
-          (uint32(s[i+1]) and ones(6)))
-        i += 1
-    elif uint32(s[i]) shr 4 == 0b1110:
-      if i <= s.len - 3:
-        result = Rune((uint32(s[i]) and ones(4)) shl 12 or
-          (uint32(s[i+1]) and ones(6)) shl 6 or (uint32(s[i+2]) and ones(6)))
-        i += 2
-    elif uint32(s[i]) shr 3 == 0b11110:
-      if i <= s.len - 4:
-        result = Rune((uint32(s[i]) and ones(3)) shl 18 or
-          (uint32(s[i+1]) and ones(6)) shl 12 or
-          (uint32(s[i+2]) and ones(6)) shl 6 or
-          (uint32(s[i+3]) and ones(6)))
-        i += 3
-    inc i
+    let u = s.nextUTF8(i)
+    w += u.twidth(w)
+  return w
 
 func notwidth*(s: openArray[char]): int =
-  result = 0
-  var i = 0
-  while i < s.len:
-    var r: Rune
-    fastRuneAt(s, i, r)
-    result += r.width()
+  var w = 0
+  for u in s.points:
+    w += u.width()
+  return w
 
 func twidth*(s: string; w: int): int =
   var i = w
-  for r in s.runes:
-    i += r.twidth(w)
+  for u in s.points:
+    i += u.twidth(w)
   return i - w
 
 func padToWidth*(s: string; size: int; schar = '$'): string =
   result = newStringOfCap(s.len)
   var w = 0
-  var r: Rune
   var i = 0
+  var pi = 0
   while i < s.len:
-    fastRuneAt(s, i, r)
-    w += r.width()
+    pi = i
+    w += s.nextUTF8(i).width()
     if w > size - 1:
       break
-    result &= r
+    for j in pi ..< i:
+      result &= s[j]
   if w > size - 1:
     if w == size and i == s.len:
-      result &= r
+      for j in pi ..< i:
+        result &= s[j]
     else:
       result &= schar
   while w < size: