blob: 9cb115cc838507784963db6022bcfd86a250eb61 (
plain) (
tree)
|
|
import std/strutils
import std/unicode
import utils/proptable
import utils/charcategory
import utils/map
include res/map/charwidth_gen
# One of the few global variables in the code. Honestly, it should not exist.
var isCJKAmbiguous = false
proc set_cjk_ambiguous*(b: bool) =
isCJKAmbiguous = b
# Warning: this shouldn't be called without normalization.
func width*(r: Rune): int =
let u = uint32(r)
if u <= 0xFFFF: # fast path for BMP
if u in CombiningTable:
return 0
if u in DoubleWidthTable:
return 2
{.cast(noSideEffect).}:
if isCJKAmbiguous and DoubleWidthAmbiguousRanges.isInRange(u):
return 2
else:
if Combining.isInRange(u):
return 0
if DoubleWidthRanges.isInRange(u):
return 2
{.cast(noSideEffect).}:
if isCJKAmbiguous and DoubleWidthAmbiguousRanges.isInRange(u):
return 2
return 1
# 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()
return ((w div 8) + 1) * 8 - w
func width*(s: string): int =
for r in s.runes():
result += r.twidth(result)
func width*(s: string, start, len: int): int =
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)
func notwidth*(s: string): int =
for r in s.runes:
result += r.width()
func twidth*(s: string, w: int): int =
var i = w
for r in s.runes():
i += r.twidth(w)
return i - w
func padToWidth*(str: string, size: int, schar = '$'): string =
if str.width() < size:
return str & ' '.repeat(size - str.width())
else:
let size = size - 1
result = newStringOfCap(str.len)
var w = 0
var i = 0
while i < str.len:
var r: Rune
fastRuneAt(str, i, r)
if w + r.width <= size:
result &= r
w += r.width
result &= schar
func isDigitAscii(r: Rune): bool =
return uint32(r) < 128 and char(r) in AsciiDigit
type BreakCategory* = enum
BREAK_ALPHA, BREAK_SPACE, BREAK_SYMBOL
func breaksWord*(r: Rune): bool =
return not (r.isDigitAscii() or r.width() == 0 or r.isAlpha())
func breaksViWordCat*(r: Rune): BreakCategory =
if r.isWhiteSpace():
return BREAK_SPACE
elif r.breaksWord():
return BREAK_SYMBOL
return BREAK_ALPHA
func breaksWordCat*(r: Rune): BreakCategory =
if not r.breaksWord():
return BREAK_ALPHA
return BREAK_SPACE
func breaksBigWordCat*(r: Rune): BreakCategory =
if not r.isWhiteSpace():
return BREAK_ALPHA
return BREAK_SPACE
|