diff --git a/go.mod b/go.mod
index 05dd384a..7dbd3201 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module github.com/kindlyops/vbs
-go 1.21
+go 1.23.0
require (
github.com/aws/aws-sdk-go v1.44.280
@@ -13,9 +13,9 @@ require (
require (
github.com/Microsoft/go-winio v0.6.2
- github.com/charmbracelet/bubbles v0.16.1
- github.com/charmbracelet/bubbletea v0.24.2
- github.com/charmbracelet/lipgloss v0.8.0
+ github.com/charmbracelet/bubbles v0.21.0
+ github.com/charmbracelet/bubbletea v1.3.4
+ github.com/charmbracelet/lipgloss v1.1.0
github.com/labstack/echo/v5 v5.0.0-20220201181537-ed2888cfa198
github.com/muesli/coral v1.0.0
github.com/pocketbase/pocketbase v0.16.5
@@ -44,11 +44,16 @@ require (
github.com/aws/aws-sdk-go-v2/service/sts v1.19.0 // indirect
github.com/aws/smithy-go v1.13.5 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
+ github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
github.com/charmbracelet/harmonica v0.2.0 // indirect
+ github.com/charmbracelet/x/ansi v0.8.0 // indirect
+ github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
+ github.com/charmbracelet/x/term v0.2.1 // indirect
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
github.com/disintegration/imaging v1.6.2 // indirect
github.com/domodwyer/mailyak/v3 v3.6.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
+ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
@@ -68,18 +73,18 @@ require (
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
- github.com/mattn/go-runewidth v0.0.14 // indirect
+ github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mattn/go-sqlite3 v1.14.17 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
- github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect
+ github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect
- github.com/muesli/termenv v0.15.2 // indirect
+ github.com/muesli/termenv v0.16.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pocketbase/dbx v1.10.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
- github.com/rivo/uniseg v0.2.0 // indirect
+ github.com/rivo/uniseg v0.4.7 // indirect
github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/cobra v1.7.0 // indirect
@@ -88,6 +93,7 @@ require (
github.com/subosito/gotenv v1.4.2 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
+ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
go.opencensus.io v0.24.0 // indirect
gocloud.dev v0.29.0 // indirect
golang.org/x/crypto v0.11.0 // indirect
@@ -95,8 +101,8 @@ require (
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/oauth2 v0.8.0 // indirect
- golang.org/x/sync v0.3.0 // indirect
- golang.org/x/sys v0.10.0 // indirect
+ golang.org/x/sync v0.11.0 // indirect
+ golang.org/x/sys v0.30.0 // indirect
golang.org/x/term v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/time v0.3.0 // indirect
diff --git a/go.sum b/go.sum
index d9b73bbe..793e759e 100644
--- a/go.sum
+++ b/go.sum
@@ -652,14 +652,28 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charmbracelet/bubbles v0.16.1 h1:6uzpAAaT9ZqKssntbvZMlksWHruQLNxg49H5WdeuYSY=
github.com/charmbracelet/bubbles v0.16.1/go.mod h1:2QCp9LFlEsBQMvIYERr7Ww2H2bA7xen1idUDIzm/+Xc=
+github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
+github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
github.com/charmbracelet/bubbletea v0.24.2 h1:uaQIKx9Ai6Gdh5zpTbGiWpytMU+CfsPp06RaW2cx/SY=
github.com/charmbracelet/bubbletea v0.24.2/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg=
+github.com/charmbracelet/bubbletea v1.3.4 h1:kCg7B+jSCFPLYRA52SDZjr51kG/fMUEoPoZrkaDHyoI=
+github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo=
+github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
+github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E=
github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c=
github.com/charmbracelet/lipgloss v0.8.0 h1:IS00fk4XAHcf8uZKc3eHeMUTCxUH6NkaTrdyCQk84RU=
github.com/charmbracelet/lipgloss v0.8.0/go.mod h1:p4eYUZZJ/0oXTuCQKFF8mqyKCz0ja6y+7DniDDw5KKU=
+github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
+github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
+github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
+github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
+github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
+github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
+github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
+github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
@@ -895,6 +909,8 @@ github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJ
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=
+github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
+github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@@ -1485,6 +1501,8 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
+github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
@@ -1551,6 +1569,8 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34=
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
+github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
+github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/coral v1.0.0 h1:odyqkoEg4aJAINOzvnjN4tUsdp+Zleccs7tRIAkkYzU=
@@ -1561,6 +1581,8 @@ github.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs
github.com/muesli/termenv v0.15.1/go.mod h1:HeAQPTzpfs016yGtA4g00CsdYnVLJvxsS4ANqrZs2sQ=
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
+github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
+github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -1747,6 +1769,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@@ -1906,6 +1930,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:
github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
+github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
+github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -2274,6 +2300,8 @@ golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
+golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -2430,6 +2458,8 @@ golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
+golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
diff --git a/vendor/github.com/charmbracelet/bubbles/help/help.go b/vendor/github.com/charmbracelet/bubbles/help/help.go
index 8e5f77f1..bb402a6c 100644
--- a/vendor/github.com/charmbracelet/bubbles/help/help.go
+++ b/vendor/github.com/charmbracelet/bubbles/help/help.go
@@ -1,3 +1,4 @@
+// Package help provides a simple help view for Bubble Tea applications.
package help
import (
@@ -15,7 +16,6 @@ import (
// Note that if a key is disabled (via key.Binding.SetEnabled) it will not be
// rendered in the help view, so in theory generated help should self-manage.
type KeyMap interface {
-
// ShortHelp returns a slice of bindings to be displayed in the short
// version of the help. The help bubble will render help in the order in
// which the help items are returned here.
@@ -82,10 +82,10 @@ func New() Model {
ShortKey: keyStyle,
ShortDesc: descStyle,
ShortSeparator: sepStyle,
- Ellipsis: sepStyle.Copy(),
- FullKey: keyStyle.Copy(),
- FullDesc: descStyle.Copy(),
- FullSeparator: sepStyle.Copy(),
+ Ellipsis: sepStyle,
+ FullKey: keyStyle,
+ FullDesc: descStyle,
+ FullSeparator: sepStyle,
},
}
}
@@ -118,35 +118,30 @@ func (m Model) ShortHelpView(bindings []key.Binding) string {
var b strings.Builder
var totalWidth int
- var separator = m.Styles.ShortSeparator.Inline(true).Render(m.ShortSeparator)
+ separator := m.Styles.ShortSeparator.Inline(true).Render(m.ShortSeparator)
for i, kb := range bindings {
if !kb.Enabled() {
continue
}
+ // Sep
var sep string
if totalWidth > 0 && i < len(bindings) {
sep = separator
}
+ // Item
str := sep +
m.Styles.ShortKey.Inline(true).Render(kb.Help().Key) + " " +
m.Styles.ShortDesc.Inline(true).Render(kb.Help().Desc)
-
w := lipgloss.Width(str)
- // If adding this help item would go over the available width, stop
- // drawing.
- if m.Width > 0 && totalWidth+w > m.Width {
- // Although if there's room for an ellipsis, print that.
- tail := " " + m.Styles.Ellipsis.Inline(true).Render(m.Ellipsis)
- tailWidth := lipgloss.Width(tail)
-
- if totalWidth+tailWidth < m.Width {
+ // Tail
+ if tail, ok := m.shouldAddItem(totalWidth, w); !ok {
+ if tail != "" {
b.WriteString(tail)
}
-
break
}
@@ -171,8 +166,7 @@ func (m Model) FullHelpView(groups [][]key.Binding) string {
out []string
totalWidth int
- sep = m.Styles.FullSeparator.Render(m.FullSeparator)
- sepWidth = lipgloss.Width(sep)
+ separator = m.Styles.FullSeparator.Inline(true).Render(m.FullSeparator)
)
// Iterate over groups to build columns
@@ -180,12 +174,17 @@ func (m Model) FullHelpView(groups [][]key.Binding) string {
if group == nil || !shouldRenderColumn(group) {
continue
}
-
var (
+ sep string
keys []string
descriptions []string
)
+ // Sep
+ if totalWidth > 0 && i < len(groups) {
+ sep = separator
+ }
+
// Separate keys and descriptions into different slices
for _, kb := range group {
if !kb.Enabled() {
@@ -195,34 +194,42 @@ func (m Model) FullHelpView(groups [][]key.Binding) string {
descriptions = append(descriptions, kb.Help().Desc)
}
+ // Column
col := lipgloss.JoinHorizontal(lipgloss.Top,
+ sep,
m.Styles.FullKey.Render(strings.Join(keys, "\n")),
- m.Styles.FullKey.Render(" "),
+ " ",
m.Styles.FullDesc.Render(strings.Join(descriptions, "\n")),
)
+ w := lipgloss.Width(col)
- // Column
- totalWidth += lipgloss.Width(col)
- if m.Width > 0 && totalWidth > m.Width {
+ // Tail
+ if tail, ok := m.shouldAddItem(totalWidth, w); !ok {
+ if tail != "" {
+ out = append(out, tail)
+ }
break
}
+ totalWidth += w
out = append(out, col)
-
- // Separator
- if i < len(group)-1 {
- totalWidth += sepWidth
- if m.Width > 0 && totalWidth > m.Width {
- break
- }
- }
-
- out = append(out, sep)
}
return lipgloss.JoinHorizontal(lipgloss.Top, out...)
}
+func (m Model) shouldAddItem(totalWidth, width int) (tail string, ok bool) {
+ // If there's room for an ellipsis, print that.
+ if m.Width > 0 && totalWidth+width > m.Width {
+ tail = " " + m.Styles.Ellipsis.Inline(true).Render(m.Ellipsis)
+
+ if totalWidth+lipgloss.Width(tail) < m.Width {
+ return tail, false
+ }
+ }
+ return "", true
+}
+
func shouldRenderColumn(b []key.Binding) (ok bool) {
for _, v := range b {
if v.Enabled() {
diff --git a/vendor/github.com/charmbracelet/bubbles/key/BUILD.bazel b/vendor/github.com/charmbracelet/bubbles/key/BUILD.bazel
index 48326c84..6248387a 100644
--- a/vendor/github.com/charmbracelet/bubbles/key/BUILD.bazel
+++ b/vendor/github.com/charmbracelet/bubbles/key/BUILD.bazel
@@ -6,5 +6,4 @@ go_library(
importmap = "github.com/kindlyops/vbs/vendor/github.com/charmbracelet/bubbles/key",
importpath = "github.com/charmbracelet/bubbles/key",
visibility = ["//visibility:public"],
- deps = ["//vendor/github.com/charmbracelet/bubbletea:go_default_library"],
)
diff --git a/vendor/github.com/charmbracelet/bubbles/key/key.go b/vendor/github.com/charmbracelet/bubbles/key/key.go
index c7888fa7..0682665d 100644
--- a/vendor/github.com/charmbracelet/bubbles/key/key.go
+++ b/vendor/github.com/charmbracelet/bubbles/key/key.go
@@ -36,9 +36,7 @@
// to render help text for keystrokes in your views.
package key
-import (
- tea "github.com/charmbracelet/bubbletea"
-)
+import "fmt"
// Binding describes a set of keybindings and, optionally, their associated
// help text.
@@ -128,8 +126,8 @@ type Help struct {
Desc string
}
-// Matches checks if the given KeyMsg matches the given bindings.
-func Matches(k tea.KeyMsg, b ...Binding) bool {
+// Matches checks if the given key matches the given bindings.
+func Matches[Key fmt.Stringer](k Key, b ...Binding) bool {
keys := k.String()
for _, binding := range b {
for _, v := range binding.keys {
diff --git a/vendor/github.com/charmbracelet/bubbles/progress/BUILD.bazel b/vendor/github.com/charmbracelet/bubbles/progress/BUILD.bazel
index 8fe134f1..225b1b85 100644
--- a/vendor/github.com/charmbracelet/bubbles/progress/BUILD.bazel
+++ b/vendor/github.com/charmbracelet/bubbles/progress/BUILD.bazel
@@ -10,8 +10,8 @@ go_library(
"//vendor/github.com/charmbracelet/bubbletea:go_default_library",
"//vendor/github.com/charmbracelet/harmonica:go_default_library",
"//vendor/github.com/charmbracelet/lipgloss:go_default_library",
+ "//vendor/github.com/charmbracelet/x/ansi:go_default_library",
"//vendor/github.com/lucasb-eyer/go-colorful:go_default_library",
- "//vendor/github.com/muesli/reflow/ansi:go_default_library",
"//vendor/github.com/muesli/termenv:go_default_library",
],
)
diff --git a/vendor/github.com/charmbracelet/bubbles/progress/progress.go b/vendor/github.com/charmbracelet/bubbles/progress/progress.go
index caeaf10e..82f5eb00 100644
--- a/vendor/github.com/charmbracelet/bubbles/progress/progress.go
+++ b/vendor/github.com/charmbracelet/bubbles/progress/progress.go
@@ -1,33 +1,27 @@
+// Package progress provides a simple progress bar for Bubble Tea applications.
package progress
import (
"fmt"
"math"
"strings"
- "sync"
+ "sync/atomic"
"time"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/harmonica"
"github.com/charmbracelet/lipgloss"
+ "github.com/charmbracelet/x/ansi"
"github.com/lucasb-eyer/go-colorful"
- "github.com/muesli/reflow/ansi"
"github.com/muesli/termenv"
)
// Internal ID management. Used during animating to assure that frame messages
// can only be received by progress components that sent them.
-var (
- lastID int
- idMtx sync.Mutex
-)
+var lastID int64
-// Return the next ID we should use on the model.
func nextID() int {
- idMtx.Lock()
- defer idMtx.Unlock()
- lastID++
- return lastID
+ return int(atomic.AddInt64(&lastID, 1))
}
const (
@@ -79,6 +73,14 @@ func WithSolidFill(color string) Option {
}
}
+// WithFillCharacters sets the characters used to construct the full and empty components of the progress bar.
+func WithFillCharacters(full rune, empty rune) Option {
+ return func(m *Model) {
+ m.Full = full
+ m.Empty = empty
+ }
+}
+
// WithoutPercentage hides the numeric percentage.
func WithoutPercentage() Option {
return func(m *Model) {
@@ -179,13 +181,15 @@ func New(opts ...Option) Model {
PercentFormat: " %3.0f%%",
colorProfile: termenv.ColorProfile(),
}
- if !m.springCustomized {
- m.SetSpringOptions(defaultFrequency, defaultDamping)
- }
for _, opt := range opts {
opt(&m)
}
+
+ if !m.springCustomized {
+ m.SetSpringOptions(defaultFrequency, defaultDamping)
+ }
+
return m
}
@@ -211,8 +215,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
// If we've more or less reached equilibrium, stop updating.
- dist := math.Abs(m.percentShown - m.targetPercent)
- if dist < 0.001 && m.velocity < 0.01 {
+ if !m.IsAnimating() {
return m, nil
}
@@ -276,7 +279,7 @@ func (m Model) View() string {
func (m Model) ViewAs(percent float64) string {
b := strings.Builder{}
percentView := m.percentageView(percent)
- m.barView(&b, percent, ansi.PrintableRuneWidth(percentView))
+ m.barView(&b, percent, ansi.StringWidth(percentView))
b.WriteString(percentView)
return b.String()
}
@@ -302,7 +305,7 @@ func (m Model) barView(b *strings.Builder, percent float64, textWidth int) {
if fw == 1 {
// this is up for debate: in a gradient of width=1, should the
// single character rendered be the first color, the last color
- // or exactly 50% inbetween? I opted for 50%
+ // or exactly 50% in between? I opted for 50%
p = 0.5
} else if m.scaleRamp {
p = float64(i) / float64(fw-1)
@@ -333,7 +336,7 @@ func (m Model) percentageView(percent float64) string {
return ""
}
percent = math.Max(0, math.Min(1, percent))
- percentage := fmt.Sprintf(m.PercentFormat, percent*100) //nolint:gomnd
+ percentage := fmt.Sprintf(m.PercentFormat, percent*100) //nolint:mnd
percentage = m.PercentageStyle.Inline(true).Render(percentage)
return percentage
}
@@ -355,16 +358,8 @@ func (m Model) color(c string) termenv.Color {
return m.colorProfile.Color(c)
}
-func max(a, b int) int {
- if a > b {
- return a
- }
- return b
-}
-
-func min(a, b int) int {
- if a < b {
- return a
- }
- return b
+// IsAnimating returns false if the progress bar reached equilibrium and is no longer animating.
+func (m *Model) IsAnimating() bool {
+ dist := math.Abs(m.percentShown - m.targetPercent)
+ return !(dist < 0.001 && m.velocity < 0.01)
}
diff --git a/vendor/github.com/charmbracelet/bubbles/spinner/spinner.go b/vendor/github.com/charmbracelet/bubbles/spinner/spinner.go
index bb53597f..b2d24b09 100644
--- a/vendor/github.com/charmbracelet/bubbles/spinner/spinner.go
+++ b/vendor/github.com/charmbracelet/bubbles/spinner/spinner.go
@@ -1,7 +1,8 @@
+// Package spinner provides a spinner component for Bubble Tea applications.
package spinner
import (
- "sync"
+ "sync/atomic"
"time"
tea "github.com/charmbracelet/bubbletea"
@@ -10,17 +11,10 @@ import (
// Internal ID management. Used during animating to ensure that frame messages
// are received only by spinner components that sent them.
-var (
- lastID int
- idMtx sync.Mutex
-)
+var lastID int64
-// Return the next ID we should use on the Model.
func nextID() int {
- idMtx.Lock()
- defer idMtx.Unlock()
- lastID++
- return lastID
+ return int(atomic.AddInt64(&lastID, 1))
}
// Spinner is a set of frames used in animating the spinner.
@@ -33,39 +27,39 @@ type Spinner struct {
var (
Line = Spinner{
Frames: []string{"|", "/", "-", "\\"},
- FPS: time.Second / 10, //nolint:gomnd
+ FPS: time.Second / 10, //nolint:mnd
}
Dot = Spinner{
Frames: []string{"⣾ ", "⣽ ", "⣻ ", "⢿ ", "⡿ ", "⣟ ", "⣯ ", "⣷ "},
- FPS: time.Second / 10, //nolint:gomnd
+ FPS: time.Second / 10, //nolint:mnd
}
MiniDot = Spinner{
Frames: []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"},
- FPS: time.Second / 12, //nolint:gomnd
+ FPS: time.Second / 12, //nolint:mnd
}
Jump = Spinner{
Frames: []string{"⢄", "⢂", "⢁", "⡁", "⡈", "⡐", "⡠"},
- FPS: time.Second / 10, //nolint:gomnd
+ FPS: time.Second / 10, //nolint:mnd
}
Pulse = Spinner{
Frames: []string{"█", "▓", "▒", "░"},
- FPS: time.Second / 8, //nolint:gomnd
+ FPS: time.Second / 8, //nolint:mnd
}
Points = Spinner{
Frames: []string{"∙∙∙", "●∙∙", "∙●∙", "∙∙●"},
- FPS: time.Second / 7, //nolint:gomnd
+ FPS: time.Second / 7, //nolint:mnd
}
Globe = Spinner{
Frames: []string{"🌍", "🌎", "🌏"},
- FPS: time.Second / 4, //nolint:gomnd
+ FPS: time.Second / 4, //nolint:mnd
}
Moon = Spinner{
Frames: []string{"🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘"},
- FPS: time.Second / 8, //nolint:gomnd
+ FPS: time.Second / 8, //nolint:mnd
}
Monkey = Spinner{
Frames: []string{"🙈", "🙉", "🙊"},
- FPS: time.Second / 3, //nolint:gomnd
+ FPS: time.Second / 3, //nolint:mnd
}
Meter = Spinner{
Frames: []string{
@@ -77,15 +71,15 @@ var (
"▰▱▱",
"▱▱▱",
},
- FPS: time.Second / 7, //nolint:gomnd
+ FPS: time.Second / 7, //nolint:mnd
}
Hamburger = Spinner{
Frames: []string{"☱", "☲", "☴", "☲"},
- FPS: time.Second / 3, //nolint:gomnd
+ FPS: time.Second / 3, //nolint:mnd
}
Ellipsis = Spinner{
Frames: []string{"", ".", "..", "..."},
- FPS: time.Second / 3, //nolint:gomnd
+ FPS: time.Second / 3, //nolint:mnd
}
)
diff --git a/vendor/github.com/charmbracelet/bubbletea/.gitattributes b/vendor/github.com/charmbracelet/bubbletea/.gitattributes
new file mode 100644
index 00000000..6c929d48
--- /dev/null
+++ b/vendor/github.com/charmbracelet/bubbletea/.gitattributes
@@ -0,0 +1 @@
+*.golden -text
diff --git a/vendor/github.com/charmbracelet/bubbletea/.gitignore b/vendor/github.com/charmbracelet/bubbletea/.gitignore
index 9cc52352..abd7c061 100644
--- a/vendor/github.com/charmbracelet/bubbletea/.gitignore
+++ b/vendor/github.com/charmbracelet/bubbletea/.gitignore
@@ -20,3 +20,4 @@ tutorials/basics/basics
tutorials/commands/commands
.idea
coverage.txt
+dist/
diff --git a/vendor/github.com/charmbracelet/bubbletea/.golangci-soft.yml b/vendor/github.com/charmbracelet/bubbletea/.golangci-soft.yml
index ef456e06..d325d4fc 100644
--- a/vendor/github.com/charmbracelet/bubbletea/.golangci-soft.yml
+++ b/vendor/github.com/charmbracelet/bubbletea/.golangci-soft.yml
@@ -1,5 +1,6 @@
run:
tests: false
+ issues-exit-code: 0
issues:
include:
@@ -14,17 +15,13 @@ issues:
linters:
enable:
- # - dupl
- exhaustive
- # - exhaustivestruct
- goconst
- godot
- godox
- - gomnd
+ - mnd
- gomoddirectives
- goprintffuncname
- - ifshort
- # - lll
- misspell
- nakedret
- nestif
@@ -35,13 +32,9 @@ linters:
# disable default linters, they are already enabled in .golangci.yml
disable:
- - deadcode
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- - structcheck
- - typecheck
- unused
- - varcheck
diff --git a/vendor/github.com/charmbracelet/bubbletea/.golangci.yml b/vendor/github.com/charmbracelet/bubbletea/.golangci.yml
index a5a91d0d..d6789e01 100644
--- a/vendor/github.com/charmbracelet/bubbletea/.golangci.yml
+++ b/vendor/github.com/charmbracelet/bubbletea/.golangci.yml
@@ -15,11 +15,10 @@ issues:
linters:
enable:
- bodyclose
- - exportloopref
+ - gofumpt
- goimports
- gosec
- nilerr
- - predeclared
- revive
- rowserrcheck
- sqlclosecheck
diff --git a/vendor/github.com/charmbracelet/bubbletea/.goreleaser.yml b/vendor/github.com/charmbracelet/bubbletea/.goreleaser.yml
new file mode 100644
index 00000000..3353d020
--- /dev/null
+++ b/vendor/github.com/charmbracelet/bubbletea/.goreleaser.yml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json
+version: 2
+includes:
+ - from_url:
+ url: charmbracelet/meta/main/goreleaser-lib.yaml
diff --git a/vendor/github.com/charmbracelet/bubbletea/BUILD.bazel b/vendor/github.com/charmbracelet/bubbletea/BUILD.bazel
index 03f93bec..ec2e3ceb 100644
--- a/vendor/github.com/charmbracelet/bubbletea/BUILD.bazel
+++ b/vendor/github.com/charmbracelet/bubbletea/BUILD.bazel
@@ -5,7 +5,13 @@ go_library(
srcs = [
"commands.go",
"exec.go",
+ "focus.go",
+ "inputreader_other.go",
+ "inputreader_windows.go",
"key.go",
+ "key_other.go",
+ "key_sequences.go",
+ "key_windows.go",
"logging.go",
"mouse.go",
"nil_renderer.go",
@@ -16,6 +22,7 @@ go_library(
"signals_windows.go",
"standard_renderer.go",
"tea.go",
+ "tea_init.go",
"tty.go",
"tty_unix.go",
"tty_windows.go",
@@ -24,14 +31,18 @@ go_library(
importpath = "github.com/charmbracelet/bubbletea",
visibility = ["//visibility:public"],
deps = [
- "//vendor/github.com/containerd/console:go_default_library",
- "//vendor/github.com/mattn/go-isatty:go_default_library",
- "//vendor/github.com/mattn/go-localereader:go_default_library",
+ "//vendor/github.com/charmbracelet/lipgloss:go_default_library",
+ "//vendor/github.com/charmbracelet/x/ansi:go_default_library",
+ "//vendor/github.com/charmbracelet/x/term:go_default_library",
"//vendor/github.com/muesli/ansi/compressor:go_default_library",
"//vendor/github.com/muesli/cancelreader:go_default_library",
- "//vendor/github.com/muesli/reflow/truncate:go_default_library",
- "//vendor/github.com/muesli/termenv:go_default_library",
"//vendor/golang.org/x/sync/errgroup:go_default_library",
- "//vendor/golang.org/x/term:go_default_library",
- ],
+ ] + select({
+ "@io_bazel_rules_go//go/platform:windows": [
+ "//vendor/github.com/erikgeiser/coninput:go_default_library",
+ "//vendor/github.com/mattn/go-localereader:go_default_library",
+ "//vendor/golang.org/x/sys/windows:go_default_library",
+ ],
+ "//conditions:default": [],
+ }),
)
diff --git a/vendor/github.com/charmbracelet/bubbletea/CONTRIBUTING.md b/vendor/github.com/charmbracelet/bubbletea/CONTRIBUTING.md
deleted file mode 100644
index 19ee18c7..00000000
--- a/vendor/github.com/charmbracelet/bubbletea/CONTRIBUTING.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Contributing
-
-Pull requests are welcome for any changes.
-
-Consider opening an issue for larger changes to get feedback on the idea from the team.
-
-If your change touches parts of the Bubble Tea renderer or internals, make sure
-that all the examples in the `examples/` folder continue to run correctly.
-
-For commit messages, please use conventional commits[^1] to make it easier to
-generate release notes.
-
-[^1]: https://www.conventionalcommits.org/en/v1.0.0
diff --git a/vendor/github.com/charmbracelet/bubbletea/README.md b/vendor/github.com/charmbracelet/bubbletea/README.md
index 0a88caa5..58dd1828 100644
--- a/vendor/github.com/charmbracelet/bubbletea/README.md
+++ b/vendor/github.com/charmbracelet/bubbletea/README.md
@@ -1,10 +1,11 @@
# Bubble Tea
- 
+ 
-
-
+
+
+
The fun, functional and stateful way to build terminal apps. A Go framework
@@ -16,9 +17,8 @@ complex terminal applications, either inline, full-window, or a mix of both.
Bubble Tea is in use in production and includes a number of features and
-performance optimizations we’ve added along the way. Among those is a standard
-framerate-based renderer, a renderer for high-performance scrollable
-regions which works alongside the main renderer, and mouse support.
+performance optimizations we’ve added along the way. Among those is
+a framerate-based renderer, mouse support, focus reporting and more.
To get started, see the tutorial below, the [examples][examples], the
[docs][docs], the [video tutorials][youtube] and some common [resources](#libraries-we-use-with-bubble-tea).
@@ -34,7 +34,7 @@ Be sure to check out [Bubbles][bubbles], a library of common UI components for B
-***
+---
## Tutorial
@@ -48,7 +48,7 @@ By the way, the non-annotated source code for this program is available
[on GitHub][tut-source].
[elm]: https://guide.elm-lang.org/architecture/
-[tut-source]:https://github.com/charmbracelet/bubbletea/tree/master/tutorials/basics
+[tut-source]: https://github.com/charmbracelet/bubbletea/tree/main/tutorials/basics
### Enough! Let's get to it.
@@ -60,6 +60,10 @@ import will be the Bubble Tea library, which we'll call `tea` for short.
```go
package main
+// These imports will be used later on the tutorial. If you save the file
+// now, Go might complain they are unused, but that's fine.
+// You may also need to run `go mod tidy` to download bubbletea and its
+// dependencies.
import (
"fmt"
"os"
@@ -71,9 +75,9 @@ import (
Bubble Tea programs are comprised of a **model** that describes the application
state and three simple methods on that model:
-* **Init**, a function that returns an initial command for the application to run.
-* **Update**, a function that handles incoming events and updates the model accordingly.
-* **View**, a function that renders the UI based on the data in the model.
+- **Init**, a function that returns an initial command for the application to run.
+- **Update**, a function that handles incoming events and updates the model accordingly.
+- **View**, a function that renders the UI based on the data in the model.
### The Model
@@ -253,8 +257,8 @@ look at the [Command Tutorial][cmd]. It's pretty simple.
There are also several [Bubble Tea examples][examples] available and, of course,
there are [Go Docs][docs].
-[cmd]: http://github.com/charmbracelet/bubbletea/tree/master/tutorials/commands/
-[examples]: http://github.com/charmbracelet/bubbletea/tree/master/examples
+[cmd]: https://github.com/charmbracelet/bubbletea/tree/main/tutorials/commands/
+[examples]: https://github.com/charmbracelet/bubbletea/tree/main/examples
[docs]: https://pkg.go.dev/github.com/charmbracelet/bubbletea?tab=doc
## Debugging
@@ -266,15 +270,21 @@ delve in headless mode and then connect to it:
```bash
# Start the debugger
-$ dlv debug --headless .
-API server listening at: 127.0.0.1:34241
+$ dlv debug --headless --api-version=2 --listen=127.0.0.1:43000 .
+API server listening at: 127.0.0.1:43000
# Connect to it from another terminal
-$ dlv connect 127.0.0.1:34241
+$ dlv connect 127.0.0.1:43000
```
-Note that the default port used will vary on your system and per run, so
-actually watch out what address the first `dlv` run tells you to connect to.
+If you do not explicitly supply the `--listen` flag, the port used will vary
+per run, so passing this in makes the debugger easier to use from a script
+or your IDE of choice.
+
+Additionally, we pass in `--api-version=2` because delve defaults to version 1
+for backwards compatibility reasons. However, delve recommends using version 2
+for all new development and some clients may no longer work with version 1.
+For more information, see the [Delve documentation](https://github.com/go-delve/delve/tree/master/Documentation/api).
### Logging Stuff
@@ -298,88 +308,68 @@ your program in another window.
## Libraries we use with Bubble Tea
-* [Bubbles][bubbles]: Common Bubble Tea components such as text inputs, viewports, spinners and so on
-* [Lip Gloss][lipgloss]: Style, format and layout tools for terminal applications
-* [Harmonica][harmonica]: A spring animation library for smooth, natural motion
-* [BubbleZone][bubblezone]: Easy mouse event tracking for Bubble Tea components
-* [Termenv][termenv]: Advanced ANSI styling for terminal applications
-* [Reflow][reflow]: Advanced ANSI-aware methods for working with text
+- [Bubbles][bubbles]: Common Bubble Tea components such as text inputs, viewports, spinners and so on
+- [Lip Gloss][lipgloss]: Style, format and layout tools for terminal applications
+- [Harmonica][harmonica]: A spring animation library for smooth, natural motion
+- [BubbleZone][bubblezone]: Easy mouse event tracking for Bubble Tea components
+- [ntcharts][ntcharts]: A terminal charting library built for Bubble Tea and [Lip Gloss][lipgloss]
[bubbles]: https://github.com/charmbracelet/bubbles
[lipgloss]: https://github.com/charmbracelet/lipgloss
[harmonica]: https://github.com/charmbracelet/harmonica
[bubblezone]: https://github.com/lrstanley/bubblezone
-[termenv]: https://github.com/muesli/termenv
-[reflow]: https://github.com/muesli/reflow
+[ntcharts]: https://github.com/NimbleMarkets/ntcharts
## Bubble Tea in the Wild
-For some Bubble Tea programs in production, see:
-
-* [AT CLI](https://github.com/daskycodes/at_cli): execute AT Commands via serial port connections
-* [Aztify](https://github.com/Azure/aztfy): bring Microsoft Azure resources under Terraform
-* [brows](https://github.com/rubysolo/brows): a GitHub release browser
-* [Canard](https://github.com/mrusme/canard): an RSS client
-* [charm](https://github.com/charmbracelet/charm): the official Charm user account manager
-* [chezmoi](https://github.com/twpayne/chezmoi): securely manage your dotfiles across multiple machines
-* [chtop](https://github.com/chhetripradeep/chtop): monitor your ClickHouse node without leaving terminal
-* [circumflex](https://github.com/bensadeh/circumflex): read Hacker News in the terminal
-* [clidle](https://github.com/ajeetdsouza/clidle): a Wordle clone
-* [cLive](https://github.com/koki-develop/clive): automate terminal operations and view them live in a browser
-* [container-canary](https://github.com/NVIDIA/container-canary): a container validator
-* [countdown](https://github.com/aldernero/countdown): a multi-event countdown timer
-* [dns53](https://github.com/purpleclay/dns53): dynamic DNS with Amazon Route53. Expose your EC2 quickly, securely and privately
-* [eks-node-viewer](https://github.com/awslabs/eks-node-viewer): a tool for visualizing dynamic node usage within an eks cluster
-* [enola](https://github.com/sherlock-project/enola): hunt down social media accounts by username across social networks
-* [flapioca](https://github.com/kbrgl/flapioca): Flappy Bird on the CLI!
-* [fm](https://github.com/knipferrc/fm): a terminal-based file manager
-* [fork-cleaner](https://github.com/caarlos0/fork-cleaner): clean up old and inactive forks in your GitHub account
-* [fztea](https://github.com/jon4hz/fztea): a Flipper Zero TUI
-* [gambit](https://github.com/maaslalani/gambit): chess in the terminal
-* [gembro](https://git.sr.ht/~rafael/gembro): a mouse-driven Gemini browser
-* [gh-b](https://github.com/joaom00/gh-b): a GitHub CLI extension for managing branches
-* [gh-dash](https://www.github.com/dlvhdr/gh-dash): a GitHub CLI extension for PRs and issues
-* [gitflow-toolkit](https://github.com/mritd/gitflow-toolkit): a GitFlow submission tool
-* [Glow](https://github.com/charmbracelet/glow): a markdown reader, browser, and online markdown stash
-* [gocovsh](https://github.com/orlangure/gocovsh): explore Go coverage reports from the CLI
-* [got](https://github.com/fedeztk/got): a simple translator and text-to-speech app build on top of simplytranslate's APIs
-* [httpit](https://github.com/gonetx/httpit): a rapid http(s) benchmark tool
-* [IDNT](https://github.com/r-darwish/idnt): a batch software uninstaller
-* [kboard](https://github.com/CamiloGarciaLaRotta/kboard): a typing game
-* [mandelbrot-cli](https://github.com/MicheleFiladelfia/mandelbrot-cli): a multiplatform terminal mandelbrot set explorer
-* [mc](https://github.com/minio/mc): the official [MinIO](https://min.io) client
-* [mergestat](https://github.com/mergestat/mergestat): run SQL queries on git repositories
-* [Neon Modem Overdrive](https://github.com/mrusme/neonmodem): a BBS-style TUI client for Discourse, Lemmy, Lobste.rs and Hacker News
-* [Noted](https://github.com/torbratsberg/noted): a note viewer and manager
-* [pathos](https://github.com/chip/pathos): a PATH env variable editor
-* [portal](https://github.com/ZinoKader/portal): secure transfers between computers
-* [redis-viewer](https://github.com/SaltFishPr/redis-viewer): a Redis databases browser
-* [sku](https://github.com/fedeztk/sku): Sudoku on the CLI
-* [Slides](https://github.com/maaslalani/slides): a markdown-based presentation tool
-* [SlurmCommander](https://github.com/CLIP-HPC/SlurmCommander): a Slurm workload manager TUI
-* [Soft Serve](https://github.com/charmbracelet/soft-serve): a command-line-first Git server that runs a TUI over SSH
-* [solitaire-tui](https://github.com/brianstrauch/solitaire-tui): Klondike Solitaire for the terminal
-* [StormForge Optimize Controller](https://github.com/thestormforge/optimize-controller): a tool for experimenting with application configurations in Kubernetes
-* [STTG](https://github.com/wille1101/sttg): a teletext client for SVT, Sweden’s national public television station
-* [sttr](https://github.com/abhimanyu003/sttr): a general-purpose text transformer
-* [tasktimer](https://github.com/caarlos0/tasktimer): a dead-simple task timer
-* [termdbms](https://github.com/mathaou/termdbms): a keyboard and mouse driven database browser
-* [ticker](https://github.com/achannarasappa/ticker): a terminal stock viewer and stock position tracker
-* [tran](https://github.com/abdfnx/tran): securely transfer stuff between computers (based on [portal](https://github.com/ZinoKader/portal))
-* [Typer](https://github.com/maaslalani/typer): a typing test
-* [tz](https://github.com/oz/tz): an aid for scheduling across multiple time zones
-* [ugm](https://github.com/ariasmn/ugm): a unix user and group browser
-* [wander](https://github.com/robinovitch61/wander): a HashiCorp Nomad terminal client
-* [WG Commander](https://github.com/AndrianBdn/wg-cmd): a TUI for a simple WireGuard VPN setup
-* [wishlist](https://github.com/charmbracelet/wishlist): an SSH directory
+There are over [10,000 applications](https://github.com/charmbracelet/bubbletea/network/dependents) built with Bubble Tea! Here are a handful of ’em.
+
+### Staff favourites
+
+- [chezmoi](https://github.com/twpayne/chezmoi): securely manage your dotfiles across multiple machines
+- [circumflex](https://github.com/bensadeh/circumflex): read Hacker News in the terminal
+- [gh-dash](https://www.github.com/dlvhdr/gh-dash): a GitHub CLI extension for PRs and issues
+- [Tetrigo](https://github.com/Broderick-Westrope/tetrigo): Tetris in the terminal
+- [Signls](https://github.com/emprcl/signls): a generative midi sequencer designed for composition and live performance
+- [Superfile](https://github.com/yorukot/superfile): a super file manager
+
+### In Industry
+
+- Microsoft Azure – [Aztify](https://github.com/Azure/aztfy): bring Microsoft Azure resources under Terraform
+- Daytona – [Daytona](https://github.com/daytonaio/daytona): open source dev environment manager
+- Cockroach Labs – [CockroachDB](https://github.com/cockroachdb/cockroach): a cloud-native, high-availability distributed SQL database
+- Truffle Security Co. – [Trufflehog](https://github.com/trufflesecurity/trufflehog): find leaked credentials
+- NVIDIA – [container-canary](https://github.com/NVIDIA/container-canary): a container validator
+- AWS – [eks-node-viewer](https://github.com/awslabs/eks-node-viewer): a tool for visualizing dynamic node usage within an EKS cluster
+- MinIO – [mc](https://github.com/minio/mc): the official [MinIO](https://min.io) client
+- Ubuntu – [Authd](https://github.com/ubuntu/authd): an authentication daemon for cloud-based identity providers
+
+### Charm stuff
+
+- [Glow](https://github.com/charmbracelet/glow): a markdown reader, browser, and online markdown stash
+- [Huh?](https://github.com/charmbracelet/huh): an interactive prompt and form toolkit
+- [Mods](https://github.com/charmbracelet/mods): AI on the CLI, built for pipelines
+- [Wishlist](https://github.com/charmbracelet/wishlist): an SSH directory (and bastion!)
+
+### There’s so much more where that came from
+
+For more applications built with Bubble Tea see [Charm & Friends][community].
+Is there something cool you made with Bubble Tea you want to share? [PRs][community] are
+welcome!
+
+## Contributing
+
+See [contributing][contribute].
+
+[contribute]: https://github.com/charmbracelet/bubbletea/contribute
## Feedback
-We'd love to hear your thoughts on this project. Feel free to drop us a note!
+We’d love to hear your thoughts on this project. Feel free to drop us a note!
-* [Twitter](https://twitter.com/charmcli)
-* [The Fediverse](https://mastodon.social/@charmcli)
-* [Discord](https://charm.sh/chat)
+- [Twitter](https://twitter.com/charmcli)
+- [The Fediverse](https://mastodon.social/@charmcli)
+- [Discord](https://charm.sh/chat)
## Acknowledgments
@@ -391,12 +381,13 @@ of days past.
[elm]: https://guide.elm-lang.org/architecture/
[gotea]: https://github.com/tj/go-tea
[zb]: https://de.wikipedia.org/wiki/Zeichenorientierte_Benutzerschnittstelle
+[community]: https://github.com/charm-and-friends/charm-in-the-wild
## License
-[MIT](https://github.com/charmbracelet/bubbletea/raw/master/LICENSE)
+[MIT](https://github.com/charmbracelet/bubbletea/raw/main/LICENSE)
-***
+---
Part of [Charm](https://charm.sh).
diff --git a/vendor/github.com/charmbracelet/bubbletea/commands.go b/vendor/github.com/charmbracelet/bubbletea/commands.go
index 7c30a121..bfa3b704 100644
--- a/vendor/github.com/charmbracelet/bubbletea/commands.go
+++ b/vendor/github.com/charmbracelet/bubbletea/commands.go
@@ -13,18 +13,22 @@ import (
// return tea.Batch(someCommand, someOtherCommand)
// }
func Batch(cmds ...Cmd) Cmd {
- var validCmds []Cmd
+ var validCmds []Cmd //nolint:prealloc
for _, c := range cmds {
if c == nil {
continue
}
validCmds = append(validCmds, c)
}
- if len(validCmds) == 0 {
+ switch len(validCmds) {
+ case 0:
return nil
- }
- return func() Msg {
- return BatchMsg(validCmds)
+ case 1:
+ return validCmds[0]
+ default:
+ return func() Msg {
+ return BatchMsg(validCmds)
+ }
}
}
@@ -90,11 +94,16 @@ type sequenceMsg []Cmd
//
// Every is analogous to Tick in the Elm Architecture.
func Every(duration time.Duration, fn func(time.Time) Msg) Cmd {
+ n := time.Now()
+ d := n.Truncate(duration).Add(duration).Sub(n)
+ t := time.NewTimer(d)
return func() Msg {
- n := time.Now()
- d := n.Truncate(duration).Add(duration).Sub(n)
- t := time.NewTimer(d)
- return fn(<-t.C)
+ ts := <-t.C
+ t.Stop()
+ for len(t.C) > 0 {
+ <-t.C
+ }
+ return fn(ts)
}
}
@@ -137,9 +146,14 @@ func Every(duration time.Duration, fn func(time.Time) Msg) Cmd {
// return m, nil
// }
func Tick(d time.Duration, fn func(time.Time) Msg) Cmd {
+ t := time.NewTimer(d)
return func() Msg {
- t := time.NewTimer(d)
- return fn(<-t.C)
+ ts := <-t.C
+ t.Stop()
+ for len(t.C) > 0 {
+ <-t.C
+ }
+ return fn(ts)
}
}
@@ -170,3 +184,33 @@ func Sequentially(cmds ...Cmd) Cmd {
return nil
}
}
+
+// setWindowTitleMsg is an internal message used to set the window title.
+type setWindowTitleMsg string
+
+// SetWindowTitle produces a command that sets the terminal title.
+//
+// For example:
+//
+// func (m model) Init() Cmd {
+// // Set title.
+// return tea.SetWindowTitle("My App")
+// }
+func SetWindowTitle(title string) Cmd {
+ return func() Msg {
+ return setWindowTitleMsg(title)
+ }
+}
+
+type windowSizeMsg struct{}
+
+// WindowSize is a command that queries the terminal for its current size. It
+// delivers the results to Update via a [WindowSizeMsg]. Keep in mind that
+// WindowSizeMsgs will automatically be delivered to Update when the [Program]
+// starts and when the window dimensions change so in many cases you will not
+// need to explicitly invoke this command.
+func WindowSize() Cmd {
+ return func() Msg {
+ return windowSizeMsg{}
+ }
+}
diff --git a/vendor/github.com/charmbracelet/bubbletea/exec.go b/vendor/github.com/charmbracelet/bubbletea/exec.go
index fb6d91ed..7a14d2a7 100644
--- a/vendor/github.com/charmbracelet/bubbletea/exec.go
+++ b/vendor/github.com/charmbracelet/bubbletea/exec.go
@@ -109,7 +109,7 @@ func (p *Program) exec(c ExecCommand, fn ExecCallback) {
}
c.SetStdin(p.input)
- c.SetStdout(p.output.TTY())
+ c.SetStdout(p.output)
c.SetStderr(os.Stderr)
// Execute system command.
diff --git a/vendor/github.com/charmbracelet/bubbletea/focus.go b/vendor/github.com/charmbracelet/bubbletea/focus.go
new file mode 100644
index 00000000..4d34bea6
--- /dev/null
+++ b/vendor/github.com/charmbracelet/bubbletea/focus.go
@@ -0,0 +1,9 @@
+package tea
+
+// FocusMsg represents a terminal focus message.
+// This occurs when the terminal gains focus.
+type FocusMsg struct{}
+
+// BlurMsg represents a terminal blur message.
+// This occurs when the terminal loses focus.
+type BlurMsg struct{}
diff --git a/vendor/github.com/charmbracelet/bubbletea/inputreader_other.go b/vendor/github.com/charmbracelet/bubbletea/inputreader_other.go
new file mode 100644
index 00000000..3426a177
--- /dev/null
+++ b/vendor/github.com/charmbracelet/bubbletea/inputreader_other.go
@@ -0,0 +1,14 @@
+//go:build !windows
+// +build !windows
+
+package tea
+
+import (
+ "io"
+
+ "github.com/muesli/cancelreader"
+)
+
+func newInputReader(r io.Reader, _ bool) (cancelreader.CancelReader, error) {
+ return cancelreader.NewReader(r)
+}
diff --git a/vendor/github.com/charmbracelet/bubbletea/inputreader_windows.go b/vendor/github.com/charmbracelet/bubbletea/inputreader_windows.go
new file mode 100644
index 00000000..9af89428
--- /dev/null
+++ b/vendor/github.com/charmbracelet/bubbletea/inputreader_windows.go
@@ -0,0 +1,127 @@
+//go:build windows
+// +build windows
+
+package tea
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "sync"
+
+ "github.com/charmbracelet/x/term"
+ "github.com/erikgeiser/coninput"
+ "github.com/muesli/cancelreader"
+ "golang.org/x/sys/windows"
+)
+
+type conInputReader struct {
+ cancelMixin
+
+ conin windows.Handle
+
+ originalMode uint32
+}
+
+var _ cancelreader.CancelReader = &conInputReader{}
+
+func newInputReader(r io.Reader, enableMouse bool) (cancelreader.CancelReader, error) {
+ fallback := func(io.Reader) (cancelreader.CancelReader, error) {
+ return cancelreader.NewReader(r)
+ }
+ if f, ok := r.(term.File); !ok || f.Fd() != os.Stdin.Fd() {
+ return fallback(r)
+ }
+
+ conin, err := coninput.NewStdinHandle()
+ if err != nil {
+ return fallback(r)
+ }
+
+ modes := []uint32{
+ windows.ENABLE_WINDOW_INPUT,
+ windows.ENABLE_EXTENDED_FLAGS,
+ }
+
+ // Since we have options to enable mouse events, [WithMouseCellMotion],
+ // [WithMouseAllMotion], and [EnableMouseCellMotion],
+ // [EnableMouseAllMotion], and [DisableMouse], we need to check if the user
+ // has enabled mouse events and add the appropriate mode accordingly.
+ // Otherwise, mouse events will be enabled all the time.
+ if enableMouse {
+ modes = append(modes, windows.ENABLE_MOUSE_INPUT)
+ }
+
+ originalMode, err := prepareConsole(conin, modes...)
+ if err != nil {
+ return nil, fmt.Errorf("failed to prepare console input: %w", err)
+ }
+
+ return &conInputReader{
+ conin: conin,
+ originalMode: originalMode,
+ }, nil
+}
+
+// Cancel implements cancelreader.CancelReader.
+func (r *conInputReader) Cancel() bool {
+ r.setCanceled()
+
+ return windows.CancelIoEx(r.conin, nil) == nil || windows.CancelIo(r.conin) == nil
+}
+
+// Close implements cancelreader.CancelReader.
+func (r *conInputReader) Close() error {
+ if r.originalMode != 0 {
+ err := windows.SetConsoleMode(r.conin, r.originalMode)
+ if err != nil {
+ return fmt.Errorf("reset console mode: %w", err)
+ }
+ }
+
+ return nil
+}
+
+// Read implements cancelreader.CancelReader.
+func (r *conInputReader) Read(_ []byte) (n int, err error) {
+ if r.isCanceled() {
+ err = cancelreader.ErrCanceled
+ }
+ return
+}
+
+func prepareConsole(input windows.Handle, modes ...uint32) (originalMode uint32, err error) {
+ err = windows.GetConsoleMode(input, &originalMode)
+ if err != nil {
+ return 0, fmt.Errorf("get console mode: %w", err)
+ }
+
+ newMode := coninput.AddInputModes(0, modes...)
+
+ err = windows.SetConsoleMode(input, newMode)
+ if err != nil {
+ return 0, fmt.Errorf("set console mode: %w", err)
+ }
+
+ return originalMode, nil
+}
+
+// cancelMixin represents a goroutine-safe cancelation status.
+type cancelMixin struct {
+ unsafeCanceled bool
+ lock sync.Mutex
+}
+
+func (c *cancelMixin) setCanceled() {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ c.unsafeCanceled = true
+}
+
+func (c *cancelMixin) isCanceled() bool {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ return c.unsafeCanceled
+}
diff --git a/vendor/github.com/charmbracelet/bubbletea/key.go b/vendor/github.com/charmbracelet/bubbletea/key.go
index c2e5e3ab..ab4792ac 100644
--- a/vendor/github.com/charmbracelet/bubbletea/key.go
+++ b/vendor/github.com/charmbracelet/bubbletea/key.go
@@ -1,11 +1,12 @@
package tea
import (
- "errors"
+ "context"
+ "fmt"
"io"
+ "regexp"
+ "strings"
"unicode/utf8"
-
- "github.com/mattn/go-localereader"
)
// KeyMsg contains information about a keypress. KeyMsgs are always sent to
@@ -54,6 +55,7 @@ type Key struct {
Type KeyType
Runes []rune
Alt bool
+ Paste bool
}
// String returns a friendly string representation for a key. It's safe (and
@@ -63,15 +65,28 @@ type Key struct {
// fmt.Println(k)
// // Output: enter
func (k Key) String() (str string) {
+ var buf strings.Builder
if k.Alt {
- str += "alt+"
+ buf.WriteString("alt+")
}
if k.Type == KeyRunes {
- str += string(k.Runes)
- return str
+ if k.Paste {
+ // Note: bubbles/keys bindings currently do string compares to
+ // recognize shortcuts. Since pasted text should never activate
+ // shortcuts, we need to ensure that the binding code doesn't
+ // match Key events that result from pastes. We achieve this
+ // here by enclosing pastes in '[...]' so that the string
+ // comparison in Matches() fails in that case.
+ buf.WriteByte('[')
+ }
+ buf.WriteString(string(k.Runes))
+ if k.Paste {
+ buf.WriteByte(']')
+ }
+ return buf.String()
} else if s, ok := keyNames[k.Type]; ok {
- str += s
- return str
+ buf.WriteString(s)
+ return buf.String()
}
return ""
}
@@ -338,85 +353,73 @@ var keyNames = map[KeyType]string{
// Sequence mappings.
var sequences = map[string]Key{
// Arrow keys
- "\x1b[A": {Type: KeyUp},
- "\x1b[B": {Type: KeyDown},
- "\x1b[C": {Type: KeyRight},
- "\x1b[D": {Type: KeyLeft},
- "\x1b[1;2A": {Type: KeyShiftUp},
- "\x1b[1;2B": {Type: KeyShiftDown},
- "\x1b[1;2C": {Type: KeyShiftRight},
- "\x1b[1;2D": {Type: KeyShiftLeft},
- "\x1b[OA": {Type: KeyShiftUp}, // DECCKM
- "\x1b[OB": {Type: KeyShiftDown}, // DECCKM
- "\x1b[OC": {Type: KeyShiftRight}, // DECCKM
- "\x1b[OD": {Type: KeyShiftLeft}, // DECCKM
- "\x1b[a": {Type: KeyShiftUp}, // urxvt
- "\x1b[b": {Type: KeyShiftDown}, // urxvt
- "\x1b[c": {Type: KeyShiftRight}, // urxvt
- "\x1b[d": {Type: KeyShiftLeft}, // urxvt
- "\x1b[1;3A": {Type: KeyUp, Alt: true},
- "\x1b[1;3B": {Type: KeyDown, Alt: true},
- "\x1b[1;3C": {Type: KeyRight, Alt: true},
- "\x1b[1;3D": {Type: KeyLeft, Alt: true},
- "\x1b\x1b[A": {Type: KeyUp, Alt: true}, // urxvt
- "\x1b\x1b[B": {Type: KeyDown, Alt: true}, // urxvt
- "\x1b\x1b[C": {Type: KeyRight, Alt: true}, // urxvt
- "\x1b\x1b[D": {Type: KeyLeft, Alt: true}, // urxvt
- "\x1b[1;4A": {Type: KeyShiftUp, Alt: true},
- "\x1b[1;4B": {Type: KeyShiftDown, Alt: true},
- "\x1b[1;4C": {Type: KeyShiftRight, Alt: true},
- "\x1b[1;4D": {Type: KeyShiftLeft, Alt: true},
- "\x1b\x1b[a": {Type: KeyShiftUp, Alt: true}, // urxvt
- "\x1b\x1b[b": {Type: KeyShiftDown, Alt: true}, // urxvt
- "\x1b\x1b[c": {Type: KeyShiftRight, Alt: true}, // urxvt
- "\x1b\x1b[d": {Type: KeyShiftLeft, Alt: true}, // urxvt
- "\x1b[1;5A": {Type: KeyCtrlUp},
- "\x1b[1;5B": {Type: KeyCtrlDown},
- "\x1b[1;5C": {Type: KeyCtrlRight},
- "\x1b[1;5D": {Type: KeyCtrlLeft},
- "\x1b[Oa": {Type: KeyCtrlUp, Alt: true}, // urxvt
- "\x1b[Ob": {Type: KeyCtrlDown, Alt: true}, // urxvt
- "\x1b[Oc": {Type: KeyCtrlRight, Alt: true}, // urxvt
- "\x1b[Od": {Type: KeyCtrlLeft, Alt: true}, // urxvt
- "\x1b[1;6A": {Type: KeyCtrlShiftUp},
- "\x1b[1;6B": {Type: KeyCtrlShiftDown},
- "\x1b[1;6C": {Type: KeyCtrlShiftRight},
- "\x1b[1;6D": {Type: KeyCtrlShiftLeft},
- "\x1b[1;7A": {Type: KeyCtrlUp, Alt: true},
- "\x1b[1;7B": {Type: KeyCtrlDown, Alt: true},
- "\x1b[1;7C": {Type: KeyCtrlRight, Alt: true},
- "\x1b[1;7D": {Type: KeyCtrlLeft, Alt: true},
- "\x1b[1;8A": {Type: KeyCtrlShiftUp, Alt: true},
- "\x1b[1;8B": {Type: KeyCtrlShiftDown, Alt: true},
- "\x1b[1;8C": {Type: KeyCtrlShiftRight, Alt: true},
- "\x1b[1;8D": {Type: KeyCtrlShiftLeft, Alt: true},
+ "\x1b[A": {Type: KeyUp},
+ "\x1b[B": {Type: KeyDown},
+ "\x1b[C": {Type: KeyRight},
+ "\x1b[D": {Type: KeyLeft},
+ "\x1b[1;2A": {Type: KeyShiftUp},
+ "\x1b[1;2B": {Type: KeyShiftDown},
+ "\x1b[1;2C": {Type: KeyShiftRight},
+ "\x1b[1;2D": {Type: KeyShiftLeft},
+ "\x1b[OA": {Type: KeyShiftUp}, // DECCKM
+ "\x1b[OB": {Type: KeyShiftDown}, // DECCKM
+ "\x1b[OC": {Type: KeyShiftRight}, // DECCKM
+ "\x1b[OD": {Type: KeyShiftLeft}, // DECCKM
+ "\x1b[a": {Type: KeyShiftUp}, // urxvt
+ "\x1b[b": {Type: KeyShiftDown}, // urxvt
+ "\x1b[c": {Type: KeyShiftRight}, // urxvt
+ "\x1b[d": {Type: KeyShiftLeft}, // urxvt
+ "\x1b[1;3A": {Type: KeyUp, Alt: true},
+ "\x1b[1;3B": {Type: KeyDown, Alt: true},
+ "\x1b[1;3C": {Type: KeyRight, Alt: true},
+ "\x1b[1;3D": {Type: KeyLeft, Alt: true},
+
+ "\x1b[1;4A": {Type: KeyShiftUp, Alt: true},
+ "\x1b[1;4B": {Type: KeyShiftDown, Alt: true},
+ "\x1b[1;4C": {Type: KeyShiftRight, Alt: true},
+ "\x1b[1;4D": {Type: KeyShiftLeft, Alt: true},
+
+ "\x1b[1;5A": {Type: KeyCtrlUp},
+ "\x1b[1;5B": {Type: KeyCtrlDown},
+ "\x1b[1;5C": {Type: KeyCtrlRight},
+ "\x1b[1;5D": {Type: KeyCtrlLeft},
+ "\x1b[Oa": {Type: KeyCtrlUp, Alt: true}, // urxvt
+ "\x1b[Ob": {Type: KeyCtrlDown, Alt: true}, // urxvt
+ "\x1b[Oc": {Type: KeyCtrlRight, Alt: true}, // urxvt
+ "\x1b[Od": {Type: KeyCtrlLeft, Alt: true}, // urxvt
+ "\x1b[1;6A": {Type: KeyCtrlShiftUp},
+ "\x1b[1;6B": {Type: KeyCtrlShiftDown},
+ "\x1b[1;6C": {Type: KeyCtrlShiftRight},
+ "\x1b[1;6D": {Type: KeyCtrlShiftLeft},
+ "\x1b[1;7A": {Type: KeyCtrlUp, Alt: true},
+ "\x1b[1;7B": {Type: KeyCtrlDown, Alt: true},
+ "\x1b[1;7C": {Type: KeyCtrlRight, Alt: true},
+ "\x1b[1;7D": {Type: KeyCtrlLeft, Alt: true},
+ "\x1b[1;8A": {Type: KeyCtrlShiftUp, Alt: true},
+ "\x1b[1;8B": {Type: KeyCtrlShiftDown, Alt: true},
+ "\x1b[1;8C": {Type: KeyCtrlShiftRight, Alt: true},
+ "\x1b[1;8D": {Type: KeyCtrlShiftLeft, Alt: true},
// Miscellaneous keys
"\x1b[Z": {Type: KeyShiftTab},
- "\x1b[2~": {Type: KeyInsert},
- "\x1b[3;2~": {Type: KeyInsert, Alt: true},
- "\x1b\x1b[2~": {Type: KeyInsert, Alt: true}, // urxvt
-
- "\x1b[3~": {Type: KeyDelete},
- "\x1b[3;3~": {Type: KeyDelete, Alt: true},
- "\x1b\x1b[3~": {Type: KeyDelete, Alt: true}, // urxvt
-
- "\x1b[5~": {Type: KeyPgUp},
- "\x1b[5;3~": {Type: KeyPgUp, Alt: true},
- "\x1b\x1b[5~": {Type: KeyPgUp, Alt: true}, // urxvt
- "\x1b[5;5~": {Type: KeyCtrlPgUp},
- "\x1b[5^": {Type: KeyCtrlPgUp}, // urxvt
- "\x1b[5;7~": {Type: KeyCtrlPgUp, Alt: true},
- "\x1b\x1b[5^": {Type: KeyCtrlPgUp, Alt: true}, // urxvt
-
- "\x1b[6~": {Type: KeyPgDown},
- "\x1b[6;3~": {Type: KeyPgDown, Alt: true},
- "\x1b\x1b[6~": {Type: KeyPgDown, Alt: true}, // urxvt
- "\x1b[6;5~": {Type: KeyCtrlPgDown},
- "\x1b[6^": {Type: KeyCtrlPgDown}, // urxvt
- "\x1b[6;7~": {Type: KeyCtrlPgDown, Alt: true},
- "\x1b\x1b[6^": {Type: KeyCtrlPgDown, Alt: true}, // urxvt
+ "\x1b[2~": {Type: KeyInsert},
+ "\x1b[3;2~": {Type: KeyInsert, Alt: true},
+
+ "\x1b[3~": {Type: KeyDelete},
+ "\x1b[3;3~": {Type: KeyDelete, Alt: true},
+
+ "\x1b[5~": {Type: KeyPgUp},
+ "\x1b[5;3~": {Type: KeyPgUp, Alt: true},
+ "\x1b[5;5~": {Type: KeyCtrlPgUp},
+ "\x1b[5^": {Type: KeyCtrlPgUp}, // urxvt
+ "\x1b[5;7~": {Type: KeyCtrlPgUp, Alt: true},
+
+ "\x1b[6~": {Type: KeyPgDown},
+ "\x1b[6;3~": {Type: KeyPgDown, Alt: true},
+ "\x1b[6;5~": {Type: KeyCtrlPgDown},
+ "\x1b[6^": {Type: KeyCtrlPgDown}, // urxvt
+ "\x1b[6;7~": {Type: KeyCtrlPgDown, Alt: true},
"\x1b[1~": {Type: KeyHome},
"\x1b[H": {Type: KeyHome}, // xterm, lxterm
@@ -438,23 +441,15 @@ var sequences = map[string]Key{
"\x1b[1;6F": {Type: KeyCtrlShiftEnd}, // xterm, lxterm
"\x1b[1;8F": {Type: KeyCtrlShiftEnd, Alt: true}, // xterm, lxterm
- "\x1b[7~": {Type: KeyHome}, // urxvt
- "\x1b\x1b[7~": {Type: KeyHome, Alt: true}, // urxvt
- "\x1b[7^": {Type: KeyCtrlHome}, // urxvt
- "\x1b\x1b[7^": {Type: KeyCtrlHome, Alt: true}, // urxvt
- "\x1b[7$": {Type: KeyShiftHome}, // urxvt
- "\x1b\x1b[7$": {Type: KeyShiftHome, Alt: true}, // urxvt
- "\x1b[7@": {Type: KeyCtrlShiftHome}, // urxvt
- "\x1b\x1b[7@": {Type: KeyCtrlShiftHome, Alt: true}, // urxvt
-
- "\x1b[8~": {Type: KeyEnd}, // urxvt
- "\x1b\x1b[8~": {Type: KeyEnd, Alt: true}, // urxvt
- "\x1b[8^": {Type: KeyCtrlEnd}, // urxvt
- "\x1b\x1b[8^": {Type: KeyCtrlEnd, Alt: true}, // urxvt
- "\x1b[8$": {Type: KeyShiftEnd}, // urxvt
- "\x1b\x1b[8$": {Type: KeyShiftEnd, Alt: true}, // urxvt
- "\x1b[8@": {Type: KeyCtrlShiftEnd}, // urxvt
- "\x1b\x1b[8@": {Type: KeyCtrlShiftEnd, Alt: true}, // urxvt
+ "\x1b[7~": {Type: KeyHome}, // urxvt
+ "\x1b[7^": {Type: KeyCtrlHome}, // urxvt
+ "\x1b[7$": {Type: KeyShiftHome}, // urxvt
+ "\x1b[7@": {Type: KeyCtrlShiftHome}, // urxvt
+
+ "\x1b[8~": {Type: KeyEnd}, // urxvt
+ "\x1b[8^": {Type: KeyCtrlEnd}, // urxvt
+ "\x1b[8$": {Type: KeyShiftEnd}, // urxvt
+ "\x1b[8@": {Type: KeyCtrlShiftEnd}, // urxvt
// Function keys, Linux console
"\x1b[[A": {Type: KeyF1}, // linux console
@@ -479,29 +474,16 @@ var sequences = map[string]Key{
"\x1b[13~": {Type: KeyF3}, // urxvt
"\x1b[14~": {Type: KeyF4}, // urxvt
- "\x1b\x1b[11~": {Type: KeyF1, Alt: true}, // urxvt
- "\x1b\x1b[12~": {Type: KeyF2, Alt: true}, // urxvt
- "\x1b\x1b[13~": {Type: KeyF3, Alt: true}, // urxvt
- "\x1b\x1b[14~": {Type: KeyF4, Alt: true}, // urxvt
-
"\x1b[15~": {Type: KeyF5}, // vt100, xterm, also urxvt
"\x1b[15;3~": {Type: KeyF5, Alt: true}, // vt100, xterm, also urxvt
- "\x1b\x1b[15~": {Type: KeyF5, Alt: true}, // urxvt
-
"\x1b[17~": {Type: KeyF6}, // vt100, xterm, also urxvt
"\x1b[18~": {Type: KeyF7}, // vt100, xterm, also urxvt
"\x1b[19~": {Type: KeyF8}, // vt100, xterm, also urxvt
"\x1b[20~": {Type: KeyF9}, // vt100, xterm, also urxvt
"\x1b[21~": {Type: KeyF10}, // vt100, xterm, also urxvt
- "\x1b\x1b[17~": {Type: KeyF6, Alt: true}, // urxvt
- "\x1b\x1b[18~": {Type: KeyF7, Alt: true}, // urxvt
- "\x1b\x1b[19~": {Type: KeyF8, Alt: true}, // urxvt
- "\x1b\x1b[20~": {Type: KeyF9, Alt: true}, // urxvt
- "\x1b\x1b[21~": {Type: KeyF10, Alt: true}, // urxvt
-
"\x1b[17;3~": {Type: KeyF6, Alt: true}, // vt100, xterm
"\x1b[18;3~": {Type: KeyF7, Alt: true}, // vt100, xterm
"\x1b[19;3~": {Type: KeyF8, Alt: true}, // vt100, xterm
@@ -514,9 +496,6 @@ var sequences = map[string]Key{
"\x1b[23;3~": {Type: KeyF11, Alt: true}, // vt100, xterm
"\x1b[24;3~": {Type: KeyF12, Alt: true}, // vt100, xterm
- "\x1b\x1b[23~": {Type: KeyF11, Alt: true}, // urxvt
- "\x1b\x1b[24~": {Type: KeyF12, Alt: true}, // urxvt
-
"\x1b[1;2P": {Type: KeyF13},
"\x1b[1;2Q": {Type: KeyF14},
@@ -526,9 +505,6 @@ var sequences = map[string]Key{
"\x1b[25;3~": {Type: KeyF13, Alt: true}, // vt100, xterm
"\x1b[26;3~": {Type: KeyF14, Alt: true}, // vt100, xterm
- "\x1b\x1b[25~": {Type: KeyF13, Alt: true}, // urxvt
- "\x1b\x1b[26~": {Type: KeyF14, Alt: true}, // urxvt
-
"\x1b[1;2R": {Type: KeyF15},
"\x1b[1;2S": {Type: KeyF16},
@@ -538,9 +514,6 @@ var sequences = map[string]Key{
"\x1b[28;3~": {Type: KeyF15, Alt: true}, // vt100, xterm
"\x1b[29;3~": {Type: KeyF16, Alt: true}, // vt100, xterm
- "\x1b\x1b[28~": {Type: KeyF15, Alt: true}, // urxvt
- "\x1b\x1b[29~": {Type: KeyF16, Alt: true}, // urxvt
-
"\x1b[15;2~": {Type: KeyF17},
"\x1b[17;2~": {Type: KeyF18},
"\x1b[18;2~": {Type: KeyF19},
@@ -551,11 +524,6 @@ var sequences = map[string]Key{
"\x1b[33~": {Type: KeyF19},
"\x1b[34~": {Type: KeyF20},
- "\x1b\x1b[31~": {Type: KeyF17, Alt: true}, // urxvt
- "\x1b\x1b[32~": {Type: KeyF18, Alt: true}, // urxvt
- "\x1b\x1b[33~": {Type: KeyF19, Alt: true}, // urxvt
- "\x1b\x1b[34~": {Type: KeyF20, Alt: true}, // urxvt
-
// Powershell sequences.
"\x1bOA": {Type: KeyUp, Alt: false},
"\x1bOB": {Type: KeyDown, Alt: false},
@@ -563,102 +531,185 @@ var sequences = map[string]Key{
"\x1bOD": {Type: KeyLeft, Alt: false},
}
-// readInputs reads keypress and mouse inputs from a TTY and returns messages
+// unknownInputByteMsg is reported by the input reader when an invalid
+// utf-8 byte is detected on the input. Currently, it is not handled
+// further by bubbletea. However, having this event makes it possible
+// to troubleshoot invalid inputs.
+type unknownInputByteMsg byte
+
+func (u unknownInputByteMsg) String() string {
+ return fmt.Sprintf("?%#02x?", int(u))
+}
+
+// unknownCSISequenceMsg is reported by the input reader when an
+// unrecognized CSI sequence is detected on the input. Currently, it
+// is not handled further by bubbletea. However, having this event
+// makes it possible to troubleshoot invalid inputs.
+type unknownCSISequenceMsg []byte
+
+func (u unknownCSISequenceMsg) String() string {
+ return fmt.Sprintf("?CSI%+v?", []byte(u)[2:])
+}
+
+var spaceRunes = []rune{' '}
+
+// readAnsiInputs reads keypress and mouse inputs from a TTY and produces messages
// containing information about the key or mouse events accordingly.
-func readInputs(input io.Reader) ([]Msg, error) {
+func readAnsiInputs(ctx context.Context, msgs chan<- Msg, input io.Reader) error {
var buf [256]byte
- // Read and block
- numBytes, err := input.Read(buf[:])
- if err != nil {
- return nil, err
- }
- b := buf[:numBytes]
- b, err = localereader.UTF8(b)
- if err != nil {
- return nil, err
- }
+ var leftOverFromPrevIteration []byte
+loop:
+ for {
+ // Read and block.
+ numBytes, err := input.Read(buf[:])
+ if err != nil {
+ return fmt.Errorf("error reading input: %w", err)
+ }
+ b := buf[:numBytes]
+ if leftOverFromPrevIteration != nil {
+ b = append(leftOverFromPrevIteration, b...)
+ }
- // Check if it's a mouse event. For now we're parsing X10-type mouse events
- // only.
- mouseEvent, err := parseX10MouseEvents(b)
- if err == nil {
- var m []Msg
- for _, v := range mouseEvent {
- m = append(m, MouseMsg(v))
+ // If we had a short read (numBytes < len(buf)), we're sure that
+ // the end of this read is an event boundary, so there is no doubt
+ // if we are encountering the end of the buffer while parsing a message.
+ // However, if we've succeeded in filling up the buffer, there may
+ // be more data in the OS buffer ready to be read in, to complete
+ // the last message in the input. In that case, we will retry with
+ // the left over data in the next iteration.
+ canHaveMoreData := numBytes == len(buf)
+
+ var i, w int
+ for i, w = 0, 0; i < len(b); i += w {
+ var msg Msg
+ w, msg = detectOneMsg(b[i:], canHaveMoreData)
+ if w == 0 {
+ // Expecting more bytes beyond the current buffer. Try waiting
+ // for more input.
+ leftOverFromPrevIteration = make([]byte, 0, len(b[i:])+len(buf))
+ leftOverFromPrevIteration = append(leftOverFromPrevIteration, b[i:]...)
+ continue loop
+ }
+
+ select {
+ case msgs <- msg:
+ case <-ctx.Done():
+ err := ctx.Err()
+ if err != nil {
+ err = fmt.Errorf("found context error while reading input: %w", err)
+ }
+ return err
+ }
}
- return m, nil
+ leftOverFromPrevIteration = nil
}
+}
- var runeSets [][]rune
- var runes []rune
+var (
+ unknownCSIRe = regexp.MustCompile(`^\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]`)
+ mouseSGRRegex = regexp.MustCompile(`(\d+);(\d+);(\d+)([Mm])`)
+)
- // Translate input into runes. In most cases we'll receive exactly one
- // rune, but there are cases, particularly when an input method editor is
- // used, where we can receive multiple runes at once.
- for i, w := 0, 0; i < len(b); i += w {
- r, width := utf8.DecodeRune(b[i:])
- if r == utf8.RuneError {
- return nil, errors.New("could not decode rune")
+func detectOneMsg(b []byte, canHaveMoreData bool) (w int, msg Msg) {
+ // Detect mouse events.
+ // X10 mouse events have a length of 6 bytes
+ const mouseEventX10Len = 6
+ if len(b) >= mouseEventX10Len && b[0] == '\x1b' && b[1] == '[' {
+ switch b[2] {
+ case 'M':
+ return mouseEventX10Len, MouseMsg(parseX10MouseEvent(b))
+ case '<':
+ if matchIndices := mouseSGRRegex.FindSubmatchIndex(b[3:]); matchIndices != nil {
+ // SGR mouse events length is the length of the match plus the length of the escape sequence
+ mouseEventSGRLen := matchIndices[1] + 3 //nolint:gomnd
+ return mouseEventSGRLen, MouseMsg(parseSGRMouseEvent(b))
+ }
}
+ }
- if r == '\x1b' && len(runes) > 1 {
- // a new key sequence has started
- runeSets = append(runeSets, runes)
- runes = []rune{}
- }
+ // Detect focus events.
+ var foundRF bool
+ foundRF, w, msg = detectReportFocus(b)
+ if foundRF {
+ return w, msg
+ }
- runes = append(runes, r)
- w = width
+ // Detect bracketed paste.
+ var foundbp bool
+ foundbp, w, msg = detectBracketedPaste(b)
+ if foundbp {
+ return w, msg
}
- // add the final set of runes we decoded
- runeSets = append(runeSets, runes)
- if len(runeSets) == 0 {
- return nil, errors.New("received 0 runes from input")
+ // Detect escape sequence and control characters other than NUL,
+ // possibly with an escape character in front to mark the Alt
+ // modifier.
+ var foundSeq bool
+ foundSeq, w, msg = detectSequence(b)
+ if foundSeq {
+ return w, msg
}
- var msgs []Msg
- for _, runes := range runeSets {
- // Is it a sequence, like an arrow key?
- if k, ok := sequences[string(runes)]; ok {
- msgs = append(msgs, KeyMsg(k))
- continue
- }
+ // No non-NUL control character or escape sequence.
+ // If we are seeing at least an escape character, remember it for later below.
+ alt := false
+ i := 0
+ if b[0] == '\x1b' {
+ alt = true
+ i++
+ }
- // Is this an unrecognized CSI sequence? If so, ignore it.
- if len(runes) > 2 && runes[0] == 0x1b && (runes[1] == '[' ||
- (len(runes) > 3 && runes[1] == 0x1b && runes[2] == '[')) {
- continue
- }
+ // Are we seeing a standalone NUL? This is not handled by detectSequence().
+ if i < len(b) && b[i] == 0 {
+ return i + 1, KeyMsg{Type: keyNUL, Alt: alt}
+ }
- // Is the alt key pressed? If so, the buffer will be prefixed with an
- // escape.
- alt := false
- if len(runes) > 1 && runes[0] == 0x1b {
- alt = true
- runes = runes[1:]
+ // Find the longest sequence of runes that are not control
+ // characters from this point.
+ var runes []rune
+ for rw := 0; i < len(b); i += rw {
+ var r rune
+ r, rw = utf8.DecodeRune(b[i:])
+ if r == utf8.RuneError || r <= rune(keyUS) || r == rune(keyDEL) || r == ' ' {
+ // Rune errors are handled below; control characters and spaces will
+ // be handled by detectSequence in the next call to detectOneMsg.
+ break
}
+ runes = append(runes, r)
+ if alt {
+ // We only support a single rune after an escape alt modifier.
+ i += rw
+ break
+ }
+ }
+ if i >= len(b) && canHaveMoreData {
+ // We have encountered the end of the input buffer. Alas, we can't
+ // be sure whether the data in the remainder of the buffer is
+ // complete (maybe there was a short read). Instead of sending anything
+ // dumb to the message channel, do a short read. The outer loop will
+ // handle this case by extending the buffer as necessary.
+ return 0, nil
+ }
- for _, v := range runes {
- // Is the first rune a control character?
- r := KeyType(v)
- if r <= keyUS || r == keyDEL {
- msgs = append(msgs, KeyMsg(Key{Type: r, Alt: alt}))
- continue
- }
-
- // If it's a space, override the type with KeySpace (but still include
- // the rune).
- if r == ' ' {
- msgs = append(msgs, KeyMsg(Key{Type: KeySpace, Runes: []rune{v}, Alt: alt}))
- continue
- }
-
- // Welp, just regular, ol' runes.
- msgs = append(msgs, KeyMsg(Key{Type: KeyRunes, Runes: []rune{v}, Alt: alt}))
+ // If we found at least one rune, we report the bunch of them as
+ // a single KeyRunes or KeySpace event.
+ if len(runes) > 0 {
+ k := Key{Type: KeyRunes, Runes: runes, Alt: alt}
+ if len(runes) == 1 && runes[0] == ' ' {
+ k.Type = KeySpace
}
+ return i, KeyMsg(k)
+ }
+
+ // We didn't find an escape sequence, nor a valid rune. Was this a
+ // lone escape character at the end of the input?
+ if alt && len(b) == 1 {
+ return 1, KeyMsg(Key{Type: KeyEscape})
}
- return msgs, nil
+ // The character at the current position is neither an escape
+ // sequence, a valid rune start or a sole escape character. Report
+ // it as an invalid byte.
+ return 1, unknownInputByteMsg(b[0])
}
diff --git a/vendor/github.com/charmbracelet/bubbletea/key_other.go b/vendor/github.com/charmbracelet/bubbletea/key_other.go
new file mode 100644
index 00000000..b8c46082
--- /dev/null
+++ b/vendor/github.com/charmbracelet/bubbletea/key_other.go
@@ -0,0 +1,13 @@
+//go:build !windows
+// +build !windows
+
+package tea
+
+import (
+ "context"
+ "io"
+)
+
+func readInputs(ctx context.Context, msgs chan<- Msg, input io.Reader) error {
+ return readAnsiInputs(ctx, msgs, input)
+}
diff --git a/vendor/github.com/charmbracelet/bubbletea/key_sequences.go b/vendor/github.com/charmbracelet/bubbletea/key_sequences.go
new file mode 100644
index 00000000..15483ef5
--- /dev/null
+++ b/vendor/github.com/charmbracelet/bubbletea/key_sequences.go
@@ -0,0 +1,131 @@
+package tea
+
+import (
+ "bytes"
+ "sort"
+ "unicode/utf8"
+)
+
+// extSequences is used by the map-based algorithm below. It contains
+// the sequences plus their alternatives with an escape character
+// prefixed, plus the control chars, plus the space.
+// It does not contain the NUL character, which is handled specially
+// by detectOneMsg.
+var extSequences = func() map[string]Key {
+ s := map[string]Key{}
+ for seq, key := range sequences {
+ key := key
+ s[seq] = key
+ if !key.Alt {
+ key.Alt = true
+ s["\x1b"+seq] = key
+ }
+ }
+ for i := keyNUL + 1; i <= keyDEL; i++ {
+ if i == keyESC {
+ continue
+ }
+ s[string([]byte{byte(i)})] = Key{Type: i}
+ s[string([]byte{'\x1b', byte(i)})] = Key{Type: i, Alt: true}
+ if i == keyUS {
+ i = keyDEL - 1
+ }
+ }
+ s[" "] = Key{Type: KeySpace, Runes: spaceRunes}
+ s["\x1b "] = Key{Type: KeySpace, Alt: true, Runes: spaceRunes}
+ s["\x1b\x1b"] = Key{Type: KeyEscape, Alt: true}
+ return s
+}()
+
+// seqLengths is the sizes of valid sequences, starting with the
+// largest size.
+var seqLengths = func() []int {
+ sizes := map[int]struct{}{}
+ for seq := range extSequences {
+ sizes[len(seq)] = struct{}{}
+ }
+ lsizes := make([]int, 0, len(sizes))
+ for sz := range sizes {
+ lsizes = append(lsizes, sz)
+ }
+ sort.Slice(lsizes, func(i, j int) bool { return lsizes[i] > lsizes[j] })
+ return lsizes
+}()
+
+// detectSequence uses a longest prefix match over the input
+// sequence and a hash map.
+func detectSequence(input []byte) (hasSeq bool, width int, msg Msg) {
+ seqs := extSequences
+ for _, sz := range seqLengths {
+ if sz > len(input) {
+ continue
+ }
+ prefix := input[:sz]
+ key, ok := seqs[string(prefix)]
+ if ok {
+ return true, sz, KeyMsg(key)
+ }
+ }
+ // Is this an unknown CSI sequence?
+ if loc := unknownCSIRe.FindIndex(input); loc != nil {
+ return true, loc[1], unknownCSISequenceMsg(input[:loc[1]])
+ }
+
+ return false, 0, nil
+}
+
+// detectBracketedPaste detects an input pasted while bracketed
+// paste mode was enabled.
+//
+// Note: this function is a no-op if bracketed paste was not enabled
+// on the terminal, since in that case we'd never see this
+// particular escape sequence.
+func detectBracketedPaste(input []byte) (hasBp bool, width int, msg Msg) {
+ // Detect the start sequence.
+ const bpStart = "\x1b[200~"
+ if len(input) < len(bpStart) || string(input[:len(bpStart)]) != bpStart {
+ return false, 0, nil
+ }
+
+ // Skip over the start sequence.
+ input = input[len(bpStart):]
+
+ // If we saw the start sequence, then we must have an end sequence
+ // as well. Find it.
+ const bpEnd = "\x1b[201~"
+ idx := bytes.Index(input, []byte(bpEnd))
+ inputLen := len(bpStart) + idx + len(bpEnd)
+ if idx == -1 {
+ // We have encountered the end of the input buffer without seeing
+ // the marker for the end of the bracketed paste.
+ // Tell the outer loop we have done a short read and we want more.
+ return true, 0, nil
+ }
+
+ // The paste is everything in-between.
+ paste := input[:idx]
+
+ // All there is in-between is runes, not to be interpreted further.
+ k := Key{Type: KeyRunes, Paste: true}
+ for len(paste) > 0 {
+ r, w := utf8.DecodeRune(paste)
+ if r != utf8.RuneError {
+ k.Runes = append(k.Runes, r)
+ }
+ paste = paste[w:]
+ }
+
+ return true, inputLen, KeyMsg(k)
+}
+
+// detectReportFocus detects a focus report sequence.
+// nolint: gomnd
+func detectReportFocus(input []byte) (hasRF bool, width int, msg Msg) {
+ switch {
+ case bytes.Equal(input, []byte("\x1b[I")):
+ return true, 3, FocusMsg{}
+ case bytes.Equal(input, []byte("\x1b[O")):
+ return true, 3, BlurMsg{}
+ }
+ return false, 0, nil
+}
diff --git a/vendor/github.com/charmbracelet/bubbletea/key_windows.go b/vendor/github.com/charmbracelet/bubbletea/key_windows.go
new file mode 100644
index 00000000..d59ff1c4
--- /dev/null
+++ b/vendor/github.com/charmbracelet/bubbletea/key_windows.go
@@ -0,0 +1,360 @@
+//go:build windows
+// +build windows
+
+package tea
+
+import (
+ "context"
+ "fmt"
+ "io"
+
+ "github.com/erikgeiser/coninput"
+ localereader "github.com/mattn/go-localereader"
+ "github.com/muesli/cancelreader"
+)
+
+func readInputs(ctx context.Context, msgs chan<- Msg, input io.Reader) error {
+ if coninReader, ok := input.(*conInputReader); ok {
+ return readConInputs(ctx, msgs, coninReader)
+ }
+
+ return readAnsiInputs(ctx, msgs, localereader.NewReader(input))
+}
+
+func readConInputs(ctx context.Context, msgsch chan<- Msg, con *conInputReader) error {
+ var ps coninput.ButtonState // keep track of previous mouse state
+ var ws coninput.WindowBufferSizeEventRecord // keep track of the last window size event
+ for {
+ events, err := coninput.ReadNConsoleInputs(con.conin, 16)
+ if err != nil {
+ if con.isCanceled() {
+ return cancelreader.ErrCanceled
+ }
+ return fmt.Errorf("read coninput events: %w", err)
+ }
+
+ for _, event := range events {
+ var msgs []Msg
+ switch e := event.Unwrap().(type) {
+ case coninput.KeyEventRecord:
+ if !e.KeyDown || e.VirtualKeyCode == coninput.VK_SHIFT {
+ continue
+ }
+
+ for i := 0; i < int(e.RepeatCount); i++ {
+ eventKeyType := keyType(e)
+ var runes []rune
+
+ // Add the character only if the key type is an actual character and not a control sequence.
+ // This mimics the behavior in readAnsiInputs where the character is also removed.
+ // We don't need to handle KeySpace here. See the comment in keyType().
+ if eventKeyType == KeyRunes {
+ runes = []rune{e.Char}
+ }
+
+ msgs = append(msgs, KeyMsg{
+ Type: eventKeyType,
+ Runes: runes,
+ Alt: e.ControlKeyState.Contains(coninput.LEFT_ALT_PRESSED | coninput.RIGHT_ALT_PRESSED),
+ })
+ }
+ case coninput.WindowBufferSizeEventRecord:
+ if e != ws {
+ ws = e
+ msgs = append(msgs, WindowSizeMsg{
+ Width: int(e.Size.X),
+ Height: int(e.Size.Y),
+ })
+ }
+ case coninput.MouseEventRecord:
+ event := mouseEvent(ps, e)
+ if event.Type != MouseUnknown {
+ msgs = append(msgs, event)
+ }
+ ps = e.ButtonState
+ case coninput.FocusEventRecord, coninput.MenuEventRecord:
+ // ignore
+ default: // unknown event
+ continue
+ }
+
+ // Send all messages to the channel
+ for _, msg := range msgs {
+ select {
+ case msgsch <- msg:
+ case <-ctx.Done():
+ err := ctx.Err()
+ if err != nil {
+ return fmt.Errorf("coninput context error: %w", err)
+ }
+ return err
+ }
+ }
+ }
+ }
+}
+
+func mouseEventButton(p, s coninput.ButtonState) (button MouseButton, action MouseAction) {
+ btn := p ^ s
+ action = MouseActionPress
+ if btn&s == 0 {
+ action = MouseActionRelease
+ }
+
+ if btn == 0 {
+ switch {
+ case s&coninput.FROM_LEFT_1ST_BUTTON_PRESSED > 0:
+ button = MouseButtonLeft
+ case s&coninput.FROM_LEFT_2ND_BUTTON_PRESSED > 0:
+ button = MouseButtonMiddle
+ case s&coninput.RIGHTMOST_BUTTON_PRESSED > 0:
+ button = MouseButtonRight
+ case s&coninput.FROM_LEFT_3RD_BUTTON_PRESSED > 0:
+ button = MouseButtonBackward
+ case s&coninput.FROM_LEFT_4TH_BUTTON_PRESSED > 0:
+ button = MouseButtonForward
+ }
+ return
+ }
+
+ switch {
+ case btn == coninput.FROM_LEFT_1ST_BUTTON_PRESSED: // left button
+ button = MouseButtonLeft
+ case btn == coninput.RIGHTMOST_BUTTON_PRESSED: // right button
+ button = MouseButtonRight
+ case btn == coninput.FROM_LEFT_2ND_BUTTON_PRESSED: // middle button
+ button = MouseButtonMiddle
+ case btn == coninput.FROM_LEFT_3RD_BUTTON_PRESSED: // unknown (possibly mouse backward)
+ button = MouseButtonBackward
+ case btn == coninput.FROM_LEFT_4TH_BUTTON_PRESSED: // unknown (possibly mouse forward)
+ button = MouseButtonForward
+ }
+
+ return button, action
+}
+
+func mouseEvent(p coninput.ButtonState, e coninput.MouseEventRecord) MouseMsg {
+ ev := MouseMsg{
+ X: int(e.MousePositon.X),
+ Y: int(e.MousePositon.Y),
+ Alt: e.ControlKeyState.Contains(coninput.LEFT_ALT_PRESSED | coninput.RIGHT_ALT_PRESSED),
+ Ctrl: e.ControlKeyState.Contains(coninput.LEFT_CTRL_PRESSED | coninput.RIGHT_CTRL_PRESSED),
+ Shift: e.ControlKeyState.Contains(coninput.SHIFT_PRESSED),
+ }
+ switch e.EventFlags {
+ case coninput.CLICK, coninput.DOUBLE_CLICK:
+ ev.Button, ev.Action = mouseEventButton(p, e.ButtonState)
+ if ev.Action == MouseActionRelease {
+ ev.Type = MouseRelease
+ }
+ switch ev.Button {
+ case MouseButtonLeft:
+ ev.Type = MouseLeft
+ case MouseButtonMiddle:
+ ev.Type = MouseMiddle
+ case MouseButtonRight:
+ ev.Type = MouseRight
+ case MouseButtonBackward:
+ ev.Type = MouseBackward
+ case MouseButtonForward:
+ ev.Type = MouseForward
+ }
+ case coninput.MOUSE_WHEELED:
+ if e.WheelDirection > 0 {
+ ev.Button = MouseButtonWheelUp
+ ev.Type = MouseWheelUp
+ } else {
+ ev.Button = MouseButtonWheelDown
+ ev.Type = MouseWheelDown
+ }
+ case coninput.MOUSE_HWHEELED:
+ if e.WheelDirection > 0 {
+ ev.Button = MouseButtonWheelRight
+ ev.Type = MouseWheelRight
+ } else {
+ ev.Button = MouseButtonWheelLeft
+ ev.Type = MouseWheelLeft
+ }
+ case coninput.MOUSE_MOVED:
+ ev.Button, _ = mouseEventButton(p, e.ButtonState)
+ ev.Action = MouseActionMotion
+ ev.Type = MouseMotion
+ }
+
+ return ev
+}
+
+func keyType(e coninput.KeyEventRecord) KeyType {
+ code := e.VirtualKeyCode
+
+ shiftPressed := e.ControlKeyState.Contains(coninput.SHIFT_PRESSED)
+ ctrlPressed := e.ControlKeyState.Contains(coninput.LEFT_CTRL_PRESSED | coninput.RIGHT_CTRL_PRESSED)
+
+ switch code {
+ case coninput.VK_RETURN:
+ return KeyEnter
+ case coninput.VK_BACK:
+ return KeyBackspace
+ case coninput.VK_TAB:
+ if shiftPressed {
+ return KeyShiftTab
+ }
+ return KeyTab
+ case coninput.VK_SPACE:
+ return KeyRunes // this could be KeySpace but on unix space also produces KeyRunes
+ case coninput.VK_ESCAPE:
+ return KeyEscape
+ case coninput.VK_UP:
+ switch {
+ case shiftPressed && ctrlPressed:
+ return KeyCtrlShiftUp
+ case shiftPressed:
+ return KeyShiftUp
+ case ctrlPressed:
+ return KeyCtrlUp
+ default:
+ return KeyUp
+ }
+ case coninput.VK_DOWN:
+ switch {
+ case shiftPressed && ctrlPressed:
+ return KeyCtrlShiftDown
+ case shiftPressed:
+ return KeyShiftDown
+ case ctrlPressed:
+ return KeyCtrlDown
+ default:
+ return KeyDown
+ }
+ case coninput.VK_RIGHT:
+ switch {
+ case shiftPressed && ctrlPressed:
+ return KeyCtrlShiftRight
+ case shiftPressed:
+ return KeyShiftRight
+ case ctrlPressed:
+ return KeyCtrlRight
+ default:
+ return KeyRight
+ }
+ case coninput.VK_LEFT:
+ switch {
+ case shiftPressed && ctrlPressed:
+ return KeyCtrlShiftLeft
+ case shiftPressed:
+ return KeyShiftLeft
+ case ctrlPressed:
+ return KeyCtrlLeft
+ default:
+ return KeyLeft
+ }
+ case coninput.VK_HOME:
+ switch {
+ case shiftPressed && ctrlPressed:
+ return KeyCtrlShiftHome
+ case shiftPressed:
+ return KeyShiftHome
+ case ctrlPressed:
+ return KeyCtrlHome
+ default:
+ return KeyHome
+ }
+ case coninput.VK_END:
+ switch {
+ case shiftPressed && ctrlPressed:
+ return KeyCtrlShiftEnd
+ case shiftPressed:
+ return KeyShiftEnd
+ case ctrlPressed:
+ return KeyCtrlEnd
+ default:
+ return KeyEnd
+ }
+ case coninput.VK_PRIOR:
+ return KeyPgUp
+ case coninput.VK_NEXT:
+ return KeyPgDown
+ case coninput.VK_DELETE:
+ return KeyDelete
+ default:
+ switch {
+ case e.ControlKeyState.Contains(coninput.LEFT_CTRL_PRESSED) && e.ControlKeyState.Contains(coninput.RIGHT_ALT_PRESSED):
+ // AltGr is pressed, then it's a rune.
+ fallthrough
+ case !e.ControlKeyState.Contains(coninput.LEFT_CTRL_PRESSED) && !e.ControlKeyState.Contains(coninput.RIGHT_CTRL_PRESSED):
+ return KeyRunes
+ }
+
+ switch e.Char {
+ case '@':
+ return KeyCtrlAt
+ case '\x01':
+ return KeyCtrlA
+ case '\x02':
+ return KeyCtrlB
+ case '\x03':
+ return KeyCtrlC
+ case '\x04':
+ return KeyCtrlD
+ case '\x05':
+ return KeyCtrlE
+ case '\x06':
+ return KeyCtrlF
+ case '\a':
+ return KeyCtrlG
+ case '\b':
+ return KeyCtrlH
+ case '\t':
+ return KeyCtrlI
+ case '\n':
+ return KeyCtrlJ
+ case '\v':
+ return KeyCtrlK
+ case '\f':
+ return KeyCtrlL
+ case '\r':
+ return KeyCtrlM
+ case '\x0e':
+ return KeyCtrlN
+ case '\x0f':
+ return KeyCtrlO
+ case '\x10':
+ return KeyCtrlP
+ case '\x11':
+ return KeyCtrlQ
+ case '\x12':
+ return KeyCtrlR
+ case '\x13':
+ return KeyCtrlS
+ case '\x14':
+ return KeyCtrlT
+ case '\x15':
+ return KeyCtrlU
+ case '\x16':
+ return KeyCtrlV
+ case '\x17':
+ return KeyCtrlW
+ case '\x18':
+ return KeyCtrlX
+ case '\x19':
+ return KeyCtrlY
+ case '\x1a':
+ return KeyCtrlZ
+ case '\x1b':
+ return KeyCtrlOpenBracket // KeyEscape
+ case '\x1c':
+ return KeyCtrlBackslash
+ case '\x1f':
+ return KeyCtrlUnderscore
+ }
+
+ switch code {
+ case coninput.VK_OEM_4:
+ return KeyCtrlOpenBracket
+ case coninput.VK_OEM_6:
+ return KeyCtrlCloseBracket
+ }
+
+ return KeyRunes
+ }
+}
diff --git a/vendor/github.com/charmbracelet/bubbletea/logging.go b/vendor/github.com/charmbracelet/bubbletea/logging.go
index 59258d4c..a5311819 100644
--- a/vendor/github.com/charmbracelet/bubbletea/logging.go
+++ b/vendor/github.com/charmbracelet/bubbletea/logging.go
@@ -1,6 +1,7 @@
package tea
import (
+ "fmt"
"io"
"log"
"os"
@@ -32,9 +33,9 @@ type LogOptionsSetter interface {
// LogToFileWith does allows to call LogToFile with a custom LogOptionsSetter.
func LogToFileWith(path string, prefix string, log LogOptionsSetter) (*os.File, error) {
- f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644)
+ f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o600) //nolint:gomnd
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("error opening file for logging: %w", err)
}
log.SetOutput(f)
diff --git a/vendor/github.com/charmbracelet/bubbletea/mouse.go b/vendor/github.com/charmbracelet/bubbletea/mouse.go
index f918d206..6ec51cc0 100644
--- a/vendor/github.com/charmbracelet/bubbletea/mouse.go
+++ b/vendor/github.com/charmbracelet/bubbletea/mouse.go
@@ -1,23 +1,36 @@
package tea
-import (
- "bytes"
- "errors"
-)
+import "strconv"
-// MouseMsg contains information about a mouse event and is sent to a program's
+// MouseMsg contains information about a mouse event and are sent to a programs
// update function when mouse activity occurs. Note that the mouse must first
// be enabled in order for the mouse events to be received.
type MouseMsg MouseEvent
+// String returns a string representation of a mouse event.
+func (m MouseMsg) String() string {
+ return MouseEvent(m).String()
+}
+
// MouseEvent represents a mouse event, which could be a click, a scroll wheel
// movement, a cursor movement, or a combination.
type MouseEvent struct {
- X int
- Y int
+ X int
+ Y int
+ Shift bool
+ Alt bool
+ Ctrl bool
+ Action MouseAction
+ Button MouseButton
+
+ // Deprecated: Use MouseAction & MouseButton instead.
Type MouseEventType
- Alt bool
- Ctrl bool
+}
+
+// IsWheel returns true if the mouse event is a wheel event.
+func (m MouseEvent) IsWheel() bool {
+ return m.Button == MouseButtonWheelUp || m.Button == MouseButtonWheelDown ||
+ m.Button == MouseButtonWheelLeft || m.Button == MouseButtonWheelRight
}
// String returns a string representation of a mouse event.
@@ -28,122 +41,268 @@ func (m MouseEvent) String() (s string) {
if m.Alt {
s += "alt+"
}
- s += mouseEventTypes[m.Type]
+ if m.Shift {
+ s += "shift+"
+ }
+
+ if m.Button == MouseButtonNone { //nolint:nestif
+ if m.Action == MouseActionMotion || m.Action == MouseActionRelease {
+ s += mouseActions[m.Action]
+ } else {
+ s += "unknown"
+ }
+ } else if m.IsWheel() {
+ s += mouseButtons[m.Button]
+ } else {
+ btn := mouseButtons[m.Button]
+ if btn != "" {
+ s += btn
+ }
+ act := mouseActions[m.Action]
+ if act != "" {
+ s += " " + act
+ }
+ }
+
return s
}
+// MouseAction represents the action that occurred during a mouse event.
+type MouseAction int
+
+// Mouse event actions.
+const (
+ MouseActionPress MouseAction = iota
+ MouseActionRelease
+ MouseActionMotion
+)
+
+var mouseActions = map[MouseAction]string{
+ MouseActionPress: "press",
+ MouseActionRelease: "release",
+ MouseActionMotion: "motion",
+}
+
+// MouseButton represents the button that was pressed during a mouse event.
+type MouseButton int
+
+// Mouse event buttons
+//
+// This is based on X11 mouse button codes.
+//
+// 1 = left button
+// 2 = middle button (pressing the scroll wheel)
+// 3 = right button
+// 4 = turn scroll wheel up
+// 5 = turn scroll wheel down
+// 6 = push scroll wheel left
+// 7 = push scroll wheel right
+// 8 = 4th button (aka browser backward button)
+// 9 = 5th button (aka browser forward button)
+// 10
+// 11
+//
+// Other buttons are not supported.
+const (
+ MouseButtonNone MouseButton = iota
+ MouseButtonLeft
+ MouseButtonMiddle
+ MouseButtonRight
+ MouseButtonWheelUp
+ MouseButtonWheelDown
+ MouseButtonWheelLeft
+ MouseButtonWheelRight
+ MouseButtonBackward
+ MouseButtonForward
+ MouseButton10
+ MouseButton11
+)
+
+var mouseButtons = map[MouseButton]string{
+ MouseButtonNone: "none",
+ MouseButtonLeft: "left",
+ MouseButtonMiddle: "middle",
+ MouseButtonRight: "right",
+ MouseButtonWheelUp: "wheel up",
+ MouseButtonWheelDown: "wheel down",
+ MouseButtonWheelLeft: "wheel left",
+ MouseButtonWheelRight: "wheel right",
+ MouseButtonBackward: "backward",
+ MouseButtonForward: "forward",
+ MouseButton10: "button 10",
+ MouseButton11: "button 11",
+}
+
// MouseEventType indicates the type of mouse event occurring.
+//
+// Deprecated: Use MouseAction & MouseButton instead.
type MouseEventType int
// Mouse event types.
+//
+// Deprecated: Use MouseAction & MouseButton instead.
const (
MouseUnknown MouseEventType = iota
MouseLeft
MouseRight
MouseMiddle
- MouseRelease
+ MouseRelease // mouse button release (X10 only)
MouseWheelUp
MouseWheelDown
+ MouseWheelLeft
+ MouseWheelRight
+ MouseBackward
+ MouseForward
MouseMotion
)
-var mouseEventTypes = map[MouseEventType]string{
- MouseUnknown: "unknown",
- MouseLeft: "left",
- MouseRight: "right",
- MouseMiddle: "middle",
- MouseRelease: "release",
- MouseWheelUp: "wheel up",
- MouseWheelDown: "wheel down",
- MouseMotion: "motion",
+// Parse SGR-encoded mouse events; SGR extended mouse events. SGR mouse events
+// look like:
+//
+// ESC [ < Cb ; Cx ; Cy (M or m)
+//
+// where:
+//
+// Cb is the encoded button code
+// Cx is the x-coordinate of the mouse
+// Cy is the y-coordinate of the mouse
+// M is for button press, m is for button release
+//
+// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Extended-coordinates
+func parseSGRMouseEvent(buf []byte) MouseEvent {
+ str := string(buf[3:])
+ matches := mouseSGRRegex.FindStringSubmatch(str)
+ if len(matches) != 5 { //nolint:gomnd
+ // Unreachable, we already checked the regex in `detectOneMsg`.
+ panic("invalid mouse event")
+ }
+
+ b, _ := strconv.Atoi(matches[1])
+ px := matches[2]
+ py := matches[3]
+ release := matches[4] == "m"
+ m := parseMouseButton(b, true)
+
+ // Wheel buttons don't have release events
+ // Motion can be reported as a release event in some terminals (Windows Terminal)
+ if m.Action != MouseActionMotion && !m.IsWheel() && release {
+ m.Action = MouseActionRelease
+ m.Type = MouseRelease
+ }
+
+ x, _ := strconv.Atoi(px)
+ y, _ := strconv.Atoi(py)
+
+ // (1,1) is the upper left. We subtract 1 to normalize it to (0,0).
+ m.X = x - 1
+ m.Y = y - 1
+
+ return m
}
+const x10MouseByteOffset = 32
+
// Parse X10-encoded mouse events; the simplest kind. The last release of X10
-// was December 1986, by the way.
+// was December 1986, by the way. The original X10 mouse protocol limits the Cx
+// and Cy coordinates to 223 (=255-032).
//
// X10 mouse events look like:
//
// ESC [M Cb Cx Cy
//
// See: http://www.xfree86.org/current/ctlseqs.html#Mouse%20Tracking
-func parseX10MouseEvents(buf []byte) ([]MouseEvent, error) {
- var r []MouseEvent
+func parseX10MouseEvent(buf []byte) MouseEvent {
+ v := buf[3:6]
+ m := parseMouseButton(int(v[0]), false)
- seq := []byte("\x1b[M")
- if !bytes.Contains(buf, seq) {
- return r, errors.New("not an X10 mouse event")
+ // (1,1) is the upper left. We subtract 1 to normalize it to (0,0).
+ m.X = int(v[1]) - x10MouseByteOffset - 1
+ m.Y = int(v[2]) - x10MouseByteOffset - 1
+
+ return m
+}
+
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Extended-coordinates
+func parseMouseButton(b int, isSGR bool) MouseEvent {
+ var m MouseEvent
+ e := b
+ if !isSGR {
+ e -= x10MouseByteOffset
}
- for _, v := range bytes.Split(buf, seq) {
- if len(v) == 0 {
- continue
- }
- if len(v) != 3 {
- return r, errors.New("not an X10 mouse event")
- }
+ const (
+ bitShift = 0b0000_0100
+ bitAlt = 0b0000_1000
+ bitCtrl = 0b0001_0000
+ bitMotion = 0b0010_0000
+ bitWheel = 0b0100_0000
+ bitAdd = 0b1000_0000 // additional buttons 8-11
- var m MouseEvent
- const byteOffset = 32
- e := v[0] - byteOffset
-
- const (
- bitShift = 0b0000_0100
- bitAlt = 0b0000_1000
- bitCtrl = 0b0001_0000
- bitMotion = 0b0010_0000
- bitWheel = 0b0100_0000
-
- bitsMask = 0b0000_0011
-
- bitsLeft = 0b0000_0000
- bitsMiddle = 0b0000_0001
- bitsRight = 0b0000_0010
- bitsRelease = 0b0000_0011
-
- bitsWheelUp = 0b0000_0000
- bitsWheelDown = 0b0000_0001
- )
-
- if e&bitWheel != 0 {
- // Check the low two bits.
- switch e & bitsMask {
- case bitsWheelUp:
- m.Type = MouseWheelUp
- case bitsWheelDown:
- m.Type = MouseWheelDown
- }
- } else {
- // Check the low two bits.
- // We do not separate clicking and dragging.
- switch e & bitsMask {
- case bitsLeft:
- m.Type = MouseLeft
- case bitsMiddle:
- m.Type = MouseMiddle
- case bitsRight:
- m.Type = MouseRight
- case bitsRelease:
- if e&bitMotion != 0 {
- m.Type = MouseMotion
- } else {
- m.Type = MouseRelease
- }
- }
- }
+ bitsMask = 0b0000_0011
+ )
- if e&bitAlt != 0 {
- m.Alt = true
- }
- if e&bitCtrl != 0 {
- m.Ctrl = true
+ if e&bitAdd != 0 {
+ m.Button = MouseButtonBackward + MouseButton(e&bitsMask)
+ } else if e&bitWheel != 0 {
+ m.Button = MouseButtonWheelUp + MouseButton(e&bitsMask)
+ } else {
+ m.Button = MouseButtonLeft + MouseButton(e&bitsMask)
+ // X10 reports a button release as 0b0000_0011 (3)
+ if e&bitsMask == bitsMask {
+ m.Action = MouseActionRelease
+ m.Button = MouseButtonNone
}
+ }
- // (1,1) is the upper left. We subtract 1 to normalize it to (0,0).
- m.X = int(v[1]) - byteOffset - 1
- m.Y = int(v[2]) - byteOffset - 1
+ // Motion bit doesn't get reported for wheel events.
+ if e&bitMotion != 0 && !m.IsWheel() {
+ m.Action = MouseActionMotion
+ }
+
+ // Modifiers
+ m.Alt = e&bitAlt != 0
+ m.Ctrl = e&bitCtrl != 0
+ m.Shift = e&bitShift != 0
- r = append(r, m)
+ // backward compatibility
+ switch {
+ case m.Button == MouseButtonLeft && m.Action == MouseActionPress:
+ m.Type = MouseLeft
+ case m.Button == MouseButtonMiddle && m.Action == MouseActionPress:
+ m.Type = MouseMiddle
+ case m.Button == MouseButtonRight && m.Action == MouseActionPress:
+ m.Type = MouseRight
+ case m.Button == MouseButtonNone && m.Action == MouseActionRelease:
+ m.Type = MouseRelease
+ case m.Button == MouseButtonWheelUp && m.Action == MouseActionPress:
+ m.Type = MouseWheelUp
+ case m.Button == MouseButtonWheelDown && m.Action == MouseActionPress:
+ m.Type = MouseWheelDown
+ case m.Button == MouseButtonWheelLeft && m.Action == MouseActionPress:
+ m.Type = MouseWheelLeft
+ case m.Button == MouseButtonWheelRight && m.Action == MouseActionPress:
+ m.Type = MouseWheelRight
+ case m.Button == MouseButtonBackward && m.Action == MouseActionPress:
+ m.Type = MouseBackward
+ case m.Button == MouseButtonForward && m.Action == MouseActionPress:
+ m.Type = MouseForward
+ case m.Action == MouseActionMotion:
+ m.Type = MouseMotion
+ switch m.Button { //nolint:exhaustive
+ case MouseButtonLeft:
+ m.Type = MouseLeft
+ case MouseButtonMiddle:
+ m.Type = MouseMiddle
+ case MouseButtonRight:
+ m.Type = MouseRight
+ case MouseButtonBackward:
+ m.Type = MouseBackward
+ case MouseButtonForward:
+ m.Type = MouseForward
+ }
+ default:
+ m.Type = MouseUnknown
}
- return r, nil
+ return m
}
diff --git a/vendor/github.com/charmbracelet/bubbletea/nil_renderer.go b/vendor/github.com/charmbracelet/bubbletea/nil_renderer.go
index f5637aa4..0bc4a172 100644
--- a/vendor/github.com/charmbracelet/bubbletea/nil_renderer.go
+++ b/vendor/github.com/charmbracelet/bubbletea/nil_renderer.go
@@ -2,18 +2,27 @@ package tea
type nilRenderer struct{}
-func (n nilRenderer) start() {}
-func (n nilRenderer) stop() {}
-func (n nilRenderer) kill() {}
-func (n nilRenderer) write(_ string) {}
-func (n nilRenderer) repaint() {}
-func (n nilRenderer) clearScreen() {}
-func (n nilRenderer) altScreen() bool { return false }
-func (n nilRenderer) enterAltScreen() {}
-func (n nilRenderer) exitAltScreen() {}
-func (n nilRenderer) showCursor() {}
-func (n nilRenderer) hideCursor() {}
-func (n nilRenderer) enableMouseCellMotion() {}
-func (n nilRenderer) disableMouseCellMotion() {}
-func (n nilRenderer) enableMouseAllMotion() {}
-func (n nilRenderer) disableMouseAllMotion() {}
+func (n nilRenderer) start() {}
+func (n nilRenderer) stop() {}
+func (n nilRenderer) kill() {}
+func (n nilRenderer) write(_ string) {}
+func (n nilRenderer) repaint() {}
+func (n nilRenderer) clearScreen() {}
+func (n nilRenderer) altScreen() bool { return false }
+func (n nilRenderer) enterAltScreen() {}
+func (n nilRenderer) exitAltScreen() {}
+func (n nilRenderer) showCursor() {}
+func (n nilRenderer) hideCursor() {}
+func (n nilRenderer) enableMouseCellMotion() {}
+func (n nilRenderer) disableMouseCellMotion() {}
+func (n nilRenderer) enableMouseAllMotion() {}
+func (n nilRenderer) disableMouseAllMotion() {}
+func (n nilRenderer) enableBracketedPaste() {}
+func (n nilRenderer) disableBracketedPaste() {}
+func (n nilRenderer) enableMouseSGRMode() {}
+func (n nilRenderer) disableMouseSGRMode() {}
+func (n nilRenderer) bracketedPasteActive() bool { return false }
+func (n nilRenderer) setWindowTitle(_ string) {}
+func (n nilRenderer) reportFocus() bool { return false }
+func (n nilRenderer) enableReportFocus() {}
+func (n nilRenderer) disableReportFocus() {}
diff --git a/vendor/github.com/charmbracelet/bubbletea/options.go b/vendor/github.com/charmbracelet/bubbletea/options.go
index 30f7e6c5..c509353b 100644
--- a/vendor/github.com/charmbracelet/bubbletea/options.go
+++ b/vendor/github.com/charmbracelet/bubbletea/options.go
@@ -3,8 +3,7 @@ package tea
import (
"context"
"io"
-
- "github.com/muesli/termenv"
+ "sync/atomic"
)
// ProgramOption is used to set options when initializing a Program. Program can
@@ -28,11 +27,7 @@ func WithContext(ctx context.Context) ProgramOption {
// won't need to use this.
func WithOutput(output io.Writer) ProgramOption {
return func(p *Program) {
- if o, ok := output.(*termenv.Output); ok {
- p.output = o
- } else {
- p.output = termenv.NewOutput(output, termenv.WithColorCache(true))
- }
+ p.output = output
}
}
@@ -54,6 +49,23 @@ func WithInputTTY() ProgramOption {
}
}
+// WithEnvironment sets the environment variables that the program will use.
+// This useful when the program is running in a remote session (e.g. SSH) and
+// you want to pass the environment variables from the remote session to the
+// program.
+//
+// Example:
+//
+// var sess ssh.Session // ssh.Session is a type from the github.com/charmbracelet/ssh package
+// pty, _, _ := sess.Pty()
+// environ := append(sess.Environ(), "TERM="+pty.Term)
+// p := tea.NewProgram(model, tea.WithEnvironment(environ)
+func WithEnvironment(env []string) ProgramOption {
+ return func(p *Program) {
+ p.environ = env
+ }
+}
+
// WithoutSignalHandler disables the signal handler that Bubble Tea sets up for
// Programs. This is useful if you want to handle signals yourself.
func WithoutSignalHandler() ProgramOption {
@@ -76,7 +88,7 @@ func WithoutCatchPanics() ProgramOption {
// This is mainly useful for testing.
func WithoutSignals() ProgramOption {
return func(p *Program) {
- p.ignoreSignals = true
+ atomic.StoreUint32(&p.ignoreSignals, 1)
}
}
@@ -100,6 +112,13 @@ func WithAltScreen() ProgramOption {
}
}
+// WithoutBracketedPaste starts the program with bracketed paste disabled.
+func WithoutBracketedPaste() ProgramOption {
+ return func(p *Program) {
+ p.startupOptions |= withoutBracketedPaste
+ }
+}
+
// WithMouseCellMotion starts the program with the mouse enabled in "cell
// motion" mode.
//
@@ -107,6 +126,9 @@ func WithAltScreen() ProgramOption {
// movement events are also captured if a mouse button is pressed (i.e., drag
// events). Cell motion mode is better supported than all motion mode.
//
+// This will try to enable the mouse in extended mode (SGR), if that is not
+// supported by the terminal it will fall back to normal mode (X10).
+//
// To enable mouse cell motion once the program has already started running use
// the EnableMouseCellMotion command. To disable the mouse when the program is
// running use the DisableMouse command.
@@ -126,6 +148,9 @@ func WithMouseCellMotion() ProgramOption {
// wheel, and motion events, which are delivered regardless of whether a mouse
// button is pressed, effectively enabling support for hover interactions.
//
+// This will try to enable the mouse in extended mode (SGR), if that is not
+// supported by the terminal it will fall back to normal mode (X10).
+//
// Many modern terminals support this, but not all. If in doubt, use
// EnableMouseCellMotion instead.
//
@@ -160,6 +185,9 @@ func WithoutRenderer() ProgramOption {
//
// This feature is provisional, and may be changed or removed in a future version
// of this package.
+//
+// Deprecated: this incurs a noticeable performance hit. A future release will
+// optimize ANSI automatically without the performance penalty.
func WithANSICompressor() ProgramOption {
return func(p *Program) {
p.startupOptions |= withANSICompressor
@@ -200,3 +228,25 @@ func WithFilter(filter func(Model, Msg) Msg) ProgramOption {
p.filter = filter
}
}
+
+// WithFPS sets a custom maximum FPS at which the renderer should run. If
+// less than 1, the default value of 60 will be used. If over 120, the FPS
+// will be capped at 120.
+func WithFPS(fps int) ProgramOption {
+ return func(p *Program) {
+ p.fps = fps
+ }
+}
+
+// WithReportFocus enables reporting when the terminal gains and loses
+// focus. When this is enabled [FocusMsg] and [BlurMsg] messages will be sent
+// to your Update method.
+//
+// Note that while most terminals and multiplexers support focus reporting,
+// some do not. Also note that tmux needs to be configured to report focus
+// events.
+func WithReportFocus() ProgramOption {
+ return func(p *Program) {
+ p.startupOptions |= withReportFocus
+ }
+}
diff --git a/vendor/github.com/charmbracelet/bubbletea/renderer.go b/vendor/github.com/charmbracelet/bubbletea/renderer.go
index a6f41627..9eb7943b 100644
--- a/vendor/github.com/charmbracelet/bubbletea/renderer.go
+++ b/vendor/github.com/charmbracelet/bubbletea/renderer.go
@@ -40,16 +40,45 @@ type renderer interface {
// events if a mouse button is pressed (i.e., drag events).
enableMouseCellMotion()
- // DisableMouseCellMotion disables Mouse Cell Motion tracking.
+ // disableMouseCellMotion disables Mouse Cell Motion tracking.
disableMouseCellMotion()
- // EnableMouseAllMotion enables mouse click, release, wheel and motion
+ // enableMouseAllMotion enables mouse click, release, wheel and motion
// events, regardless of whether a mouse button is pressed. Many modern
// terminals support this, but not all.
enableMouseAllMotion()
- // DisableMouseAllMotion disables All Motion mouse tracking.
+ // disableMouseAllMotion disables All Motion mouse tracking.
disableMouseAllMotion()
+
+ // enableMouseSGRMode enables mouse extended mode (SGR).
+ enableMouseSGRMode()
+
+ // disableMouseSGRMode disables mouse extended mode (SGR).
+ disableMouseSGRMode()
+
+ // enableBracketedPaste enables bracketed paste, where characters
+ // inside the input are not interpreted when pasted as a whole.
+ enableBracketedPaste()
+
+ // disableBracketedPaste disables bracketed paste.
+ disableBracketedPaste()
+
+ // bracketedPasteActive reports whether bracketed paste mode is
+ // currently enabled.
+ bracketedPasteActive() bool
+
+ // setWindowTitle sets the terminal window title.
+ setWindowTitle(string)
+
+ // reportFocus returns whether reporting focus events is enabled.
+ reportFocus() bool
+
+ // enableReportFocus reports focus events to the program.
+ enableReportFocus()
+
+ // disableReportFocus stops reporting focus events to the program.
+ disableReportFocus()
}
// repaintMsg forces a full repaint.
diff --git a/vendor/github.com/charmbracelet/bubbletea/screen.go b/vendor/github.com/charmbracelet/bubbletea/screen.go
index 899db3d2..dfec48f0 100644
--- a/vendor/github.com/charmbracelet/bubbletea/screen.go
+++ b/vendor/github.com/charmbracelet/bubbletea/screen.go
@@ -116,6 +116,54 @@ func ShowCursor() Msg {
// this message with ShowCursor.
type showCursorMsg struct{}
+// EnableBracketedPaste is a special command that tells the Bubble Tea program
+// to accept bracketed paste input.
+//
+// Note that bracketed paste will be automatically disabled when the
+// program quits.
+func EnableBracketedPaste() Msg {
+ return enableBracketedPasteMsg{}
+}
+
+// enableBracketedPasteMsg in an internal message signals that
+// bracketed paste should be enabled. You can send an
+// enableBracketedPasteMsg with EnableBracketedPaste.
+type enableBracketedPasteMsg struct{}
+
+// DisableBracketedPaste is a special command that tells the Bubble Tea program
+// to accept bracketed paste input.
+//
+// Note that bracketed paste will be automatically disabled when the
+// program quits.
+func DisableBracketedPaste() Msg {
+ return disableBracketedPasteMsg{}
+}
+
+// disableBracketedPasteMsg in an internal message signals that
+// bracketed paste should be disabled. You can send an
+// disableBracketedPasteMsg with DisableBracketedPaste.
+type disableBracketedPasteMsg struct{}
+
+// enableReportFocusMsg is an internal message that signals to enable focus
+// reporting. You can send an enableReportFocusMsg with EnableReportFocus.
+type enableReportFocusMsg struct{}
+
+// EnableReportFocus is a special command that tells the Bubble Tea program to
+// report focus events to the program.
+func EnableReportFocus() Msg {
+ return enableReportFocusMsg{}
+}
+
+// disableReportFocusMsg is an internal message that signals to disable focus
+// reporting. You can send an disableReportFocusMsg with DisableReportFocus.
+type disableReportFocusMsg struct{}
+
+// DisableReportFocus is a special command that tells the Bubble Tea program to
+// stop reporting focus events to the program.
+func DisableReportFocus() Msg {
+ return disableReportFocusMsg{}
+}
+
// EnterAltScreen enters the alternate screen buffer, which consumes the entire
// terminal window. ExitAltScreen will return the terminal to its former state.
//
@@ -123,6 +171,8 @@ type showCursorMsg struct{}
func (p *Program) EnterAltScreen() {
if p.renderer != nil {
p.renderer.enterAltScreen()
+ } else {
+ p.startupOptions |= withAltScreen
}
}
@@ -132,6 +182,8 @@ func (p *Program) EnterAltScreen() {
func (p *Program) ExitAltScreen() {
if p.renderer != nil {
p.renderer.exitAltScreen()
+ } else {
+ p.startupOptions &^= withAltScreen
}
}
@@ -140,7 +192,11 @@ func (p *Program) ExitAltScreen() {
//
// Deprecated: Use the WithMouseCellMotion ProgramOption instead.
func (p *Program) EnableMouseCellMotion() {
- p.renderer.enableMouseCellMotion()
+ if p.renderer != nil {
+ p.renderer.enableMouseCellMotion()
+ } else {
+ p.startupOptions |= withMouseCellMotion
+ }
}
// DisableMouseCellMotion disables Mouse Cell Motion tracking. This will be
@@ -148,7 +204,11 @@ func (p *Program) EnableMouseCellMotion() {
//
// Deprecated: The mouse will automatically be disabled when the program exits.
func (p *Program) DisableMouseCellMotion() {
- p.renderer.disableMouseCellMotion()
+ if p.renderer != nil {
+ p.renderer.disableMouseCellMotion()
+ } else {
+ p.startupOptions &^= withMouseCellMotion
+ }
}
// EnableMouseAllMotion enables mouse click, release, wheel and motion events,
@@ -157,7 +217,11 @@ func (p *Program) DisableMouseCellMotion() {
//
// Deprecated: Use the WithMouseAllMotion ProgramOption instead.
func (p *Program) EnableMouseAllMotion() {
- p.renderer.enableMouseAllMotion()
+ if p.renderer != nil {
+ p.renderer.enableMouseAllMotion()
+ } else {
+ p.startupOptions |= withMouseAllMotion
+ }
}
// DisableMouseAllMotion disables All Motion mouse tracking. This will be
@@ -165,5 +229,20 @@ func (p *Program) EnableMouseAllMotion() {
//
// Deprecated: The mouse will automatically be disabled when the program exits.
func (p *Program) DisableMouseAllMotion() {
- p.renderer.disableMouseAllMotion()
+ if p.renderer != nil {
+ p.renderer.disableMouseAllMotion()
+ } else {
+ p.startupOptions &^= withMouseAllMotion
+ }
+}
+
+// SetWindowTitle sets the terminal window title.
+//
+// Deprecated: Use the SetWindowTitle command instead.
+func (p *Program) SetWindowTitle(title string) {
+ if p.renderer != nil {
+ p.renderer.setWindowTitle(title)
+ } else {
+ p.startupTitle = title
+ }
}
diff --git a/vendor/github.com/charmbracelet/bubbletea/signals_unix.go b/vendor/github.com/charmbracelet/bubbletea/signals_unix.go
index 826f58b9..40954038 100644
--- a/vendor/github.com/charmbracelet/bubbletea/signals_unix.go
+++ b/vendor/github.com/charmbracelet/bubbletea/signals_unix.go
@@ -1,5 +1,5 @@
-//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || aix
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris aix
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || aix || zos
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris aix zos
package tea
diff --git a/vendor/github.com/charmbracelet/bubbletea/standard_renderer.go b/vendor/github.com/charmbracelet/bubbletea/standard_renderer.go
index 0ab9473d..45e8c82d 100644
--- a/vendor/github.com/charmbracelet/bubbletea/standard_renderer.go
+++ b/vendor/github.com/charmbracelet/bubbletea/standard_renderer.go
@@ -8,15 +8,15 @@ import (
"sync"
"time"
+ "github.com/charmbracelet/x/ansi"
"github.com/muesli/ansi/compressor"
- "github.com/muesli/reflow/truncate"
- "github.com/muesli/termenv"
)
const (
// defaultFramerate specifies the maximum interval at which we should
// update the view.
- defaultFramerate = time.Second / 60
+ defaultFPS = 60
+ maxFPS = 120
)
// standardRenderer is a framerate-based terminal renderer, updating the view
@@ -26,7 +26,7 @@ const (
// to exclude ranges of lines, allowing them to be written to directly.
type standardRenderer struct {
mtx *sync.Mutex
- out *termenv.Output
+ out io.Writer
buf bytes.Buffer
queuedMessageLines []string
@@ -34,7 +34,9 @@ type standardRenderer struct {
ticker *time.Ticker
done chan struct{}
lastRender string
+ lastRenderedLines []string
linesRendered int
+ altLinesRendered int
useANSICompressor bool
once sync.Once
@@ -44,6 +46,12 @@ type standardRenderer struct {
// essentially whether or not we're using the full size of the terminal
altScreenActive bool
+ // whether or not we're currently using bracketed paste
+ bpActive bool
+
+ // reportingFocus whether reporting focus events is enabled
+ reportingFocus bool
+
// renderer dimensions; usually the size of the window
width int
height int
@@ -54,17 +62,22 @@ type standardRenderer struct {
// newRenderer creates a new renderer. Normally you'll want to initialize it
// with os.Stdout as the first argument.
-func newRenderer(out *termenv.Output, useANSICompressor bool) renderer {
+func newRenderer(out io.Writer, useANSICompressor bool, fps int) renderer {
+ if fps < 1 {
+ fps = defaultFPS
+ } else if fps > maxFPS {
+ fps = maxFPS
+ }
r := &standardRenderer{
out: out,
mtx: &sync.Mutex{},
done: make(chan struct{}),
- framerate: defaultFramerate,
+ framerate: time.Second / time.Duration(fps),
useANSICompressor: useANSICompressor,
queuedMessageLines: []string{},
}
if r.useANSICompressor {
- r.out = termenv.NewOutput(&compressor.Writer{Forward: out})
+ r.out = &compressor.Writer{Forward: out}
}
return r
}
@@ -99,15 +112,22 @@ func (r *standardRenderer) stop() {
r.mtx.Lock()
defer r.mtx.Unlock()
- r.out.ClearLine()
+ r.execute(ansi.EraseEntireLine)
+ // Move the cursor back to the beginning of the line
+ r.execute("\r")
if r.useANSICompressor {
- if w, ok := r.out.TTY().(io.WriteCloser); ok {
+ if w, ok := r.out.(io.WriteCloser); ok {
_ = w.Close()
}
}
}
+// execute writes a sequence to the terminal.
+func (r *standardRenderer) execute(seq string) {
+ _, _ = io.WriteString(r.out, seq)
+}
+
// kill halts the renderer. The final frame will not be rendered.
func (r *standardRenderer) kill() {
// Stop the renderer before acquiring the mutex to avoid a deadlock.
@@ -118,7 +138,9 @@ func (r *standardRenderer) kill() {
r.mtx.Lock()
defer r.mtx.Unlock()
- r.out.ClearLine()
+ r.execute(ansi.EraseEntireLine)
+ // Move the cursor back to the beginning of the line
+ r.execute("\r")
}
// listen waits for ticks on the ticker, or a signal to stop the renderer.
@@ -141,13 +163,19 @@ func (r *standardRenderer) flush() {
defer r.mtx.Unlock()
if r.buf.Len() == 0 || r.buf.String() == r.lastRender {
- // Nothing to do
+ // Nothing to do.
return
}
- // Output buffer
+ // Output buffer.
buf := &bytes.Buffer{}
- out := termenv.NewOutput(buf)
+
+ // Moving to the beginning of the section, that we rendered.
+ if r.altScreenActive {
+ buf.WriteString(ansi.CursorHomePosition)
+ } else if r.linesRendered > 1 {
+ buf.WriteString(ansi.CursorUp(r.linesRendered - 1))
+ }
newLines := strings.Split(r.buf.String(), "\n")
@@ -159,84 +187,87 @@ func (r *standardRenderer) flush() {
newLines = newLines[len(newLines)-r.height:]
}
- numLinesThisFlush := len(newLines)
- oldLines := strings.Split(r.lastRender, "\n")
- skipLines := make(map[int]struct{})
flushQueuedMessages := len(r.queuedMessageLines) > 0 && !r.altScreenActive
- // Add any queued messages to this render
if flushQueuedMessages {
- newLines = append(r.queuedMessageLines, newLines...)
+ // Dump the lines we've queued up for printing.
+ for _, line := range r.queuedMessageLines {
+ if ansi.StringWidth(line) < r.width {
+ // We only erase the rest of the line when the line is shorter than
+ // the width of the terminal. When the cursor reaches the end of
+ // the line, any escape sequences that follow will only affect the
+ // last cell of the line.
+
+ // Removing previously rendered content at the end of line.
+ line = line + ansi.EraseLineRight
+ }
+
+ _, _ = buf.WriteString(line)
+ _, _ = buf.WriteString("\r\n")
+ }
+ // Clear the queued message lines.
r.queuedMessageLines = []string{}
}
- // Clear any lines we painted in the last render.
- if r.linesRendered > 0 {
- for i := r.linesRendered - 1; i > 0; i-- {
- // If the number of lines we want to render hasn't increased and
- // new line is the same as the old line we can skip rendering for
- // this line as a performance optimization.
- if (len(newLines) <= len(oldLines)) && (len(newLines) > i && len(oldLines) > i) && (newLines[i] == oldLines[i]) {
- skipLines[i] = struct{}{}
- } else if _, exists := r.ignoreLines[i]; !exists {
- out.ClearLine()
- }
+ // Paint new lines.
+ for i := 0; i < len(newLines); i++ {
+ canSkip := !flushQueuedMessages && // Queuing messages triggers repaint -> we don't have access to previous frame content.
+ len(r.lastRenderedLines) > i && r.lastRenderedLines[i] == newLines[i] // Previously rendered line is the same.
- out.CursorUp(1)
+ if _, ignore := r.ignoreLines[i]; ignore || canSkip {
+ // Unless this is the last line, move the cursor down.
+ if i < len(newLines)-1 {
+ buf.WriteByte('\n')
+ }
+ continue
}
- if _, exists := r.ignoreLines[0]; !exists {
- // We need to return to the start of the line here to properly
- // erase it. Going back the entire width of the terminal will
- // usually be farther than we need to go, but terminal emulators
- // will stop the cursor at the start of the line as a rule.
- //
- // We use this sequence in particular because it's part of the ANSI
- // standard (whereas others are proprietary to, say, VT100/VT52).
- // If cursor previous line (ESC[ + + F) were better supported
- // we could use that above to eliminate this step.
- out.CursorBack(r.width)
- out.ClearLine()
+ if i == 0 && r.lastRender == "" {
+ // On first render, reset the cursor to the start of the line
+ // before writing anything.
+ buf.WriteByte('\r')
}
- }
- // Merge the set of lines we're skipping as a rendering optimization with
- // the set of lines we've explicitly asked the renderer to ignore.
- if r.ignoreLines != nil {
- for k, v := range r.ignoreLines {
- skipLines[k] = v
+ line := newLines[i]
+
+ // Truncate lines wider than the width of the window to avoid
+ // wrapping, which will mess up rendering. If we don't have the
+ // width of the window this will be ignored.
+ //
+ // Note that on Windows we only get the width of the window on
+ // program initialization, so after a resize this won't perform
+ // correctly (signal SIGWINCH is not supported on Windows).
+ if r.width > 0 {
+ line = ansi.Truncate(line, r.width, "")
}
- }
- // Paint new lines
- for i := 0; i < len(newLines); i++ {
- if _, skip := skipLines[i]; skip {
- // Unless this is the last line, move the cursor down.
- if i < len(newLines)-1 {
- out.CursorDown(1)
- }
- } else {
- line := newLines[i]
-
- // Truncate lines wider than the width of the window to avoid
- // wrapping, which will mess up rendering. If we don't have the
- // width of the window this will be ignored.
- //
- // Note that on Windows we only get the width of the window on
- // program initialization, so after a resize this won't perform
- // correctly (signal SIGWINCH is not supported on Windows).
- if r.width > 0 {
- line = truncate.String(line, uint(r.width))
- }
+ if ansi.StringWidth(line) < r.width {
+ // We only erase the rest of the line when the line is shorter than
+ // the width of the terminal. When the cursor reaches the end of
+ // the line, any escape sequences that follow will only affect the
+ // last cell of the line.
- _, _ = out.WriteString(line)
+ // Removing previously rendered content at the end of line.
+ line = line + ansi.EraseLineRight
+ }
- if i < len(newLines)-1 {
- _, _ = out.WriteString("\r\n")
- }
+ _, _ = buf.WriteString(line)
+
+ if i < len(newLines)-1 {
+ _, _ = buf.WriteString("\r\n")
}
}
- r.linesRendered = numLinesThisFlush
+
+ // Clearing left over content from last render.
+ if r.lastLinesRendered() > len(newLines) {
+ buf.WriteString(ansi.EraseScreenBelow)
+ }
+
+ if r.altScreenActive {
+ r.altLinesRendered = len(newLines)
+ } else {
+ r.linesRendered = len(newLines)
+ }
// Make sure the cursor is at the start of the last line to keep rendering
// behavior consistent.
@@ -244,16 +275,29 @@ func (r *standardRenderer) flush() {
// This case fixes a bug in macOS terminal. In other terminals the
// other case seems to do the job regardless of whether or not we're
// using the full terminal window.
- out.MoveCursor(r.linesRendered, 0)
+ buf.WriteString(ansi.CursorPosition(0, len(newLines)))
} else {
- out.CursorBack(r.width)
+ buf.WriteString(ansi.CursorBackward(r.width))
}
_, _ = r.out.Write(buf.Bytes())
r.lastRender = r.buf.String()
+
+ // Save previously rendered lines for comparison in the next render. If we
+ // don't do this, we can't skip rendering lines that haven't changed.
+ // See https://github.com/charmbracelet/bubbletea/pull/1233
+ r.lastRenderedLines = newLines
r.buf.Reset()
}
+// lastLinesRendered returns the number of lines rendered lastly.
+func (r *standardRenderer) lastLinesRendered() int {
+ if r.altScreenActive {
+ return r.altLinesRendered
+ }
+ return r.linesRendered
+}
+
// write writes to the internal buffer. The buffer will be outputted via the
// ticker which calls flush().
func (r *standardRenderer) write(s string) {
@@ -274,14 +318,15 @@ func (r *standardRenderer) write(s string) {
func (r *standardRenderer) repaint() {
r.lastRender = ""
+ r.lastRenderedLines = nil
}
func (r *standardRenderer) clearScreen() {
r.mtx.Lock()
defer r.mtx.Unlock()
- r.out.ClearScreen()
- r.out.MoveCursor(1, 1)
+ r.execute(ansi.EraseEntireScreen)
+ r.execute(ansi.CursorHomePosition)
r.repaint()
}
@@ -302,7 +347,7 @@ func (r *standardRenderer) enterAltScreen() {
}
r.altScreenActive = true
- r.out.AltScreen()
+ r.execute(ansi.SetAltScreenSaveCursorMode)
// Ensure that the terminal is cleared, even when it doesn't support
// alt screen (or alt screen support is disabled, like GNU screen by
@@ -310,18 +355,21 @@ func (r *standardRenderer) enterAltScreen() {
//
// Note: we can't use r.clearScreen() here because the mutex is already
// locked.
- r.out.ClearScreen()
- r.out.MoveCursor(1, 1)
+ r.execute(ansi.EraseEntireScreen)
+ r.execute(ansi.CursorHomePosition)
// cmd.exe and other terminals keep separate cursor states for the AltScreen
// and the main buffer. We have to explicitly reset the cursor visibility
// whenever we enter AltScreen.
if r.cursorHidden {
- r.out.HideCursor()
+ r.execute(ansi.HideCursor)
} else {
- r.out.ShowCursor()
+ r.execute(ansi.ShowCursor)
}
+ // Entering the alt screen resets the lines rendered count.
+ r.altLinesRendered = 0
+
r.repaint()
}
@@ -334,15 +382,15 @@ func (r *standardRenderer) exitAltScreen() {
}
r.altScreenActive = false
- r.out.ExitAltScreen()
+ r.execute(ansi.ResetAltScreenSaveCursorMode)
// cmd.exe and other terminals keep separate cursor states for the AltScreen
// and the main buffer. We have to explicitly reset the cursor visibility
// whenever we exit AltScreen.
if r.cursorHidden {
- r.out.HideCursor()
+ r.execute(ansi.HideCursor)
} else {
- r.out.ShowCursor()
+ r.execute(ansi.ShowCursor)
}
r.repaint()
@@ -353,7 +401,7 @@ func (r *standardRenderer) showCursor() {
defer r.mtx.Unlock()
r.cursorHidden = false
- r.out.ShowCursor()
+ r.execute(ansi.ShowCursor)
}
func (r *standardRenderer) hideCursor() {
@@ -361,35 +409,100 @@ func (r *standardRenderer) hideCursor() {
defer r.mtx.Unlock()
r.cursorHidden = true
- r.out.HideCursor()
+ r.execute(ansi.HideCursor)
}
func (r *standardRenderer) enableMouseCellMotion() {
r.mtx.Lock()
defer r.mtx.Unlock()
- r.out.EnableMouseCellMotion()
+ r.execute(ansi.SetButtonEventMouseMode)
}
func (r *standardRenderer) disableMouseCellMotion() {
r.mtx.Lock()
defer r.mtx.Unlock()
- r.out.DisableMouseCellMotion()
+ r.execute(ansi.ResetButtonEventMouseMode)
}
func (r *standardRenderer) enableMouseAllMotion() {
r.mtx.Lock()
defer r.mtx.Unlock()
- r.out.EnableMouseAllMotion()
+ r.execute(ansi.SetAnyEventMouseMode)
}
func (r *standardRenderer) disableMouseAllMotion() {
r.mtx.Lock()
defer r.mtx.Unlock()
- r.out.DisableMouseAllMotion()
+ r.execute(ansi.ResetAnyEventMouseMode)
+}
+
+func (r *standardRenderer) enableMouseSGRMode() {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ r.execute(ansi.SetSgrExtMouseMode)
+}
+
+func (r *standardRenderer) disableMouseSGRMode() {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ r.execute(ansi.ResetSgrExtMouseMode)
+}
+
+func (r *standardRenderer) enableBracketedPaste() {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ r.execute(ansi.SetBracketedPasteMode)
+ r.bpActive = true
+}
+
+func (r *standardRenderer) disableBracketedPaste() {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ r.execute(ansi.ResetBracketedPasteMode)
+ r.bpActive = false
+}
+
+func (r *standardRenderer) bracketedPasteActive() bool {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ return r.bpActive
+}
+
+func (r *standardRenderer) enableReportFocus() {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ r.execute(ansi.SetFocusEventMode)
+ r.reportingFocus = true
+}
+
+func (r *standardRenderer) disableReportFocus() {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ r.execute(ansi.ResetFocusEventMode)
+ r.reportingFocus = false
+}
+
+func (r *standardRenderer) reportFocus() bool {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ return r.reportingFocus
+}
+
+// setWindowTitle sets the terminal window title.
+func (r *standardRenderer) setWindowTitle(title string) {
+ r.execute(ansi.SetWindowTitle(title))
}
// setIgnoredLines specifies lines not to be touched by the standard Bubble Tea
@@ -397,7 +510,7 @@ func (r *standardRenderer) disableMouseAllMotion() {
func (r *standardRenderer) setIgnoredLines(from int, to int) {
// Lock if we're going to be clearing some lines since we don't want
// anything jacking our cursor.
- if r.linesRendered > 0 {
+ if r.lastLinesRendered() > 0 {
r.mtx.Lock()
defer r.mtx.Unlock()
}
@@ -410,17 +523,17 @@ func (r *standardRenderer) setIgnoredLines(from int, to int) {
}
// Erase ignored lines
- if r.linesRendered > 0 {
+ lastLinesRendered := r.lastLinesRendered()
+ if lastLinesRendered > 0 {
buf := &bytes.Buffer{}
- out := termenv.NewOutput(buf)
- for i := r.linesRendered - 1; i >= 0; i-- {
+ for i := lastLinesRendered - 1; i >= 0; i-- {
if _, exists := r.ignoreLines[i]; exists {
- out.ClearLine()
+ buf.WriteString(ansi.EraseEntireLine)
}
- out.CursorUp(1)
+ buf.WriteString(ansi.CUU1)
}
- out.MoveCursor(r.linesRendered, 0) // put cursor back
+ buf.WriteString(ansi.CursorPosition(0, lastLinesRendered)) // put cursor back
_, _ = r.out.Write(buf.Bytes())
}
}
@@ -450,21 +563,23 @@ func (r *standardRenderer) clearIgnoredLines() {
// use in high-performance rendering, such as a pager that could potentially
// be rendering very complicated ansi. In cases where the content is simpler
// standard Bubble Tea rendering should suffice.
+//
+// Deprecated: This option is deprecated and will be removed in a future
+// version of this package.
func (r *standardRenderer) insertTop(lines []string, topBoundary, bottomBoundary int) {
r.mtx.Lock()
defer r.mtx.Unlock()
buf := &bytes.Buffer{}
- out := termenv.NewOutput(buf)
- out.ChangeScrollingRegion(topBoundary, bottomBoundary)
- out.MoveCursor(topBoundary, 0)
- out.InsertLines(len(lines))
- _, _ = out.WriteString(strings.Join(lines, "\r\n"))
- out.ChangeScrollingRegion(0, r.height)
+ buf.WriteString(ansi.SetTopBottomMargins(topBoundary, bottomBoundary))
+ buf.WriteString(ansi.CursorPosition(0, topBoundary))
+ buf.WriteString(ansi.InsertLine(len(lines)))
+ _, _ = buf.WriteString(strings.Join(lines, "\r\n"))
+ buf.WriteString(ansi.SetTopBottomMargins(0, r.height))
// Move cursor back to where the main rendering routine expects it to be
- out.MoveCursor(r.linesRendered, 0)
+ buf.WriteString(ansi.CursorPosition(0, r.lastLinesRendered()))
_, _ = r.out.Write(buf.Bytes())
}
@@ -478,20 +593,22 @@ func (r *standardRenderer) insertTop(lines []string, topBoundary, bottomBoundary
// See note in insertTop() for caveats, how this function only makes sense for
// full-window applications, and how it differs from the normal way we do
// rendering in Bubble Tea.
+//
+// Deprecated: This option is deprecated and will be removed in a future
+// version of this package.
func (r *standardRenderer) insertBottom(lines []string, topBoundary, bottomBoundary int) {
r.mtx.Lock()
defer r.mtx.Unlock()
buf := &bytes.Buffer{}
- out := termenv.NewOutput(buf)
- out.ChangeScrollingRegion(topBoundary, bottomBoundary)
- out.MoveCursor(bottomBoundary, 0)
- _, _ = out.WriteString("\r\n" + strings.Join(lines, "\r\n"))
- out.ChangeScrollingRegion(0, r.height)
+ buf.WriteString(ansi.SetTopBottomMargins(topBoundary, bottomBoundary))
+ buf.WriteString(ansi.CursorPosition(0, bottomBoundary))
+ _, _ = buf.WriteString("\r\n" + strings.Join(lines, "\r\n"))
+ buf.WriteString(ansi.SetTopBottomMargins(0, r.height))
// Move cursor back to where the main rendering routine expects it to be
- out.MoveCursor(r.linesRendered, 0)
+ buf.WriteString(ansi.CursorPosition(0, r.lastLinesRendered()))
_, _ = r.out.Write(buf.Bytes())
}
@@ -563,6 +680,8 @@ type syncScrollAreaMsg struct {
// should also be called on resize (WindowSizeMsg).
//
// For high-performance, scroll-based rendering only.
+//
+// Deprecated: This option will be removed in a future version of this package.
func SyncScrollArea(lines []string, topBoundary int, bottomBoundary int) Cmd {
return func() Msg {
return syncScrollAreaMsg{
@@ -579,6 +698,8 @@ type clearScrollAreaMsg struct{}
// those lines to the main rendering routine.
//
// For high-performance, scroll-based rendering only.
+//
+// Deprecated: This option will be removed in a future version of this package.
func ClearScrollArea() Msg {
return clearScrollAreaMsg{}
}
@@ -594,6 +715,8 @@ type scrollUpMsg struct {
// from view.
//
// For high-performance, scroll-based rendering only.
+//
+// Deprecated: This option will be removed in a future version of this package.
func ScrollUp(newLines []string, topBoundary, bottomBoundary int) Cmd {
return func() Msg {
return scrollUpMsg{
@@ -615,6 +738,8 @@ type scrollDownMsg struct {
// disappear from view.
//
// For high-performance, scroll-based rendering only.
+//
+// Deprecated: This option will be removed in a future version of this package.
func ScrollDown(newLines []string, topBoundary, bottomBoundary int) Cmd {
return func() Msg {
return scrollDownMsg{
diff --git a/vendor/github.com/charmbracelet/bubbletea/tea.go b/vendor/github.com/charmbracelet/bubbletea/tea.go
index 2e024ed6..0bc915e5 100644
--- a/vendor/github.com/charmbracelet/bubbletea/tea.go
+++ b/vendor/github.com/charmbracelet/bubbletea/tea.go
@@ -16,20 +16,24 @@ import (
"io"
"os"
"os/signal"
+ "runtime"
"runtime/debug"
"sync"
+ "sync/atomic"
"syscall"
- "github.com/containerd/console"
- isatty "github.com/mattn/go-isatty"
+ "github.com/charmbracelet/x/term"
"github.com/muesli/cancelreader"
- "github.com/muesli/termenv"
"golang.org/x/sync/errgroup"
)
-// ErrProgramKilled is returned by [Program.Run] when the program got killed.
+// ErrProgramKilled is returned by [Program.Run] when the program gets killed.
var ErrProgramKilled = errors.New("program was killed")
+// ErrInterrupted is returned by [Program.Run] when the program get a SIGINT
+// signal, or when it receives a [InterruptMsg].
+var ErrInterrupted = errors.New("program was interrupted")
+
// Msg contain data from the result of a IO operation. Msgs trigger the update
// function and, henceforth, the UI.
type Msg interface{}
@@ -58,8 +62,6 @@ type Model interface {
// update function.
type Cmd func() Msg
-type handlers []chan struct{}
-
type inputType int
const (
@@ -82,7 +84,7 @@ func (i inputType) String() string {
// generally set with ProgramOptions.
//
// The options here are treated as bits.
-type startupOptions byte
+type startupOptions int16
func (s startupOptions) has(option startupOptions) bool {
return s&option != 0
@@ -94,22 +96,55 @@ const (
withMouseAllMotion
withANSICompressor
withoutSignalHandler
-
// Catching panics is incredibly useful for restoring the terminal to a
// usable state after a panic occurs. When this is set, Bubble Tea will
// recover from panics, print the stack trace, and disable raw mode. This
// feature is on by default.
withoutCatchPanics
+ withoutBracketedPaste
+ withReportFocus
)
+// channelHandlers manages the series of channels returned by various processes.
+// It allows us to wait for those processes to terminate before exiting the
+// program.
+type channelHandlers []chan struct{}
+
+// Adds a channel to the list of handlers. We wait for all handlers to terminate
+// gracefully on shutdown.
+func (h *channelHandlers) add(ch chan struct{}) {
+ *h = append(*h, ch)
+}
+
+// shutdown waits for all handlers to terminate.
+func (h channelHandlers) shutdown() {
+ var wg sync.WaitGroup
+ for _, ch := range h {
+ wg.Add(1)
+ go func(ch chan struct{}) {
+ <-ch
+ wg.Done()
+ }(ch)
+ }
+ wg.Wait()
+}
+
// Program is a terminal user interface.
type Program struct {
initialModel Model
+ // handlers is a list of channels that need to be waited on before the
+ // program can exit.
+ handlers channelHandlers
+
// Configuration options that will set as the program is initializing,
// treated as bits. These options can be set via various ProgramOptions.
startupOptions startupOptions
+ // startupTitle is the title that will be set on the terminal when the
+ // program starts.
+ startupTitle string
+
inputType inputType
ctx context.Context
@@ -120,30 +155,38 @@ type Program struct {
finished chan struct{}
// where to send output, this will usually be os.Stdout.
- output *termenv.Output
- restoreOutput func() error
- renderer renderer
+ output io.Writer
+ // ttyOutput is null if output is not a TTY.
+ ttyOutput term.File
+ previousOutputState *term.State
+ renderer renderer
+
+ // the environment variables for the program, defaults to os.Environ().
+ environ []string
// where to read inputs from, this will usually be os.Stdin.
- input io.Reader
- cancelReader cancelreader.CancelReader
- readLoopDone chan struct{}
- console console.Console
+ input io.Reader
+ // ttyInput is null if input is not a TTY.
+ ttyInput term.File
+ previousTtyInputState *term.State
+ cancelReader cancelreader.CancelReader
+ readLoopDone chan struct{}
// was the altscreen active before releasing the terminal?
altScreenWasActive bool
- ignoreSignals bool
+ ignoreSignals uint32
- // Stores the original reference to stdin for cases where input is not a
- // TTY on windows and we've automatically opened CONIN$ to receive input.
- // When the program exits this will be restored.
- //
- // Lint ignore note: the linter will find false positive on unix systems
- // as this value only comes into play on Windows, hence the ignore comment
- // below.
- windowsStdin *os.File //nolint:golint,structcheck,unused
+ bpWasActive bool // was the bracketed paste mode active before releasing the terminal?
+ reportFocus bool // was focus reporting active before releasing the terminal?
filter func(Model, Msg) Msg
+
+ // fps is the frames per second we should set on the renderer, if
+ // applicable,
+ fps int
+
+ // mouseMode is true if the program should enable mouse mode on Windows.
+ mouseMode bool
}
// Quit is a special command that tells the Bubble Tea program to exit.
@@ -151,10 +194,41 @@ func Quit() Msg {
return QuitMsg{}
}
-// QuitMsg signals that the program should quit. You can send a QuitMsg with
-// Quit.
+// QuitMsg signals that the program should quit. You can send a [QuitMsg] with
+// [Quit].
type QuitMsg struct{}
+// Suspend is a special command that tells the Bubble Tea program to suspend.
+func Suspend() Msg {
+ return SuspendMsg{}
+}
+
+// SuspendMsg signals the program should suspend.
+// This usually happens when ctrl+z is pressed on common programs, but since
+// bubbletea puts the terminal in raw mode, we need to handle it in a
+// per-program basis.
+//
+// You can send this message with [Suspend()].
+type SuspendMsg struct{}
+
+// ResumeMsg can be listen to to do something once a program is resumed back
+// from a suspend state.
+type ResumeMsg struct{}
+
+// InterruptMsg signals the program should suspend.
+// This usually happens when ctrl+c is pressed on common programs, but since
+// bubbletea puts the terminal in raw mode, we need to handle it in a
+// per-program basis.
+//
+// You can send this message with [Interrupt()].
+type InterruptMsg struct{}
+
+// Interrupt is a special command that tells the Bubble Tea program to
+// interrupt.
+func Interrupt() Msg {
+ return InterruptMsg{}
+}
+
// NewProgram creates a new Program.
func NewProgram(model Model, opts ...ProgramOption) *Program {
p := &Program{
@@ -177,13 +251,13 @@ func NewProgram(model Model, opts ...ProgramOption) *Program {
// if no output was set, set it to stdout
if p.output == nil {
- p.output = termenv.DefaultOutput()
-
- // cache detected color values
- termenv.WithColorCache(true)(p.output)
+ p.output = os.Stdout
}
- p.restoreOutput, _ = termenv.EnableVirtualTerminalProcessing(p.output)
+ // if no environment was set, set it to os.Environ()
+ if p.environ == nil {
+ p.environ = os.Environ()
+ }
return p
}
@@ -212,9 +286,14 @@ func (p *Program) handleSignals() chan struct{} {
case <-p.ctx.Done():
return
- case <-sig:
- if !p.ignoreSignals {
- p.msgs <- QuitMsg{}
+ case s := <-sig:
+ if atomic.LoadUint32(&p.ignoreSignals) == 0 {
+ switch s {
+ case syscall.SIGINT:
+ p.msgs <- InterruptMsg{}
+ default:
+ p.msgs <- QuitMsg{}
+ }
return
}
}
@@ -228,7 +307,7 @@ func (p *Program) handleSignals() chan struct{} {
func (p *Program) handleResize() chan struct{} {
ch := make(chan struct{})
- if f, ok := p.output.TTY().(*os.File); ok && isatty.IsTerminal(f.Fd()) {
+ if p.ttyOutput != nil {
// Get the initial terminal size and send it to the program.
go p.checkResize()
@@ -265,6 +344,11 @@ func (p *Program) handleCommands(cmds chan Cmd) chan struct{} {
// possible to cancel them so we'll have to leak the goroutine
// until Cmd returns.
go func() {
+ // Recover from panics.
+ if !p.startupOptions.has(withoutCatchPanics) {
+ defer p.recoverFromPanic()
+ }
+
msg := cmd() // this can be long.
p.Send(msg)
}()
@@ -275,6 +359,12 @@ func (p *Program) handleCommands(cmds chan Cmd) chan struct{} {
return ch
}
+func (p *Program) disableMouse() {
+ p.renderer.disableMouseCellMotion()
+ p.renderer.disableMouseAllMotion()
+ p.renderer.disableMouseSGRMode()
+}
+
// eventLoop is the central message loop. It receives and handles the default
// Bubble Tea messages, update the model and triggers redraws.
func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) {
@@ -300,6 +390,14 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) {
case QuitMsg:
return model, nil
+ case InterruptMsg:
+ return model, ErrInterrupted
+
+ case SuspendMsg:
+ if suspendSupported {
+ p.suspend()
+ }
+
case clearScreenMsg:
p.renderer.clearScreen()
@@ -309,15 +407,34 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) {
case exitAltScreenMsg:
p.renderer.exitAltScreen()
- case enableMouseCellMotionMsg:
- p.renderer.enableMouseCellMotion()
-
- case enableMouseAllMotionMsg:
- p.renderer.enableMouseAllMotion()
+ case enableMouseCellMotionMsg, enableMouseAllMotionMsg:
+ switch msg.(type) {
+ case enableMouseCellMotionMsg:
+ p.renderer.enableMouseCellMotion()
+ case enableMouseAllMotionMsg:
+ p.renderer.enableMouseAllMotion()
+ }
+ // mouse mode (1006) is a no-op if the terminal doesn't support it.
+ p.renderer.enableMouseSGRMode()
+
+ // XXX: This is used to enable mouse mode on Windows. We need
+ // to reinitialize the cancel reader to get the mouse events to
+ // work.
+ if runtime.GOOS == "windows" && !p.mouseMode {
+ p.mouseMode = true
+ p.initCancelReader(true) //nolint:errcheck
+ }
case disableMouseMsg:
- p.renderer.disableMouseCellMotion()
- p.renderer.disableMouseAllMotion()
+ p.disableMouse()
+
+ // XXX: On Windows, mouse mode is enabled on the input reader
+ // level. We need to instruct the input reader to stop reading
+ // mouse events.
+ if runtime.GOOS == "windows" && p.mouseMode {
+ p.mouseMode = false
+ p.initCancelReader(true) //nolint:errcheck
+ }
case showCursorMsg:
p.renderer.showCursor()
@@ -325,6 +442,18 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) {
case hideCursorMsg:
p.renderer.hideCursor()
+ case enableBracketedPasteMsg:
+ p.renderer.enableBracketedPaste()
+
+ case disableBracketedPasteMsg:
+ p.renderer.disableBracketedPaste()
+
+ case enableReportFocusMsg:
+ p.renderer.enableReportFocus()
+
+ case disableReportFocusMsg:
+ p.renderer.disableReportFocus()
+
case execMsg:
// NB: this blocks.
p.exec(msg.cmd, msg.fn)
@@ -362,6 +491,12 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) {
p.Send(msg)
}
}()
+
+ case setWindowTitleMsg:
+ p.SetWindowTitle(string(msg))
+
+ case windowSizeMsg:
+ go p.checkResize()
}
// Process internal messages for the renderer.
@@ -381,7 +516,7 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) {
// terminated by either [Program.Quit], [Program.Kill], or its signal handler.
// Returns the final model.
func (p *Program) Run() (Model, error) {
- handlers := handlers{}
+ p.handlers = channelHandlers{}
cmds := make(chan Cmd)
p.errs = make(chan error)
p.finished = make(chan struct{}, 1)
@@ -398,11 +533,11 @@ func (p *Program) Run() (Model, error) {
// piped in or redirected to the application.
//
// To disable input entirely pass nil to the [WithInput] program option.
- f, isFile := p.input.(*os.File)
+ f, isFile := p.input.(term.File)
if !isFile {
break
}
- if isatty.IsTerminal(f.Fd()) {
+ if term.IsTerminal(f.Fd()) {
break
}
@@ -428,24 +563,17 @@ func (p *Program) Run() (Model, error) {
// Handle signals.
if !p.startupOptions.has(withoutSignalHandler) {
- handlers.add(p.handleSignals())
+ p.handlers.add(p.handleSignals())
}
// Recover from panics.
if !p.startupOptions.has(withoutCatchPanics) {
- defer func() {
- if r := recover(); r != nil {
- p.shutdown(true)
- fmt.Printf("Caught panic:\n\n%s\n\nRestoring terminal...\n\n", r)
- debug.PrintStack()
- return
- }
- }()
+ defer p.recoverFromPanic()
}
// If no renderer is set use the standard one.
if p.renderer == nil {
- p.renderer = newRenderer(p.output, p.startupOptions.has(withANSICompressor))
+ p.renderer = newRenderer(p.output, p.startupOptions.has(withANSICompressor), p.fps)
}
// Check if output is a TTY before entering raw mode, hiding the cursor and
@@ -455,20 +583,39 @@ func (p *Program) Run() (Model, error) {
}
// Honor program startup options.
+ if p.startupTitle != "" {
+ p.renderer.setWindowTitle(p.startupTitle)
+ }
if p.startupOptions&withAltScreen != 0 {
p.renderer.enterAltScreen()
}
+ if p.startupOptions&withoutBracketedPaste == 0 {
+ p.renderer.enableBracketedPaste()
+ }
if p.startupOptions&withMouseCellMotion != 0 {
p.renderer.enableMouseCellMotion()
+ p.renderer.enableMouseSGRMode()
} else if p.startupOptions&withMouseAllMotion != 0 {
p.renderer.enableMouseAllMotion()
+ p.renderer.enableMouseSGRMode()
}
+ // XXX: Should we enable mouse mode on Windows?
+ // This needs to happen before initializing the cancel and input reader.
+ p.mouseMode = p.startupOptions&withMouseCellMotion != 0 || p.startupOptions&withMouseAllMotion != 0
+
+ if p.startupOptions&withReportFocus != 0 {
+ p.renderer.enableReportFocus()
+ }
+
+ // Start the renderer.
+ p.renderer.start()
+
// Initialize the program.
model := p.initialModel
if initCmd := model.Init(); initCmd != nil {
ch := make(chan struct{})
- handlers.add(ch)
+ p.handlers.add(ch)
go func() {
defer close(ch)
@@ -480,50 +627,33 @@ func (p *Program) Run() (Model, error) {
}()
}
- // Start the renderer.
- p.renderer.start()
-
// Render the initial view.
p.renderer.write(model.View())
// Subscribe to user input.
if p.input != nil {
- if err := p.initCancelReader(); err != nil {
+ if err := p.initCancelReader(false); err != nil {
return model, err
}
}
// Handle resize events.
- handlers.add(p.handleResize())
+ p.handlers.add(p.handleResize())
// Process commands.
- handlers.add(p.handleCommands(cmds))
+ p.handlers.add(p.handleCommands(cmds))
// Run event loop, handle updates and draw.
model, err := p.eventLoop(model, cmds)
- killed := p.ctx.Err() != nil
- if killed {
- err = ErrProgramKilled
- } else {
+ killed := p.ctx.Err() != nil || err != nil
+ if killed && err == nil {
+ err = fmt.Errorf("%w: %s", ErrProgramKilled, p.ctx.Err())
+ }
+ if err == nil {
// Ensure we rendered the final state of the model.
p.renderer.write(model.View())
}
- // Tear down.
- p.cancel()
-
- // Check if the cancel reader has been setup before waiting and closing.
- if p.cancelReader != nil {
- // Wait for input loop to finish.
- if p.cancelReader.Cancel() {
- p.waitForReadLoop()
- }
- _ = p.cancelReader.Close()
- }
-
- // Wait for all handlers to finish.
- handlers.shutdown()
-
// Restore terminal state.
p.shutdown(killed)
@@ -578,7 +708,7 @@ func (p *Program) Quit() {
// The final render that you would normally see when quitting will be skipped.
// [program.Run] returns a [ErrProgramKilled] error.
func (p *Program) Kill() {
- p.cancel()
+ p.shutdown(true)
}
// Wait waits/blocks until the underlying Program finished shutting down.
@@ -589,6 +719,22 @@ func (p *Program) Wait() {
// shutdown performs operations to free up resources and restore the terminal
// to its original state.
func (p *Program) shutdown(kill bool) {
+ p.cancel()
+
+ // Wait for all handlers to finish.
+ p.handlers.shutdown()
+
+ // Check if the cancel reader has been setup before waiting and closing.
+ if p.cancelReader != nil {
+ // Wait for input loop to finish.
+ if p.cancelReader.Cancel() {
+ if !kill {
+ p.waitForReadLoop()
+ }
+ }
+ _ = p.cancelReader.Close()
+ }
+
if p.renderer != nil {
if kill {
p.renderer.kill()
@@ -598,24 +744,38 @@ func (p *Program) shutdown(kill bool) {
}
_ = p.restoreTerminalState()
- if p.restoreOutput != nil {
- _ = p.restoreOutput()
+ if !kill {
+ p.finished <- struct{}{}
+ }
+}
+
+// recoverFromPanic recovers from a panic, prints the stack trace, and restores
+// the terminal to a usable state.
+func (p *Program) recoverFromPanic() {
+ if r := recover(); r != nil {
+ p.shutdown(true)
+ fmt.Printf("Caught panic:\n\n%s\n\nRestoring terminal...\n\n", r)
+ debug.PrintStack()
}
- p.finished <- struct{}{}
}
// ReleaseTerminal restores the original terminal state and cancels the input
// reader. You can return control to the Program with RestoreTerminal.
func (p *Program) ReleaseTerminal() error {
- p.ignoreSignals = true
- p.cancelReader.Cancel()
+ atomic.StoreUint32(&p.ignoreSignals, 1)
+ if p.cancelReader != nil {
+ p.cancelReader.Cancel()
+ }
+
p.waitForReadLoop()
if p.renderer != nil {
p.renderer.stop()
+ p.altScreenWasActive = p.renderer.altScreen()
+ p.bpWasActive = p.renderer.bracketedPasteActive()
+ p.reportFocus = p.renderer.reportFocus()
}
- p.altScreenWasActive = p.renderer.altScreen()
return p.restoreTerminalState()
}
@@ -623,15 +783,14 @@ func (p *Program) ReleaseTerminal() error {
// terminal to the former state when the program was running, and repaints.
// Use it to reinitialize a Program after running ReleaseTerminal.
func (p *Program) RestoreTerminal() error {
- p.ignoreSignals = false
+ atomic.StoreUint32(&p.ignoreSignals, 0)
if err := p.initTerminal(); err != nil {
return err
}
- if err := p.initCancelReader(); err != nil {
+ if err := p.initCancelReader(false); err != nil {
return err
}
-
if p.altScreenWasActive {
p.renderer.enterAltScreen()
} else {
@@ -641,6 +800,12 @@ func (p *Program) RestoreTerminal() error {
if p.renderer != nil {
p.renderer.start()
}
+ if p.bpWasActive {
+ p.renderer.enableBracketedPaste()
+ }
+ if p.reportFocus {
+ p.renderer.enableReportFocus()
+ }
// If the output is a terminal, it may have been resized while another
// process was at the foreground, in which case we may not have received
@@ -674,22 +839,3 @@ func (p *Program) Printf(template string, args ...interface{}) {
messageBody: fmt.Sprintf(template, args...),
}
}
-
-// Adds a handler to the list of handlers. We wait for all handlers to terminate
-// gracefully on shutdown.
-func (h *handlers) add(ch chan struct{}) {
- *h = append(*h, ch)
-}
-
-// Shutdown waits for all handlers to terminate.
-func (h handlers) shutdown() {
- var wg sync.WaitGroup
- for _, ch := range h {
- wg.Add(1)
- go func(ch chan struct{}) {
- <-ch
- wg.Done()
- }(ch)
- }
- wg.Wait()
-}
diff --git a/vendor/github.com/charmbracelet/bubbletea/tea_init.go b/vendor/github.com/charmbracelet/bubbletea/tea_init.go
new file mode 100644
index 00000000..19b6cc39
--- /dev/null
+++ b/vendor/github.com/charmbracelet/bubbletea/tea_init.go
@@ -0,0 +1,22 @@
+package tea
+
+import (
+ "github.com/charmbracelet/lipgloss"
+)
+
+func init() {
+ // XXX: This is a workaround to make assure that Lip Gloss and Termenv
+ // query the terminal before any Bubble Tea Program runs and acquires the
+ // terminal. Without this, Programs that use Lip Gloss/Termenv might hang
+ // while waiting for a a [termenv.OSCTimeout] while querying the terminal
+ // for its background/foreground colors.
+ //
+ // This happens because Bubble Tea acquires the terminal before termenv
+ // reads any responses.
+ //
+ // Note that this will only affect programs running on the default IO i.e.
+ // [os.Stdout] and [os.Stdin].
+ //
+ // This workaround will be removed in v2.
+ _ = lipgloss.HasDarkBackground()
+}
diff --git a/vendor/github.com/charmbracelet/bubbletea/tty.go b/vendor/github.com/charmbracelet/bubbletea/tty.go
index 3ab6639b..9490faca 100644
--- a/vendor/github.com/charmbracelet/bubbletea/tty.go
+++ b/vendor/github.com/charmbracelet/bubbletea/tty.go
@@ -2,26 +2,34 @@ package tea
import (
"errors"
+ "fmt"
"io"
- "os"
"time"
- isatty "github.com/mattn/go-isatty"
+ "github.com/charmbracelet/x/term"
"github.com/muesli/cancelreader"
- "golang.org/x/term"
)
+func (p *Program) suspend() {
+ if err := p.ReleaseTerminal(); err != nil {
+ // If we can't release input, abort.
+ return
+ }
+
+ suspendProcess()
+
+ _ = p.RestoreTerminal()
+ go p.Send(ResumeMsg{})
+}
+
func (p *Program) initTerminal() error {
- err := p.initInput()
- if err != nil {
- return err
+ if _, ok := p.renderer.(*nilRenderer); ok {
+ // No need to initialize the terminal if we're not rendering
+ return nil
}
- if p.console != nil {
- err = p.console.SetRaw()
- if err != nil {
- return err
- }
+ if err := p.initInput(); err != nil {
+ return err
}
p.renderer.hideCursor()
@@ -32,34 +40,51 @@ func (p *Program) initTerminal() error {
// Bubble Tea program.
func (p *Program) restoreTerminalState() error {
if p.renderer != nil {
+ p.renderer.disableBracketedPaste()
p.renderer.showCursor()
- p.renderer.disableMouseCellMotion()
- p.renderer.disableMouseAllMotion()
+ p.disableMouse()
+
+ if p.renderer.reportFocus() {
+ p.renderer.disableReportFocus()
+ }
if p.renderer.altScreen() {
p.renderer.exitAltScreen()
// give the terminal a moment to catch up
- time.Sleep(time.Millisecond * 10)
+ time.Sleep(time.Millisecond * 10) //nolint:gomnd
}
}
- if p.console != nil {
- err := p.console.Reset()
- if err != nil {
- return err
+ return p.restoreInput()
+}
+
+// restoreInput restores the tty input to its original state.
+func (p *Program) restoreInput() error {
+ if p.ttyInput != nil && p.previousTtyInputState != nil {
+ if err := term.Restore(p.ttyInput.Fd(), p.previousTtyInputState); err != nil {
+ return fmt.Errorf("error restoring console: %w", err)
}
}
-
- return p.restoreInput()
+ if p.ttyOutput != nil && p.previousOutputState != nil {
+ if err := term.Restore(p.ttyOutput.Fd(), p.previousOutputState); err != nil {
+ return fmt.Errorf("error restoring console: %w", err)
+ }
+ }
+ return nil
}
// initCancelReader (re)commences reading inputs.
-func (p *Program) initCancelReader() error {
+func (p *Program) initCancelReader(cancel bool) error {
+ if cancel && p.cancelReader != nil {
+ p.cancelReader.Cancel()
+ p.waitForReadLoop()
+ }
+
var err error
- p.cancelReader, err = cancelreader.NewReader(p.input)
+ p.cancelReader, err = newInputReader(p.input, p.mouseMode)
if err != nil {
- return err
+ return fmt.Errorf("error creating cancelreader: %w", err)
}
p.readLoopDone = make(chan struct{})
@@ -71,25 +96,11 @@ func (p *Program) initCancelReader() error {
func (p *Program) readLoop() {
defer close(p.readLoopDone)
- for {
- if p.ctx.Err() != nil {
- return
- }
-
- msgs, err := readInputs(p.cancelReader)
- if err != nil {
- if !errors.Is(err, io.EOF) && !errors.Is(err, cancelreader.ErrCanceled) {
- select {
- case <-p.ctx.Done():
- case p.errs <- err:
- }
- }
-
- return
- }
-
- for _, msg := range msgs {
- p.msgs <- msg
+ err := readInputs(p.ctx, p.msgs, p.cancelReader)
+ if !errors.Is(err, io.EOF) && !errors.Is(err, cancelreader.ErrCanceled) {
+ select {
+ case <-p.ctx.Done():
+ case p.errs <- err:
}
}
}
@@ -98,7 +109,7 @@ func (p *Program) readLoop() {
func (p *Program) waitForReadLoop() {
select {
case <-p.readLoopDone:
- case <-time.After(500 * time.Millisecond):
+ case <-time.After(500 * time.Millisecond): //nolint:gomnd
// The read loop hangs, which means the input
// cancelReader's cancel function has returned true even
// though it was not able to cancel the read.
@@ -108,13 +119,12 @@ func (p *Program) waitForReadLoop() {
// checkResize detects the current size of the output and informs the program
// via a WindowSizeMsg.
func (p *Program) checkResize() {
- f, ok := p.output.TTY().(*os.File)
- if !ok || !isatty.IsTerminal(f.Fd()) {
+ if p.ttyOutput == nil {
// can't query window size
return
}
- w, h, err := term.GetSize(int(f.Fd()))
+ w, h, err := term.GetSize(p.ttyOutput.Fd())
if err != nil {
select {
case <-p.ctx.Done():
diff --git a/vendor/github.com/charmbracelet/bubbletea/tty_unix.go b/vendor/github.com/charmbracelet/bubbletea/tty_unix.go
index b6f5ffdf..5cbb4fe1 100644
--- a/vendor/github.com/charmbracelet/bubbletea/tty_unix.go
+++ b/vendor/github.com/charmbracelet/bubbletea/tty_unix.go
@@ -1,42 +1,49 @@
-//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || aix
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris aix
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || aix || zos
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris aix zos
package tea
import (
+ "fmt"
"os"
+ "os/signal"
+ "syscall"
- "github.com/containerd/console"
+ "github.com/charmbracelet/x/term"
)
-func (p *Program) initInput() error {
- // If input's a file, use console to manage it
- if f, ok := p.input.(*os.File); ok {
- c, err := console.ConsoleFromFile(f)
+func (p *Program) initInput() (err error) {
+ // Check if input is a terminal
+ if f, ok := p.input.(term.File); ok && term.IsTerminal(f.Fd()) {
+ p.ttyInput = f
+ p.previousTtyInputState, err = term.MakeRaw(p.ttyInput.Fd())
if err != nil {
- return nil //nolint:nilerr // ignore error, this was just a test
+ return fmt.Errorf("error entering raw mode: %w", err)
}
- p.console = c
}
- return nil
-}
-
-// On unix systems, RestoreInput closes any TTYs we opened for input. Note that
-// we don't do this on Windows as it causes the prompt to not be drawn until
-// the terminal receives a keypress rather than appearing promptly after the
-// program exits.
-func (p *Program) restoreInput() error {
- if p.console != nil {
- return p.console.Reset()
+ if f, ok := p.output.(term.File); ok && term.IsTerminal(f.Fd()) {
+ p.ttyOutput = f
}
+
return nil
}
func openInputTTY() (*os.File, error) {
f, err := os.Open("/dev/tty")
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("could not open a new TTY: %w", err)
}
return f, nil
}
+
+const suspendSupported = true
+
+// Send SIGTSTP to the entire process group.
+func suspendProcess() {
+ c := make(chan os.Signal, 1)
+ signal.Notify(c, syscall.SIGCONT)
+ _ = syscall.Kill(0, syscall.SIGTSTP)
+ // blocks until a CONT happens...
+ <-c
+}
diff --git a/vendor/github.com/charmbracelet/bubbletea/tty_windows.go b/vendor/github.com/charmbracelet/bubbletea/tty_windows.go
index be415aef..a3a2525b 100644
--- a/vendor/github.com/charmbracelet/bubbletea/tty_windows.go
+++ b/vendor/github.com/charmbracelet/bubbletea/tty_windows.go
@@ -4,44 +4,65 @@
package tea
import (
+ "fmt"
"os"
- "github.com/containerd/console"
+ "github.com/charmbracelet/x/term"
+ "golang.org/x/sys/windows"
)
-func (p *Program) initInput() error {
- // If input's a file, use console to manage it
- if f, ok := p.input.(*os.File); ok {
- // Save a reference to the current stdin then replace stdin with our
- // input. We do this so we can hand input off to containerd/console to
- // set raw mode, and do it in this fashion because the method
- // console.ConsoleFromFile isn't supported on Windows.
- p.windowsStdin = os.Stdin
- os.Stdin = f
-
- // Note: this will panic if it fails.
- c := console.Current()
- p.console = c
+func (p *Program) initInput() (err error) {
+ // Save stdin state and enable VT input
+ // We also need to enable VT
+ // input here.
+ if f, ok := p.input.(term.File); ok && term.IsTerminal(f.Fd()) {
+ p.ttyInput = f
+ p.previousTtyInputState, err = term.MakeRaw(p.ttyInput.Fd())
+ if err != nil {
+ return err
+ }
+
+ // Enable VT input
+ var mode uint32
+ if err := windows.GetConsoleMode(windows.Handle(p.ttyInput.Fd()), &mode); err != nil {
+ return fmt.Errorf("error getting console mode: %w", err)
+ }
+
+ if err := windows.SetConsoleMode(windows.Handle(p.ttyInput.Fd()), mode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err != nil {
+ return fmt.Errorf("error setting console mode: %w", err)
+ }
}
- return nil
-}
+ // Save output screen buffer state and enable VT processing.
+ if f, ok := p.output.(term.File); ok && term.IsTerminal(f.Fd()) {
+ p.ttyOutput = f
+ p.previousOutputState, err = term.GetState(f.Fd())
+ if err != nil {
+ return err
+ }
-// restoreInput restores stdout in the event that we placed it aside to handle
-// input with CONIN$, above.
-func (p *Program) restoreInput() error {
- if p.windowsStdin != nil {
- os.Stdin = p.windowsStdin
+ var mode uint32
+ if err := windows.GetConsoleMode(windows.Handle(p.ttyOutput.Fd()), &mode); err != nil {
+ return fmt.Errorf("error getting console mode: %w", err)
+ }
+
+ if err := windows.SetConsoleMode(windows.Handle(p.ttyOutput.Fd()), mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err != nil {
+ return fmt.Errorf("error setting console mode: %w", err)
+ }
}
- return nil
+ return
}
// Open the Windows equivalent of a TTY.
func openInputTTY() (*os.File, error) {
- f, err := os.OpenFile("CONIN$", os.O_RDWR, 0644)
+ f, err := os.OpenFile("CONIN$", os.O_RDWR, 0o644)
if err != nil {
return nil, err
}
return f, nil
}
+
+const suspendSupported = false
+
+func suspendProcess() {}
diff --git a/vendor/github.com/charmbracelet/lipgloss/.golangci-soft.yml b/vendor/github.com/charmbracelet/colorprofile/.golangci-soft.yml
similarity index 79%
rename from vendor/github.com/charmbracelet/lipgloss/.golangci-soft.yml
rename to vendor/github.com/charmbracelet/colorprofile/.golangci-soft.yml
index ef456e06..d325d4fc 100644
--- a/vendor/github.com/charmbracelet/lipgloss/.golangci-soft.yml
+++ b/vendor/github.com/charmbracelet/colorprofile/.golangci-soft.yml
@@ -1,5 +1,6 @@
run:
tests: false
+ issues-exit-code: 0
issues:
include:
@@ -14,17 +15,13 @@ issues:
linters:
enable:
- # - dupl
- exhaustive
- # - exhaustivestruct
- goconst
- godot
- godox
- - gomnd
+ - mnd
- gomoddirectives
- goprintffuncname
- - ifshort
- # - lll
- misspell
- nakedret
- nestif
@@ -35,13 +32,9 @@ linters:
# disable default linters, they are already enabled in .golangci.yml
disable:
- - deadcode
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- - structcheck
- - typecheck
- unused
- - varcheck
diff --git a/vendor/github.com/charmbracelet/colorprofile/.golangci.yml b/vendor/github.com/charmbracelet/colorprofile/.golangci.yml
new file mode 100644
index 00000000..d6789e01
--- /dev/null
+++ b/vendor/github.com/charmbracelet/colorprofile/.golangci.yml
@@ -0,0 +1,28 @@
+run:
+ tests: false
+
+issues:
+ include:
+ - EXC0001
+ - EXC0005
+ - EXC0011
+ - EXC0012
+ - EXC0013
+
+ max-issues-per-linter: 0
+ max-same-issues: 0
+
+linters:
+ enable:
+ - bodyclose
+ - gofumpt
+ - goimports
+ - gosec
+ - nilerr
+ - revive
+ - rowserrcheck
+ - sqlclosecheck
+ - tparallel
+ - unconvert
+ - unparam
+ - whitespace
diff --git a/vendor/github.com/charmbracelet/colorprofile/.goreleaser.yml b/vendor/github.com/charmbracelet/colorprofile/.goreleaser.yml
new file mode 100644
index 00000000..40d9f298
--- /dev/null
+++ b/vendor/github.com/charmbracelet/colorprofile/.goreleaser.yml
@@ -0,0 +1,6 @@
+includes:
+ - from_url:
+ url: charmbracelet/meta/main/goreleaser-lib.yaml
+
+# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json
+
diff --git a/vendor/github.com/charmbracelet/colorprofile/BUILD.bazel b/vendor/github.com/charmbracelet/colorprofile/BUILD.bazel
new file mode 100644
index 00000000..7ddc3e35
--- /dev/null
+++ b/vendor/github.com/charmbracelet/colorprofile/BUILD.bazel
@@ -0,0 +1,26 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "env.go",
+ "env_other.go",
+ "env_windows.go",
+ "profile.go",
+ "writer.go",
+ ],
+ importmap = "github.com/kindlyops/vbs/vendor/github.com/charmbracelet/colorprofile",
+ importpath = "github.com/charmbracelet/colorprofile",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//vendor/github.com/charmbracelet/x/ansi:go_default_library",
+ "//vendor/github.com/charmbracelet/x/term:go_default_library",
+ "//vendor/github.com/lucasb-eyer/go-colorful:go_default_library",
+ "//vendor/github.com/xo/terminfo:go_default_library",
+ ] + select({
+ "@io_bazel_rules_go//go/platform:windows": [
+ "//vendor/golang.org/x/sys/windows:go_default_library",
+ ],
+ "//conditions:default": [],
+ }),
+)
diff --git a/vendor/github.com/charmbracelet/colorprofile/LICENSE b/vendor/github.com/charmbracelet/colorprofile/LICENSE
new file mode 100644
index 00000000..b7974b07
--- /dev/null
+++ b/vendor/github.com/charmbracelet/colorprofile/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020-2024 Charmbracelet, Inc
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/charmbracelet/colorprofile/README.md b/vendor/github.com/charmbracelet/colorprofile/README.md
new file mode 100644
index 00000000..c72b2f4b
--- /dev/null
+++ b/vendor/github.com/charmbracelet/colorprofile/README.md
@@ -0,0 +1,103 @@
+# Colorprofile
+
+
+
+
+
+
+
+A simple, powerful—and at times magical—package for detecting terminal color
+profiles and performing color (and CSI) degradation.
+
+## Detecting the terminal’s color profile
+
+Detecting the terminal’s color profile is easy.
+
+```go
+import "github.com/charmbracelet/colorprofile"
+
+// Detect the color profile. If you’re planning on writing to stderr you'd want
+// to use os.Stderr instead.
+p := colorprofile.Detect(os.Stdout, os.Environ())
+
+// Comment on the profile.
+fmt.Printf("You know, your colors are quite %s.", func() string {
+ switch p {
+ case colorprofile.TrueColor:
+ return "fancy"
+ case colorprofile.ANSI256:
+ return "1990s fancy"
+ case colorprofile.ANSI:
+ return "normcore"
+ case colorprofile.Ascii:
+ return "ancient"
+ case colorprofile.NoTTY:
+ return "naughty!"
+ }
+ return "...IDK" // this should never happen
+}())
+```
+
+## Downsampling colors
+
+When necessary, colors can be downsampled to a given profile, or manually
+downsampled to a specific profile.
+
+```go
+p := colorprofile.Detect(os.Stdout, os.Environ())
+c := color.RGBA{0x6b, 0x50, 0xff, 0xff} // #6b50ff
+
+// Downsample to the detected profile, when necessary.
+convertedColor := p.Convert(c)
+
+// Or manually convert to a given profile.
+ansi256Color := colorprofile.ANSI256.Convert(c)
+ansiColor := colorprofile.ANSI.Convert(c)
+noColor := colorprofile.Ascii.Convert(c)
+noANSI := colorprofile.NoTTY.Convert(c)
+```
+
+## Automatic downsampling with a Writer
+
+You can also magically downsample colors in ANSI output, when necessary. If
+output is not a TTY ANSI will be dropped entirely.
+
+```go
+myFancyANSI := "\x1b[38;2;107;80;255mCute \x1b[1;3mpuppy!!\x1b[m"
+
+// Automatically downsample for the terminal at stdout.
+w := colorprofile.NewWriter(os.Stdout, os.Environ())
+fmt.Fprintf(w, myFancyANSI)
+
+// Downsample to 4-bit ANSI.
+w.Profile = colorprofile.ANSI
+fmt.Fprintf(w, myFancyANSI)
+
+// Ascii-fy, no colors.
+w.Profile = colorprofile.Ascii
+fmt.Fprintf(w, myFancyANSI)
+
+// Strip ANSI altogether.
+w.Profile = colorprofile.NoTTY
+fmt.Fprintf(w, myFancyANSI) // not as fancy
+```
+
+## Feedback
+
+We’d love to hear your thoughts on this project. Feel free to drop us a note!
+
+- [Twitter](https://twitter.com/charmcli)
+- [The Fediverse](https://mastodon.social/@charmcli)
+- [Discord](https://charm.sh/chat)
+
+## License
+
+[MIT](https://github.com/charmbracelet/bubbletea/raw/master/LICENSE)
+
+---
+
+Part of [Charm](https://charm.sh).
+
+
+
+Charm热爱开源 • Charm loves open source • نحنُ نحب المصادر المفتوحة
diff --git a/vendor/github.com/charmbracelet/colorprofile/env.go b/vendor/github.com/charmbracelet/colorprofile/env.go
new file mode 100644
index 00000000..8df3d8f7
--- /dev/null
+++ b/vendor/github.com/charmbracelet/colorprofile/env.go
@@ -0,0 +1,287 @@
+package colorprofile
+
+import (
+ "bytes"
+ "io"
+ "os/exec"
+ "runtime"
+ "strconv"
+ "strings"
+
+ "github.com/charmbracelet/x/term"
+ "github.com/xo/terminfo"
+)
+
+// Detect returns the color profile based on the terminal output, and
+// environment variables. This respects NO_COLOR, CLICOLOR, and CLICOLOR_FORCE
+// environment variables.
+//
+// The rules as follows:
+// - TERM=dumb is always treated as NoTTY unless CLICOLOR_FORCE=1 is set.
+// - If COLORTERM=truecolor, and the profile is not NoTTY, it gest upgraded to TrueColor.
+// - Using any 256 color terminal (e.g. TERM=xterm-256color) will set the profile to ANSI256.
+// - Using any color terminal (e.g. TERM=xterm-color) will set the profile to ANSI.
+// - Using CLICOLOR=1 without TERM defined should be treated as ANSI if the
+// output is a terminal.
+// - NO_COLOR takes precedence over CLICOLOR/CLICOLOR_FORCE, and will disable
+// colors but not text decoration, i.e. bold, italic, faint, etc.
+//
+// See https://no-color.org/ and https://bixense.com/clicolors/ for more information.
+func Detect(output io.Writer, env []string) Profile {
+ out, ok := output.(term.File)
+ isatty := ok && term.IsTerminal(out.Fd())
+ environ := newEnviron(env)
+ term := environ.get("TERM")
+ isDumb := term == "dumb"
+ envp := colorProfile(isatty, environ)
+ if envp == TrueColor || envNoColor(environ) {
+ // We already know we have TrueColor, or NO_COLOR is set.
+ return envp
+ }
+
+ if isatty && !isDumb {
+ tip := Terminfo(term)
+ tmuxp := tmux(environ)
+
+ // Color profile is the maximum of env, terminfo, and tmux.
+ return max(envp, max(tip, tmuxp))
+ }
+
+ return envp
+}
+
+// Env returns the color profile based on the terminal environment variables.
+// This respects NO_COLOR, CLICOLOR, and CLICOLOR_FORCE environment variables.
+//
+// The rules as follows:
+// - TERM=dumb is always treated as NoTTY unless CLICOLOR_FORCE=1 is set.
+// - If COLORTERM=truecolor, and the profile is not NoTTY, it gest upgraded to TrueColor.
+// - Using any 256 color terminal (e.g. TERM=xterm-256color) will set the profile to ANSI256.
+// - Using any color terminal (e.g. TERM=xterm-color) will set the profile to ANSI.
+// - Using CLICOLOR=1 without TERM defined should be treated as ANSI if the
+// output is a terminal.
+// - NO_COLOR takes precedence over CLICOLOR/CLICOLOR_FORCE, and will disable
+// colors but not text decoration, i.e. bold, italic, faint, etc.
+//
+// See https://no-color.org/ and https://bixense.com/clicolors/ for more information.
+func Env(env []string) (p Profile) {
+ return colorProfile(true, newEnviron(env))
+}
+
+func colorProfile(isatty bool, env environ) (p Profile) {
+ isDumb := env.get("TERM") == "dumb"
+ envp := envColorProfile(env)
+ if !isatty || isDumb {
+ // Check if the output is a terminal.
+ // Treat dumb terminals as NoTTY
+ p = NoTTY
+ } else {
+ p = envp
+ }
+
+ if envNoColor(env) && isatty {
+ if p > Ascii {
+ p = Ascii
+ }
+ return
+ }
+
+ if cliColorForced(env) {
+ if p < ANSI {
+ p = ANSI
+ }
+ if envp > p {
+ p = envp
+ }
+
+ return
+ }
+
+ if cliColor(env) {
+ if isatty && !isDumb && p < ANSI {
+ p = ANSI
+ }
+ }
+
+ return p
+}
+
+// envNoColor returns true if the environment variables explicitly disable color output
+// by setting NO_COLOR (https://no-color.org/).
+func envNoColor(env environ) bool {
+ noColor, _ := strconv.ParseBool(env.get("NO_COLOR"))
+ return noColor
+}
+
+func cliColor(env environ) bool {
+ cliColor, _ := strconv.ParseBool(env.get("CLICOLOR"))
+ return cliColor
+}
+
+func cliColorForced(env environ) bool {
+ cliColorForce, _ := strconv.ParseBool(env.get("CLICOLOR_FORCE"))
+ return cliColorForce
+}
+
+func colorTerm(env environ) bool {
+ colorTerm := strings.ToLower(env.get("COLORTERM"))
+ return colorTerm == "truecolor" || colorTerm == "24bit" ||
+ colorTerm == "yes" || colorTerm == "true"
+}
+
+// envColorProfile returns infers the color profile from the environment.
+func envColorProfile(env environ) (p Profile) {
+ term, ok := env.lookup("TERM")
+ if !ok || len(term) == 0 || term == "dumb" {
+ p = NoTTY
+ if runtime.GOOS == "windows" {
+ // Use Windows API to detect color profile. Windows Terminal and
+ // cmd.exe don't define $TERM.
+ if wcp, ok := windowsColorProfile(env); ok {
+ p = wcp
+ }
+ }
+ } else {
+ p = ANSI
+ }
+
+ parts := strings.Split(term, "-")
+ switch parts[0] {
+ case "alacritty",
+ "contour",
+ "foot",
+ "ghostty",
+ "kitty",
+ "rio",
+ "st",
+ "wezterm":
+ return TrueColor
+ case "xterm":
+ if len(parts) > 1 {
+ switch parts[1] {
+ case "ghostty", "kitty":
+ // These terminals can be defined as xterm-TERMNAME
+ return TrueColor
+ }
+ }
+ case "tmux", "screen":
+ if p < ANSI256 {
+ p = ANSI256
+ }
+ }
+
+ if isCloudShell, _ := strconv.ParseBool(env.get("GOOGLE_CLOUD_SHELL")); isCloudShell {
+ return TrueColor
+ }
+
+ // GNU Screen doesn't support TrueColor
+ // Tmux doesn't support $COLORTERM
+ if colorTerm(env) && !strings.HasPrefix(term, "screen") && !strings.HasPrefix(term, "tmux") {
+ return TrueColor
+ }
+
+ if strings.HasSuffix(term, "256color") && p < ANSI256 {
+ p = ANSI256
+ }
+
+ return
+}
+
+// Terminfo returns the color profile based on the terminal's terminfo
+// database. This relies on the Tc and RGB capabilities to determine if the
+// terminal supports TrueColor.
+// If term is empty or "dumb", it returns NoTTY.
+func Terminfo(term string) (p Profile) {
+ if len(term) == 0 || term == "dumb" {
+ return NoTTY
+ }
+
+ p = ANSI
+ ti, err := terminfo.Load(term)
+ if err != nil {
+ return
+ }
+
+ extbools := ti.ExtBoolCapsShort()
+ if _, ok := extbools["Tc"]; ok {
+ return TrueColor
+ }
+
+ if _, ok := extbools["RGB"]; ok {
+ return TrueColor
+ }
+
+ return
+}
+
+// Tmux returns the color profile based on `tmux info` output. Tmux supports
+// overriding the terminal's color capabilities, so this function will return
+// the color profile based on the tmux configuration.
+func Tmux(env []string) Profile {
+ return tmux(newEnviron(env))
+}
+
+// tmux returns the color profile based on the tmux environment variables.
+func tmux(env environ) (p Profile) {
+ if tmux, ok := env.lookup("TMUX"); !ok || len(tmux) == 0 {
+ // Not in tmux
+ return NoTTY
+ }
+
+ // Check if tmux has either Tc or RGB capabilities. Otherwise, return
+ // ANSI256.
+ p = ANSI256
+ cmd := exec.Command("tmux", "info")
+ out, err := cmd.Output()
+ if err != nil {
+ return
+ }
+
+ for _, line := range bytes.Split(out, []byte("\n")) {
+ if (bytes.Contains(line, []byte("Tc")) || bytes.Contains(line, []byte("RGB"))) &&
+ bytes.Contains(line, []byte("true")) {
+ return TrueColor
+ }
+ }
+
+ return
+}
+
+// environ is a map of environment variables.
+type environ map[string]string
+
+// newEnviron returns a new environment map from a slice of environment
+// variables.
+func newEnviron(environ []string) environ {
+ m := make(map[string]string, len(environ))
+ for _, e := range environ {
+ parts := strings.SplitN(e, "=", 2)
+ var value string
+ if len(parts) == 2 {
+ value = parts[1]
+ }
+ m[parts[0]] = value
+ }
+ return m
+}
+
+// lookup returns the value of an environment variable and a boolean indicating
+// if it exists.
+func (e environ) lookup(key string) (string, bool) {
+ v, ok := e[key]
+ return v, ok
+}
+
+// get returns the value of an environment variable and empty string if it
+// doesn't exist.
+func (e environ) get(key string) string {
+ v, _ := e.lookup(key)
+ return v
+}
+
+func max[T ~byte | ~int](a, b T) T {
+ if a > b {
+ return a
+ }
+ return b
+}
diff --git a/vendor/github.com/charmbracelet/colorprofile/env_other.go b/vendor/github.com/charmbracelet/colorprofile/env_other.go
new file mode 100644
index 00000000..080994bc
--- /dev/null
+++ b/vendor/github.com/charmbracelet/colorprofile/env_other.go
@@ -0,0 +1,8 @@
+//go:build !windows
+// +build !windows
+
+package colorprofile
+
+func windowsColorProfile(map[string]string) (Profile, bool) {
+ return 0, false
+}
diff --git a/vendor/github.com/charmbracelet/colorprofile/env_windows.go b/vendor/github.com/charmbracelet/colorprofile/env_windows.go
new file mode 100644
index 00000000..3b9c28f9
--- /dev/null
+++ b/vendor/github.com/charmbracelet/colorprofile/env_windows.go
@@ -0,0 +1,45 @@
+//go:build windows
+// +build windows
+
+package colorprofile
+
+import (
+ "strconv"
+
+ "golang.org/x/sys/windows"
+)
+
+func windowsColorProfile(env map[string]string) (Profile, bool) {
+ if env["ConEmuANSI"] == "ON" {
+ return TrueColor, true
+ }
+
+ if len(env["WT_SESSION"]) > 0 {
+ // Windows Terminal supports TrueColor
+ return TrueColor, true
+ }
+
+ major, _, build := windows.RtlGetNtVersionNumbers()
+ if build < 10586 || major < 10 {
+ // No ANSI support before WindowsNT 10 build 10586
+ if len(env["ANSICON"]) > 0 {
+ ansiconVer := env["ANSICON_VER"]
+ cv, err := strconv.Atoi(ansiconVer)
+ if err != nil || cv < 181 {
+ // No 8 bit color support before ANSICON 1.81
+ return ANSI, true
+ }
+
+ return ANSI256, true
+ }
+
+ return NoTTY, true
+ }
+
+ if build < 14931 {
+ // No true color support before build 14931
+ return ANSI256, true
+ }
+
+ return TrueColor, true
+}
diff --git a/vendor/github.com/charmbracelet/colorprofile/profile.go b/vendor/github.com/charmbracelet/colorprofile/profile.go
new file mode 100644
index 00000000..97e37ac3
--- /dev/null
+++ b/vendor/github.com/charmbracelet/colorprofile/profile.go
@@ -0,0 +1,399 @@
+package colorprofile
+
+import (
+ "image/color"
+ "math"
+
+ "github.com/charmbracelet/x/ansi"
+ "github.com/lucasb-eyer/go-colorful"
+)
+
+// Profile is a color profile: NoTTY, Ascii, ANSI, ANSI256, or TrueColor.
+type Profile byte
+
+const (
+ // NoTTY, not a terminal profile.
+ NoTTY Profile = iota
+ // Ascii, uncolored profile.
+ Ascii //nolint:revive
+ // ANSI, 4-bit color profile.
+ ANSI
+ // ANSI256, 8-bit color profile.
+ ANSI256
+ // TrueColor, 24-bit color profile.
+ TrueColor
+)
+
+// String returns the string representation of a Profile.
+func (p Profile) String() string {
+ switch p {
+ case TrueColor:
+ return "TrueColor"
+ case ANSI256:
+ return "ANSI256"
+ case ANSI:
+ return "ANSI"
+ case Ascii:
+ return "Ascii"
+ case NoTTY:
+ return "NoTTY"
+ }
+ return "Unknown"
+}
+
+// Convert transforms a given Color to a Color supported within the Profile.
+func (p Profile) Convert(c color.Color) color.Color {
+ if p <= Ascii {
+ return nil
+ }
+
+ switch c := c.(type) {
+ case ansi.BasicColor:
+ return c
+
+ case ansi.ExtendedColor:
+ if p == ANSI {
+ return ansi256ToANSIColor(c)
+ }
+ return c
+
+ case ansi.TrueColor, color.Color:
+ h, ok := colorful.MakeColor(c)
+ if !ok {
+ return nil
+ }
+ if p != TrueColor {
+ ac := hexToANSI256Color(h)
+ if p == ANSI {
+ return ansi256ToANSIColor(ac)
+ }
+ return ac
+ }
+ return c
+ }
+
+ return c
+}
+
+func hexToANSI256Color(c colorful.Color) ansi.ExtendedColor {
+ v2ci := func(v float64) int {
+ if v < 48 {
+ return 0
+ }
+ if v < 115 {
+ return 1
+ }
+ return int((v - 35) / 40)
+ }
+
+ // Calculate the nearest 0-based color index at 16..231
+ r := v2ci(c.R * 255.0) // 0..5 each
+ g := v2ci(c.G * 255.0)
+ b := v2ci(c.B * 255.0)
+ ci := 36*r + 6*g + b /* 0..215 */
+
+ // Calculate the represented colors back from the index
+ i2cv := [6]int{0, 0x5f, 0x87, 0xaf, 0xd7, 0xff}
+ cr := i2cv[r] // r/g/b, 0..255 each
+ cg := i2cv[g]
+ cb := i2cv[b]
+
+ // Calculate the nearest 0-based gray index at 232..255
+ var grayIdx int
+ average := (cr + cg + cb) / 3
+ if average > 238 {
+ grayIdx = 23
+ } else {
+ grayIdx = (average - 3) / 10 // 0..23
+ }
+ gv := 8 + 10*grayIdx // same value for r/g/b, 0..255
+
+ // Return the one which is nearer to the original input rgb value
+ c2 := colorful.Color{R: float64(cr) / 255.0, G: float64(cg) / 255.0, B: float64(cb) / 255.0}
+ g2 := colorful.Color{R: float64(gv) / 255.0, G: float64(gv) / 255.0, B: float64(gv) / 255.0}
+ colorDist := c.DistanceHSLuv(c2)
+ grayDist := c.DistanceHSLuv(g2)
+
+ if colorDist <= grayDist {
+ return ansi.ExtendedColor(16 + ci) //nolint:gosec
+ }
+ return ansi.ExtendedColor(232 + grayIdx) //nolint:gosec
+}
+
+func ansi256ToANSIColor(c ansi.ExtendedColor) ansi.BasicColor {
+ var r int
+ md := math.MaxFloat64
+
+ h, _ := colorful.Hex(ansiHex[c])
+ for i := 0; i <= 15; i++ {
+ hb, _ := colorful.Hex(ansiHex[i])
+ d := h.DistanceHSLuv(hb)
+
+ if d < md {
+ md = d
+ r = i
+ }
+ }
+
+ return ansi.BasicColor(r) //nolint:gosec
+}
+
+// RGB values of ANSI colors (0-255).
+var ansiHex = []string{
+ "#000000",
+ "#800000",
+ "#008000",
+ "#808000",
+ "#000080",
+ "#800080",
+ "#008080",
+ "#c0c0c0",
+ "#808080",
+ "#ff0000",
+ "#00ff00",
+ "#ffff00",
+ "#0000ff",
+ "#ff00ff",
+ "#00ffff",
+ "#ffffff",
+ "#000000",
+ "#00005f",
+ "#000087",
+ "#0000af",
+ "#0000d7",
+ "#0000ff",
+ "#005f00",
+ "#005f5f",
+ "#005f87",
+ "#005faf",
+ "#005fd7",
+ "#005fff",
+ "#008700",
+ "#00875f",
+ "#008787",
+ "#0087af",
+ "#0087d7",
+ "#0087ff",
+ "#00af00",
+ "#00af5f",
+ "#00af87",
+ "#00afaf",
+ "#00afd7",
+ "#00afff",
+ "#00d700",
+ "#00d75f",
+ "#00d787",
+ "#00d7af",
+ "#00d7d7",
+ "#00d7ff",
+ "#00ff00",
+ "#00ff5f",
+ "#00ff87",
+ "#00ffaf",
+ "#00ffd7",
+ "#00ffff",
+ "#5f0000",
+ "#5f005f",
+ "#5f0087",
+ "#5f00af",
+ "#5f00d7",
+ "#5f00ff",
+ "#5f5f00",
+ "#5f5f5f",
+ "#5f5f87",
+ "#5f5faf",
+ "#5f5fd7",
+ "#5f5fff",
+ "#5f8700",
+ "#5f875f",
+ "#5f8787",
+ "#5f87af",
+ "#5f87d7",
+ "#5f87ff",
+ "#5faf00",
+ "#5faf5f",
+ "#5faf87",
+ "#5fafaf",
+ "#5fafd7",
+ "#5fafff",
+ "#5fd700",
+ "#5fd75f",
+ "#5fd787",
+ "#5fd7af",
+ "#5fd7d7",
+ "#5fd7ff",
+ "#5fff00",
+ "#5fff5f",
+ "#5fff87",
+ "#5fffaf",
+ "#5fffd7",
+ "#5fffff",
+ "#870000",
+ "#87005f",
+ "#870087",
+ "#8700af",
+ "#8700d7",
+ "#8700ff",
+ "#875f00",
+ "#875f5f",
+ "#875f87",
+ "#875faf",
+ "#875fd7",
+ "#875fff",
+ "#878700",
+ "#87875f",
+ "#878787",
+ "#8787af",
+ "#8787d7",
+ "#8787ff",
+ "#87af00",
+ "#87af5f",
+ "#87af87",
+ "#87afaf",
+ "#87afd7",
+ "#87afff",
+ "#87d700",
+ "#87d75f",
+ "#87d787",
+ "#87d7af",
+ "#87d7d7",
+ "#87d7ff",
+ "#87ff00",
+ "#87ff5f",
+ "#87ff87",
+ "#87ffaf",
+ "#87ffd7",
+ "#87ffff",
+ "#af0000",
+ "#af005f",
+ "#af0087",
+ "#af00af",
+ "#af00d7",
+ "#af00ff",
+ "#af5f00",
+ "#af5f5f",
+ "#af5f87",
+ "#af5faf",
+ "#af5fd7",
+ "#af5fff",
+ "#af8700",
+ "#af875f",
+ "#af8787",
+ "#af87af",
+ "#af87d7",
+ "#af87ff",
+ "#afaf00",
+ "#afaf5f",
+ "#afaf87",
+ "#afafaf",
+ "#afafd7",
+ "#afafff",
+ "#afd700",
+ "#afd75f",
+ "#afd787",
+ "#afd7af",
+ "#afd7d7",
+ "#afd7ff",
+ "#afff00",
+ "#afff5f",
+ "#afff87",
+ "#afffaf",
+ "#afffd7",
+ "#afffff",
+ "#d70000",
+ "#d7005f",
+ "#d70087",
+ "#d700af",
+ "#d700d7",
+ "#d700ff",
+ "#d75f00",
+ "#d75f5f",
+ "#d75f87",
+ "#d75faf",
+ "#d75fd7",
+ "#d75fff",
+ "#d78700",
+ "#d7875f",
+ "#d78787",
+ "#d787af",
+ "#d787d7",
+ "#d787ff",
+ "#d7af00",
+ "#d7af5f",
+ "#d7af87",
+ "#d7afaf",
+ "#d7afd7",
+ "#d7afff",
+ "#d7d700",
+ "#d7d75f",
+ "#d7d787",
+ "#d7d7af",
+ "#d7d7d7",
+ "#d7d7ff",
+ "#d7ff00",
+ "#d7ff5f",
+ "#d7ff87",
+ "#d7ffaf",
+ "#d7ffd7",
+ "#d7ffff",
+ "#ff0000",
+ "#ff005f",
+ "#ff0087",
+ "#ff00af",
+ "#ff00d7",
+ "#ff00ff",
+ "#ff5f00",
+ "#ff5f5f",
+ "#ff5f87",
+ "#ff5faf",
+ "#ff5fd7",
+ "#ff5fff",
+ "#ff8700",
+ "#ff875f",
+ "#ff8787",
+ "#ff87af",
+ "#ff87d7",
+ "#ff87ff",
+ "#ffaf00",
+ "#ffaf5f",
+ "#ffaf87",
+ "#ffafaf",
+ "#ffafd7",
+ "#ffafff",
+ "#ffd700",
+ "#ffd75f",
+ "#ffd787",
+ "#ffd7af",
+ "#ffd7d7",
+ "#ffd7ff",
+ "#ffff00",
+ "#ffff5f",
+ "#ffff87",
+ "#ffffaf",
+ "#ffffd7",
+ "#ffffff",
+ "#080808",
+ "#121212",
+ "#1c1c1c",
+ "#262626",
+ "#303030",
+ "#3a3a3a",
+ "#444444",
+ "#4e4e4e",
+ "#585858",
+ "#626262",
+ "#6c6c6c",
+ "#767676",
+ "#808080",
+ "#8a8a8a",
+ "#949494",
+ "#9e9e9e",
+ "#a8a8a8",
+ "#b2b2b2",
+ "#bcbcbc",
+ "#c6c6c6",
+ "#d0d0d0",
+ "#dadada",
+ "#e4e4e4",
+ "#eeeeee",
+}
diff --git a/vendor/github.com/charmbracelet/colorprofile/writer.go b/vendor/github.com/charmbracelet/colorprofile/writer.go
new file mode 100644
index 00000000..d04b3b99
--- /dev/null
+++ b/vendor/github.com/charmbracelet/colorprofile/writer.go
@@ -0,0 +1,166 @@
+package colorprofile
+
+import (
+ "bytes"
+ "image/color"
+ "io"
+ "strconv"
+
+ "github.com/charmbracelet/x/ansi"
+)
+
+// NewWriter creates a new color profile writer that downgrades color sequences
+// based on the detected color profile.
+//
+// If environ is nil, it will use os.Environ() to get the environment variables.
+//
+// It queries the given writer to determine if it supports ANSI escape codes.
+// If it does, along with the given environment variables, it will determine
+// the appropriate color profile to use for color formatting.
+//
+// This respects the NO_COLOR, CLICOLOR, and CLICOLOR_FORCE environment variables.
+func NewWriter(w io.Writer, environ []string) *Writer {
+ return &Writer{
+ Forward: w,
+ Profile: Detect(w, environ),
+ }
+}
+
+// Writer represents a color profile writer that writes ANSI sequences to the
+// underlying writer.
+type Writer struct {
+ Forward io.Writer
+ Profile Profile
+}
+
+// Write writes the given text to the underlying writer.
+func (w *Writer) Write(p []byte) (int, error) {
+ switch w.Profile {
+ case TrueColor:
+ return w.Forward.Write(p)
+ case NoTTY:
+ return io.WriteString(w.Forward, ansi.Strip(string(p)))
+ default:
+ return w.downsample(p)
+ }
+}
+
+// downsample downgrades the given text to the appropriate color profile.
+func (w *Writer) downsample(p []byte) (int, error) {
+ var buf bytes.Buffer
+ var state byte
+
+ parser := ansi.GetParser()
+ defer ansi.PutParser(parser)
+
+ for len(p) > 0 {
+ parser.Reset()
+ seq, _, read, newState := ansi.DecodeSequence(p, state, parser)
+
+ switch {
+ case ansi.HasCsiPrefix(seq) && parser.Command() == 'm':
+ handleSgr(w, parser, &buf)
+ default:
+ // If we're not a style SGR sequence, just write the bytes.
+ if n, err := buf.Write(seq); err != nil {
+ return n, err
+ }
+ }
+
+ p = p[read:]
+ state = newState
+ }
+
+ return w.Forward.Write(buf.Bytes())
+}
+
+// WriteString writes the given text to the underlying writer.
+func (w *Writer) WriteString(s string) (n int, err error) {
+ return w.Write([]byte(s))
+}
+
+func handleSgr(w *Writer, p *ansi.Parser, buf *bytes.Buffer) {
+ var style ansi.Style
+ params := p.Params()
+ for i := 0; i < len(params); i++ {
+ param := params[i]
+
+ switch param := param.Param(0); param {
+ case 0:
+ // SGR default parameter is 0. We use an empty string to reduce the
+ // number of bytes written to the buffer.
+ style = append(style, "")
+ case 30, 31, 32, 33, 34, 35, 36, 37: // 8-bit foreground color
+ if w.Profile < ANSI {
+ continue
+ }
+ style = style.ForegroundColor(
+ w.Profile.Convert(ansi.BasicColor(param - 30))) //nolint:gosec
+ case 38: // 16 or 24-bit foreground color
+ var c color.Color
+ if n := ansi.ReadStyleColor(params[i:], &c); n > 0 {
+ i += n - 1
+ }
+ if w.Profile < ANSI {
+ continue
+ }
+ style = style.ForegroundColor(w.Profile.Convert(c))
+ case 39: // default foreground color
+ if w.Profile < ANSI {
+ continue
+ }
+ style = style.DefaultForegroundColor()
+ case 40, 41, 42, 43, 44, 45, 46, 47: // 8-bit background color
+ if w.Profile < ANSI {
+ continue
+ }
+ style = style.BackgroundColor(
+ w.Profile.Convert(ansi.BasicColor(param - 40))) //nolint:gosec
+ case 48: // 16 or 24-bit background color
+ var c color.Color
+ if n := ansi.ReadStyleColor(params[i:], &c); n > 0 {
+ i += n - 1
+ }
+ if w.Profile < ANSI {
+ continue
+ }
+ style = style.BackgroundColor(w.Profile.Convert(c))
+ case 49: // default background color
+ if w.Profile < ANSI {
+ continue
+ }
+ style = style.DefaultBackgroundColor()
+ case 58: // 16 or 24-bit underline color
+ var c color.Color
+ if n := ansi.ReadStyleColor(params[i:], &c); n > 0 {
+ i += n - 1
+ }
+ if w.Profile < ANSI {
+ continue
+ }
+ style = style.UnderlineColor(w.Profile.Convert(c))
+ case 59: // default underline color
+ if w.Profile < ANSI {
+ continue
+ }
+ style = style.DefaultUnderlineColor()
+ case 90, 91, 92, 93, 94, 95, 96, 97: // 8-bit bright foreground color
+ if w.Profile < ANSI {
+ continue
+ }
+ style = style.ForegroundColor(
+ w.Profile.Convert(ansi.BasicColor(param - 90 + 8))) //nolint:gosec
+ case 100, 101, 102, 103, 104, 105, 106, 107: // 8-bit bright background color
+ if w.Profile < ANSI {
+ continue
+ }
+ style = style.BackgroundColor(
+ w.Profile.Convert(ansi.BasicColor(param - 100 + 8))) //nolint:gosec
+ default:
+ // If this is not a color attribute, just append it to the style.
+ style = append(style, strconv.Itoa(param))
+ }
+ }
+
+ _, _ = buf.WriteString(style.String())
+}
diff --git a/vendor/github.com/charmbracelet/lipgloss/.gitignore b/vendor/github.com/charmbracelet/lipgloss/.gitignore
index 53e1c2b7..db482015 100644
--- a/vendor/github.com/charmbracelet/lipgloss/.gitignore
+++ b/vendor/github.com/charmbracelet/lipgloss/.gitignore
@@ -1 +1,2 @@
ssh_example_ed25519*
+dist/
diff --git a/vendor/github.com/charmbracelet/lipgloss/.golangci.yml b/vendor/github.com/charmbracelet/lipgloss/.golangci.yml
index a5a91d0d..90c5c08b 100644
--- a/vendor/github.com/charmbracelet/lipgloss/.golangci.yml
+++ b/vendor/github.com/charmbracelet/lipgloss/.golangci.yml
@@ -15,11 +15,22 @@ issues:
linters:
enable:
- bodyclose
- - exportloopref
+ - exhaustive
+ - goconst
+ - godot
+ - godox
+ - gofumpt
- goimports
+ - gomoddirectives
+ - goprintffuncname
- gosec
+ - misspell
+ - nakedret
+ - nestif
- nilerr
- - predeclared
+ - noctx
+ - nolintlint
+ - prealloc
- revive
- rowserrcheck
- sqlclosecheck
@@ -27,3 +38,4 @@ linters:
- unconvert
- unparam
- whitespace
+ - wrapcheck
diff --git a/vendor/github.com/charmbracelet/lipgloss/.goreleaser.yml b/vendor/github.com/charmbracelet/lipgloss/.goreleaser.yml
new file mode 100644
index 00000000..3353d020
--- /dev/null
+++ b/vendor/github.com/charmbracelet/lipgloss/.goreleaser.yml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json
+version: 2
+includes:
+ - from_url:
+ url: charmbracelet/meta/main/goreleaser-lib.yaml
diff --git a/vendor/github.com/charmbracelet/lipgloss/BUILD.bazel b/vendor/github.com/charmbracelet/lipgloss/BUILD.bazel
index 2d60ea05..8179cdce 100644
--- a/vendor/github.com/charmbracelet/lipgloss/BUILD.bazel
+++ b/vendor/github.com/charmbracelet/lipgloss/BUILD.bazel
@@ -11,6 +11,7 @@ go_library(
"get.go",
"join.go",
"position.go",
+ "ranges.go",
"renderer.go",
"runes.go",
"set.go",
@@ -23,11 +24,9 @@ go_library(
importpath = "github.com/charmbracelet/lipgloss",
visibility = ["//visibility:public"],
deps = [
- "//vendor/github.com/mattn/go-runewidth:go_default_library",
- "//vendor/github.com/muesli/reflow/ansi:go_default_library",
- "//vendor/github.com/muesli/reflow/truncate:go_default_library",
- "//vendor/github.com/muesli/reflow/wordwrap:go_default_library",
- "//vendor/github.com/muesli/reflow/wrap:go_default_library",
+ "//vendor/github.com/charmbracelet/x/ansi:go_default_library",
+ "//vendor/github.com/charmbracelet/x/cellbuf:go_default_library",
"//vendor/github.com/muesli/termenv:go_default_library",
+ "//vendor/github.com/rivo/uniseg:go_default_library",
],
)
diff --git a/vendor/github.com/charmbracelet/lipgloss/README.md b/vendor/github.com/charmbracelet/lipgloss/README.md
index 2ebabc76..cee2371c 100644
--- a/vendor/github.com/charmbracelet/lipgloss/README.md
+++ b/vendor/github.com/charmbracelet/lipgloss/README.md
@@ -1,16 +1,16 @@
-Lip Gloss
-=========
+# Lip Gloss
- 
+ 
+
Style definitions for nice terminal layouts. Built with TUIs in mind.
-
+
Lip Gloss takes an expressive, declarative approach to terminal rendering.
Users familiar with CSS will feel at home with Lip Gloss.
@@ -64,7 +64,6 @@ The terminal's color profile will be automatically detected, and colors outside
the gamut of the current palette will be automatically coerced to their closest
available value.
-
### Adaptive Colors
You can also specify color options for light and dark backgrounds:
@@ -78,11 +77,11 @@ appropriate color will be chosen at runtime.
### Complete Colors
-CompleteColor specifies exact values for truecolor, ANSI256, and ANSI color
+CompleteColor specifies exact values for True Color, ANSI256, and ANSI color
profiles.
```go
-lipgloss.CompleteColor{True: "#0000FF", ANSI256: "86", ANSI: "5"}
+lipgloss.CompleteColor{TrueColor: "#0000FF", ANSI256: "86", ANSI: "5"}
```
Automatic color degradation will not be performed in this case and it will be
@@ -90,7 +89,7 @@ based on the color specified.
### Complete Adaptive Colors
-You can use CompleteColor with AdaptiveColor to specify the exact values for
+You can use `CompleteColor` with `AdaptiveColor` to specify the exact values for
light and dark backgrounds without automatic color degradation.
```go
@@ -115,7 +114,6 @@ var style = lipgloss.NewStyle().
Reverse(true)
```
-
## Block-Level Formatting
Lip Gloss also supports rules for block-level formatting:
@@ -154,7 +152,6 @@ lipgloss.NewStyle().Padding(1, 4, 2)
lipgloss.NewStyle().Margin(2, 4, 3, 1)
```
-
## Aligning Text
You can align paragraphs of text to the left, right, or center.
@@ -167,7 +164,6 @@ var style = lipgloss.NewStyle().
Align(lipgloss.Center) // just kidding, align it in the center
```
-
## Width and Height
Setting a minimum width and height is simple and straightforward.
@@ -180,7 +176,6 @@ var style = lipgloss.NewStyle().
Foreground(lipgloss.Color("63"))
```
-
## Borders
Adding borders is easy:
@@ -220,7 +215,7 @@ pattern to the margin and padding shorthand functions.
lipgloss.NewStyle().
Border(lipgloss.ThickBorder(), true, false)
-// Add a thick border to the right and bottom sides. Rules are set clockwise
+// Add a double border to the top and left sides. Rules are set clockwise
// from top.
lipgloss.NewStyle().
Border(lipgloss.DoubleBorder(), true, false, false, true)
@@ -228,21 +223,22 @@ lipgloss.NewStyle().
For more on borders see [the docs][docs].
-
## Copying Styles
-Just use `Copy()`:
+Just use assignment:
```go
-var style = lipgloss.NewStyle().Foreground(lipgloss.Color("219"))
+style := lipgloss.NewStyle().Foreground(lipgloss.Color("219"))
-var wildStyle = style.Copy().Blink(true)
-```
+copiedStyle := style // this is a true copy
-`Copy()` performs a copy on the underlying data structure ensuring that you get
-a true, dereferenced copy of a style. Without copying, it's possible to mutate
-styles.
+wildStyle := style.Blink(true) // this is also true copy, with blink added
+
+```
+Since `Style` data structures contains only primitive types, assigning a style
+to another effectively creates a new copy of the style without mutating the
+original.
## Inheritance
@@ -261,7 +257,6 @@ var styleB = lipgloss.NewStyle().
Inherit(styleA)
```
-
## Unsetting Rules
All rules can be unset:
@@ -276,7 +271,6 @@ var style = lipgloss.NewStyle().
When a rule is unset, it won't be inherited or copied.
-
## Enforcing Rules
Sometimes, such as when developing a component, you want to make sure style
@@ -353,7 +347,6 @@ For an example on using a custom renderer over SSH with [Wish][wish] see the
In addition to pure styling, Lip Gloss also ships with some utilities to help
assemble your layouts.
-
### Joining Paragraphs
Horizontally and vertically joining paragraphs is a cinch.
@@ -370,7 +363,6 @@ lipgloss.JoinVertical(lipgloss.Center, paragraphA, paragraphB)
lipgloss.JoinHorizontal(0.2, paragraphA, paragraphB, paragraphC)
```
-
### Measuring Width and Height
Sometimes you’ll want to know the width and height of text blocks when building
@@ -391,7 +383,6 @@ height := lipgloss.Height(block)
w, h := lipgloss.Size(block)
```
-
### Placing Text in Whitespace
Sometimes you’ll simply want to place a block of text in whitespace.
@@ -411,8 +402,318 @@ block := lipgloss.Place(30, 80, lipgloss.Right, lipgloss.Bottom, fancyStyledPara
You can also style the whitespace. For details, see [the docs][docs].
+## Rendering Tables
+
+Lip Gloss ships with a table rendering sub-package.
+
+```go
+import "github.com/charmbracelet/lipgloss/table"
+```
+
+Define some rows of data.
+
+```go
+rows := [][]string{
+ {"Chinese", "您好", "你好"},
+ {"Japanese", "こんにちは", "やあ"},
+ {"Arabic", "أهلين", "أهلا"},
+ {"Russian", "Здравствуйте", "Привет"},
+ {"Spanish", "Hola", "¿Qué tal?"},
+}
+```
+
+Use the table package to style and render the table.
+
+```go
+var (
+ purple = lipgloss.Color("99")
+ gray = lipgloss.Color("245")
+ lightGray = lipgloss.Color("241")
+
+ headerStyle = lipgloss.NewStyle().Foreground(purple).Bold(true).Align(lipgloss.Center)
+ cellStyle = lipgloss.NewStyle().Padding(0, 1).Width(14)
+ oddRowStyle = cellStyle.Foreground(gray)
+ evenRowStyle = cellStyle.Foreground(lightGray)
+)
+
+t := table.New().
+ Border(lipgloss.NormalBorder()).
+ BorderStyle(lipgloss.NewStyle().Foreground(purple)).
+ StyleFunc(func(row, col int) lipgloss.Style {
+ switch {
+ case row == table.HeaderRow:
+ return headerStyle
+ case row%2 == 0:
+ return evenRowStyle
+ default:
+ return oddRowStyle
+ }
+ }).
+ Headers("LANGUAGE", "FORMAL", "INFORMAL").
+ Rows(rows...)
+
+// You can also add tables row-by-row
+t.Row("English", "You look absolutely fabulous.", "How's it going?")
+```
+
+Print the table.
+
+```go
+fmt.Println(t)
+```
+
+
+
+> [!WARNING]
+> Table `Rows` need to be declared before `Offset` otherwise it does nothing.
+
+### Table Borders
+
+There are helpers to generate tables in markdown or ASCII style:
+
+#### Markdown Table
+
+```go
+table.New().Border(lipgloss.MarkdownBorder()).BorderTop(false).BorderBottom(false)
+```
+
+```
+| LANGUAGE | FORMAL | INFORMAL |
+|----------|--------------|-----------|
+| Chinese | Nǐn hǎo | Nǐ hǎo |
+| French | Bonjour | Salut |
+| Russian | Zdravstvuyte | Privet |
+| Spanish | Hola | ¿Qué tal? |
+```
+
+#### ASCII Table
+
+```go
+table.New().Border(lipgloss.ASCIIBorder())
+```
+
+```
++----------+--------------+-----------+
+| LANGUAGE | FORMAL | INFORMAL |
++----------+--------------+-----------+
+| Chinese | Nǐn hǎo | Nǐ hǎo |
+| French | Bonjour | Salut |
+| Russian | Zdravstvuyte | Privet |
+| Spanish | Hola | ¿Qué tal? |
++----------+--------------+-----------+
+```
+
+For more on tables see [the docs](https://pkg.go.dev/github.com/charmbracelet/lipgloss?tab=doc) and [examples](https://github.com/charmbracelet/lipgloss/tree/master/examples/table).
+
+## Rendering Lists
+
+Lip Gloss ships with a list rendering sub-package.
+
+```go
+import "github.com/charmbracelet/lipgloss/list"
+```
+
+Define a new list.
+
+```go
+l := list.New("A", "B", "C")
+```
+
+Print the list.
+
+```go
+fmt.Println(l)
+
+// • A
+// • B
+// • C
+```
+
+Lists have the ability to nest.
+
+```go
+l := list.New(
+ "A", list.New("Artichoke"),
+ "B", list.New("Baking Flour", "Bananas", "Barley", "Bean Sprouts"),
+ "C", list.New("Cashew Apple", "Cashews", "Coconut Milk", "Curry Paste", "Currywurst"),
+ "D", list.New("Dill", "Dragonfruit", "Dried Shrimp"),
+ "E", list.New("Eggs"),
+ "F", list.New("Fish Cake", "Furikake"),
+ "J", list.New("Jicama"),
+ "K", list.New("Kohlrabi"),
+ "L", list.New("Leeks", "Lentils", "Licorice Root"),
+)
+```
+
+Print the list.
-***
+```go
+fmt.Println(l)
+```
+
+
+
+
+
+Lists can be customized via their enumeration function as well as using
+`lipgloss.Style`s.
+
+```go
+enumeratorStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("99")).MarginRight(1)
+itemStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("212")).MarginRight(1)
+
+l := list.New(
+ "Glossier",
+ "Claire’s Boutique",
+ "Nyx",
+ "Mac",
+ "Milk",
+ ).
+ Enumerator(list.Roman).
+ EnumeratorStyle(enumeratorStyle).
+ ItemStyle(itemStyle)
+```
+
+Print the list.
+
+
+
+
+
+In addition to the predefined enumerators (`Arabic`, `Alphabet`, `Roman`, `Bullet`, `Tree`),
+you may also define your own custom enumerator:
+
+```go
+l := list.New("Duck", "Duck", "Duck", "Duck", "Goose", "Duck", "Duck")
+
+func DuckDuckGooseEnumerator(l list.Items, i int) string {
+ if l.At(i).Value() == "Goose" {
+ return "Honk →"
+ }
+ return ""
+}
+
+l = l.Enumerator(DuckDuckGooseEnumerator)
+```
+
+Print the list:
+
+
+
+
+
+If you need, you can also build lists incrementally:
+
+```go
+l := list.New()
+
+for i := 0; i < repeat; i++ {
+ l.Item("Lip Gloss")
+}
+```
+
+## Rendering Trees
+
+Lip Gloss ships with a tree rendering sub-package.
+
+```go
+import "github.com/charmbracelet/lipgloss/tree"
+```
+
+Define a new tree.
+
+```go
+t := tree.Root(".").
+ Child("A", "B", "C")
+```
+
+Print the tree.
+
+```go
+fmt.Println(t)
+
+// .
+// ├── A
+// ├── B
+// └── C
+```
+
+Trees have the ability to nest.
+
+```go
+t := tree.Root(".").
+ Child("macOS").
+ Child(
+ tree.New().
+ Root("Linux").
+ Child("NixOS").
+ Child("Arch Linux (btw)").
+ Child("Void Linux"),
+ ).
+ Child(
+ tree.New().
+ Root("BSD").
+ Child("FreeBSD").
+ Child("OpenBSD"),
+ )
+```
+
+Print the tree.
+
+```go
+fmt.Println(t)
+```
+
+
+
+
+
+Trees can be customized via their enumeration function as well as using
+`lipgloss.Style`s.
+
+```go
+enumeratorStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("63")).MarginRight(1)
+rootStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("35"))
+itemStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("212"))
+
+t := tree.
+ Root("⁜ Makeup").
+ Child(
+ "Glossier",
+ "Fenty Beauty",
+ tree.New().Child(
+ "Gloss Bomb Universal Lip Luminizer",
+ "Hot Cheeks Velour Blushlighter",
+ ),
+ "Nyx",
+ "Mac",
+ "Milk",
+ ).
+ Enumerator(tree.RoundedEnumerator).
+ EnumeratorStyle(enumeratorStyle).
+ RootStyle(rootStyle).
+ ItemStyle(itemStyle)
+```
+
+Print the tree.
+
+
+
+
+
+The predefined enumerators for trees are `DefaultEnumerator` and `RoundedEnumerator`.
+
+If you need, you can also build trees incrementally:
+
+```go
+t := tree.New()
+
+for i := 0; i < repeat; i++ {
+ t.Child("Lip Gloss")
+}
+```
+
+---
## FAQ
@@ -448,10 +749,11 @@ import (
lipgloss.SetColorProfile(termenv.TrueColor)
```
-*Note:* this option limits the flexibility of your application and can cause
+_Note:_ this option limits the flexibility of your application and can cause
ANSI escape codes to be output in cases where that might not be desired. Take
careful note of your use case and environment before choosing to force a color
profile.
+
## What about [Bubble Tea][tea]?
@@ -465,7 +767,6 @@ In simple terms, you can use Lip Gloss to help build your Bubble Tea views.
[tea]: https://github.com/charmbracelet/tea
-
## Under the Hood
Lip Gloss is built on the excellent [Termenv][termenv] and [Reflow][reflow]
@@ -475,7 +776,6 @@ For many use cases Termenv and Reflow will be sufficient for your needs.
[termenv]: https://github.com/muesli/termenv
[reflow]: https://github.com/muesli/reflow
-
## Rendering Markdown
For a more document-centric rendering solution with support for things like
@@ -484,20 +784,25 @@ the stylesheet-based Markdown renderer.
[glamour]: https://github.com/charmbracelet/glamour
+## Contributing
+
+See [contributing][contribute].
+
+[contribute]: https://github.com/charmbracelet/lipgloss/contribute
## Feedback
We’d love to hear your thoughts on this project. Feel free to drop us a note!
-* [Twitter](https://twitter.com/charmcli)
-* [The Fediverse](https://mastodon.social/@charmcli)
-* [Discord](https://charm.sh/chat)
+- [Twitter](https://twitter.com/charmcli)
+- [The Fediverse](https://mastodon.social/@charmcli)
+- [Discord](https://charm.sh/chat)
## License
[MIT](https://github.com/charmbracelet/lipgloss/raw/master/LICENSE)
-***
+---
Part of [Charm](https://charm.sh).
@@ -505,7 +810,6 @@ Part of [Charm](https://charm.sh).
Charm热爱开源 • Charm loves open source
-
[docs]: https://pkg.go.dev/github.com/charmbracelet/lipgloss?tab=doc
[wish]: https://github.com/charmbracelet/wish
[ssh-example]: examples/ssh
diff --git a/vendor/github.com/charmbracelet/lipgloss/Taskfile.yaml b/vendor/github.com/charmbracelet/lipgloss/Taskfile.yaml
new file mode 100644
index 00000000..0b4a7711
--- /dev/null
+++ b/vendor/github.com/charmbracelet/lipgloss/Taskfile.yaml
@@ -0,0 +1,19 @@
+# https://taskfile.dev
+
+version: '3'
+
+tasks:
+ lint:
+ desc: Run base linters
+ cmds:
+ - golangci-lint run
+
+ test:
+ desc: Run tests
+ cmds:
+ - go test ./... {{.CLI_ARGS}}
+
+ test:table:
+ desc: Run table tests
+ cmds:
+ - go test ./table {{.CLI_ARGS}}
diff --git a/vendor/github.com/charmbracelet/lipgloss/align.go b/vendor/github.com/charmbracelet/lipgloss/align.go
index 6c0fb2dc..ce654b23 100644
--- a/vendor/github.com/charmbracelet/lipgloss/align.go
+++ b/vendor/github.com/charmbracelet/lipgloss/align.go
@@ -3,7 +3,7 @@ package lipgloss
import (
"strings"
- "github.com/muesli/reflow/ansi"
+ "github.com/charmbracelet/x/ansi"
"github.com/muesli/termenv"
)
@@ -15,7 +15,7 @@ func alignTextHorizontal(str string, pos Position, width int, style *termenv.Sty
var b strings.Builder
for i, l := range lines {
- lineWidth := ansi.PrintableRuneWidth(l)
+ lineWidth := ansi.StringWidth(l)
shortAmount := widestLine - lineWidth // difference from the widest line
shortAmount += max(0, width-(shortAmount+lineWidth)) // difference from the total width, if set
@@ -30,8 +30,8 @@ func alignTextHorizontal(str string, pos Position, width int, style *termenv.Sty
l = s + l
case Center:
// Note: remainder goes on the right.
- left := shortAmount / 2 //nolint:gomnd
- right := left + shortAmount%2 //nolint:gomnd
+ left := shortAmount / 2 //nolint:mnd
+ right := left + shortAmount%2 //nolint:mnd
leftSpaces := strings.Repeat(" ", left)
rightSpaces := strings.Repeat(" ", right)
@@ -69,7 +69,7 @@ func alignTextVertical(str string, pos Position, height int, _ *termenv.Style) s
case Top:
return str + strings.Repeat("\n", height-strHeight)
case Center:
- var topPadding, bottomPadding = (height - strHeight) / 2, (height - strHeight) / 2
+ topPadding, bottomPadding := (height-strHeight)/2, (height-strHeight)/2 //nolint:mnd
if strHeight+topPadding+bottomPadding > height {
topPadding--
} else if strHeight+topPadding+bottomPadding < height {
diff --git a/vendor/github.com/charmbracelet/lipgloss/borders.go b/vendor/github.com/charmbracelet/lipgloss/borders.go
index 2c493161..b36f8743 100644
--- a/vendor/github.com/charmbracelet/lipgloss/borders.go
+++ b/vendor/github.com/charmbracelet/lipgloss/borders.go
@@ -3,22 +3,27 @@ package lipgloss
import (
"strings"
- "github.com/mattn/go-runewidth"
- "github.com/muesli/reflow/ansi"
+ "github.com/charmbracelet/x/ansi"
"github.com/muesli/termenv"
+ "github.com/rivo/uniseg"
)
// Border contains a series of values which comprise the various parts of a
// border.
type Border struct {
- Top string
- Bottom string
- Left string
- Right string
- TopLeft string
- TopRight string
- BottomRight string
- BottomLeft string
+ Top string
+ Bottom string
+ Left string
+ Right string
+ TopLeft string
+ TopRight string
+ BottomLeft string
+ BottomRight string
+ MiddleLeft string
+ MiddleRight string
+ Middle string
+ MiddleTop string
+ MiddleBottom string
}
// GetTopSize returns the width of the top border. If borders contain runes of
@@ -63,36 +68,51 @@ var (
noBorder = Border{}
normalBorder = Border{
- Top: "─",
- Bottom: "─",
- Left: "│",
- Right: "│",
- TopLeft: "┌",
- TopRight: "┐",
- BottomLeft: "└",
- BottomRight: "┘",
+ Top: "─",
+ Bottom: "─",
+ Left: "│",
+ Right: "│",
+ TopLeft: "┌",
+ TopRight: "┐",
+ BottomLeft: "└",
+ BottomRight: "┘",
+ MiddleLeft: "├",
+ MiddleRight: "┤",
+ Middle: "┼",
+ MiddleTop: "┬",
+ MiddleBottom: "┴",
}
roundedBorder = Border{
- Top: "─",
- Bottom: "─",
- Left: "│",
- Right: "│",
- TopLeft: "╭",
- TopRight: "╮",
- BottomLeft: "╰",
- BottomRight: "╯",
+ Top: "─",
+ Bottom: "─",
+ Left: "│",
+ Right: "│",
+ TopLeft: "╭",
+ TopRight: "╮",
+ BottomLeft: "╰",
+ BottomRight: "╯",
+ MiddleLeft: "├",
+ MiddleRight: "┤",
+ Middle: "┼",
+ MiddleTop: "┬",
+ MiddleBottom: "┴",
}
blockBorder = Border{
- Top: "█",
- Bottom: "█",
- Left: "█",
- Right: "█",
- TopLeft: "█",
- TopRight: "█",
- BottomLeft: "█",
- BottomRight: "█",
+ Top: "█",
+ Bottom: "█",
+ Left: "█",
+ Right: "█",
+ TopLeft: "█",
+ TopRight: "█",
+ BottomLeft: "█",
+ BottomRight: "█",
+ MiddleLeft: "█",
+ MiddleRight: "█",
+ Middle: "█",
+ MiddleTop: "█",
+ MiddleBottom: "█",
}
outerHalfBlockBorder = Border{
@@ -118,36 +138,83 @@ var (
}
thickBorder = Border{
- Top: "━",
- Bottom: "━",
- Left: "┃",
- Right: "┃",
- TopLeft: "┏",
- TopRight: "┓",
- BottomLeft: "┗",
- BottomRight: "┛",
+ Top: "━",
+ Bottom: "━",
+ Left: "┃",
+ Right: "┃",
+ TopLeft: "┏",
+ TopRight: "┓",
+ BottomLeft: "┗",
+ BottomRight: "┛",
+ MiddleLeft: "┣",
+ MiddleRight: "┫",
+ Middle: "╋",
+ MiddleTop: "┳",
+ MiddleBottom: "┻",
}
doubleBorder = Border{
- Top: "═",
- Bottom: "═",
- Left: "║",
- Right: "║",
- TopLeft: "╔",
- TopRight: "╗",
- BottomLeft: "╚",
- BottomRight: "╝",
+ Top: "═",
+ Bottom: "═",
+ Left: "║",
+ Right: "║",
+ TopLeft: "╔",
+ TopRight: "╗",
+ BottomLeft: "╚",
+ BottomRight: "╝",
+ MiddleLeft: "╠",
+ MiddleRight: "╣",
+ Middle: "╬",
+ MiddleTop: "╦",
+ MiddleBottom: "╩",
}
hiddenBorder = Border{
- Top: " ",
- Bottom: " ",
- Left: " ",
- Right: " ",
- TopLeft: " ",
- TopRight: " ",
- BottomLeft: " ",
- BottomRight: " ",
+ Top: " ",
+ Bottom: " ",
+ Left: " ",
+ Right: " ",
+ TopLeft: " ",
+ TopRight: " ",
+ BottomLeft: " ",
+ BottomRight: " ",
+ MiddleLeft: " ",
+ MiddleRight: " ",
+ Middle: " ",
+ MiddleTop: " ",
+ MiddleBottom: " ",
+ }
+
+ markdownBorder = Border{
+ Top: "-",
+ Bottom: "-",
+ Left: "|",
+ Right: "|",
+ TopLeft: "|",
+ TopRight: "|",
+ BottomLeft: "|",
+ BottomRight: "|",
+ MiddleLeft: "|",
+ MiddleRight: "|",
+ Middle: "|",
+ MiddleTop: "|",
+ MiddleBottom: "|",
+ }
+
+ asciiBorder = Border{
+ Top: "-",
+ Bottom: "-",
+ Left: "|",
+ Right: "|",
+ TopLeft: "+",
+ TopRight: "+",
+ BottomLeft: "+",
+ BottomRight: "+",
+ MiddleLeft: "+",
+ MiddleRight: "+",
+ Middle: "+",
+ MiddleTop: "+",
+ MiddleBottom: "+",
}
)
@@ -196,13 +263,23 @@ func HiddenBorder() Border {
return hiddenBorder
}
+// MarkdownBorder return a table border in markdown style.
+//
+// Make sure to disable top and bottom border for the best result. This will
+// ensure that the output is valid markdown.
+//
+// table.New().Border(lipgloss.MarkdownBorder()).BorderTop(false).BorderBottom(false)
+func MarkdownBorder() Border {
+ return markdownBorder
+}
+
+// ASCIIBorder returns a table border with ASCII characters.
+func ASCIIBorder() Border {
+ return asciiBorder
+}
+
func (s Style) applyBorder(str string) string {
var (
- topSet = s.isSet(borderTopKey)
- rightSet = s.isSet(borderRightKey)
- bottomSet = s.isSet(borderBottomKey)
- leftSet = s.isSet(borderLeftKey)
-
border = s.getBorderStyle()
hasTop = s.getAsBool(borderTopKey, false)
hasRight = s.getAsBool(borderRightKey, false)
@@ -222,7 +299,7 @@ func (s Style) applyBorder(str string) string {
// If a border is set and no sides have been specifically turned on or off
// render borders on all sides.
- if border != noBorder && !(topSet || rightSet || bottomSet || leftSet) {
+ if s.implicitBorders() {
hasTop = true
hasRight = true
hasBottom = true
@@ -346,16 +423,12 @@ func (s Style) applyBorder(str string) string {
// Render the horizontal (top or bottom) portion of a border.
func renderHorizontalEdge(left, middle, right string, width int) string {
- if width < 1 {
- return ""
- }
-
if middle == "" {
middle = " "
}
- leftWidth := ansi.PrintableRuneWidth(left)
- rightWidth := ansi.PrintableRuneWidth(right)
+ leftWidth := ansi.StringWidth(left)
+ rightWidth := ansi.StringWidth(right)
runes := []rune(middle)
j := 0
@@ -368,7 +441,7 @@ func renderHorizontalEdge(left, middle, right string, width int) string {
if j >= len(runes) {
j = 0
}
- i += ansi.PrintableRuneWidth(string(runes[j]))
+ i += ansi.StringWidth(string(runes[j]))
}
out.WriteString(right)
@@ -381,7 +454,7 @@ func (s Style) styleBorder(border string, fg, bg TerminalColor) string {
return border
}
- var style = termenv.Style{}
+ style := termenv.Style{}
if fg != noColor {
style = style.Foreground(fg.color(s.r))
@@ -393,13 +466,18 @@ func (s Style) styleBorder(border string, fg, bg TerminalColor) string {
return style.Styled(border)
}
-func maxRuneWidth(str string) (width int) {
- for _, r := range str {
- w := runewidth.RuneWidth(r)
+func maxRuneWidth(str string) int {
+ var width int
+
+ state := -1
+ for len(str) > 0 {
+ var w int
+ _, str, w, state = uniseg.FirstGraphemeClusterInString(str, state)
if w > width {
width = w
}
}
+
return width
}
diff --git a/vendor/github.com/charmbracelet/lipgloss/color.go b/vendor/github.com/charmbracelet/lipgloss/color.go
index 43f5b434..6caf3a3d 100644
--- a/vendor/github.com/charmbracelet/lipgloss/color.go
+++ b/vendor/github.com/charmbracelet/lipgloss/color.go
@@ -20,7 +20,7 @@ var noColor = NoColor{}
//
// Example usage:
//
-// var style = someStyle.Copy().Background(lipgloss.NoColor{})
+// var style = someStyle.Background(lipgloss.NoColor{})
type NoColor struct{}
func (NoColor) color(*Renderer) termenv.Color {
@@ -35,7 +35,7 @@ func (NoColor) color(*Renderer) termenv.Color {
//
// Deprecated.
func (n NoColor) RGBA() (r, g, b, a uint32) {
- return 0x0, 0x0, 0x0, 0xFFFF //nolint:gomnd
+ return 0x0, 0x0, 0x0, 0xFFFF //nolint:mnd
}
// Color specifies a color by hex or ANSI value. For example:
diff --git a/vendor/github.com/charmbracelet/lipgloss/get.go b/vendor/github.com/charmbracelet/lipgloss/get.go
index d0f0826e..422b4ce9 100644
--- a/vendor/github.com/charmbracelet/lipgloss/get.go
+++ b/vendor/github.com/charmbracelet/lipgloss/get.go
@@ -3,7 +3,7 @@ package lipgloss
import (
"strings"
- "github.com/muesli/reflow/ansi"
+ "github.com/charmbracelet/x/ansi"
)
// GetBold returns the style's bold value. If no value is set false is returned.
@@ -300,7 +300,7 @@ func (s Style) GetBorderTopWidth() int {
// runes of varying widths, the widest rune is returned. If no border exists on
// the top edge, 0 is returned.
func (s Style) GetBorderTopSize() int {
- if !s.getAsBool(borderTopKey, false) {
+ if !s.getAsBool(borderTopKey, false) && !s.implicitBorders() {
return 0
}
return s.getBorderStyle().GetTopSize()
@@ -310,7 +310,7 @@ func (s Style) GetBorderTopSize() int {
// runes of varying widths, the widest rune is returned. If no border exists on
// the left edge, 0 is returned.
func (s Style) GetBorderLeftSize() int {
- if !s.getAsBool(borderLeftKey, false) {
+ if !s.getAsBool(borderLeftKey, false) && !s.implicitBorders() {
return 0
}
return s.getBorderStyle().GetLeftSize()
@@ -320,7 +320,7 @@ func (s Style) GetBorderLeftSize() int {
// contain runes of varying widths, the widest rune is returned. If no border
// exists on the left edge, 0 is returned.
func (s Style) GetBorderBottomSize() int {
- if !s.getAsBool(borderBottomKey, false) {
+ if !s.getAsBool(borderBottomKey, false) && !s.implicitBorders() {
return 0
}
return s.getBorderStyle().GetBottomSize()
@@ -330,26 +330,24 @@ func (s Style) GetBorderBottomSize() int {
// contain runes of varying widths, the widest rune is returned. If no border
// exists on the right edge, 0 is returned.
func (s Style) GetBorderRightSize() int {
- if !s.getAsBool(borderRightKey, false) {
+ if !s.getAsBool(borderRightKey, false) && !s.implicitBorders() {
return 0
}
- return s.getBorderStyle().GetBottomSize()
+ return s.getBorderStyle().GetRightSize()
}
// GetHorizontalBorderSize returns the width of the horizontal borders. If
// borders contain runes of varying widths, the widest rune is returned. If no
// border exists on the horizontal edges, 0 is returned.
func (s Style) GetHorizontalBorderSize() int {
- b := s.getBorderStyle()
- return b.GetLeftSize() + b.GetRightSize()
+ return s.GetBorderLeftSize() + s.GetBorderRightSize()
}
// GetVerticalBorderSize returns the width of the vertical borders. If
// borders contain runes of varying widths, the widest rune is returned. If no
// border exists on the vertical edges, 0 is returned.
func (s Style) GetVerticalBorderSize() int {
- b := s.getBorderStyle()
- return b.GetTopSize() + b.GetBottomSize()
+ return s.GetBorderTopSize() + s.GetBorderBottomSize()
}
// GetInline returns the style's inline setting. If no value is set false is
@@ -410,65 +408,136 @@ func (s Style) GetFrameSize() (x, y int) {
return s.GetHorizontalFrameSize(), s.GetVerticalFrameSize()
}
+// GetTransform returns the transform set on the style. If no transform is set
+// nil is returned.
+func (s Style) GetTransform() func(string) string {
+ return s.getAsTransform(transformKey)
+}
+
// Returns whether or not the given property is set.
func (s Style) isSet(k propKey) bool {
- _, exists := s.rules[k]
- return exists
+ return s.props.has(k)
}
func (s Style) getAsBool(k propKey, defaultVal bool) bool {
- v, ok := s.rules[k]
- if !ok {
+ if !s.isSet(k) {
return defaultVal
}
- if b, ok := v.(bool); ok {
- return b
- }
- return defaultVal
+ return s.attrs&int(k) != 0
}
func (s Style) getAsColor(k propKey) TerminalColor {
- v, ok := s.rules[k]
- if !ok {
+ if !s.isSet(k) {
return noColor
}
- if c, ok := v.(TerminalColor); ok {
+
+ var c TerminalColor
+ switch k { //nolint:exhaustive
+ case foregroundKey:
+ c = s.fgColor
+ case backgroundKey:
+ c = s.bgColor
+ case marginBackgroundKey:
+ c = s.marginBgColor
+ case borderTopForegroundKey:
+ c = s.borderTopFgColor
+ case borderRightForegroundKey:
+ c = s.borderRightFgColor
+ case borderBottomForegroundKey:
+ c = s.borderBottomFgColor
+ case borderLeftForegroundKey:
+ c = s.borderLeftFgColor
+ case borderTopBackgroundKey:
+ c = s.borderTopBgColor
+ case borderRightBackgroundKey:
+ c = s.borderRightBgColor
+ case borderBottomBackgroundKey:
+ c = s.borderBottomBgColor
+ case borderLeftBackgroundKey:
+ c = s.borderLeftBgColor
+ }
+
+ if c != nil {
return c
}
+
return noColor
}
func (s Style) getAsInt(k propKey) int {
- v, ok := s.rules[k]
- if !ok {
+ if !s.isSet(k) {
return 0
}
- if i, ok := v.(int); ok {
- return i
+ switch k { //nolint:exhaustive
+ case widthKey:
+ return s.width
+ case heightKey:
+ return s.height
+ case paddingTopKey:
+ return s.paddingTop
+ case paddingRightKey:
+ return s.paddingRight
+ case paddingBottomKey:
+ return s.paddingBottom
+ case paddingLeftKey:
+ return s.paddingLeft
+ case marginTopKey:
+ return s.marginTop
+ case marginRightKey:
+ return s.marginRight
+ case marginBottomKey:
+ return s.marginBottom
+ case marginLeftKey:
+ return s.marginLeft
+ case maxWidthKey:
+ return s.maxWidth
+ case maxHeightKey:
+ return s.maxHeight
+ case tabWidthKey:
+ return s.tabWidth
}
return 0
}
func (s Style) getAsPosition(k propKey) Position {
- v, ok := s.rules[k]
- if !ok {
+ if !s.isSet(k) {
return Position(0)
}
- if p, ok := v.(Position); ok {
- return p
+ switch k { //nolint:exhaustive
+ case alignHorizontalKey:
+ return s.alignHorizontal
+ case alignVerticalKey:
+ return s.alignVertical
}
return Position(0)
}
func (s Style) getBorderStyle() Border {
- v, ok := s.rules[borderStyleKey]
- if !ok {
+ if !s.isSet(borderStyleKey) {
return noBorder
}
- if b, ok := v.(Border); ok {
- return b
+ return s.borderStyle
+}
+
+// Returns whether or not the style has implicit borders. This happens when
+// a border style has been set but no border sides have been explicitly turned
+// on or off.
+func (s Style) implicitBorders() bool {
+ var (
+ borderStyle = s.getBorderStyle()
+ topSet = s.isSet(borderTopKey)
+ rightSet = s.isSet(borderRightKey)
+ bottomSet = s.isSet(borderBottomKey)
+ leftSet = s.isSet(borderLeftKey)
+ )
+ return borderStyle != noBorder && !(topSet || rightSet || bottomSet || leftSet)
+}
+
+func (s Style) getAsTransform(propKey) func(string) string {
+ if !s.isSet(transformKey) {
+ return nil
}
- return noBorder
+ return s.transform
}
// Split a string into lines, additionally returning the size of the widest
@@ -477,7 +546,7 @@ func getLines(s string) (lines []string, widest int) {
lines = strings.Split(s, "\n")
for _, l := range lines {
- w := ansi.PrintableRuneWidth(l)
+ w := ansi.StringWidth(l)
if widest < w {
widest = w
}
diff --git a/vendor/github.com/charmbracelet/lipgloss/join.go b/vendor/github.com/charmbracelet/lipgloss/join.go
index f265976e..b0a23a54 100644
--- a/vendor/github.com/charmbracelet/lipgloss/join.go
+++ b/vendor/github.com/charmbracelet/lipgloss/join.go
@@ -4,7 +4,7 @@ import (
"math"
"strings"
- "github.com/muesli/reflow/ansi"
+ "github.com/charmbracelet/x/ansi"
)
// JoinHorizontal is a utility function for horizontally joining two
@@ -12,7 +12,7 @@ import (
// the position, with 0 being all the way at the top and 1 being all the way
// at the bottom.
//
-// If you just want to align to the left, right or center you may as well just
+// If you just want to align to the top, center or bottom you may as well just
// use the helper constants Top, Center, and Bottom.
//
// Example:
@@ -85,7 +85,7 @@ func JoinHorizontal(pos Position, strs ...string) string {
b.WriteString(block[i])
// Also make lines the same length
- b.WriteString(strings.Repeat(" ", maxWidths[j]-ansi.PrintableRuneWidth(block[i])))
+ b.WriteString(strings.Repeat(" ", maxWidths[j]-ansi.StringWidth(block[i])))
}
if i < len(blocks[0])-1 {
b.WriteRune('\n')
@@ -137,7 +137,7 @@ func JoinVertical(pos Position, strs ...string) string {
var b strings.Builder
for i, block := range blocks {
for j, line := range block {
- w := maxWidth - ansi.PrintableRuneWidth(line)
+ w := maxWidth - ansi.StringWidth(line)
switch pos { //nolint:exhaustive
case Left:
diff --git a/vendor/github.com/charmbracelet/lipgloss/position.go b/vendor/github.com/charmbracelet/lipgloss/position.go
index 7d229e03..185f5af3 100644
--- a/vendor/github.com/charmbracelet/lipgloss/position.go
+++ b/vendor/github.com/charmbracelet/lipgloss/position.go
@@ -4,7 +4,7 @@ import (
"math"
"strings"
- "github.com/muesli/reflow/ansi"
+ "github.com/charmbracelet/x/ansi"
)
// Position represents a position along a horizontal or vertical axis. It's in
@@ -66,7 +66,7 @@ func (r *Renderer) PlaceHorizontal(width int, pos Position, str string, opts ...
var b strings.Builder
for i, l := range lines {
// Is this line shorter than the longest line?
- short := max(0, contentWidth-ansi.PrintableRuneWidth(l))
+ short := max(0, contentWidth-ansi.StringWidth(l))
switch pos { //nolint:exhaustive
case Left:
diff --git a/vendor/github.com/charmbracelet/lipgloss/ranges.go b/vendor/github.com/charmbracelet/lipgloss/ranges.go
new file mode 100644
index 00000000..d1716998
--- /dev/null
+++ b/vendor/github.com/charmbracelet/lipgloss/ranges.go
@@ -0,0 +1,48 @@
+package lipgloss
+
+import (
+ "strings"
+
+ "github.com/charmbracelet/x/ansi"
+)
+
+// StyleRanges allows to, given a string, style ranges of it differently.
+// The function will take into account existing styles.
+// Ranges should not overlap.
+func StyleRanges(s string, ranges ...Range) string {
+ if len(ranges) == 0 {
+ return s
+ }
+
+ var buf strings.Builder
+ lastIdx := 0
+ stripped := ansi.Strip(s)
+
+ // Use Truncate and TruncateLeft to style match.MatchedIndexes without
+ // losing the original option style:
+ for _, rng := range ranges {
+ // Add the text before this match
+ if rng.Start > lastIdx {
+ buf.WriteString(ansi.Cut(s, lastIdx, rng.Start))
+ }
+ // Add the matched range with its highlight
+ buf.WriteString(rng.Style.Render(ansi.Cut(stripped, rng.Start, rng.End)))
+ lastIdx = rng.End
+ }
+
+ // Add any remaining text after the last match
+ buf.WriteString(ansi.TruncateLeft(s, lastIdx, ""))
+
+ return buf.String()
+}
+
+// NewRange returns a range that can be used with [StyleRanges].
+func NewRange(start, end int, style Style) Range {
+ return Range{start, end, style}
+}
+
+// Range to be used with [StyleRanges].
+type Range struct {
+ Start, End int
+ Style Style
+}
diff --git a/vendor/github.com/charmbracelet/lipgloss/renderer.go b/vendor/github.com/charmbracelet/lipgloss/renderer.go
index 85ffd254..233aa7c0 100644
--- a/vendor/github.com/charmbracelet/lipgloss/renderer.go
+++ b/vendor/github.com/charmbracelet/lipgloss/renderer.go
@@ -28,9 +28,6 @@ type Renderer struct {
mtx sync.RWMutex
}
-// RendererOption is a function that can be used to configure a [Renderer].
-type RendererOption func(r *Renderer)
-
// DefaultRenderer returns the default renderer.
func DefaultRenderer() *Renderer {
return renderer
diff --git a/vendor/github.com/charmbracelet/lipgloss/set.go b/vendor/github.com/charmbracelet/lipgloss/set.go
index 432eac5d..fde38fae 100644
--- a/vendor/github.com/charmbracelet/lipgloss/set.go
+++ b/vendor/github.com/charmbracelet/lipgloss/set.go
@@ -1,34 +1,161 @@
package lipgloss
-// This could (should) probably just be moved into NewStyle(). We've broken it
-// out, so we can call it in a lazy way.
-func (s *Style) init() {
- if s.rules == nil {
- s.rules = make(rules)
- }
-}
-
// Set a value on the underlying rules map.
func (s *Style) set(key propKey, value interface{}) {
- s.init()
-
- switch v := value.(type) {
- case int:
+ // We don't allow negative integers on any of our other values, so just keep
+ // them at zero or above. We could use uints instead, but the
+ // conversions are a little tedious, so we're sticking with ints for
+ // sake of usability.
+ switch key { //nolint:exhaustive
+ case foregroundKey:
+ s.fgColor = colorOrNil(value)
+ case backgroundKey:
+ s.bgColor = colorOrNil(value)
+ case widthKey:
+ s.width = max(0, value.(int))
+ case heightKey:
+ s.height = max(0, value.(int))
+ case alignHorizontalKey:
+ s.alignHorizontal = value.(Position)
+ case alignVerticalKey:
+ s.alignVertical = value.(Position)
+ case paddingTopKey:
+ s.paddingTop = max(0, value.(int))
+ case paddingRightKey:
+ s.paddingRight = max(0, value.(int))
+ case paddingBottomKey:
+ s.paddingBottom = max(0, value.(int))
+ case paddingLeftKey:
+ s.paddingLeft = max(0, value.(int))
+ case marginTopKey:
+ s.marginTop = max(0, value.(int))
+ case marginRightKey:
+ s.marginRight = max(0, value.(int))
+ case marginBottomKey:
+ s.marginBottom = max(0, value.(int))
+ case marginLeftKey:
+ s.marginLeft = max(0, value.(int))
+ case marginBackgroundKey:
+ s.marginBgColor = colorOrNil(value)
+ case borderStyleKey:
+ s.borderStyle = value.(Border)
+ case borderTopForegroundKey:
+ s.borderTopFgColor = colorOrNil(value)
+ case borderRightForegroundKey:
+ s.borderRightFgColor = colorOrNil(value)
+ case borderBottomForegroundKey:
+ s.borderBottomFgColor = colorOrNil(value)
+ case borderLeftForegroundKey:
+ s.borderLeftFgColor = colorOrNil(value)
+ case borderTopBackgroundKey:
+ s.borderTopBgColor = colorOrNil(value)
+ case borderRightBackgroundKey:
+ s.borderRightBgColor = colorOrNil(value)
+ case borderBottomBackgroundKey:
+ s.borderBottomBgColor = colorOrNil(value)
+ case borderLeftBackgroundKey:
+ s.borderLeftBgColor = colorOrNil(value)
+ case maxWidthKey:
+ s.maxWidth = max(0, value.(int))
+ case maxHeightKey:
+ s.maxHeight = max(0, value.(int))
+ case tabWidthKey:
// TabWidth is the only property that may have a negative value (and
// that negative value can be no less than -1).
- if key == tabWidthKey {
- s.rules[key] = v
- break
+ s.tabWidth = value.(int)
+ case transformKey:
+ s.transform = value.(func(string) string)
+ default:
+ if v, ok := value.(bool); ok { //nolint:nestif
+ if v {
+ s.attrs |= int(key)
+ } else {
+ s.attrs &^= int(key)
+ }
+ } else if attrs, ok := value.(int); ok {
+ // bool attrs
+ if attrs&int(key) != 0 {
+ s.attrs |= int(key)
+ } else {
+ s.attrs &^= int(key)
+ }
}
+ }
- // We don't allow negative integers on any of our other values, so just keep
- // them at zero or above. We could use uints instead, but the
- // conversions are a little tedious, so we're sticking with ints for
- // sake of usability.
- s.rules[key] = max(0, v)
+ // Set the prop on
+ s.props = s.props.set(key)
+}
+
+// setFrom sets the property from another style.
+func (s *Style) setFrom(key propKey, i Style) {
+ switch key { //nolint:exhaustive
+ case foregroundKey:
+ s.set(foregroundKey, i.fgColor)
+ case backgroundKey:
+ s.set(backgroundKey, i.bgColor)
+ case widthKey:
+ s.set(widthKey, i.width)
+ case heightKey:
+ s.set(heightKey, i.height)
+ case alignHorizontalKey:
+ s.set(alignHorizontalKey, i.alignHorizontal)
+ case alignVerticalKey:
+ s.set(alignVerticalKey, i.alignVertical)
+ case paddingTopKey:
+ s.set(paddingTopKey, i.paddingTop)
+ case paddingRightKey:
+ s.set(paddingRightKey, i.paddingRight)
+ case paddingBottomKey:
+ s.set(paddingBottomKey, i.paddingBottom)
+ case paddingLeftKey:
+ s.set(paddingLeftKey, i.paddingLeft)
+ case marginTopKey:
+ s.set(marginTopKey, i.marginTop)
+ case marginRightKey:
+ s.set(marginRightKey, i.marginRight)
+ case marginBottomKey:
+ s.set(marginBottomKey, i.marginBottom)
+ case marginLeftKey:
+ s.set(marginLeftKey, i.marginLeft)
+ case marginBackgroundKey:
+ s.set(marginBackgroundKey, i.marginBgColor)
+ case borderStyleKey:
+ s.set(borderStyleKey, i.borderStyle)
+ case borderTopForegroundKey:
+ s.set(borderTopForegroundKey, i.borderTopFgColor)
+ case borderRightForegroundKey:
+ s.set(borderRightForegroundKey, i.borderRightFgColor)
+ case borderBottomForegroundKey:
+ s.set(borderBottomForegroundKey, i.borderBottomFgColor)
+ case borderLeftForegroundKey:
+ s.set(borderLeftForegroundKey, i.borderLeftFgColor)
+ case borderTopBackgroundKey:
+ s.set(borderTopBackgroundKey, i.borderTopBgColor)
+ case borderRightBackgroundKey:
+ s.set(borderRightBackgroundKey, i.borderRightBgColor)
+ case borderBottomBackgroundKey:
+ s.set(borderBottomBackgroundKey, i.borderBottomBgColor)
+ case borderLeftBackgroundKey:
+ s.set(borderLeftBackgroundKey, i.borderLeftBgColor)
+ case maxWidthKey:
+ s.set(maxWidthKey, i.maxWidth)
+ case maxHeightKey:
+ s.set(maxHeightKey, i.maxHeight)
+ case tabWidthKey:
+ s.set(tabWidthKey, i.tabWidth)
+ case transformKey:
+ s.set(transformKey, i.transform)
default:
- s.rules[key] = v
+ // Set attributes for set bool properties
+ s.set(key, i.attrs)
+ }
+}
+
+func colorOrNil(c interface{}) TerminalColor {
+ if c, ok := c.(TerminalColor); ok {
+ return c
}
+ return nil
}
// Bold sets a bold formatting rule.
@@ -115,7 +242,7 @@ func (s Style) Height(i int) Style {
//
// With one argument, the position value is applied to the horizontal alignment.
//
-// With two arguments, the value is applied to the vertical and horizontal
+// With two arguments, the value is applied to the horizontal and vertical
// alignments, in that order.
func (s Style) Align(p ...Position) Style {
if len(p) > 0 {
@@ -194,6 +321,8 @@ func (s Style) PaddingBottom(i int) Style {
// applied to the padding. This is true by default as it's more than likely the
// desired and expected behavior, but it can be disabled for certain graphic
// effects.
+//
+// Deprecated: Just use margins and padding.
func (s Style) ColorWhitespace(v bool) Style {
s.set(colorWhitespaceKey, v)
return s
@@ -476,7 +605,7 @@ func (s Style) BorderLeftBackground(c TerminalColor) Style {
// var userStyle = text.Style{ /* ... */ }
// fmt.Println(userStyle.Inline(true).Render(userInput))
func (s Style) Inline(v bool) Style {
- o := s.Copy()
+ o := s // copy
o.set(inlineKey, v)
return o
}
@@ -494,7 +623,7 @@ func (s Style) Inline(v bool) Style {
// var userStyle = text.Style{ /* ... */ }
// fmt.Println(userStyle.MaxWidth(16).Render(userInput))
func (s Style) MaxWidth(n int) Style {
- o := s.Copy()
+ o := s // copy
o.set(maxWidthKey, n)
return o
}
@@ -506,7 +635,7 @@ func (s Style) MaxWidth(n int) Style {
// Because this in intended to be used at the time of render, this method will
// not mutate the style and instead returns a copy.
func (s Style) MaxHeight(n int) Style {
- o := s.Copy()
+ o := s // copy
o.set(maxHeightKey, n)
return o
}
@@ -544,6 +673,18 @@ func (s Style) StrikethroughSpaces(v bool) Style {
return s
}
+// Transform applies a given function to a string at render time, allowing for
+// the string being rendered to be manipuated.
+//
+// Example:
+//
+// s := NewStyle().Transform(strings.ToUpper)
+// fmt.Println(s.Render("raow!") // "RAOW!"
+func (s Style) Transform(fn func(string) string) Style {
+ s.set(transformKey, fn)
+ return s
+}
+
// Renderer sets the renderer for the style. This is useful for changing the
// renderer for a style that is being used in a different context.
func (s Style) Renderer(r *Renderer) Style {
@@ -569,19 +710,19 @@ func whichSidesInt(i ...int) (top, right, bottom, left int, ok bool) {
left = i[0]
right = i[0]
ok = true
- case 2: //nolint:gomnd
+ case 2: //nolint:mnd
top = i[0]
bottom = i[0]
left = i[1]
right = i[1]
ok = true
- case 3: //nolint:gomnd
+ case 3: //nolint:mnd
top = i[0]
left = i[1]
right = i[1]
bottom = i[2]
ok = true
- case 4: //nolint:gomnd
+ case 4: //nolint:mnd
top = i[0]
right = i[1]
bottom = i[2]
@@ -602,19 +743,19 @@ func whichSidesBool(i ...bool) (top, right, bottom, left bool, ok bool) {
left = i[0]
right = i[0]
ok = true
- case 2: //nolint:gomnd
+ case 2: //nolint:mnd
top = i[0]
bottom = i[0]
left = i[1]
right = i[1]
ok = true
- case 3: //nolint:gomnd
+ case 3: //nolint:mnd
top = i[0]
left = i[1]
right = i[1]
bottom = i[2]
ok = true
- case 4: //nolint:gomnd
+ case 4: //nolint:mnd
top = i[0]
right = i[1]
bottom = i[2]
@@ -635,19 +776,19 @@ func whichSidesColor(i ...TerminalColor) (top, right, bottom, left TerminalColor
left = i[0]
right = i[0]
ok = true
- case 2: //nolint:gomnd
+ case 2: //nolint:mnd
top = i[0]
bottom = i[0]
left = i[1]
right = i[1]
ok = true
- case 3: //nolint:gomnd
+ case 3: //nolint:mnd
top = i[0]
left = i[1]
right = i[1]
bottom = i[2]
ok = true
- case 4: //nolint:gomnd
+ case 4: //nolint:mnd
top = i[0]
right = i[1]
bottom = i[2]
diff --git a/vendor/github.com/charmbracelet/lipgloss/size.go b/vendor/github.com/charmbracelet/lipgloss/size.go
index 439a5cb8..e169ff5e 100644
--- a/vendor/github.com/charmbracelet/lipgloss/size.go
+++ b/vendor/github.com/charmbracelet/lipgloss/size.go
@@ -3,7 +3,7 @@ package lipgloss
import (
"strings"
- "github.com/muesli/reflow/ansi"
+ "github.com/charmbracelet/x/ansi"
)
// Width returns the cell width of characters in the string. ANSI sequences are
@@ -14,7 +14,7 @@ import (
// will give you accurate results.
func Width(str string) (width int) {
for _, l := range strings.Split(str, "\n") {
- w := ansi.PrintableRuneWidth(l)
+ w := ansi.StringWidth(l)
if w > width {
width = w
}
diff --git a/vendor/github.com/charmbracelet/lipgloss/style.go b/vendor/github.com/charmbracelet/lipgloss/style.go
index ee50bcf7..59fa3ab2 100644
--- a/vendor/github.com/charmbracelet/lipgloss/style.go
+++ b/vendor/github.com/charmbracelet/lipgloss/style.go
@@ -4,26 +4,31 @@ import (
"strings"
"unicode"
- "github.com/muesli/reflow/truncate"
- "github.com/muesli/reflow/wordwrap"
- "github.com/muesli/reflow/wrap"
+ "github.com/charmbracelet/x/ansi"
+ "github.com/charmbracelet/x/cellbuf"
"github.com/muesli/termenv"
)
const tabWidthDefault = 4
// Property for a key.
-type propKey int
+type propKey int64
// Available properties.
const (
- boldKey propKey = iota
+ // Boolean props come first.
+ boldKey propKey = 1 << iota
italicKey
underlineKey
strikethroughKey
reverseKey
blinkKey
faintKey
+ underlineSpacesKey
+ strikethroughSpacesKey
+ colorWhitespaceKey
+
+ // Non-boolean props.
foregroundKey
backgroundKey
widthKey
@@ -37,8 +42,6 @@ const (
paddingBottomKey
paddingLeftKey
- colorWhitespaceKey
-
// Margins.
marginTopKey
marginRightKey
@@ -71,12 +74,27 @@ const (
maxWidthKey
maxHeightKey
tabWidthKey
- underlineSpacesKey
- strikethroughSpacesKey
+
+ transformKey
)
-// A set of properties.
-type rules map[propKey]interface{}
+// props is a set of properties.
+type props int64
+
+// set sets a property.
+func (p props) set(k propKey) props {
+ return p | props(k)
+}
+
+// unset unsets a property.
+func (p props) unset(k propKey) props {
+ return p &^ props(k)
+}
+
+// has checks if a property is set.
+func (p props) has(k propKey) bool {
+ return p&props(k) != 0
+}
// NewStyle returns a new, empty Style. While it's syntactic sugar for the
// Style{} primitive, it's recommended to use this function for creating styles
@@ -98,8 +116,48 @@ func (r *Renderer) NewStyle() Style {
// Style contains a set of rules that comprise a style as a whole.
type Style struct {
r *Renderer
- rules map[propKey]interface{}
+ props props
value string
+
+ // we store bool props values here
+ attrs int
+
+ // props that have values
+ fgColor TerminalColor
+ bgColor TerminalColor
+
+ width int
+ height int
+
+ alignHorizontal Position
+ alignVertical Position
+
+ paddingTop int
+ paddingRight int
+ paddingBottom int
+ paddingLeft int
+
+ marginTop int
+ marginRight int
+ marginBottom int
+ marginLeft int
+ marginBgColor TerminalColor
+
+ borderStyle Border
+ borderTopFgColor TerminalColor
+ borderRightFgColor TerminalColor
+ borderBottomFgColor TerminalColor
+ borderLeftFgColor TerminalColor
+ borderTopBgColor TerminalColor
+ borderRightBgColor TerminalColor
+ borderBottomBgColor TerminalColor
+ borderLeftBgColor TerminalColor
+
+ maxWidth int
+ maxHeight int
+ tabWidth int
+
+ transform func(string) string
}
// joinString joins a list of strings into a single string separated with a
@@ -131,15 +189,11 @@ func (s Style) String() string {
}
// Copy returns a copy of this style, including any underlying string values.
+//
+// Deprecated: to copy just use assignment (i.e. a := b). All methods also
+// return a new style.
func (s Style) Copy() Style {
- o := NewStyle()
- o.init()
- for k, v := range s.rules {
- o.rules[k] = v
- }
- o.r = s.r
- o.value = s.value
- return o
+ return s
}
// Inherit overlays the style in the argument onto this style by copying each explicitly
@@ -148,9 +202,11 @@ func (s Style) Copy() Style {
//
// Margins, padding, and underlying string values are not inherited.
func (s Style) Inherit(i Style) Style {
- s.init()
+ for k := boldKey; k <= transformKey; k <<= 1 {
+ if !i.isSet(k) {
+ continue
+ }
- for k, v := range i.rules {
switch k { //nolint:exhaustive
case marginTopKey, marginRightKey, marginBottomKey, marginLeftKey:
// Margins are not inherited
@@ -161,14 +217,15 @@ func (s Style) Inherit(i Style) Style {
case backgroundKey:
// The margins also inherit the background color
if !s.isSet(marginBackgroundKey) && !i.isSet(marginBackgroundKey) {
- s.rules[marginBackgroundKey] = v
+ s.set(marginBackgroundKey, i.bgColor)
}
}
- if _, exists := s.rules[k]; exists {
+ if s.isSet(k) {
continue
}
- s.rules[k] = v
+
+ s.setFrom(k, i)
}
return s
}
@@ -216,18 +273,24 @@ func (s Style) Render(strs ...string) string {
maxWidth = s.getAsInt(maxWidthKey)
maxHeight = s.getAsInt(maxHeightKey)
- underlineSpaces = underline && s.getAsBool(underlineSpacesKey, true)
- strikethroughSpaces = strikethrough && s.getAsBool(strikethroughSpacesKey, true)
+ underlineSpaces = s.getAsBool(underlineSpacesKey, false) || (underline && s.getAsBool(underlineSpacesKey, true))
+ strikethroughSpaces = s.getAsBool(strikethroughSpacesKey, false) || (strikethrough && s.getAsBool(strikethroughSpacesKey, true))
// Do we need to style whitespace (padding and space outside
// paragraphs) separately?
styleWhitespace = reverse
// Do we need to style spaces separately?
- useSpaceStyler = underlineSpaces || strikethroughSpaces
+ useSpaceStyler = (underline && !underlineSpaces) || (strikethrough && !strikethroughSpaces) || underlineSpaces || strikethroughSpaces
+
+ transform = s.getAsTransform(transformKey)
)
- if len(s.rules) == 0 {
+ if transform != nil {
+ str = transform(str)
+ }
+
+ if s.props == 0 {
return s.maybeConvertTabs(str)
}
@@ -245,9 +308,7 @@ func (s Style) Render(strs ...string) string {
te = te.Underline()
}
if reverse {
- if reverse {
- teWhitespace = teWhitespace.Reverse()
- }
+ teWhitespace = teWhitespace.Reverse()
te = te.Reverse()
}
if blink {
@@ -293,6 +354,8 @@ func (s Style) Render(strs ...string) string {
// Potentially convert tabs to spaces
str = s.maybeConvertTabs(str)
+ // carriage returns can cause strange behaviour when rendering.
+ str = strings.ReplaceAll(str, "\r\n", "\n")
// Strip newlines in single line mode
if inline {
@@ -302,8 +365,7 @@ func (s Style) Render(strs ...string) string {
// Word wrap
if !inline && width > 0 {
wrapAt := width - leftPadding - rightPadding
- str = wordwrap.String(str, wrapAt)
- str = wrap.String(str, wrapAt) // force-wrap long strings
+ str = cellbuf.Wrap(str, wrapAt, "")
}
// Render core text
@@ -333,7 +395,7 @@ func (s Style) Render(strs ...string) string {
}
// Padding
- if !inline {
+ if !inline { //nolint:nestif
if leftPadding > 0 {
var st *termenv.Style
if colorWhitespace || styleWhitespace {
@@ -370,7 +432,7 @@ func (s Style) Render(strs ...string) string {
{
numLines := strings.Count(str, "\n")
- if !(numLines == 0 && width == 0) {
+ if numLines != 0 || width != 0 {
var st *termenv.Style
if colorWhitespace || styleWhitespace {
st = &teWhitespace
@@ -389,7 +451,7 @@ func (s Style) Render(strs ...string) string {
lines := strings.Split(str, "\n")
for i := range lines {
- lines[i] = truncate.String(lines[i], uint(maxWidth))
+ lines[i] = ansi.Truncate(lines[i], maxWidth, "")
}
str = strings.Join(lines, "\n")
@@ -398,7 +460,10 @@ func (s Style) Render(strs ...string) string {
// Truncate according to MaxHeight
if maxHeight > 0 {
lines := strings.Split(str, "\n")
- str = strings.Join(lines[:min(maxHeight, len(lines))], "\n")
+ height := min(maxHeight, len(lines))
+ if len(lines) > 0 {
+ str = strings.Join(lines[:height], "\n")
+ }
}
return str
@@ -456,36 +521,23 @@ func (s Style) applyMargins(str string, inline bool) string {
// Apply left padding.
func padLeft(str string, n int, style *termenv.Style) string {
- if n == 0 {
- return str
- }
-
- sp := strings.Repeat(" ", n)
- if style != nil {
- sp = style.Styled(sp)
- }
-
- b := strings.Builder{}
- l := strings.Split(str, "\n")
-
- for i := range l {
- b.WriteString(sp)
- b.WriteString(l[i])
- if i != len(l)-1 {
- b.WriteRune('\n')
- }
- }
-
- return b.String()
+ return pad(str, -n, style)
}
// Apply right padding.
func padRight(str string, n int, style *termenv.Style) string {
- if n == 0 || str == "" {
+ return pad(str, n, style)
+}
+
+// pad adds padding to either the left or right side of a string.
+// Positive values add to the right side while negative values
+// add to the left side.
+func pad(str string, n int, style *termenv.Style) string {
+ if n == 0 {
return str
}
- sp := strings.Repeat(" ", n)
+ sp := strings.Repeat(" ", abs(n))
if style != nil {
sp = style.Styled(sp)
}
@@ -494,8 +546,17 @@ func padRight(str string, n int, style *termenv.Style) string {
l := strings.Split(str, "\n")
for i := range l {
- b.WriteString(l[i])
- b.WriteString(sp)
+ switch {
+ // pad right
+ case n > 0:
+ b.WriteString(l[i])
+ b.WriteString(sp)
+ // pad left
+ default:
+ b.WriteString(sp)
+ b.WriteString(l[i])
+ }
+
if i != len(l)-1 {
b.WriteRune('\n')
}
@@ -504,16 +565,24 @@ func padRight(str string, n int, style *termenv.Style) string {
return b.String()
}
-func max(a, b int) int {
+func max(a, b int) int { //nolint:unparam,predeclared
if a > b {
return a
}
return b
}
-func min(a, b int) int {
+func min(a, b int) int { //nolint:predeclared
if a < b {
return a
}
return b
}
+
+func abs(a int) int {
+ if a < 0 {
+ return -a
+ }
+
+ return a
+}
diff --git a/vendor/github.com/charmbracelet/lipgloss/unset.go b/vendor/github.com/charmbracelet/lipgloss/unset.go
index f889f9e2..1086e722 100644
--- a/vendor/github.com/charmbracelet/lipgloss/unset.go
+++ b/vendor/github.com/charmbracelet/lipgloss/unset.go
@@ -1,159 +1,164 @@
package lipgloss
+// unset unsets a property from a style.
+func (s *Style) unset(key propKey) {
+ s.props = s.props.unset(key)
+}
+
// UnsetBold removes the bold style rule, if set.
func (s Style) UnsetBold() Style {
- delete(s.rules, boldKey)
+ s.unset(boldKey)
return s
}
// UnsetItalic removes the italic style rule, if set.
func (s Style) UnsetItalic() Style {
- delete(s.rules, italicKey)
+ s.unset(italicKey)
return s
}
// UnsetUnderline removes the underline style rule, if set.
func (s Style) UnsetUnderline() Style {
- delete(s.rules, underlineKey)
+ s.unset(underlineKey)
return s
}
// UnsetStrikethrough removes the strikethrough style rule, if set.
func (s Style) UnsetStrikethrough() Style {
- delete(s.rules, strikethroughKey)
+ s.unset(strikethroughKey)
return s
}
// UnsetReverse removes the reverse style rule, if set.
func (s Style) UnsetReverse() Style {
- delete(s.rules, reverseKey)
+ s.unset(reverseKey)
return s
}
// UnsetBlink removes the blink style rule, if set.
func (s Style) UnsetBlink() Style {
- delete(s.rules, blinkKey)
+ s.unset(blinkKey)
return s
}
// UnsetFaint removes the faint style rule, if set.
func (s Style) UnsetFaint() Style {
- delete(s.rules, faintKey)
+ s.unset(faintKey)
return s
}
// UnsetForeground removes the foreground style rule, if set.
func (s Style) UnsetForeground() Style {
- delete(s.rules, foregroundKey)
+ s.unset(foregroundKey)
return s
}
// UnsetBackground removes the background style rule, if set.
func (s Style) UnsetBackground() Style {
- delete(s.rules, backgroundKey)
+ s.unset(backgroundKey)
return s
}
// UnsetWidth removes the width style rule, if set.
func (s Style) UnsetWidth() Style {
- delete(s.rules, widthKey)
+ s.unset(widthKey)
return s
}
// UnsetHeight removes the height style rule, if set.
func (s Style) UnsetHeight() Style {
- delete(s.rules, heightKey)
+ s.unset(heightKey)
return s
}
// UnsetAlign removes the horizontal and vertical text alignment style rule, if set.
func (s Style) UnsetAlign() Style {
- delete(s.rules, alignHorizontalKey)
- delete(s.rules, alignVerticalKey)
+ s.unset(alignHorizontalKey)
+ s.unset(alignVerticalKey)
return s
}
// UnsetAlignHorizontal removes the horizontal text alignment style rule, if set.
func (s Style) UnsetAlignHorizontal() Style {
- delete(s.rules, alignHorizontalKey)
+ s.unset(alignHorizontalKey)
return s
}
// UnsetAlignVertical removes the vertical text alignment style rule, if set.
func (s Style) UnsetAlignVertical() Style {
- delete(s.rules, alignVerticalKey)
+ s.unset(alignVerticalKey)
return s
}
// UnsetPadding removes all padding style rules.
func (s Style) UnsetPadding() Style {
- delete(s.rules, paddingLeftKey)
- delete(s.rules, paddingRightKey)
- delete(s.rules, paddingTopKey)
- delete(s.rules, paddingBottomKey)
+ s.unset(paddingLeftKey)
+ s.unset(paddingRightKey)
+ s.unset(paddingTopKey)
+ s.unset(paddingBottomKey)
return s
}
// UnsetPaddingLeft removes the left padding style rule, if set.
func (s Style) UnsetPaddingLeft() Style {
- delete(s.rules, paddingLeftKey)
+ s.unset(paddingLeftKey)
return s
}
// UnsetPaddingRight removes the right padding style rule, if set.
func (s Style) UnsetPaddingRight() Style {
- delete(s.rules, paddingRightKey)
+ s.unset(paddingRightKey)
return s
}
// UnsetPaddingTop removes the top padding style rule, if set.
func (s Style) UnsetPaddingTop() Style {
- delete(s.rules, paddingTopKey)
+ s.unset(paddingTopKey)
return s
}
// UnsetPaddingBottom removes the bottom padding style rule, if set.
func (s Style) UnsetPaddingBottom() Style {
- delete(s.rules, paddingBottomKey)
+ s.unset(paddingBottomKey)
return s
}
// UnsetColorWhitespace removes the rule for coloring padding, if set.
func (s Style) UnsetColorWhitespace() Style {
- delete(s.rules, colorWhitespaceKey)
+ s.unset(colorWhitespaceKey)
return s
}
// UnsetMargins removes all margin style rules.
func (s Style) UnsetMargins() Style {
- delete(s.rules, marginLeftKey)
- delete(s.rules, marginRightKey)
- delete(s.rules, marginTopKey)
- delete(s.rules, marginBottomKey)
+ s.unset(marginLeftKey)
+ s.unset(marginRightKey)
+ s.unset(marginTopKey)
+ s.unset(marginBottomKey)
return s
}
// UnsetMarginLeft removes the left margin style rule, if set.
func (s Style) UnsetMarginLeft() Style {
- delete(s.rules, marginLeftKey)
+ s.unset(marginLeftKey)
return s
}
// UnsetMarginRight removes the right margin style rule, if set.
func (s Style) UnsetMarginRight() Style {
- delete(s.rules, marginRightKey)
+ s.unset(marginRightKey)
return s
}
// UnsetMarginTop removes the top margin style rule, if set.
func (s Style) UnsetMarginTop() Style {
- delete(s.rules, marginTopKey)
+ s.unset(marginTopKey)
return s
}
// UnsetMarginBottom removes the bottom margin style rule, if set.
func (s Style) UnsetMarginBottom() Style {
- delete(s.rules, marginBottomKey)
+ s.unset(marginBottomKey)
return s
}
@@ -161,147 +166,161 @@ func (s Style) UnsetMarginBottom() Style {
// margin's background color can be set from the background color of another
// style during inheritance.
func (s Style) UnsetMarginBackground() Style {
- delete(s.rules, marginBackgroundKey)
+ s.unset(marginBackgroundKey)
return s
}
// UnsetBorderStyle removes the border style rule, if set.
func (s Style) UnsetBorderStyle() Style {
- delete(s.rules, borderStyleKey)
+ s.unset(borderStyleKey)
return s
}
// UnsetBorderTop removes the border top style rule, if set.
func (s Style) UnsetBorderTop() Style {
- delete(s.rules, borderTopKey)
+ s.unset(borderTopKey)
return s
}
// UnsetBorderRight removes the border right style rule, if set.
func (s Style) UnsetBorderRight() Style {
- delete(s.rules, borderRightKey)
+ s.unset(borderRightKey)
return s
}
// UnsetBorderBottom removes the border bottom style rule, if set.
func (s Style) UnsetBorderBottom() Style {
- delete(s.rules, borderBottomKey)
+ s.unset(borderBottomKey)
return s
}
// UnsetBorderLeft removes the border left style rule, if set.
func (s Style) UnsetBorderLeft() Style {
- delete(s.rules, borderLeftKey)
+ s.unset(borderLeftKey)
return s
}
// UnsetBorderForeground removes all border foreground color styles, if set.
func (s Style) UnsetBorderForeground() Style {
- delete(s.rules, borderTopForegroundKey)
- delete(s.rules, borderRightForegroundKey)
- delete(s.rules, borderBottomForegroundKey)
- delete(s.rules, borderLeftForegroundKey)
+ s.unset(borderTopForegroundKey)
+ s.unset(borderRightForegroundKey)
+ s.unset(borderBottomForegroundKey)
+ s.unset(borderLeftForegroundKey)
return s
}
// UnsetBorderTopForeground removes the top border foreground color rule,
// if set.
func (s Style) UnsetBorderTopForeground() Style {
- delete(s.rules, borderTopForegroundKey)
+ s.unset(borderTopForegroundKey)
return s
}
// UnsetBorderRightForeground removes the right border foreground color rule,
// if set.
func (s Style) UnsetBorderRightForeground() Style {
- delete(s.rules, borderRightForegroundKey)
+ s.unset(borderRightForegroundKey)
return s
}
// UnsetBorderBottomForeground removes the bottom border foreground color
// rule, if set.
func (s Style) UnsetBorderBottomForeground() Style {
- delete(s.rules, borderBottomForegroundKey)
+ s.unset(borderBottomForegroundKey)
return s
}
// UnsetBorderLeftForeground removes the left border foreground color rule,
// if set.
func (s Style) UnsetBorderLeftForeground() Style {
- delete(s.rules, borderLeftForegroundKey)
+ s.unset(borderLeftForegroundKey)
return s
}
// UnsetBorderBackground removes all border background color styles, if
// set.
func (s Style) UnsetBorderBackground() Style {
- delete(s.rules, borderTopBackgroundKey)
- delete(s.rules, borderRightBackgroundKey)
- delete(s.rules, borderBottomBackgroundKey)
- delete(s.rules, borderLeftBackgroundKey)
+ s.unset(borderTopBackgroundKey)
+ s.unset(borderRightBackgroundKey)
+ s.unset(borderBottomBackgroundKey)
+ s.unset(borderLeftBackgroundKey)
return s
}
// UnsetBorderTopBackgroundColor removes the top border background color rule,
// if set.
+//
+// Deprecated: This function simply calls Style.UnsetBorderTopBackground.
func (s Style) UnsetBorderTopBackgroundColor() Style {
- delete(s.rules, borderTopBackgroundKey)
+ return s.UnsetBorderTopBackground()
+}
+
+// UnsetBorderTopBackground removes the top border background color rule,
+// if set.
+func (s Style) UnsetBorderTopBackground() Style {
+ s.unset(borderTopBackgroundKey)
return s
}
// UnsetBorderRightBackground removes the right border background color
// rule, if set.
func (s Style) UnsetBorderRightBackground() Style {
- delete(s.rules, borderRightBackgroundKey)
+ s.unset(borderRightBackgroundKey)
return s
}
// UnsetBorderBottomBackground removes the bottom border background color
// rule, if set.
func (s Style) UnsetBorderBottomBackground() Style {
- delete(s.rules, borderBottomBackgroundKey)
+ s.unset(borderBottomBackgroundKey)
return s
}
// UnsetBorderLeftBackground removes the left border color rule, if set.
func (s Style) UnsetBorderLeftBackground() Style {
- delete(s.rules, borderLeftBackgroundKey)
+ s.unset(borderLeftBackgroundKey)
return s
}
// UnsetInline removes the inline style rule, if set.
func (s Style) UnsetInline() Style {
- delete(s.rules, inlineKey)
+ s.unset(inlineKey)
return s
}
// UnsetMaxWidth removes the max width style rule, if set.
func (s Style) UnsetMaxWidth() Style {
- delete(s.rules, maxWidthKey)
+ s.unset(maxWidthKey)
return s
}
// UnsetMaxHeight removes the max height style rule, if set.
func (s Style) UnsetMaxHeight() Style {
- delete(s.rules, maxHeightKey)
+ s.unset(maxHeightKey)
return s
}
-// UnsetMaxHeight removes the max height style rule, if set.
+// UnsetTabWidth removes the tab width style rule, if set.
func (s Style) UnsetTabWidth() Style {
- delete(s.rules, tabWidthKey)
+ s.unset(tabWidthKey)
return s
}
// UnsetUnderlineSpaces removes the value set by UnderlineSpaces.
func (s Style) UnsetUnderlineSpaces() Style {
- delete(s.rules, underlineSpacesKey)
+ s.unset(underlineSpacesKey)
return s
}
// UnsetStrikethroughSpaces removes the value set by StrikethroughSpaces.
func (s Style) UnsetStrikethroughSpaces() Style {
- delete(s.rules, strikethroughSpacesKey)
+ s.unset(strikethroughSpacesKey)
+ return s
+}
+
+// UnsetTransform removes the value set by Transform.
+func (s Style) UnsetTransform() Style {
+ s.unset(transformKey)
return s
}
diff --git a/vendor/github.com/charmbracelet/lipgloss/whitespace.go b/vendor/github.com/charmbracelet/lipgloss/whitespace.go
index 78815fed..040dc98e 100644
--- a/vendor/github.com/charmbracelet/lipgloss/whitespace.go
+++ b/vendor/github.com/charmbracelet/lipgloss/whitespace.go
@@ -3,7 +3,7 @@ package lipgloss
import (
"strings"
- "github.com/muesli/reflow/ansi"
+ "github.com/charmbracelet/x/ansi"
"github.com/muesli/termenv"
)
@@ -45,12 +45,12 @@ func (w whitespace) render(width int) string {
if j >= len(r) {
j = 0
}
- i += ansi.PrintableRuneWidth(string(r[j]))
+ i += ansi.StringWidth(string(r[j]))
}
// Fill any extra gaps white spaces. This might be necessary if any runes
// are more than one cell wide, which could leave a one-rune gap.
- short := width - ansi.PrintableRuneWidth(b.String())
+ short := width - ansi.StringWidth(b.String())
if short > 0 {
b.WriteString(strings.Repeat(" ", short))
}
diff --git a/vendor/github.com/charmbracelet/x/ansi/BUILD.bazel b/vendor/github.com/charmbracelet/x/ansi/BUILD.bazel
new file mode 100644
index 00000000..9c7f9908
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/BUILD.bazel
@@ -0,0 +1,59 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "ansi.go",
+ "ascii.go",
+ "background.go",
+ "c0.go",
+ "c1.go",
+ "charset.go",
+ "clipboard.go",
+ "color.go",
+ "ctrl.go",
+ "cursor.go",
+ "cwd.go",
+ "doc.go",
+ "focus.go",
+ "graphics.go",
+ "hyperlink.go",
+ "iterm2.go",
+ "keypad.go",
+ "kitty.go",
+ "method.go",
+ "mode.go",
+ "modes.go",
+ "mouse.go",
+ "notification.go",
+ "parser.go",
+ "parser_decode.go",
+ "parser_handler.go",
+ "parser_sync.go",
+ "passthrough.go",
+ "paste.go",
+ "reset.go",
+ "screen.go",
+ "sgr.go",
+ "status.go",
+ "style.go",
+ "termcap.go",
+ "title.go",
+ "truncate.go",
+ "util.go",
+ "width.go",
+ "winop.go",
+ "wrap.go",
+ "xterm.go",
+ ],
+ importmap = "github.com/kindlyops/vbs/vendor/github.com/charmbracelet/x/ansi",
+ importpath = "github.com/charmbracelet/x/ansi",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//vendor/github.com/charmbracelet/x/ansi/kitty:go_default_library",
+ "//vendor/github.com/charmbracelet/x/ansi/parser:go_default_library",
+ "//vendor/github.com/lucasb-eyer/go-colorful:go_default_library",
+ "//vendor/github.com/mattn/go-runewidth:go_default_library",
+ "//vendor/github.com/rivo/uniseg:go_default_library",
+ ],
+)
diff --git a/vendor/github.com/muesli/reflow/LICENSE b/vendor/github.com/charmbracelet/x/ansi/LICENSE
similarity index 96%
rename from vendor/github.com/muesli/reflow/LICENSE
rename to vendor/github.com/charmbracelet/x/ansi/LICENSE
index 8532c45c..65a5654e 100644
--- a/vendor/github.com/muesli/reflow/LICENSE
+++ b/vendor/github.com/charmbracelet/x/ansi/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2019 Christian Muehlhaeuser
+Copyright (c) 2023 Charmbracelet, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/vendor/github.com/charmbracelet/x/ansi/ansi.go b/vendor/github.com/charmbracelet/x/ansi/ansi.go
new file mode 100644
index 00000000..48d873c3
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/ansi.go
@@ -0,0 +1,11 @@
+package ansi
+
+import "io"
+
+// Execute is a function that "execute" the given escape sequence by writing it
+// to the provided output writter.
+//
+// This is a syntactic sugar over [io.WriteString].
+func Execute(w io.Writer, s string) (int, error) {
+ return io.WriteString(w, s)
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/ascii.go b/vendor/github.com/charmbracelet/x/ansi/ascii.go
new file mode 100644
index 00000000..188582f7
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/ascii.go
@@ -0,0 +1,8 @@
+package ansi
+
+const (
+ // SP is the space character (Char: \x20).
+ SP = 0x20
+ // DEL is the delete character (Caret: ^?, Char: \x7f).
+ DEL = 0x7F
+)
diff --git a/vendor/github.com/charmbracelet/x/ansi/background.go b/vendor/github.com/charmbracelet/x/ansi/background.go
new file mode 100644
index 00000000..2383cf09
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/background.go
@@ -0,0 +1,169 @@
+package ansi
+
+import (
+ "fmt"
+ "image/color"
+)
+
+// Colorizer is a [color.Color] interface that can be formatted as a string.
+type Colorizer interface {
+ color.Color
+ fmt.Stringer
+}
+
+// HexColorizer is a [color.Color] that can be formatted as a hex string.
+type HexColorizer struct{ color.Color }
+
+var _ Colorizer = HexColorizer{}
+
+// String returns the color as a hex string. If the color is nil, an empty
+// string is returned.
+func (h HexColorizer) String() string {
+ if h.Color == nil {
+ return ""
+ }
+ r, g, b, _ := h.RGBA()
+ // Get the lower 8 bits
+ r &= 0xff
+ g &= 0xff
+ b &= 0xff
+ return fmt.Sprintf("#%02x%02x%02x", uint8(r), uint8(g), uint8(b)) //nolint:gosec
+}
+
+// XRGBColorizer is a [color.Color] that can be formatted as an XParseColor
+// rgb: string.
+//
+// See: https://linux.die.net/man/3/xparsecolor
+type XRGBColorizer struct{ color.Color }
+
+var _ Colorizer = XRGBColorizer{}
+
+// String returns the color as an XParseColor rgb: string. If the color is nil,
+// an empty string is returned.
+func (x XRGBColorizer) String() string {
+ if x.Color == nil {
+ return ""
+ }
+ r, g, b, _ := x.RGBA()
+ // Get the lower 8 bits
+ return fmt.Sprintf("rgb:%04x/%04x/%04x", r, g, b)
+}
+
+// XRGBAColorizer is a [color.Color] that can be formatted as an XParseColor
+// rgba: string.
+//
+// See: https://linux.die.net/man/3/xparsecolor
+type XRGBAColorizer struct{ color.Color }
+
+var _ Colorizer = XRGBAColorizer{}
+
+// String returns the color as an XParseColor rgba: string. If the color is nil,
+// an empty string is returned.
+func (x XRGBAColorizer) String() string {
+ if x.Color == nil {
+ return ""
+ }
+ r, g, b, a := x.RGBA()
+ // Get the lower 8 bits
+ return fmt.Sprintf("rgba:%04x/%04x/%04x/%04x", r, g, b, a)
+}
+
+// SetForegroundColor returns a sequence that sets the default terminal
+// foreground color.
+//
+// OSC 10 ; color ST
+// OSC 10 ; color BEL
+//
+// Where color is the encoded color number.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
+func SetForegroundColor(c color.Color) string {
+ var s string
+ switch c := c.(type) {
+ case Colorizer:
+ s = c.String()
+ case fmt.Stringer:
+ s = c.String()
+ default:
+ s = HexColorizer{c}.String()
+ }
+ return "\x1b]10;" + s + "\x07"
+}
+
+// RequestForegroundColor is a sequence that requests the current default
+// terminal foreground color.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
+const RequestForegroundColor = "\x1b]10;?\x07"
+
+// ResetForegroundColor is a sequence that resets the default terminal
+// foreground color.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
+const ResetForegroundColor = "\x1b]110\x07"
+
+// SetBackgroundColor returns a sequence that sets the default terminal
+// background color.
+//
+// OSC 11 ; color ST
+// OSC 11 ; color BEL
+//
+// Where color is the encoded color number.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
+func SetBackgroundColor(c color.Color) string {
+ var s string
+ switch c := c.(type) {
+ case Colorizer:
+ s = c.String()
+ case fmt.Stringer:
+ s = c.String()
+ default:
+ s = HexColorizer{c}.String()
+ }
+ return "\x1b]11;" + s + "\x07"
+}
+
+// RequestBackgroundColor is a sequence that requests the current default
+// terminal background color.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
+const RequestBackgroundColor = "\x1b]11;?\x07"
+
+// ResetBackgroundColor is a sequence that resets the default terminal
+// background color.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
+const ResetBackgroundColor = "\x1b]111\x07"
+
+// SetCursorColor returns a sequence that sets the terminal cursor color.
+//
+// OSC 12 ; color ST
+// OSC 12 ; color BEL
+//
+// Where color is the encoded color number.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
+func SetCursorColor(c color.Color) string {
+ var s string
+ switch c := c.(type) {
+ case Colorizer:
+ s = c.String()
+ case fmt.Stringer:
+ s = c.String()
+ default:
+ s = HexColorizer{c}.String()
+ }
+ return "\x1b]12;" + s + "\x07"
+}
+
+// RequestCursorColor is a sequence that requests the current terminal cursor
+// color.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
+const RequestCursorColor = "\x1b]12;?\x07"
+
+// ResetCursorColor is a sequence that resets the terminal cursor color.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
+const ResetCursorColor = "\x1b]112\x07"
diff --git a/vendor/github.com/charmbracelet/x/ansi/c0.go b/vendor/github.com/charmbracelet/x/ansi/c0.go
new file mode 100644
index 00000000..28ff7c2a
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/c0.go
@@ -0,0 +1,79 @@
+package ansi
+
+// C0 control characters.
+//
+// These range from (0x00-0x1F) as defined in ISO 646 (ASCII).
+// See: https://en.wikipedia.org/wiki/C0_and_C1_control_codes
+const (
+ // NUL is the null character (Caret: ^@, Char: \0).
+ NUL = 0x00
+ // SOH is the start of heading character (Caret: ^A).
+ SOH = 0x01
+ // STX is the start of text character (Caret: ^B).
+ STX = 0x02
+ // ETX is the end of text character (Caret: ^C).
+ ETX = 0x03
+ // EOT is the end of transmission character (Caret: ^D).
+ EOT = 0x04
+ // ENQ is the enquiry character (Caret: ^E).
+ ENQ = 0x05
+ // ACK is the acknowledge character (Caret: ^F).
+ ACK = 0x06
+ // BEL is the bell character (Caret: ^G, Char: \a).
+ BEL = 0x07
+ // BS is the backspace character (Caret: ^H, Char: \b).
+ BS = 0x08
+ // HT is the horizontal tab character (Caret: ^I, Char: \t).
+ HT = 0x09
+ // LF is the line feed character (Caret: ^J, Char: \n).
+ LF = 0x0A
+ // VT is the vertical tab character (Caret: ^K, Char: \v).
+ VT = 0x0B
+ // FF is the form feed character (Caret: ^L, Char: \f).
+ FF = 0x0C
+ // CR is the carriage return character (Caret: ^M, Char: \r).
+ CR = 0x0D
+ // SO is the shift out character (Caret: ^N).
+ SO = 0x0E
+ // SI is the shift in character (Caret: ^O).
+ SI = 0x0F
+ // DLE is the data link escape character (Caret: ^P).
+ DLE = 0x10
+ // DC1 is the device control 1 character (Caret: ^Q).
+ DC1 = 0x11
+ // DC2 is the device control 2 character (Caret: ^R).
+ DC2 = 0x12
+ // DC3 is the device control 3 character (Caret: ^S).
+ DC3 = 0x13
+ // DC4 is the device control 4 character (Caret: ^T).
+ DC4 = 0x14
+ // NAK is the negative acknowledge character (Caret: ^U).
+ NAK = 0x15
+ // SYN is the synchronous idle character (Caret: ^V).
+ SYN = 0x16
+ // ETB is the end of transmission block character (Caret: ^W).
+ ETB = 0x17
+ // CAN is the cancel character (Caret: ^X).
+ CAN = 0x18
+ // EM is the end of medium character (Caret: ^Y).
+ EM = 0x19
+ // SUB is the substitute character (Caret: ^Z).
+ SUB = 0x1A
+ // ESC is the escape character (Caret: ^[, Char: \e).
+ ESC = 0x1B
+ // FS is the file separator character (Caret: ^\).
+ FS = 0x1C
+ // GS is the group separator character (Caret: ^]).
+ GS = 0x1D
+ // RS is the record separator character (Caret: ^^).
+ RS = 0x1E
+ // US is the unit separator character (Caret: ^_).
+ US = 0x1F
+
+ // LS0 is the locking shift 0 character.
+ // This is an alias for [SI].
+ LS0 = SI
+ // LS1 is the locking shift 1 character.
+ // This is an alias for [SO].
+ LS1 = SO
+)
diff --git a/vendor/github.com/charmbracelet/x/ansi/c1.go b/vendor/github.com/charmbracelet/x/ansi/c1.go
new file mode 100644
index 00000000..71058f53
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/c1.go
@@ -0,0 +1,72 @@
+package ansi
+
+// C1 control characters.
+//
+// These range from (0x80-0x9F) as defined in ISO 6429 (ECMA-48).
+// See: https://en.wikipedia.org/wiki/C0_and_C1_control_codes
+const (
+ // PAD is the padding character.
+ PAD = 0x80
+ // HOP is the high octet preset character.
+ HOP = 0x81
+ // BPH is the break permitted here character.
+ BPH = 0x82
+ // NBH is the no break here character.
+ NBH = 0x83
+ // IND is the index character.
+ IND = 0x84
+ // NEL is the next line character.
+ NEL = 0x85
+ // SSA is the start of selected area character.
+ SSA = 0x86
+ // ESA is the end of selected area character.
+ ESA = 0x87
+ // HTS is the horizontal tab set character.
+ HTS = 0x88
+ // HTJ is the horizontal tab with justification character.
+ HTJ = 0x89
+ // VTS is the vertical tab set character.
+ VTS = 0x8A
+ // PLD is the partial line forward character.
+ PLD = 0x8B
+ // PLU is the partial line backward character.
+ PLU = 0x8C
+ // RI is the reverse index character.
+ RI = 0x8D
+ // SS2 is the single shift 2 character.
+ SS2 = 0x8E
+ // SS3 is the single shift 3 character.
+ SS3 = 0x8F
+ // DCS is the device control string character.
+ DCS = 0x90
+ // PU1 is the private use 1 character.
+ PU1 = 0x91
+ // PU2 is the private use 2 character.
+ PU2 = 0x92
+ // STS is the set transmit state character.
+ STS = 0x93
+ // CCH is the cancel character.
+ CCH = 0x94
+ // MW is the message waiting character.
+ MW = 0x95
+ // SPA is the start of guarded area character.
+ SPA = 0x96
+ // EPA is the end of guarded area character.
+ EPA = 0x97
+ // SOS is the start of string character.
+ SOS = 0x98
+ // SGCI is the single graphic character introducer character.
+ SGCI = 0x99
+ // SCI is the single character introducer character.
+ SCI = 0x9A
+ // CSI is the control sequence introducer character.
+ CSI = 0x9B
+ // ST is the string terminator character.
+ ST = 0x9C
+ // OSC is the operating system command character.
+ OSC = 0x9D
+ // PM is the privacy message character.
+ PM = 0x9E
+ // APC is the application program command character.
+ APC = 0x9F
+)
diff --git a/vendor/github.com/charmbracelet/x/ansi/charset.go b/vendor/github.com/charmbracelet/x/ansi/charset.go
new file mode 100644
index 00000000..50fff51f
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/charset.go
@@ -0,0 +1,55 @@
+package ansi
+
+// SelectCharacterSet sets the G-set character designator to the specified
+// character set.
+//
+// ESC Ps Pd
+//
+// Where Ps is the G-set character designator, and Pd is the identifier.
+// For 94-character sets, the designator can be one of:
+// - ( G0
+// - ) G1
+// - * G2
+// - + G3
+//
+// For 96-character sets, the designator can be one of:
+// - - G1
+// - . G2
+// - / G3
+//
+// Some common 94-character sets are:
+// - 0 DEC Special Drawing Set
+// - A United Kingdom (UK)
+// - B United States (USASCII)
+//
+// Examples:
+//
+// ESC ( B Select character set G0 = United States (USASCII)
+// ESC ( 0 Select character set G0 = Special Character and Line Drawing Set
+// ESC ) 0 Select character set G1 = Special Character and Line Drawing Set
+// ESC * A Select character set G2 = United Kingdom (UK)
+//
+// See: https://vt100.net/docs/vt510-rm/SCS.html
+func SelectCharacterSet(gset byte, charset byte) string {
+ return "\x1b" + string(gset) + string(charset)
+}
+
+// SCS is an alias for SelectCharacterSet.
+func SCS(gset byte, charset byte) string {
+ return SelectCharacterSet(gset, charset)
+}
+
+// Locking Shift 1 Right (LS1R) shifts G1 into GR character set.
+const LS1R = "\x1b~"
+
+// Locking Shift 2 (LS2) shifts G2 into GL character set.
+const LS2 = "\x1bn"
+
+// Locking Shift 2 Right (LS2R) shifts G2 into GR character set.
+const LS2R = "\x1b}"
+
+// Locking Shift 3 (LS3) shifts G3 into GL character set.
+const LS3 = "\x1bo"
+
+// Locking Shift 3 Right (LS3R) shifts G3 into GR character set.
+const LS3R = "\x1b|"
diff --git a/vendor/github.com/charmbracelet/x/ansi/clipboard.go b/vendor/github.com/charmbracelet/x/ansi/clipboard.go
new file mode 100644
index 00000000..94d26c36
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/clipboard.go
@@ -0,0 +1,75 @@
+package ansi
+
+import "encoding/base64"
+
+// Clipboard names.
+const (
+ SystemClipboard = 'c'
+ PrimaryClipboard = 'p'
+)
+
+// SetClipboard returns a sequence for manipulating the clipboard.
+//
+// OSC 52 ; Pc ; Pd ST
+// OSC 52 ; Pc ; Pd BEL
+//
+// Where Pc is the clipboard name and Pd is the base64 encoded data.
+// Empty data or invalid base64 data will reset the clipboard.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
+func SetClipboard(c byte, d string) string {
+ if d != "" {
+ d = base64.StdEncoding.EncodeToString([]byte(d))
+ }
+ return "\x1b]52;" + string(c) + ";" + d + "\x07"
+}
+
+// SetSystemClipboard returns a sequence for setting the system clipboard.
+//
+// This is equivalent to SetClipboard(SystemClipboard, d).
+func SetSystemClipboard(d string) string {
+ return SetClipboard(SystemClipboard, d)
+}
+
+// SetPrimaryClipboard returns a sequence for setting the primary clipboard.
+//
+// This is equivalent to SetClipboard(PrimaryClipboard, d).
+func SetPrimaryClipboard(d string) string {
+ return SetClipboard(PrimaryClipboard, d)
+}
+
+// ResetClipboard returns a sequence for resetting the clipboard.
+//
+// This is equivalent to SetClipboard(c, "").
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
+func ResetClipboard(c byte) string {
+ return SetClipboard(c, "")
+}
+
+// ResetSystemClipboard is a sequence for resetting the system clipboard.
+//
+// This is equivalent to ResetClipboard(SystemClipboard).
+const ResetSystemClipboard = "\x1b]52;c;\x07"
+
+// ResetPrimaryClipboard is a sequence for resetting the primary clipboard.
+//
+// This is equivalent to ResetClipboard(PrimaryClipboard).
+const ResetPrimaryClipboard = "\x1b]52;p;\x07"
+
+// RequestClipboard returns a sequence for requesting the clipboard.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
+func RequestClipboard(c byte) string {
+ return "\x1b]52;" + string(c) + ";?\x07"
+}
+
+// RequestSystemClipboard is a sequence for requesting the system clipboard.
+//
+// This is equivalent to RequestClipboard(SystemClipboard).
+const RequestSystemClipboard = "\x1b]52;c;?\x07"
+
+// RequestPrimaryClipboard is a sequence for requesting the primary clipboard.
+//
+// This is equivalent to RequestClipboard(PrimaryClipboard).
+const RequestPrimaryClipboard = "\x1b]52;p;?\x07"
diff --git a/vendor/github.com/charmbracelet/x/ansi/color.go b/vendor/github.com/charmbracelet/x/ansi/color.go
new file mode 100644
index 00000000..77f8a08d
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/color.go
@@ -0,0 +1,196 @@
+package ansi
+
+import (
+ "image/color"
+)
+
+// Technically speaking, the 16 basic ANSI colors are arbitrary and can be
+// customized at the terminal level. Given that, we're returning what we feel
+// are good defaults.
+//
+// This could also be a slice, but we use a map to make the mappings very
+// explicit.
+//
+// See: https://www.ditig.com/publications/256-colors-cheat-sheet
+var lowANSI = map[uint32]uint32{
+ 0: 0x000000, // black
+ 1: 0x800000, // red
+ 2: 0x008000, // green
+ 3: 0x808000, // yellow
+ 4: 0x000080, // blue
+ 5: 0x800080, // magenta
+ 6: 0x008080, // cyan
+ 7: 0xc0c0c0, // white
+ 8: 0x808080, // bright black
+ 9: 0xff0000, // bright red
+ 10: 0x00ff00, // bright green
+ 11: 0xffff00, // bright yellow
+ 12: 0x0000ff, // bright blue
+ 13: 0xff00ff, // bright magenta
+ 14: 0x00ffff, // bright cyan
+ 15: 0xffffff, // bright white
+}
+
+// Color is a color that can be used in a terminal. ANSI (including
+// ANSI256) and 24-bit "true colors" fall under this category.
+type Color interface {
+ color.Color
+}
+
+// BasicColor is an ANSI 3-bit or 4-bit color with a value from 0 to 15.
+type BasicColor uint8
+
+var _ Color = BasicColor(0)
+
+const (
+ // Black is the ANSI black color.
+ Black BasicColor = iota
+
+ // Red is the ANSI red color.
+ Red
+
+ // Green is the ANSI green color.
+ Green
+
+ // Yellow is the ANSI yellow color.
+ Yellow
+
+ // Blue is the ANSI blue color.
+ Blue
+
+ // Magenta is the ANSI magenta color.
+ Magenta
+
+ // Cyan is the ANSI cyan color.
+ Cyan
+
+ // White is the ANSI white color.
+ White
+
+ // BrightBlack is the ANSI bright black color.
+ BrightBlack
+
+ // BrightRed is the ANSI bright red color.
+ BrightRed
+
+ // BrightGreen is the ANSI bright green color.
+ BrightGreen
+
+ // BrightYellow is the ANSI bright yellow color.
+ BrightYellow
+
+ // BrightBlue is the ANSI bright blue color.
+ BrightBlue
+
+ // BrightMagenta is the ANSI bright magenta color.
+ BrightMagenta
+
+ // BrightCyan is the ANSI bright cyan color.
+ BrightCyan
+
+ // BrightWhite is the ANSI bright white color.
+ BrightWhite
+)
+
+// RGBA returns the red, green, blue and alpha components of the color. It
+// satisfies the color.Color interface.
+func (c BasicColor) RGBA() (uint32, uint32, uint32, uint32) {
+ ansi := uint32(c)
+ if ansi > 15 {
+ return 0, 0, 0, 0xffff
+ }
+
+ r, g, b := ansiToRGB(ansi)
+ return toRGBA(r, g, b)
+}
+
+// ExtendedColor is an ANSI 256 (8-bit) color with a value from 0 to 255.
+type ExtendedColor uint8
+
+var _ Color = ExtendedColor(0)
+
+// RGBA returns the red, green, blue and alpha components of the color. It
+// satisfies the color.Color interface.
+func (c ExtendedColor) RGBA() (uint32, uint32, uint32, uint32) {
+ r, g, b := ansiToRGB(uint32(c))
+ return toRGBA(r, g, b)
+}
+
+// TrueColor is a 24-bit color that can be used in the terminal.
+// This can be used to represent RGB colors.
+//
+// For example, the color red can be represented as:
+//
+// TrueColor(0xff0000)
+type TrueColor uint32
+
+var _ Color = TrueColor(0)
+
+// RGBA returns the red, green, blue and alpha components of the color. It
+// satisfies the color.Color interface.
+func (c TrueColor) RGBA() (uint32, uint32, uint32, uint32) {
+ r, g, b := hexToRGB(uint32(c))
+ return toRGBA(r, g, b)
+}
+
+// ansiToRGB converts an ANSI color to a 24-bit RGB color.
+//
+// r, g, b := ansiToRGB(57)
+func ansiToRGB(ansi uint32) (uint32, uint32, uint32) {
+ // For out-of-range values return black.
+ if ansi > 255 {
+ return 0, 0, 0
+ }
+
+ // Low ANSI.
+ if ansi < 16 {
+ h, ok := lowANSI[ansi]
+ if !ok {
+ return 0, 0, 0
+ }
+ r, g, b := hexToRGB(h)
+ return r, g, b
+ }
+
+ // Grays.
+ if ansi > 231 {
+ s := (ansi-232)*10 + 8
+ return s, s, s
+ }
+
+ // ANSI256.
+ n := ansi - 16
+ b := n % 6
+ g := (n - b) / 6 % 6
+ r := (n - b - g*6) / 36 % 6
+ for _, v := range []*uint32{&r, &g, &b} {
+ if *v > 0 {
+ c := *v*40 + 55
+ *v = c
+ }
+ }
+
+ return r, g, b
+}
+
+// hexToRGB converts a number in hexadecimal format to red, green, and blue
+// values.
+//
+// r, g, b := hexToRGB(0x0000FF)
+func hexToRGB(hex uint32) (uint32, uint32, uint32) {
+ return hex >> 16 & 0xff, hex >> 8 & 0xff, hex & 0xff
+}
+
+// toRGBA converts an RGB 8-bit color values to 32-bit color values suitable
+// for color.Color.
+//
+// color.Color requires 16-bit color values, so we duplicate the 8-bit values
+// to fill the 16-bit values.
+//
+// This always returns 0xffff (opaque) for the alpha channel.
+func toRGBA(r, g, b uint32) (uint32, uint32, uint32, uint32) {
+ r |= r << 8
+ g |= g << 8
+ b |= b << 8
+ return r, g, b, 0xffff
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/ctrl.go b/vendor/github.com/charmbracelet/x/ansi/ctrl.go
new file mode 100644
index 00000000..8ca744cf
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/ctrl.go
@@ -0,0 +1,137 @@
+package ansi
+
+import (
+ "strconv"
+ "strings"
+)
+
+// RequestNameVersion (XTVERSION) is a control sequence that requests the
+// terminal's name and version. It responds with a DSR sequence identifying the
+// terminal.
+//
+// CSI > 0 q
+// DCS > | text ST
+//
+// See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-PC-Style-Function-Keys
+const (
+ RequestNameVersion = "\x1b[>q"
+ XTVERSION = RequestNameVersion
+)
+
+// RequestXTVersion is a control sequence that requests the terminal's XTVERSION. It responds with a DSR sequence identifying the version.
+//
+// CSI > Ps q
+// DCS > | text ST
+//
+// See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-PC-Style-Function-Keys
+//
+// Deprecated: use [RequestNameVersion] instead.
+const RequestXTVersion = RequestNameVersion
+
+// PrimaryDeviceAttributes (DA1) is a control sequence that reports the
+// terminal's primary device attributes.
+//
+// CSI c
+// CSI 0 c
+// CSI ? Ps ; ... c
+//
+// If no attributes are given, or if the attribute is 0, this function returns
+// the request sequence. Otherwise, it returns the response sequence.
+//
+// See https://vt100.net/docs/vt510-rm/DA1.html
+func PrimaryDeviceAttributes(attrs ...int) string {
+ if len(attrs) == 0 {
+ return RequestPrimaryDeviceAttributes
+ } else if len(attrs) == 1 && attrs[0] == 0 {
+ return "\x1b[0c"
+ }
+
+ as := make([]string, len(attrs))
+ for i, a := range attrs {
+ as[i] = strconv.Itoa(a)
+ }
+ return "\x1b[?" + strings.Join(as, ";") + "c"
+}
+
+// DA1 is an alias for [PrimaryDeviceAttributes].
+func DA1(attrs ...int) string {
+ return PrimaryDeviceAttributes(attrs...)
+}
+
+// RequestPrimaryDeviceAttributes is a control sequence that requests the
+// terminal's primary device attributes (DA1).
+//
+// CSI c
+//
+// See https://vt100.net/docs/vt510-rm/DA1.html
+const RequestPrimaryDeviceAttributes = "\x1b[c"
+
+// SecondaryDeviceAttributes (DA2) is a control sequence that reports the
+// terminal's secondary device attributes.
+//
+// CSI > c
+// CSI > 0 c
+// CSI > Ps ; ... c
+//
+// See https://vt100.net/docs/vt510-rm/DA2.html
+func SecondaryDeviceAttributes(attrs ...int) string {
+ if len(attrs) == 0 {
+ return RequestSecondaryDeviceAttributes
+ }
+
+ as := make([]string, len(attrs))
+ for i, a := range attrs {
+ as[i] = strconv.Itoa(a)
+ }
+ return "\x1b[>" + strings.Join(as, ";") + "c"
+}
+
+// DA2 is an alias for [SecondaryDeviceAttributes].
+func DA2(attrs ...int) string {
+ return SecondaryDeviceAttributes(attrs...)
+}
+
+// RequestSecondaryDeviceAttributes is a control sequence that requests the
+// terminal's secondary device attributes (DA2).
+//
+// CSI > c
+//
+// See https://vt100.net/docs/vt510-rm/DA2.html
+const RequestSecondaryDeviceAttributes = "\x1b[>c"
+
+// TertiaryDeviceAttributes (DA3) is a control sequence that reports the
+// terminal's tertiary device attributes.
+//
+// CSI = c
+// CSI = 0 c
+// DCS ! | Text ST
+//
+// Where Text is the unit ID for the terminal.
+//
+// If no unit ID is given, or if the unit ID is 0, this function returns the
+// request sequence. Otherwise, it returns the response sequence.
+//
+// See https://vt100.net/docs/vt510-rm/DA3.html
+func TertiaryDeviceAttributes(unitID string) string {
+ switch unitID {
+ case "":
+ return RequestTertiaryDeviceAttributes
+ case "0":
+ return "\x1b[=0c"
+ }
+
+ return "\x1bP!|" + unitID + "\x1b\\"
+}
+
+// DA3 is an alias for [TertiaryDeviceAttributes].
+func DA3(unitID string) string {
+ return TertiaryDeviceAttributes(unitID)
+}
+
+// RequestTertiaryDeviceAttributes is a control sequence that requests the
+// terminal's tertiary device attributes (DA3).
+//
+// CSI = c
+//
+// See https://vt100.net/docs/vt510-rm/DA3.html
+const RequestTertiaryDeviceAttributes = "\x1b[=c"
diff --git a/vendor/github.com/charmbracelet/x/ansi/cursor.go b/vendor/github.com/charmbracelet/x/ansi/cursor.go
new file mode 100644
index 00000000..0c364d60
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/cursor.go
@@ -0,0 +1,633 @@
+package ansi
+
+import "strconv"
+
+// SaveCursor (DECSC) is an escape sequence that saves the current cursor
+// position.
+//
+// ESC 7
+//
+// See: https://vt100.net/docs/vt510-rm/DECSC.html
+const (
+ SaveCursor = "\x1b7"
+ DECSC = SaveCursor
+)
+
+// RestoreCursor (DECRC) is an escape sequence that restores the cursor
+// position.
+//
+// ESC 8
+//
+// See: https://vt100.net/docs/vt510-rm/DECRC.html
+const (
+ RestoreCursor = "\x1b8"
+ DECRC = RestoreCursor
+)
+
+// RequestCursorPosition is an escape sequence that requests the current cursor
+// position.
+//
+// CSI 6 n
+//
+// The terminal will report the cursor position as a CSI sequence in the
+// following format:
+//
+// CSI Pl ; Pc R
+//
+// Where Pl is the line number and Pc is the column number.
+// See: https://vt100.net/docs/vt510-rm/CPR.html
+//
+// Deprecated: use [RequestCursorPositionReport] instead.
+const RequestCursorPosition = "\x1b[6n"
+
+// RequestExtendedCursorPosition (DECXCPR) is a sequence for requesting the
+// cursor position report including the current page number.
+//
+// CSI ? 6 n
+//
+// The terminal will report the cursor position as a CSI sequence in the
+// following format:
+//
+// CSI ? Pl ; Pc ; Pp R
+//
+// Where Pl is the line number, Pc is the column number, and Pp is the page
+// number.
+// See: https://vt100.net/docs/vt510-rm/DECXCPR.html
+//
+// Deprecated: use [RequestExtendedCursorPositionReport] instead.
+const RequestExtendedCursorPosition = "\x1b[?6n"
+
+// CursorUp (CUU) returns a sequence for moving the cursor up n cells.
+//
+// CSI n A
+//
+// See: https://vt100.net/docs/vt510-rm/CUU.html
+func CursorUp(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "A"
+}
+
+// CUU is an alias for [CursorUp].
+func CUU(n int) string {
+ return CursorUp(n)
+}
+
+// CUU1 is a sequence for moving the cursor up one cell.
+const CUU1 = "\x1b[A"
+
+// CursorUp1 is a sequence for moving the cursor up one cell.
+//
+// This is equivalent to CursorUp(1).
+//
+// Deprecated: use [CUU1] instead.
+const CursorUp1 = "\x1b[A"
+
+// CursorDown (CUD) returns a sequence for moving the cursor down n cells.
+//
+// CSI n B
+//
+// See: https://vt100.net/docs/vt510-rm/CUD.html
+func CursorDown(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "B"
+}
+
+// CUD is an alias for [CursorDown].
+func CUD(n int) string {
+ return CursorDown(n)
+}
+
+// CUD1 is a sequence for moving the cursor down one cell.
+const CUD1 = "\x1b[B"
+
+// CursorDown1 is a sequence for moving the cursor down one cell.
+//
+// This is equivalent to CursorDown(1).
+//
+// Deprecated: use [CUD1] instead.
+const CursorDown1 = "\x1b[B"
+
+// CursorForward (CUF) returns a sequence for moving the cursor right n cells.
+//
+// # CSI n C
+//
+// See: https://vt100.net/docs/vt510-rm/CUF.html
+func CursorForward(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "C"
+}
+
+// CUF is an alias for [CursorForward].
+func CUF(n int) string {
+ return CursorForward(n)
+}
+
+// CUF1 is a sequence for moving the cursor right one cell.
+const CUF1 = "\x1b[C"
+
+// CursorRight (CUF) returns a sequence for moving the cursor right n cells.
+//
+// CSI n C
+//
+// See: https://vt100.net/docs/vt510-rm/CUF.html
+//
+// Deprecated: use [CursorForward] instead.
+func CursorRight(n int) string {
+ return CursorForward(n)
+}
+
+// CursorRight1 is a sequence for moving the cursor right one cell.
+//
+// This is equivalent to CursorRight(1).
+//
+// Deprecated: use [CUF1] instead.
+const CursorRight1 = CUF1
+
+// CursorBackward (CUB) returns a sequence for moving the cursor left n cells.
+//
+// # CSI n D
+//
+// See: https://vt100.net/docs/vt510-rm/CUB.html
+func CursorBackward(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "D"
+}
+
+// CUB is an alias for [CursorBackward].
+func CUB(n int) string {
+ return CursorBackward(n)
+}
+
+// CUB1 is a sequence for moving the cursor left one cell.
+const CUB1 = "\x1b[D"
+
+// CursorLeft (CUB) returns a sequence for moving the cursor left n cells.
+//
+// CSI n D
+//
+// See: https://vt100.net/docs/vt510-rm/CUB.html
+//
+// Deprecated: use [CursorBackward] instead.
+func CursorLeft(n int) string {
+ return CursorBackward(n)
+}
+
+// CursorLeft1 is a sequence for moving the cursor left one cell.
+//
+// This is equivalent to CursorLeft(1).
+//
+// Deprecated: use [CUB1] instead.
+const CursorLeft1 = CUB1
+
+// CursorNextLine (CNL) returns a sequence for moving the cursor to the
+// beginning of the next line n times.
+//
+// CSI n E
+//
+// See: https://vt100.net/docs/vt510-rm/CNL.html
+func CursorNextLine(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "E"
+}
+
+// CNL is an alias for [CursorNextLine].
+func CNL(n int) string {
+ return CursorNextLine(n)
+}
+
+// CursorPreviousLine (CPL) returns a sequence for moving the cursor to the
+// beginning of the previous line n times.
+//
+// CSI n F
+//
+// See: https://vt100.net/docs/vt510-rm/CPL.html
+func CursorPreviousLine(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "F"
+}
+
+// CPL is an alias for [CursorPreviousLine].
+func CPL(n int) string {
+ return CursorPreviousLine(n)
+}
+
+// CursorHorizontalAbsolute (CHA) returns a sequence for moving the cursor to
+// the given column.
+//
+// Default is 1.
+//
+// CSI n G
+//
+// See: https://vt100.net/docs/vt510-rm/CHA.html
+func CursorHorizontalAbsolute(col int) string {
+ var s string
+ if col > 0 {
+ s = strconv.Itoa(col)
+ }
+ return "\x1b[" + s + "G"
+}
+
+// CHA is an alias for [CursorHorizontalAbsolute].
+func CHA(col int) string {
+ return CursorHorizontalAbsolute(col)
+}
+
+// CursorPosition (CUP) returns a sequence for setting the cursor to the
+// given row and column.
+//
+// Default is 1,1.
+//
+// CSI n ; m H
+//
+// See: https://vt100.net/docs/vt510-rm/CUP.html
+func CursorPosition(col, row int) string {
+ if row <= 0 && col <= 0 {
+ return HomeCursorPosition
+ }
+
+ var r, c string
+ if row > 0 {
+ r = strconv.Itoa(row)
+ }
+ if col > 0 {
+ c = strconv.Itoa(col)
+ }
+ return "\x1b[" + r + ";" + c + "H"
+}
+
+// CUP is an alias for [CursorPosition].
+func CUP(col, row int) string {
+ return CursorPosition(col, row)
+}
+
+// CursorHomePosition is a sequence for moving the cursor to the upper left
+// corner of the scrolling region. This is equivalent to `CursorPosition(1, 1)`.
+const CursorHomePosition = "\x1b[H"
+
+// SetCursorPosition (CUP) returns a sequence for setting the cursor to the
+// given row and column.
+//
+// CSI n ; m H
+//
+// See: https://vt100.net/docs/vt510-rm/CUP.html
+//
+// Deprecated: use [CursorPosition] instead.
+func SetCursorPosition(col, row int) string {
+ if row <= 0 && col <= 0 {
+ return HomeCursorPosition
+ }
+
+ var r, c string
+ if row > 0 {
+ r = strconv.Itoa(row)
+ }
+ if col > 0 {
+ c = strconv.Itoa(col)
+ }
+ return "\x1b[" + r + ";" + c + "H"
+}
+
+// HomeCursorPosition is a sequence for moving the cursor to the upper left
+// corner of the scrolling region. This is equivalent to `SetCursorPosition(1, 1)`.
+//
+// Deprecated: use [CursorHomePosition] instead.
+const HomeCursorPosition = CursorHomePosition
+
+// MoveCursor (CUP) returns a sequence for setting the cursor to the
+// given row and column.
+//
+// CSI n ; m H
+//
+// See: https://vt100.net/docs/vt510-rm/CUP.html
+//
+// Deprecated: use [CursorPosition] instead.
+func MoveCursor(col, row int) string {
+ return SetCursorPosition(col, row)
+}
+
+// CursorOrigin is a sequence for moving the cursor to the upper left corner of
+// the display. This is equivalent to `SetCursorPosition(1, 1)`.
+//
+// Deprecated: use [CursorHomePosition] instead.
+const CursorOrigin = "\x1b[1;1H"
+
+// MoveCursorOrigin is a sequence for moving the cursor to the upper left
+// corner of the display. This is equivalent to `SetCursorPosition(1, 1)`.
+//
+// Deprecated: use [CursorHomePosition] instead.
+const MoveCursorOrigin = CursorOrigin
+
+// CursorHorizontalForwardTab (CHT) returns a sequence for moving the cursor to
+// the next tab stop n times.
+//
+// Default is 1.
+//
+// CSI n I
+//
+// See: https://vt100.net/docs/vt510-rm/CHT.html
+func CursorHorizontalForwardTab(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "I"
+}
+
+// CHT is an alias for [CursorHorizontalForwardTab].
+func CHT(n int) string {
+ return CursorHorizontalForwardTab(n)
+}
+
+// EraseCharacter (ECH) returns a sequence for erasing n characters and moving
+// the cursor to the right. This doesn't affect other cell attributes.
+//
+// Default is 1.
+//
+// CSI n X
+//
+// See: https://vt100.net/docs/vt510-rm/ECH.html
+func EraseCharacter(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "X"
+}
+
+// ECH is an alias for [EraseCharacter].
+func ECH(n int) string {
+ return EraseCharacter(n)
+}
+
+// CursorBackwardTab (CBT) returns a sequence for moving the cursor to the
+// previous tab stop n times.
+//
+// Default is 1.
+//
+// CSI n Z
+//
+// See: https://vt100.net/docs/vt510-rm/CBT.html
+func CursorBackwardTab(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "Z"
+}
+
+// CBT is an alias for [CursorBackwardTab].
+func CBT(n int) string {
+ return CursorBackwardTab(n)
+}
+
+// VerticalPositionAbsolute (VPA) returns a sequence for moving the cursor to
+// the given row.
+//
+// Default is 1.
+//
+// CSI n d
+//
+// See: https://vt100.net/docs/vt510-rm/VPA.html
+func VerticalPositionAbsolute(row int) string {
+ var s string
+ if row > 0 {
+ s = strconv.Itoa(row)
+ }
+ return "\x1b[" + s + "d"
+}
+
+// VPA is an alias for [VerticalPositionAbsolute].
+func VPA(row int) string {
+ return VerticalPositionAbsolute(row)
+}
+
+// VerticalPositionRelative (VPR) returns a sequence for moving the cursor down
+// n rows relative to the current position.
+//
+// Default is 1.
+//
+// CSI n e
+//
+// See: https://vt100.net/docs/vt510-rm/VPR.html
+func VerticalPositionRelative(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "e"
+}
+
+// VPR is an alias for [VerticalPositionRelative].
+func VPR(n int) string {
+ return VerticalPositionRelative(n)
+}
+
+// HorizontalVerticalPosition (HVP) returns a sequence for moving the cursor to
+// the given row and column.
+//
+// Default is 1,1.
+//
+// CSI n ; m f
+//
+// This has the same effect as [CursorPosition].
+//
+// See: https://vt100.net/docs/vt510-rm/HVP.html
+func HorizontalVerticalPosition(col, row int) string {
+ var r, c string
+ if row > 0 {
+ r = strconv.Itoa(row)
+ }
+ if col > 0 {
+ c = strconv.Itoa(col)
+ }
+ return "\x1b[" + r + ";" + c + "f"
+}
+
+// HVP is an alias for [HorizontalVerticalPosition].
+func HVP(col, row int) string {
+ return HorizontalVerticalPosition(col, row)
+}
+
+// HorizontalVerticalHomePosition is a sequence for moving the cursor to the
+// upper left corner of the scrolling region. This is equivalent to
+// `HorizontalVerticalPosition(1, 1)`.
+const HorizontalVerticalHomePosition = "\x1b[f"
+
+// SaveCurrentCursorPosition (SCOSC) is a sequence for saving the current cursor
+// position for SCO console mode.
+//
+// CSI s
+//
+// This acts like [DECSC], except the page number where the cursor is located
+// is not saved.
+//
+// See: https://vt100.net/docs/vt510-rm/SCOSC.html
+const (
+ SaveCurrentCursorPosition = "\x1b[s"
+ SCOSC = SaveCurrentCursorPosition
+)
+
+// SaveCursorPosition (SCP or SCOSC) is a sequence for saving the cursor
+// position.
+//
+// CSI s
+//
+// This acts like Save, except the page number where the cursor is located is
+// not saved.
+//
+// See: https://vt100.net/docs/vt510-rm/SCOSC.html
+//
+// Deprecated: use [SaveCurrentCursorPosition] instead.
+const SaveCursorPosition = "\x1b[s"
+
+// RestoreCurrentCursorPosition (SCORC) is a sequence for restoring the current
+// cursor position for SCO console mode.
+//
+// CSI u
+//
+// This acts like [DECRC], except the page number where the cursor was saved is
+// not restored.
+//
+// See: https://vt100.net/docs/vt510-rm/SCORC.html
+const (
+ RestoreCurrentCursorPosition = "\x1b[u"
+ SCORC = RestoreCurrentCursorPosition
+)
+
+// RestoreCursorPosition (RCP or SCORC) is a sequence for restoring the cursor
+// position.
+//
+// CSI u
+//
+// This acts like Restore, except the cursor stays on the same page where the
+// cursor was saved.
+//
+// See: https://vt100.net/docs/vt510-rm/SCORC.html
+//
+// Deprecated: use [RestoreCurrentCursorPosition] instead.
+const RestoreCursorPosition = "\x1b[u"
+
+// SetCursorStyle (DECSCUSR) returns a sequence for changing the cursor style.
+//
+// Default is 1.
+//
+// CSI Ps SP q
+//
+// Where Ps is the cursor style:
+//
+// 0: Blinking block
+// 1: Blinking block (default)
+// 2: Steady block
+// 3: Blinking underline
+// 4: Steady underline
+// 5: Blinking bar (xterm)
+// 6: Steady bar (xterm)
+//
+// See: https://vt100.net/docs/vt510-rm/DECSCUSR.html
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81
+func SetCursorStyle(style int) string {
+ if style < 0 {
+ style = 0
+ }
+ return "\x1b[" + strconv.Itoa(style) + " q"
+}
+
+// DECSCUSR is an alias for [SetCursorStyle].
+func DECSCUSR(style int) string {
+ return SetCursorStyle(style)
+}
+
+// SetPointerShape returns a sequence for changing the mouse pointer cursor
+// shape. Use "default" for the default pointer shape.
+//
+// OSC 22 ; Pt ST
+// OSC 22 ; Pt BEL
+//
+// Where Pt is the pointer shape name. The name can be anything that the
+// operating system can understand. Some common names are:
+//
+// - copy
+// - crosshair
+// - default
+// - ew-resize
+// - n-resize
+// - text
+// - wait
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands
+func SetPointerShape(shape string) string {
+ return "\x1b]22;" + shape + "\x07"
+}
+
+// ReverseIndex (RI) is an escape sequence for moving the cursor up one line in
+// the same column. If the cursor is at the top margin, the screen scrolls
+// down.
+//
+// This has the same effect as [RI].
+const ReverseIndex = "\x1bM"
+
+// HorizontalPositionAbsolute (HPA) returns a sequence for moving the cursor to
+// the given column. This has the same effect as [CUP].
+//
+// Default is 1.
+//
+// CSI n `
+//
+// See: https://vt100.net/docs/vt510-rm/HPA.html
+func HorizontalPositionAbsolute(col int) string {
+ var s string
+ if col > 0 {
+ s = strconv.Itoa(col)
+ }
+ return "\x1b[" + s + "`"
+}
+
+// HPA is an alias for [HorizontalPositionAbsolute].
+func HPA(col int) string {
+ return HorizontalPositionAbsolute(col)
+}
+
+// HorizontalPositionRelative (HPR) returns a sequence for moving the cursor
+// right n columns relative to the current position. This has the same effect
+// as [CUP].
+//
+// Default is 1.
+//
+// CSI n a
+//
+// See: https://vt100.net/docs/vt510-rm/HPR.html
+func HorizontalPositionRelative(n int) string {
+ var s string
+ if n > 0 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "a"
+}
+
+// HPR is an alias for [HorizontalPositionRelative].
+func HPR(n int) string {
+ return HorizontalPositionRelative(n)
+}
+
+// Index (IND) is an escape sequence for moving the cursor down one line in the
+// same column. If the cursor is at the bottom margin, the screen scrolls up.
+// This has the same effect as [IND].
+const Index = "\x1bD"
diff --git a/vendor/github.com/charmbracelet/x/ansi/cwd.go b/vendor/github.com/charmbracelet/x/ansi/cwd.go
new file mode 100644
index 00000000..b03ac1bb
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/cwd.go
@@ -0,0 +1,26 @@
+package ansi
+
+import (
+ "net/url"
+ "path"
+)
+
+// NotifyWorkingDirectory returns a sequence that notifies the terminal
+// of the current working directory.
+//
+// OSC 7 ; Pt BEL
+//
+// Where Pt is a URL in the format "file://[host]/[path]".
+// Set host to "localhost" if this is a path on the local computer.
+//
+// See: https://wezfurlong.org/wezterm/shell-integration.html#osc-7-escape-sequence-to-set-the-working-directory
+// See: https://iterm2.com/documentation-escape-codes.html#:~:text=RemoteHost%20and%20CurrentDir%3A-,OSC%207,-%3B%20%5BPs%5D%20ST
+func NotifyWorkingDirectory(host string, paths ...string) string {
+ path := path.Join(paths...)
+ u := &url.URL{
+ Scheme: "file",
+ Host: host,
+ Path: path,
+ }
+ return "\x1b]7;" + u.String() + "\x07"
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/doc.go b/vendor/github.com/charmbracelet/x/ansi/doc.go
new file mode 100644
index 00000000..e955e9f1
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/doc.go
@@ -0,0 +1,7 @@
+// Package ansi defines common ANSI escape sequences based on the ECMA-48
+// specs.
+//
+// All sequences use 7-bit C1 control codes, which are supported by most
+// terminal emulators. OSC sequences are terminated by a BEL for wider
+// compatibility with terminals.
+package ansi
diff --git a/vendor/github.com/charmbracelet/x/ansi/focus.go b/vendor/github.com/charmbracelet/x/ansi/focus.go
new file mode 100644
index 00000000..4e0207ce
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/focus.go
@@ -0,0 +1,9 @@
+package ansi
+
+// Focus is an escape sequence to notify the terminal that it has focus.
+// This is used with [FocusEventMode].
+const Focus = "\x1b[I"
+
+// Blur is an escape sequence to notify the terminal that it has lost focus.
+// This is used with [FocusEventMode].
+const Blur = "\x1b[O"
diff --git a/vendor/github.com/charmbracelet/x/ansi/graphics.go b/vendor/github.com/charmbracelet/x/ansi/graphics.go
new file mode 100644
index 00000000..604fef47
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/graphics.go
@@ -0,0 +1,199 @@
+package ansi
+
+import (
+ "bytes"
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "image"
+ "io"
+ "os"
+ "strings"
+
+ "github.com/charmbracelet/x/ansi/kitty"
+)
+
+// KittyGraphics returns a sequence that encodes the given image in the Kitty
+// graphics protocol.
+//
+// APC G [comma separated options] ; [base64 encoded payload] ST
+//
+// See https://sw.kovidgoyal.net/kitty/graphics-protocol/
+func KittyGraphics(payload []byte, opts ...string) string {
+ var buf bytes.Buffer
+ buf.WriteString("\x1b_G")
+ buf.WriteString(strings.Join(opts, ","))
+ if len(payload) > 0 {
+ buf.WriteString(";")
+ buf.Write(payload)
+ }
+ buf.WriteString("\x1b\\")
+ return buf.String()
+}
+
+var (
+ // KittyGraphicsTempDir is the directory where temporary files are stored.
+ // This is used in [WriteKittyGraphics] along with [os.CreateTemp].
+ KittyGraphicsTempDir = ""
+
+ // KittyGraphicsTempPattern is the pattern used to create temporary files.
+ // This is used in [WriteKittyGraphics] along with [os.CreateTemp].
+ // The Kitty Graphics protocol requires the file path to contain the
+ // substring "tty-graphics-protocol".
+ KittyGraphicsTempPattern = "tty-graphics-protocol-*"
+)
+
+// WriteKittyGraphics writes an image using the Kitty Graphics protocol with
+// the given options to w. It chunks the written data if o.Chunk is true.
+//
+// You can omit m and use nil when rendering an image from a file. In this
+// case, you must provide a file path in o.File and use o.Transmission =
+// [kitty.File]. You can also use o.Transmission = [kitty.TempFile] to write
+// the image to a temporary file. In that case, the file path is ignored, and
+// the image is written to a temporary file that is automatically deleted by
+// the terminal.
+//
+// See https://sw.kovidgoyal.net/kitty/graphics-protocol/
+func WriteKittyGraphics(w io.Writer, m image.Image, o *kitty.Options) error {
+ if o == nil {
+ o = &kitty.Options{}
+ }
+
+ if o.Transmission == 0 && len(o.File) != 0 {
+ o.Transmission = kitty.File
+ }
+
+ var data bytes.Buffer // the data to be encoded into base64
+ e := &kitty.Encoder{
+ Compress: o.Compression == kitty.Zlib,
+ Format: o.Format,
+ }
+
+ switch o.Transmission {
+ case kitty.Direct:
+ if err := e.Encode(&data, m); err != nil {
+ return fmt.Errorf("failed to encode direct image: %w", err)
+ }
+
+ case kitty.SharedMemory:
+ // TODO: Implement shared memory
+ return fmt.Errorf("shared memory transmission is not yet implemented")
+
+ case kitty.File:
+ if len(o.File) == 0 {
+ return kitty.ErrMissingFile
+ }
+
+ f, err := os.Open(o.File)
+ if err != nil {
+ return fmt.Errorf("failed to open file: %w", err)
+ }
+
+ defer f.Close() //nolint:errcheck
+
+ stat, err := f.Stat()
+ if err != nil {
+ return fmt.Errorf("failed to get file info: %w", err)
+ }
+
+ mode := stat.Mode()
+ if !mode.IsRegular() {
+ return fmt.Errorf("file is not a regular file")
+ }
+
+ // Write the file path to the buffer
+ if _, err := data.WriteString(f.Name()); err != nil {
+ return fmt.Errorf("failed to write file path to buffer: %w", err)
+ }
+
+ case kitty.TempFile:
+ f, err := os.CreateTemp(KittyGraphicsTempDir, KittyGraphicsTempPattern)
+ if err != nil {
+ return fmt.Errorf("failed to create file: %w", err)
+ }
+
+ defer f.Close() //nolint:errcheck
+
+ if err := e.Encode(f, m); err != nil {
+ return fmt.Errorf("failed to encode image to file: %w", err)
+ }
+
+ // Write the file path to the buffer
+ if _, err := data.WriteString(f.Name()); err != nil {
+ return fmt.Errorf("failed to write file path to buffer: %w", err)
+ }
+ }
+
+ // Encode image to base64
+ var payload bytes.Buffer // the base64 encoded image to be written to w
+ b64 := base64.NewEncoder(base64.StdEncoding, &payload)
+ if _, err := data.WriteTo(b64); err != nil {
+ return fmt.Errorf("failed to write base64 encoded image to payload: %w", err)
+ }
+ if err := b64.Close(); err != nil {
+ return err
+ }
+
+ // If not chunking, write all at once
+ if !o.Chunk {
+ _, err := io.WriteString(w, KittyGraphics(payload.Bytes(), o.Options()...))
+ return err
+ }
+
+ // Write in chunks
+ var (
+ err error
+ n int
+ )
+ chunk := make([]byte, kitty.MaxChunkSize)
+ isFirstChunk := true
+
+ for {
+ // Stop if we read less than the chunk size [kitty.MaxChunkSize].
+ n, err = io.ReadFull(&payload, chunk)
+ if errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) {
+ break
+ }
+ if err != nil {
+ return fmt.Errorf("failed to read chunk: %w", err)
+ }
+
+ opts := buildChunkOptions(o, isFirstChunk, false)
+ if _, err := io.WriteString(w, KittyGraphics(chunk[:n], opts...)); err != nil {
+ return err
+ }
+
+ isFirstChunk = false
+ }
+
+ // Write the last chunk
+ opts := buildChunkOptions(o, isFirstChunk, true)
+ _, err = io.WriteString(w, KittyGraphics(chunk[:n], opts...))
+ return err
+}
+
+// buildChunkOptions creates the options slice for a chunk
+func buildChunkOptions(o *kitty.Options, isFirstChunk, isLastChunk bool) []string {
+ var opts []string
+ if isFirstChunk {
+ opts = o.Options()
+ } else {
+ // These options are allowed in subsequent chunks
+ if o.Quite > 0 {
+ opts = append(opts, fmt.Sprintf("q=%d", o.Quite))
+ }
+ if o.Action == kitty.Frame {
+ opts = append(opts, "a=f")
+ }
+ }
+
+ if !isFirstChunk || !isLastChunk {
+ // We don't need to encode the (m=) option when we only have one chunk.
+ if isLastChunk {
+ opts = append(opts, "m=0")
+ } else {
+ opts = append(opts, "m=1")
+ }
+ }
+ return opts
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/hyperlink.go b/vendor/github.com/charmbracelet/x/ansi/hyperlink.go
new file mode 100644
index 00000000..323bfe93
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/hyperlink.go
@@ -0,0 +1,28 @@
+package ansi
+
+import "strings"
+
+// SetHyperlink returns a sequence for starting a hyperlink.
+//
+// OSC 8 ; Params ; Uri ST
+// OSC 8 ; Params ; Uri BEL
+//
+// To reset the hyperlink, omit the URI.
+//
+// See: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
+func SetHyperlink(uri string, params ...string) string {
+ var p string
+ if len(params) > 0 {
+ p = strings.Join(params, ":")
+ }
+ return "\x1b]8;" + p + ";" + uri + "\x07"
+}
+
+// ResetHyperlink returns a sequence for resetting the hyperlink.
+//
+// This is equivalent to SetHyperlink("", params...).
+//
+// See: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
+func ResetHyperlink(params ...string) string {
+ return SetHyperlink("", params...)
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/iterm2.go b/vendor/github.com/charmbracelet/x/ansi/iterm2.go
new file mode 100644
index 00000000..0ecb336d
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/iterm2.go
@@ -0,0 +1,18 @@
+package ansi
+
+import "fmt"
+
+// ITerm2 returns a sequence that uses the iTerm2 proprietary protocol. Use the
+// iterm2 package for a more convenient API.
+//
+// OSC 1337 ; key = value ST
+//
+// Example:
+//
+// ITerm2(iterm2.File{...})
+//
+// See https://iterm2.com/documentation-escape-codes.html
+// See https://iterm2.com/documentation-images.html
+func ITerm2(data any) string {
+ return "\x1b]1337;" + fmt.Sprint(data) + "\x07"
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/keypad.go b/vendor/github.com/charmbracelet/x/ansi/keypad.go
new file mode 100644
index 00000000..9183c6a7
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/keypad.go
@@ -0,0 +1,28 @@
+package ansi
+
+// Keypad Application Mode (DECKPAM) is a mode that determines whether the
+// keypad sends application sequences or ANSI sequences.
+//
+// This works like enabling [DECNKM].
+// Use [NumericKeypadMode] to set the numeric keypad mode.
+//
+// ESC =
+//
+// See: https://vt100.net/docs/vt510-rm/DECKPAM.html
+const (
+ KeypadApplicationMode = "\x1b="
+ DECKPAM = KeypadApplicationMode
+)
+
+// Keypad Numeric Mode (DECKPNM) is a mode that determines whether the keypad
+// sends application sequences or ANSI sequences.
+//
+// This works the same as disabling [DECNKM].
+//
+// ESC >
+//
+// See: https://vt100.net/docs/vt510-rm/DECKPNM.html
+const (
+ KeypadNumericMode = "\x1b>"
+ DECKPNM = KeypadNumericMode
+)
diff --git a/vendor/github.com/charmbracelet/x/ansi/kitty.go b/vendor/github.com/charmbracelet/x/ansi/kitty.go
new file mode 100644
index 00000000..124ab839
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/kitty.go
@@ -0,0 +1,90 @@
+package ansi
+
+import "strconv"
+
+// Kitty keyboard protocol progressive enhancement flags.
+// See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement
+const (
+ KittyDisambiguateEscapeCodes = 1 << iota
+ KittyReportEventTypes
+ KittyReportAlternateKeys
+ KittyReportAllKeysAsEscapeCodes
+ KittyReportAssociatedKeys
+
+ KittyAllFlags = KittyDisambiguateEscapeCodes | KittyReportEventTypes |
+ KittyReportAlternateKeys | KittyReportAllKeysAsEscapeCodes | KittyReportAssociatedKeys
+)
+
+// RequestKittyKeyboard is a sequence to request the terminal Kitty keyboard
+// protocol enabled flags.
+//
+// See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/
+const RequestKittyKeyboard = "\x1b[?u"
+
+// KittyKeyboard returns a sequence to request keyboard enhancements from the terminal.
+// The flags argument is a bitmask of the Kitty keyboard protocol flags. While
+// mode specifies how the flags should be interpreted.
+//
+// Possible values for flags mask:
+//
+// 1: Disambiguate escape codes
+// 2: Report event types
+// 4: Report alternate keys
+// 8: Report all keys as escape codes
+// 16: Report associated text
+//
+// Possible values for mode:
+//
+// 1: Set given flags and unset all others
+// 2: Set given flags and keep existing flags unchanged
+// 3: Unset given flags and keep existing flags unchanged
+//
+// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement
+func KittyKeyboard(flags, mode int) string {
+ return "\x1b[=" + strconv.Itoa(flags) + ";" + strconv.Itoa(mode) + "u"
+}
+
+// PushKittyKeyboard returns a sequence to push the given flags to the terminal
+// Kitty Keyboard stack.
+//
+// Possible values for flags mask:
+//
+// 0: Disable all features
+// 1: Disambiguate escape codes
+// 2: Report event types
+// 4: Report alternate keys
+// 8: Report all keys as escape codes
+// 16: Report associated text
+//
+// CSI > flags u
+//
+// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement
+func PushKittyKeyboard(flags int) string {
+ var f string
+ if flags > 0 {
+ f = strconv.Itoa(flags)
+ }
+
+ return "\x1b[>" + f + "u"
+}
+
+// DisableKittyKeyboard is a sequence to push zero into the terminal Kitty
+// Keyboard stack to disable the protocol.
+//
+// This is equivalent to PushKittyKeyboard(0).
+const DisableKittyKeyboard = "\x1b[>u"
+
+// PopKittyKeyboard returns a sequence to pop n number of flags from the
+// terminal Kitty Keyboard stack.
+//
+// CSI < flags u
+//
+// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement
+func PopKittyKeyboard(n int) string {
+ var num string
+ if n > 0 {
+ num = strconv.Itoa(n)
+ }
+
+ return "\x1b[<" + num + "u"
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/kitty/BUILD.bazel b/vendor/github.com/charmbracelet/x/ansi/kitty/BUILD.bazel
new file mode 100644
index 00000000..c26d4abf
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/kitty/BUILD.bazel
@@ -0,0 +1,14 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "decoder.go",
+ "encoder.go",
+ "graphics.go",
+ "options.go",
+ ],
+ importmap = "github.com/kindlyops/vbs/vendor/github.com/charmbracelet/x/ansi/kitty",
+ importpath = "github.com/charmbracelet/x/ansi/kitty",
+ visibility = ["//visibility:public"],
+)
diff --git a/vendor/github.com/charmbracelet/x/ansi/kitty/decoder.go b/vendor/github.com/charmbracelet/x/ansi/kitty/decoder.go
new file mode 100644
index 00000000..fbd08441
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/kitty/decoder.go
@@ -0,0 +1,85 @@
+package kitty
+
+import (
+ "compress/zlib"
+ "fmt"
+ "image"
+ "image/color"
+ "image/png"
+ "io"
+)
+
+// Decoder is a decoder for the Kitty graphics protocol. It supports decoding
+// images in the 24-bit [RGB], 32-bit [RGBA], and [PNG] formats. It can also
+// decompress data using zlib.
+// The default format is 32-bit [RGBA].
+type Decoder struct {
+ // Uses zlib decompression.
+ Decompress bool
+
+ // Can be one of [RGB], [RGBA], or [PNG].
+ Format int
+
+ // Width of the image in pixels. This can be omitted if the image is [PNG]
+ // formatted.
+ Width int
+
+ // Height of the image in pixels. This can be omitted if the image is [PNG]
+ // formatted.
+ Height int
+}
+
+// Decode decodes the image data from r in the specified format.
+func (d *Decoder) Decode(r io.Reader) (image.Image, error) {
+ if d.Decompress {
+ zr, err := zlib.NewReader(r)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create zlib reader: %w", err)
+ }
+
+ defer zr.Close() //nolint:errcheck
+ r = zr
+ }
+
+ if d.Format == 0 {
+ d.Format = RGBA
+ }
+
+ switch d.Format {
+ case RGBA, RGB:
+ return d.decodeRGBA(r, d.Format == RGBA)
+
+ case PNG:
+ return png.Decode(r)
+
+ default:
+ return nil, fmt.Errorf("unsupported format: %d", d.Format)
+ }
+}
+
+// decodeRGBA decodes the image data in 32-bit RGBA or 24-bit RGB formats.
+func (d *Decoder) decodeRGBA(r io.Reader, alpha bool) (image.Image, error) {
+ m := image.NewRGBA(image.Rect(0, 0, d.Width, d.Height))
+
+ var buf []byte
+ if alpha {
+ buf = make([]byte, 4)
+ } else {
+ buf = make([]byte, 3)
+ }
+
+ for y := 0; y < d.Height; y++ {
+ for x := 0; x < d.Width; x++ {
+ if _, err := io.ReadFull(r, buf[:]); err != nil {
+ return nil, fmt.Errorf("failed to read pixel data: %w", err)
+ }
+ if alpha {
+ m.SetRGBA(x, y, color.RGBA{buf[0], buf[1], buf[2], buf[3]})
+ } else {
+ m.SetRGBA(x, y, color.RGBA{buf[0], buf[1], buf[2], 0xff})
+ }
+ }
+ }
+
+ return m, nil
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/kitty/encoder.go b/vendor/github.com/charmbracelet/x/ansi/kitty/encoder.go
new file mode 100644
index 00000000..f668b9e3
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/kitty/encoder.go
@@ -0,0 +1,64 @@
+package kitty
+
+import (
+ "compress/zlib"
+ "fmt"
+ "image"
+ "image/png"
+ "io"
+)
+
+// Encoder is an encoder for the Kitty graphics protocol. It supports encoding
+// images in the 24-bit [RGB], 32-bit [RGBA], and [PNG] formats, and
+// compressing the data using zlib.
+// The default format is 32-bit [RGBA].
+type Encoder struct {
+ // Uses zlib compression.
+ Compress bool
+
+ // Can be one of [RGBA], [RGB], or [PNG].
+ Format int
+}
+
+// Encode encodes the image data in the specified format and writes it to w.
+func (e *Encoder) Encode(w io.Writer, m image.Image) error {
+ if m == nil {
+ return nil
+ }
+
+ if e.Compress {
+ zw := zlib.NewWriter(w)
+ defer zw.Close() //nolint:errcheck
+ w = zw
+ }
+
+ if e.Format == 0 {
+ e.Format = RGBA
+ }
+
+ switch e.Format {
+ case RGBA, RGB:
+ bounds := m.Bounds()
+ for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ r, g, b, a := m.At(x, y).RGBA()
+ switch e.Format {
+ case RGBA:
+ w.Write([]byte{byte(r >> 8), byte(g >> 8), byte(b >> 8), byte(a >> 8)}) //nolint:errcheck
+ case RGB:
+ w.Write([]byte{byte(r >> 8), byte(g >> 8), byte(b >> 8)}) //nolint:errcheck
+ }
+ }
+ }
+
+ case PNG:
+ if err := png.Encode(w, m); err != nil {
+ return fmt.Errorf("failed to encode PNG: %w", err)
+ }
+
+ default:
+ return fmt.Errorf("unsupported format: %d", e.Format)
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/kitty/graphics.go b/vendor/github.com/charmbracelet/x/ansi/kitty/graphics.go
new file mode 100644
index 00000000..490e7a8a
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/kitty/graphics.go
@@ -0,0 +1,414 @@
+package kitty
+
+import "errors"
+
+// ErrMissingFile is returned when the file path is missing.
+var ErrMissingFile = errors.New("missing file path")
+
+// MaxChunkSize is the maximum chunk size for the image data.
+const MaxChunkSize = 1024 * 4
+
+// Placeholder is a special Unicode character that can be used as a placeholder
+// for an image.
+const Placeholder = '\U0010EEEE'
+
+// Graphics image format.
+const (
+ // 32-bit RGBA format.
+ RGBA = 32
+
+ // 24-bit RGB format.
+ RGB = 24
+
+ // PNG format.
+ PNG = 100
+)
+
+// Compression types.
+const (
+ Zlib = 'z'
+)
+
+// Transmission types.
+const (
+ // The data transmitted directly in the escape sequence.
+ Direct = 'd'
+
+ // The data transmitted in a regular file.
+ File = 'f'
+
+ // A temporary file is used and deleted after transmission.
+ TempFile = 't'
+
+ // A shared memory object.
+ // For POSIX see https://pubs.opengroup.org/onlinepubs/9699919799/functions/shm_open.html
+ // For Windows see https://docs.microsoft.com/en-us/windows/win32/memory/creating-named-shared-memory
+ SharedMemory = 's'
+)
+
+// Action types.
+const (
+ // Transmit image data.
+ Transmit = 't'
+ // TransmitAndPut transmit image data and display (put) it.
+ TransmitAndPut = 'T'
+ // Query terminal for image info.
+ Query = 'q'
+ // Put (display) previously transmitted image.
+ Put = 'p'
+ // Delete image.
+ Delete = 'd'
+ // Frame transmits data for animation frames.
+ Frame = 'f'
+ // Animate controls animation.
+ Animate = 'a'
+ // Compose composes animation frames.
+ Compose = 'c'
+)
+
+// Delete types.
+const (
+ // Delete all placements visible on screen
+ DeleteAll = 'a'
+ // Delete all images with the specified id, specified using the i key. If
+ // you specify a p key for the placement id as well, then only the
+ // placement with the specified image id and placement id will be deleted.
+ DeleteID = 'i'
+ // Delete newest image with the specified number, specified using the I
+ // key. If you specify a p key for the placement id as well, then only the
+ // placement with the specified number and placement id will be deleted.
+ DeleteNumber = 'n'
+ // Delete all placements that intersect with the current cursor position.
+ DeleteCursor = 'c'
+ // Delete animation frames.
+ DeleteFrames = 'f'
+ // Delete all placements that intersect a specific cell, the cell is
+ // specified using the x and y keys
+ DeleteCell = 'p'
+ // Delete all placements that intersect a specific cell having a specific
+ // z-index. The cell and z-index is specified using the x, y and z keys.
+ DeleteCellZ = 'q'
+ // Delete all images whose id is greater than or equal to the value of the x
+ // key and less than or equal to the value of the y.
+ DeleteRange = 'r'
+ // Delete all placements that intersect the specified column, specified using
+ // the x key.
+ DeleteColumn = 'x'
+ // Delete all placements that intersect the specified row, specified using
+ // the y key.
+ DeleteRow = 'y'
+ // Delete all placements that have the specified z-index, specified using the
+ // z key.
+ DeleteZ = 'z'
+)
+
+// Diacritic returns the diacritic rune at the specified index. If the index is
+// out of bounds, the first diacritic rune is returned.
+func Diacritic(i int) rune {
+ if i < 0 || i >= len(diacritics) {
+ return diacritics[0]
+ }
+ return diacritics[i]
+}
+
+// From https://sw.kovidgoyal.net/kitty/_downloads/f0a0de9ec8d9ff4456206db8e0814937/rowcolumn-diacritics.txt
+// See https://sw.kovidgoyal.net/kitty/graphics-protocol/#unicode-placeholders for further explanation.
+var diacritics = []rune{
+ '\u0305',
+ '\u030D',
+ '\u030E',
+ '\u0310',
+ '\u0312',
+ '\u033D',
+ '\u033E',
+ '\u033F',
+ '\u0346',
+ '\u034A',
+ '\u034B',
+ '\u034C',
+ '\u0350',
+ '\u0351',
+ '\u0352',
+ '\u0357',
+ '\u035B',
+ '\u0363',
+ '\u0364',
+ '\u0365',
+ '\u0366',
+ '\u0367',
+ '\u0368',
+ '\u0369',
+ '\u036A',
+ '\u036B',
+ '\u036C',
+ '\u036D',
+ '\u036E',
+ '\u036F',
+ '\u0483',
+ '\u0484',
+ '\u0485',
+ '\u0486',
+ '\u0487',
+ '\u0592',
+ '\u0593',
+ '\u0594',
+ '\u0595',
+ '\u0597',
+ '\u0598',
+ '\u0599',
+ '\u059C',
+ '\u059D',
+ '\u059E',
+ '\u059F',
+ '\u05A0',
+ '\u05A1',
+ '\u05A8',
+ '\u05A9',
+ '\u05AB',
+ '\u05AC',
+ '\u05AF',
+ '\u05C4',
+ '\u0610',
+ '\u0611',
+ '\u0612',
+ '\u0613',
+ '\u0614',
+ '\u0615',
+ '\u0616',
+ '\u0617',
+ '\u0657',
+ '\u0658',
+ '\u0659',
+ '\u065A',
+ '\u065B',
+ '\u065D',
+ '\u065E',
+ '\u06D6',
+ '\u06D7',
+ '\u06D8',
+ '\u06D9',
+ '\u06DA',
+ '\u06DB',
+ '\u06DC',
+ '\u06DF',
+ '\u06E0',
+ '\u06E1',
+ '\u06E2',
+ '\u06E4',
+ '\u06E7',
+ '\u06E8',
+ '\u06EB',
+ '\u06EC',
+ '\u0730',
+ '\u0732',
+ '\u0733',
+ '\u0735',
+ '\u0736',
+ '\u073A',
+ '\u073D',
+ '\u073F',
+ '\u0740',
+ '\u0741',
+ '\u0743',
+ '\u0745',
+ '\u0747',
+ '\u0749',
+ '\u074A',
+ '\u07EB',
+ '\u07EC',
+ '\u07ED',
+ '\u07EE',
+ '\u07EF',
+ '\u07F0',
+ '\u07F1',
+ '\u07F3',
+ '\u0816',
+ '\u0817',
+ '\u0818',
+ '\u0819',
+ '\u081B',
+ '\u081C',
+ '\u081D',
+ '\u081E',
+ '\u081F',
+ '\u0820',
+ '\u0821',
+ '\u0822',
+ '\u0823',
+ '\u0825',
+ '\u0826',
+ '\u0827',
+ '\u0829',
+ '\u082A',
+ '\u082B',
+ '\u082C',
+ '\u082D',
+ '\u0951',
+ '\u0953',
+ '\u0954',
+ '\u0F82',
+ '\u0F83',
+ '\u0F86',
+ '\u0F87',
+ '\u135D',
+ '\u135E',
+ '\u135F',
+ '\u17DD',
+ '\u193A',
+ '\u1A17',
+ '\u1A75',
+ '\u1A76',
+ '\u1A77',
+ '\u1A78',
+ '\u1A79',
+ '\u1A7A',
+ '\u1A7B',
+ '\u1A7C',
+ '\u1B6B',
+ '\u1B6D',
+ '\u1B6E',
+ '\u1B6F',
+ '\u1B70',
+ '\u1B71',
+ '\u1B72',
+ '\u1B73',
+ '\u1CD0',
+ '\u1CD1',
+ '\u1CD2',
+ '\u1CDA',
+ '\u1CDB',
+ '\u1CE0',
+ '\u1DC0',
+ '\u1DC1',
+ '\u1DC3',
+ '\u1DC4',
+ '\u1DC5',
+ '\u1DC6',
+ '\u1DC7',
+ '\u1DC8',
+ '\u1DC9',
+ '\u1DCB',
+ '\u1DCC',
+ '\u1DD1',
+ '\u1DD2',
+ '\u1DD3',
+ '\u1DD4',
+ '\u1DD5',
+ '\u1DD6',
+ '\u1DD7',
+ '\u1DD8',
+ '\u1DD9',
+ '\u1DDA',
+ '\u1DDB',
+ '\u1DDC',
+ '\u1DDD',
+ '\u1DDE',
+ '\u1DDF',
+ '\u1DE0',
+ '\u1DE1',
+ '\u1DE2',
+ '\u1DE3',
+ '\u1DE4',
+ '\u1DE5',
+ '\u1DE6',
+ '\u1DFE',
+ '\u20D0',
+ '\u20D1',
+ '\u20D4',
+ '\u20D5',
+ '\u20D6',
+ '\u20D7',
+ '\u20DB',
+ '\u20DC',
+ '\u20E1',
+ '\u20E7',
+ '\u20E9',
+ '\u20F0',
+ '\u2CEF',
+ '\u2CF0',
+ '\u2CF1',
+ '\u2DE0',
+ '\u2DE1',
+ '\u2DE2',
+ '\u2DE3',
+ '\u2DE4',
+ '\u2DE5',
+ '\u2DE6',
+ '\u2DE7',
+ '\u2DE8',
+ '\u2DE9',
+ '\u2DEA',
+ '\u2DEB',
+ '\u2DEC',
+ '\u2DED',
+ '\u2DEE',
+ '\u2DEF',
+ '\u2DF0',
+ '\u2DF1',
+ '\u2DF2',
+ '\u2DF3',
+ '\u2DF4',
+ '\u2DF5',
+ '\u2DF6',
+ '\u2DF7',
+ '\u2DF8',
+ '\u2DF9',
+ '\u2DFA',
+ '\u2DFB',
+ '\u2DFC',
+ '\u2DFD',
+ '\u2DFE',
+ '\u2DFF',
+ '\uA66F',
+ '\uA67C',
+ '\uA67D',
+ '\uA6F0',
+ '\uA6F1',
+ '\uA8E0',
+ '\uA8E1',
+ '\uA8E2',
+ '\uA8E3',
+ '\uA8E4',
+ '\uA8E5',
+ '\uA8E6',
+ '\uA8E7',
+ '\uA8E8',
+ '\uA8E9',
+ '\uA8EA',
+ '\uA8EB',
+ '\uA8EC',
+ '\uA8ED',
+ '\uA8EE',
+ '\uA8EF',
+ '\uA8F0',
+ '\uA8F1',
+ '\uAAB0',
+ '\uAAB2',
+ '\uAAB3',
+ '\uAAB7',
+ '\uAAB8',
+ '\uAABE',
+ '\uAABF',
+ '\uAAC1',
+ '\uFE20',
+ '\uFE21',
+ '\uFE22',
+ '\uFE23',
+ '\uFE24',
+ '\uFE25',
+ '\uFE26',
+ '\U00010A0F',
+ '\U00010A38',
+ '\U0001D185',
+ '\U0001D186',
+ '\U0001D187',
+ '\U0001D188',
+ '\U0001D189',
+ '\U0001D1AA',
+ '\U0001D1AB',
+ '\U0001D1AC',
+ '\U0001D1AD',
+ '\U0001D242',
+ '\U0001D243',
+ '\U0001D244',
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/kitty/options.go b/vendor/github.com/charmbracelet/x/ansi/kitty/options.go
new file mode 100644
index 00000000..a8d907bd
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/kitty/options.go
@@ -0,0 +1,367 @@
+package kitty
+
+import (
+ "encoding"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+var (
+ _ encoding.TextMarshaler = Options{}
+ _ encoding.TextUnmarshaler = &Options{}
+)
+
+// Options represents a Kitty Graphics Protocol options.
+type Options struct {
+ // Common options.
+
+ // Action (a=t) is the action to be performed on the image. Can be one of
+ // [Transmit], [TransmitDisplay], [Query], [Put], [Delete], [Frame],
+ // [Animate], [Compose].
+ Action byte
+
+ // Quite mode (q=0) is the quiet mode. Can be either zero, one, or two
+ // where zero is the default, 1 suppresses OK responses, and 2 suppresses
+ // both OK and error responses.
+ Quite byte
+
+ // Transmission options.
+
+ // ID (i=) is the image ID. The ID is a unique identifier for the image.
+ // Must be a positive integer up to [math.MaxUint32].
+ ID int
+
+ // PlacementID (p=) is the placement ID. The placement ID is a unique
+ // identifier for the placement of the image. Must be a positive integer up
+ // to [math.MaxUint32].
+ PlacementID int
+
+ // Number (I=0) is the number of images to be transmitted.
+ Number int
+
+ // Format (f=32) is the image format. One of [RGBA], [RGB], [PNG].
+ Format int
+
+ // ImageWidth (s=0) is the transmitted image width.
+ ImageWidth int
+
+ // ImageHeight (v=0) is the transmitted image height.
+ ImageHeight int
+
+ // Compression (o=) is the image compression type. Can be [Zlib] or zero.
+ Compression byte
+
+ // Transmission (t=d) is the image transmission type. Can be [Direct], [File],
+ // [TempFile], or[SharedMemory].
+ Transmission byte
+
+ // File is the file path to be used when the transmission type is [File].
+ // If [Options.Transmission] is omitted i.e. zero and this is non-empty,
+ // the transmission type is set to [File].
+ File string
+
+ // Size (S=0) is the size to be read from the transmission medium.
+ Size int
+
+ // Offset (O=0) is the offset byte to start reading from the transmission
+ // medium.
+ Offset int
+
+ // Chunk (m=) whether the image is transmitted in chunks. Can be either
+ // zero or one. When true, the image is transmitted in chunks. Each chunk
+ // must be a multiple of 4, and up to [MaxChunkSize] bytes. Each chunk must
+ // have the m=1 option except for the last chunk which must have m=0.
+ Chunk bool
+
+ // Display options.
+
+ // X (x=0) is the pixel X coordinate of the image to start displaying.
+ X int
+
+ // Y (y=0) is the pixel Y coordinate of the image to start displaying.
+ Y int
+
+ // Z (z=0) is the Z coordinate of the image to display.
+ Z int
+
+ // Width (w=0) is the width of the image to display.
+ Width int
+
+ // Height (h=0) is the height of the image to display.
+ Height int
+
+ // OffsetX (X=0) is the OffsetX coordinate of the cursor cell to start
+ // displaying the image. OffsetX=0 is the leftmost cell. This must be
+ // smaller than the terminal cell width.
+ OffsetX int
+
+ // OffsetY (Y=0) is the OffsetY coordinate of the cursor cell to start
+ // displaying the image. OffsetY=0 is the topmost cell. This must be
+ // smaller than the terminal cell height.
+ OffsetY int
+
+ // Columns (c=0) is the number of columns to display the image. The image
+ // will be scaled to fit the number of columns.
+ Columns int
+
+ // Rows (r=0) is the number of rows to display the image. The image will be
+ // scaled to fit the number of rows.
+ Rows int
+
+ // VirtualPlacement (U=0) whether to use virtual placement. This is used
+ // with Unicode [Placeholder] to display images.
+ VirtualPlacement bool
+
+ // DoNotMoveCursor (C=0) whether to move the cursor after displaying the
+ // image.
+ DoNotMoveCursor bool
+
+ // ParentID (P=0) is the parent image ID. The parent ID is the ID of the
+ // image that is the parent of the current image. This is used with Unicode
+ // [Placeholder] to display images relative to the parent image.
+ ParentID int
+
+ // ParentPlacementID (Q=0) is the parent placement ID. The parent placement
+ // ID is the ID of the placement of the parent image. This is used with
+ // Unicode [Placeholder] to display images relative to the parent image.
+ ParentPlacementID int
+
+ // Delete options.
+
+ // Delete (d=a) is the delete action. Can be one of [DeleteAll],
+ // [DeleteID], [DeleteNumber], [DeleteCursor], [DeleteFrames],
+ // [DeleteCell], [DeleteCellZ], [DeleteRange], [DeleteColumn], [DeleteRow],
+ // [DeleteZ].
+ Delete byte
+
+ // DeleteResources indicates whether to delete the resources associated
+ // with the image.
+ DeleteResources bool
+}
+
+// Options returns the options as a slice of a key-value pairs.
+func (o *Options) Options() (opts []string) {
+ opts = []string{}
+ if o.Format == 0 {
+ o.Format = RGBA
+ }
+
+ if o.Action == 0 {
+ o.Action = Transmit
+ }
+
+ if o.Delete == 0 {
+ o.Delete = DeleteAll
+ }
+
+ if o.Transmission == 0 {
+ if len(o.File) > 0 {
+ o.Transmission = File
+ } else {
+ o.Transmission = Direct
+ }
+ }
+
+ if o.Format != RGBA {
+ opts = append(opts, fmt.Sprintf("f=%d", o.Format))
+ }
+
+ if o.Quite > 0 {
+ opts = append(opts, fmt.Sprintf("q=%d", o.Quite))
+ }
+
+ if o.ID > 0 {
+ opts = append(opts, fmt.Sprintf("i=%d", o.ID))
+ }
+
+ if o.PlacementID > 0 {
+ opts = append(opts, fmt.Sprintf("p=%d", o.PlacementID))
+ }
+
+ if o.Number > 0 {
+ opts = append(opts, fmt.Sprintf("I=%d", o.Number))
+ }
+
+ if o.ImageWidth > 0 {
+ opts = append(opts, fmt.Sprintf("s=%d", o.ImageWidth))
+ }
+
+ if o.ImageHeight > 0 {
+ opts = append(opts, fmt.Sprintf("v=%d", o.ImageHeight))
+ }
+
+ if o.Transmission != Direct {
+ opts = append(opts, fmt.Sprintf("t=%c", o.Transmission))
+ }
+
+ if o.Size > 0 {
+ opts = append(opts, fmt.Sprintf("S=%d", o.Size))
+ }
+
+ if o.Offset > 0 {
+ opts = append(opts, fmt.Sprintf("O=%d", o.Offset))
+ }
+
+ if o.Compression == Zlib {
+ opts = append(opts, fmt.Sprintf("o=%c", o.Compression))
+ }
+
+ if o.VirtualPlacement {
+ opts = append(opts, "U=1")
+ }
+
+ if o.DoNotMoveCursor {
+ opts = append(opts, "C=1")
+ }
+
+ if o.ParentID > 0 {
+ opts = append(opts, fmt.Sprintf("P=%d", o.ParentID))
+ }
+
+ if o.ParentPlacementID > 0 {
+ opts = append(opts, fmt.Sprintf("Q=%d", o.ParentPlacementID))
+ }
+
+ if o.X > 0 {
+ opts = append(opts, fmt.Sprintf("x=%d", o.X))
+ }
+
+ if o.Y > 0 {
+ opts = append(opts, fmt.Sprintf("y=%d", o.Y))
+ }
+
+ if o.Z > 0 {
+ opts = append(opts, fmt.Sprintf("z=%d", o.Z))
+ }
+
+ if o.Width > 0 {
+ opts = append(opts, fmt.Sprintf("w=%d", o.Width))
+ }
+
+ if o.Height > 0 {
+ opts = append(opts, fmt.Sprintf("h=%d", o.Height))
+ }
+
+ if o.OffsetX > 0 {
+ opts = append(opts, fmt.Sprintf("X=%d", o.OffsetX))
+ }
+
+ if o.OffsetY > 0 {
+ opts = append(opts, fmt.Sprintf("Y=%d", o.OffsetY))
+ }
+
+ if o.Columns > 0 {
+ opts = append(opts, fmt.Sprintf("c=%d", o.Columns))
+ }
+
+ if o.Rows > 0 {
+ opts = append(opts, fmt.Sprintf("r=%d", o.Rows))
+ }
+
+ if o.Delete != DeleteAll || o.DeleteResources {
+ da := o.Delete
+ if o.DeleteResources {
+ da = da - ' ' // to uppercase
+ }
+
+ opts = append(opts, fmt.Sprintf("d=%c", da))
+ }
+
+ if o.Action != Transmit {
+ opts = append(opts, fmt.Sprintf("a=%c", o.Action))
+ }
+
+ return
+}
+
+// String returns the string representation of the options.
+func (o Options) String() string {
+ return strings.Join(o.Options(), ",")
+}
+
+// MarshalText returns the string representation of the options.
+func (o Options) MarshalText() ([]byte, error) {
+ return []byte(o.String()), nil
+}
+
+// UnmarshalText parses the options from the given string.
+func (o *Options) UnmarshalText(text []byte) error {
+ opts := strings.Split(string(text), ",")
+ for _, opt := range opts {
+ ps := strings.SplitN(opt, "=", 2)
+ if len(ps) != 2 || len(ps[1]) == 0 {
+ continue
+ }
+
+ switch ps[0] {
+ case "a":
+ o.Action = ps[1][0]
+ case "o":
+ o.Compression = ps[1][0]
+ case "t":
+ o.Transmission = ps[1][0]
+ case "d":
+ d := ps[1][0]
+ if d >= 'A' && d <= 'Z' {
+ o.DeleteResources = true
+ d = d + ' ' // to lowercase
+ }
+ o.Delete = d
+ case "i", "q", "p", "I", "f", "s", "v", "S", "O", "m", "x", "y", "z", "w", "h", "X", "Y", "c", "r", "U", "P", "Q":
+ v, err := strconv.Atoi(ps[1])
+ if err != nil {
+ continue
+ }
+
+ switch ps[0] {
+ case "i":
+ o.ID = v
+ case "q":
+ o.Quite = byte(v)
+ case "p":
+ o.PlacementID = v
+ case "I":
+ o.Number = v
+ case "f":
+ o.Format = v
+ case "s":
+ o.ImageWidth = v
+ case "v":
+ o.ImageHeight = v
+ case "S":
+ o.Size = v
+ case "O":
+ o.Offset = v
+ case "m":
+ o.Chunk = v == 0 || v == 1
+ case "x":
+ o.X = v
+ case "y":
+ o.Y = v
+ case "z":
+ o.Z = v
+ case "w":
+ o.Width = v
+ case "h":
+ o.Height = v
+ case "X":
+ o.OffsetX = v
+ case "Y":
+ o.OffsetY = v
+ case "c":
+ o.Columns = v
+ case "r":
+ o.Rows = v
+ case "U":
+ o.VirtualPlacement = v == 1
+ case "P":
+ o.ParentID = v
+ case "Q":
+ o.ParentPlacementID = v
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/method.go b/vendor/github.com/charmbracelet/x/ansi/method.go
new file mode 100644
index 00000000..0218809c
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/method.go
@@ -0,0 +1,172 @@
+package ansi
+
+// Method is a type that represents the how the renderer should calculate the
+// display width of cells.
+type Method uint8
+
+// Display width modes.
+const (
+ WcWidth Method = iota
+ GraphemeWidth
+)
+
+// StringWidth returns the width of a string in cells. This is the number of
+// cells that the string will occupy when printed in a terminal. ANSI escape
+// codes are ignored and wide characters (such as East Asians and emojis) are
+// accounted for.
+func (m Method) StringWidth(s string) int {
+ return stringWidth(m, s)
+}
+
+// Truncate truncates a string to a given length, adding a tail to the end if
+// the string is longer than the given length. This function is aware of ANSI
+// escape codes and will not break them, and accounts for wide-characters (such
+// as East-Asian characters and emojis).
+func (m Method) Truncate(s string, length int, tail string) string {
+ return truncate(m, s, length, tail)
+}
+
+// TruncateLeft truncates a string to a given length, adding a prefix to the
+// beginning if the string is longer than the given length. This function is
+// aware of ANSI escape codes and will not break them, and accounts for
+// wide-characters (such as East-Asian characters and emojis).
+func (m Method) TruncateLeft(s string, length int, prefix string) string {
+ return truncateLeft(m, s, length, prefix)
+}
+
+// Cut the string, without adding any prefix or tail strings. This function is
+// aware of ANSI escape codes and will not break them, and accounts for
+// wide-characters (such as East-Asian characters and emojis). Note that the
+// [left] parameter is inclusive, while [right] isn't.
+func (m Method) Cut(s string, left, right int) string {
+ return cut(m, s, left, right)
+}
+
+// Hardwrap wraps a string or a block of text to a given line length, breaking
+// word boundaries. This will preserve ANSI escape codes and will account for
+// wide-characters in the string.
+// When preserveSpace is true, spaces at the beginning of a line will be
+// preserved.
+// This treats the text as a sequence of graphemes.
+func (m Method) Hardwrap(s string, length int, preserveSpace bool) string {
+ return hardwrap(m, s, length, preserveSpace)
+}
+
+// Wordwrap wraps a string or a block of text to a given line length, not
+// breaking word boundaries. This will preserve ANSI escape codes and will
+// account for wide-characters in the string.
+// The breakpoints string is a list of characters that are considered
+// breakpoints for word wrapping. A hyphen (-) is always considered a
+// breakpoint.
+//
+// Note: breakpoints must be a string of 1-cell wide rune characters.
+func (m Method) Wordwrap(s string, length int, breakpoints string) string {
+ return wordwrap(m, s, length, breakpoints)
+}
+
+// Wrap wraps a string or a block of text to a given line length, breaking word
+// boundaries if necessary. This will preserve ANSI escape codes and will
+// account for wide-characters in the string. The breakpoints string is a list
+// of characters that are considered breakpoints for word wrapping. A hyphen
+// (-) is always considered a breakpoint.
+//
+// Note: breakpoints must be a string of 1-cell wide rune characters.
+func (m Method) Wrap(s string, length int, breakpoints string) string {
+ return wrap(m, s, length, breakpoints)
+}
+
+// DecodeSequence decodes the first ANSI escape sequence or a printable
+// grapheme from the given data. It returns the sequence slice, the number of
+// bytes read, the cell width for each sequence, and the new state.
+//
+// The cell width will always be 0 for control and escape sequences, 1 for
+// ASCII printable characters, and the number of cells other Unicode characters
+// occupy. It uses the uniseg package to calculate the width of Unicode
+// graphemes and characters. This means it will always do grapheme clustering
+// (mode 2027).
+//
+// Passing a non-nil [*Parser] as the last argument will allow the decoder to
+// collect sequence parameters, data, and commands. The parser cmd will have
+// the packed command value that contains intermediate and prefix characters.
+// In the case of a OSC sequence, the cmd will be the OSC command number. Use
+// [Cmd] and [Param] types to unpack command intermediates and prefixes as well
+// as parameters.
+//
+// Zero [Cmd] means the CSI, DCS, or ESC sequence is invalid. Moreover, checking the
+// validity of other data sequences, OSC, DCS, etc, will require checking for
+// the returned sequence terminator bytes such as ST (ESC \\) and BEL).
+//
+// We store the command byte in [Cmd] in the most significant byte, the
+// prefix byte in the next byte, and the intermediate byte in the least
+// significant byte. This is done to avoid using a struct to store the command
+// and its intermediates and prefixes. The command byte is always the least
+// significant byte i.e. [Cmd & 0xff]. Use the [Cmd] type to unpack the
+// command, intermediate, and prefix bytes. Note that we only collect the last
+// prefix character and intermediate byte.
+//
+// The [p.Params] slice will contain the parameters of the sequence. Any
+// sub-parameter will have the [parser.HasMoreFlag] set. Use the [Param] type
+// to unpack the parameters.
+//
+// Example:
+//
+// var state byte // the initial state is always zero [NormalState]
+// p := NewParser(32, 1024) // create a new parser with a 32 params buffer and 1024 data buffer (optional)
+// input := []byte("\x1b[31mHello, World!\x1b[0m")
+// for len(input) > 0 {
+// seq, width, n, newState := DecodeSequence(input, state, p)
+// log.Printf("seq: %q, width: %d", seq, width)
+// state = newState
+// input = input[n:]
+// }
+func (m Method) DecodeSequence(data []byte, state byte, p *Parser) (seq []byte, width, n int, newState byte) {
+ return decodeSequence(m, data, state, p)
+}
+
+// DecodeSequenceInString decodes the first ANSI escape sequence or a printable
+// grapheme from the given data. It returns the sequence slice, the number of
+// bytes read, the cell width for each sequence, and the new state.
+//
+// The cell width will always be 0 for control and escape sequences, 1 for
+// ASCII printable characters, and the number of cells other Unicode characters
+// occupy. It uses the uniseg package to calculate the width of Unicode
+// graphemes and characters. This means it will always do grapheme clustering
+// (mode 2027).
+//
+// Passing a non-nil [*Parser] as the last argument will allow the decoder to
+// collect sequence parameters, data, and commands. The parser cmd will have
+// the packed command value that contains intermediate and prefix characters.
+// In the case of a OSC sequence, the cmd will be the OSC command number. Use
+// [Cmd] and [Param] types to unpack command intermediates and prefixes as well
+// as parameters.
+//
+// Zero [Cmd] means the CSI, DCS, or ESC sequence is invalid. Moreover, checking the
+// validity of other data sequences, OSC, DCS, etc, will require checking for
+// the returned sequence terminator bytes such as ST (ESC \\) and BEL).
+//
+// We store the command byte in [Cmd] in the most significant byte, the
+// prefix byte in the next byte, and the intermediate byte in the least
+// significant byte. This is done to avoid using a struct to store the command
+// and its intermediates and prefixes. The command byte is always the least
+// significant byte i.e. [Cmd & 0xff]. Use the [Cmd] type to unpack the
+// command, intermediate, and prefix bytes. Note that we only collect the last
+// prefix character and intermediate byte.
+//
+// The [p.Params] slice will contain the parameters of the sequence. Any
+// sub-parameter will have the [parser.HasMoreFlag] set. Use the [Param] type
+// to unpack the parameters.
+//
+// Example:
+//
+// var state byte // the initial state is always zero [NormalState]
+// p := NewParser(32, 1024) // create a new parser with a 32 params buffer and 1024 data buffer (optional)
+// input := []byte("\x1b[31mHello, World!\x1b[0m")
+// for len(input) > 0 {
+// seq, width, n, newState := DecodeSequenceInString(input, state, p)
+// log.Printf("seq: %q, width: %d", seq, width)
+// state = newState
+// input = input[n:]
+// }
+func (m Method) DecodeSequenceInString(data string, state byte, p *Parser) (seq string, width, n int, newState byte) {
+ return decodeSequence(m, data, state, p)
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/mode.go b/vendor/github.com/charmbracelet/x/ansi/mode.go
new file mode 100644
index 00000000..57f3f0a8
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/mode.go
@@ -0,0 +1,763 @@
+package ansi
+
+import (
+ "strconv"
+ "strings"
+)
+
+// ModeSetting represents a mode setting.
+type ModeSetting byte
+
+// ModeSetting constants.
+const (
+ ModeNotRecognized ModeSetting = iota
+ ModeSet
+ ModeReset
+ ModePermanentlySet
+ ModePermanentlyReset
+)
+
+// IsNotRecognized returns true if the mode is not recognized.
+func (m ModeSetting) IsNotRecognized() bool {
+ return m == ModeNotRecognized
+}
+
+// IsSet returns true if the mode is set or permanently set.
+func (m ModeSetting) IsSet() bool {
+ return m == ModeSet || m == ModePermanentlySet
+}
+
+// IsReset returns true if the mode is reset or permanently reset.
+func (m ModeSetting) IsReset() bool {
+ return m == ModeReset || m == ModePermanentlyReset
+}
+
+// IsPermanentlySet returns true if the mode is permanently set.
+func (m ModeSetting) IsPermanentlySet() bool {
+ return m == ModePermanentlySet
+}
+
+// IsPermanentlyReset returns true if the mode is permanently reset.
+func (m ModeSetting) IsPermanentlyReset() bool {
+ return m == ModePermanentlyReset
+}
+
+// Mode represents an interface for terminal modes.
+// Modes can be set, reset, and requested.
+type Mode interface {
+ Mode() int
+}
+
+// SetMode (SM) returns a sequence to set a mode.
+// The mode arguments are a list of modes to set.
+//
+// If one of the modes is a [DECMode], the function will returns two escape
+// sequences.
+//
+// ANSI format:
+//
+// CSI Pd ; ... ; Pd h
+//
+// DEC format:
+//
+// CSI ? Pd ; ... ; Pd h
+//
+// See: https://vt100.net/docs/vt510-rm/SM.html
+func SetMode(modes ...Mode) string {
+ return setMode(false, modes...)
+}
+
+// SM is an alias for [SetMode].
+func SM(modes ...Mode) string {
+ return SetMode(modes...)
+}
+
+// ResetMode (RM) returns a sequence to reset a mode.
+// The mode arguments are a list of modes to reset.
+//
+// If one of the modes is a [DECMode], the function will returns two escape
+// sequences.
+//
+// ANSI format:
+//
+// CSI Pd ; ... ; Pd l
+//
+// DEC format:
+//
+// CSI ? Pd ; ... ; Pd l
+//
+// See: https://vt100.net/docs/vt510-rm/RM.html
+func ResetMode(modes ...Mode) string {
+ return setMode(true, modes...)
+}
+
+// RM is an alias for [ResetMode].
+func RM(modes ...Mode) string {
+ return ResetMode(modes...)
+}
+
+func setMode(reset bool, modes ...Mode) (s string) {
+ if len(modes) == 0 {
+ return
+ }
+
+ cmd := "h"
+ if reset {
+ cmd = "l"
+ }
+
+ seq := "\x1b["
+ if len(modes) == 1 {
+ switch modes[0].(type) {
+ case DECMode:
+ seq += "?"
+ }
+ return seq + strconv.Itoa(modes[0].Mode()) + cmd
+ }
+
+ dec := make([]string, 0, len(modes)/2)
+ ansi := make([]string, 0, len(modes)/2)
+ for _, m := range modes {
+ switch m.(type) {
+ case DECMode:
+ dec = append(dec, strconv.Itoa(m.Mode()))
+ case ANSIMode:
+ ansi = append(ansi, strconv.Itoa(m.Mode()))
+ }
+ }
+
+ if len(ansi) > 0 {
+ s += seq + strings.Join(ansi, ";") + cmd
+ }
+ if len(dec) > 0 {
+ s += seq + "?" + strings.Join(dec, ";") + cmd
+ }
+ return
+}
+
+// RequestMode (DECRQM) returns a sequence to request a mode from the terminal.
+// The terminal responds with a report mode function [DECRPM].
+//
+// ANSI format:
+//
+// CSI Pa $ p
+//
+// DEC format:
+//
+// CSI ? Pa $ p
+//
+// See: https://vt100.net/docs/vt510-rm/DECRQM.html
+func RequestMode(m Mode) string {
+ seq := "\x1b["
+ switch m.(type) {
+ case DECMode:
+ seq += "?"
+ }
+ return seq + strconv.Itoa(m.Mode()) + "$p"
+}
+
+// DECRQM is an alias for [RequestMode].
+func DECRQM(m Mode) string {
+ return RequestMode(m)
+}
+
+// ReportMode (DECRPM) returns a sequence that the terminal sends to the host
+// in response to a mode request [DECRQM].
+//
+// ANSI format:
+//
+// CSI Pa ; Ps ; $ y
+//
+// DEC format:
+//
+// CSI ? Pa ; Ps $ y
+//
+// Where Pa is the mode number, and Ps is the mode value.
+//
+// 0: Not recognized
+// 1: Set
+// 2: Reset
+// 3: Permanent set
+// 4: Permanent reset
+//
+// See: https://vt100.net/docs/vt510-rm/DECRPM.html
+func ReportMode(mode Mode, value ModeSetting) string {
+ if value > 4 {
+ value = 0
+ }
+ switch mode.(type) {
+ case DECMode:
+ return "\x1b[?" + strconv.Itoa(mode.Mode()) + ";" + strconv.Itoa(int(value)) + "$y"
+ }
+ return "\x1b[" + strconv.Itoa(mode.Mode()) + ";" + strconv.Itoa(int(value)) + "$y"
+}
+
+// DECRPM is an alias for [ReportMode].
+func DECRPM(mode Mode, value ModeSetting) string {
+ return ReportMode(mode, value)
+}
+
+// ANSIMode represents an ANSI terminal mode.
+type ANSIMode int //nolint:revive
+
+// Mode returns the ANSI mode as an integer.
+func (m ANSIMode) Mode() int {
+ return int(m)
+}
+
+// DECMode represents a private DEC terminal mode.
+type DECMode int
+
+// Mode returns the DEC mode as an integer.
+func (m DECMode) Mode() int {
+ return int(m)
+}
+
+// Keyboard Action Mode (KAM) is a mode that controls locking of the keyboard.
+// When the keyboard is locked, it cannot send data to the terminal.
+//
+// See: https://vt100.net/docs/vt510-rm/KAM.html
+const (
+ KeyboardActionMode = ANSIMode(2)
+ KAM = KeyboardActionMode
+
+ SetKeyboardActionMode = "\x1b[2h"
+ ResetKeyboardActionMode = "\x1b[2l"
+ RequestKeyboardActionMode = "\x1b[2$p"
+)
+
+// Insert/Replace Mode (IRM) is a mode that determines whether characters are
+// inserted or replaced when typed.
+//
+// When enabled, characters are inserted at the cursor position pushing the
+// characters to the right. When disabled, characters replace the character at
+// the cursor position.
+//
+// See: https://vt100.net/docs/vt510-rm/IRM.html
+const (
+ InsertReplaceMode = ANSIMode(4)
+ IRM = InsertReplaceMode
+
+ SetInsertReplaceMode = "\x1b[4h"
+ ResetInsertReplaceMode = "\x1b[4l"
+ RequestInsertReplaceMode = "\x1b[4$p"
+)
+
+// Send Receive Mode (SRM) or Local Echo Mode is a mode that determines whether
+// the terminal echoes characters back to the host. When enabled, the terminal
+// sends characters to the host as they are typed.
+//
+// See: https://vt100.net/docs/vt510-rm/SRM.html
+const (
+ SendReceiveMode = ANSIMode(12)
+ LocalEchoMode = SendReceiveMode
+ SRM = SendReceiveMode
+
+ SetSendReceiveMode = "\x1b[12h"
+ ResetSendReceiveMode = "\x1b[12l"
+ RequestSendReceiveMode = "\x1b[12$p"
+
+ SetLocalEchoMode = "\x1b[12h"
+ ResetLocalEchoMode = "\x1b[12l"
+ RequestLocalEchoMode = "\x1b[12$p"
+)
+
+// Line Feed/New Line Mode (LNM) is a mode that determines whether the terminal
+// interprets the line feed character as a new line.
+//
+// When enabled, the terminal interprets the line feed character as a new line.
+// When disabled, the terminal interprets the line feed character as a line feed.
+//
+// A new line moves the cursor to the first position of the next line.
+// A line feed moves the cursor down one line without changing the column
+// scrolling the screen if necessary.
+//
+// See: https://vt100.net/docs/vt510-rm/LNM.html
+const (
+ LineFeedNewLineMode = ANSIMode(20)
+ LNM = LineFeedNewLineMode
+
+ SetLineFeedNewLineMode = "\x1b[20h"
+ ResetLineFeedNewLineMode = "\x1b[20l"
+ RequestLineFeedNewLineMode = "\x1b[20$p"
+)
+
+// Cursor Keys Mode (DECCKM) is a mode that determines whether the cursor keys
+// send ANSI cursor sequences or application sequences.
+//
+// See: https://vt100.net/docs/vt510-rm/DECCKM.html
+const (
+ CursorKeysMode = DECMode(1)
+ DECCKM = CursorKeysMode
+
+ SetCursorKeysMode = "\x1b[?1h"
+ ResetCursorKeysMode = "\x1b[?1l"
+ RequestCursorKeysMode = "\x1b[?1$p"
+)
+
+// Deprecated: use [SetCursorKeysMode] and [ResetCursorKeysMode] instead.
+const (
+ EnableCursorKeys = "\x1b[?1h"
+ DisableCursorKeys = "\x1b[?1l"
+)
+
+// Origin Mode (DECOM) is a mode that determines whether the cursor moves to the
+// home position or the margin position.
+//
+// See: https://vt100.net/docs/vt510-rm/DECOM.html
+const (
+ OriginMode = DECMode(6)
+ DECOM = OriginMode
+
+ SetOriginMode = "\x1b[?6h"
+ ResetOriginMode = "\x1b[?6l"
+ RequestOriginMode = "\x1b[?6$p"
+)
+
+// Auto Wrap Mode (DECAWM) is a mode that determines whether the cursor wraps
+// to the next line when it reaches the right margin.
+//
+// See: https://vt100.net/docs/vt510-rm/DECAWM.html
+const (
+ AutoWrapMode = DECMode(7)
+ DECAWM = AutoWrapMode
+
+ SetAutoWrapMode = "\x1b[?7h"
+ ResetAutoWrapMode = "\x1b[?7l"
+ RequestAutoWrapMode = "\x1b[?7$p"
+)
+
+// X10 Mouse Mode is a mode that determines whether the mouse reports on button
+// presses.
+//
+// The terminal responds with the following encoding:
+//
+// CSI M CbCxCy
+//
+// Where Cb is the button-1, where it can be 1, 2, or 3.
+// Cx and Cy are the x and y coordinates of the mouse event.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
+const (
+ X10MouseMode = DECMode(9)
+
+ SetX10MouseMode = "\x1b[?9h"
+ ResetX10MouseMode = "\x1b[?9l"
+ RequestX10MouseMode = "\x1b[?9$p"
+)
+
+// Text Cursor Enable Mode (DECTCEM) is a mode that shows/hides the cursor.
+//
+// See: https://vt100.net/docs/vt510-rm/DECTCEM.html
+const (
+ TextCursorEnableMode = DECMode(25)
+ DECTCEM = TextCursorEnableMode
+
+ SetTextCursorEnableMode = "\x1b[?25h"
+ ResetTextCursorEnableMode = "\x1b[?25l"
+ RequestTextCursorEnableMode = "\x1b[?25$p"
+)
+
+// These are aliases for [SetTextCursorEnableMode] and [ResetTextCursorEnableMode].
+const (
+ ShowCursor = SetTextCursorEnableMode
+ HideCursor = ResetTextCursorEnableMode
+)
+
+// Text Cursor Enable Mode (DECTCEM) is a mode that shows/hides the cursor.
+//
+// See: https://vt100.net/docs/vt510-rm/DECTCEM.html
+//
+// Deprecated: use [SetTextCursorEnableMode] and [ResetTextCursorEnableMode] instead.
+const (
+ CursorEnableMode = DECMode(25)
+ RequestCursorVisibility = "\x1b[?25$p"
+)
+
+// Numeric Keypad Mode (DECNKM) is a mode that determines whether the keypad
+// sends application sequences or numeric sequences.
+//
+// This works like [DECKPAM] and [DECKPNM], but uses different sequences.
+//
+// See: https://vt100.net/docs/vt510-rm/DECNKM.html
+const (
+ NumericKeypadMode = DECMode(66)
+ DECNKM = NumericKeypadMode
+
+ SetNumericKeypadMode = "\x1b[?66h"
+ ResetNumericKeypadMode = "\x1b[?66l"
+ RequestNumericKeypadMode = "\x1b[?66$p"
+)
+
+// Backarrow Key Mode (DECBKM) is a mode that determines whether the backspace
+// key sends a backspace or delete character. Disabled by default.
+//
+// See: https://vt100.net/docs/vt510-rm/DECBKM.html
+const (
+ BackarrowKeyMode = DECMode(67)
+ DECBKM = BackarrowKeyMode
+
+ SetBackarrowKeyMode = "\x1b[?67h"
+ ResetBackarrowKeyMode = "\x1b[?67l"
+ RequestBackarrowKeyMode = "\x1b[?67$p"
+)
+
+// Left Right Margin Mode (DECLRMM) is a mode that determines whether the left
+// and right margins can be set with [DECSLRM].
+//
+// See: https://vt100.net/docs/vt510-rm/DECLRMM.html
+const (
+ LeftRightMarginMode = DECMode(69)
+ DECLRMM = LeftRightMarginMode
+
+ SetLeftRightMarginMode = "\x1b[?69h"
+ ResetLeftRightMarginMode = "\x1b[?69l"
+ RequestLeftRightMarginMode = "\x1b[?69$p"
+)
+
+// Normal Mouse Mode is a mode that determines whether the mouse reports on
+// button presses and releases. It will also report modifier keys, wheel
+// events, and extra buttons.
+//
+// It uses the same encoding as [X10MouseMode] with a few differences:
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
+const (
+ NormalMouseMode = DECMode(1000)
+
+ SetNormalMouseMode = "\x1b[?1000h"
+ ResetNormalMouseMode = "\x1b[?1000l"
+ RequestNormalMouseMode = "\x1b[?1000$p"
+)
+
+// VT Mouse Tracking is a mode that determines whether the mouse reports on
+// button press and release.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
+//
+// Deprecated: use [NormalMouseMode] instead.
+const (
+ MouseMode = DECMode(1000)
+
+ EnableMouse = "\x1b[?1000h"
+ DisableMouse = "\x1b[?1000l"
+ RequestMouse = "\x1b[?1000$p"
+)
+
+// Highlight Mouse Tracking is a mode that determines whether the mouse reports
+// on button presses, releases, and highlighted cells.
+//
+// It uses the same encoding as [NormalMouseMode] with a few differences:
+//
+// On highlight events, the terminal responds with the following encoding:
+//
+// CSI t CxCy
+// CSI T CxCyCxCyCxCy
+//
+// Where the parameters are startx, starty, endx, endy, mousex, and mousey.
+const (
+ HighlightMouseMode = DECMode(1001)
+
+ SetHighlightMouseMode = "\x1b[?1001h"
+ ResetHighlightMouseMode = "\x1b[?1001l"
+ RequestHighlightMouseMode = "\x1b[?1001$p"
+)
+
+// VT Hilite Mouse Tracking is a mode that determines whether the mouse reports on
+// button presses, releases, and highlighted cells.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
+//
+// Deprecated: use [HighlightMouseMode] instead.
+const (
+ MouseHiliteMode = DECMode(1001)
+
+ EnableMouseHilite = "\x1b[?1001h"
+ DisableMouseHilite = "\x1b[?1001l"
+ RequestMouseHilite = "\x1b[?1001$p"
+)
+
+// Button Event Mouse Tracking is essentially the same as [NormalMouseMode],
+// but it also reports button-motion events when a button is pressed.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
+const (
+ ButtonEventMouseMode = DECMode(1002)
+
+ SetButtonEventMouseMode = "\x1b[?1002h"
+ ResetButtonEventMouseMode = "\x1b[?1002l"
+ RequestButtonEventMouseMode = "\x1b[?1002$p"
+)
+
+// Cell Motion Mouse Tracking is a mode that determines whether the mouse
+// reports on button press, release, and motion events.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
+//
+// Deprecated: use [ButtonEventMouseMode] instead.
+const (
+ MouseCellMotionMode = DECMode(1002)
+
+ EnableMouseCellMotion = "\x1b[?1002h"
+ DisableMouseCellMotion = "\x1b[?1002l"
+ RequestMouseCellMotion = "\x1b[?1002$p"
+)
+
+// Any Event Mouse Tracking is the same as [ButtonEventMouseMode], except that
+// all motion events are reported even if no mouse buttons are pressed.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
+const (
+ AnyEventMouseMode = DECMode(1003)
+
+ SetAnyEventMouseMode = "\x1b[?1003h"
+ ResetAnyEventMouseMode = "\x1b[?1003l"
+ RequestAnyEventMouseMode = "\x1b[?1003$p"
+)
+
+// All Mouse Tracking is a mode that determines whether the mouse reports on
+// button press, release, motion, and highlight events.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
+//
+// Deprecated: use [AnyEventMouseMode] instead.
+const (
+ MouseAllMotionMode = DECMode(1003)
+
+ EnableMouseAllMotion = "\x1b[?1003h"
+ DisableMouseAllMotion = "\x1b[?1003l"
+ RequestMouseAllMotion = "\x1b[?1003$p"
+)
+
+// Focus Event Mode is a mode that determines whether the terminal reports focus
+// and blur events.
+//
+// The terminal sends the following encoding:
+//
+// CSI I // Focus In
+// CSI O // Focus Out
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Focus-Tracking
+const (
+ FocusEventMode = DECMode(1004)
+
+ SetFocusEventMode = "\x1b[?1004h"
+ ResetFocusEventMode = "\x1b[?1004l"
+ RequestFocusEventMode = "\x1b[?1004$p"
+)
+
+// Deprecated: use [SetFocusEventMode], [ResetFocusEventMode], and
+// [RequestFocusEventMode] instead.
+const (
+ ReportFocusMode = DECMode(1004)
+
+ EnableReportFocus = "\x1b[?1004h"
+ DisableReportFocus = "\x1b[?1004l"
+ RequestReportFocus = "\x1b[?1004$p"
+)
+
+// SGR Extended Mouse Mode is a mode that changes the mouse tracking encoding
+// to use SGR parameters.
+//
+// The terminal responds with the following encoding:
+//
+// CSI < Cb ; Cx ; Cy M
+//
+// Where Cb is the same as [NormalMouseMode], and Cx and Cy are the x and y.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
+const (
+ SgrExtMouseMode = DECMode(1006)
+
+ SetSgrExtMouseMode = "\x1b[?1006h"
+ ResetSgrExtMouseMode = "\x1b[?1006l"
+ RequestSgrExtMouseMode = "\x1b[?1006$p"
+)
+
+// Deprecated: use [SgrExtMouseMode] [SetSgrExtMouseMode],
+// [ResetSgrExtMouseMode], and [RequestSgrExtMouseMode] instead.
+const (
+ MouseSgrExtMode = DECMode(1006)
+ EnableMouseSgrExt = "\x1b[?1006h"
+ DisableMouseSgrExt = "\x1b[?1006l"
+ RequestMouseSgrExt = "\x1b[?1006$p"
+)
+
+// UTF-8 Extended Mouse Mode is a mode that changes the mouse tracking encoding
+// to use UTF-8 parameters.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
+const (
+ Utf8ExtMouseMode = DECMode(1005)
+
+ SetUtf8ExtMouseMode = "\x1b[?1005h"
+ ResetUtf8ExtMouseMode = "\x1b[?1005l"
+ RequestUtf8ExtMouseMode = "\x1b[?1005$p"
+)
+
+// URXVT Extended Mouse Mode is a mode that changes the mouse tracking encoding
+// to use an alternate encoding.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
+const (
+ UrxvtExtMouseMode = DECMode(1015)
+
+ SetUrxvtExtMouseMode = "\x1b[?1015h"
+ ResetUrxvtExtMouseMode = "\x1b[?1015l"
+ RequestUrxvtExtMouseMode = "\x1b[?1015$p"
+)
+
+// SGR Pixel Extended Mouse Mode is a mode that changes the mouse tracking
+// encoding to use SGR parameters with pixel coordinates.
+//
+// This is similar to [SgrExtMouseMode], but also reports pixel coordinates.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
+const (
+ SgrPixelExtMouseMode = DECMode(1016)
+
+ SetSgrPixelExtMouseMode = "\x1b[?1016h"
+ ResetSgrPixelExtMouseMode = "\x1b[?1016l"
+ RequestSgrPixelExtMouseMode = "\x1b[?1016$p"
+)
+
+// Alternate Screen Mode is a mode that determines whether the alternate screen
+// buffer is active. When this mode is enabled, the alternate screen buffer is
+// cleared.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
+const (
+ AltScreenMode = DECMode(1047)
+
+ SetAltScreenMode = "\x1b[?1047h"
+ ResetAltScreenMode = "\x1b[?1047l"
+ RequestAltScreenMode = "\x1b[?1047$p"
+)
+
+// Save Cursor Mode is a mode that saves the cursor position.
+// This is equivalent to [SaveCursor] and [RestoreCursor].
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
+const (
+ SaveCursorMode = DECMode(1048)
+
+ SetSaveCursorMode = "\x1b[?1048h"
+ ResetSaveCursorMode = "\x1b[?1048l"
+ RequestSaveCursorMode = "\x1b[?1048$p"
+)
+
+// Alternate Screen Save Cursor Mode is a mode that saves the cursor position as in
+// [SaveCursorMode], switches to the alternate screen buffer as in [AltScreenMode],
+// and clears the screen on switch.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
+const (
+ AltScreenSaveCursorMode = DECMode(1049)
+
+ SetAltScreenSaveCursorMode = "\x1b[?1049h"
+ ResetAltScreenSaveCursorMode = "\x1b[?1049l"
+ RequestAltScreenSaveCursorMode = "\x1b[?1049$p"
+)
+
+// Alternate Screen Buffer is a mode that determines whether the alternate screen
+// buffer is active.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
+//
+// Deprecated: use [AltScreenSaveCursorMode] instead.
+const (
+ AltScreenBufferMode = DECMode(1049)
+
+ SetAltScreenBufferMode = "\x1b[?1049h"
+ ResetAltScreenBufferMode = "\x1b[?1049l"
+ RequestAltScreenBufferMode = "\x1b[?1049$p"
+
+ EnableAltScreenBuffer = "\x1b[?1049h"
+ DisableAltScreenBuffer = "\x1b[?1049l"
+ RequestAltScreenBuffer = "\x1b[?1049$p"
+)
+
+// Bracketed Paste Mode is a mode that determines whether pasted text is
+// bracketed with escape sequences.
+//
+// See: https://cirw.in/blog/bracketed-paste
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Bracketed-Paste-Mode
+const (
+ BracketedPasteMode = DECMode(2004)
+
+ SetBracketedPasteMode = "\x1b[?2004h"
+ ResetBracketedPasteMode = "\x1b[?2004l"
+ RequestBracketedPasteMode = "\x1b[?2004$p"
+)
+
+// Deprecated: use [SetBracketedPasteMode], [ResetBracketedPasteMode], and
+// [RequestBracketedPasteMode] instead.
+const (
+ EnableBracketedPaste = "\x1b[?2004h"
+ DisableBracketedPaste = "\x1b[?2004l"
+ RequestBracketedPaste = "\x1b[?2004$p"
+)
+
+// Synchronized Output Mode is a mode that determines whether output is
+// synchronized with the terminal.
+//
+// See: https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036
+const (
+ SynchronizedOutputMode = DECMode(2026)
+
+ SetSynchronizedOutputMode = "\x1b[?2026h"
+ ResetSynchronizedOutputMode = "\x1b[?2026l"
+ RequestSynchronizedOutputMode = "\x1b[?2026$p"
+)
+
+// Deprecated: use [SynchronizedOutputMode], [SetSynchronizedOutputMode], and
+// [ResetSynchronizedOutputMode], and [RequestSynchronizedOutputMode] instead.
+const (
+ SyncdOutputMode = DECMode(2026)
+
+ EnableSyncdOutput = "\x1b[?2026h"
+ DisableSyncdOutput = "\x1b[?2026l"
+ RequestSyncdOutput = "\x1b[?2026$p"
+)
+
+// Grapheme Clustering Mode is a mode that determines whether the terminal
+// should look for grapheme clusters instead of single runes in the rendered
+// text. This makes the terminal properly render combining characters such as
+// emojis.
+//
+// See: https://github.com/contour-terminal/terminal-unicode-core
+const (
+ GraphemeClusteringMode = DECMode(2027)
+
+ SetGraphemeClusteringMode = "\x1b[?2027h"
+ ResetGraphemeClusteringMode = "\x1b[?2027l"
+ RequestGraphemeClusteringMode = "\x1b[?2027$p"
+)
+
+// Deprecated: use [SetGraphemeClusteringMode], [ResetGraphemeClusteringMode], and
+// [RequestGraphemeClusteringMode] instead.
+const (
+ EnableGraphemeClustering = "\x1b[?2027h"
+ DisableGraphemeClustering = "\x1b[?2027l"
+ RequestGraphemeClustering = "\x1b[?2027$p"
+)
+
+// Win32Input is a mode that determines whether input is processed by the
+// Win32 console and Conpty.
+//
+// See: https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md
+const (
+ Win32InputMode = DECMode(9001)
+
+ SetWin32InputMode = "\x1b[?9001h"
+ ResetWin32InputMode = "\x1b[?9001l"
+ RequestWin32InputMode = "\x1b[?9001$p"
+)
+
+// Deprecated: use [SetWin32InputMode], [ResetWin32InputMode], and
+// [RequestWin32InputMode] instead.
+const (
+ EnableWin32Input = "\x1b[?9001h"
+ DisableWin32Input = "\x1b[?9001l"
+ RequestWin32Input = "\x1b[?9001$p"
+)
diff --git a/vendor/github.com/charmbracelet/x/ansi/modes.go b/vendor/github.com/charmbracelet/x/ansi/modes.go
new file mode 100644
index 00000000..1bec5bc8
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/modes.go
@@ -0,0 +1,71 @@
+package ansi
+
+// Modes represents the terminal modes that can be set or reset. By default,
+// all modes are [ModeNotRecognized].
+type Modes map[Mode]ModeSetting
+
+// NewModes creates a new Modes map. By default, all modes are
+// [ModeNotRecognized].
+func NewModes() Modes {
+ return make(Modes)
+}
+
+// Get returns the setting of a terminal mode. If the mode is not set, it
+// returns [ModeNotRecognized].
+func (m Modes) Get(mode Mode) ModeSetting {
+ return m[mode]
+}
+
+// Delete deletes a terminal mode. This has the same effect as setting the mode
+// to [ModeNotRecognized].
+func (m Modes) Delete(mode Mode) {
+ delete(m, mode)
+}
+
+// Set sets a terminal mode to [ModeSet].
+func (m Modes) Set(modes ...Mode) {
+ for _, mode := range modes {
+ m[mode] = ModeSet
+ }
+}
+
+// PermanentlySet sets a terminal mode to [ModePermanentlySet].
+func (m Modes) PermanentlySet(modes ...Mode) {
+ for _, mode := range modes {
+ m[mode] = ModePermanentlySet
+ }
+}
+
+// Reset sets a terminal mode to [ModeReset].
+func (m Modes) Reset(modes ...Mode) {
+ for _, mode := range modes {
+ m[mode] = ModeReset
+ }
+}
+
+// PermanentlyReset sets a terminal mode to [ModePermanentlyReset].
+func (m Modes) PermanentlyReset(modes ...Mode) {
+ for _, mode := range modes {
+ m[mode] = ModePermanentlyReset
+ }
+}
+
+// IsSet returns true if the mode is set to [ModeSet] or [ModePermanentlySet].
+func (m Modes) IsSet(mode Mode) bool {
+ return m[mode].IsSet()
+}
+
+// IsPermanentlySet returns true if the mode is set to [ModePermanentlySet].
+func (m Modes) IsPermanentlySet(mode Mode) bool {
+ return m[mode].IsPermanentlySet()
+}
+
+// IsReset returns true if the mode is set to [ModeReset] or [ModePermanentlyReset].
+func (m Modes) IsReset(mode Mode) bool {
+ return m[mode].IsReset()
+}
+
+// IsPermanentlyReset returns true if the mode is set to [ModePermanentlyReset].
+func (m Modes) IsPermanentlyReset(mode Mode) bool {
+ return m[mode].IsPermanentlyReset()
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/mouse.go b/vendor/github.com/charmbracelet/x/ansi/mouse.go
new file mode 100644
index 00000000..95b0127f
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/mouse.go
@@ -0,0 +1,172 @@
+package ansi
+
+import (
+ "fmt"
+)
+
+// MouseButton represents the button that was pressed during a mouse message.
+type MouseButton byte
+
+// Mouse event buttons
+//
+// This is based on X11 mouse button codes.
+//
+// 1 = left button
+// 2 = middle button (pressing the scroll wheel)
+// 3 = right button
+// 4 = turn scroll wheel up
+// 5 = turn scroll wheel down
+// 6 = push scroll wheel left
+// 7 = push scroll wheel right
+// 8 = 4th button (aka browser backward button)
+// 9 = 5th button (aka browser forward button)
+// 10
+// 11
+//
+// Other buttons are not supported.
+const (
+ MouseNone MouseButton = iota
+ MouseButton1
+ MouseButton2
+ MouseButton3
+ MouseButton4
+ MouseButton5
+ MouseButton6
+ MouseButton7
+ MouseButton8
+ MouseButton9
+ MouseButton10
+ MouseButton11
+
+ MouseLeft = MouseButton1
+ MouseMiddle = MouseButton2
+ MouseRight = MouseButton3
+ MouseWheelUp = MouseButton4
+ MouseWheelDown = MouseButton5
+ MouseWheelLeft = MouseButton6
+ MouseWheelRight = MouseButton7
+ MouseBackward = MouseButton8
+ MouseForward = MouseButton9
+ MouseRelease = MouseNone
+)
+
+var mouseButtons = map[MouseButton]string{
+ MouseNone: "none",
+ MouseLeft: "left",
+ MouseMiddle: "middle",
+ MouseRight: "right",
+ MouseWheelUp: "wheelup",
+ MouseWheelDown: "wheeldown",
+ MouseWheelLeft: "wheelleft",
+ MouseWheelRight: "wheelright",
+ MouseBackward: "backward",
+ MouseForward: "forward",
+ MouseButton10: "button10",
+ MouseButton11: "button11",
+}
+
+// String returns a string representation of the mouse button.
+func (b MouseButton) String() string {
+ return mouseButtons[b]
+}
+
+// EncodeMouseButton returns a byte representing a mouse button.
+// The button is a bitmask of the following leftmost values:
+//
+// - The first two bits are the button number:
+// 0 = left button, wheel up, or button no. 8 aka (backwards)
+// 1 = middle button, wheel down, or button no. 9 aka (forwards)
+// 2 = right button, wheel left, or button no. 10
+// 3 = release event, wheel right, or button no. 11
+//
+// - The third bit indicates whether the shift key was pressed.
+//
+// - The fourth bit indicates the alt key was pressed.
+//
+// - The fifth bit indicates the control key was pressed.
+//
+// - The sixth bit indicates motion events. Combined with button number 3, i.e.
+// release event, it represents a drag event.
+//
+// - The seventh bit indicates a wheel event.
+//
+// - The eighth bit indicates additional buttons.
+//
+// If button is [MouseNone], and motion is false, this returns a release event.
+// If button is undefined, this function returns 0xff.
+func EncodeMouseButton(b MouseButton, motion, shift, alt, ctrl bool) (m byte) {
+ // mouse bit shifts
+ const (
+ bitShift = 0b0000_0100
+ bitAlt = 0b0000_1000
+ bitCtrl = 0b0001_0000
+ bitMotion = 0b0010_0000
+ bitWheel = 0b0100_0000
+ bitAdd = 0b1000_0000 // additional buttons 8-11
+
+ bitsMask = 0b0000_0011
+ )
+
+ if b == MouseNone {
+ m = bitsMask
+ } else if b >= MouseLeft && b <= MouseRight {
+ m = byte(b - MouseLeft)
+ } else if b >= MouseWheelUp && b <= MouseWheelRight {
+ m = byte(b - MouseWheelUp)
+ m |= bitWheel
+ } else if b >= MouseBackward && b <= MouseButton11 {
+ m = byte(b - MouseBackward)
+ m |= bitAdd
+ } else {
+ m = 0xff // invalid button
+ }
+
+ if shift {
+ m |= bitShift
+ }
+ if alt {
+ m |= bitAlt
+ }
+ if ctrl {
+ m |= bitCtrl
+ }
+ if motion {
+ m |= bitMotion
+ }
+
+ return
+}
+
+// x10Offset is the offset for X10 mouse events.
+// See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
+const x10Offset = 32
+
+// MouseX10 returns an escape sequence representing a mouse event in X10 mode.
+// Note that this requires the terminal support X10 mouse modes.
+//
+// CSI M Cb Cx Cy
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
+func MouseX10(b byte, x, y int) string {
+ return "\x1b[M" + string(b+x10Offset) + string(byte(x)+x10Offset+1) + string(byte(y)+x10Offset+1)
+}
+
+// MouseSgr returns an escape sequence representing a mouse event in SGR mode.
+//
+// CSI < Cb ; Cx ; Cy M
+// CSI < Cb ; Cx ; Cy m (release)
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
+func MouseSgr(b byte, x, y int, release bool) string {
+ s := 'M'
+ if release {
+ s = 'm'
+ }
+ if x < 0 {
+ x = -x
+ }
+ if y < 0 {
+ y = -y
+ }
+ return fmt.Sprintf("\x1b[<%d;%d;%d%c", b, x+1, y+1, s)
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/notification.go b/vendor/github.com/charmbracelet/x/ansi/notification.go
new file mode 100644
index 00000000..c712f340
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/notification.go
@@ -0,0 +1,13 @@
+package ansi
+
+// Notify sends a desktop notification using iTerm's OSC 9.
+//
+// OSC 9 ; Mc ST
+// OSC 9 ; Mc BEL
+//
+// Where Mc is the notification body.
+//
+// See: https://iterm2.com/documentation-escape-codes.html
+func Notify(s string) string {
+ return "\x1b]9;" + s + "\x07"
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/parser.go b/vendor/github.com/charmbracelet/x/ansi/parser.go
new file mode 100644
index 00000000..882e1ed7
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/parser.go
@@ -0,0 +1,417 @@
+package ansi
+
+import (
+ "unicode/utf8"
+ "unsafe"
+
+ "github.com/charmbracelet/x/ansi/parser"
+)
+
+// Parser represents a DEC ANSI compatible sequence parser.
+//
+// It uses a state machine to parse ANSI escape sequences and control
+// characters. The parser is designed to be used with a terminal emulator or
+// similar application that needs to parse ANSI escape sequences and control
+// characters.
+// See package [parser] for more information.
+//
+//go:generate go run ./gen.go
+type Parser struct {
+ handler Handler
+
+ // params contains the raw parameters of the sequence.
+ // These parameters used when constructing CSI and DCS sequences.
+ params []int
+
+ // data contains the raw data of the sequence.
+ // These data used when constructing OSC, DCS, SOS, PM, and APC sequences.
+ data []byte
+
+ // dataLen keeps track of the length of the data buffer.
+ // If dataLen is -1, the data buffer is unlimited and will grow as needed.
+ // Otherwise, dataLen is limited by the size of the data buffer.
+ dataLen int
+
+ // paramsLen keeps track of the number of parameters.
+ // This is limited by the size of the params buffer.
+ //
+ // This is also used when collecting UTF-8 runes to keep track of the
+ // number of rune bytes collected.
+ paramsLen int
+
+ // cmd contains the raw command along with the private prefix and
+ // intermediate bytes of the sequence.
+ // The first lower byte contains the command byte, the next byte contains
+ // the private prefix, and the next byte contains the intermediate byte.
+ //
+ // This is also used when collecting UTF-8 runes treating it as a slice of
+ // 4 bytes.
+ cmd int
+
+ // state is the current state of the parser.
+ state byte
+}
+
+// NewParser returns a new parser with the default settings.
+// The [Parser] uses a default size of 32 for the parameters and 64KB for the
+// data buffer. Use [Parser.SetParamsSize] and [Parser.SetDataSize] to set the
+// size of the parameters and data buffer respectively.
+func NewParser() *Parser {
+ p := new(Parser)
+ p.SetParamsSize(parser.MaxParamsSize)
+ p.SetDataSize(1024 * 64) // 64KB data buffer
+ return p
+}
+
+// SetParamsSize sets the size of the parameters buffer.
+// This is used when constructing CSI and DCS sequences.
+func (p *Parser) SetParamsSize(size int) {
+ p.params = make([]int, size)
+}
+
+// SetDataSize sets the size of the data buffer.
+// This is used when constructing OSC, DCS, SOS, PM, and APC sequences.
+// If size is less than or equal to 0, the data buffer is unlimited and will
+// grow as needed.
+func (p *Parser) SetDataSize(size int) {
+ if size <= 0 {
+ size = 0
+ p.dataLen = -1
+ }
+ p.data = make([]byte, size)
+}
+
+// Params returns the list of parsed packed parameters.
+func (p *Parser) Params() Params {
+ return unsafe.Slice((*Param)(unsafe.Pointer(&p.params[0])), p.paramsLen)
+}
+
+// Param returns the parameter at the given index and falls back to the default
+// value if the parameter is missing. If the index is out of bounds, it returns
+// the default value and false.
+func (p *Parser) Param(i, def int) (int, bool) {
+ if i < 0 || i >= p.paramsLen {
+ return def, false
+ }
+ return Param(p.params[i]).Param(def), true
+}
+
+// Command returns the packed command of the last dispatched sequence. Use
+// [Cmd] to unpack the command.
+func (p *Parser) Command() int {
+ return p.cmd
+}
+
+// Rune returns the last dispatched sequence as a rune.
+func (p *Parser) Rune() rune {
+ rw := utf8ByteLen(byte(p.cmd & 0xff))
+ if rw == -1 {
+ return utf8.RuneError
+ }
+ r, _ := utf8.DecodeRune((*[utf8.UTFMax]byte)(unsafe.Pointer(&p.cmd))[:rw])
+ return r
+}
+
+// Control returns the last dispatched sequence as a control code.
+func (p *Parser) Control() byte {
+ return byte(p.cmd & 0xff)
+}
+
+// Data returns the raw data of the last dispatched sequence.
+func (p *Parser) Data() []byte {
+ return p.data[:p.dataLen]
+}
+
+// Reset resets the parser to its initial state.
+func (p *Parser) Reset() {
+ p.clear()
+ p.state = parser.GroundState
+}
+
+// clear clears the parser parameters and command.
+func (p *Parser) clear() {
+ if len(p.params) > 0 {
+ p.params[0] = parser.MissingParam
+ }
+ p.paramsLen = 0
+ p.cmd = 0
+}
+
+// State returns the current state of the parser.
+func (p *Parser) State() parser.State {
+ return p.state
+}
+
+// StateName returns the name of the current state.
+func (p *Parser) StateName() string {
+ return parser.StateNames[p.state]
+}
+
+// Parse parses the given dispatcher and byte buffer.
+// Deprecated: Loop over the buffer and call [Parser.Advance] instead.
+func (p *Parser) Parse(b []byte) {
+ for i := 0; i < len(b); i++ {
+ p.Advance(b[i])
+ }
+}
+
+// Advance advances the parser using the given byte. It returns the action
+// performed by the parser.
+func (p *Parser) Advance(b byte) parser.Action {
+ switch p.state {
+ case parser.Utf8State:
+ // We handle UTF-8 here.
+ return p.advanceUtf8(b)
+ default:
+ return p.advance(b)
+ }
+}
+
+func (p *Parser) collectRune(b byte) {
+ if p.paramsLen >= utf8.UTFMax {
+ return
+ }
+
+ shift := p.paramsLen * 8
+ p.cmd &^= 0xff << shift
+ p.cmd |= int(b) << shift
+ p.paramsLen++
+}
+
+func (p *Parser) advanceUtf8(b byte) parser.Action {
+ // Collect UTF-8 rune bytes.
+ p.collectRune(b)
+ rw := utf8ByteLen(byte(p.cmd & 0xff))
+ if rw == -1 {
+ // We panic here because the first byte comes from the state machine,
+ // if this panics, it means there is a bug in the state machine!
+ panic("invalid rune") // unreachable
+ }
+
+ if p.paramsLen < rw {
+ return parser.CollectAction
+ }
+
+ // We have enough bytes to decode the rune using unsafe
+ if p.handler.Print != nil {
+ p.handler.Print(p.Rune())
+ }
+
+ p.state = parser.GroundState
+ p.paramsLen = 0
+
+ return parser.PrintAction
+}
+
+func (p *Parser) advance(b byte) parser.Action {
+ state, action := parser.Table.Transition(p.state, b)
+
+ // We need to clear the parser state if the state changes from EscapeState.
+ // This is because when we enter the EscapeState, we don't get a chance to
+ // clear the parser state. For example, when a sequence terminates with a
+ // ST (\x1b\\ or \x9c), we dispatch the current sequence and transition to
+ // EscapeState. However, the parser state is not cleared in this case and
+ // we need to clear it here before dispatching the esc sequence.
+ if p.state != state {
+ if p.state == parser.EscapeState {
+ p.performAction(parser.ClearAction, state, b)
+ }
+ if action == parser.PutAction &&
+ p.state == parser.DcsEntryState && state == parser.DcsStringState {
+ // XXX: This is a special case where we need to start collecting
+ // non-string parameterized data i.e. doesn't follow the ECMA-48 §
+ // 5.4.1 string parameters format.
+ p.performAction(parser.StartAction, state, 0)
+ }
+ }
+
+ // Handle special cases
+ switch {
+ case b == ESC && p.state == parser.EscapeState:
+ // Two ESCs in a row
+ p.performAction(parser.ExecuteAction, state, b)
+ default:
+ p.performAction(action, state, b)
+ }
+
+ p.state = state
+
+ return action
+}
+
+func (p *Parser) parseStringCmd() {
+ // Try to parse the command
+ datalen := len(p.data)
+ if p.dataLen >= 0 {
+ datalen = p.dataLen
+ }
+ for i := 0; i < datalen; i++ {
+ d := p.data[i]
+ if d < '0' || d > '9' {
+ break
+ }
+ if p.cmd == parser.MissingCommand {
+ p.cmd = 0
+ }
+ p.cmd *= 10
+ p.cmd += int(d - '0')
+ }
+}
+
+func (p *Parser) performAction(action parser.Action, state parser.State, b byte) {
+ switch action {
+ case parser.IgnoreAction:
+ break
+
+ case parser.ClearAction:
+ p.clear()
+
+ case parser.PrintAction:
+ p.cmd = int(b)
+ if p.handler.Print != nil {
+ p.handler.Print(rune(b))
+ }
+
+ case parser.ExecuteAction:
+ p.cmd = int(b)
+ if p.handler.Execute != nil {
+ p.handler.Execute(b)
+ }
+
+ case parser.PrefixAction:
+ // Collect private prefix
+ // we only store the last prefix
+ p.cmd &^= 0xff << parser.PrefixShift
+ p.cmd |= int(b) << parser.PrefixShift
+
+ case parser.CollectAction:
+ if state == parser.Utf8State {
+ // Reset the UTF-8 counter
+ p.paramsLen = 0
+ p.collectRune(b)
+ } else {
+ // Collect intermediate bytes
+ // we only store the last intermediate byte
+ p.cmd &^= 0xff << parser.IntermedShift
+ p.cmd |= int(b) << parser.IntermedShift
+ }
+
+ case parser.ParamAction:
+ // Collect parameters
+ if p.paramsLen >= len(p.params) {
+ break
+ }
+
+ if b >= '0' && b <= '9' {
+ if p.params[p.paramsLen] == parser.MissingParam {
+ p.params[p.paramsLen] = 0
+ }
+
+ p.params[p.paramsLen] *= 10
+ p.params[p.paramsLen] += int(b - '0')
+ }
+
+ if b == ':' {
+ p.params[p.paramsLen] |= parser.HasMoreFlag
+ }
+
+ if b == ';' || b == ':' {
+ p.paramsLen++
+ if p.paramsLen < len(p.params) {
+ p.params[p.paramsLen] = parser.MissingParam
+ }
+ }
+
+ case parser.StartAction:
+ if p.dataLen < 0 && p.data != nil {
+ p.data = p.data[:0]
+ } else {
+ p.dataLen = 0
+ }
+ if p.state >= parser.DcsEntryState && p.state <= parser.DcsStringState {
+ // Collect the command byte for DCS
+ p.cmd |= int(b)
+ } else {
+ p.cmd = parser.MissingCommand
+ }
+
+ case parser.PutAction:
+ switch p.state {
+ case parser.OscStringState:
+ if b == ';' && p.cmd == parser.MissingCommand {
+ p.parseStringCmd()
+ }
+ }
+
+ if p.dataLen < 0 {
+ p.data = append(p.data, b)
+ } else {
+ if p.dataLen < len(p.data) {
+ p.data[p.dataLen] = b
+ p.dataLen++
+ }
+ }
+
+ case parser.DispatchAction:
+ // Increment the last parameter
+ if p.paramsLen > 0 && p.paramsLen < len(p.params)-1 ||
+ p.paramsLen == 0 && len(p.params) > 0 && p.params[0] != parser.MissingParam {
+ p.paramsLen++
+ }
+
+ if p.state == parser.OscStringState && p.cmd == parser.MissingCommand {
+ // Ensure we have a command for OSC
+ p.parseStringCmd()
+ }
+
+ data := p.data
+ if p.dataLen >= 0 {
+ data = data[:p.dataLen]
+ }
+ switch p.state {
+ case parser.CsiEntryState, parser.CsiParamState, parser.CsiIntermediateState:
+ p.cmd |= int(b)
+ if p.handler.HandleCsi != nil {
+ p.handler.HandleCsi(Cmd(p.cmd), p.Params())
+ }
+ case parser.EscapeState, parser.EscapeIntermediateState:
+ p.cmd |= int(b)
+ if p.handler.HandleEsc != nil {
+ p.handler.HandleEsc(Cmd(p.cmd))
+ }
+ case parser.DcsEntryState, parser.DcsParamState, parser.DcsIntermediateState, parser.DcsStringState:
+ if p.handler.HandleDcs != nil {
+ p.handler.HandleDcs(Cmd(p.cmd), p.Params(), data)
+ }
+ case parser.OscStringState:
+ if p.handler.HandleOsc != nil {
+ p.handler.HandleOsc(p.cmd, data)
+ }
+ case parser.SosStringState:
+ if p.handler.HandleSos != nil {
+ p.handler.HandleSos(data)
+ }
+ case parser.PmStringState:
+ if p.handler.HandlePm != nil {
+ p.handler.HandlePm(data)
+ }
+ case parser.ApcStringState:
+ if p.handler.HandleApc != nil {
+ p.handler.HandleApc(data)
+ }
+ }
+ }
+}
+
+func utf8ByteLen(b byte) int {
+ if b <= 0b0111_1111 { // 0x00-0x7F
+ return 1
+ } else if b >= 0b1100_0000 && b <= 0b1101_1111 { // 0xC0-0xDF
+ return 2
+ } else if b >= 0b1110_0000 && b <= 0b1110_1111 { // 0xE0-0xEF
+ return 3
+ } else if b >= 0b1111_0000 && b <= 0b1111_0111 { // 0xF0-0xF7
+ return 4
+ }
+ return -1
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/parser/BUILD.bazel b/vendor/github.com/charmbracelet/x/ansi/parser/BUILD.bazel
new file mode 100644
index 00000000..cd7c53d9
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/parser/BUILD.bazel
@@ -0,0 +1,13 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "const.go",
+ "seq.go",
+ "transition_table.go",
+ ],
+ importmap = "github.com/kindlyops/vbs/vendor/github.com/charmbracelet/x/ansi/parser",
+ importpath = "github.com/charmbracelet/x/ansi/parser",
+ visibility = ["//visibility:public"],
+)
diff --git a/vendor/github.com/charmbracelet/x/ansi/parser/const.go b/vendor/github.com/charmbracelet/x/ansi/parser/const.go
new file mode 100644
index 00000000..d62dbf37
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/parser/const.go
@@ -0,0 +1,78 @@
+package parser
+
+// Action is a DEC ANSI parser action.
+type Action = byte
+
+// These are the actions that the parser can take.
+const (
+ NoneAction Action = iota
+ ClearAction
+ CollectAction
+ PrefixAction
+ DispatchAction
+ ExecuteAction
+ StartAction // Start of a data string
+ PutAction // Put into the data string
+ ParamAction
+ PrintAction
+
+ IgnoreAction = NoneAction
+)
+
+// nolint: unused
+var ActionNames = []string{
+ "NoneAction",
+ "ClearAction",
+ "CollectAction",
+ "PrefixAction",
+ "DispatchAction",
+ "ExecuteAction",
+ "StartAction",
+ "PutAction",
+ "ParamAction",
+ "PrintAction",
+}
+
+// State is a DEC ANSI parser state.
+type State = byte
+
+// These are the states that the parser can be in.
+const (
+ GroundState State = iota
+ CsiEntryState
+ CsiIntermediateState
+ CsiParamState
+ DcsEntryState
+ DcsIntermediateState
+ DcsParamState
+ DcsStringState
+ EscapeState
+ EscapeIntermediateState
+ OscStringState
+ SosStringState
+ PmStringState
+ ApcStringState
+
+ // Utf8State is not part of the DEC ANSI standard. It is used to handle
+ // UTF-8 sequences.
+ Utf8State
+)
+
+// nolint: unused
+var StateNames = []string{
+ "GroundState",
+ "CsiEntryState",
+ "CsiIntermediateState",
+ "CsiParamState",
+ "DcsEntryState",
+ "DcsIntermediateState",
+ "DcsParamState",
+ "DcsStringState",
+ "EscapeState",
+ "EscapeIntermediateState",
+ "OscStringState",
+ "SosStringState",
+ "PmStringState",
+ "ApcStringState",
+ "Utf8State",
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/parser/seq.go b/vendor/github.com/charmbracelet/x/ansi/parser/seq.go
new file mode 100644
index 00000000..29f491d1
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/parser/seq.go
@@ -0,0 +1,136 @@
+package parser
+
+import "math"
+
+// Shift and masks for sequence parameters and intermediates.
+const (
+ PrefixShift = 8
+ IntermedShift = 16
+ FinalMask = 0xff
+ HasMoreFlag = math.MinInt32
+ ParamMask = ^HasMoreFlag
+ MissingParam = ParamMask
+ MissingCommand = MissingParam
+ MaxParam = math.MaxUint16 // the maximum value a parameter can have
+)
+
+const (
+ // MaxParamsSize is the maximum number of parameters a sequence can have.
+ MaxParamsSize = 32
+
+ // DefaultParamValue is the default value used for missing parameters.
+ DefaultParamValue = 0
+)
+
+// Prefix returns the prefix byte of the sequence.
+// This is always gonna be one of the following '<' '=' '>' '?' and in the
+// range of 0x3C-0x3F.
+// Zero is returned if the sequence does not have a prefix.
+func Prefix(cmd int) int {
+ return (cmd >> PrefixShift) & FinalMask
+}
+
+// Intermediate returns the intermediate byte of the sequence.
+// An intermediate byte is in the range of 0x20-0x2F. This includes these
+// characters from ' ', '!', '"', '#', '$', '%', '&', ”', '(', ')', '*', '+',
+// ',', '-', '.', '/'.
+// Zero is returned if the sequence does not have an intermediate byte.
+func Intermediate(cmd int) int {
+ return (cmd >> IntermedShift) & FinalMask
+}
+
+// Command returns the command byte of the CSI sequence.
+func Command(cmd int) int {
+ return cmd & FinalMask
+}
+
+// Param returns the parameter at the given index.
+// It returns -1 if the parameter does not exist.
+func Param(params []int, i int) int {
+ if len(params) == 0 || i < 0 || i >= len(params) {
+ return -1
+ }
+
+ p := params[i] & ParamMask
+ if p == MissingParam {
+ return -1
+ }
+
+ return p
+}
+
+// HasMore returns true if the parameter has more sub-parameters.
+func HasMore(params []int, i int) bool {
+ if len(params) == 0 || i >= len(params) {
+ return false
+ }
+
+ return params[i]&HasMoreFlag != 0
+}
+
+// Subparams returns the sub-parameters of the given parameter.
+// It returns nil if the parameter does not exist.
+func Subparams(params []int, i int) []int {
+ if len(params) == 0 || i < 0 || i >= len(params) {
+ return nil
+ }
+
+ // Count the number of parameters before the given parameter index.
+ var count int
+ var j int
+ for j = 0; j < len(params); j++ {
+ if count == i {
+ break
+ }
+ if !HasMore(params, j) {
+ count++
+ }
+ }
+
+ if count > i || j >= len(params) {
+ return nil
+ }
+
+ var subs []int
+ for ; j < len(params); j++ {
+ if !HasMore(params, j) {
+ break
+ }
+ p := Param(params, j)
+ if p == -1 {
+ p = DefaultParamValue
+ }
+ subs = append(subs, p)
+ }
+
+ p := Param(params, j)
+ if p == -1 {
+ p = DefaultParamValue
+ }
+
+ return append(subs, p)
+}
+
+// Len returns the number of parameters in the sequence.
+// This will return the number of parameters in the sequence, excluding any
+// sub-parameters.
+func Len(params []int) int {
+ var n int
+ for i := 0; i < len(params); i++ {
+ if !HasMore(params, i) {
+ n++
+ }
+ }
+ return n
+}
+
+// Range iterates over the parameters of the sequence and calls the given
+// function for each parameter.
+// The function should return false to stop the iteration.
+func Range(params []int, fn func(i int, param int, hasMore bool) bool) {
+ for i := 0; i < len(params); i++ {
+ if !fn(i, Param(params, i), HasMore(params, i)) {
+ break
+ }
+ }
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/parser/transition_table.go b/vendor/github.com/charmbracelet/x/ansi/parser/transition_table.go
new file mode 100644
index 00000000..558a5eac
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/parser/transition_table.go
@@ -0,0 +1,273 @@
+package parser
+
+// Table values are generated like this:
+//
+// index: currentState << IndexStateShift | charCode
+// value: action << TransitionActionShift | nextState
+const (
+ TransitionActionShift = 4
+ TransitionStateMask = 15
+ IndexStateShift = 8
+
+ // DefaultTableSize is the default size of the transition table.
+ DefaultTableSize = 4096
+)
+
+// Table is a DEC ANSI transition table.
+var Table = GenerateTransitionTable()
+
+// TransitionTable is a DEC ANSI transition table.
+// https://vt100.net/emu/dec_ansi_parser
+type TransitionTable []byte
+
+// NewTransitionTable returns a new DEC ANSI transition table.
+func NewTransitionTable(size int) TransitionTable {
+ if size <= 0 {
+ size = DefaultTableSize
+ }
+ return TransitionTable(make([]byte, size))
+}
+
+// SetDefault sets default transition.
+func (t TransitionTable) SetDefault(action Action, state State) {
+ for i := 0; i < len(t); i++ {
+ t[i] = action<> TransitionActionShift
+}
+
+// byte range macro
+func r(start, end byte) []byte {
+ var a []byte
+ for i := int(start); i <= int(end); i++ {
+ a = append(a, byte(i))
+ }
+ return a
+}
+
+// GenerateTransitionTable generates a DEC ANSI transition table compatible
+// with the VT500-series of terminals. This implementation includes a few
+// modifications that include:
+// - A new Utf8State is introduced to handle UTF8 sequences.
+// - Osc and Dcs data accept UTF8 sequences by extending the printable range
+// to 0xFF and 0xFE respectively.
+// - We don't ignore 0x3A (':') when building Csi and Dcs parameters and
+// instead use it to denote sub-parameters.
+// - Support dispatching SosPmApc sequences.
+// - The DEL (0x7F) character is executed in the Ground state.
+// - The DEL (0x7F) character is collected in the DcsPassthrough string state.
+// - The ST C1 control character (0x9C) is executed and not ignored.
+func GenerateTransitionTable() TransitionTable {
+ table := NewTransitionTable(DefaultTableSize)
+ table.SetDefault(NoneAction, GroundState)
+
+ // Anywhere
+ for _, state := range r(GroundState, Utf8State) {
+ // Anywhere -> Ground
+ table.AddMany([]byte{0x18, 0x1a, 0x99, 0x9a}, state, ExecuteAction, GroundState)
+ table.AddRange(0x80, 0x8F, state, ExecuteAction, GroundState)
+ table.AddRange(0x90, 0x97, state, ExecuteAction, GroundState)
+ table.AddOne(0x9C, state, ExecuteAction, GroundState)
+ // Anywhere -> Escape
+ table.AddOne(0x1B, state, ClearAction, EscapeState)
+ // Anywhere -> SosStringState
+ table.AddOne(0x98, state, StartAction, SosStringState)
+ // Anywhere -> PmStringState
+ table.AddOne(0x9E, state, StartAction, PmStringState)
+ // Anywhere -> ApcStringState
+ table.AddOne(0x9F, state, StartAction, ApcStringState)
+ // Anywhere -> CsiEntry
+ table.AddOne(0x9B, state, ClearAction, CsiEntryState)
+ // Anywhere -> DcsEntry
+ table.AddOne(0x90, state, ClearAction, DcsEntryState)
+ // Anywhere -> OscString
+ table.AddOne(0x9D, state, StartAction, OscStringState)
+ // Anywhere -> Utf8
+ table.AddRange(0xC2, 0xDF, state, CollectAction, Utf8State) // UTF8 2 byte sequence
+ table.AddRange(0xE0, 0xEF, state, CollectAction, Utf8State) // UTF8 3 byte sequence
+ table.AddRange(0xF0, 0xF4, state, CollectAction, Utf8State) // UTF8 4 byte sequence
+ }
+
+ // Ground
+ table.AddRange(0x00, 0x17, GroundState, ExecuteAction, GroundState)
+ table.AddOne(0x19, GroundState, ExecuteAction, GroundState)
+ table.AddRange(0x1C, 0x1F, GroundState, ExecuteAction, GroundState)
+ table.AddRange(0x20, 0x7E, GroundState, PrintAction, GroundState)
+ table.AddOne(0x7F, GroundState, ExecuteAction, GroundState)
+
+ // EscapeIntermediate
+ table.AddRange(0x00, 0x17, EscapeIntermediateState, ExecuteAction, EscapeIntermediateState)
+ table.AddOne(0x19, EscapeIntermediateState, ExecuteAction, EscapeIntermediateState)
+ table.AddRange(0x1C, 0x1F, EscapeIntermediateState, ExecuteAction, EscapeIntermediateState)
+ table.AddRange(0x20, 0x2F, EscapeIntermediateState, CollectAction, EscapeIntermediateState)
+ table.AddOne(0x7F, EscapeIntermediateState, IgnoreAction, EscapeIntermediateState)
+ // EscapeIntermediate -> Ground
+ table.AddRange(0x30, 0x7E, EscapeIntermediateState, DispatchAction, GroundState)
+
+ // Escape
+ table.AddRange(0x00, 0x17, EscapeState, ExecuteAction, EscapeState)
+ table.AddOne(0x19, EscapeState, ExecuteAction, EscapeState)
+ table.AddRange(0x1C, 0x1F, EscapeState, ExecuteAction, EscapeState)
+ table.AddOne(0x7F, EscapeState, IgnoreAction, EscapeState)
+ // Escape -> Ground
+ table.AddRange(0x30, 0x4F, EscapeState, DispatchAction, GroundState)
+ table.AddRange(0x51, 0x57, EscapeState, DispatchAction, GroundState)
+ table.AddOne(0x59, EscapeState, DispatchAction, GroundState)
+ table.AddOne(0x5A, EscapeState, DispatchAction, GroundState)
+ table.AddOne(0x5C, EscapeState, DispatchAction, GroundState)
+ table.AddRange(0x60, 0x7E, EscapeState, DispatchAction, GroundState)
+ // Escape -> Escape_intermediate
+ table.AddRange(0x20, 0x2F, EscapeState, CollectAction, EscapeIntermediateState)
+ // Escape -> Sos_pm_apc_string
+ table.AddOne('X', EscapeState, StartAction, SosStringState) // SOS
+ table.AddOne('^', EscapeState, StartAction, PmStringState) // PM
+ table.AddOne('_', EscapeState, StartAction, ApcStringState) // APC
+ // Escape -> Dcs_entry
+ table.AddOne('P', EscapeState, ClearAction, DcsEntryState)
+ // Escape -> Csi_entry
+ table.AddOne('[', EscapeState, ClearAction, CsiEntryState)
+ // Escape -> Osc_string
+ table.AddOne(']', EscapeState, StartAction, OscStringState)
+
+ // Sos_pm_apc_string
+ for _, state := range r(SosStringState, ApcStringState) {
+ table.AddRange(0x00, 0x17, state, PutAction, state)
+ table.AddOne(0x19, state, PutAction, state)
+ table.AddRange(0x1C, 0x1F, state, PutAction, state)
+ table.AddRange(0x20, 0x7F, state, PutAction, state)
+ // ESC, ST, CAN, and SUB terminate the sequence
+ table.AddOne(0x1B, state, DispatchAction, EscapeState)
+ table.AddOne(0x9C, state, DispatchAction, GroundState)
+ table.AddMany([]byte{0x18, 0x1A}, state, IgnoreAction, GroundState)
+ }
+
+ // Dcs_entry
+ table.AddRange(0x00, 0x07, DcsEntryState, IgnoreAction, DcsEntryState)
+ table.AddRange(0x0E, 0x17, DcsEntryState, IgnoreAction, DcsEntryState)
+ table.AddOne(0x19, DcsEntryState, IgnoreAction, DcsEntryState)
+ table.AddRange(0x1C, 0x1F, DcsEntryState, IgnoreAction, DcsEntryState)
+ table.AddOne(0x7F, DcsEntryState, IgnoreAction, DcsEntryState)
+ // Dcs_entry -> Dcs_intermediate
+ table.AddRange(0x20, 0x2F, DcsEntryState, CollectAction, DcsIntermediateState)
+ // Dcs_entry -> Dcs_param
+ table.AddRange(0x30, 0x3B, DcsEntryState, ParamAction, DcsParamState)
+ table.AddRange(0x3C, 0x3F, DcsEntryState, PrefixAction, DcsParamState)
+ // Dcs_entry -> Dcs_passthrough
+ table.AddRange(0x08, 0x0D, DcsEntryState, PutAction, DcsStringState) // Follows ECMA-48 § 8.3.27
+ // XXX: allows passing ESC (not a ECMA-48 standard) this to allow for
+ // passthrough of ANSI sequences like in Screen or Tmux passthrough mode.
+ table.AddOne(0x1B, DcsEntryState, PutAction, DcsStringState)
+ table.AddRange(0x40, 0x7E, DcsEntryState, StartAction, DcsStringState)
+
+ // Dcs_intermediate
+ table.AddRange(0x00, 0x17, DcsIntermediateState, IgnoreAction, DcsIntermediateState)
+ table.AddOne(0x19, DcsIntermediateState, IgnoreAction, DcsIntermediateState)
+ table.AddRange(0x1C, 0x1F, DcsIntermediateState, IgnoreAction, DcsIntermediateState)
+ table.AddRange(0x20, 0x2F, DcsIntermediateState, CollectAction, DcsIntermediateState)
+ table.AddOne(0x7F, DcsIntermediateState, IgnoreAction, DcsIntermediateState)
+ // Dcs_intermediate -> Dcs_passthrough
+ table.AddRange(0x30, 0x3F, DcsIntermediateState, StartAction, DcsStringState)
+ table.AddRange(0x40, 0x7E, DcsIntermediateState, StartAction, DcsStringState)
+
+ // Dcs_param
+ table.AddRange(0x00, 0x17, DcsParamState, IgnoreAction, DcsParamState)
+ table.AddOne(0x19, DcsParamState, IgnoreAction, DcsParamState)
+ table.AddRange(0x1C, 0x1F, DcsParamState, IgnoreAction, DcsParamState)
+ table.AddRange(0x30, 0x3B, DcsParamState, ParamAction, DcsParamState)
+ table.AddOne(0x7F, DcsParamState, IgnoreAction, DcsParamState)
+ table.AddRange(0x3C, 0x3F, DcsParamState, IgnoreAction, DcsParamState)
+ // Dcs_param -> Dcs_intermediate
+ table.AddRange(0x20, 0x2F, DcsParamState, CollectAction, DcsIntermediateState)
+ // Dcs_param -> Dcs_passthrough
+ table.AddRange(0x40, 0x7E, DcsParamState, StartAction, DcsStringState)
+
+ // Dcs_passthrough
+ table.AddRange(0x00, 0x17, DcsStringState, PutAction, DcsStringState)
+ table.AddOne(0x19, DcsStringState, PutAction, DcsStringState)
+ table.AddRange(0x1C, 0x1F, DcsStringState, PutAction, DcsStringState)
+ table.AddRange(0x20, 0x7E, DcsStringState, PutAction, DcsStringState)
+ table.AddOne(0x7F, DcsStringState, PutAction, DcsStringState)
+ table.AddRange(0x80, 0xFF, DcsStringState, PutAction, DcsStringState) // Allow Utf8 characters by extending the printable range from 0x7F to 0xFF
+ // ST, CAN, SUB, and ESC terminate the sequence
+ table.AddOne(0x1B, DcsStringState, DispatchAction, EscapeState)
+ table.AddOne(0x9C, DcsStringState, DispatchAction, GroundState)
+ table.AddMany([]byte{0x18, 0x1A}, DcsStringState, IgnoreAction, GroundState)
+
+ // Csi_param
+ table.AddRange(0x00, 0x17, CsiParamState, ExecuteAction, CsiParamState)
+ table.AddOne(0x19, CsiParamState, ExecuteAction, CsiParamState)
+ table.AddRange(0x1C, 0x1F, CsiParamState, ExecuteAction, CsiParamState)
+ table.AddRange(0x30, 0x3B, CsiParamState, ParamAction, CsiParamState)
+ table.AddOne(0x7F, CsiParamState, IgnoreAction, CsiParamState)
+ table.AddRange(0x3C, 0x3F, CsiParamState, IgnoreAction, CsiParamState)
+ // Csi_param -> Ground
+ table.AddRange(0x40, 0x7E, CsiParamState, DispatchAction, GroundState)
+ // Csi_param -> Csi_intermediate
+ table.AddRange(0x20, 0x2F, CsiParamState, CollectAction, CsiIntermediateState)
+
+ // Csi_intermediate
+ table.AddRange(0x00, 0x17, CsiIntermediateState, ExecuteAction, CsiIntermediateState)
+ table.AddOne(0x19, CsiIntermediateState, ExecuteAction, CsiIntermediateState)
+ table.AddRange(0x1C, 0x1F, CsiIntermediateState, ExecuteAction, CsiIntermediateState)
+ table.AddRange(0x20, 0x2F, CsiIntermediateState, CollectAction, CsiIntermediateState)
+ table.AddOne(0x7F, CsiIntermediateState, IgnoreAction, CsiIntermediateState)
+ // Csi_intermediate -> Ground
+ table.AddRange(0x40, 0x7E, CsiIntermediateState, DispatchAction, GroundState)
+ // Csi_intermediate -> Csi_ignore
+ table.AddRange(0x30, 0x3F, CsiIntermediateState, IgnoreAction, GroundState)
+
+ // Csi_entry
+ table.AddRange(0x00, 0x17, CsiEntryState, ExecuteAction, CsiEntryState)
+ table.AddOne(0x19, CsiEntryState, ExecuteAction, CsiEntryState)
+ table.AddRange(0x1C, 0x1F, CsiEntryState, ExecuteAction, CsiEntryState)
+ table.AddOne(0x7F, CsiEntryState, IgnoreAction, CsiEntryState)
+ // Csi_entry -> Ground
+ table.AddRange(0x40, 0x7E, CsiEntryState, DispatchAction, GroundState)
+ // Csi_entry -> Csi_intermediate
+ table.AddRange(0x20, 0x2F, CsiEntryState, CollectAction, CsiIntermediateState)
+ // Csi_entry -> Csi_param
+ table.AddRange(0x30, 0x3B, CsiEntryState, ParamAction, CsiParamState)
+ table.AddRange(0x3C, 0x3F, CsiEntryState, PrefixAction, CsiParamState)
+
+ // Osc_string
+ table.AddRange(0x00, 0x06, OscStringState, IgnoreAction, OscStringState)
+ table.AddRange(0x08, 0x17, OscStringState, IgnoreAction, OscStringState)
+ table.AddOne(0x19, OscStringState, IgnoreAction, OscStringState)
+ table.AddRange(0x1C, 0x1F, OscStringState, IgnoreAction, OscStringState)
+ table.AddRange(0x20, 0xFF, OscStringState, PutAction, OscStringState) // Allow Utf8 characters by extending the printable range from 0x7F to 0xFF
+
+ // ST, CAN, SUB, ESC, and BEL terminate the sequence
+ table.AddOne(0x1B, OscStringState, DispatchAction, EscapeState)
+ table.AddOne(0x07, OscStringState, DispatchAction, GroundState)
+ table.AddOne(0x9C, OscStringState, DispatchAction, GroundState)
+ table.AddMany([]byte{0x18, 0x1A}, OscStringState, IgnoreAction, GroundState)
+
+ return table
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/parser_decode.go b/vendor/github.com/charmbracelet/x/ansi/parser_decode.go
new file mode 100644
index 00000000..3e504739
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/parser_decode.go
@@ -0,0 +1,524 @@
+package ansi
+
+import (
+ "unicode/utf8"
+
+ "github.com/charmbracelet/x/ansi/parser"
+ "github.com/mattn/go-runewidth"
+ "github.com/rivo/uniseg"
+)
+
+// State represents the state of the ANSI escape sequence parser used by
+// [DecodeSequence].
+type State = byte
+
+// ANSI escape sequence states used by [DecodeSequence].
+const (
+ NormalState State = iota
+ PrefixState
+ ParamsState
+ IntermedState
+ EscapeState
+ StringState
+)
+
+// DecodeSequence decodes the first ANSI escape sequence or a printable
+// grapheme from the given data. It returns the sequence slice, the number of
+// bytes read, the cell width for each sequence, and the new state.
+//
+// The cell width will always be 0 for control and escape sequences, 1 for
+// ASCII printable characters, and the number of cells other Unicode characters
+// occupy. It uses the uniseg package to calculate the width of Unicode
+// graphemes and characters. This means it will always do grapheme clustering
+// (mode 2027).
+//
+// Passing a non-nil [*Parser] as the last argument will allow the decoder to
+// collect sequence parameters, data, and commands. The parser cmd will have
+// the packed command value that contains intermediate and prefix characters.
+// In the case of a OSC sequence, the cmd will be the OSC command number. Use
+// [Cmd] and [Param] types to unpack command intermediates and prefixes as well
+// as parameters.
+//
+// Zero [Cmd] means the CSI, DCS, or ESC sequence is invalid. Moreover, checking the
+// validity of other data sequences, OSC, DCS, etc, will require checking for
+// the returned sequence terminator bytes such as ST (ESC \\) and BEL).
+//
+// We store the command byte in [Cmd] in the most significant byte, the
+// prefix byte in the next byte, and the intermediate byte in the least
+// significant byte. This is done to avoid using a struct to store the command
+// and its intermediates and prefixes. The command byte is always the least
+// significant byte i.e. [Cmd & 0xff]. Use the [Cmd] type to unpack the
+// command, intermediate, and prefix bytes. Note that we only collect the last
+// prefix character and intermediate byte.
+//
+// The [p.Params] slice will contain the parameters of the sequence. Any
+// sub-parameter will have the [parser.HasMoreFlag] set. Use the [Param] type
+// to unpack the parameters.
+//
+// Example:
+//
+// var state byte // the initial state is always zero [NormalState]
+// p := NewParser(32, 1024) // create a new parser with a 32 params buffer and 1024 data buffer (optional)
+// input := []byte("\x1b[31mHello, World!\x1b[0m")
+// for len(input) > 0 {
+// seq, width, n, newState := DecodeSequence(input, state, p)
+// log.Printf("seq: %q, width: %d", seq, width)
+// state = newState
+// input = input[n:]
+// }
+//
+// This function treats the text as a sequence of grapheme clusters.
+func DecodeSequence[T string | []byte](b T, state byte, p *Parser) (seq T, width int, n int, newState byte) {
+ return decodeSequence(GraphemeWidth, b, state, p)
+}
+
+// DecodeSequenceWc decodes the first ANSI escape sequence or a printable
+// grapheme from the given data. It returns the sequence slice, the number of
+// bytes read, the cell width for each sequence, and the new state.
+//
+// The cell width will always be 0 for control and escape sequences, 1 for
+// ASCII printable characters, and the number of cells other Unicode characters
+// occupy. It uses the uniseg package to calculate the width of Unicode
+// graphemes and characters. This means it will always do grapheme clustering
+// (mode 2027).
+//
+// Passing a non-nil [*Parser] as the last argument will allow the decoder to
+// collect sequence parameters, data, and commands. The parser cmd will have
+// the packed command value that contains intermediate and prefix characters.
+// In the case of a OSC sequence, the cmd will be the OSC command number. Use
+// [Cmd] and [Param] types to unpack command intermediates and prefixes as well
+// as parameters.
+//
+// Zero [Cmd] means the CSI, DCS, or ESC sequence is invalid. Moreover, checking the
+// validity of other data sequences, OSC, DCS, etc, will require checking for
+// the returned sequence terminator bytes such as ST (ESC \\) and BEL).
+//
+// We store the command byte in [Cmd] in the most significant byte, the
+// prefix byte in the next byte, and the intermediate byte in the least
+// significant byte. This is done to avoid using a struct to store the command
+// and its intermediates and prefixes. The command byte is always the least
+// significant byte i.e. [Cmd & 0xff]. Use the [Cmd] type to unpack the
+// command, intermediate, and prefix bytes. Note that we only collect the last
+// prefix character and intermediate byte.
+//
+// The [p.Params] slice will contain the parameters of the sequence. Any
+// sub-parameter will have the [parser.HasMoreFlag] set. Use the [Param] type
+// to unpack the parameters.
+//
+// Example:
+//
+// var state byte // the initial state is always zero [NormalState]
+// p := NewParser(32, 1024) // create a new parser with a 32 params buffer and 1024 data buffer (optional)
+// input := []byte("\x1b[31mHello, World!\x1b[0m")
+// for len(input) > 0 {
+// seq, width, n, newState := DecodeSequenceWc(input, state, p)
+// log.Printf("seq: %q, width: %d", seq, width)
+// state = newState
+// input = input[n:]
+// }
+//
+// This function treats the text as a sequence of wide characters and runes.
+func DecodeSequenceWc[T string | []byte](b T, state byte, p *Parser) (seq T, width int, n int, newState byte) {
+ return decodeSequence(WcWidth, b, state, p)
+}
+
+func decodeSequence[T string | []byte](m Method, b T, state State, p *Parser) (seq T, width int, n int, newState byte) {
+ for i := 0; i < len(b); i++ {
+ c := b[i]
+
+ switch state {
+ case NormalState:
+ switch c {
+ case ESC:
+ if p != nil {
+ if len(p.params) > 0 {
+ p.params[0] = parser.MissingParam
+ }
+ p.cmd = 0
+ p.paramsLen = 0
+ p.dataLen = 0
+ }
+ state = EscapeState
+ continue
+ case CSI, DCS:
+ if p != nil {
+ if len(p.params) > 0 {
+ p.params[0] = parser.MissingParam
+ }
+ p.cmd = 0
+ p.paramsLen = 0
+ p.dataLen = 0
+ }
+ state = PrefixState
+ continue
+ case OSC, APC, SOS, PM:
+ if p != nil {
+ p.cmd = parser.MissingCommand
+ p.dataLen = 0
+ }
+ state = StringState
+ continue
+ }
+
+ if p != nil {
+ p.dataLen = 0
+ p.paramsLen = 0
+ p.cmd = 0
+ }
+ if c > US && c < DEL {
+ // ASCII printable characters
+ return b[i : i+1], 1, 1, NormalState
+ }
+
+ if c <= US || c == DEL || c < 0xC0 {
+ // C0 & C1 control characters & DEL
+ return b[i : i+1], 0, 1, NormalState
+ }
+
+ if utf8.RuneStart(c) {
+ seq, _, width, _ = FirstGraphemeCluster(b, -1)
+ if m == WcWidth {
+ width = runewidth.StringWidth(string(seq))
+ }
+ i += len(seq)
+ return b[:i], width, i, NormalState
+ }
+
+ // Invalid UTF-8 sequence
+ return b[:i], 0, i, NormalState
+ case PrefixState:
+ if c >= '<' && c <= '?' {
+ if p != nil {
+ // We only collect the last prefix character.
+ p.cmd &^= 0xff << parser.PrefixShift
+ p.cmd |= int(c) << parser.PrefixShift
+ }
+ break
+ }
+
+ state = ParamsState
+ fallthrough
+ case ParamsState:
+ if c >= '0' && c <= '9' {
+ if p != nil {
+ if p.params[p.paramsLen] == parser.MissingParam {
+ p.params[p.paramsLen] = 0
+ }
+
+ p.params[p.paramsLen] *= 10
+ p.params[p.paramsLen] += int(c - '0')
+ }
+ break
+ }
+
+ if c == ':' {
+ if p != nil {
+ p.params[p.paramsLen] |= parser.HasMoreFlag
+ }
+ }
+
+ if c == ';' || c == ':' {
+ if p != nil {
+ p.paramsLen++
+ if p.paramsLen < len(p.params) {
+ p.params[p.paramsLen] = parser.MissingParam
+ }
+ }
+ break
+ }
+
+ state = IntermedState
+ fallthrough
+ case IntermedState:
+ if c >= ' ' && c <= '/' {
+ if p != nil {
+ p.cmd &^= 0xff << parser.IntermedShift
+ p.cmd |= int(c) << parser.IntermedShift
+ }
+ break
+ }
+
+ if p != nil {
+ // Increment the last parameter
+ if p.paramsLen > 0 && p.paramsLen < len(p.params)-1 ||
+ p.paramsLen == 0 && len(p.params) > 0 && p.params[0] != parser.MissingParam {
+ p.paramsLen++
+ }
+ }
+
+ if c >= '@' && c <= '~' {
+ if p != nil {
+ p.cmd &^= 0xff
+ p.cmd |= int(c)
+ }
+
+ if HasDcsPrefix(b) {
+ // Continue to collect DCS data
+ if p != nil {
+ p.dataLen = 0
+ }
+ state = StringState
+ continue
+ }
+
+ return b[:i+1], 0, i + 1, NormalState
+ }
+
+ // Invalid CSI/DCS sequence
+ return b[:i], 0, i, NormalState
+ case EscapeState:
+ switch c {
+ case '[', 'P':
+ if p != nil {
+ if len(p.params) > 0 {
+ p.params[0] = parser.MissingParam
+ }
+ p.paramsLen = 0
+ p.cmd = 0
+ }
+ state = PrefixState
+ continue
+ case ']', 'X', '^', '_':
+ if p != nil {
+ p.cmd = parser.MissingCommand
+ p.dataLen = 0
+ }
+ state = StringState
+ continue
+ }
+
+ if c >= ' ' && c <= '/' {
+ if p != nil {
+ p.cmd &^= 0xff << parser.IntermedShift
+ p.cmd |= int(c) << parser.IntermedShift
+ }
+ continue
+ } else if c >= '0' && c <= '~' {
+ if p != nil {
+ p.cmd &^= 0xff
+ p.cmd |= int(c)
+ }
+ return b[:i+1], 0, i + 1, NormalState
+ }
+
+ // Invalid escape sequence
+ return b[:i], 0, i, NormalState
+ case StringState:
+ switch c {
+ case BEL:
+ if HasOscPrefix(b) {
+ parseOscCmd(p)
+ return b[:i+1], 0, i + 1, NormalState
+ }
+ case CAN, SUB:
+ if HasOscPrefix(b) {
+ // Ensure we parse the OSC command number
+ parseOscCmd(p)
+ }
+
+ // Cancel the sequence
+ return b[:i], 0, i, NormalState
+ case ST:
+ if HasOscPrefix(b) {
+ // Ensure we parse the OSC command number
+ parseOscCmd(p)
+ }
+
+ return b[:i+1], 0, i + 1, NormalState
+ case ESC:
+ if HasStPrefix(b[i:]) {
+ if HasOscPrefix(b) {
+ // Ensure we parse the OSC command number
+ parseOscCmd(p)
+ }
+
+ // End of string 7-bit (ST)
+ return b[:i+2], 0, i + 2, NormalState
+ }
+
+ // Otherwise, cancel the sequence
+ return b[:i], 0, i, NormalState
+ }
+
+ if p != nil && p.dataLen < len(p.data) {
+ p.data[p.dataLen] = c
+ p.dataLen++
+
+ // Parse the OSC command number
+ if c == ';' && HasOscPrefix(b) {
+ parseOscCmd(p)
+ }
+ }
+ }
+ }
+
+ return b, 0, len(b), state
+}
+
+func parseOscCmd(p *Parser) {
+ if p == nil || p.cmd != parser.MissingCommand {
+ return
+ }
+ for j := 0; j < p.dataLen; j++ {
+ d := p.data[j]
+ if d < '0' || d > '9' {
+ break
+ }
+ if p.cmd == parser.MissingCommand {
+ p.cmd = 0
+ }
+ p.cmd *= 10
+ p.cmd += int(d - '0')
+ }
+}
+
+// Equal returns true if the given byte slices are equal.
+func Equal[T string | []byte](a, b T) bool {
+ return string(a) == string(b)
+}
+
+// HasPrefix returns true if the given byte slice has prefix.
+func HasPrefix[T string | []byte](b, prefix T) bool {
+ return len(b) >= len(prefix) && Equal(b[0:len(prefix)], prefix)
+}
+
+// HasSuffix returns true if the given byte slice has suffix.
+func HasSuffix[T string | []byte](b, suffix T) bool {
+ return len(b) >= len(suffix) && Equal(b[len(b)-len(suffix):], suffix)
+}
+
+// HasCsiPrefix returns true if the given byte slice has a CSI prefix.
+func HasCsiPrefix[T string | []byte](b T) bool {
+ return (len(b) > 0 && b[0] == CSI) ||
+ (len(b) > 1 && b[0] == ESC && b[1] == '[')
+}
+
+// HasOscPrefix returns true if the given byte slice has an OSC prefix.
+func HasOscPrefix[T string | []byte](b T) bool {
+ return (len(b) > 0 && b[0] == OSC) ||
+ (len(b) > 1 && b[0] == ESC && b[1] == ']')
+}
+
+// HasApcPrefix returns true if the given byte slice has an APC prefix.
+func HasApcPrefix[T string | []byte](b T) bool {
+ return (len(b) > 0 && b[0] == APC) ||
+ (len(b) > 1 && b[0] == ESC && b[1] == '_')
+}
+
+// HasDcsPrefix returns true if the given byte slice has a DCS prefix.
+func HasDcsPrefix[T string | []byte](b T) bool {
+ return (len(b) > 0 && b[0] == DCS) ||
+ (len(b) > 1 && b[0] == ESC && b[1] == 'P')
+}
+
+// HasSosPrefix returns true if the given byte slice has a SOS prefix.
+func HasSosPrefix[T string | []byte](b T) bool {
+ return (len(b) > 0 && b[0] == SOS) ||
+ (len(b) > 1 && b[0] == ESC && b[1] == 'X')
+}
+
+// HasPmPrefix returns true if the given byte slice has a PM prefix.
+func HasPmPrefix[T string | []byte](b T) bool {
+ return (len(b) > 0 && b[0] == PM) ||
+ (len(b) > 1 && b[0] == ESC && b[1] == '^')
+}
+
+// HasStPrefix returns true if the given byte slice has a ST prefix.
+func HasStPrefix[T string | []byte](b T) bool {
+ return (len(b) > 0 && b[0] == ST) ||
+ (len(b) > 1 && b[0] == ESC && b[1] == '\\')
+}
+
+// HasEscPrefix returns true if the given byte slice has an ESC prefix.
+func HasEscPrefix[T string | []byte](b T) bool {
+ return len(b) > 0 && b[0] == ESC
+}
+
+// FirstGraphemeCluster returns the first grapheme cluster in the given string or byte slice.
+// This is a syntactic sugar function that wraps
+// uniseg.FirstGraphemeClusterInString and uniseg.FirstGraphemeCluster.
+func FirstGraphemeCluster[T string | []byte](b T, state int) (T, T, int, int) {
+ switch b := any(b).(type) {
+ case string:
+ cluster, rest, width, newState := uniseg.FirstGraphemeClusterInString(b, state)
+ return T(cluster), T(rest), width, newState
+ case []byte:
+ cluster, rest, width, newState := uniseg.FirstGraphemeCluster(b, state)
+ return T(cluster), T(rest), width, newState
+ }
+ panic("unreachable")
+}
+
+// Cmd represents a sequence command. This is used to pack/unpack a sequence
+// command with its intermediate and prefix characters. Those are commonly
+// found in CSI and DCS sequences.
+type Cmd int
+
+// Prefix returns the unpacked prefix byte of the CSI sequence.
+// This is always gonna be one of the following '<' '=' '>' '?' and in the
+// range of 0x3C-0x3F.
+// Zero is returned if the sequence does not have a prefix.
+func (c Cmd) Prefix() byte {
+ return byte(parser.Prefix(int(c)))
+}
+
+// Intermediate returns the unpacked intermediate byte of the CSI sequence.
+// An intermediate byte is in the range of 0x20-0x2F. This includes these
+// characters from ' ', '!', '"', '#', '$', '%', '&', ”', '(', ')', '*', '+',
+// ',', '-', '.', '/'.
+// Zero is returned if the sequence does not have an intermediate byte.
+func (c Cmd) Intermediate() byte {
+ return byte(parser.Intermediate(int(c)))
+}
+
+// Final returns the unpacked command byte of the CSI sequence.
+func (c Cmd) Final() byte {
+ return byte(parser.Command(int(c)))
+}
+
+// Command packs a command with the given prefix, intermediate, and final. A
+// zero byte means the sequence does not have a prefix or intermediate.
+//
+// Prefixes are in the range of 0x3C-0x3F that is one of `<=>?`.
+//
+// Intermediates are in the range of 0x20-0x2F that is anything in
+// `!"#$%&'()*+,-./`.
+//
+// Final bytes are in the range of 0x40-0x7E that is anything in the range
+// `@A–Z[\]^_`a–z{|}~`.
+func Command(prefix, inter, final byte) (c int) {
+ c = int(final)
+ c |= int(prefix) << parser.PrefixShift
+ c |= int(inter) << parser.IntermedShift
+ return
+}
+
+// Param represents a sequence parameter. Sequence parameters with
+// sub-parameters are packed with the HasMoreFlag set. This is used to unpack
+// the parameters from a CSI and DCS sequences.
+type Param int
+
+// Param returns the unpacked parameter at the given index.
+// It returns the default value if the parameter is missing.
+func (s Param) Param(def int) int {
+ p := int(s) & parser.ParamMask
+ if p == parser.MissingParam {
+ return def
+ }
+ return p
+}
+
+// HasMore unpacks the HasMoreFlag from the parameter.
+func (s Param) HasMore() bool {
+ return s&parser.HasMoreFlag != 0
+}
+
+// Parameter packs an escape code parameter with the given parameter and
+// whether this parameter has following sub-parameters.
+func Parameter(p int, hasMore bool) (s int) {
+ s = p & parser.ParamMask
+ if hasMore {
+ s |= parser.HasMoreFlag
+ }
+ return
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/parser_handler.go b/vendor/github.com/charmbracelet/x/ansi/parser_handler.go
new file mode 100644
index 00000000..03f9ed4c
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/parser_handler.go
@@ -0,0 +1,60 @@
+package ansi
+
+import "unsafe"
+
+// Params represents a list of packed parameters.
+type Params []Param
+
+// Param returns the parameter at the given index and if it is part of a
+// sub-parameters. It falls back to the default value if the parameter is
+// missing. If the index is out of bounds, it returns the default value and
+// false.
+func (p Params) Param(i, def int) (int, bool, bool) {
+ if i < 0 || i >= len(p) {
+ return def, false, false
+ }
+ return p[i].Param(def), p[i].HasMore(), true
+}
+
+// ForEach iterates over the parameters and calls the given function for each
+// parameter. If a parameter is part of a sub-parameter, it will be called with
+// hasMore set to true.
+// Use def to set a default value for missing parameters.
+func (p Params) ForEach(def int, f func(i, param int, hasMore bool)) {
+ for i := range p {
+ f(i, p[i].Param(def), p[i].HasMore())
+ }
+}
+
+// ToParams converts a list of integers to a list of parameters.
+func ToParams(params []int) Params {
+ return unsafe.Slice((*Param)(unsafe.Pointer(¶ms[0])), len(params))
+}
+
+// Handler handles actions performed by the parser.
+// It is used to handle ANSI escape sequences, control characters, and runes.
+type Handler struct {
+ // Print is called when a printable rune is encountered.
+ Print func(r rune)
+ // Execute is called when a control character is encountered.
+ Execute func(b byte)
+ // HandleCsi is called when a CSI sequence is encountered.
+ HandleCsi func(cmd Cmd, params Params)
+ // HandleEsc is called when an ESC sequence is encountered.
+ HandleEsc func(cmd Cmd)
+ // HandleDcs is called when a DCS sequence is encountered.
+ HandleDcs func(cmd Cmd, params Params, data []byte)
+ // HandleOsc is called when an OSC sequence is encountered.
+ HandleOsc func(cmd int, data []byte)
+ // HandlePm is called when a PM sequence is encountered.
+ HandlePm func(data []byte)
+ // HandleApc is called when an APC sequence is encountered.
+ HandleApc func(data []byte)
+ // HandleSos is called when a SOS sequence is encountered.
+ HandleSos func(data []byte)
+}
+
+// SetHandler sets the handler for the parser.
+func (p *Parser) SetHandler(h Handler) {
+ p.handler = h
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/parser_sync.go b/vendor/github.com/charmbracelet/x/ansi/parser_sync.go
new file mode 100644
index 00000000..65d25a9a
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/parser_sync.go
@@ -0,0 +1,29 @@
+package ansi
+
+import (
+ "sync"
+
+ "github.com/charmbracelet/x/ansi/parser"
+)
+
+var parserPool = sync.Pool{
+ New: func() any {
+ p := NewParser()
+ p.SetParamsSize(parser.MaxParamsSize)
+ p.SetDataSize(1024 * 1024 * 4) // 4MB of data buffer
+ return p
+ },
+}
+
+// GetParser returns a parser from a sync pool.
+func GetParser() *Parser {
+ return parserPool.Get().(*Parser)
+}
+
+// PutParser returns a parser to a sync pool. The parser is reset
+// automatically.
+func PutParser(p *Parser) {
+ p.Reset()
+ p.dataLen = 0
+ parserPool.Put(p)
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/passthrough.go b/vendor/github.com/charmbracelet/x/ansi/passthrough.go
new file mode 100644
index 00000000..14a74522
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/passthrough.go
@@ -0,0 +1,63 @@
+package ansi
+
+import (
+ "bytes"
+)
+
+// ScreenPassthrough wraps the given ANSI sequence in a DCS passthrough
+// sequence to be sent to the outer terminal. This is used to send raw escape
+// sequences to the outer terminal when running inside GNU Screen.
+//
+// DCS ST
+//
+// Note: Screen limits the length of string sequences to 768 bytes (since 2014).
+// Use zero to indicate no limit, otherwise, this will chunk the returned
+// string into limit sized chunks.
+//
+// See: https://www.gnu.org/software/screen/manual/screen.html#String-Escapes
+// See: https://git.savannah.gnu.org/cgit/screen.git/tree/src/screen.h?id=c184c6ec27683ff1a860c45be5cf520d896fd2ef#n44
+func ScreenPassthrough(seq string, limit int) string {
+ var b bytes.Buffer
+ b.WriteString("\x1bP")
+ if limit > 0 {
+ for i := 0; i < len(seq); i += limit {
+ end := i + limit
+ if end > len(seq) {
+ end = len(seq)
+ }
+ b.WriteString(seq[i:end])
+ if end < len(seq) {
+ b.WriteString("\x1b\\\x1bP")
+ }
+ }
+ } else {
+ b.WriteString(seq)
+ }
+ b.WriteString("\x1b\\")
+ return b.String()
+}
+
+// TmuxPassthrough wraps the given ANSI sequence in a special DCS passthrough
+// sequence to be sent to the outer terminal. This is used to send raw escape
+// sequences to the outer terminal when running inside Tmux.
+//
+// DCS tmux ; ST
+//
+// Where is the given sequence in which all occurrences of ESC
+// (0x1b) are doubled i.e. replaced with ESC ESC (0x1b 0x1b).
+//
+// Note: this needs the `allow-passthrough` option to be set to `on`.
+//
+// See: https://github.com/tmux/tmux/wiki/FAQ#what-is-the-passthrough-escape-sequence-and-how-do-i-use-it
+func TmuxPassthrough(seq string) string {
+ var b bytes.Buffer
+ b.WriteString("\x1bPtmux;")
+ for i := 0; i < len(seq); i++ {
+ if seq[i] == ESC {
+ b.WriteByte(ESC)
+ }
+ b.WriteByte(seq[i])
+ }
+ b.WriteString("\x1b\\")
+ return b.String()
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/paste.go b/vendor/github.com/charmbracelet/x/ansi/paste.go
new file mode 100644
index 00000000..2f9ea6f7
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/paste.go
@@ -0,0 +1,7 @@
+package ansi
+
+// BracketedPasteStart is the control sequence to enable bracketed paste mode.
+const BracketedPasteStart = "\x1b[200~"
+
+// BracketedPasteEnd is the control sequence to disable bracketed paste mode.
+const BracketedPasteEnd = "\x1b[201~"
diff --git a/vendor/github.com/charmbracelet/x/ansi/reset.go b/vendor/github.com/charmbracelet/x/ansi/reset.go
new file mode 100644
index 00000000..c1b89ea4
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/reset.go
@@ -0,0 +1,11 @@
+package ansi
+
+// ResetInitialState (RIS) resets the terminal to its initial state.
+//
+// ESC c
+//
+// See: https://vt100.net/docs/vt510-rm/RIS.html
+const (
+ ResetInitialState = "\x1bc"
+ RIS = ResetInitialState
+)
diff --git a/vendor/github.com/charmbracelet/x/ansi/screen.go b/vendor/github.com/charmbracelet/x/ansi/screen.go
new file mode 100644
index 00000000..c76e4f0d
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/screen.go
@@ -0,0 +1,410 @@
+package ansi
+
+import (
+ "strconv"
+ "strings"
+)
+
+// EraseDisplay (ED) clears the display or parts of the display. A screen is
+// the shown part of the terminal display excluding the scrollback buffer.
+// Possible values:
+//
+// Default is 0.
+//
+// 0: Clear from cursor to end of screen.
+// 1: Clear from cursor to beginning of the screen.
+// 2: Clear entire screen (and moves cursor to upper left on DOS).
+// 3: Clear entire display which delete all lines saved in the scrollback buffer (xterm).
+//
+// CSI J
+//
+// See: https://vt100.net/docs/vt510-rm/ED.html
+func EraseDisplay(n int) string {
+ var s string
+ if n > 0 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "J"
+}
+
+// ED is an alias for [EraseDisplay].
+func ED(n int) string {
+ return EraseDisplay(n)
+}
+
+// EraseDisplay constants.
+// These are the possible values for the EraseDisplay function.
+const (
+ EraseScreenBelow = "\x1b[J"
+ EraseScreenAbove = "\x1b[1J"
+ EraseEntireScreen = "\x1b[2J"
+ EraseEntireDisplay = "\x1b[3J"
+)
+
+// EraseLine (EL) clears the current line or parts of the line. Possible values:
+//
+// 0: Clear from cursor to end of line.
+// 1: Clear from cursor to beginning of the line.
+// 2: Clear entire line.
+//
+// The cursor position is not affected.
+//
+// CSI K
+//
+// See: https://vt100.net/docs/vt510-rm/EL.html
+func EraseLine(n int) string {
+ var s string
+ if n > 0 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "K"
+}
+
+// EL is an alias for [EraseLine].
+func EL(n int) string {
+ return EraseLine(n)
+}
+
+// EraseLine constants.
+// These are the possible values for the EraseLine function.
+const (
+ EraseLineRight = "\x1b[K"
+ EraseLineLeft = "\x1b[1K"
+ EraseEntireLine = "\x1b[2K"
+)
+
+// ScrollUp (SU) scrolls the screen up n lines. New lines are added at the
+// bottom of the screen.
+//
+// CSI Pn S
+//
+// See: https://vt100.net/docs/vt510-rm/SU.html
+func ScrollUp(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "S"
+}
+
+// PanDown is an alias for [ScrollUp].
+func PanDown(n int) string {
+ return ScrollUp(n)
+}
+
+// SU is an alias for [ScrollUp].
+func SU(n int) string {
+ return ScrollUp(n)
+}
+
+// ScrollDown (SD) scrolls the screen down n lines. New lines are added at the
+// top of the screen.
+//
+// CSI Pn T
+//
+// See: https://vt100.net/docs/vt510-rm/SD.html
+func ScrollDown(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "T"
+}
+
+// PanUp is an alias for [ScrollDown].
+func PanUp(n int) string {
+ return ScrollDown(n)
+}
+
+// SD is an alias for [ScrollDown].
+func SD(n int) string {
+ return ScrollDown(n)
+}
+
+// InsertLine (IL) inserts n blank lines at the current cursor position.
+// Existing lines are moved down.
+//
+// CSI Pn L
+//
+// See: https://vt100.net/docs/vt510-rm/IL.html
+func InsertLine(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "L"
+}
+
+// IL is an alias for [InsertLine].
+func IL(n int) string {
+ return InsertLine(n)
+}
+
+// DeleteLine (DL) deletes n lines at the current cursor position. Existing
+// lines are moved up.
+//
+// CSI Pn M
+//
+// See: https://vt100.net/docs/vt510-rm/DL.html
+func DeleteLine(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "M"
+}
+
+// DL is an alias for [DeleteLine].
+func DL(n int) string {
+ return DeleteLine(n)
+}
+
+// SetTopBottomMargins (DECSTBM) sets the top and bottom margins for the scrolling
+// region. The default is the entire screen.
+//
+// Default is 1 and the bottom of the screen.
+//
+// CSI Pt ; Pb r
+//
+// See: https://vt100.net/docs/vt510-rm/DECSTBM.html
+func SetTopBottomMargins(top, bot int) string {
+ var t, b string
+ if top > 0 {
+ t = strconv.Itoa(top)
+ }
+ if bot > 0 {
+ b = strconv.Itoa(bot)
+ }
+ return "\x1b[" + t + ";" + b + "r"
+}
+
+// DECSTBM is an alias for [SetTopBottomMargins].
+func DECSTBM(top, bot int) string {
+ return SetTopBottomMargins(top, bot)
+}
+
+// SetLeftRightMargins (DECSLRM) sets the left and right margins for the scrolling
+// region.
+//
+// Default is 1 and the right of the screen.
+//
+// CSI Pl ; Pr s
+//
+// See: https://vt100.net/docs/vt510-rm/DECSLRM.html
+func SetLeftRightMargins(left, right int) string {
+ var l, r string
+ if left > 0 {
+ l = strconv.Itoa(left)
+ }
+ if right > 0 {
+ r = strconv.Itoa(right)
+ }
+ return "\x1b[" + l + ";" + r + "s"
+}
+
+// DECSLRM is an alias for [SetLeftRightMargins].
+func DECSLRM(left, right int) string {
+ return SetLeftRightMargins(left, right)
+}
+
+// SetScrollingRegion (DECSTBM) sets the top and bottom margins for the scrolling
+// region. The default is the entire screen.
+//
+// CSI ; r
+//
+// See: https://vt100.net/docs/vt510-rm/DECSTBM.html
+//
+// Deprecated: use [SetTopBottomMargins] instead.
+func SetScrollingRegion(t, b int) string {
+ if t < 0 {
+ t = 0
+ }
+ if b < 0 {
+ b = 0
+ }
+ return "\x1b[" + strconv.Itoa(t) + ";" + strconv.Itoa(b) + "r"
+}
+
+// InsertCharacter (ICH) inserts n blank characters at the current cursor
+// position. Existing characters move to the right. Characters moved past the
+// right margin are lost. ICH has no effect outside the scrolling margins.
+//
+// Default is 1.
+//
+// CSI Pn @
+//
+// See: https://vt100.net/docs/vt510-rm/ICH.html
+func InsertCharacter(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "@"
+}
+
+// ICH is an alias for [InsertCharacter].
+func ICH(n int) string {
+ return InsertCharacter(n)
+}
+
+// DeleteCharacter (DCH) deletes n characters at the current cursor position.
+// As the characters are deleted, the remaining characters move to the left and
+// the cursor remains at the same position.
+//
+// Default is 1.
+//
+// CSI Pn P
+//
+// See: https://vt100.net/docs/vt510-rm/DCH.html
+func DeleteCharacter(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "P"
+}
+
+// DCH is an alias for [DeleteCharacter].
+func DCH(n int) string {
+ return DeleteCharacter(n)
+}
+
+// SetTabEvery8Columns (DECST8C) sets the tab stops at every 8 columns.
+//
+// CSI ? 5 W
+//
+// See: https://vt100.net/docs/vt510-rm/DECST8C.html
+const (
+ SetTabEvery8Columns = "\x1b[?5W"
+ DECST8C = SetTabEvery8Columns
+)
+
+// HorizontalTabSet (HTS) sets a horizontal tab stop at the current cursor
+// column.
+//
+// This is equivalent to [HTS].
+//
+// ESC H
+//
+// See: https://vt100.net/docs/vt510-rm/HTS.html
+const HorizontalTabSet = "\x1bH"
+
+// TabClear (TBC) clears tab stops.
+//
+// Default is 0.
+//
+// Possible values:
+// 0: Clear tab stop at the current column. (default)
+// 3: Clear all tab stops.
+//
+// CSI Pn g
+//
+// See: https://vt100.net/docs/vt510-rm/TBC.html
+func TabClear(n int) string {
+ var s string
+ if n > 0 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "g"
+}
+
+// TBC is an alias for [TabClear].
+func TBC(n int) string {
+ return TabClear(n)
+}
+
+// RequestPresentationStateReport (DECRQPSR) requests the terminal to send a
+// report of the presentation state. This includes the cursor information [DECCIR],
+// and tab stop [DECTABSR] reports.
+//
+// Default is 0.
+//
+// Possible values:
+// 0: Error, request ignored.
+// 1: Cursor information report [DECCIR].
+// 2: Tab stop report [DECTABSR].
+//
+// CSI Ps $ w
+//
+// See: https://vt100.net/docs/vt510-rm/DECRQPSR.html
+func RequestPresentationStateReport(n int) string {
+ var s string
+ if n > 0 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "$w"
+}
+
+// DECRQPSR is an alias for [RequestPresentationStateReport].
+func DECRQPSR(n int) string {
+ return RequestPresentationStateReport(n)
+}
+
+// TabStopReport (DECTABSR) is the response to a tab stop report request.
+// It reports the tab stops set in the terminal.
+//
+// The response is a list of tab stops separated by a slash (/) character.
+//
+// DCS 2 $ u D ... D ST
+//
+// Where D is a decimal number representing a tab stop.
+//
+// See: https://vt100.net/docs/vt510-rm/DECTABSR.html
+func TabStopReport(stops ...int) string {
+ var s []string
+ for _, v := range stops {
+ s = append(s, strconv.Itoa(v))
+ }
+ return "\x1bP2$u" + strings.Join(s, "/") + "\x1b\\"
+}
+
+// DECTABSR is an alias for [TabStopReport].
+func DECTABSR(stops ...int) string {
+ return TabStopReport(stops...)
+}
+
+// CursorInformationReport (DECCIR) is the response to a cursor information
+// report request. It reports the cursor position, visual attributes, and
+// character protection attributes. It also reports the status of origin mode
+// [DECOM] and the current active character set.
+//
+// The response is a list of values separated by a semicolon (;) character.
+//
+// DCS 1 $ u D ... D ST
+//
+// Where D is a decimal number representing a value.
+//
+// See: https://vt100.net/docs/vt510-rm/DECCIR.html
+func CursorInformationReport(values ...int) string {
+ var s []string
+ for _, v := range values {
+ s = append(s, strconv.Itoa(v))
+ }
+ return "\x1bP1$u" + strings.Join(s, ";") + "\x1b\\"
+}
+
+// DECCIR is an alias for [CursorInformationReport].
+func DECCIR(values ...int) string {
+ return CursorInformationReport(values...)
+}
+
+// RepeatPreviousCharacter (REP) repeats the previous character n times.
+// This is identical to typing the same character n times.
+//
+// Default is 1.
+//
+// CSI Pn b
+//
+// See: ECMA-48 § 8.3.103
+func RepeatPreviousCharacter(n int) string {
+ var s string
+ if n > 1 {
+ s = strconv.Itoa(n)
+ }
+ return "\x1b[" + s + "b"
+}
+
+// REP is an alias for [RepeatPreviousCharacter].
+func REP(n int) string {
+ return RepeatPreviousCharacter(n)
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/sgr.go b/vendor/github.com/charmbracelet/x/ansi/sgr.go
new file mode 100644
index 00000000..1a18c98e
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/sgr.go
@@ -0,0 +1,95 @@
+package ansi
+
+import "strconv"
+
+// Select Graphic Rendition (SGR) is a command that sets display attributes.
+//
+// Default is 0.
+//
+// CSI Ps ; Ps ... m
+//
+// See: https://vt100.net/docs/vt510-rm/SGR.html
+func SelectGraphicRendition(ps ...Attr) string {
+ if len(ps) == 0 {
+ return ResetStyle
+ }
+
+ var s Style
+ for _, p := range ps {
+ attr, ok := attrStrings[p]
+ if ok {
+ s = append(s, attr)
+ } else {
+ if p < 0 {
+ p = 0
+ }
+ s = append(s, strconv.Itoa(p))
+ }
+ }
+
+ return s.String()
+}
+
+// SGR is an alias for [SelectGraphicRendition].
+func SGR(ps ...Attr) string {
+ return SelectGraphicRendition(ps...)
+}
+
+var attrStrings = map[int]string{
+ ResetAttr: "0",
+ BoldAttr: "1",
+ FaintAttr: "2",
+ ItalicAttr: "3",
+ UnderlineAttr: "4",
+ SlowBlinkAttr: "5",
+ RapidBlinkAttr: "6",
+ ReverseAttr: "7",
+ ConcealAttr: "8",
+ StrikethroughAttr: "9",
+ NoBoldAttr: "21",
+ NormalIntensityAttr: "22",
+ NoItalicAttr: "23",
+ NoUnderlineAttr: "24",
+ NoBlinkAttr: "25",
+ NoReverseAttr: "27",
+ NoConcealAttr: "28",
+ NoStrikethroughAttr: "29",
+ BlackForegroundColorAttr: "30",
+ RedForegroundColorAttr: "31",
+ GreenForegroundColorAttr: "32",
+ YellowForegroundColorAttr: "33",
+ BlueForegroundColorAttr: "34",
+ MagentaForegroundColorAttr: "35",
+ CyanForegroundColorAttr: "36",
+ WhiteForegroundColorAttr: "37",
+ ExtendedForegroundColorAttr: "38",
+ DefaultForegroundColorAttr: "39",
+ BlackBackgroundColorAttr: "40",
+ RedBackgroundColorAttr: "41",
+ GreenBackgroundColorAttr: "42",
+ YellowBackgroundColorAttr: "43",
+ BlueBackgroundColorAttr: "44",
+ MagentaBackgroundColorAttr: "45",
+ CyanBackgroundColorAttr: "46",
+ WhiteBackgroundColorAttr: "47",
+ ExtendedBackgroundColorAttr: "48",
+ DefaultBackgroundColorAttr: "49",
+ ExtendedUnderlineColorAttr: "58",
+ DefaultUnderlineColorAttr: "59",
+ BrightBlackForegroundColorAttr: "90",
+ BrightRedForegroundColorAttr: "91",
+ BrightGreenForegroundColorAttr: "92",
+ BrightYellowForegroundColorAttr: "93",
+ BrightBlueForegroundColorAttr: "94",
+ BrightMagentaForegroundColorAttr: "95",
+ BrightCyanForegroundColorAttr: "96",
+ BrightWhiteForegroundColorAttr: "97",
+ BrightBlackBackgroundColorAttr: "100",
+ BrightRedBackgroundColorAttr: "101",
+ BrightGreenBackgroundColorAttr: "102",
+ BrightYellowBackgroundColorAttr: "103",
+ BrightBlueBackgroundColorAttr: "104",
+ BrightMagentaBackgroundColorAttr: "105",
+ BrightCyanBackgroundColorAttr: "106",
+ BrightWhiteBackgroundColorAttr: "107",
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/status.go b/vendor/github.com/charmbracelet/x/ansi/status.go
new file mode 100644
index 00000000..4337e189
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/status.go
@@ -0,0 +1,144 @@
+package ansi
+
+import (
+ "strconv"
+ "strings"
+)
+
+// StatusReport represents a terminal status report.
+type StatusReport interface {
+ // StatusReport returns the status report identifier.
+ StatusReport() int
+}
+
+// ANSIReport represents an ANSI terminal status report.
+type ANSIStatusReport int //nolint:revive
+
+// Report returns the status report identifier.
+func (s ANSIStatusReport) StatusReport() int {
+ return int(s)
+}
+
+// DECStatusReport represents a DEC terminal status report.
+type DECStatusReport int
+
+// Status returns the status report identifier.
+func (s DECStatusReport) StatusReport() int {
+ return int(s)
+}
+
+// DeviceStatusReport (DSR) is a control sequence that reports the terminal's
+// status.
+// The terminal responds with a DSR sequence.
+//
+// CSI Ps n
+// CSI ? Ps n
+//
+// If one of the statuses is a [DECStatus], the sequence will use the DEC
+// format.
+//
+// See also https://vt100.net/docs/vt510-rm/DSR.html
+func DeviceStatusReport(statues ...StatusReport) string {
+ var dec bool
+ list := make([]string, len(statues))
+ seq := "\x1b["
+ for i, status := range statues {
+ list[i] = strconv.Itoa(status.StatusReport())
+ switch status.(type) {
+ case DECStatusReport:
+ dec = true
+ }
+ }
+ if dec {
+ seq += "?"
+ }
+ return seq + strings.Join(list, ";") + "n"
+}
+
+// DSR is an alias for [DeviceStatusReport].
+func DSR(status StatusReport) string {
+ return DeviceStatusReport(status)
+}
+
+// RequestCursorPositionReport is an escape sequence that requests the current
+// cursor position.
+//
+// CSI 6 n
+//
+// The terminal will report the cursor position as a CSI sequence in the
+// following format:
+//
+// CSI Pl ; Pc R
+//
+// Where Pl is the line number and Pc is the column number.
+// See: https://vt100.net/docs/vt510-rm/CPR.html
+const RequestCursorPositionReport = "\x1b[6n"
+
+// RequestExtendedCursorPositionReport (DECXCPR) is a sequence for requesting
+// the cursor position report including the current page number.
+//
+// CSI ? 6 n
+//
+// The terminal will report the cursor position as a CSI sequence in the
+// following format:
+//
+// CSI ? Pl ; Pc ; Pp R
+//
+// Where Pl is the line number, Pc is the column number, and Pp is the page
+// number.
+// See: https://vt100.net/docs/vt510-rm/DECXCPR.html
+const RequestExtendedCursorPositionReport = "\x1b[?6n"
+
+// CursorPositionReport (CPR) is a control sequence that reports the cursor's
+// position.
+//
+// CSI Pl ; Pc R
+//
+// Where Pl is the line number and Pc is the column number.
+//
+// See also https://vt100.net/docs/vt510-rm/CPR.html
+func CursorPositionReport(line, column int) string {
+ if line < 1 {
+ line = 1
+ }
+ if column < 1 {
+ column = 1
+ }
+ return "\x1b[" + strconv.Itoa(line) + ";" + strconv.Itoa(column) + "R"
+}
+
+// CPR is an alias for [CursorPositionReport].
+func CPR(line, column int) string {
+ return CursorPositionReport(line, column)
+}
+
+// ExtendedCursorPositionReport (DECXCPR) is a control sequence that reports the
+// cursor's position along with the page number (optional).
+//
+// CSI ? Pl ; Pc R
+// CSI ? Pl ; Pc ; Pv R
+//
+// Where Pl is the line number, Pc is the column number, and Pv is the page
+// number.
+//
+// If the page number is zero or negative, the returned sequence won't include
+// the page number.
+//
+// See also https://vt100.net/docs/vt510-rm/DECXCPR.html
+func ExtendedCursorPositionReport(line, column, page int) string {
+ if line < 1 {
+ line = 1
+ }
+ if column < 1 {
+ column = 1
+ }
+ if page < 1 {
+ return "\x1b[?" + strconv.Itoa(line) + ";" + strconv.Itoa(column) + "R"
+ }
+ return "\x1b[?" + strconv.Itoa(line) + ";" + strconv.Itoa(column) + ";" + strconv.Itoa(page) + "R"
+}
+
+// DECXCPR is an alias for [ExtendedCursorPositionReport].
+func DECXCPR(line, column, page int) string {
+ return ExtendedCursorPositionReport(line, column, page)
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/style.go b/vendor/github.com/charmbracelet/x/ansi/style.go
new file mode 100644
index 00000000..46ddcaa9
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/style.go
@@ -0,0 +1,660 @@
+package ansi
+
+import (
+ "image/color"
+ "strconv"
+ "strings"
+)
+
+// ResetStyle is a SGR (Select Graphic Rendition) style sequence that resets
+// all attributes.
+// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
+const ResetStyle = "\x1b[m"
+
+// Attr is a SGR (Select Graphic Rendition) style attribute.
+type Attr = int
+
+// Style represents an ANSI SGR (Select Graphic Rendition) style.
+type Style []string
+
+// String returns the ANSI SGR (Select Graphic Rendition) style sequence for
+// the given style.
+func (s Style) String() string {
+ if len(s) == 0 {
+ return ResetStyle
+ }
+ return "\x1b[" + strings.Join(s, ";") + "m"
+}
+
+// Styled returns a styled string with the given style applied.
+func (s Style) Styled(str string) string {
+ if len(s) == 0 {
+ return str
+ }
+ return s.String() + str + ResetStyle
+}
+
+// Reset appends the reset style attribute to the style.
+func (s Style) Reset() Style {
+ return append(s, resetAttr)
+}
+
+// Bold appends the bold style attribute to the style.
+func (s Style) Bold() Style {
+ return append(s, boldAttr)
+}
+
+// Faint appends the faint style attribute to the style.
+func (s Style) Faint() Style {
+ return append(s, faintAttr)
+}
+
+// Italic appends the italic style attribute to the style.
+func (s Style) Italic() Style {
+ return append(s, italicAttr)
+}
+
+// Underline appends the underline style attribute to the style.
+func (s Style) Underline() Style {
+ return append(s, underlineAttr)
+}
+
+// UnderlineStyle appends the underline style attribute to the style.
+func (s Style) UnderlineStyle(u UnderlineStyle) Style {
+ switch u {
+ case NoUnderlineStyle:
+ return s.NoUnderline()
+ case SingleUnderlineStyle:
+ return s.Underline()
+ case DoubleUnderlineStyle:
+ return append(s, doubleUnderlineStyle)
+ case CurlyUnderlineStyle:
+ return append(s, curlyUnderlineStyle)
+ case DottedUnderlineStyle:
+ return append(s, dottedUnderlineStyle)
+ case DashedUnderlineStyle:
+ return append(s, dashedUnderlineStyle)
+ }
+ return s
+}
+
+// DoubleUnderline appends the double underline style attribute to the style.
+// This is a convenience method for UnderlineStyle(DoubleUnderlineStyle).
+func (s Style) DoubleUnderline() Style {
+ return s.UnderlineStyle(DoubleUnderlineStyle)
+}
+
+// CurlyUnderline appends the curly underline style attribute to the style.
+// This is a convenience method for UnderlineStyle(CurlyUnderlineStyle).
+func (s Style) CurlyUnderline() Style {
+ return s.UnderlineStyle(CurlyUnderlineStyle)
+}
+
+// DottedUnderline appends the dotted underline style attribute to the style.
+// This is a convenience method for UnderlineStyle(DottedUnderlineStyle).
+func (s Style) DottedUnderline() Style {
+ return s.UnderlineStyle(DottedUnderlineStyle)
+}
+
+// DashedUnderline appends the dashed underline style attribute to the style.
+// This is a convenience method for UnderlineStyle(DashedUnderlineStyle).
+func (s Style) DashedUnderline() Style {
+ return s.UnderlineStyle(DashedUnderlineStyle)
+}
+
+// SlowBlink appends the slow blink style attribute to the style.
+func (s Style) SlowBlink() Style {
+ return append(s, slowBlinkAttr)
+}
+
+// RapidBlink appends the rapid blink style attribute to the style.
+func (s Style) RapidBlink() Style {
+ return append(s, rapidBlinkAttr)
+}
+
+// Reverse appends the reverse style attribute to the style.
+func (s Style) Reverse() Style {
+ return append(s, reverseAttr)
+}
+
+// Conceal appends the conceal style attribute to the style.
+func (s Style) Conceal() Style {
+ return append(s, concealAttr)
+}
+
+// Strikethrough appends the strikethrough style attribute to the style.
+func (s Style) Strikethrough() Style {
+ return append(s, strikethroughAttr)
+}
+
+// NoBold appends the no bold style attribute to the style.
+func (s Style) NoBold() Style {
+ return append(s, noBoldAttr)
+}
+
+// NormalIntensity appends the normal intensity style attribute to the style.
+func (s Style) NormalIntensity() Style {
+ return append(s, normalIntensityAttr)
+}
+
+// NoItalic appends the no italic style attribute to the style.
+func (s Style) NoItalic() Style {
+ return append(s, noItalicAttr)
+}
+
+// NoUnderline appends the no underline style attribute to the style.
+func (s Style) NoUnderline() Style {
+ return append(s, noUnderlineAttr)
+}
+
+// NoBlink appends the no blink style attribute to the style.
+func (s Style) NoBlink() Style {
+ return append(s, noBlinkAttr)
+}
+
+// NoReverse appends the no reverse style attribute to the style.
+func (s Style) NoReverse() Style {
+ return append(s, noReverseAttr)
+}
+
+// NoConceal appends the no conceal style attribute to the style.
+func (s Style) NoConceal() Style {
+ return append(s, noConcealAttr)
+}
+
+// NoStrikethrough appends the no strikethrough style attribute to the style.
+func (s Style) NoStrikethrough() Style {
+ return append(s, noStrikethroughAttr)
+}
+
+// DefaultForegroundColor appends the default foreground color style attribute to the style.
+func (s Style) DefaultForegroundColor() Style {
+ return append(s, defaultForegroundColorAttr)
+}
+
+// DefaultBackgroundColor appends the default background color style attribute to the style.
+func (s Style) DefaultBackgroundColor() Style {
+ return append(s, defaultBackgroundColorAttr)
+}
+
+// DefaultUnderlineColor appends the default underline color style attribute to the style.
+func (s Style) DefaultUnderlineColor() Style {
+ return append(s, defaultUnderlineColorAttr)
+}
+
+// ForegroundColor appends the foreground color style attribute to the style.
+func (s Style) ForegroundColor(c Color) Style {
+ return append(s, foregroundColorString(c))
+}
+
+// BackgroundColor appends the background color style attribute to the style.
+func (s Style) BackgroundColor(c Color) Style {
+ return append(s, backgroundColorString(c))
+}
+
+// UnderlineColor appends the underline color style attribute to the style.
+func (s Style) UnderlineColor(c Color) Style {
+ return append(s, underlineColorString(c))
+}
+
+// UnderlineStyle represents an ANSI SGR (Select Graphic Rendition) underline
+// style.
+type UnderlineStyle = byte
+
+const (
+ doubleUnderlineStyle = "4:2"
+ curlyUnderlineStyle = "4:3"
+ dottedUnderlineStyle = "4:4"
+ dashedUnderlineStyle = "4:5"
+)
+
+const (
+ // NoUnderlineStyle is the default underline style.
+ NoUnderlineStyle UnderlineStyle = iota
+ // SingleUnderlineStyle is a single underline style.
+ SingleUnderlineStyle
+ // DoubleUnderlineStyle is a double underline style.
+ DoubleUnderlineStyle
+ // CurlyUnderlineStyle is a curly underline style.
+ CurlyUnderlineStyle
+ // DottedUnderlineStyle is a dotted underline style.
+ DottedUnderlineStyle
+ // DashedUnderlineStyle is a dashed underline style.
+ DashedUnderlineStyle
+)
+
+// SGR (Select Graphic Rendition) style attributes.
+// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
+const (
+ ResetAttr Attr = 0
+ BoldAttr Attr = 1
+ FaintAttr Attr = 2
+ ItalicAttr Attr = 3
+ UnderlineAttr Attr = 4
+ SlowBlinkAttr Attr = 5
+ RapidBlinkAttr Attr = 6
+ ReverseAttr Attr = 7
+ ConcealAttr Attr = 8
+ StrikethroughAttr Attr = 9
+ NoBoldAttr Attr = 21 // Some terminals treat this as double underline.
+ NormalIntensityAttr Attr = 22
+ NoItalicAttr Attr = 23
+ NoUnderlineAttr Attr = 24
+ NoBlinkAttr Attr = 25
+ NoReverseAttr Attr = 27
+ NoConcealAttr Attr = 28
+ NoStrikethroughAttr Attr = 29
+ BlackForegroundColorAttr Attr = 30
+ RedForegroundColorAttr Attr = 31
+ GreenForegroundColorAttr Attr = 32
+ YellowForegroundColorAttr Attr = 33
+ BlueForegroundColorAttr Attr = 34
+ MagentaForegroundColorAttr Attr = 35
+ CyanForegroundColorAttr Attr = 36
+ WhiteForegroundColorAttr Attr = 37
+ ExtendedForegroundColorAttr Attr = 38
+ DefaultForegroundColorAttr Attr = 39
+ BlackBackgroundColorAttr Attr = 40
+ RedBackgroundColorAttr Attr = 41
+ GreenBackgroundColorAttr Attr = 42
+ YellowBackgroundColorAttr Attr = 43
+ BlueBackgroundColorAttr Attr = 44
+ MagentaBackgroundColorAttr Attr = 45
+ CyanBackgroundColorAttr Attr = 46
+ WhiteBackgroundColorAttr Attr = 47
+ ExtendedBackgroundColorAttr Attr = 48
+ DefaultBackgroundColorAttr Attr = 49
+ ExtendedUnderlineColorAttr Attr = 58
+ DefaultUnderlineColorAttr Attr = 59
+ BrightBlackForegroundColorAttr Attr = 90
+ BrightRedForegroundColorAttr Attr = 91
+ BrightGreenForegroundColorAttr Attr = 92
+ BrightYellowForegroundColorAttr Attr = 93
+ BrightBlueForegroundColorAttr Attr = 94
+ BrightMagentaForegroundColorAttr Attr = 95
+ BrightCyanForegroundColorAttr Attr = 96
+ BrightWhiteForegroundColorAttr Attr = 97
+ BrightBlackBackgroundColorAttr Attr = 100
+ BrightRedBackgroundColorAttr Attr = 101
+ BrightGreenBackgroundColorAttr Attr = 102
+ BrightYellowBackgroundColorAttr Attr = 103
+ BrightBlueBackgroundColorAttr Attr = 104
+ BrightMagentaBackgroundColorAttr Attr = 105
+ BrightCyanBackgroundColorAttr Attr = 106
+ BrightWhiteBackgroundColorAttr Attr = 107
+
+ RGBColorIntroducerAttr Attr = 2
+ ExtendedColorIntroducerAttr Attr = 5
+)
+
+const (
+ resetAttr = "0"
+ boldAttr = "1"
+ faintAttr = "2"
+ italicAttr = "3"
+ underlineAttr = "4"
+ slowBlinkAttr = "5"
+ rapidBlinkAttr = "6"
+ reverseAttr = "7"
+ concealAttr = "8"
+ strikethroughAttr = "9"
+ noBoldAttr = "21"
+ normalIntensityAttr = "22"
+ noItalicAttr = "23"
+ noUnderlineAttr = "24"
+ noBlinkAttr = "25"
+ noReverseAttr = "27"
+ noConcealAttr = "28"
+ noStrikethroughAttr = "29"
+ blackForegroundColorAttr = "30"
+ redForegroundColorAttr = "31"
+ greenForegroundColorAttr = "32"
+ yellowForegroundColorAttr = "33"
+ blueForegroundColorAttr = "34"
+ magentaForegroundColorAttr = "35"
+ cyanForegroundColorAttr = "36"
+ whiteForegroundColorAttr = "37"
+ extendedForegroundColorAttr = "38"
+ defaultForegroundColorAttr = "39"
+ blackBackgroundColorAttr = "40"
+ redBackgroundColorAttr = "41"
+ greenBackgroundColorAttr = "42"
+ yellowBackgroundColorAttr = "43"
+ blueBackgroundColorAttr = "44"
+ magentaBackgroundColorAttr = "45"
+ cyanBackgroundColorAttr = "46"
+ whiteBackgroundColorAttr = "47"
+ extendedBackgroundColorAttr = "48"
+ defaultBackgroundColorAttr = "49"
+ extendedUnderlineColorAttr = "58"
+ defaultUnderlineColorAttr = "59"
+ brightBlackForegroundColorAttr = "90"
+ brightRedForegroundColorAttr = "91"
+ brightGreenForegroundColorAttr = "92"
+ brightYellowForegroundColorAttr = "93"
+ brightBlueForegroundColorAttr = "94"
+ brightMagentaForegroundColorAttr = "95"
+ brightCyanForegroundColorAttr = "96"
+ brightWhiteForegroundColorAttr = "97"
+ brightBlackBackgroundColorAttr = "100"
+ brightRedBackgroundColorAttr = "101"
+ brightGreenBackgroundColorAttr = "102"
+ brightYellowBackgroundColorAttr = "103"
+ brightBlueBackgroundColorAttr = "104"
+ brightMagentaBackgroundColorAttr = "105"
+ brightCyanBackgroundColorAttr = "106"
+ brightWhiteBackgroundColorAttr = "107"
+)
+
+// foregroundColorString returns the style SGR attribute for the given
+// foreground color.
+// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
+func foregroundColorString(c Color) string {
+ switch c := c.(type) {
+ case BasicColor:
+ // 3-bit or 4-bit ANSI foreground
+ // "3" or "9" where n is the color number from 0 to 7
+ switch c {
+ case Black:
+ return blackForegroundColorAttr
+ case Red:
+ return redForegroundColorAttr
+ case Green:
+ return greenForegroundColorAttr
+ case Yellow:
+ return yellowForegroundColorAttr
+ case Blue:
+ return blueForegroundColorAttr
+ case Magenta:
+ return magentaForegroundColorAttr
+ case Cyan:
+ return cyanForegroundColorAttr
+ case White:
+ return whiteForegroundColorAttr
+ case BrightBlack:
+ return brightBlackForegroundColorAttr
+ case BrightRed:
+ return brightRedForegroundColorAttr
+ case BrightGreen:
+ return brightGreenForegroundColorAttr
+ case BrightYellow:
+ return brightYellowForegroundColorAttr
+ case BrightBlue:
+ return brightBlueForegroundColorAttr
+ case BrightMagenta:
+ return brightMagentaForegroundColorAttr
+ case BrightCyan:
+ return brightCyanForegroundColorAttr
+ case BrightWhite:
+ return brightWhiteForegroundColorAttr
+ }
+ case ExtendedColor:
+ // 256-color ANSI foreground
+ // "38;5;"
+ return "38;5;" + strconv.FormatUint(uint64(c), 10)
+ case TrueColor, color.Color:
+ // 24-bit "true color" foreground
+ // "38;2;;;"
+ r, g, b, _ := c.RGBA()
+ return "38;2;" +
+ strconv.FormatUint(uint64(shift(r)), 10) + ";" +
+ strconv.FormatUint(uint64(shift(g)), 10) + ";" +
+ strconv.FormatUint(uint64(shift(b)), 10)
+ }
+ return defaultForegroundColorAttr
+}
+
+// backgroundColorString returns the style SGR attribute for the given
+// background color.
+// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
+func backgroundColorString(c Color) string {
+ switch c := c.(type) {
+ case BasicColor:
+ // 3-bit or 4-bit ANSI foreground
+ // "4" or "10" where n is the color number from 0 to 7
+ switch c {
+ case Black:
+ return blackBackgroundColorAttr
+ case Red:
+ return redBackgroundColorAttr
+ case Green:
+ return greenBackgroundColorAttr
+ case Yellow:
+ return yellowBackgroundColorAttr
+ case Blue:
+ return blueBackgroundColorAttr
+ case Magenta:
+ return magentaBackgroundColorAttr
+ case Cyan:
+ return cyanBackgroundColorAttr
+ case White:
+ return whiteBackgroundColorAttr
+ case BrightBlack:
+ return brightBlackBackgroundColorAttr
+ case BrightRed:
+ return brightRedBackgroundColorAttr
+ case BrightGreen:
+ return brightGreenBackgroundColorAttr
+ case BrightYellow:
+ return brightYellowBackgroundColorAttr
+ case BrightBlue:
+ return brightBlueBackgroundColorAttr
+ case BrightMagenta:
+ return brightMagentaBackgroundColorAttr
+ case BrightCyan:
+ return brightCyanBackgroundColorAttr
+ case BrightWhite:
+ return brightWhiteBackgroundColorAttr
+ }
+ case ExtendedColor:
+ // 256-color ANSI foreground
+ // "48;5;"
+ return "48;5;" + strconv.FormatUint(uint64(c), 10)
+ case TrueColor, color.Color:
+ // 24-bit "true color" foreground
+ // "38;2;;;"
+ r, g, b, _ := c.RGBA()
+ return "48;2;" +
+ strconv.FormatUint(uint64(shift(r)), 10) + ";" +
+ strconv.FormatUint(uint64(shift(g)), 10) + ";" +
+ strconv.FormatUint(uint64(shift(b)), 10)
+ }
+ return defaultBackgroundColorAttr
+}
+
+// underlineColorString returns the style SGR attribute for the given underline
+// color.
+// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
+func underlineColorString(c Color) string {
+ switch c := c.(type) {
+ // NOTE: we can't use 3-bit and 4-bit ANSI color codes with underline
+ // color, use 256-color instead.
+ //
+ // 256-color ANSI underline color
+ // "58;5;"
+ case BasicColor:
+ return "58;5;" + strconv.FormatUint(uint64(c), 10)
+ case ExtendedColor:
+ return "58;5;" + strconv.FormatUint(uint64(c), 10)
+ case TrueColor, color.Color:
+ // 24-bit "true color" foreground
+ // "38;2;;;"
+ r, g, b, _ := c.RGBA()
+ return "58;2;" +
+ strconv.FormatUint(uint64(shift(r)), 10) + ";" +
+ strconv.FormatUint(uint64(shift(g)), 10) + ";" +
+ strconv.FormatUint(uint64(shift(b)), 10)
+ }
+ return defaultUnderlineColorAttr
+}
+
+// ReadStyleColor decodes a color from a slice of parameters. It returns the
+// number of parameters read and the color. This function is used to read SGR
+// color parameters following the ITU T.416 standard.
+//
+// It supports reading the following color types:
+// - 0: implementation defined
+// - 1: transparent
+// - 2: RGB direct color
+// - 3: CMY direct color
+// - 4: CMYK direct color
+// - 5: indexed color
+// - 6: RGBA direct color (WezTerm extension)
+//
+// The parameters can be separated by semicolons (;) or colons (:). Mixing
+// separators is not allowed.
+//
+// The specs supports defining a color space id, a color tolerance value, and a
+// tolerance color space id. However, these values have no effect on the
+// returned color and will be ignored.
+//
+// This implementation includes a few modifications to the specs:
+// 1. Support for legacy color values separated by semicolons (;) with respect to RGB, and indexed colors
+// 2. Support ignoring and omitting the color space id (second parameter) with respect to RGB colors
+// 3. Support ignoring and omitting the 6th parameter with respect to RGB and CMY colors
+// 4. Support reading RGBA colors
+func ReadStyleColor(params Params, co *color.Color) (n int) {
+ if len(params) < 2 { // Need at least SGR type and color type
+ return 0
+ }
+
+ // First parameter indicates one of 38, 48, or 58 (foreground, background, or underline)
+ s := params[0]
+ p := params[1]
+ colorType := p.Param(0)
+ n = 2
+
+ paramsfn := func() (p1, p2, p3, p4 int) {
+ // Where should we start reading the color?
+ switch {
+ case s.HasMore() && p.HasMore() && len(params) > 8 && params[2].HasMore() && params[3].HasMore() && params[4].HasMore() && params[5].HasMore() && params[6].HasMore() && params[7].HasMore():
+ // We have color space id, a 6th parameter, a tolerance value, and a tolerance color space
+ n += 7
+ return params[3].Param(0), params[4].Param(0), params[5].Param(0), params[6].Param(0)
+ case s.HasMore() && p.HasMore() && len(params) > 7 && params[2].HasMore() && params[3].HasMore() && params[4].HasMore() && params[5].HasMore() && params[6].HasMore():
+ // We have color space id, a 6th parameter, and a tolerance value
+ n += 6
+ return params[3].Param(0), params[4].Param(0), params[5].Param(0), params[6].Param(0)
+ case s.HasMore() && p.HasMore() && len(params) > 6 && params[2].HasMore() && params[3].HasMore() && params[4].HasMore() && params[5].HasMore():
+ // We have color space id and a 6th parameter
+ // 48 : 4 : : 1 : 2 : 3 :4
+ n += 5
+ return params[3].Param(0), params[4].Param(0), params[5].Param(0), params[6].Param(0)
+ case s.HasMore() && p.HasMore() && len(params) > 5 && params[2].HasMore() && params[3].HasMore() && params[4].HasMore() && !params[5].HasMore():
+ // We have color space
+ // 48 : 3 : : 1 : 2 : 3
+ n += 4
+ return params[3].Param(0), params[4].Param(0), params[5].Param(0), -1
+ case s.HasMore() && p.HasMore() && p.Param(0) == 2 && params[2].HasMore() && params[3].HasMore() && !params[4].HasMore():
+ // We have color values separated by colons (:)
+ // 48 : 2 : 1 : 2 : 3
+ fallthrough
+ case !s.HasMore() && !p.HasMore() && p.Param(0) == 2 && !params[2].HasMore() && !params[3].HasMore() && !params[4].HasMore():
+ // Support legacy color values separated by semicolons (;)
+ // 48 ; 2 ; 1 ; 2 ; 3
+ n += 3
+ return params[2].Param(0), params[3].Param(0), params[4].Param(0), -1
+ }
+ // Ambiguous SGR color
+ return -1, -1, -1, -1
+ }
+
+ switch colorType {
+ case 0: // implementation defined
+ return 2
+ case 1: // transparent
+ *co = color.Transparent
+ return 2
+ case 2: // RGB direct color
+ if len(params) < 5 {
+ return 0
+ }
+
+ r, g, b, _ := paramsfn()
+ if r == -1 || g == -1 || b == -1 {
+ return 0
+ }
+
+ *co = color.RGBA{
+ R: uint8(r), //nolint:gosec
+ G: uint8(g), //nolint:gosec
+ B: uint8(b), //nolint:gosec
+ A: 0xff,
+ }
+ return
+
+ case 3: // CMY direct color
+ if len(params) < 5 {
+ return 0
+ }
+
+ c, m, y, _ := paramsfn()
+ if c == -1 || m == -1 || y == -1 {
+ return 0
+ }
+
+ *co = color.CMYK{
+ C: uint8(c), //nolint:gosec
+ M: uint8(m), //nolint:gosec
+ Y: uint8(y), //nolint:gosec
+ K: 0,
+ }
+ return
+
+ case 4: // CMYK direct color
+ if len(params) < 6 {
+ return 0
+ }
+
+ c, m, y, k := paramsfn()
+ if c == -1 || m == -1 || y == -1 || k == -1 {
+ return 0
+ }
+
+ *co = color.CMYK{
+ C: uint8(c), //nolint:gosec
+ M: uint8(m), //nolint:gosec
+ Y: uint8(y), //nolint:gosec
+ K: uint8(k), //nolint:gosec
+ }
+ return
+
+ case 5: // indexed color
+ if len(params) < 3 {
+ return 0
+ }
+ switch {
+ case s.HasMore() && p.HasMore() && !params[2].HasMore():
+ // Colon separated indexed color
+ // 38 : 5 : 234
+ case !s.HasMore() && !p.HasMore() && !params[2].HasMore():
+ // Legacy semicolon indexed color
+ // 38 ; 5 ; 234
+ default:
+ return 0
+ }
+ *co = ExtendedColor(params[2].Param(0)) //nolint:gosec
+ return 3
+
+ case 6: // RGBA direct color
+ if len(params) < 6 {
+ return 0
+ }
+
+ r, g, b, a := paramsfn()
+ if r == -1 || g == -1 || b == -1 || a == -1 {
+ return 0
+ }
+
+ *co = color.RGBA{
+ R: uint8(r), //nolint:gosec
+ G: uint8(g), //nolint:gosec
+ B: uint8(b), //nolint:gosec
+ A: uint8(a), //nolint:gosec
+ }
+ return
+
+ default:
+ return 0
+ }
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/termcap.go b/vendor/github.com/charmbracelet/x/ansi/termcap.go
new file mode 100644
index 00000000..3c5c7da9
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/termcap.go
@@ -0,0 +1,41 @@
+package ansi
+
+import (
+ "encoding/hex"
+ "strings"
+)
+
+// RequestTermcap (XTGETTCAP) requests Termcap/Terminfo strings.
+//
+// DCS + q ST
+//
+// Where is a list of Termcap/Terminfo capabilities, encoded in 2-digit
+// hexadecimals, separated by semicolons.
+//
+// See: https://man7.org/linux/man-pages/man5/terminfo.5.html
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
+func XTGETTCAP(caps ...string) string {
+ if len(caps) == 0 {
+ return ""
+ }
+
+ s := "\x1bP+q"
+ for i, c := range caps {
+ if i > 0 {
+ s += ";"
+ }
+ s += strings.ToUpper(hex.EncodeToString([]byte(c)))
+ }
+
+ return s + "\x1b\\"
+}
+
+// RequestTermcap is an alias for [XTGETTCAP].
+func RequestTermcap(caps ...string) string {
+ return XTGETTCAP(caps...)
+}
+
+// RequestTerminfo is an alias for [XTGETTCAP].
+func RequestTerminfo(caps ...string) string {
+ return XTGETTCAP(caps...)
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/title.go b/vendor/github.com/charmbracelet/x/ansi/title.go
new file mode 100644
index 00000000..8fd8bf98
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/title.go
@@ -0,0 +1,32 @@
+package ansi
+
+// SetIconNameWindowTitle returns a sequence for setting the icon name and
+// window title.
+//
+// OSC 0 ; title ST
+// OSC 0 ; title BEL
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands
+func SetIconNameWindowTitle(s string) string {
+ return "\x1b]0;" + s + "\x07"
+}
+
+// SetIconName returns a sequence for setting the icon name.
+//
+// OSC 1 ; title ST
+// OSC 1 ; title BEL
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands
+func SetIconName(s string) string {
+ return "\x1b]1;" + s + "\x07"
+}
+
+// SetWindowTitle returns a sequence for setting the window title.
+//
+// OSC 2 ; title ST
+// OSC 2 ; title BEL
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands
+func SetWindowTitle(s string) string {
+ return "\x1b]2;" + s + "\x07"
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/truncate.go b/vendor/github.com/charmbracelet/x/ansi/truncate.go
new file mode 100644
index 00000000..1fa3efef
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/truncate.go
@@ -0,0 +1,282 @@
+package ansi
+
+import (
+ "bytes"
+
+ "github.com/charmbracelet/x/ansi/parser"
+ "github.com/mattn/go-runewidth"
+ "github.com/rivo/uniseg"
+)
+
+// Cut the string, without adding any prefix or tail strings. This function is
+// aware of ANSI escape codes and will not break them, and accounts for
+// wide-characters (such as East-Asian characters and emojis). Note that the
+// [left] parameter is inclusive, while [right] isn't.
+// This treats the text as a sequence of graphemes.
+func Cut(s string, left, right int) string {
+ return cut(GraphemeWidth, s, left, right)
+}
+
+// CutWc the string, without adding any prefix or tail strings. This function is
+// aware of ANSI escape codes and will not break them, and accounts for
+// wide-characters (such as East-Asian characters and emojis). Note that the
+// [left] parameter is inclusive, while [right] isn't.
+// This treats the text as a sequence of wide characters and runes.
+func CutWc(s string, left, right int) string {
+ return cut(WcWidth, s, left, right)
+}
+
+func cut(m Method, s string, left, right int) string {
+ if right <= left {
+ return ""
+ }
+
+ truncate := Truncate
+ truncateLeft := TruncateLeft
+ if m == WcWidth {
+ truncate = TruncateWc
+ truncateLeft = TruncateWc
+ }
+
+ if left == 0 {
+ return truncate(s, right, "")
+ }
+ return truncateLeft(Truncate(s, right, ""), left, "")
+}
+
+// Truncate truncates a string to a given length, adding a tail to the end if
+// the string is longer than the given length. This function is aware of ANSI
+// escape codes and will not break them, and accounts for wide-characters (such
+// as East-Asian characters and emojis).
+// This treats the text as a sequence of graphemes.
+func Truncate(s string, length int, tail string) string {
+ return truncate(GraphemeWidth, s, length, tail)
+}
+
+// TruncateWc truncates a string to a given length, adding a tail to the end if
+// the string is longer than the given length. This function is aware of ANSI
+// escape codes and will not break them, and accounts for wide-characters (such
+// as East-Asian characters and emojis).
+// This treats the text as a sequence of wide characters and runes.
+func TruncateWc(s string, length int, tail string) string {
+ return truncate(WcWidth, s, length, tail)
+}
+
+func truncate(m Method, s string, length int, tail string) string {
+ if sw := StringWidth(s); sw <= length {
+ return s
+ }
+
+ tw := StringWidth(tail)
+ length -= tw
+ if length < 0 {
+ return ""
+ }
+
+ var cluster []byte
+ var buf bytes.Buffer
+ curWidth := 0
+ ignoring := false
+ pstate := parser.GroundState // initial state
+ b := []byte(s)
+ i := 0
+
+ // Here we iterate over the bytes of the string and collect printable
+ // characters and runes. We also keep track of the width of the string
+ // in cells.
+ //
+ // Once we reach the given length, we start ignoring characters and only
+ // collect ANSI escape codes until we reach the end of string.
+ for i < len(b) {
+ state, action := parser.Table.Transition(pstate, b[i])
+ if state == parser.Utf8State {
+ // This action happens when we transition to the Utf8State.
+ var width int
+ cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1)
+ if m == WcWidth {
+ width = runewidth.StringWidth(string(cluster))
+ }
+
+ // increment the index by the length of the cluster
+ i += len(cluster)
+
+ // Are we ignoring? Skip to the next byte
+ if ignoring {
+ continue
+ }
+
+ // Is this gonna be too wide?
+ // If so write the tail and stop collecting.
+ if curWidth+width > length && !ignoring {
+ ignoring = true
+ buf.WriteString(tail)
+ }
+
+ if curWidth+width > length {
+ continue
+ }
+
+ curWidth += width
+ buf.Write(cluster)
+
+ // Done collecting, now we're back in the ground state.
+ pstate = parser.GroundState
+ continue
+ }
+
+ switch action {
+ case parser.PrintAction:
+ // Is this gonna be too wide?
+ // If so write the tail and stop collecting.
+ if curWidth >= length && !ignoring {
+ ignoring = true
+ buf.WriteString(tail)
+ }
+
+ // Skip to the next byte if we're ignoring
+ if ignoring {
+ i++
+ continue
+ }
+
+ // collects printable ASCII
+ curWidth++
+ fallthrough
+ default:
+ buf.WriteByte(b[i])
+ i++
+ }
+
+ // Transition to the next state.
+ pstate = state
+
+ // Once we reach the given length, we start ignoring runes and write
+ // the tail to the buffer.
+ if curWidth > length && !ignoring {
+ ignoring = true
+ buf.WriteString(tail)
+ }
+ }
+
+ return buf.String()
+}
+
+// TruncateLeft truncates a string from the left side by removing n characters,
+// adding a prefix to the beginning if the string is longer than n.
+// This function is aware of ANSI escape codes and will not break them, and
+// accounts for wide-characters (such as East-Asian characters and emojis).
+// This treats the text as a sequence of graphemes.
+func TruncateLeft(s string, n int, prefix string) string {
+ return truncateLeft(GraphemeWidth, s, n, prefix)
+}
+
+// TruncateLeftWc truncates a string from the left side by removing n characters,
+// adding a prefix to the beginning if the string is longer than n.
+// This function is aware of ANSI escape codes and will not break them, and
+// accounts for wide-characters (such as East-Asian characters and emojis).
+// This treats the text as a sequence of wide characters and runes.
+func TruncateLeftWc(s string, n int, prefix string) string {
+ return truncateLeft(WcWidth, s, n, prefix)
+}
+
+func truncateLeft(m Method, s string, n int, prefix string) string {
+ if n <= 0 {
+ return s
+ }
+
+ var cluster []byte
+ var buf bytes.Buffer
+ curWidth := 0
+ ignoring := true
+ pstate := parser.GroundState
+ b := []byte(s)
+ i := 0
+
+ for i < len(b) {
+ if !ignoring {
+ buf.Write(b[i:])
+ break
+ }
+
+ state, action := parser.Table.Transition(pstate, b[i])
+ if state == parser.Utf8State {
+ var width int
+ cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1)
+ if m == WcWidth {
+ width = runewidth.StringWidth(string(cluster))
+ }
+
+ i += len(cluster)
+ curWidth += width
+
+ if curWidth > n && ignoring {
+ ignoring = false
+ buf.WriteString(prefix)
+ }
+
+ if ignoring {
+ continue
+ }
+
+ if curWidth > n {
+ buf.Write(cluster)
+ }
+
+ pstate = parser.GroundState
+ continue
+ }
+
+ switch action {
+ case parser.PrintAction:
+ curWidth++
+
+ if curWidth > n && ignoring {
+ ignoring = false
+ buf.WriteString(prefix)
+ }
+
+ if ignoring {
+ i++
+ continue
+ }
+
+ fallthrough
+ default:
+ buf.WriteByte(b[i])
+ i++
+ }
+
+ pstate = state
+ if curWidth > n && ignoring {
+ ignoring = false
+ buf.WriteString(prefix)
+ }
+ }
+
+ return buf.String()
+}
+
+// ByteToGraphemeRange takes start and stop byte positions and converts them to
+// grapheme-aware char positions.
+// You can use this with [Truncate], [TruncateLeft], and [Cut].
+func ByteToGraphemeRange(str string, byteStart, byteStop int) (charStart, charStop int) {
+ bytePos, charPos := 0, 0
+ gr := uniseg.NewGraphemes(str)
+ for byteStart > bytePos {
+ if !gr.Next() {
+ break
+ }
+ bytePos += len(gr.Str())
+ charPos += max(1, gr.Width())
+ }
+ charStart = charPos
+ for byteStop > bytePos {
+ if !gr.Next() {
+ break
+ }
+ bytePos += len(gr.Str())
+ charPos += max(1, gr.Width())
+ }
+ charStop = charPos
+ return
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/util.go b/vendor/github.com/charmbracelet/x/ansi/util.go
new file mode 100644
index 00000000..301ef15f
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/util.go
@@ -0,0 +1,106 @@
+package ansi
+
+import (
+ "fmt"
+ "image/color"
+ "strconv"
+ "strings"
+
+ "github.com/lucasb-eyer/go-colorful"
+)
+
+// colorToHexString returns a hex string representation of a color.
+func colorToHexString(c color.Color) string {
+ if c == nil {
+ return ""
+ }
+ shift := func(v uint32) uint32 {
+ if v > 0xff {
+ return v >> 8
+ }
+ return v
+ }
+ r, g, b, _ := c.RGBA()
+ r, g, b = shift(r), shift(g), shift(b)
+ return fmt.Sprintf("#%02x%02x%02x", r, g, b)
+}
+
+// rgbToHex converts red, green, and blue values to a hexadecimal value.
+//
+// hex := rgbToHex(0, 0, 255) // 0x0000FF
+func rgbToHex(r, g, b uint32) uint32 {
+ return r<<16 + g<<8 + b
+}
+
+type shiftable interface {
+ ~uint | ~uint16 | ~uint32 | ~uint64
+}
+
+func shift[T shiftable](x T) T {
+ if x > 0xff {
+ x >>= 8
+ }
+ return x
+}
+
+// XParseColor is a helper function that parses a string into a color.Color. It
+// provides a similar interface to the XParseColor function in Xlib. It
+// supports the following formats:
+//
+// - #RGB
+// - #RRGGBB
+// - rgb:RRRR/GGGG/BBBB
+// - rgba:RRRR/GGGG/BBBB/AAAA
+//
+// If the string is not a valid color, nil is returned.
+//
+// See: https://linux.die.net/man/3/xparsecolor
+func XParseColor(s string) color.Color {
+ switch {
+ case strings.HasPrefix(s, "#"):
+ c, err := colorful.Hex(s)
+ if err != nil {
+ return nil
+ }
+
+ return c
+ case strings.HasPrefix(s, "rgb:"):
+ parts := strings.Split(s[4:], "/")
+ if len(parts) != 3 {
+ return nil
+ }
+
+ r, _ := strconv.ParseUint(parts[0], 16, 32)
+ g, _ := strconv.ParseUint(parts[1], 16, 32)
+ b, _ := strconv.ParseUint(parts[2], 16, 32)
+
+ return color.RGBA{uint8(shift(r)), uint8(shift(g)), uint8(shift(b)), 255} //nolint:gosec
+ case strings.HasPrefix(s, "rgba:"):
+ parts := strings.Split(s[5:], "/")
+ if len(parts) != 4 {
+ return nil
+ }
+
+ r, _ := strconv.ParseUint(parts[0], 16, 32)
+ g, _ := strconv.ParseUint(parts[1], 16, 32)
+ b, _ := strconv.ParseUint(parts[2], 16, 32)
+ a, _ := strconv.ParseUint(parts[3], 16, 32)
+
+ return color.RGBA{uint8(shift(r)), uint8(shift(g)), uint8(shift(b)), uint8(shift(a))} //nolint:gosec
+ }
+ return nil
+}
+
+type ordered interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64 |
+ ~string
+}
+
+func max[T ordered](a, b T) T { //nolint:predeclared
+ if a > b {
+ return a
+ }
+ return b
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/width.go b/vendor/github.com/charmbracelet/x/ansi/width.go
new file mode 100644
index 00000000..d0487d35
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/width.go
@@ -0,0 +1,113 @@
+package ansi
+
+import (
+ "bytes"
+
+ "github.com/charmbracelet/x/ansi/parser"
+ "github.com/mattn/go-runewidth"
+ "github.com/rivo/uniseg"
+)
+
+// Strip removes ANSI escape codes from a string.
+func Strip(s string) string {
+ var (
+ buf bytes.Buffer // buffer for collecting printable characters
+ ri int // rune index
+ rw int // rune width
+ pstate = parser.GroundState // initial state
+ )
+
+ // This implements a subset of the Parser to only collect runes and
+ // printable characters.
+ for i := 0; i < len(s); i++ {
+ if pstate == parser.Utf8State {
+ // During this state, collect rw bytes to form a valid rune in the
+ // buffer. After getting all the rune bytes into the buffer,
+ // transition to GroundState and reset the counters.
+ buf.WriteByte(s[i])
+ ri++
+ if ri < rw {
+ continue
+ }
+ pstate = parser.GroundState
+ ri = 0
+ rw = 0
+ continue
+ }
+
+ state, action := parser.Table.Transition(pstate, s[i])
+ switch action {
+ case parser.CollectAction:
+ if state == parser.Utf8State {
+ // This action happens when we transition to the Utf8State.
+ rw = utf8ByteLen(s[i])
+ buf.WriteByte(s[i])
+ ri++
+ }
+ case parser.PrintAction, parser.ExecuteAction:
+ // collects printable ASCII and non-printable characters
+ buf.WriteByte(s[i])
+ }
+
+ // Transition to the next state.
+ // The Utf8State is managed separately above.
+ if pstate != parser.Utf8State {
+ pstate = state
+ }
+ }
+
+ return buf.String()
+}
+
+// StringWidth returns the width of a string in cells. This is the number of
+// cells that the string will occupy when printed in a terminal. ANSI escape
+// codes are ignored and wide characters (such as East Asians and emojis) are
+// accounted for.
+// This treats the text as a sequence of grapheme clusters.
+func StringWidth(s string) int {
+ return stringWidth(GraphemeWidth, s)
+}
+
+// StringWidthWc returns the width of a string in cells. This is the number of
+// cells that the string will occupy when printed in a terminal. ANSI escape
+// codes are ignored and wide characters (such as East Asians and emojis) are
+// accounted for.
+// This treats the text as a sequence of wide characters and runes.
+func StringWidthWc(s string) int {
+ return stringWidth(WcWidth, s)
+}
+
+func stringWidth(m Method, s string) int {
+ if s == "" {
+ return 0
+ }
+
+ var (
+ pstate = parser.GroundState // initial state
+ cluster string
+ width int
+ )
+
+ for i := 0; i < len(s); i++ {
+ state, action := parser.Table.Transition(pstate, s[i])
+ if state == parser.Utf8State {
+ var w int
+ cluster, _, w, _ = uniseg.FirstGraphemeClusterInString(s[i:], -1)
+ if m == WcWidth {
+ w = runewidth.StringWidth(cluster)
+ }
+ width += w
+ i += len(cluster) - 1
+ pstate = parser.GroundState
+ continue
+ }
+
+ if action == parser.PrintAction {
+ width++
+ }
+
+ pstate = state
+ }
+
+ return width
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/winop.go b/vendor/github.com/charmbracelet/x/ansi/winop.go
new file mode 100644
index 00000000..0238780d
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/winop.go
@@ -0,0 +1,53 @@
+package ansi
+
+import (
+ "strconv"
+ "strings"
+)
+
+const (
+ // ResizeWindowWinOp is a window operation that resizes the terminal
+ // window.
+ ResizeWindowWinOp = 4
+
+ // RequestWindowSizeWinOp is a window operation that requests a report of
+ // the size of the terminal window in pixels. The response is in the form:
+ // CSI 4 ; height ; width t
+ RequestWindowSizeWinOp = 14
+
+ // RequestCellSizeWinOp is a window operation that requests a report of
+ // the size of the terminal cell size in pixels. The response is in the form:
+ // CSI 6 ; height ; width t
+ RequestCellSizeWinOp = 16
+)
+
+// WindowOp (XTWINOPS) is a sequence that manipulates the terminal window.
+//
+// CSI Ps ; Ps ; Ps t
+//
+// Ps is a semicolon-separated list of parameters.
+// See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps;Ps;Ps-t.1EB0
+func WindowOp(p int, ps ...int) string {
+ if p <= 0 {
+ return ""
+ }
+
+ if len(ps) == 0 {
+ return "\x1b[" + strconv.Itoa(p) + "t"
+ }
+
+ params := make([]string, 0, len(ps)+1)
+ params = append(params, strconv.Itoa(p))
+ for _, p := range ps {
+ if p >= 0 {
+ params = append(params, strconv.Itoa(p))
+ }
+ }
+
+ return "\x1b[" + strings.Join(params, ";") + "t"
+}
+
+// XTWINOPS is an alias for [WindowOp].
+func XTWINOPS(p int, ps ...int) string {
+ return WindowOp(p, ps...)
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/wrap.go b/vendor/github.com/charmbracelet/x/ansi/wrap.go
new file mode 100644
index 00000000..6b995800
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/wrap.go
@@ -0,0 +1,467 @@
+package ansi
+
+import (
+ "bytes"
+ "unicode"
+ "unicode/utf8"
+
+ "github.com/charmbracelet/x/ansi/parser"
+ "github.com/mattn/go-runewidth"
+ "github.com/rivo/uniseg"
+)
+
+// nbsp is a non-breaking space
+const nbsp = 0xA0
+
+// Hardwrap wraps a string or a block of text to a given line length, breaking
+// word boundaries. This will preserve ANSI escape codes and will account for
+// wide-characters in the string.
+// When preserveSpace is true, spaces at the beginning of a line will be
+// preserved.
+// This treats the text as a sequence of graphemes.
+func Hardwrap(s string, limit int, preserveSpace bool) string {
+ return hardwrap(GraphemeWidth, s, limit, preserveSpace)
+}
+
+// HardwrapWc wraps a string or a block of text to a given line length, breaking
+// word boundaries. This will preserve ANSI escape codes and will account for
+// wide-characters in the string.
+// When preserveSpace is true, spaces at the beginning of a line will be
+// preserved.
+// This treats the text as a sequence of wide characters and runes.
+func HardwrapWc(s string, limit int, preserveSpace bool) string {
+ return hardwrap(WcWidth, s, limit, preserveSpace)
+}
+
+func hardwrap(m Method, s string, limit int, preserveSpace bool) string {
+ if limit < 1 {
+ return s
+ }
+
+ var (
+ cluster []byte
+ buf bytes.Buffer
+ curWidth int
+ forceNewline bool
+ pstate = parser.GroundState // initial state
+ b = []byte(s)
+ )
+
+ addNewline := func() {
+ buf.WriteByte('\n')
+ curWidth = 0
+ }
+
+ i := 0
+ for i < len(b) {
+ state, action := parser.Table.Transition(pstate, b[i])
+ if state == parser.Utf8State {
+ var width int
+ cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1)
+ if m == WcWidth {
+ width = runewidth.StringWidth(string(cluster))
+ }
+ i += len(cluster)
+
+ if curWidth+width > limit {
+ addNewline()
+ }
+ if !preserveSpace && curWidth == 0 && len(cluster) <= 4 {
+ // Skip spaces at the beginning of a line
+ if r, _ := utf8.DecodeRune(cluster); r != utf8.RuneError && unicode.IsSpace(r) {
+ pstate = parser.GroundState
+ continue
+ }
+ }
+
+ buf.Write(cluster)
+ curWidth += width
+ pstate = parser.GroundState
+ continue
+ }
+
+ switch action {
+ case parser.PrintAction, parser.ExecuteAction:
+ if b[i] == '\n' {
+ addNewline()
+ forceNewline = false
+ break
+ }
+
+ if curWidth+1 > limit {
+ addNewline()
+ forceNewline = true
+ }
+
+ // Skip spaces at the beginning of a line
+ if curWidth == 0 {
+ if !preserveSpace && forceNewline && unicode.IsSpace(rune(b[i])) {
+ break
+ }
+ forceNewline = false
+ }
+
+ buf.WriteByte(b[i])
+ if action == parser.PrintAction {
+ curWidth++
+ }
+ default:
+ buf.WriteByte(b[i])
+ }
+
+ // We manage the UTF8 state separately manually above.
+ if pstate != parser.Utf8State {
+ pstate = state
+ }
+ i++
+ }
+
+ return buf.String()
+}
+
+// Wordwrap wraps a string or a block of text to a given line length, not
+// breaking word boundaries. This will preserve ANSI escape codes and will
+// account for wide-characters in the string.
+// The breakpoints string is a list of characters that are considered
+// breakpoints for word wrapping. A hyphen (-) is always considered a
+// breakpoint.
+//
+// Note: breakpoints must be a string of 1-cell wide rune characters.
+//
+// This treats the text as a sequence of graphemes.
+func Wordwrap(s string, limit int, breakpoints string) string {
+ return wordwrap(GraphemeWidth, s, limit, breakpoints)
+}
+
+// WordwrapWc wraps a string or a block of text to a given line length, not
+// breaking word boundaries. This will preserve ANSI escape codes and will
+// account for wide-characters in the string.
+// The breakpoints string is a list of characters that are considered
+// breakpoints for word wrapping. A hyphen (-) is always considered a
+// breakpoint.
+//
+// Note: breakpoints must be a string of 1-cell wide rune characters.
+//
+// This treats the text as a sequence of wide characters and runes.
+func WordwrapWc(s string, limit int, breakpoints string) string {
+ return wordwrap(WcWidth, s, limit, breakpoints)
+}
+
+func wordwrap(m Method, s string, limit int, breakpoints string) string {
+ if limit < 1 {
+ return s
+ }
+
+ var (
+ cluster []byte
+ buf bytes.Buffer
+ word bytes.Buffer
+ space bytes.Buffer
+ curWidth int
+ wordLen int
+ pstate = parser.GroundState // initial state
+ b = []byte(s)
+ )
+
+ addSpace := func() {
+ curWidth += space.Len()
+ buf.Write(space.Bytes())
+ space.Reset()
+ }
+
+ addWord := func() {
+ if word.Len() == 0 {
+ return
+ }
+
+ addSpace()
+ curWidth += wordLen
+ buf.Write(word.Bytes())
+ word.Reset()
+ wordLen = 0
+ }
+
+ addNewline := func() {
+ buf.WriteByte('\n')
+ curWidth = 0
+ space.Reset()
+ }
+
+ i := 0
+ for i < len(b) {
+ state, action := parser.Table.Transition(pstate, b[i])
+ if state == parser.Utf8State {
+ var width int
+ cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1)
+ if m == WcWidth {
+ width = runewidth.StringWidth(string(cluster))
+ }
+ i += len(cluster)
+
+ r, _ := utf8.DecodeRune(cluster)
+ if r != utf8.RuneError && unicode.IsSpace(r) && r != nbsp {
+ addWord()
+ space.WriteRune(r)
+ } else if bytes.ContainsAny(cluster, breakpoints) {
+ addSpace()
+ addWord()
+ buf.Write(cluster)
+ curWidth++
+ } else {
+ word.Write(cluster)
+ wordLen += width
+ if curWidth+space.Len()+wordLen > limit &&
+ wordLen < limit {
+ addNewline()
+ }
+ }
+
+ pstate = parser.GroundState
+ continue
+ }
+
+ switch action {
+ case parser.PrintAction, parser.ExecuteAction:
+ r := rune(b[i])
+ switch {
+ case r == '\n':
+ if wordLen == 0 {
+ if curWidth+space.Len() > limit {
+ curWidth = 0
+ } else {
+ buf.Write(space.Bytes())
+ }
+ space.Reset()
+ }
+
+ addWord()
+ addNewline()
+ case unicode.IsSpace(r):
+ addWord()
+ space.WriteByte(b[i])
+ case r == '-':
+ fallthrough
+ case runeContainsAny(r, breakpoints):
+ addSpace()
+ addWord()
+ buf.WriteByte(b[i])
+ curWidth++
+ default:
+ word.WriteByte(b[i])
+ wordLen++
+ if curWidth+space.Len()+wordLen > limit &&
+ wordLen < limit {
+ addNewline()
+ }
+ }
+
+ default:
+ word.WriteByte(b[i])
+ }
+
+ // We manage the UTF8 state separately manually above.
+ if pstate != parser.Utf8State {
+ pstate = state
+ }
+ i++
+ }
+
+ addWord()
+
+ return buf.String()
+}
+
+// Wrap wraps a string or a block of text to a given line length, breaking word
+// boundaries if necessary. This will preserve ANSI escape codes and will
+// account for wide-characters in the string. The breakpoints string is a list
+// of characters that are considered breakpoints for word wrapping. A hyphen
+// (-) is always considered a breakpoint.
+//
+// Note: breakpoints must be a string of 1-cell wide rune characters.
+//
+// This treats the text as a sequence of graphemes.
+func Wrap(s string, limit int, breakpoints string) string {
+ return wrap(GraphemeWidth, s, limit, breakpoints)
+}
+
+// WrapWc wraps a string or a block of text to a given line length, breaking word
+// boundaries if necessary. This will preserve ANSI escape codes and will
+// account for wide-characters in the string. The breakpoints string is a list
+// of characters that are considered breakpoints for word wrapping. A hyphen
+// (-) is always considered a breakpoint.
+//
+// Note: breakpoints must be a string of 1-cell wide rune characters.
+//
+// This treats the text as a sequence of wide characters and runes.
+func WrapWc(s string, limit int, breakpoints string) string {
+ return wrap(WcWidth, s, limit, breakpoints)
+}
+
+func wrap(m Method, s string, limit int, breakpoints string) string {
+ if limit < 1 {
+ return s
+ }
+
+ var (
+ cluster []byte
+ buf bytes.Buffer
+ word bytes.Buffer
+ space bytes.Buffer
+ curWidth int // written width of the line
+ wordLen int // word buffer len without ANSI escape codes
+ pstate = parser.GroundState // initial state
+ b = []byte(s)
+ )
+
+ addSpace := func() {
+ curWidth += space.Len()
+ buf.Write(space.Bytes())
+ space.Reset()
+ }
+
+ addWord := func() {
+ if word.Len() == 0 {
+ return
+ }
+
+ addSpace()
+ curWidth += wordLen
+ buf.Write(word.Bytes())
+ word.Reset()
+ wordLen = 0
+ }
+
+ addNewline := func() {
+ buf.WriteByte('\n')
+ curWidth = 0
+ space.Reset()
+ }
+
+ i := 0
+ for i < len(b) {
+ state, action := parser.Table.Transition(pstate, b[i])
+ if state == parser.Utf8State {
+ var width int
+ cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1)
+ if m == WcWidth {
+ width = runewidth.StringWidth(string(cluster))
+ }
+ i += len(cluster)
+
+ r, _ := utf8.DecodeRune(cluster)
+ switch {
+ case r != utf8.RuneError && unicode.IsSpace(r) && r != nbsp: // nbsp is a non-breaking space
+ addWord()
+ space.WriteRune(r)
+ case bytes.ContainsAny(cluster, breakpoints):
+ addSpace()
+ if curWidth+wordLen+width > limit {
+ word.Write(cluster)
+ wordLen += width
+ } else {
+ addWord()
+ buf.Write(cluster)
+ curWidth += width
+ }
+ default:
+ if wordLen+width > limit {
+ // Hardwrap the word if it's too long
+ addWord()
+ }
+
+ word.Write(cluster)
+ wordLen += width
+
+ if curWidth+wordLen+space.Len() > limit {
+ addNewline()
+ }
+ }
+
+ pstate = parser.GroundState
+ continue
+ }
+
+ switch action {
+ case parser.PrintAction, parser.ExecuteAction:
+ switch r := rune(b[i]); {
+ case r == '\n':
+ if wordLen == 0 {
+ if curWidth+space.Len() > limit {
+ curWidth = 0
+ } else {
+ // preserve whitespaces
+ buf.Write(space.Bytes())
+ }
+ space.Reset()
+ }
+
+ addWord()
+ addNewline()
+ case unicode.IsSpace(r):
+ addWord()
+ space.WriteRune(r)
+ case r == '-':
+ fallthrough
+ case runeContainsAny(r, breakpoints):
+ addSpace()
+ if curWidth+wordLen >= limit {
+ // We can't fit the breakpoint in the current line, treat
+ // it as part of the word.
+ word.WriteRune(r)
+ wordLen++
+ } else {
+ addWord()
+ buf.WriteRune(r)
+ curWidth++
+ }
+ default:
+ if curWidth == limit {
+ addNewline()
+ }
+ word.WriteRune(r)
+ wordLen++
+
+ if wordLen == limit {
+ // Hardwrap the word if it's too long
+ addWord()
+ }
+
+ if curWidth+wordLen+space.Len() > limit {
+ addNewline()
+ }
+ }
+
+ default:
+ word.WriteByte(b[i])
+ }
+
+ // We manage the UTF8 state separately manually above.
+ if pstate != parser.Utf8State {
+ pstate = state
+ }
+ i++
+ }
+
+ if wordLen == 0 {
+ if curWidth+space.Len() > limit {
+ curWidth = 0
+ } else {
+ // preserve whitespaces
+ buf.Write(space.Bytes())
+ }
+ space.Reset()
+ }
+
+ addWord()
+
+ return buf.String()
+}
+
+func runeContainsAny(r rune, s string) bool {
+ for _, c := range s {
+ if c == r {
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/charmbracelet/x/ansi/xterm.go b/vendor/github.com/charmbracelet/x/ansi/xterm.go
new file mode 100644
index 00000000..83fd4bdc
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/ansi/xterm.go
@@ -0,0 +1,138 @@
+package ansi
+
+import "strconv"
+
+// KeyModifierOptions (XTMODKEYS) sets/resets xterm key modifier options.
+//
+// Default is 0.
+//
+// CSI > Pp m
+// CSI > Pp ; Pv m
+//
+// If Pv is omitted, the resource is reset to its initial value.
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
+func KeyModifierOptions(p int, vs ...int) string {
+ var pp, pv string
+ if p > 0 {
+ pp = strconv.Itoa(p)
+ }
+
+ if len(vs) == 0 {
+ return "\x1b[>" + strconv.Itoa(p) + "m"
+ }
+
+ v := vs[0]
+ if v > 0 {
+ pv = strconv.Itoa(v)
+ return "\x1b[>" + pp + ";" + pv + "m"
+ }
+
+ return "\x1b[>" + pp + "m"
+}
+
+// XTMODKEYS is an alias for [KeyModifierOptions].
+func XTMODKEYS(p int, vs ...int) string {
+ return KeyModifierOptions(p, vs...)
+}
+
+// SetKeyModifierOptions sets xterm key modifier options.
+// This is an alias for [KeyModifierOptions].
+func SetKeyModifierOptions(pp int, pv int) string {
+ return KeyModifierOptions(pp, pv)
+}
+
+// ResetKeyModifierOptions resets xterm key modifier options.
+// This is an alias for [KeyModifierOptions].
+func ResetKeyModifierOptions(pp int) string {
+ return KeyModifierOptions(pp)
+}
+
+// QueryKeyModifierOptions (XTQMODKEYS) requests xterm key modifier options.
+//
+// Default is 0.
+//
+// CSI ? Pp m
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
+func QueryKeyModifierOptions(pp int) string {
+ var p string
+ if pp > 0 {
+ p = strconv.Itoa(pp)
+ }
+ return "\x1b[?" + p + "m"
+}
+
+// XTQMODKEYS is an alias for [QueryKeyModifierOptions].
+func XTQMODKEYS(pp int) string {
+ return QueryKeyModifierOptions(pp)
+}
+
+// Modify Other Keys (modifyOtherKeys) is an xterm feature that allows the
+// terminal to modify the behavior of certain keys to send different escape
+// sequences when pressed.
+//
+// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
+const (
+ SetModifyOtherKeys1 = "\x1b[>4;1m"
+ SetModifyOtherKeys2 = "\x1b[>4;2m"
+ ResetModifyOtherKeys = "\x1b[>4m"
+ QueryModifyOtherKeys = "\x1b[?4m"
+)
+
+// ModifyOtherKeys returns a sequence that sets XTerm modifyOtherKeys mode.
+// The mode argument specifies the mode to set.
+//
+// 0: Disable modifyOtherKeys mode.
+// 1: Enable modifyOtherKeys mode 1.
+// 2: Enable modifyOtherKeys mode 2.
+//
+// CSI > 4 ; mode m
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
+// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
+//
+// Deprecated: use [SetModifyOtherKeys1] or [SetModifyOtherKeys2] instead.
+func ModifyOtherKeys(mode int) string {
+ return "\x1b[>4;" + strconv.Itoa(mode) + "m"
+}
+
+// DisableModifyOtherKeys disables the modifyOtherKeys mode.
+//
+// CSI > 4 ; 0 m
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
+// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
+//
+// Deprecated: use [ResetModifyOtherKeys] instead.
+const DisableModifyOtherKeys = "\x1b[>4;0m"
+
+// EnableModifyOtherKeys1 enables the modifyOtherKeys mode 1.
+//
+// CSI > 4 ; 1 m
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
+// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
+//
+// Deprecated: use [SetModifyOtherKeys1] instead.
+const EnableModifyOtherKeys1 = "\x1b[>4;1m"
+
+// EnableModifyOtherKeys2 enables the modifyOtherKeys mode 2.
+//
+// CSI > 4 ; 2 m
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
+// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
+//
+// Deprecated: use [SetModifyOtherKeys2] instead.
+const EnableModifyOtherKeys2 = "\x1b[>4;2m"
+
+// RequestModifyOtherKeys requests the modifyOtherKeys mode.
+//
+// CSI ? 4 m
+//
+// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
+// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
+//
+// Deprecated: use [QueryModifyOtherKeys] instead.
+const RequestModifyOtherKeys = "\x1b[?4m"
diff --git a/vendor/github.com/charmbracelet/x/cellbuf/BUILD.bazel b/vendor/github.com/charmbracelet/x/cellbuf/BUILD.bazel
new file mode 100644
index 00000000..eb7222be
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/cellbuf/BUILD.bazel
@@ -0,0 +1,31 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "buffer.go",
+ "cell.go",
+ "errors.go",
+ "geom.go",
+ "hardscroll.go",
+ "hashmap.go",
+ "link.go",
+ "screen.go",
+ "sequence.go",
+ "style.go",
+ "tabstop.go",
+ "utils.go",
+ "wrap.go",
+ "writer.go",
+ ],
+ importmap = "github.com/kindlyops/vbs/vendor/github.com/charmbracelet/x/cellbuf",
+ importpath = "github.com/charmbracelet/x/cellbuf",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//vendor/github.com/charmbracelet/colorprofile:go_default_library",
+ "//vendor/github.com/charmbracelet/x/ansi:go_default_library",
+ "//vendor/github.com/charmbracelet/x/term:go_default_library",
+ "//vendor/github.com/mattn/go-runewidth:go_default_library",
+ "//vendor/github.com/rivo/uniseg:go_default_library",
+ ],
+)
diff --git a/vendor/github.com/charmbracelet/x/cellbuf/LICENSE b/vendor/github.com/charmbracelet/x/cellbuf/LICENSE
new file mode 100644
index 00000000..65a5654e
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/cellbuf/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Charmbracelet, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/charmbracelet/x/cellbuf/buffer.go b/vendor/github.com/charmbracelet/x/cellbuf/buffer.go
new file mode 100644
index 00000000..790d1f7c
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/cellbuf/buffer.go
@@ -0,0 +1,473 @@
+package cellbuf
+
+import (
+ "strings"
+
+ "github.com/mattn/go-runewidth"
+ "github.com/rivo/uniseg"
+)
+
+// NewCell returns a new cell. This is a convenience function that initializes a
+// new cell with the given content. The cell's width is determined by the
+// content using [runewidth.RuneWidth].
+// This will only account for the first combined rune in the content. If the
+// content is empty, it will return an empty cell with a width of 0.
+func NewCell(r rune, comb ...rune) (c *Cell) {
+ c = new(Cell)
+ c.Rune = r
+ c.Width = runewidth.RuneWidth(r)
+ for _, r := range comb {
+ if runewidth.RuneWidth(r) > 0 {
+ break
+ }
+ c.Comb = append(c.Comb, r)
+ }
+ c.Comb = comb
+ c.Width = runewidth.StringWidth(string(append([]rune{r}, comb...)))
+ return
+}
+
+// NewCellString returns a new cell with the given string content. This is a
+// convenience function that initializes a new cell with the given content. The
+// cell's width is determined by the content using [runewidth.StringWidth].
+// This will only use the first combined rune in the string. If the string is
+// empty, it will return an empty cell with a width of 0.
+func NewCellString(s string) (c *Cell) {
+ c = new(Cell)
+ for i, r := range s {
+ if i == 0 {
+ c.Rune = r
+ // We only care about the first rune's width
+ c.Width = runewidth.RuneWidth(r)
+ } else {
+ if runewidth.RuneWidth(r) > 0 {
+ break
+ }
+ c.Comb = append(c.Comb, r)
+ }
+ }
+ return
+}
+
+// NewGraphemeCell returns a new cell. This is a convenience function that
+// initializes a new cell with the given content. The cell's width is determined
+// by the content using [uniseg.FirstGraphemeClusterInString].
+// This is used when the content is a grapheme cluster i.e. a sequence of runes
+// that form a single visual unit.
+// This will only return the first grapheme cluster in the string. If the
+// string is empty, it will return an empty cell with a width of 0.
+func NewGraphemeCell(s string) (c *Cell) {
+ g, _, w, _ := uniseg.FirstGraphemeClusterInString(s, -1)
+ return newGraphemeCell(g, w)
+}
+
+func newGraphemeCell(s string, w int) (c *Cell) {
+ c = new(Cell)
+ c.Width = w
+ for i, r := range s {
+ if i == 0 {
+ c.Rune = r
+ } else {
+ c.Comb = append(c.Comb, r)
+ }
+ }
+ return
+}
+
+// Line represents a line in the terminal.
+// A nil cell represents an blank cell, a cell with a space character and a
+// width of 1.
+// If a cell has no content and a width of 0, it is a placeholder for a wide
+// cell.
+type Line []*Cell
+
+// Width returns the width of the line.
+func (l Line) Width() int {
+ return len(l)
+}
+
+// Len returns the length of the line.
+func (l Line) Len() int {
+ return len(l)
+}
+
+// String returns the string representation of the line. Any trailing spaces
+// are removed.
+func (l Line) String() (s string) {
+ for _, c := range l {
+ if c == nil {
+ s += " "
+ } else if c.Empty() {
+ continue
+ } else {
+ s += c.String()
+ }
+ }
+ s = strings.TrimRight(s, " ")
+ return
+}
+
+// At returns the cell at the given x position.
+// If the cell does not exist, it returns nil.
+func (l Line) At(x int) *Cell {
+ if x < 0 || x >= len(l) {
+ return nil
+ }
+
+ c := l[x]
+ if c == nil {
+ newCell := BlankCell
+ return &newCell
+ }
+
+ return c
+}
+
+// Set sets the cell at the given x position. If a wide cell is given, it will
+// set the cell and the following cells to [EmptyCell]. It returns true if the
+// cell was set.
+func (l Line) Set(x int, c *Cell) bool {
+ return l.set(x, c, true)
+}
+
+func (l Line) set(x int, c *Cell, clone bool) bool {
+ width := l.Width()
+ if x < 0 || x >= width {
+ return false
+ }
+
+ // When a wide cell is partially overwritten, we need
+ // to fill the rest of the cell with space cells to
+ // avoid rendering issues.
+ prev := l.At(x)
+ if prev != nil && prev.Width > 1 {
+ // Writing to the first wide cell
+ for j := 0; j < prev.Width && x+j < l.Width(); j++ {
+ l[x+j] = prev.Clone().Blank()
+ }
+ } else if prev != nil && prev.Width == 0 {
+ // Writing to wide cell placeholders
+ for j := 1; j < maxCellWidth && x-j >= 0; j++ {
+ wide := l.At(x - j)
+ if wide != nil && wide.Width > 1 && j < wide.Width {
+ for k := 0; k < wide.Width; k++ {
+ l[x-j+k] = wide.Clone().Blank()
+ }
+ break
+ }
+ }
+ }
+
+ if clone && c != nil {
+ // Clone the cell if not nil.
+ c = c.Clone()
+ }
+
+ if c != nil && x+c.Width > width {
+ // If the cell is too wide, we write blanks with the same style.
+ for i := 0; i < c.Width && x+i < width; i++ {
+ l[x+i] = c.Clone().Blank()
+ }
+ } else {
+ l[x] = c
+
+ // Mark wide cells with an empty cell zero width
+ // We set the wide cell down below
+ if c != nil && c.Width > 1 {
+ for j := 1; j < c.Width && x+j < l.Width(); j++ {
+ var wide Cell
+ l[x+j] = &wide
+ }
+ }
+ }
+
+ return true
+}
+
+// Buffer is a 2D grid of cells representing a screen or terminal.
+type Buffer struct {
+ // Lines holds the lines of the buffer.
+ Lines []Line
+}
+
+// NewBuffer creates a new buffer with the given width and height.
+// This is a convenience function that initializes a new buffer and resizes it.
+func NewBuffer(width int, height int) *Buffer {
+ b := new(Buffer)
+ b.Resize(width, height)
+ return b
+}
+
+// String returns the string representation of the buffer.
+func (b *Buffer) String() (s string) {
+ for i, l := range b.Lines {
+ s += l.String()
+ if i < len(b.Lines)-1 {
+ s += "\r\n"
+ }
+ }
+ return
+}
+
+// Line returns a pointer to the line at the given y position.
+// If the line does not exist, it returns nil.
+func (b *Buffer) Line(y int) Line {
+ if y < 0 || y >= len(b.Lines) {
+ return nil
+ }
+ return b.Lines[y]
+}
+
+// Cell implements Screen.
+func (b *Buffer) Cell(x int, y int) *Cell {
+ if y < 0 || y >= len(b.Lines) {
+ return nil
+ }
+ return b.Lines[y].At(x)
+}
+
+// maxCellWidth is the maximum width a terminal cell can get.
+const maxCellWidth = 4
+
+// SetCell sets the cell at the given x, y position.
+func (b *Buffer) SetCell(x, y int, c *Cell) bool {
+ return b.setCell(x, y, c, true)
+}
+
+// setCell sets the cell at the given x, y position. This will always clone and
+// allocates a new cell if c is not nil.
+func (b *Buffer) setCell(x, y int, c *Cell, clone bool) bool {
+ if y < 0 || y >= len(b.Lines) {
+ return false
+ }
+ return b.Lines[y].set(x, c, clone)
+}
+
+// Height implements Screen.
+func (b *Buffer) Height() int {
+ return len(b.Lines)
+}
+
+// Width implements Screen.
+func (b *Buffer) Width() int {
+ if len(b.Lines) == 0 {
+ return 0
+ }
+ return b.Lines[0].Width()
+}
+
+// Bounds returns the bounds of the buffer.
+func (b *Buffer) Bounds() Rectangle {
+ return Rect(0, 0, b.Width(), b.Height())
+}
+
+// Resize resizes the buffer to the given width and height.
+func (b *Buffer) Resize(width int, height int) {
+ if width == 0 || height == 0 {
+ b.Lines = nil
+ return
+ }
+
+ if width > b.Width() {
+ line := make(Line, width-b.Width())
+ for i := range b.Lines {
+ b.Lines[i] = append(b.Lines[i], line...)
+ }
+ } else if width < b.Width() {
+ for i := range b.Lines {
+ b.Lines[i] = b.Lines[i][:width]
+ }
+ }
+
+ if height > len(b.Lines) {
+ for i := len(b.Lines); i < height; i++ {
+ b.Lines = append(b.Lines, make(Line, width))
+ }
+ } else if height < len(b.Lines) {
+ b.Lines = b.Lines[:height]
+ }
+}
+
+// FillRect fills the buffer with the given cell and rectangle.
+func (b *Buffer) FillRect(c *Cell, rect Rectangle) {
+ cellWidth := 1
+ if c != nil && c.Width > 1 {
+ cellWidth = c.Width
+ }
+ for y := rect.Min.Y; y < rect.Max.Y; y++ {
+ for x := rect.Min.X; x < rect.Max.X; x += cellWidth {
+ b.setCell(x, y, c, false) //nolint:errcheck
+ }
+ }
+}
+
+// Fill fills the buffer with the given cell and rectangle.
+func (b *Buffer) Fill(c *Cell) {
+ b.FillRect(c, b.Bounds())
+}
+
+// Clear clears the buffer with space cells and rectangle.
+func (b *Buffer) Clear() {
+ b.ClearRect(b.Bounds())
+}
+
+// ClearRect clears the buffer with space cells within the specified
+// rectangles. Only cells within the rectangle's bounds are affected.
+func (b *Buffer) ClearRect(rect Rectangle) {
+ b.FillRect(nil, rect)
+}
+
+// InsertLine inserts n lines at the given line position, with the given
+// optional cell, within the specified rectangles. If no rectangles are
+// specified, it inserts lines in the entire buffer. Only cells within the
+// rectangle's horizontal bounds are affected. Lines are pushed out of the
+// rectangle bounds and lost. This follows terminal [ansi.IL] behavior.
+// It returns the pushed out lines.
+func (b *Buffer) InsertLine(y, n int, c *Cell) {
+ b.InsertLineRect(y, n, c, b.Bounds())
+}
+
+// InsertLineRect inserts new lines at the given line position, with the
+// given optional cell, within the rectangle bounds. Only cells within the
+// rectangle's horizontal bounds are affected. Lines are pushed out of the
+// rectangle bounds and lost. This follows terminal [ansi.IL] behavior.
+func (b *Buffer) InsertLineRect(y, n int, c *Cell, rect Rectangle) {
+ if n <= 0 || y < rect.Min.Y || y >= rect.Max.Y || y >= b.Height() {
+ return
+ }
+
+ // Limit number of lines to insert to available space
+ if y+n > rect.Max.Y {
+ n = rect.Max.Y - y
+ }
+
+ // Move existing lines down within the bounds
+ for i := rect.Max.Y - 1; i >= y+n; i-- {
+ for x := rect.Min.X; x < rect.Max.X; x++ {
+ // We don't need to clone c here because we're just moving lines down.
+ b.setCell(x, i, b.Lines[i-n][x], false)
+ }
+ }
+
+ // Clear the newly inserted lines within bounds
+ for i := y; i < y+n; i++ {
+ for x := rect.Min.X; x < rect.Max.X; x++ {
+ b.setCell(x, i, c, true)
+ }
+ }
+}
+
+// DeleteLineRect deletes lines at the given line position, with the given
+// optional cell, within the rectangle bounds. Only cells within the
+// rectangle's bounds are affected. Lines are shifted up within the bounds and
+// new blank lines are created at the bottom. This follows terminal [ansi.DL]
+// behavior.
+func (b *Buffer) DeleteLineRect(y, n int, c *Cell, rect Rectangle) {
+ if n <= 0 || y < rect.Min.Y || y >= rect.Max.Y || y >= b.Height() {
+ return
+ }
+
+ // Limit deletion count to available space in scroll region
+ if n > rect.Max.Y-y {
+ n = rect.Max.Y - y
+ }
+
+ // Shift cells up within the bounds
+ for dst := y; dst < rect.Max.Y-n; dst++ {
+ src := dst + n
+ for x := rect.Min.X; x < rect.Max.X; x++ {
+ // We don't need to clone c here because we're just moving cells up.
+ // b.lines[dst][x] = b.lines[src][x]
+ b.setCell(x, dst, b.Lines[src][x], false)
+ }
+ }
+
+ // Fill the bottom n lines with blank cells
+ for i := rect.Max.Y - n; i < rect.Max.Y; i++ {
+ for x := rect.Min.X; x < rect.Max.X; x++ {
+ b.setCell(x, i, c, true)
+ }
+ }
+}
+
+// DeleteLine deletes n lines at the given line position, with the given
+// optional cell, within the specified rectangles. If no rectangles are
+// specified, it deletes lines in the entire buffer.
+func (b *Buffer) DeleteLine(y, n int, c *Cell) {
+ b.DeleteLineRect(y, n, c, b.Bounds())
+}
+
+// InsertCell inserts new cells at the given position, with the given optional
+// cell, within the specified rectangles. If no rectangles are specified, it
+// inserts cells in the entire buffer. This follows terminal [ansi.ICH]
+// behavior.
+func (b *Buffer) InsertCell(x, y, n int, c *Cell) {
+ b.InsertCellRect(x, y, n, c, b.Bounds())
+}
+
+// InsertCellRect inserts new cells at the given position, with the given
+// optional cell, within the rectangle bounds. Only cells within the
+// rectangle's bounds are affected, following terminal [ansi.ICH] behavior.
+func (b *Buffer) InsertCellRect(x, y, n int, c *Cell, rect Rectangle) {
+ if n <= 0 || y < rect.Min.Y || y >= rect.Max.Y || y >= b.Height() ||
+ x < rect.Min.X || x >= rect.Max.X || x >= b.Width() {
+ return
+ }
+
+ // Limit number of cells to insert to available space
+ if x+n > rect.Max.X {
+ n = rect.Max.X - x
+ }
+
+ // Move existing cells within rectangle bounds to the right
+ for i := rect.Max.X - 1; i >= x+n && i-n >= rect.Min.X; i-- {
+ // We don't need to clone c here because we're just moving cells to the
+ // right.
+ // b.lines[y][i] = b.lines[y][i-n]
+ b.setCell(i, y, b.Lines[y][i-n], false)
+ }
+
+ // Clear the newly inserted cells within rectangle bounds
+ for i := x; i < x+n && i < rect.Max.X; i++ {
+ b.setCell(i, y, c, true)
+ }
+}
+
+// DeleteCell deletes cells at the given position, with the given optional
+// cell, within the specified rectangles. If no rectangles are specified, it
+// deletes cells in the entire buffer. This follows terminal [ansi.DCH]
+// behavior.
+func (b *Buffer) DeleteCell(x, y, n int, c *Cell) {
+ b.DeleteCellRect(x, y, n, c, b.Bounds())
+}
+
+// DeleteCellRect deletes cells at the given position, with the given
+// optional cell, within the rectangle bounds. Only cells within the
+// rectangle's bounds are affected, following terminal [ansi.DCH] behavior.
+func (b *Buffer) DeleteCellRect(x, y, n int, c *Cell, rect Rectangle) {
+ if n <= 0 || y < rect.Min.Y || y >= rect.Max.Y || y >= b.Height() ||
+ x < rect.Min.X || x >= rect.Max.X || x >= b.Width() {
+ return
+ }
+
+ // Calculate how many positions we can actually delete
+ remainingCells := rect.Max.X - x
+ if n > remainingCells {
+ n = remainingCells
+ }
+
+ // Shift the remaining cells to the left
+ for i := x; i < rect.Max.X-n; i++ {
+ if i+n < rect.Max.X {
+ // We don't need to clone c here because we're just moving cells to
+ // the left.
+ // b.lines[y][i] = b.lines[y][i+n]
+ b.setCell(i, y, b.Lines[y][i+n], false)
+ }
+ }
+
+ // Fill the vacated positions with the given cell
+ for i := rect.Max.X - n; i < rect.Max.X; i++ {
+ b.setCell(i, y, c, true)
+ }
+}
diff --git a/vendor/github.com/charmbracelet/x/cellbuf/cell.go b/vendor/github.com/charmbracelet/x/cellbuf/cell.go
new file mode 100644
index 00000000..991c919e
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/cellbuf/cell.go
@@ -0,0 +1,503 @@
+package cellbuf
+
+import (
+ "github.com/charmbracelet/x/ansi"
+)
+
+var (
+ // BlankCell is a cell with a single space, width of 1, and no style or link.
+ BlankCell = Cell{Rune: ' ', Width: 1}
+
+ // EmptyCell is just an empty cell used for comparisons and as a placeholder
+ // for wide cells.
+ EmptyCell = Cell{}
+)
+
+// Cell represents a single cell in the terminal screen.
+type Cell struct {
+ // The style of the cell. Nil style means no style. Zero value prints a
+ // reset sequence.
+ Style Style
+
+ // Link is the hyperlink of the cell.
+ Link Link
+
+ // Comb is the combining runes of the cell. This is nil if the cell is a
+ // single rune or if it's a zero width cell that is part of a wider cell.
+ Comb []rune
+
+ // Width is the mono-space width of the grapheme cluster.
+ Width int
+
+ // Rune is the main rune of the cell. This is zero if the cell is part of a
+ // wider cell.
+ Rune rune
+}
+
+// Append appends runes to the cell without changing the width. This is useful
+// when we want to use the cell to store escape sequences or other runes that
+// don't affect the width of the cell.
+func (c *Cell) Append(r ...rune) {
+ for i, r := range r {
+ if i == 0 && c.Rune == 0 {
+ c.Rune = r
+ continue
+ }
+ c.Comb = append(c.Comb, r)
+ }
+}
+
+// String returns the string content of the cell excluding any styles, links,
+// and escape sequences.
+func (c Cell) String() string {
+ if c.Rune == 0 {
+ return ""
+ }
+ if len(c.Comb) == 0 {
+ return string(c.Rune)
+ }
+ return string(append([]rune{c.Rune}, c.Comb...))
+}
+
+// Equal returns whether the cell is equal to the other cell.
+func (c *Cell) Equal(o *Cell) bool {
+ return o != nil &&
+ c.Width == o.Width &&
+ c.Rune == o.Rune &&
+ runesEqual(c.Comb, o.Comb) &&
+ c.Style.Equal(&o.Style) &&
+ c.Link.Equal(&o.Link)
+}
+
+// Empty returns whether the cell is an empty cell. An empty cell is a cell
+// with a width of 0, a rune of 0, and no combining runes.
+func (c Cell) Empty() bool {
+ return c.Width == 0 &&
+ c.Rune == 0 &&
+ len(c.Comb) == 0
+}
+
+// Reset resets the cell to the default state zero value.
+func (c *Cell) Reset() {
+ c.Rune = 0
+ c.Comb = nil
+ c.Width = 0
+ c.Style.Reset()
+ c.Link.Reset()
+}
+
+// Clear returns whether the cell consists of only attributes that don't
+// affect appearance of a space character.
+func (c *Cell) Clear() bool {
+ return c.Rune == ' ' && len(c.Comb) == 0 && c.Width == 1 && c.Style.Clear() && c.Link.Empty()
+}
+
+// Clone returns a copy of the cell.
+func (c *Cell) Clone() (n *Cell) {
+ n = new(Cell)
+ *n = *c
+ return
+}
+
+// Blank makes the cell a blank cell by setting the rune to a space, comb to
+// nil, and the width to 1.
+func (c *Cell) Blank() *Cell {
+ c.Rune = ' '
+ c.Comb = nil
+ c.Width = 1
+ return c
+}
+
+// Link represents a hyperlink in the terminal screen.
+type Link struct {
+ URL string
+ Params string
+}
+
+// String returns a string representation of the hyperlink.
+func (h Link) String() string {
+ return h.URL
+}
+
+// Reset resets the hyperlink to the default state zero value.
+func (h *Link) Reset() {
+ h.URL = ""
+ h.Params = ""
+}
+
+// Equal returns whether the hyperlink is equal to the other hyperlink.
+func (h *Link) Equal(o *Link) bool {
+ return o != nil && h.URL == o.URL && h.Params == o.Params
+}
+
+// Empty returns whether the hyperlink is empty.
+func (h Link) Empty() bool {
+ return h.URL == "" && h.Params == ""
+}
+
+// AttrMask is a bitmask for text attributes that can change the look of text.
+// These attributes can be combined to create different styles.
+type AttrMask uint8
+
+// These are the available text attributes that can be combined to create
+// different styles.
+const (
+ BoldAttr AttrMask = 1 << iota
+ FaintAttr
+ ItalicAttr
+ SlowBlinkAttr
+ RapidBlinkAttr
+ ReverseAttr
+ ConcealAttr
+ StrikethroughAttr
+
+ ResetAttr AttrMask = 0
+)
+
+// UnderlineStyle is the style of underline to use for text.
+type UnderlineStyle = ansi.UnderlineStyle
+
+// These are the available underline styles.
+const (
+ NoUnderline = ansi.NoUnderlineStyle
+ SingleUnderline = ansi.SingleUnderlineStyle
+ DoubleUnderline = ansi.DoubleUnderlineStyle
+ CurlyUnderline = ansi.CurlyUnderlineStyle
+ DottedUnderline = ansi.DottedUnderlineStyle
+ DashedUnderline = ansi.DashedUnderlineStyle
+)
+
+// Style represents the Style of a cell.
+type Style struct {
+ Fg ansi.Color
+ Bg ansi.Color
+ Ul ansi.Color
+ Attrs AttrMask
+ UlStyle UnderlineStyle
+}
+
+// Sequence returns the ANSI sequence that sets the style.
+func (s Style) Sequence() string {
+ if s.Empty() {
+ return ansi.ResetStyle
+ }
+
+ var b ansi.Style
+
+ if s.Attrs != 0 {
+ if s.Attrs&BoldAttr != 0 {
+ b = b.Bold()
+ }
+ if s.Attrs&FaintAttr != 0 {
+ b = b.Faint()
+ }
+ if s.Attrs&ItalicAttr != 0 {
+ b = b.Italic()
+ }
+ if s.Attrs&SlowBlinkAttr != 0 {
+ b = b.SlowBlink()
+ }
+ if s.Attrs&RapidBlinkAttr != 0 {
+ b = b.RapidBlink()
+ }
+ if s.Attrs&ReverseAttr != 0 {
+ b = b.Reverse()
+ }
+ if s.Attrs&ConcealAttr != 0 {
+ b = b.Conceal()
+ }
+ if s.Attrs&StrikethroughAttr != 0 {
+ b = b.Strikethrough()
+ }
+ }
+ if s.UlStyle != NoUnderline {
+ switch s.UlStyle {
+ case SingleUnderline:
+ b = b.Underline()
+ case DoubleUnderline:
+ b = b.DoubleUnderline()
+ case CurlyUnderline:
+ b = b.CurlyUnderline()
+ case DottedUnderline:
+ b = b.DottedUnderline()
+ case DashedUnderline:
+ b = b.DashedUnderline()
+ }
+ }
+ if s.Fg != nil {
+ b = b.ForegroundColor(s.Fg)
+ }
+ if s.Bg != nil {
+ b = b.BackgroundColor(s.Bg)
+ }
+ if s.Ul != nil {
+ b = b.UnderlineColor(s.Ul)
+ }
+
+ return b.String()
+}
+
+// DiffSequence returns the ANSI sequence that sets the style as a diff from
+// another style.
+func (s Style) DiffSequence(o Style) string {
+ if o.Empty() {
+ return s.Sequence()
+ }
+
+ var b ansi.Style
+
+ if !colorEqual(s.Fg, o.Fg) {
+ b = b.ForegroundColor(s.Fg)
+ }
+
+ if !colorEqual(s.Bg, o.Bg) {
+ b = b.BackgroundColor(s.Bg)
+ }
+
+ if !colorEqual(s.Ul, o.Ul) {
+ b = b.UnderlineColor(s.Ul)
+ }
+
+ var (
+ noBlink bool
+ isNormal bool
+ )
+
+ if s.Attrs != o.Attrs {
+ if s.Attrs&BoldAttr != o.Attrs&BoldAttr {
+ if s.Attrs&BoldAttr != 0 {
+ b = b.Bold()
+ } else if !isNormal {
+ isNormal = true
+ b = b.NormalIntensity()
+ }
+ }
+ if s.Attrs&FaintAttr != o.Attrs&FaintAttr {
+ if s.Attrs&FaintAttr != 0 {
+ b = b.Faint()
+ } else if !isNormal {
+ b = b.NormalIntensity()
+ }
+ }
+ if s.Attrs&ItalicAttr != o.Attrs&ItalicAttr {
+ if s.Attrs&ItalicAttr != 0 {
+ b = b.Italic()
+ } else {
+ b = b.NoItalic()
+ }
+ }
+ if s.Attrs&SlowBlinkAttr != o.Attrs&SlowBlinkAttr {
+ if s.Attrs&SlowBlinkAttr != 0 {
+ b = b.SlowBlink()
+ } else if !noBlink {
+ noBlink = true
+ b = b.NoBlink()
+ }
+ }
+ if s.Attrs&RapidBlinkAttr != o.Attrs&RapidBlinkAttr {
+ if s.Attrs&RapidBlinkAttr != 0 {
+ b = b.RapidBlink()
+ } else if !noBlink {
+ b = b.NoBlink()
+ }
+ }
+ if s.Attrs&ReverseAttr != o.Attrs&ReverseAttr {
+ if s.Attrs&ReverseAttr != 0 {
+ b = b.Reverse()
+ } else {
+ b = b.NoReverse()
+ }
+ }
+ if s.Attrs&ConcealAttr != o.Attrs&ConcealAttr {
+ if s.Attrs&ConcealAttr != 0 {
+ b = b.Conceal()
+ } else {
+ b = b.NoConceal()
+ }
+ }
+ if s.Attrs&StrikethroughAttr != o.Attrs&StrikethroughAttr {
+ if s.Attrs&StrikethroughAttr != 0 {
+ b = b.Strikethrough()
+ } else {
+ b = b.NoStrikethrough()
+ }
+ }
+ }
+
+ if s.UlStyle != o.UlStyle {
+ b = b.UnderlineStyle(s.UlStyle)
+ }
+
+ return b.String()
+}
+
+// Equal returns true if the style is equal to the other style.
+func (s *Style) Equal(o *Style) bool {
+ return s.Attrs == o.Attrs &&
+ s.UlStyle == o.UlStyle &&
+ colorEqual(s.Fg, o.Fg) &&
+ colorEqual(s.Bg, o.Bg) &&
+ colorEqual(s.Ul, o.Ul)
+}
+
+func colorEqual(c, o ansi.Color) bool {
+ if c == nil && o == nil {
+ return true
+ }
+ if c == nil || o == nil {
+ return false
+ }
+ cr, cg, cb, ca := c.RGBA()
+ or, og, ob, oa := o.RGBA()
+ return cr == or && cg == og && cb == ob && ca == oa
+}
+
+// Bold sets the bold attribute.
+func (s *Style) Bold(v bool) *Style {
+ if v {
+ s.Attrs |= BoldAttr
+ } else {
+ s.Attrs &^= BoldAttr
+ }
+ return s
+}
+
+// Faint sets the faint attribute.
+func (s *Style) Faint(v bool) *Style {
+ if v {
+ s.Attrs |= FaintAttr
+ } else {
+ s.Attrs &^= FaintAttr
+ }
+ return s
+}
+
+// Italic sets the italic attribute.
+func (s *Style) Italic(v bool) *Style {
+ if v {
+ s.Attrs |= ItalicAttr
+ } else {
+ s.Attrs &^= ItalicAttr
+ }
+ return s
+}
+
+// SlowBlink sets the slow blink attribute.
+func (s *Style) SlowBlink(v bool) *Style {
+ if v {
+ s.Attrs |= SlowBlinkAttr
+ } else {
+ s.Attrs &^= SlowBlinkAttr
+ }
+ return s
+}
+
+// RapidBlink sets the rapid blink attribute.
+func (s *Style) RapidBlink(v bool) *Style {
+ if v {
+ s.Attrs |= RapidBlinkAttr
+ } else {
+ s.Attrs &^= RapidBlinkAttr
+ }
+ return s
+}
+
+// Reverse sets the reverse attribute.
+func (s *Style) Reverse(v bool) *Style {
+ if v {
+ s.Attrs |= ReverseAttr
+ } else {
+ s.Attrs &^= ReverseAttr
+ }
+ return s
+}
+
+// Conceal sets the conceal attribute.
+func (s *Style) Conceal(v bool) *Style {
+ if v {
+ s.Attrs |= ConcealAttr
+ } else {
+ s.Attrs &^= ConcealAttr
+ }
+ return s
+}
+
+// Strikethrough sets the strikethrough attribute.
+func (s *Style) Strikethrough(v bool) *Style {
+ if v {
+ s.Attrs |= StrikethroughAttr
+ } else {
+ s.Attrs &^= StrikethroughAttr
+ }
+ return s
+}
+
+// UnderlineStyle sets the underline style.
+func (s *Style) UnderlineStyle(style UnderlineStyle) *Style {
+ s.UlStyle = style
+ return s
+}
+
+// Underline sets the underline attribute.
+// This is a syntactic sugar for [UnderlineStyle].
+func (s *Style) Underline(v bool) *Style {
+ if v {
+ return s.UnderlineStyle(SingleUnderline)
+ }
+ return s.UnderlineStyle(NoUnderline)
+}
+
+// Foreground sets the foreground color.
+func (s *Style) Foreground(c ansi.Color) *Style {
+ s.Fg = c
+ return s
+}
+
+// Background sets the background color.
+func (s *Style) Background(c ansi.Color) *Style {
+ s.Bg = c
+ return s
+}
+
+// UnderlineColor sets the underline color.
+func (s *Style) UnderlineColor(c ansi.Color) *Style {
+ s.Ul = c
+ return s
+}
+
+// Reset resets the style to default.
+func (s *Style) Reset() *Style {
+ s.Fg = nil
+ s.Bg = nil
+ s.Ul = nil
+ s.Attrs = ResetAttr
+ s.UlStyle = NoUnderline
+ return s
+}
+
+// Empty returns true if the style is empty.
+func (s *Style) Empty() bool {
+ return s.Fg == nil && s.Bg == nil && s.Ul == nil && s.Attrs == ResetAttr && s.UlStyle == NoUnderline
+}
+
+// Clear returns whether the style consists of only attributes that don't
+// affect appearance of a space character.
+func (s *Style) Clear() bool {
+ return s.UlStyle == NoUnderline &&
+ s.Attrs&^(BoldAttr|FaintAttr|ItalicAttr|SlowBlinkAttr|RapidBlinkAttr) == 0 &&
+ s.Fg == nil &&
+ s.Bg == nil &&
+ s.Ul == nil
+}
+
+func runesEqual(a, b []rune) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i, r := range a {
+ if r != b[i] {
+ return false
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/charmbracelet/x/cellbuf/errors.go b/vendor/github.com/charmbracelet/x/cellbuf/errors.go
new file mode 100644
index 00000000..64258fe3
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/cellbuf/errors.go
@@ -0,0 +1,6 @@
+package cellbuf
+
+import "errors"
+
+// ErrOutOfBounds is returned when the given x, y position is out of bounds.
+var ErrOutOfBounds = errors.New("out of bounds")
diff --git a/vendor/github.com/charmbracelet/x/cellbuf/geom.go b/vendor/github.com/charmbracelet/x/cellbuf/geom.go
new file mode 100644
index 00000000..c12e6fb1
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/cellbuf/geom.go
@@ -0,0 +1,21 @@
+package cellbuf
+
+import (
+ "image"
+)
+
+// Position represents an x, y position.
+type Position = image.Point
+
+// Pos is a shorthand for Position{X: x, Y: y}.
+func Pos(x, y int) Position {
+ return image.Pt(x, y)
+}
+
+// Rectange represents a rectangle.
+type Rectangle = image.Rectangle
+
+// Rect is a shorthand for Rectangle.
+func Rect(x, y, w, h int) Rectangle {
+ return image.Rect(x, y, x+w, y+h)
+}
diff --git a/vendor/github.com/charmbracelet/x/cellbuf/hardscroll.go b/vendor/github.com/charmbracelet/x/cellbuf/hardscroll.go
new file mode 100644
index 00000000..402ac06a
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/cellbuf/hardscroll.go
@@ -0,0 +1,272 @@
+package cellbuf
+
+import (
+ "strings"
+
+ "github.com/charmbracelet/x/ansi"
+)
+
+// scrollOptimize optimizes the screen to transform the old buffer into the new
+// buffer.
+func (s *Screen) scrollOptimize() {
+ height := s.newbuf.Height()
+ if s.oldnum == nil || len(s.oldnum) < height {
+ s.oldnum = make([]int, height)
+ }
+
+ // Calculate the indices
+ s.updateHashmap()
+ if len(s.hashtab) < height {
+ return
+ }
+
+ // Pass 1 - from top to bottom scrolling up
+ for i := 0; i < height; {
+ for i < height && (s.oldnum[i] == newIndex || s.oldnum[i] <= i) {
+ i++
+ }
+ if i >= height {
+ break
+ }
+
+ shift := s.oldnum[i] - i // shift > 0
+ start := i
+
+ i++
+ for i < height && s.oldnum[i] != newIndex && s.oldnum[i]-i == shift {
+ i++
+ }
+ end := i - 1 + shift
+
+ if !s.scrolln(shift, start, end, height-1) {
+ continue
+ }
+ }
+
+ // Pass 2 - from bottom to top scrolling down
+ for i := height - 1; i >= 0; {
+ for i >= 0 && (s.oldnum[i] == newIndex || s.oldnum[i] >= i) {
+ i--
+ }
+ if i < 0 {
+ break
+ }
+
+ shift := s.oldnum[i] - i // shift < 0
+ end := i
+
+ i--
+ for i >= 0 && s.oldnum[i] != newIndex && s.oldnum[i]-i == shift {
+ i--
+ }
+
+ start := i + 1 - (-shift)
+ if !s.scrolln(shift, start, end, height-1) {
+ continue
+ }
+ }
+}
+
+// scrolln scrolls the screen up by n lines.
+func (s *Screen) scrolln(n, top, bot, maxY int) (v bool) { //nolint:unparam
+ const (
+ nonDestScrollRegion = false
+ memoryBelow = false
+ )
+
+ blank := s.clearBlank()
+ if n > 0 {
+ // Scroll up (forward)
+ v = s.scrollUp(n, top, bot, 0, maxY, blank)
+ if !v {
+ s.buf.WriteString(ansi.SetTopBottomMargins(top+1, bot+1))
+
+ // XXX: How should we handle this in inline mode when not using alternate screen?
+ s.cur.X, s.cur.Y = -1, -1
+ v = s.scrollUp(n, top, bot, top, bot, blank)
+ s.buf.WriteString(ansi.SetTopBottomMargins(1, maxY+1))
+ s.cur.X, s.cur.Y = -1, -1
+ }
+
+ if !v {
+ v = s.scrollIdl(n, top, bot-n+1, blank)
+ }
+
+ // Clear newly shifted-in lines.
+ if v &&
+ (nonDestScrollRegion || (memoryBelow && bot == maxY)) {
+ if bot == maxY {
+ s.move(0, bot-n+1)
+ s.clearToBottom(nil)
+ } else {
+ for i := 0; i < n; i++ {
+ s.move(0, bot-i)
+ s.clearToEnd(nil, false)
+ }
+ }
+ }
+ } else if n < 0 {
+ // Scroll down (backward)
+ v = s.scrollDown(-n, top, bot, 0, maxY, blank)
+ if !v {
+ s.buf.WriteString(ansi.SetTopBottomMargins(top+1, bot+1))
+
+ // XXX: How should we handle this in inline mode when not using alternate screen?
+ s.cur.X, s.cur.Y = -1, -1
+ v = s.scrollDown(-n, top, bot, top, bot, blank)
+ s.buf.WriteString(ansi.SetTopBottomMargins(1, maxY+1))
+ s.cur.X, s.cur.Y = -1, -1
+
+ if !v {
+ v = s.scrollIdl(-n, bot+n+1, top, blank)
+ }
+
+ // Clear newly shifted-in lines.
+ if v &&
+ (nonDestScrollRegion || (memoryBelow && top == 0)) {
+ for i := 0; i < -n; i++ {
+ s.move(0, top+i)
+ s.clearToEnd(nil, false)
+ }
+ }
+ }
+ }
+
+ if !v {
+ return
+ }
+
+ s.scrollBuffer(s.curbuf, n, top, bot, blank)
+
+ // shift hash values too, they can be reused
+ s.scrollOldhash(n, top, bot)
+
+ return true
+}
+
+// scrollBuffer scrolls the buffer by n lines.
+func (s *Screen) scrollBuffer(b *Buffer, n, top, bot int, blank *Cell) {
+ if top < 0 || bot < top || bot >= b.Height() {
+ // Nothing to scroll
+ return
+ }
+
+ if n < 0 {
+ // shift n lines downwards
+ limit := top - n
+ for line := bot; line >= limit && line >= 0 && line >= top; line-- {
+ copy(b.Lines[line], b.Lines[line+n])
+ }
+ for line := top; line < limit && line <= b.Height()-1 && line <= bot; line++ {
+ b.FillRect(blank, Rect(0, line, b.Width(), 1))
+ }
+ }
+
+ if n > 0 {
+ // shift n lines upwards
+ limit := bot - n
+ for line := top; line <= limit && line <= b.Height()-1 && line <= bot; line++ {
+ copy(b.Lines[line], b.Lines[line+n])
+ }
+ for line := bot; line > limit && line >= 0 && line >= top; line-- {
+ b.FillRect(blank, Rect(0, line, b.Width(), 1))
+ }
+ }
+
+ s.touchLine(b.Width(), b.Height(), top, bot-top+1, true)
+}
+
+// touchLine marks the line as touched.
+func (s *Screen) touchLine(width, height, y, n int, changed bool) {
+ if n < 0 || y < 0 || y >= height {
+ return // Nothing to touch
+ }
+
+ for i := y; i < y+n && i < height; i++ {
+ if changed {
+ s.touch[i] = lineData{firstCell: 0, lastCell: width - 1}
+ } else {
+ delete(s.touch, i)
+ }
+ }
+}
+
+// scrollUp scrolls the screen up by n lines.
+func (s *Screen) scrollUp(n, top, bot, minY, maxY int, blank *Cell) bool {
+ if n == 1 && top == minY && bot == maxY {
+ s.move(0, bot)
+ s.updatePen(blank)
+ s.buf.WriteByte('\n')
+ } else if n == 1 && bot == maxY {
+ s.move(0, top)
+ s.updatePen(blank)
+ s.buf.WriteString(ansi.DeleteLine(1))
+ } else if top == minY && bot == maxY {
+ if s.xtermLike {
+ s.move(0, bot)
+ } else {
+ s.move(0, top)
+ }
+ s.updatePen(blank)
+ if s.xtermLike {
+ s.buf.WriteString(ansi.ScrollUp(n))
+ } else {
+ s.buf.WriteString(strings.Repeat("\n", n))
+ }
+ } else if bot == maxY {
+ s.move(0, top)
+ s.updatePen(blank)
+ s.buf.WriteString(ansi.DeleteLine(n))
+ } else {
+ return false
+ }
+ return true
+}
+
+// scrollDown scrolls the screen down by n lines.
+func (s *Screen) scrollDown(n, top, bot, minY, maxY int, blank *Cell) bool {
+ if n == 1 && top == minY && bot == maxY {
+ s.move(0, top)
+ s.updatePen(blank)
+ s.buf.WriteString(ansi.ReverseIndex)
+ } else if n == 1 && bot == maxY {
+ s.move(0, top)
+ s.updatePen(blank)
+ s.buf.WriteString(ansi.InsertLine(1))
+ } else if top == minY && bot == maxY {
+ s.move(0, top)
+ s.updatePen(blank)
+ if s.xtermLike {
+ s.buf.WriteString(ansi.ScrollDown(n))
+ } else {
+ s.buf.WriteString(strings.Repeat(ansi.ReverseIndex, n))
+ }
+ } else if bot == maxY {
+ s.move(0, top)
+ s.updatePen(blank)
+ s.buf.WriteString(ansi.InsertLine(n))
+ } else {
+ return false
+ }
+ return true
+}
+
+// scrollIdl scrolls the screen n lines by using [ansi.DL] at del and using
+// [ansi.IL] at ins.
+func (s *Screen) scrollIdl(n, del, ins int, blank *Cell) bool {
+ if n < 0 {
+ return false
+ }
+
+ // Delete lines
+ s.move(0, del)
+ s.updatePen(blank)
+ s.buf.WriteString(ansi.DeleteLine(n))
+
+ // Insert lines
+ s.move(0, ins)
+ s.updatePen(blank)
+ s.buf.WriteString(ansi.InsertLine(n))
+
+ return true
+}
diff --git a/vendor/github.com/charmbracelet/x/cellbuf/hashmap.go b/vendor/github.com/charmbracelet/x/cellbuf/hashmap.go
new file mode 100644
index 00000000..0d25b549
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/cellbuf/hashmap.go
@@ -0,0 +1,301 @@
+package cellbuf
+
+import (
+ "github.com/charmbracelet/x/ansi"
+)
+
+// hash returns the hash value of a [Line].
+func hash(l Line) (h uint64) {
+ for _, c := range l {
+ var r rune
+ if c == nil {
+ r = ansi.SP
+ } else {
+ r = c.Rune
+ }
+ h += (h << 5) + uint64(r)
+ }
+ return
+}
+
+// hashmap represents a single [Line] hash.
+type hashmap struct {
+ value uint64
+ oldcount, newcount int
+ oldindex, newindex int
+}
+
+// The value used to indicate lines created by insertions and scrolls.
+const newIndex = -1
+
+// updateHashmap updates the hashmap with the new hash value.
+func (s *Screen) updateHashmap() {
+ height := s.newbuf.Height()
+ if len(s.oldhash) >= height && len(s.newhash) >= height {
+ // rehash changed lines
+ for i := 0; i < height; i++ {
+ _, ok := s.touch[i]
+ if ok {
+ s.oldhash[i] = hash(s.curbuf.Line(i))
+ s.newhash[i] = hash(s.newbuf.Line(i))
+ }
+ }
+ } else {
+ // rehash all
+ if len(s.oldhash) != height {
+ s.oldhash = make([]uint64, height)
+ }
+ if len(s.newhash) != height {
+ s.newhash = make([]uint64, height)
+ }
+ for i := 0; i < height; i++ {
+ s.oldhash[i] = hash(s.curbuf.Line(i))
+ s.newhash[i] = hash(s.newbuf.Line(i))
+ }
+ }
+
+ s.hashtab = make([]hashmap, height*2)
+ for i := 0; i < height; i++ {
+ hashval := s.oldhash[i]
+
+ // Find matching hash or empty slot
+ idx := 0
+ for idx < len(s.hashtab) && s.hashtab[idx].value != 0 {
+ if s.hashtab[idx].value == hashval {
+ break
+ }
+ idx++
+ }
+
+ s.hashtab[idx].value = hashval // in case this is a new hash
+ s.hashtab[idx].oldcount++
+ s.hashtab[idx].oldindex = i
+ }
+ for i := 0; i < height; i++ {
+ hashval := s.newhash[i]
+
+ // Find matching hash or empty slot
+ idx := 0
+ for idx < len(s.hashtab) && s.hashtab[idx].value != 0 {
+ if s.hashtab[idx].value == hashval {
+ break
+ }
+ idx++
+ }
+
+ s.hashtab[idx].value = hashval // in case this is a new hash
+ s.hashtab[idx].newcount++
+ s.hashtab[idx].newindex = i
+
+ s.oldnum[i] = newIndex // init old indices slice
+ }
+
+ // Mark line pair corresponding to unique hash pairs.
+ for i := 0; i < len(s.hashtab) && s.hashtab[i].value != 0; i++ {
+ hsp := &s.hashtab[i]
+ if hsp.oldcount == 1 && hsp.newcount == 1 && hsp.oldindex != hsp.newindex {
+ s.oldnum[hsp.newindex] = hsp.oldindex
+ }
+ }
+
+ s.growHunks()
+
+ // Eliminate bad or impossible shifts. This includes removing those hunks
+ // which could not grow because of conflicts, as well those which are to be
+ // moved too far, they are likely to destroy more than carry.
+ for i := 0; i < height; {
+ var start, shift, size int
+ for i < height && s.oldnum[i] == newIndex {
+ i++
+ }
+ if i >= height {
+ break
+ }
+ start = i
+ shift = s.oldnum[i] - i
+ i++
+ for i < height && s.oldnum[i] != newIndex && s.oldnum[i]-i == shift {
+ i++
+ }
+ size = i - start
+ if size < 3 || size+min(size/8, 2) < abs(shift) {
+ for start < i {
+ s.oldnum[start] = newIndex
+ start++
+ }
+ }
+ }
+
+ // After clearing invalid hunks, try grow the rest.
+ s.growHunks()
+}
+
+// scrollOldhash
+func (s *Screen) scrollOldhash(n, top, bot int) {
+ if len(s.oldhash) == 0 {
+ return
+ }
+
+ size := bot - top + 1 - abs(n)
+ if n > 0 {
+ // Move existing hashes up
+ copy(s.oldhash[top:], s.oldhash[top+n:top+n+size])
+ // Recalculate hashes for newly shifted-in lines
+ for i := bot; i > bot-n; i-- {
+ s.oldhash[i] = hash(s.curbuf.Line(i))
+ }
+ } else {
+ // Move existing hashes down
+ copy(s.oldhash[top-n:], s.oldhash[top:top+size])
+ // Recalculate hashes for newly shifted-in lines
+ for i := top; i < top-n; i++ {
+ s.oldhash[i] = hash(s.curbuf.Line(i))
+ }
+ }
+}
+
+func (s *Screen) growHunks() {
+ var (
+ backLimit int // limits for cells to fill
+ backRefLimit int // limit for references
+ i int
+ nextHunk int
+ )
+
+ height := s.newbuf.Height()
+ for i < height && s.oldnum[i] == newIndex {
+ i++
+ }
+ for ; i < height; i = nextHunk {
+ var (
+ forwardLimit int
+ forwardRefLimit int
+ end int
+ start = i
+ shift = s.oldnum[i] - i
+ )
+
+ // get forward limit
+ i = start + 1
+ for i < height &&
+ s.oldnum[i] != newIndex &&
+ s.oldnum[i]-i == shift {
+ i++
+ }
+
+ end = i
+ for i < height && s.oldnum[i] == newIndex {
+ i++
+ }
+
+ nextHunk = i
+ forwardLimit = i
+ if i >= height || s.oldnum[i] >= i {
+ forwardRefLimit = i
+ } else {
+ forwardRefLimit = s.oldnum[i]
+ }
+
+ i = start - 1
+
+ // grow back
+ if shift < 0 {
+ backLimit = backRefLimit + (-shift)
+ }
+ for i >= backLimit {
+ if s.newhash[i] == s.oldhash[i+shift] ||
+ s.costEffective(i+shift, i, shift < 0) {
+ s.oldnum[i] = i + shift
+ } else {
+ break
+ }
+ i--
+ }
+
+ i = end
+ // grow forward
+ if shift > 0 {
+ forwardLimit = forwardRefLimit - shift
+ }
+ for i < forwardLimit {
+ if s.newhash[i] == s.oldhash[i+shift] ||
+ s.costEffective(i+shift, i, shift > 0) {
+ s.oldnum[i] = i + shift
+ } else {
+ break
+ }
+ i++
+ }
+
+ backLimit = i
+ backRefLimit = backLimit
+ if shift > 0 {
+ backRefLimit += shift
+ }
+ }
+}
+
+// costEffective returns true if the cost of moving line 'from' to line 'to' seems to be
+// cost effective. 'blank' indicates whether the line 'to' would become blank.
+func (s *Screen) costEffective(from, to int, blank bool) bool {
+ if from == to {
+ return false
+ }
+
+ newFrom := s.oldnum[from]
+ if newFrom == newIndex {
+ newFrom = from
+ }
+
+ // On the left side of >= is the cost before moving. On the right side --
+ // cost after moving.
+
+ // Calculate costs before moving.
+ var costBeforeMove int
+ if blank {
+ // Cost of updating blank line at destination.
+ costBeforeMove = s.updateCostBlank(s.newbuf.Line(to))
+ } else {
+ // Cost of updating exiting line at destination.
+ costBeforeMove = s.updateCost(s.curbuf.Line(to), s.newbuf.Line(to))
+ }
+
+ // Add cost of updating source line
+ costBeforeMove += s.updateCost(s.curbuf.Line(newFrom), s.newbuf.Line(from))
+
+ // Calculate costs after moving.
+ var costAfterMove int
+ if newFrom == from {
+ // Source becomes blank after move
+ costAfterMove = s.updateCostBlank(s.newbuf.Line(from))
+ } else {
+ // Source gets updated from another line
+ costAfterMove = s.updateCost(s.curbuf.Line(newFrom), s.newbuf.Line(from))
+ }
+
+ // Add cost of moving source line to destination
+ costAfterMove += s.updateCost(s.curbuf.Line(from), s.newbuf.Line(to))
+
+ // Return true if moving is cost effective (costs less or equal)
+ return costBeforeMove >= costAfterMove
+}
+
+func (s *Screen) updateCost(from, to Line) (cost int) {
+ var fidx, tidx int
+ for i := s.newbuf.Width() - 1; i > 0; i, fidx, tidx = i-1, fidx+1, tidx+1 {
+ if !cellEqual(from.At(fidx), to.At(tidx)) {
+ cost++
+ }
+ }
+ return
+}
+
+func (s *Screen) updateCostBlank(to Line) (cost int) {
+ var tidx int
+ for i := s.newbuf.Width() - 1; i > 0; i, tidx = i-1, tidx+1 {
+ if !cellEqual(nil, to.At(tidx)) {
+ cost++
+ }
+ }
+ return
+}
diff --git a/vendor/github.com/charmbracelet/x/cellbuf/link.go b/vendor/github.com/charmbracelet/x/cellbuf/link.go
new file mode 100644
index 00000000..112f8e8a
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/cellbuf/link.go
@@ -0,0 +1,14 @@
+package cellbuf
+
+import (
+ "github.com/charmbracelet/colorprofile"
+)
+
+// Convert converts a hyperlink to respect the given color profile.
+func ConvertLink(h Link, p colorprofile.Profile) Link {
+ if p == colorprofile.NoTTY {
+ return Link{}
+ }
+
+ return h
+}
diff --git a/vendor/github.com/charmbracelet/x/cellbuf/screen.go b/vendor/github.com/charmbracelet/x/cellbuf/screen.go
new file mode 100644
index 00000000..963b9cac
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/cellbuf/screen.go
@@ -0,0 +1,1457 @@
+package cellbuf
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "os"
+ "strings"
+ "sync"
+
+ "github.com/charmbracelet/colorprofile"
+ "github.com/charmbracelet/x/ansi"
+ "github.com/charmbracelet/x/term"
+)
+
+// ErrInvalidDimensions is returned when the dimensions of a window are invalid
+// for the operation.
+var ErrInvalidDimensions = errors.New("invalid dimensions")
+
+// notLocal returns whether the coordinates are not considered local movement
+// using the defined thresholds.
+// This takes the number of columns, and the coordinates of the current and
+// target positions.
+func notLocal(cols, fx, fy, tx, ty int) bool {
+ // The typical distance for a [ansi.CUP] sequence. Anything less than this
+ // is considered local movement.
+ const longDist = 8 - 1
+ return (tx > longDist) &&
+ (tx < cols-1-longDist) &&
+ (abs(ty-fy)+abs(tx-fx) > longDist)
+}
+
+// relativeCursorMove returns the relative cursor movement sequence using one or two
+// of the following sequences [ansi.CUU], [ansi.CUD], [ansi.CUF], [ansi.CUB],
+// [ansi.VPA], [ansi.HPA].
+// When overwrite is true, this will try to optimize the sequence by using the
+// screen cells values to move the cursor instead of using escape sequences.
+func relativeCursorMove(s *Screen, fx, fy, tx, ty int, overwrite, useTabs, useBackspace bool) string {
+ var seq strings.Builder
+
+ width, height := s.newbuf.Width(), s.newbuf.Height()
+ if ty != fy {
+ var yseq string
+ if s.xtermLike && !s.opts.RelativeCursor {
+ yseq = ansi.VerticalPositionAbsolute(ty + 1)
+ }
+
+ // OPTIM: Use [ansi.LF] and [ansi.ReverseIndex] as optimizations.
+
+ if ty > fy {
+ n := ty - fy
+ if cud := ansi.CursorDown(n); yseq == "" || len(cud) < len(yseq) {
+ yseq = cud
+ }
+ shouldScroll := !s.opts.AltScreen && fy+n >= s.scrollHeight
+ if lf := strings.Repeat("\n", n); shouldScroll || (fy+n < height && len(lf) < len(yseq)) {
+ // TODO: Ensure we're not unintentionally scrolling the screen down.
+ yseq = lf
+ s.scrollHeight = max(s.scrollHeight, fy+n)
+ }
+ } else if ty < fy {
+ n := fy - ty
+ if cuu := ansi.CursorUp(n); yseq == "" || len(cuu) < len(yseq) {
+ yseq = cuu
+ }
+ if n == 1 && fy-1 > 0 {
+ // TODO: Ensure we're not unintentionally scrolling the screen up.
+ yseq = ansi.ReverseIndex
+ }
+ }
+
+ seq.WriteString(yseq)
+ }
+
+ if tx != fx {
+ var xseq string
+ if s.xtermLike && !s.opts.RelativeCursor {
+ xseq = ansi.HorizontalPositionAbsolute(tx + 1)
+ }
+
+ if tx > fx {
+ n := tx - fx
+ if useTabs {
+ var tabs int
+ var col int
+ for col = fx; s.tabs.Next(col) <= tx; col = s.tabs.Next(col) {
+ tabs++
+ if col == s.tabs.Next(col) || col >= width-1 {
+ break
+ }
+ }
+
+ if tabs > 0 {
+ cht := ansi.CursorHorizontalForwardTab(tabs)
+ tab := strings.Repeat("\t", tabs)
+ if false && s.xtermLike && len(cht) < len(tab) {
+ // TODO: The linux console and some terminals such as
+ // Alacritty don't support [ansi.CHT]. Enable this when
+ // we have a way to detect this, or after 5 years when
+ // we're sure everyone has updated their terminals :P
+ seq.WriteString(cht)
+ } else {
+ seq.WriteString(tab)
+ }
+
+ n = tx - col
+ fx = col
+ }
+ }
+
+ if cuf := ansi.CursorForward(n); xseq == "" || len(cuf) < len(xseq) {
+ xseq = cuf
+ }
+
+ // If we have no attribute and style changes, overwrite is cheaper.
+ var ovw string
+ if overwrite && ty >= 0 {
+ for i := 0; i < n; i++ {
+ cell := s.newbuf.Cell(fx+i, ty)
+ if cell != nil && cell.Width > 0 {
+ i += cell.Width - 1
+ if !cell.Style.Equal(&s.cur.Style) || !cell.Link.Equal(&s.cur.Link) {
+ overwrite = false
+ break
+ }
+ }
+ }
+ }
+
+ if overwrite && ty >= 0 {
+ for i := 0; i < n; i++ {
+ cell := s.newbuf.Cell(fx+i, ty)
+ if cell != nil && cell.Width > 0 {
+ ovw += cell.String()
+ i += cell.Width - 1
+ } else {
+ ovw += " "
+ }
+ }
+ }
+
+ if overwrite && len(ovw) < len(xseq) {
+ xseq = ovw
+ }
+ } else if tx < fx {
+ n := fx - tx
+ if useTabs && s.xtermLike {
+ // VT100 does not support backward tabs [ansi.CBT].
+
+ col := fx
+
+ var cbt int // cursor backward tabs count
+ for s.tabs.Prev(col) >= tx {
+ col = s.tabs.Prev(col)
+ cbt++
+ if col == s.tabs.Prev(col) || col <= 0 {
+ break
+ }
+ }
+
+ if cbt > 0 {
+ seq.WriteString(ansi.CursorBackwardTab(cbt))
+ n = col - tx
+ }
+ }
+
+ if cub := ansi.CursorBackward(n); xseq == "" || len(cub) < len(xseq) {
+ xseq = cub
+ }
+
+ if useBackspace && n < len(xseq) {
+ xseq = strings.Repeat("\b", n)
+ }
+ }
+
+ seq.WriteString(xseq)
+ }
+
+ return seq.String()
+}
+
+// moveCursor moves and returns the cursor movement sequence to move the cursor
+// to the specified position.
+// When overwrite is true, this will try to optimize the sequence by using the
+// screen cells values to move the cursor instead of using escape sequences.
+func moveCursor(s *Screen, x, y int, overwrite bool) (seq string) {
+ fx, fy := s.cur.X, s.cur.Y
+
+ if !s.opts.RelativeCursor {
+ // Method #0: Use [ansi.CUP] if the distance is long.
+ seq = ansi.CursorPosition(x+1, y+1)
+ if fx == -1 || fy == -1 || notLocal(s.newbuf.Width(), fx, fy, x, y) {
+ return
+ }
+ }
+
+ // Optimize based on options.
+ trials := 0
+ if s.opts.HardTabs {
+ trials |= 2 // 0b10 in binary
+ }
+ if s.opts.Backspace {
+ trials |= 1 // 0b01 in binary
+ }
+
+ // Try all possible combinations of hard tabs and backspace optimizations.
+ for i := 0; i <= trials; i++ {
+ // Skip combinations that are not enabled.
+ if i & ^trials != 0 {
+ continue
+ }
+
+ useHardTabs := i&2 != 0
+ useBackspace := i&1 != 0
+
+ // Method #1: Use local movement sequences.
+ nseq := relativeCursorMove(s, fx, fy, x, y, overwrite, useHardTabs, useBackspace)
+ if (i == 0 && len(seq) == 0) || len(nseq) < len(seq) {
+ seq = nseq
+ }
+
+ // Method #2: Use [ansi.CR] and local movement sequences.
+ nseq = "\r" + relativeCursorMove(s, 0, fy, x, y, overwrite, useHardTabs, useBackspace)
+ if len(nseq) < len(seq) {
+ seq = nseq
+ }
+
+ if !s.opts.RelativeCursor {
+ // Method #3: Use [ansi.CursorHomePosition] and local movement sequences.
+ nseq = ansi.CursorHomePosition + relativeCursorMove(s, 0, 0, x, y, overwrite, useHardTabs, useBackspace)
+ if len(nseq) < len(seq) {
+ seq = nseq
+ }
+ }
+ }
+
+ return
+}
+
+// moveCursor moves the cursor to the specified position.
+func (s *Screen) moveCursor(x, y int, overwrite bool) {
+ if !s.opts.AltScreen && s.cur.X == -1 && s.cur.Y == -1 {
+ // First cursor movement in inline mode, move the cursor to the first
+ // column before moving to the target position.
+ s.buf.WriteByte('\r') //nolint:errcheck
+ s.cur.X, s.cur.Y = 0, 0
+ }
+ s.buf.WriteString(moveCursor(s, x, y, overwrite)) //nolint:errcheck
+ s.cur.X, s.cur.Y = x, y
+}
+
+func (s *Screen) move(x, y int) {
+ // XXX: Make sure we use the max height and width of the buffer in case
+ // we're in the middle of a resize operation.
+ width := max(s.newbuf.Width(), s.curbuf.Width())
+ height := max(s.newbuf.Height(), s.curbuf.Height())
+
+ if width > 0 && x >= width {
+ // Handle autowrap
+ y += (x / width)
+ x %= width
+ }
+
+ // XXX: Disable styles if there's any
+ // Some move operations such as [ansi.LF] can apply styles to the new
+ // cursor position, thus, we need to reset the styles before moving the
+ // cursor.
+ blank := s.clearBlank()
+ resetPen := y != s.cur.Y && !blank.Equal(&BlankCell)
+ if resetPen {
+ s.updatePen(nil)
+ }
+
+ // Reset wrap around (phantom cursor) state
+ if s.atPhantom {
+ s.cur.X = 0
+ s.buf.WriteByte('\r') //nolint:errcheck
+ s.atPhantom = false // reset phantom cell state
+ }
+
+ // TODO: Investigate if we need to handle this case and/or if we need the
+ // following code.
+ //
+ // if width > 0 && s.cur.X >= width {
+ // l := (s.cur.X + 1) / width
+ //
+ // s.cur.Y += l
+ // if height > 0 && s.cur.Y >= height {
+ // l -= s.cur.Y - height - 1
+ // }
+ //
+ // if l > 0 {
+ // s.cur.X = 0
+ // s.buf.WriteString("\r" + strings.Repeat("\n", l)) //nolint:errcheck
+ // }
+ // }
+
+ if height > 0 {
+ if s.cur.Y > height-1 {
+ s.cur.Y = height - 1
+ }
+ if y > height-1 {
+ y = height - 1
+ }
+ }
+
+ if x == s.cur.X && y == s.cur.Y {
+ // We give up later because we need to run checks for the phantom cell
+ // and others before we can determine if we can give up.
+ return
+ }
+
+ // We set the new cursor in [Screen.moveCursor].
+ s.moveCursor(x, y, true) // Overwrite cells if possible
+}
+
+// Cursor represents a terminal Cursor.
+type Cursor struct {
+ Style
+ Link
+ Position
+}
+
+// ScreenOptions are options for the screen.
+type ScreenOptions struct {
+ // Term is the terminal type to use when writing to the screen. When empty,
+ // `$TERM` is used from [os.Getenv].
+ Term string
+ // Profile is the color profile to use when writing to the screen.
+ Profile colorprofile.Profile
+ // RelativeCursor is whether to use relative cursor movements. This is
+ // useful when alt-screen is not used or when using inline mode.
+ RelativeCursor bool
+ // AltScreen is whether to use the alternate screen buffer.
+ AltScreen bool
+ // ShowCursor is whether to show the cursor.
+ ShowCursor bool
+ // HardTabs is whether to use hard tabs to optimize cursor movements.
+ HardTabs bool
+ // Backspace is whether to use backspace characters to move the cursor.
+ Backspace bool
+}
+
+// lineData represents the metadata for a line.
+type lineData struct {
+ // first and last changed cell indices
+ firstCell, lastCell int
+ // old index used for scrolling
+ oldIndex int //nolint:unused
+}
+
+// Screen represents the terminal screen.
+type Screen struct {
+ w io.Writer
+ buf *bytes.Buffer // buffer for writing to the screen
+ curbuf *Buffer // the current buffer
+ newbuf *Buffer // the new buffer
+ tabs *TabStops
+ touch map[int]lineData
+ queueAbove []string // the queue of strings to write above the screen
+ oldhash, newhash []uint64 // the old and new hash values for each line
+ hashtab []hashmap // the hashmap table
+ oldnum []int // old indices from previous hash
+ cur, saved Cursor // the current and saved cursors
+ opts ScreenOptions
+ mu sync.Mutex
+ method ansi.Method
+ scrollHeight int // keeps track of how many lines we've scrolled down (inline mode)
+ altScreenMode bool // whether alternate screen mode is enabled
+ cursorHidden bool // whether text cursor mode is enabled
+ clear bool // whether to force clear the screen
+ xtermLike bool // whether to use xterm-like optimizations, otherwise, it uses vt100 only
+ queuedText bool // whether we have queued non-zero width text queued up
+ atPhantom bool // whether the cursor is out of bounds and at a phantom cell
+}
+
+// SetMethod sets the method used to calculate the width of cells.
+func (s *Screen) SetMethod(method ansi.Method) {
+ s.method = method
+}
+
+// UseBackspaces sets whether to use backspace characters to move the cursor.
+func (s *Screen) UseBackspaces(v bool) {
+ s.opts.Backspace = v
+}
+
+// UseHardTabs sets whether to use hard tabs to optimize cursor movements.
+func (s *Screen) UseHardTabs(v bool) {
+ s.opts.HardTabs = v
+}
+
+// SetColorProfile sets the color profile to use when writing to the screen.
+func (s *Screen) SetColorProfile(p colorprofile.Profile) {
+ s.opts.Profile = p
+}
+
+// SetRelativeCursor sets whether to use relative cursor movements.
+func (s *Screen) SetRelativeCursor(v bool) {
+ s.opts.RelativeCursor = v
+}
+
+// EnterAltScreen enters the alternate screen buffer.
+func (s *Screen) EnterAltScreen() {
+ s.opts.AltScreen = true
+ s.clear = true
+ s.saved = s.cur
+}
+
+// ExitAltScreen exits the alternate screen buffer.
+func (s *Screen) ExitAltScreen() {
+ s.opts.AltScreen = false
+ s.clear = true
+ s.cur = s.saved
+}
+
+// ShowCursor shows the cursor.
+func (s *Screen) ShowCursor() {
+ s.opts.ShowCursor = true
+}
+
+// HideCursor hides the cursor.
+func (s *Screen) HideCursor() {
+ s.opts.ShowCursor = false
+}
+
+// Bounds implements Window.
+func (s *Screen) Bounds() Rectangle {
+ // Always return the new buffer bounds.
+ return s.newbuf.Bounds()
+}
+
+// Cell implements Window.
+func (s *Screen) Cell(x int, y int) *Cell {
+ return s.newbuf.Cell(x, y)
+}
+
+// Redraw forces a full redraw of the screen.
+func (s *Screen) Redraw() {
+ s.mu.Lock()
+ s.clear = true
+ s.mu.Unlock()
+}
+
+// Clear clears the screen with blank cells. This is a convenience method for
+// [Screen.Fill] with a nil cell.
+func (s *Screen) Clear() bool {
+ return s.ClearRect(s.newbuf.Bounds())
+}
+
+// ClearRect clears the given rectangle with blank cells. This is a convenience
+// method for [Screen.FillRect] with a nil cell.
+func (s *Screen) ClearRect(r Rectangle) bool {
+ return s.FillRect(nil, r)
+}
+
+// SetCell implements Window.
+func (s *Screen) SetCell(x int, y int, cell *Cell) (v bool) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ cellWidth := 1
+ if cell != nil {
+ cellWidth = cell.Width
+ }
+ if prev := s.curbuf.Cell(x, y); !cellEqual(prev, cell) {
+ chg, ok := s.touch[y]
+ if !ok {
+ chg = lineData{firstCell: x, lastCell: x + cellWidth}
+ } else {
+ chg.firstCell = min(chg.firstCell, x)
+ chg.lastCell = max(chg.lastCell, x+cellWidth)
+ }
+ s.touch[y] = chg
+ }
+
+ return s.newbuf.SetCell(x, y, cell)
+}
+
+// Fill implements Window.
+func (s *Screen) Fill(cell *Cell) bool {
+ return s.FillRect(cell, s.newbuf.Bounds())
+}
+
+// FillRect implements Window.
+func (s *Screen) FillRect(cell *Cell, r Rectangle) bool {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ s.newbuf.FillRect(cell, r)
+ for i := r.Min.Y; i < r.Max.Y; i++ {
+ s.touch[i] = lineData{firstCell: r.Min.X, lastCell: r.Max.X}
+ }
+ return true
+}
+
+// isXtermLike returns whether the terminal is xterm-like. This means that the
+// terminal supports ECMA-48 and ANSI X3.64 escape sequences.
+// TODO: Should this be a lookup table into each $TERM terminfo database? Like
+// we could keep a map of ANSI escape sequence to terminfo capability name and
+// check if the database supports the escape sequence. Instead of keeping a
+// list of terminal names here.
+func isXtermLike(termtype string) (v bool) {
+ parts := strings.Split(termtype, "-")
+ if len(parts) == 0 {
+ return
+ }
+
+ switch parts[0] {
+ case
+ "alacritty",
+ "contour",
+ "foot",
+ "ghostty",
+ "kitty",
+ "linux",
+ "rio",
+ "screen",
+ "st",
+ "tmux",
+ "wezterm",
+ "xterm":
+ v = true
+ }
+
+ return
+}
+
+// NewScreen creates a new Screen.
+func NewScreen(w io.Writer, width, height int, opts *ScreenOptions) (s *Screen) {
+ s = new(Screen)
+ s.w = w
+ if opts != nil {
+ s.opts = *opts
+ }
+
+ if s.opts.Term == "" {
+ s.opts.Term = os.Getenv("TERM")
+ }
+
+ if width <= 0 || height <= 0 {
+ if f, ok := w.(term.File); ok {
+ width, height, _ = term.GetSize(f.Fd())
+ }
+ }
+ if width < 0 {
+ width = 0
+ }
+ if height < 0 {
+ height = 0
+ }
+
+ s.buf = new(bytes.Buffer)
+ s.xtermLike = isXtermLike(s.opts.Term)
+ s.curbuf = NewBuffer(width, height)
+ s.newbuf = NewBuffer(width, height)
+ s.cur = Cursor{Position: Pos(-1, -1)} // start at -1 to force a move
+ s.saved = s.cur
+ s.reset()
+
+ return
+}
+
+// Width returns the width of the screen.
+func (s *Screen) Width() int {
+ return s.newbuf.Width()
+}
+
+// Height returns the height of the screen.
+func (s *Screen) Height() int {
+ return s.newbuf.Height()
+}
+
+// cellEqual returns whether the two cells are equal. A nil cell is considered
+// a [BlankCell].
+func cellEqual(a, b *Cell) bool {
+ if a == b {
+ return true
+ }
+ if a == nil {
+ a = &BlankCell
+ }
+ if b == nil {
+ b = &BlankCell
+ }
+ return a.Equal(b)
+}
+
+// putCell draws a cell at the current cursor position.
+func (s *Screen) putCell(cell *Cell) {
+ width, height := s.newbuf.Width(), s.newbuf.Height()
+ if s.opts.AltScreen && s.cur.X == width-1 && s.cur.Y == height-1 {
+ s.putCellLR(cell)
+ } else {
+ s.putAttrCell(cell)
+ }
+}
+
+// wrapCursor wraps the cursor to the next line.
+//
+//nolint:unused
+func (s *Screen) wrapCursor() {
+ const autoRightMargin = true
+ if autoRightMargin {
+ // Assume we have auto wrap mode enabled.
+ s.cur.X = 0
+ s.cur.Y++
+ } else {
+ s.cur.X--
+ }
+}
+
+func (s *Screen) putAttrCell(cell *Cell) {
+ if cell != nil && cell.Empty() {
+ // XXX: Zero width cells are special and should not be written to the
+ // screen no matter what other attributes they have.
+ // Zero width cells are used for wide characters that are split into
+ // multiple cells.
+ return
+ }
+
+ if cell == nil {
+ cell = s.clearBlank()
+ }
+
+ // We're at pending wrap state (phantom cell), incoming cell should
+ // wrap.
+ if s.atPhantom {
+ s.wrapCursor()
+ s.atPhantom = false
+ }
+
+ s.updatePen(cell)
+ s.buf.WriteRune(cell.Rune) //nolint:errcheck
+ for _, c := range cell.Comb {
+ s.buf.WriteRune(c) //nolint:errcheck
+ }
+
+ s.cur.X += cell.Width
+
+ if cell.Width > 0 {
+ s.queuedText = true
+ }
+
+ if s.cur.X >= s.newbuf.Width() {
+ s.atPhantom = true
+ }
+}
+
+// putCellLR draws a cell at the lower right corner of the screen.
+func (s *Screen) putCellLR(cell *Cell) {
+ // Optimize for the lower right corner cell.
+ curX := s.cur.X
+ if cell == nil || !cell.Empty() {
+ s.buf.WriteString(ansi.ResetAutoWrapMode) //nolint:errcheck
+ s.putAttrCell(cell)
+ // Writing to lower-right corner cell should not wrap.
+ s.atPhantom = false
+ s.cur.X = curX
+ s.buf.WriteString(ansi.SetAutoWrapMode) //nolint:errcheck
+ }
+}
+
+// updatePen updates the cursor pen styles.
+func (s *Screen) updatePen(cell *Cell) {
+ if cell == nil {
+ cell = &BlankCell
+ }
+
+ if s.opts.Profile != 0 {
+ // Downsample colors to the given color profile.
+ cell.Style = ConvertStyle(cell.Style, s.opts.Profile)
+ cell.Link = ConvertLink(cell.Link, s.opts.Profile)
+ }
+
+ if !cell.Style.Equal(&s.cur.Style) {
+ seq := cell.Style.DiffSequence(s.cur.Style)
+ if cell.Style.Empty() && len(seq) > len(ansi.ResetStyle) {
+ seq = ansi.ResetStyle
+ }
+ s.buf.WriteString(seq) //nolint:errcheck
+ s.cur.Style = cell.Style
+ }
+ if !cell.Link.Equal(&s.cur.Link) {
+ s.buf.WriteString(ansi.SetHyperlink(cell.Link.URL, cell.Link.Params)) //nolint:errcheck
+ s.cur.Link = cell.Link
+ }
+}
+
+// emitRange emits a range of cells to the buffer. It it equivalent to calling
+// [Screen.putCell] for each cell in the range. This is optimized to use
+// [ansi.ECH] and [ansi.REP].
+// Returns whether the cursor is at the end of interval or somewhere in the
+// middle.
+func (s *Screen) emitRange(line Line, n int) (eoi bool) {
+ for n > 0 {
+ var count int
+ for n > 1 && !cellEqual(line.At(0), line.At(1)) {
+ s.putCell(line.At(0))
+ line = line[1:]
+ n--
+ }
+
+ cell0 := line[0]
+ if n == 1 {
+ s.putCell(cell0)
+ return false
+ }
+
+ count = 2
+ for count < n && cellEqual(line.At(count), cell0) {
+ count++
+ }
+
+ ech := ansi.EraseCharacter(count)
+ cup := ansi.CursorPosition(s.cur.X+count, s.cur.Y)
+ rep := ansi.RepeatPreviousCharacter(count)
+ if s.xtermLike && count > len(ech)+len(cup) && cell0 != nil && cell0.Clear() {
+ s.updatePen(cell0)
+ s.buf.WriteString(ech) //nolint:errcheck
+
+ // If this is the last cell, we don't need to move the cursor.
+ if count < n {
+ s.move(s.cur.X+count, s.cur.Y)
+ } else {
+ return true // cursor in the middle
+ }
+ } else if s.xtermLike && count > len(rep) &&
+ (cell0 == nil || (len(cell0.Comb) == 0 && cell0.Rune < 256)) {
+ // We only support ASCII characters. Most terminals will handle
+ // non-ASCII characters correctly, but some might not, ahem xterm.
+ //
+ // NOTE: [ansi.REP] only repeats the last rune and won't work
+ // if the last cell contains multiple runes.
+
+ wrapPossible := s.cur.X+count >= s.newbuf.Width()
+ repCount := count
+ if wrapPossible {
+ repCount--
+ }
+
+ s.updatePen(cell0)
+ s.putCell(cell0)
+ repCount-- // cell0 is a single width cell ASCII character
+
+ s.buf.WriteString(ansi.RepeatPreviousCharacter(repCount)) //nolint:errcheck
+ s.cur.X += repCount
+ if wrapPossible {
+ s.putCell(cell0)
+ }
+ } else {
+ for i := 0; i < count; i++ {
+ s.putCell(line.At(i))
+ }
+ }
+
+ line = line[clamp(count, 0, len(line)):]
+ n -= count
+ }
+
+ return
+}
+
+// putRange puts a range of cells from the old line to the new line.
+// Returns whether the cursor is at the end of interval or somewhere in the
+// middle.
+func (s *Screen) putRange(oldLine, newLine Line, y, start, end int) (eoi bool) {
+ inline := min(len(ansi.CursorPosition(start+1, y+1)),
+ min(len(ansi.HorizontalPositionAbsolute(start+1)),
+ len(ansi.CursorForward(start+1))))
+ if (end - start + 1) > inline {
+ var j, same int
+ for j, same = start, 0; j <= end; j++ {
+ oldCell, newCell := oldLine.At(j), newLine.At(j)
+ if same == 0 && oldCell != nil && oldCell.Empty() {
+ continue
+ }
+ if cellEqual(oldCell, newCell) {
+ same++
+ } else {
+ if same > end-start {
+ s.emitRange(newLine[start:], j-same-start)
+ s.move(j, y)
+ start = j
+ }
+ same = 0
+ }
+ }
+
+ i := s.emitRange(newLine[start:], j-same-start)
+
+ // Always return 1 for the next [Screen.move] after a [Screen.putRange] if
+ // we found identical characters at end of interval.
+ if same == 0 {
+ return i
+ }
+ return true
+ }
+
+ return s.emitRange(newLine[start:], end-start+1)
+}
+
+// clearToEnd clears the screen from the current cursor position to the end of
+// line.
+func (s *Screen) clearToEnd(blank *Cell, force bool) { //nolint:unparam
+ if s.cur.Y >= 0 {
+ curline := s.curbuf.Line(s.cur.Y)
+ for j := s.cur.X; j < s.curbuf.Width(); j++ {
+ if j >= 0 {
+ c := curline.At(j)
+ if !cellEqual(c, blank) {
+ curline.Set(j, blank)
+ force = true
+ }
+ }
+ }
+ }
+
+ if force {
+ s.updatePen(blank)
+ count := s.newbuf.Width() - s.cur.X
+ if s.el0Cost() <= count {
+ s.buf.WriteString(ansi.EraseLineRight) //nolint:errcheck
+ } else {
+ for i := 0; i < count; i++ {
+ s.putCell(blank)
+ }
+ }
+ }
+}
+
+// clearBlank returns a blank cell based on the current cursor background color.
+func (s *Screen) clearBlank() *Cell {
+ c := BlankCell
+ if !s.cur.Style.Empty() || !s.cur.Link.Empty() {
+ c.Style = s.cur.Style
+ c.Link = s.cur.Link
+ }
+ return &c
+}
+
+// insertCells inserts the count cells pointed by the given line at the current
+// cursor position.
+func (s *Screen) insertCells(line Line, count int) {
+ if s.xtermLike {
+ // Use [ansi.ICH] as an optimization.
+ s.buf.WriteString(ansi.InsertCharacter(count)) //nolint:errcheck
+ } else {
+ // Otherwise, use [ansi.IRM] mode.
+ s.buf.WriteString(ansi.SetInsertReplaceMode) //nolint:errcheck
+ }
+
+ for i := 0; count > 0; i++ {
+ s.putAttrCell(line[i])
+ count--
+ }
+
+ if !s.xtermLike {
+ s.buf.WriteString(ansi.ResetInsertReplaceMode) //nolint:errcheck
+ }
+}
+
+// el0Cost returns the cost of using [ansi.EL] 0 i.e. [ansi.EraseLineRight]. If
+// this terminal supports background color erase, it can be cheaper to use
+// [ansi.EL] 0 i.e. [ansi.EraseLineRight] to clear
+// trailing spaces.
+func (s *Screen) el0Cost() int {
+ if s.xtermLike {
+ return 0
+ }
+ return len(ansi.EraseLineRight)
+}
+
+// transformLine transforms the given line in the current window to the
+// corresponding line in the new window. It uses [ansi.ICH] and [ansi.DCH] to
+// insert or delete characters.
+func (s *Screen) transformLine(y int) {
+ var firstCell, oLastCell, nLastCell int // first, old last, new last index
+ oldLine := s.curbuf.Line(y)
+ newLine := s.newbuf.Line(y)
+
+ // Find the first changed cell in the line
+ var lineChanged bool
+ for i := 0; i < s.newbuf.Width(); i++ {
+ if !cellEqual(newLine.At(i), oldLine.At(i)) {
+ lineChanged = true
+ break
+ }
+ }
+
+ const ceolStandoutGlitch = false
+ if ceolStandoutGlitch && lineChanged {
+ s.move(0, y)
+ s.clearToEnd(nil, false)
+ s.putRange(oldLine, newLine, y, 0, s.newbuf.Width()-1)
+ } else {
+ blank := newLine.At(0)
+
+ // It might be cheaper to clear leading spaces with [ansi.EL] 1 i.e.
+ // [ansi.EraseLineLeft].
+ if blank == nil || blank.Clear() {
+ var oFirstCell, nFirstCell int
+ for oFirstCell = 0; oFirstCell < s.curbuf.Width(); oFirstCell++ {
+ if !cellEqual(oldLine.At(oFirstCell), blank) {
+ break
+ }
+ }
+ for nFirstCell = 0; nFirstCell < s.newbuf.Width(); nFirstCell++ {
+ if !cellEqual(newLine.At(nFirstCell), blank) {
+ break
+ }
+ }
+
+ if nFirstCell == oFirstCell {
+ firstCell = nFirstCell
+
+ // Find the first differing cell
+ for firstCell < s.newbuf.Width() &&
+ cellEqual(oldLine.At(firstCell), newLine.At(firstCell)) {
+ firstCell++
+ }
+ } else if oFirstCell > nFirstCell {
+ firstCell = nFirstCell
+ } else if oFirstCell < nFirstCell {
+ firstCell = oFirstCell
+ el1Cost := len(ansi.EraseLineLeft)
+ if el1Cost < nFirstCell-oFirstCell {
+ if nFirstCell >= s.newbuf.Width() {
+ s.move(0, y)
+ s.updatePen(blank)
+ s.buf.WriteString(ansi.EraseLineRight) //nolint:errcheck
+ } else {
+ s.move(nFirstCell-1, y)
+ s.updatePen(blank)
+ s.buf.WriteString(ansi.EraseLineLeft) //nolint:errcheck
+ }
+
+ for firstCell < nFirstCell {
+ oldLine.Set(firstCell, blank)
+ firstCell++
+ }
+ }
+ }
+ } else {
+ // Find the first differing cell
+ for firstCell < s.newbuf.Width() && cellEqual(newLine.At(firstCell), oldLine.At(firstCell)) {
+ firstCell++
+ }
+ }
+
+ // If we didn't find one, we're done
+ if firstCell >= s.newbuf.Width() {
+ return
+ }
+
+ blank = newLine.At(s.newbuf.Width() - 1)
+ if blank != nil && !blank.Clear() {
+ // Find the last differing cell
+ nLastCell = s.newbuf.Width() - 1
+ for nLastCell > firstCell && cellEqual(newLine.At(nLastCell), oldLine.At(nLastCell)) {
+ nLastCell--
+ }
+
+ if nLastCell >= firstCell {
+ s.move(firstCell, y)
+ s.putRange(oldLine, newLine, y, firstCell, nLastCell)
+ if firstCell < len(oldLine) && firstCell < len(newLine) {
+ copy(oldLine[firstCell:], newLine[firstCell:])
+ } else {
+ copy(oldLine, newLine)
+ }
+ }
+
+ return
+ }
+
+ // Find last non-blank cell in the old line.
+ oLastCell = s.curbuf.Width() - 1
+ for oLastCell > firstCell && cellEqual(oldLine.At(oLastCell), blank) {
+ oLastCell--
+ }
+
+ // Find last non-blank cell in the new line.
+ nLastCell = s.newbuf.Width() - 1
+ for nLastCell > firstCell && cellEqual(newLine.At(nLastCell), blank) {
+ nLastCell--
+ }
+
+ if nLastCell == firstCell && s.el0Cost() < oLastCell-nLastCell {
+ s.move(firstCell, y)
+ if !cellEqual(newLine.At(firstCell), blank) {
+ s.putCell(newLine.At(firstCell))
+ }
+ s.clearToEnd(blank, false)
+ } else if nLastCell != oLastCell &&
+ !cellEqual(newLine.At(nLastCell), oldLine.At(oLastCell)) {
+ s.move(firstCell, y)
+ if oLastCell-nLastCell > s.el0Cost() {
+ if s.putRange(oldLine, newLine, y, firstCell, nLastCell) {
+ s.move(nLastCell+1, y)
+ }
+ s.clearToEnd(blank, false)
+ } else {
+ n := max(nLastCell, oLastCell)
+ s.putRange(oldLine, newLine, y, firstCell, n)
+ }
+ } else {
+ nLastNonBlank := nLastCell
+ oLastNonBlank := oLastCell
+
+ // Find the last cells that really differ.
+ // Can be -1 if no cells differ.
+ for cellEqual(newLine.At(nLastCell), oldLine.At(oLastCell)) {
+ if !cellEqual(newLine.At(nLastCell-1), oldLine.At(oLastCell-1)) {
+ break
+ }
+ nLastCell--
+ oLastCell--
+ if nLastCell == -1 || oLastCell == -1 {
+ break
+ }
+ }
+
+ n := min(oLastCell, nLastCell)
+ if n >= firstCell {
+ s.move(firstCell, y)
+ s.putRange(oldLine, newLine, y, firstCell, n)
+ }
+
+ if oLastCell < nLastCell {
+ m := max(nLastNonBlank, oLastNonBlank)
+ if n != 0 {
+ for n > 0 {
+ wide := newLine.At(n + 1)
+ if wide == nil || !wide.Empty() {
+ break
+ }
+ n--
+ oLastCell--
+ }
+ } else if n >= firstCell && newLine.At(n) != nil && newLine.At(n).Width > 1 {
+ next := newLine.At(n + 1)
+ for next != nil && next.Empty() {
+ n++
+ oLastCell++
+ }
+ }
+
+ s.move(n+1, y)
+ ichCost := 3 + nLastCell - oLastCell
+ if s.xtermLike && (nLastCell < nLastNonBlank || ichCost > (m-n)) {
+ s.putRange(oldLine, newLine, y, n+1, m)
+ } else {
+ s.insertCells(newLine[n+1:], nLastCell-oLastCell)
+ }
+ } else if oLastCell > nLastCell {
+ s.move(n+1, y)
+ dchCost := 3 + oLastCell - nLastCell
+ if dchCost > len(ansi.EraseLineRight)+nLastNonBlank-(n+1) {
+ if s.putRange(oldLine, newLine, y, n+1, nLastNonBlank) {
+ s.move(nLastNonBlank+1, y)
+ }
+ s.clearToEnd(blank, false)
+ } else {
+ s.updatePen(blank)
+ s.deleteCells(oLastCell - nLastCell)
+ }
+ }
+ }
+ }
+
+ // Update the old line with the new line
+ if firstCell < len(oldLine) && firstCell < len(newLine) {
+ copy(oldLine[firstCell:], newLine[firstCell:])
+ } else {
+ copy(oldLine, newLine)
+ }
+}
+
+// deleteCells deletes the count cells at the current cursor position and moves
+// the rest of the line to the left. This is equivalent to [ansi.DCH].
+func (s *Screen) deleteCells(count int) {
+ // [ansi.DCH] will shift in cells from the right margin so we need to
+ // ensure that they are the right style.
+ s.buf.WriteString(ansi.DeleteCharacter(count)) //nolint:errcheck
+}
+
+// clearToBottom clears the screen from the current cursor position to the end
+// of the screen.
+func (s *Screen) clearToBottom(blank *Cell) {
+ row, col := s.cur.Y, s.cur.X
+ if row < 0 {
+ row = 0
+ }
+
+ s.updatePen(blank)
+ s.buf.WriteString(ansi.EraseScreenBelow) //nolint:errcheck
+ // Clear the rest of the current line
+ s.curbuf.ClearRect(Rect(col, row, s.curbuf.Width()-col, 1))
+ // Clear everything below the current line
+ s.curbuf.ClearRect(Rect(0, row+1, s.curbuf.Width(), s.curbuf.Height()-row-1))
+}
+
+// clearBottom tests if clearing the end of the screen would satisfy part of
+// the screen update. Scan backwards through lines in the screen checking if
+// each is blank and one or more are changed.
+// It returns the top line.
+func (s *Screen) clearBottom(total int) (top int) {
+ if total <= 0 {
+ return
+ }
+
+ top = total
+ last := s.newbuf.Width()
+ blank := s.clearBlank()
+ canClearWithBlank := blank == nil || blank.Clear()
+
+ if canClearWithBlank {
+ var row int
+ for row = total - 1; row >= 0; row-- {
+ oldLine := s.curbuf.Line(row)
+ newLine := s.newbuf.Line(row)
+
+ var col int
+ ok := true
+ for col = 0; ok && col < last; col++ {
+ ok = cellEqual(newLine.At(col), blank)
+ }
+ if !ok {
+ break
+ }
+
+ for col = 0; ok && col < last; col++ {
+ ok = len(oldLine) == last && cellEqual(oldLine.At(col), blank)
+ }
+ if !ok {
+ top = row
+ }
+ }
+
+ if top < total {
+ s.move(0, top-1) // top is 1-based
+ s.clearToBottom(blank)
+ if s.oldhash != nil && s.newhash != nil &&
+ row < len(s.oldhash) && row < len(s.newhash) {
+ for row := top; row < s.newbuf.Height(); row++ {
+ s.oldhash[row] = s.newhash[row]
+ }
+ }
+ }
+ }
+
+ return
+}
+
+// clearScreen clears the screen and put cursor at home.
+func (s *Screen) clearScreen(blank *Cell) {
+ s.updatePen(blank)
+ s.buf.WriteString(ansi.CursorHomePosition) //nolint:errcheck
+ s.buf.WriteString(ansi.EraseEntireScreen) //nolint:errcheck
+ s.cur.X, s.cur.Y = 0, 0
+ s.curbuf.Fill(blank)
+}
+
+// clearBelow clears everything below and including the row.
+func (s *Screen) clearBelow(blank *Cell, row int) {
+ s.move(0, row)
+ s.clearToBottom(blank)
+}
+
+// clearUpdate forces a screen redraw.
+func (s *Screen) clearUpdate() {
+ blank := s.clearBlank()
+ var nonEmpty int
+ if s.opts.AltScreen {
+ // XXX: We're using the maximum height of the two buffers to ensure
+ // we write newly added lines to the screen in [Screen.transformLine].
+ nonEmpty = max(s.curbuf.Height(), s.newbuf.Height())
+ s.clearScreen(blank)
+ } else {
+ nonEmpty = s.newbuf.Height()
+ s.clearBelow(blank, 0)
+ }
+ nonEmpty = s.clearBottom(nonEmpty)
+ for i := 0; i < nonEmpty; i++ {
+ s.transformLine(i)
+ }
+}
+
+// Flush flushes the buffer to the screen.
+func (s *Screen) Flush() (err error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ return s.flush()
+}
+
+func (s *Screen) flush() (err error) {
+ // Write the buffer
+ if s.buf.Len() > 0 {
+ _, err = s.w.Write(s.buf.Bytes()) //nolint:errcheck
+ if err == nil {
+ s.buf.Reset()
+ }
+ }
+
+ return
+}
+
+// Render renders changes of the screen to the internal buffer. Call
+// [Screen.Flush] to flush pending changes to the screen.
+func (s *Screen) Render() {
+ s.mu.Lock()
+ s.render()
+ s.mu.Unlock()
+}
+
+func (s *Screen) render() {
+ // Do we need to render anything?
+ if s.opts.AltScreen == s.altScreenMode &&
+ !s.opts.ShowCursor == s.cursorHidden &&
+ !s.clear &&
+ len(s.touch) == 0 &&
+ len(s.queueAbove) == 0 {
+ return
+ }
+
+ // TODO: Investigate whether this is necessary. Theoretically, terminals
+ // can add/remove tab stops and we should be able to handle that. We could
+ // use [ansi.DECTABSR] to read the tab stops, but that's not implemented in
+ // most terminals :/
+ // // Are we using hard tabs? If so, ensure tabs are using the
+ // // default interval using [ansi.DECST8C].
+ // if s.opts.HardTabs && !s.initTabs {
+ // s.buf.WriteString(ansi.SetTabEvery8Columns)
+ // s.initTabs = true
+ // }
+
+ // Do we need alt-screen mode?
+ if s.opts.AltScreen != s.altScreenMode {
+ if s.opts.AltScreen {
+ s.buf.WriteString(ansi.SetAltScreenSaveCursorMode)
+ } else {
+ s.buf.WriteString(ansi.ResetAltScreenSaveCursorMode)
+ }
+ s.altScreenMode = s.opts.AltScreen
+ }
+
+ // Do we need text cursor mode?
+ if !s.opts.ShowCursor != s.cursorHidden {
+ s.cursorHidden = !s.opts.ShowCursor
+ if s.cursorHidden {
+ s.buf.WriteString(ansi.HideCursor)
+ }
+ }
+
+ // Do we have queued strings to write above the screen?
+ if len(s.queueAbove) > 0 {
+ // TODO: Use scrolling region if available.
+ // TODO: Use [Screen.Write] [io.Writer] interface.
+
+ // We need to scroll the screen up by the number of lines in the queue.
+ // We can't use [ansi.SU] because we want the cursor to move down until
+ // it reaches the bottom of the screen.
+ s.move(0, s.newbuf.Height()-1)
+ s.buf.WriteString(strings.Repeat("\n", len(s.queueAbove)))
+ s.cur.Y += len(s.queueAbove)
+ // XXX: Now go to the top of the screen, insert new lines, and write
+ // the queued strings. It is important to use [Screen.moveCursor]
+ // instead of [Screen.move] because we don't want to perform any checks
+ // on the cursor position.
+ s.moveCursor(0, 0, false)
+ s.buf.WriteString(ansi.InsertLine(len(s.queueAbove)))
+ for _, line := range s.queueAbove {
+ s.buf.WriteString(line + "\r\n")
+ }
+
+ // Clear the queue
+ s.queueAbove = s.queueAbove[:0]
+ }
+
+ var nonEmpty int
+
+ // XXX: In inline mode, after a screen resize, we need to clear the extra
+ // lines at the bottom of the screen. This is because in inline mode, we
+ // don't use the full screen height and the current buffer size might be
+ // larger than the new buffer size.
+ partialClear := !s.opts.AltScreen && s.cur.X != -1 && s.cur.Y != -1 &&
+ s.curbuf.Width() == s.newbuf.Width() &&
+ s.curbuf.Height() > 0 &&
+ s.curbuf.Height() > s.newbuf.Height()
+
+ if !s.clear && partialClear {
+ s.clearBelow(nil, s.newbuf.Height()-1)
+ }
+
+ if s.clear {
+ s.clearUpdate()
+ s.clear = false
+ } else if len(s.touch) > 0 {
+ if s.opts.AltScreen {
+ // Optimize scrolling for the alternate screen buffer.
+ // TODO: Should we optimize for inline mode as well? If so, we need
+ // to know the actual cursor position to use [ansi.DECSTBM].
+ s.scrollOptimize()
+ }
+
+ var changedLines int
+ var i int
+
+ if s.opts.AltScreen {
+ nonEmpty = min(s.curbuf.Height(), s.newbuf.Height())
+ } else {
+ nonEmpty = s.newbuf.Height()
+ }
+
+ nonEmpty = s.clearBottom(nonEmpty)
+ for i = 0; i < nonEmpty; i++ {
+ _, ok := s.touch[i]
+ if ok {
+ s.transformLine(i)
+ changedLines++
+ }
+ }
+ }
+
+ // Sync windows and screen
+ s.touch = make(map[int]lineData, s.newbuf.Height())
+
+ if s.curbuf.Width() != s.newbuf.Width() || s.curbuf.Height() != s.newbuf.Height() {
+ // Resize the old buffer to match the new buffer.
+ _, oldh := s.curbuf.Width(), s.curbuf.Height()
+ s.curbuf.Resize(s.newbuf.Width(), s.newbuf.Height())
+ // Sync new lines to old lines
+ for i := oldh - 1; i < s.newbuf.Height(); i++ {
+ copy(s.curbuf.Line(i), s.newbuf.Line(i))
+ }
+ }
+
+ s.updatePen(nil) // nil indicates a blank cell with no styles
+
+ // Do we have enough changes to justify toggling the cursor?
+ if s.buf.Len() > 1 && s.opts.ShowCursor && !s.cursorHidden && s.queuedText {
+ nb := new(bytes.Buffer)
+ nb.Grow(s.buf.Len() + len(ansi.HideCursor) + len(ansi.ShowCursor))
+ nb.WriteString(ansi.HideCursor)
+ nb.Write(s.buf.Bytes())
+ nb.WriteString(ansi.ShowCursor)
+ *s.buf = *nb
+ }
+
+ s.queuedText = false
+}
+
+// Close writes the final screen update and resets the screen.
+func (s *Screen) Close() (err error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ s.render()
+ s.updatePen(nil)
+ // Go to the bottom of the screen
+ s.move(0, s.newbuf.Height()-1)
+
+ if s.altScreenMode {
+ s.buf.WriteString(ansi.ResetAltScreenSaveCursorMode)
+ s.altScreenMode = false
+ }
+
+ if s.cursorHidden {
+ s.buf.WriteString(ansi.ShowCursor)
+ s.cursorHidden = false
+ }
+
+ // Write the buffer
+ err = s.flush()
+ if err != nil {
+ return
+ }
+
+ s.reset()
+ return
+}
+
+// reset resets the screen to its initial state.
+func (s *Screen) reset() {
+ s.scrollHeight = 0
+ s.cursorHidden = false
+ s.altScreenMode = false
+ s.touch = make(map[int]lineData, s.newbuf.Height())
+ if s.curbuf != nil {
+ s.curbuf.Clear()
+ }
+ if s.newbuf != nil {
+ s.newbuf.Clear()
+ }
+ s.buf.Reset()
+ s.tabs = DefaultTabStops(s.newbuf.Width())
+ s.oldhash, s.newhash = nil, nil
+
+ // We always disable HardTabs when termtype is "linux".
+ if strings.HasPrefix(s.opts.Term, "linux") {
+ s.opts.HardTabs = false
+ }
+}
+
+// Resize resizes the screen.
+func (s *Screen) Resize(width, height int) bool {
+ oldw := s.newbuf.Width()
+ oldh := s.newbuf.Height()
+
+ if s.opts.AltScreen || width != oldw {
+ // We only clear the whole screen if the width changes. Adding/removing
+ // rows is handled by the [Screen.render] and [Screen.transformLine]
+ // methods.
+ s.clear = true
+ }
+
+ // Clear new columns and lines
+ if width > oldh {
+ s.ClearRect(Rect(max(oldw-1, 0), 0, width-oldw, height))
+ } else if width < oldw {
+ s.ClearRect(Rect(max(width-1, 0), 0, oldw-width, height))
+ }
+
+ if height > oldh {
+ s.ClearRect(Rect(0, max(oldh-1, 0), width, height-oldh))
+ } else if height < oldh {
+ s.ClearRect(Rect(0, max(height-1, 0), width, oldh-height))
+ }
+
+ s.mu.Lock()
+ s.newbuf.Resize(width, height)
+ s.tabs.Resize(width)
+ s.oldhash, s.newhash = nil, nil
+ s.scrollHeight = 0 // reset scroll lines
+ s.mu.Unlock()
+
+ return true
+}
+
+// MoveTo moves the cursor to the given position.
+func (s *Screen) MoveTo(x, y int) {
+ s.mu.Lock()
+ s.move(x, y)
+ s.mu.Unlock()
+}
+
+// InsertAbove inserts string above the screen. The inserted string is not
+// managed by the screen. This does nothing when alternate screen mode is
+// enabled.
+func (s *Screen) InsertAbove(str string) {
+ if s.opts.AltScreen {
+ return
+ }
+ s.mu.Lock()
+ for _, line := range strings.Split(str, "\n") {
+ s.queueAbove = append(s.queueAbove, s.method.Truncate(line, s.Width(), ""))
+ }
+ s.mu.Unlock()
+}
diff --git a/vendor/github.com/charmbracelet/x/cellbuf/sequence.go b/vendor/github.com/charmbracelet/x/cellbuf/sequence.go
new file mode 100644
index 00000000..613eefef
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/cellbuf/sequence.go
@@ -0,0 +1,131 @@
+package cellbuf
+
+import (
+ "bytes"
+ "image/color"
+
+ "github.com/charmbracelet/x/ansi"
+)
+
+// ReadStyle reads a Select Graphic Rendition (SGR) escape sequences from a
+// list of parameters.
+func ReadStyle(params ansi.Params, pen *Style) {
+ if len(params) == 0 {
+ pen.Reset()
+ return
+ }
+
+ for i := 0; i < len(params); i++ {
+ param, hasMore, _ := params.Param(i, 0)
+ switch param {
+ case 0: // Reset
+ pen.Reset()
+ case 1: // Bold
+ pen.Bold(true)
+ case 2: // Dim/Faint
+ pen.Faint(true)
+ case 3: // Italic
+ pen.Italic(true)
+ case 4: // Underline
+ nextParam, _, ok := params.Param(i+1, 0)
+ if hasMore && ok { // Only accept subparameters i.e. separated by ":"
+ switch nextParam {
+ case 0, 1, 2, 3, 4, 5:
+ i++
+ switch nextParam {
+ case 0: // No Underline
+ pen.UnderlineStyle(NoUnderline)
+ case 1: // Single Underline
+ pen.UnderlineStyle(SingleUnderline)
+ case 2: // Double Underline
+ pen.UnderlineStyle(DoubleUnderline)
+ case 3: // Curly Underline
+ pen.UnderlineStyle(CurlyUnderline)
+ case 4: // Dotted Underline
+ pen.UnderlineStyle(DottedUnderline)
+ case 5: // Dashed Underline
+ pen.UnderlineStyle(DashedUnderline)
+ }
+ }
+ } else {
+ // Single Underline
+ pen.Underline(true)
+ }
+ case 5: // Slow Blink
+ pen.SlowBlink(true)
+ case 6: // Rapid Blink
+ pen.RapidBlink(true)
+ case 7: // Reverse
+ pen.Reverse(true)
+ case 8: // Conceal
+ pen.Conceal(true)
+ case 9: // Crossed-out/Strikethrough
+ pen.Strikethrough(true)
+ case 22: // Normal Intensity (not bold or faint)
+ pen.Bold(false).Faint(false)
+ case 23: // Not italic, not Fraktur
+ pen.Italic(false)
+ case 24: // Not underlined
+ pen.Underline(false)
+ case 25: // Blink off
+ pen.SlowBlink(false).RapidBlink(false)
+ case 27: // Positive (not reverse)
+ pen.Reverse(false)
+ case 28: // Reveal
+ pen.Conceal(false)
+ case 29: // Not crossed out
+ pen.Strikethrough(false)
+ case 30, 31, 32, 33, 34, 35, 36, 37: // Set foreground
+ pen.Foreground(ansi.Black + ansi.BasicColor(param-30)) //nolint:gosec
+ case 38: // Set foreground 256 or truecolor
+ var c color.Color
+ n := ReadStyleColor(params[i:], &c)
+ if n > 0 {
+ pen.Foreground(c)
+ i += n - 1
+ }
+ case 39: // Default foreground
+ pen.Foreground(nil)
+ case 40, 41, 42, 43, 44, 45, 46, 47: // Set background
+ pen.Background(ansi.Black + ansi.BasicColor(param-40)) //nolint:gosec
+ case 48: // Set background 256 or truecolor
+ var c color.Color
+ n := ReadStyleColor(params[i:], &c)
+ if n > 0 {
+ pen.Background(c)
+ i += n - 1
+ }
+ case 49: // Default Background
+ pen.Background(nil)
+ case 58: // Set underline color
+ var c color.Color
+ n := ReadStyleColor(params[i:], &c)
+ if n > 0 {
+ pen.UnderlineColor(c)
+ i += n - 1
+ }
+ case 59: // Default underline color
+ pen.UnderlineColor(nil)
+ case 90, 91, 92, 93, 94, 95, 96, 97: // Set bright foreground
+ pen.Foreground(ansi.BrightBlack + ansi.BasicColor(param-90)) //nolint:gosec
+ case 100, 101, 102, 103, 104, 105, 106, 107: // Set bright background
+ pen.Background(ansi.BrightBlack + ansi.BasicColor(param-100)) //nolint:gosec
+ }
+ }
+}
+
+// ReadLink reads a hyperlink escape sequence from a data buffer.
+func ReadLink(p []byte, link *Link) {
+ params := bytes.Split(p, []byte{';'})
+ if len(params) != 3 {
+ return
+ }
+ link.Params = string(params[1])
+ link.URL = string(params[2])
+}
+
+// ReadStyleColor reads a color from a list of parameters.
+// See [ansi.ReadStyleColor] for more information.
+func ReadStyleColor(params ansi.Params, c *color.Color) int {
+ return ansi.ReadStyleColor(params, c)
+}
diff --git a/vendor/github.com/charmbracelet/x/cellbuf/style.go b/vendor/github.com/charmbracelet/x/cellbuf/style.go
new file mode 100644
index 00000000..82c4afb7
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/cellbuf/style.go
@@ -0,0 +1,31 @@
+package cellbuf
+
+import (
+ "github.com/charmbracelet/colorprofile"
+)
+
+// Convert converts a style to respect the given color profile.
+func ConvertStyle(s Style, p colorprofile.Profile) Style {
+ switch p {
+ case colorprofile.TrueColor:
+ return s
+ case colorprofile.Ascii:
+ s.Fg = nil
+ s.Bg = nil
+ s.Ul = nil
+ case colorprofile.NoTTY:
+ return Style{}
+ }
+
+ if s.Fg != nil {
+ s.Fg = p.Convert(s.Fg)
+ }
+ if s.Bg != nil {
+ s.Bg = p.Convert(s.Bg)
+ }
+ if s.Ul != nil {
+ s.Ul = p.Convert(s.Ul)
+ }
+
+ return s
+}
diff --git a/vendor/github.com/charmbracelet/x/cellbuf/tabstop.go b/vendor/github.com/charmbracelet/x/cellbuf/tabstop.go
new file mode 100644
index 00000000..24eec449
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/cellbuf/tabstop.go
@@ -0,0 +1,137 @@
+package cellbuf
+
+// DefaultTabInterval is the default tab interval.
+const DefaultTabInterval = 8
+
+// TabStops represents horizontal line tab stops.
+type TabStops struct {
+ stops []int
+ interval int
+ width int
+}
+
+// NewTabStops creates a new set of tab stops from a number of columns and an
+// interval.
+func NewTabStops(width, interval int) *TabStops {
+ ts := new(TabStops)
+ ts.interval = interval
+ ts.width = width
+ ts.stops = make([]int, (width+(interval-1))/interval)
+ ts.init(0, width)
+ return ts
+}
+
+// DefaultTabStops creates a new set of tab stops with the default interval.
+func DefaultTabStops(cols int) *TabStops {
+ return NewTabStops(cols, DefaultTabInterval)
+}
+
+// Resize resizes the tab stops to the given width.
+func (ts *TabStops) Resize(width int) {
+ if width == ts.width {
+ return
+ }
+
+ if width < ts.width {
+ size := (width + (ts.interval - 1)) / ts.interval
+ ts.stops = ts.stops[:size]
+ } else {
+ size := (width - ts.width + (ts.interval - 1)) / ts.interval
+ ts.stops = append(ts.stops, make([]int, size)...)
+ }
+
+ ts.init(ts.width, width)
+ ts.width = width
+}
+
+// IsStop returns true if the given column is a tab stop.
+func (ts TabStops) IsStop(col int) bool {
+ mask := ts.mask(col)
+ i := col >> 3
+ if i < 0 || i >= len(ts.stops) {
+ return false
+ }
+ return ts.stops[i]&mask != 0
+}
+
+// Next returns the next tab stop after the given column.
+func (ts TabStops) Next(col int) int {
+ return ts.Find(col, 1)
+}
+
+// Prev returns the previous tab stop before the given column.
+func (ts TabStops) Prev(col int) int {
+ return ts.Find(col, -1)
+}
+
+// Find returns the prev/next tab stop before/after the given column and delta.
+// If delta is positive, it returns the next tab stop after the given column.
+// If delta is negative, it returns the previous tab stop before the given column.
+// If delta is zero, it returns the given column.
+func (ts TabStops) Find(col, delta int) int {
+ if delta == 0 {
+ return col
+ }
+
+ var prev bool
+ count := delta
+ if count < 0 {
+ count = -count
+ prev = true
+ }
+
+ for count > 0 {
+ if !prev {
+ if col >= ts.width-1 {
+ return col
+ }
+
+ col++
+ } else {
+ if col < 1 {
+ return col
+ }
+
+ col--
+ }
+
+ if ts.IsStop(col) {
+ count--
+ }
+ }
+
+ return col
+}
+
+// Set adds a tab stop at the given column.
+func (ts *TabStops) Set(col int) {
+ mask := ts.mask(col)
+ ts.stops[col>>3] |= mask
+}
+
+// Reset removes the tab stop at the given column.
+func (ts *TabStops) Reset(col int) {
+ mask := ts.mask(col)
+ ts.stops[col>>3] &= ^mask
+}
+
+// Clear removes all tab stops.
+func (ts *TabStops) Clear() {
+ ts.stops = make([]int, len(ts.stops))
+}
+
+// mask returns the mask for the given column.
+func (ts *TabStops) mask(col int) int {
+ return 1 << (col & (ts.interval - 1))
+}
+
+// init initializes the tab stops starting from col until width.
+func (ts *TabStops) init(col, width int) {
+ for x := col; x < width; x++ {
+ if x%ts.interval == 0 {
+ ts.Set(x)
+ } else {
+ ts.Reset(x)
+ }
+ }
+}
diff --git a/vendor/github.com/charmbracelet/x/cellbuf/utils.go b/vendor/github.com/charmbracelet/x/cellbuf/utils.go
new file mode 100644
index 00000000..b0452fa9
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/cellbuf/utils.go
@@ -0,0 +1,38 @@
+package cellbuf
+
+import (
+ "strings"
+)
+
+// Height returns the height of a string.
+func Height(s string) int {
+ return strings.Count(s, "\n") + 1
+}
+
+func min(a, b int) int { //nolint:predeclared
+ if a > b {
+ return b
+ }
+ return a
+}
+
+func max(a, b int) int { //nolint:predeclared
+ if a > b {
+ return a
+ }
+ return b
+}
+
+func clamp(v, low, high int) int {
+ if high < low {
+ low, high = high, low
+ }
+ return min(high, max(low, v))
+}
+
+func abs(a int) int {
+ if a < 0 {
+ return -a
+ }
+ return a
+}
diff --git a/vendor/github.com/charmbracelet/x/cellbuf/wrap.go b/vendor/github.com/charmbracelet/x/cellbuf/wrap.go
new file mode 100644
index 00000000..59a2a337
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/cellbuf/wrap.go
@@ -0,0 +1,178 @@
+package cellbuf
+
+import (
+ "bytes"
+ "unicode"
+ "unicode/utf8"
+
+ "github.com/charmbracelet/x/ansi"
+)
+
+// Wrap returns a string that is wrapped to the specified limit applying any
+// ANSI escape sequences in the string. It tries to wrap the string at word
+// boundaries, but will break words if necessary.
+//
+// The breakpoints string is a list of characters that are considered
+// breakpoints for word wrapping. A hyphen (-) is always considered a
+// breakpoint.
+//
+// Note: breakpoints must be a string of 1-cell wide rune characters.
+func Wrap(s string, limit int, breakpoints string) string {
+ if len(s) == 0 {
+ return ""
+ }
+
+ if limit < 1 {
+ return s
+ }
+
+ p := ansi.GetParser()
+ defer ansi.PutParser(p)
+
+ var (
+ buf bytes.Buffer
+ word bytes.Buffer
+ space bytes.Buffer
+ style, curStyle Style
+ link, curLink Link
+ curWidth int
+ wordLen int
+ )
+
+ addSpace := func() {
+ curWidth += space.Len()
+ buf.Write(space.Bytes())
+ space.Reset()
+ }
+
+ addWord := func() {
+ if word.Len() == 0 {
+ return
+ }
+
+ curLink = link
+ curStyle = style
+
+ addSpace()
+ curWidth += wordLen
+ buf.Write(word.Bytes())
+ word.Reset()
+ wordLen = 0
+ }
+
+ addNewline := func() {
+ if !curStyle.Empty() {
+ buf.WriteString(ansi.ResetStyle)
+ }
+ if !curLink.Empty() {
+ buf.WriteString(ansi.ResetHyperlink())
+ }
+ buf.WriteByte('\n')
+ if !curLink.Empty() {
+ buf.WriteString(ansi.SetHyperlink(curLink.URL, curLink.Params))
+ }
+ if !curStyle.Empty() {
+ buf.WriteString(curStyle.Sequence())
+ }
+ curWidth = 0
+ space.Reset()
+ }
+
+ var state byte
+ for len(s) > 0 {
+ seq, width, n, newState := ansi.DecodeSequence(s, state, p)
+ switch width {
+ case 0:
+ if ansi.Equal(seq, "\t") {
+ addWord()
+ space.WriteString(seq)
+ break
+ } else if ansi.Equal(seq, "\n") {
+ if wordLen == 0 {
+ if curWidth+space.Len() > limit {
+ curWidth = 0
+ } else {
+ // preserve whitespaces
+ buf.Write(space.Bytes())
+ }
+ space.Reset()
+ }
+
+ addWord()
+ addNewline()
+ break
+ } else if ansi.HasCsiPrefix(seq) && p.Command() == 'm' {
+ // SGR style sequence [ansi.SGR]
+ ReadStyle(p.Params(), &style)
+ } else if ansi.HasOscPrefix(seq) && p.Command() == 8 {
+ // Hyperlink sequence [ansi.SetHyperlink]
+ ReadLink(p.Data(), &link)
+ }
+
+ word.WriteString(seq)
+ default:
+ if len(seq) == 1 {
+ // ASCII
+ r, _ := utf8.DecodeRuneInString(seq)
+ if unicode.IsSpace(r) {
+ addWord()
+ space.WriteRune(r)
+ break
+ } else if r == '-' || runeContainsAny(r, breakpoints) {
+ addSpace()
+ if curWidth+wordLen+width <= limit {
+ addWord()
+ buf.WriteString(seq)
+ curWidth += width
+ break
+ }
+ }
+ }
+
+ if wordLen+width > limit {
+ // Hardwrap the word if it's too long
+ addWord()
+ }
+
+ word.WriteString(seq)
+ wordLen += width
+
+ if curWidth+wordLen+space.Len() > limit {
+ addNewline()
+ }
+ }
+
+ s = s[n:]
+ state = newState
+ }
+
+ if wordLen == 0 {
+ if curWidth+space.Len() > limit {
+ curWidth = 0
+ } else {
+ // preserve whitespaces
+ buf.Write(space.Bytes())
+ }
+ space.Reset()
+ }
+
+ addWord()
+
+ if !curLink.Empty() {
+ buf.WriteString(ansi.ResetHyperlink())
+ }
+ if !curStyle.Empty() {
+ buf.WriteString(ansi.ResetStyle)
+ }
+
+ return buf.String()
+}
+
+func runeContainsAny[T string | []rune](r rune, s T) bool {
+ for _, c := range []rune(s) {
+ if c == r {
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/charmbracelet/x/cellbuf/writer.go b/vendor/github.com/charmbracelet/x/cellbuf/writer.go
new file mode 100644
index 00000000..ae8b2a81
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/cellbuf/writer.go
@@ -0,0 +1,339 @@
+package cellbuf
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+
+ "github.com/charmbracelet/x/ansi"
+)
+
+// CellBuffer is a cell buffer that represents a set of cells in a screen or a
+// grid.
+type CellBuffer interface {
+ // Cell returns the cell at the given position.
+ Cell(x, y int) *Cell
+ // SetCell sets the cell at the given position to the given cell. It
+ // returns whether the cell was set successfully.
+ SetCell(x, y int, c *Cell) bool
+ // Bounds returns the bounds of the cell buffer.
+ Bounds() Rectangle
+}
+
+// FillRect fills the rectangle within the cell buffer with the given cell.
+// This will not fill cells outside the bounds of the cell buffer.
+func FillRect(s CellBuffer, c *Cell, rect Rectangle) {
+ for y := rect.Min.Y; y < rect.Max.Y; y++ {
+ for x := rect.Min.X; x < rect.Max.X; x++ {
+ s.SetCell(x, y, c) //nolint:errcheck
+ }
+ }
+}
+
+// Fill fills the cell buffer with the given cell.
+func Fill(s CellBuffer, c *Cell) {
+ FillRect(s, c, s.Bounds())
+}
+
+// ClearRect clears the rectangle within the cell buffer with blank cells.
+func ClearRect(s CellBuffer, rect Rectangle) {
+ FillRect(s, nil, rect)
+}
+
+// Clear clears the cell buffer with blank cells.
+func Clear(s CellBuffer) {
+ Fill(s, nil)
+}
+
+// SetContentRect clears the rectangle within the cell buffer with blank cells,
+// and sets the given string as its content. If the height or width of the
+// string exceeds the height or width of the cell buffer, it will be truncated.
+func SetContentRect(s CellBuffer, str string, rect Rectangle) {
+ // Replace all "\n" with "\r\n" to ensure the cursor is reset to the start
+ // of the line. Make sure we don't replace "\r\n" with "\r\r\n".
+ str = strings.ReplaceAll(str, "\r\n", "\n")
+ str = strings.ReplaceAll(str, "\n", "\r\n")
+ ClearRect(s, rect)
+ printString(s, ansi.GraphemeWidth, rect.Min.X, rect.Min.Y, rect, str, true, "")
+}
+
+// SetContent clears the cell buffer with blank cells, and sets the given string
+// as its content. If the height or width of the string exceeds the height or
+// width of the cell buffer, it will be truncated.
+func SetContent(s CellBuffer, str string) {
+ SetContentRect(s, str, s.Bounds())
+}
+
+// Render returns a string representation of the grid with ANSI escape sequences.
+func Render(d CellBuffer) string {
+ var buf bytes.Buffer
+ height := d.Bounds().Dy()
+ for y := 0; y < height; y++ {
+ _, line := RenderLine(d, y)
+ buf.WriteString(line)
+ if y < height-1 {
+ buf.WriteString("\r\n")
+ }
+ }
+ return buf.String()
+}
+
+// RenderLine returns a string representation of the yth line of the grid along
+// with the width of the line.
+func RenderLine(d CellBuffer, n int) (w int, line string) {
+ var pen Style
+ var link Link
+ var buf bytes.Buffer
+ var pendingLine string
+ var pendingWidth int // this ignores space cells until we hit a non-space cell
+
+ writePending := func() {
+ // If there's no pending line, we don't need to do anything.
+ if len(pendingLine) == 0 {
+ return
+ }
+ buf.WriteString(pendingLine)
+ w += pendingWidth
+ pendingWidth = 0
+ pendingLine = ""
+ }
+
+ for x := 0; x < d.Bounds().Dx(); x++ {
+ if cell := d.Cell(x, n); cell != nil && cell.Width > 0 {
+ // Convert the cell's style and link to the given color profile.
+ cellStyle := cell.Style
+ cellLink := cell.Link
+ if cellStyle.Empty() && !pen.Empty() {
+ writePending()
+ buf.WriteString(ansi.ResetStyle) //nolint:errcheck
+ pen.Reset()
+ }
+ if !cellStyle.Equal(&pen) {
+ writePending()
+ seq := cellStyle.DiffSequence(pen)
+ buf.WriteString(seq) // nolint:errcheck
+ pen = cellStyle
+ }
+
+ // Write the URL escape sequence
+ if cellLink != link && link.URL != "" {
+ writePending()
+ buf.WriteString(ansi.ResetHyperlink()) //nolint:errcheck
+ link.Reset()
+ }
+ if cellLink != link {
+ writePending()
+ buf.WriteString(ansi.SetHyperlink(cellLink.URL, cellLink.Params)) //nolint:errcheck
+ link = cellLink
+ }
+
+ // We only write the cell content if it's not empty. If it is, we
+ // append it to the pending line and width to be evaluated later.
+ if cell.Equal(&BlankCell) {
+ pendingLine += cell.String()
+ pendingWidth += cell.Width
+ } else {
+ writePending()
+ buf.WriteString(cell.String())
+ w += cell.Width
+ }
+ }
+ }
+ if link.URL != "" {
+ buf.WriteString(ansi.ResetHyperlink()) //nolint:errcheck
+ }
+ if !pen.Empty() {
+ buf.WriteString(ansi.ResetStyle) //nolint:errcheck
+ }
+ return w, strings.TrimRight(buf.String(), " ") // Trim trailing spaces
+}
+
+// ScreenWriter represents a writer that writes to a [Screen] parsing ANSI
+// escape sequences and Unicode characters and converting them into cells that
+// can be written to a cell [Buffer].
+type ScreenWriter struct {
+ *Screen
+}
+
+// NewScreenWriter creates a new ScreenWriter that writes to the given Screen.
+// This is a convenience function for creating a ScreenWriter.
+func NewScreenWriter(s *Screen) *ScreenWriter {
+ return &ScreenWriter{s}
+}
+
+// Write writes the given bytes to the screen.
+// This will recognize ANSI [ansi.SGR] style and [ansi.SetHyperlink] escape
+// sequences.
+func (s *ScreenWriter) Write(p []byte) (n int, err error) {
+ printString(s.Screen, s.method,
+ s.cur.X, s.cur.Y, s.Bounds(),
+ p, false, "")
+ return len(p), nil
+}
+
+// SetContent clears the screen with blank cells, and sets the given string as
+// its content. If the height or width of the string exceeds the height or
+// width of the screen, it will be truncated.
+//
+// This will recognize ANSI [ansi.SGR] style and [ansi.SetHyperlink] escape sequences.
+func (s *ScreenWriter) SetContent(str string) {
+ s.SetContentRect(str, s.Bounds())
+}
+
+// SetContentRect clears the rectangle within the screen with blank cells, and
+// sets the given string as its content. If the height or width of the string
+// exceeds the height or width of the screen, it will be truncated.
+//
+// This will recognize ANSI [ansi.SGR] style and [ansi.SetHyperlink] escape
+// sequences.
+func (s *ScreenWriter) SetContentRect(str string, rect Rectangle) {
+ // Replace all "\n" with "\r\n" to ensure the cursor is reset to the start
+ // of the line. Make sure we don't replace "\r\n" with "\r\r\n".
+ str = strings.ReplaceAll(str, "\r\n", "\n")
+ str = strings.ReplaceAll(str, "\n", "\r\n")
+ s.ClearRect(rect)
+ printString(s.Screen, s.method,
+ rect.Min.X, rect.Min.Y, rect,
+ str, true, "")
+}
+
+// Print prints the string at the current cursor position. It will wrap the
+// string to the width of the screen if it exceeds the width of the screen.
+// This will recognize ANSI [ansi.SGR] style and [ansi.SetHyperlink] escape
+// sequences.
+func (s *ScreenWriter) Print(str string, v ...interface{}) {
+ if len(v) > 0 {
+ str = fmt.Sprintf(str, v...)
+ }
+ printString(s.Screen, s.method,
+ s.cur.X, s.cur.Y, s.Bounds(),
+ str, false, "")
+}
+
+// PrintAt prints the string at the given position. It will wrap the string to
+// the width of the screen if it exceeds the width of the screen.
+// This will recognize ANSI [ansi.SGR] style and [ansi.SetHyperlink] escape
+// sequences.
+func (s *ScreenWriter) PrintAt(x, y int, str string, v ...interface{}) {
+ if len(v) > 0 {
+ str = fmt.Sprintf(str, v...)
+ }
+ printString(s.Screen, s.method,
+ x, y, s.Bounds(),
+ str, false, "")
+}
+
+// PrintCrop prints the string at the current cursor position and truncates the
+// text if it exceeds the width of the screen. Use tail to specify a string to
+// append if the string is truncated.
+// This will recognize ANSI [ansi.SGR] style and [ansi.SetHyperlink] escape
+// sequences.
+func (s *ScreenWriter) PrintCrop(str string, tail string) {
+ printString(s.Screen, s.method,
+ s.cur.X, s.cur.Y, s.Bounds(),
+ str, true, tail)
+}
+
+// PrintCropAt prints the string at the given position and truncates the text
+// if it exceeds the width of the screen. Use tail to specify a string to append
+// if the string is truncated.
+// This will recognize ANSI [ansi.SGR] style and [ansi.SetHyperlink] escape
+// sequences.
+func (s *ScreenWriter) PrintCropAt(x, y int, str string, tail string) {
+ printString(s.Screen, s.method,
+ x, y, s.Bounds(),
+ str, true, tail)
+}
+
+// printString draws a string starting at the given position.
+func printString[T []byte | string](
+ s CellBuffer,
+ m ansi.Method,
+ x, y int,
+ bounds Rectangle, str T,
+ truncate bool, tail string,
+) {
+ p := ansi.GetParser()
+ defer ansi.PutParser(p)
+
+ var tailc Cell
+ if truncate && len(tail) > 0 {
+ if m == ansi.WcWidth {
+ tailc = *NewCellString(tail)
+ } else {
+ tailc = *NewGraphemeCell(tail)
+ }
+ }
+
+ decoder := ansi.DecodeSequenceWc[T]
+ if m == ansi.GraphemeWidth {
+ decoder = ansi.DecodeSequence[T]
+ }
+
+ var cell Cell
+ var style Style
+ var link Link
+ var state byte
+ for len(str) > 0 {
+ seq, width, n, newState := decoder(str, state, p)
+
+ switch width {
+ case 1, 2, 3, 4: // wide cells can go up to 4 cells wide
+ cell.Width += width
+ cell.Append([]rune(string(seq))...)
+
+ if !truncate && x+cell.Width > bounds.Max.X && y+1 < bounds.Max.Y {
+ // Wrap the string to the width of the window
+ x = bounds.Min.X
+ y++
+ }
+ if Pos(x, y).In(bounds) {
+ if truncate && tailc.Width > 0 && x+cell.Width > bounds.Max.X-tailc.Width {
+ // Truncate the string and append the tail if any.
+ cell := tailc
+ cell.Style = style
+ cell.Link = link
+ s.SetCell(x, y, &cell)
+ x += tailc.Width
+ } else {
+ // Print the cell to the screen
+ cell.Style = style
+ cell.Link = link
+ s.SetCell(x, y, &cell) //nolint:errcheck
+ x += width
+ }
+ }
+
+ // String is too long for the line, truncate it.
+ // Make sure we reset the cell for the next iteration.
+ cell.Reset()
+ default:
+ // Valid sequences always have a non-zero Cmd.
+ // TODO: Handle cursor movement and other sequences
+ switch {
+ case ansi.HasCsiPrefix(seq) && p.Command() == 'm':
+ // SGR - Select Graphic Rendition
+ ReadStyle(p.Params(), &style)
+ case ansi.HasOscPrefix(seq) && p.Command() == 8:
+ // Hyperlinks
+ ReadLink(p.Data(), &link)
+ case ansi.Equal(seq, T("\n")):
+ y++
+ case ansi.Equal(seq, T("\r")):
+ x = bounds.Min.X
+ default:
+ cell.Append([]rune(string(seq))...)
+ }
+ }
+
+ // Advance the state and data
+ state = newState
+ str = str[n:]
+ }
+
+ // Make sure to set the last cell if it's not empty.
+ if !cell.Empty() {
+ s.SetCell(x, y, &cell) //nolint:errcheck
+ cell.Reset()
+ }
+}
diff --git a/vendor/github.com/charmbracelet/x/term/BUILD.bazel b/vendor/github.com/charmbracelet/x/term/BUILD.bazel
new file mode 100644
index 00000000..307b8326
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/term/BUILD.bazel
@@ -0,0 +1,54 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "term.go",
+ "term_other.go",
+ "term_unix.go",
+ "term_unix_bsd.go",
+ "term_unix_other.go",
+ "term_windows.go",
+ "terminal.go",
+ "util.go",
+ ],
+ importmap = "github.com/kindlyops/vbs/vendor/github.com/charmbracelet/x/term",
+ importpath = "github.com/charmbracelet/x/term",
+ visibility = ["//visibility:public"],
+ deps = select({
+ "@io_bazel_rules_go//go/platform:aix": [
+ "//vendor/golang.org/x/sys/unix:go_default_library",
+ ],
+ "@io_bazel_rules_go//go/platform:android": [
+ "//vendor/golang.org/x/sys/unix:go_default_library",
+ ],
+ "@io_bazel_rules_go//go/platform:darwin": [
+ "//vendor/golang.org/x/sys/unix:go_default_library",
+ ],
+ "@io_bazel_rules_go//go/platform:dragonfly": [
+ "//vendor/golang.org/x/sys/unix:go_default_library",
+ ],
+ "@io_bazel_rules_go//go/platform:freebsd": [
+ "//vendor/golang.org/x/sys/unix:go_default_library",
+ ],
+ "@io_bazel_rules_go//go/platform:ios": [
+ "//vendor/golang.org/x/sys/unix:go_default_library",
+ ],
+ "@io_bazel_rules_go//go/platform:linux": [
+ "//vendor/golang.org/x/sys/unix:go_default_library",
+ ],
+ "@io_bazel_rules_go//go/platform:netbsd": [
+ "//vendor/golang.org/x/sys/unix:go_default_library",
+ ],
+ "@io_bazel_rules_go//go/platform:openbsd": [
+ "//vendor/golang.org/x/sys/unix:go_default_library",
+ ],
+ "@io_bazel_rules_go//go/platform:solaris": [
+ "//vendor/golang.org/x/sys/unix:go_default_library",
+ ],
+ "@io_bazel_rules_go//go/platform:windows": [
+ "//vendor/golang.org/x/sys/windows:go_default_library",
+ ],
+ "//conditions:default": [],
+ }),
+)
diff --git a/vendor/github.com/charmbracelet/x/term/LICENSE b/vendor/github.com/charmbracelet/x/term/LICENSE
new file mode 100644
index 00000000..65a5654e
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/term/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Charmbracelet, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/charmbracelet/x/term/term.go b/vendor/github.com/charmbracelet/x/term/term.go
new file mode 100644
index 00000000..58d6522c
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/term/term.go
@@ -0,0 +1,49 @@
+package term
+
+// State contains platform-specific state of a terminal.
+type State struct {
+ state
+}
+
+// IsTerminal returns whether the given file descriptor is a terminal.
+func IsTerminal(fd uintptr) bool {
+ return isTerminal(fd)
+}
+
+// MakeRaw puts the terminal connected to the given file descriptor into raw
+// mode and returns the previous state of the terminal so that it can be
+// restored.
+func MakeRaw(fd uintptr) (*State, error) {
+ return makeRaw(fd)
+}
+
+// GetState returns the current state of a terminal which may be useful to
+// restore the terminal after a signal.
+func GetState(fd uintptr) (*State, error) {
+ return getState(fd)
+}
+
+// SetState sets the given state of the terminal.
+func SetState(fd uintptr, state *State) error {
+ return setState(fd, state)
+}
+
+// Restore restores the terminal connected to the given file descriptor to a
+// previous state.
+func Restore(fd uintptr, oldState *State) error {
+ return restore(fd, oldState)
+}
+
+// GetSize returns the visible dimensions of the given terminal.
+//
+// These dimensions don't include any scrollback buffer height.
+func GetSize(fd uintptr) (width, height int, err error) {
+ return getSize(fd)
+}
+
+// ReadPassword reads a line of input from a terminal without local echo. This
+// is commonly used for inputting passwords and other sensitive data. The slice
+// returned does not include the \n.
+func ReadPassword(fd uintptr) ([]byte, error) {
+ return readPassword(fd)
+}
diff --git a/vendor/github.com/charmbracelet/x/term/term_other.go b/vendor/github.com/charmbracelet/x/term/term_other.go
new file mode 100644
index 00000000..092c7e9d
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/term/term_other.go
@@ -0,0 +1,39 @@
+//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !zos && !windows && !solaris && !plan9
+// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!zos,!windows,!solaris,!plan9
+
+package term
+
+import (
+ "fmt"
+ "runtime"
+)
+
+type state struct{}
+
+func isTerminal(fd uintptr) bool {
+ return false
+}
+
+func makeRaw(fd uintptr) (*State, error) {
+ return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
+
+func getState(fd uintptr) (*State, error) {
+ return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
+
+func restore(fd uintptr, state *State) error {
+ return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
+
+func getSize(fd uintptr) (width, height int, err error) {
+ return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
+
+func setState(fd uintptr, state *State) error {
+ return fmt.Errorf("terminal: SetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
+
+func readPassword(fd uintptr) ([]byte, error) {
+ return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
diff --git a/vendor/github.com/charmbracelet/x/term/term_unix.go b/vendor/github.com/charmbracelet/x/term/term_unix.go
new file mode 100644
index 00000000..1459cb1b
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/term/term_unix.go
@@ -0,0 +1,96 @@
+//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
+
+package term
+
+import (
+ "golang.org/x/sys/unix"
+)
+
+type state struct {
+ unix.Termios
+}
+
+func isTerminal(fd uintptr) bool {
+ _, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios)
+ return err == nil
+}
+
+func makeRaw(fd uintptr) (*State, error) {
+ termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios)
+ if err != nil {
+ return nil, err
+ }
+
+ oldState := State{state{Termios: *termios}}
+
+ // This attempts to replicate the behaviour documented for cfmakeraw in
+ // the termios(3) manpage.
+ termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
+ termios.Oflag &^= unix.OPOST
+ termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
+ termios.Cflag &^= unix.CSIZE | unix.PARENB
+ termios.Cflag |= unix.CS8
+ termios.Cc[unix.VMIN] = 1
+ termios.Cc[unix.VTIME] = 0
+ if err := unix.IoctlSetTermios(int(fd), ioctlWriteTermios, termios); err != nil {
+ return nil, err
+ }
+
+ return &oldState, nil
+}
+
+func setState(fd uintptr, state *State) error {
+ var termios *unix.Termios
+ if state != nil {
+ termios = &state.Termios
+ }
+ return unix.IoctlSetTermios(int(fd), ioctlWriteTermios, termios)
+}
+
+func getState(fd uintptr) (*State, error) {
+ termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios)
+ if err != nil {
+ return nil, err
+ }
+
+ return &State{state{Termios: *termios}}, nil
+}
+
+func restore(fd uintptr, state *State) error {
+ return unix.IoctlSetTermios(int(fd), ioctlWriteTermios, &state.Termios)
+}
+
+func getSize(fd uintptr) (width, height int, err error) {
+ ws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ)
+ if err != nil {
+ return 0, 0, err
+ }
+ return int(ws.Col), int(ws.Row), nil
+}
+
+// passwordReader is an io.Reader that reads from a specific file descriptor.
+type passwordReader int
+
+func (r passwordReader) Read(buf []byte) (int, error) {
+ return unix.Read(int(r), buf)
+}
+
+func readPassword(fd uintptr) ([]byte, error) {
+ termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios)
+ if err != nil {
+ return nil, err
+ }
+
+ newState := *termios
+ newState.Lflag &^= unix.ECHO
+ newState.Lflag |= unix.ICANON | unix.ISIG
+ newState.Iflag |= unix.ICRNL
+ if err := unix.IoctlSetTermios(int(fd), ioctlWriteTermios, &newState); err != nil {
+ return nil, err
+ }
+
+ defer unix.IoctlSetTermios(int(fd), ioctlWriteTermios, termios)
+
+ return readPasswordLine(passwordReader(fd))
+}
diff --git a/vendor/github.com/charmbracelet/x/term/term_unix_bsd.go b/vendor/github.com/charmbracelet/x/term/term_unix_bsd.go
new file mode 100644
index 00000000..b435031a
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/term/term_unix_bsd.go
@@ -0,0 +1,11 @@
+//go:build darwin || dragonfly || freebsd || netbsd || openbsd
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package term
+
+import "golang.org/x/sys/unix"
+
+const (
+ ioctlReadTermios = unix.TIOCGETA
+ ioctlWriteTermios = unix.TIOCSETA
+)
diff --git a/vendor/github.com/charmbracelet/x/term/term_unix_other.go b/vendor/github.com/charmbracelet/x/term/term_unix_other.go
new file mode 100644
index 00000000..ee2a29eb
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/term/term_unix_other.go
@@ -0,0 +1,11 @@
+//go:build aix || linux || solaris || zos
+// +build aix linux solaris zos
+
+package term
+
+import "golang.org/x/sys/unix"
+
+const (
+ ioctlReadTermios = unix.TCGETS
+ ioctlWriteTermios = unix.TCSETS
+)
diff --git a/vendor/github.com/charmbracelet/x/term/term_windows.go b/vendor/github.com/charmbracelet/x/term/term_windows.go
new file mode 100644
index 00000000..fe7afdec
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/term/term_windows.go
@@ -0,0 +1,87 @@
+//go:build windows
+// +build windows
+
+package term
+
+import (
+ "os"
+
+ "golang.org/x/sys/windows"
+)
+
+type state struct {
+ Mode uint32
+}
+
+func isTerminal(fd uintptr) bool {
+ var st uint32
+ err := windows.GetConsoleMode(windows.Handle(fd), &st)
+ return err == nil
+}
+
+func makeRaw(fd uintptr) (*State, error) {
+ var st uint32
+ if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil {
+ return nil, err
+ }
+ raw := st &^ (windows.ENABLE_ECHO_INPUT | windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT)
+ raw |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT
+ if err := windows.SetConsoleMode(windows.Handle(fd), raw); err != nil {
+ return nil, err
+ }
+ return &State{state{st}}, nil
+}
+
+func setState(fd uintptr, state *State) error {
+ var mode uint32
+ if state != nil {
+ mode = state.Mode
+ }
+ return windows.SetConsoleMode(windows.Handle(fd), mode)
+}
+
+func getState(fd uintptr) (*State, error) {
+ var st uint32
+ if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil {
+ return nil, err
+ }
+ return &State{state{st}}, nil
+}
+
+func restore(fd uintptr, state *State) error {
+ return windows.SetConsoleMode(windows.Handle(fd), state.Mode)
+}
+
+func getSize(fd uintptr) (width, height int, err error) {
+ var info windows.ConsoleScreenBufferInfo
+ if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
+ return 0, 0, err
+ }
+ return int(info.Window.Right - info.Window.Left + 1), int(info.Window.Bottom - info.Window.Top + 1), nil
+}
+
+func readPassword(fd uintptr) ([]byte, error) {
+ var st uint32
+ if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil {
+ return nil, err
+ }
+ old := st
+
+ st &^= (windows.ENABLE_ECHO_INPUT | windows.ENABLE_LINE_INPUT)
+ st |= (windows.ENABLE_PROCESSED_OUTPUT | windows.ENABLE_PROCESSED_INPUT)
+ if err := windows.SetConsoleMode(windows.Handle(fd), st); err != nil {
+ return nil, err
+ }
+
+ defer windows.SetConsoleMode(windows.Handle(fd), old)
+
+ var h windows.Handle
+ p, _ := windows.GetCurrentProcess()
+ if err := windows.DuplicateHandle(p, windows.Handle(fd), p, &h, 0, false, windows.DUPLICATE_SAME_ACCESS); err != nil {
+ return nil, err
+ }
+
+ f := os.NewFile(uintptr(h), "stdin")
+ defer f.Close()
+ return readPasswordLine(f)
+}
diff --git a/vendor/github.com/charmbracelet/x/term/terminal.go b/vendor/github.com/charmbracelet/x/term/terminal.go
new file mode 100644
index 00000000..8963163f
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/term/terminal.go
@@ -0,0 +1,12 @@
+package term
+
+import (
+ "io"
+)
+
+// File represents a file that has a file descriptor and can be read from,
+// written to, and closed.
+type File interface {
+ io.ReadWriteCloser
+ Fd() uintptr
+}
diff --git a/vendor/github.com/charmbracelet/x/term/util.go b/vendor/github.com/charmbracelet/x/term/util.go
new file mode 100644
index 00000000..b7313418
--- /dev/null
+++ b/vendor/github.com/charmbracelet/x/term/util.go
@@ -0,0 +1,47 @@
+package term
+
+import (
+ "io"
+ "runtime"
+)
+
+// readPasswordLine reads from reader until it finds \n or io.EOF.
+// The slice returned does not include the \n.
+// readPasswordLine also ignores any \r it finds.
+// Windows uses \r as end of line. So, on Windows, readPasswordLine
+// reads until it finds \r and ignores any \n it finds during processing.
+func readPasswordLine(reader io.Reader) ([]byte, error) {
+ var buf [1]byte
+ var ret []byte
+
+ for {
+ n, err := reader.Read(buf[:])
+ if n > 0 {
+ switch buf[0] {
+ case '\b':
+ if len(ret) > 0 {
+ ret = ret[:len(ret)-1]
+ }
+ case '\n':
+ if runtime.GOOS != "windows" {
+ return ret, nil
+ }
+ // otherwise ignore \n
+ case '\r':
+ if runtime.GOOS == "windows" {
+ return ret, nil
+ }
+ // otherwise ignore \r
+ default:
+ ret = append(ret, buf[0])
+ }
+ continue
+ }
+ if err != nil {
+ if err == io.EOF && len(ret) > 0 {
+ return ret, nil
+ }
+ return ret, err
+ }
+ }
+}
diff --git a/vendor/github.com/containerd/console/.golangci.yml b/vendor/github.com/containerd/console/.golangci.yml
deleted file mode 100644
index abe3d84b..00000000
--- a/vendor/github.com/containerd/console/.golangci.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-linters:
- enable:
- - gofmt
- - goimports
- - ineffassign
- - misspell
- - revive
- - staticcheck
- - structcheck
- - unconvert
- - unused
- - varcheck
- - vet
- disable:
- - errcheck
-
-run:
- timeout: 3m
- skip-dirs:
- - vendor
diff --git a/vendor/github.com/containerd/console/BUILD.bazel b/vendor/github.com/containerd/console/BUILD.bazel
deleted file mode 100644
index bf46b947..00000000
--- a/vendor/github.com/containerd/console/BUILD.bazel
+++ /dev/null
@@ -1,35 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library")
-
-go_library(
- name = "go_default_library",
- srcs = [
- "console.go",
- "console_linux.go",
- "console_unix.go",
- "console_windows.go",
- "pty_freebsd_cgo.go",
- "pty_freebsd_nocgo.go",
- "pty_unix.go",
- "tc_darwin.go",
- "tc_freebsd_cgo.go",
- "tc_freebsd_nocgo.go",
- "tc_linux.go",
- "tc_netbsd.go",
- "tc_openbsd_cgo.go",
- "tc_openbsd_nocgo.go",
- "tc_unix.go",
- "tc_zos.go",
- ],
- cgo = True,
- importmap = "github.com/kindlyops/vbs/vendor/github.com/containerd/console",
- importpath = "github.com/containerd/console",
- visibility = ["//visibility:public"],
- deps = [
- "//vendor/golang.org/x/sys/unix:go_default_library",
- ] + select({
- "@io_bazel_rules_go//go/platform:windows": [
- "//vendor/golang.org/x/sys/windows:go_default_library",
- ],
- "//conditions:default": [],
- }),
-)
diff --git a/vendor/github.com/containerd/console/LICENSE b/vendor/github.com/containerd/console/LICENSE
deleted file mode 100644
index 584149b6..00000000
--- a/vendor/github.com/containerd/console/LICENSE
+++ /dev/null
@@ -1,191 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- https://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- Copyright The containerd Authors
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- https://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/vendor/github.com/containerd/console/README.md b/vendor/github.com/containerd/console/README.md
deleted file mode 100644
index 580b461a..00000000
--- a/vendor/github.com/containerd/console/README.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# console
-
-[](https://pkg.go.dev/github.com/containerd/console)
-[](https://github.com/containerd/console/actions?query=workflow%3ACI)
-[](https://goreportcard.com/report/github.com/containerd/console)
-
-Golang package for dealing with consoles. Light on deps and a simple API.
-
-## Modifying the current process
-
-```go
-current := console.Current()
-defer current.Reset()
-
-if err := current.SetRaw(); err != nil {
-}
-ws, err := current.Size()
-current.Resize(ws)
-```
-
-## Project details
-
-console is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
-As a containerd sub-project, you will find the:
- * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md),
- * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS),
- * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md)
-
-information in our [`containerd/project`](https://github.com/containerd/project) repository.
diff --git a/vendor/github.com/containerd/console/console.go b/vendor/github.com/containerd/console/console.go
deleted file mode 100644
index 810a71f4..00000000
--- a/vendor/github.com/containerd/console/console.go
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package console
-
-import (
- "errors"
- "io"
- "os"
-)
-
-var ErrNotAConsole = errors.New("provided file is not a console")
-
-type File interface {
- io.ReadWriteCloser
-
- // Fd returns its file descriptor
- Fd() uintptr
- // Name returns its file name
- Name() string
-}
-
-type Console interface {
- File
-
- // Resize resizes the console to the provided window size
- Resize(WinSize) error
- // ResizeFrom resizes the calling console to the size of the
- // provided console
- ResizeFrom(Console) error
- // SetRaw sets the console in raw mode
- SetRaw() error
- // DisableEcho disables echo on the console
- DisableEcho() error
- // Reset restores the console to its orignal state
- Reset() error
- // Size returns the window size of the console
- Size() (WinSize, error)
-}
-
-// WinSize specifies the window size of the console
-type WinSize struct {
- // Height of the console
- Height uint16
- // Width of the console
- Width uint16
- x uint16
- y uint16
-}
-
-// Current returns the current process' console
-func Current() (c Console) {
- var err error
- // Usually all three streams (stdin, stdout, and stderr)
- // are open to the same console, but some might be redirected,
- // so try all three.
- for _, s := range []*os.File{os.Stderr, os.Stdout, os.Stdin} {
- if c, err = ConsoleFromFile(s); err == nil {
- return c
- }
- }
- // One of the std streams should always be a console
- // for the design of this function.
- panic(err)
-}
-
-// ConsoleFromFile returns a console using the provided file
-// nolint:revive
-func ConsoleFromFile(f File) (Console, error) {
- if err := checkConsole(f); err != nil {
- return nil, err
- }
- return newMaster(f)
-}
diff --git a/vendor/github.com/containerd/console/console_linux.go b/vendor/github.com/containerd/console/console_linux.go
deleted file mode 100644
index 28b77b7a..00000000
--- a/vendor/github.com/containerd/console/console_linux.go
+++ /dev/null
@@ -1,281 +0,0 @@
-//go:build linux
-// +build linux
-
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package console
-
-import (
- "io"
- "os"
- "sync"
-
- "golang.org/x/sys/unix"
-)
-
-const (
- maxEvents = 128
-)
-
-// Epoller manages multiple epoll consoles using edge-triggered epoll api so we
-// dont have to deal with repeated wake-up of EPOLLER or EPOLLHUP.
-// For more details, see:
-// - https://github.com/systemd/systemd/pull/4262
-// - https://github.com/moby/moby/issues/27202
-//
-// Example usage of Epoller and EpollConsole can be as follow:
-//
-// epoller, _ := NewEpoller()
-// epollConsole, _ := epoller.Add(console)
-// go epoller.Wait()
-// var (
-// b bytes.Buffer
-// wg sync.WaitGroup
-// )
-// wg.Add(1)
-// go func() {
-// io.Copy(&b, epollConsole)
-// wg.Done()
-// }()
-// // perform I/O on the console
-// epollConsole.Shutdown(epoller.CloseConsole)
-// wg.Wait()
-// epollConsole.Close()
-type Epoller struct {
- efd int
- mu sync.Mutex
- fdMapping map[int]*EpollConsole
- closeOnce sync.Once
-}
-
-// NewEpoller returns an instance of epoller with a valid epoll fd.
-func NewEpoller() (*Epoller, error) {
- efd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC)
- if err != nil {
- return nil, err
- }
- return &Epoller{
- efd: efd,
- fdMapping: make(map[int]*EpollConsole),
- }, nil
-}
-
-// Add creates an epoll console based on the provided console. The console will
-// be registered with EPOLLET (i.e. using edge-triggered notification) and its
-// file descriptor will be set to non-blocking mode. After this, user should use
-// the return console to perform I/O.
-func (e *Epoller) Add(console Console) (*EpollConsole, error) {
- sysfd := int(console.Fd())
- // Set sysfd to non-blocking mode
- if err := unix.SetNonblock(sysfd, true); err != nil {
- return nil, err
- }
-
- ev := unix.EpollEvent{
- Events: unix.EPOLLIN | unix.EPOLLOUT | unix.EPOLLRDHUP | unix.EPOLLET,
- Fd: int32(sysfd),
- }
- if err := unix.EpollCtl(e.efd, unix.EPOLL_CTL_ADD, sysfd, &ev); err != nil {
- return nil, err
- }
- ef := &EpollConsole{
- Console: console,
- sysfd: sysfd,
- readc: sync.NewCond(&sync.Mutex{}),
- writec: sync.NewCond(&sync.Mutex{}),
- }
- e.mu.Lock()
- e.fdMapping[sysfd] = ef
- e.mu.Unlock()
- return ef, nil
-}
-
-// Wait starts the loop to wait for its consoles' notifications and signal
-// appropriate console that it can perform I/O.
-func (e *Epoller) Wait() error {
- events := make([]unix.EpollEvent, maxEvents)
- for {
- n, err := unix.EpollWait(e.efd, events, -1)
- if err != nil {
- // EINTR: The call was interrupted by a signal handler before either
- // any of the requested events occurred or the timeout expired
- if err == unix.EINTR {
- continue
- }
- return err
- }
- for i := 0; i < n; i++ {
- ev := &events[i]
- // the console is ready to be read from
- if ev.Events&(unix.EPOLLIN|unix.EPOLLHUP|unix.EPOLLERR) != 0 {
- if epfile := e.getConsole(int(ev.Fd)); epfile != nil {
- epfile.signalRead()
- }
- }
- // the console is ready to be written to
- if ev.Events&(unix.EPOLLOUT|unix.EPOLLHUP|unix.EPOLLERR) != 0 {
- if epfile := e.getConsole(int(ev.Fd)); epfile != nil {
- epfile.signalWrite()
- }
- }
- }
- }
-}
-
-// CloseConsole unregisters the console's file descriptor from epoll interface
-func (e *Epoller) CloseConsole(fd int) error {
- e.mu.Lock()
- defer e.mu.Unlock()
- delete(e.fdMapping, fd)
- return unix.EpollCtl(e.efd, unix.EPOLL_CTL_DEL, fd, &unix.EpollEvent{})
-}
-
-func (e *Epoller) getConsole(sysfd int) *EpollConsole {
- e.mu.Lock()
- f := e.fdMapping[sysfd]
- e.mu.Unlock()
- return f
-}
-
-// Close closes the epoll fd
-func (e *Epoller) Close() error {
- closeErr := os.ErrClosed // default to "file already closed"
- e.closeOnce.Do(func() {
- closeErr = unix.Close(e.efd)
- })
- return closeErr
-}
-
-// EpollConsole acts like a console but registers its file descriptor with an
-// epoll fd and uses epoll API to perform I/O.
-type EpollConsole struct {
- Console
- readc *sync.Cond
- writec *sync.Cond
- sysfd int
- closed bool
-}
-
-// Read reads up to len(p) bytes into p. It returns the number of bytes read
-// (0 <= n <= len(p)) and any error encountered.
-//
-// If the console's read returns EAGAIN or EIO, we assume that it's a
-// temporary error because the other side went away and wait for the signal
-// generated by epoll event to continue.
-func (ec *EpollConsole) Read(p []byte) (n int, err error) {
- var read int
- ec.readc.L.Lock()
- defer ec.readc.L.Unlock()
- for {
- read, err = ec.Console.Read(p[n:])
- n += read
- if err != nil {
- var hangup bool
- if perr, ok := err.(*os.PathError); ok {
- hangup = (perr.Err == unix.EAGAIN || perr.Err == unix.EIO)
- } else {
- hangup = (err == unix.EAGAIN || err == unix.EIO)
- }
- // if the other end disappear, assume this is temporary and wait for the
- // signal to continue again. Unless we didnt read anything and the
- // console is already marked as closed then we should exit
- if hangup && !(n == 0 && len(p) > 0 && ec.closed) {
- ec.readc.Wait()
- continue
- }
- }
- break
- }
- // if we didnt read anything then return io.EOF to end gracefully
- if n == 0 && len(p) > 0 && err == nil {
- err = io.EOF
- }
- // signal for others that we finished the read
- ec.readc.Signal()
- return n, err
-}
-
-// Writes len(p) bytes from p to the console. It returns the number of bytes
-// written from p (0 <= n <= len(p)) and any error encountered that caused
-// the write to stop early.
-//
-// If writes to the console returns EAGAIN or EIO, we assume that it's a
-// temporary error because the other side went away and wait for the signal
-// generated by epoll event to continue.
-func (ec *EpollConsole) Write(p []byte) (n int, err error) {
- var written int
- ec.writec.L.Lock()
- defer ec.writec.L.Unlock()
- for {
- written, err = ec.Console.Write(p[n:])
- n += written
- if err != nil {
- var hangup bool
- if perr, ok := err.(*os.PathError); ok {
- hangup = (perr.Err == unix.EAGAIN || perr.Err == unix.EIO)
- } else {
- hangup = (err == unix.EAGAIN || err == unix.EIO)
- }
- // if the other end disappears, assume this is temporary and wait for the
- // signal to continue again.
- if hangup {
- ec.writec.Wait()
- continue
- }
- }
- // unrecoverable error, break the loop and return the error
- break
- }
- if n < len(p) && err == nil {
- err = io.ErrShortWrite
- }
- // signal for others that we finished the write
- ec.writec.Signal()
- return n, err
-}
-
-// Shutdown closes the file descriptor and signals call waiters for this fd.
-// It accepts a callback which will be called with the console's fd. The
-// callback typically will be used to do further cleanup such as unregister the
-// console's fd from the epoll interface.
-// User should call Shutdown and wait for all I/O operation to be finished
-// before closing the console.
-func (ec *EpollConsole) Shutdown(close func(int) error) error {
- ec.readc.L.Lock()
- defer ec.readc.L.Unlock()
- ec.writec.L.Lock()
- defer ec.writec.L.Unlock()
-
- ec.readc.Broadcast()
- ec.writec.Broadcast()
- ec.closed = true
- return close(ec.sysfd)
-}
-
-// signalRead signals that the console is readable.
-func (ec *EpollConsole) signalRead() {
- ec.readc.L.Lock()
- ec.readc.Signal()
- ec.readc.L.Unlock()
-}
-
-// signalWrite signals that the console is writable.
-func (ec *EpollConsole) signalWrite() {
- ec.writec.L.Lock()
- ec.writec.Signal()
- ec.writec.L.Unlock()
-}
diff --git a/vendor/github.com/containerd/console/console_unix.go b/vendor/github.com/containerd/console/console_unix.go
deleted file mode 100644
index 161f5d12..00000000
--- a/vendor/github.com/containerd/console/console_unix.go
+++ /dev/null
@@ -1,157 +0,0 @@
-//go:build darwin || freebsd || linux || netbsd || openbsd || zos
-// +build darwin freebsd linux netbsd openbsd zos
-
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package console
-
-import (
- "golang.org/x/sys/unix"
-)
-
-// NewPty creates a new pty pair
-// The master is returned as the first console and a string
-// with the path to the pty slave is returned as the second
-func NewPty() (Console, string, error) {
- f, err := openpt()
- if err != nil {
- return nil, "", err
- }
- slave, err := ptsname(f)
- if err != nil {
- return nil, "", err
- }
- if err := unlockpt(f); err != nil {
- return nil, "", err
- }
- m, err := newMaster(f)
- if err != nil {
- return nil, "", err
- }
- return m, slave, nil
-}
-
-type master struct {
- f File
- original *unix.Termios
-}
-
-func (m *master) Read(b []byte) (int, error) {
- return m.f.Read(b)
-}
-
-func (m *master) Write(b []byte) (int, error) {
- return m.f.Write(b)
-}
-
-func (m *master) Close() error {
- return m.f.Close()
-}
-
-func (m *master) Resize(ws WinSize) error {
- return tcswinsz(m.f.Fd(), ws)
-}
-
-func (m *master) ResizeFrom(c Console) error {
- ws, err := c.Size()
- if err != nil {
- return err
- }
- return m.Resize(ws)
-}
-
-func (m *master) Reset() error {
- if m.original == nil {
- return nil
- }
- return tcset(m.f.Fd(), m.original)
-}
-
-func (m *master) getCurrent() (unix.Termios, error) {
- var termios unix.Termios
- if err := tcget(m.f.Fd(), &termios); err != nil {
- return unix.Termios{}, err
- }
- return termios, nil
-}
-
-func (m *master) SetRaw() error {
- rawState, err := m.getCurrent()
- if err != nil {
- return err
- }
- rawState = cfmakeraw(rawState)
- rawState.Oflag = rawState.Oflag | unix.OPOST
- return tcset(m.f.Fd(), &rawState)
-}
-
-func (m *master) DisableEcho() error {
- rawState, err := m.getCurrent()
- if err != nil {
- return err
- }
- rawState.Lflag = rawState.Lflag &^ unix.ECHO
- return tcset(m.f.Fd(), &rawState)
-}
-
-func (m *master) Size() (WinSize, error) {
- return tcgwinsz(m.f.Fd())
-}
-
-func (m *master) Fd() uintptr {
- return m.f.Fd()
-}
-
-func (m *master) Name() string {
- return m.f.Name()
-}
-
-// checkConsole checks if the provided file is a console
-func checkConsole(f File) error {
- var termios unix.Termios
- if tcget(f.Fd(), &termios) != nil {
- return ErrNotAConsole
- }
- return nil
-}
-
-func newMaster(f File) (Console, error) {
- m := &master{
- f: f,
- }
- t, err := m.getCurrent()
- if err != nil {
- return nil, err
- }
- m.original = &t
- return m, nil
-}
-
-// ClearONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair
-// created by us acts normally. In particular, a not-very-well-known default of
-// Linux unix98 ptys is that they have +onlcr by default. While this isn't a
-// problem for terminal emulators, because we relay data from the terminal we
-// also relay that funky line discipline.
-func ClearONLCR(fd uintptr) error {
- return setONLCR(fd, false)
-}
-
-// SetONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair
-// created by us acts as intended for a terminal emulator.
-func SetONLCR(fd uintptr) error {
- return setONLCR(fd, true)
-}
diff --git a/vendor/github.com/containerd/console/console_windows.go b/vendor/github.com/containerd/console/console_windows.go
deleted file mode 100644
index f48e4861..00000000
--- a/vendor/github.com/containerd/console/console_windows.go
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package console
-
-import (
- "errors"
- "fmt"
- "os"
-
- "golang.org/x/sys/windows"
-)
-
-var (
- vtInputSupported bool
- ErrNotImplemented = errors.New("not implemented")
-)
-
-func (m *master) initStdios() {
- // Note: We discard console mode warnings, because in/out can be redirected.
- //
- // TODO: Investigate opening CONOUT$/CONIN$ to handle this correctly
-
- m.in = windows.Handle(os.Stdin.Fd())
- if err := windows.GetConsoleMode(m.in, &m.inMode); err == nil {
- // Validate that windows.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
- if err = windows.SetConsoleMode(m.in, m.inMode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err == nil {
- vtInputSupported = true
- }
- // Unconditionally set the console mode back even on failure because SetConsoleMode
- // remembers invalid bits on input handles.
- windows.SetConsoleMode(m.in, m.inMode)
- }
-
- m.out = windows.Handle(os.Stdout.Fd())
- if err := windows.GetConsoleMode(m.out, &m.outMode); err == nil {
- if err := windows.SetConsoleMode(m.out, m.outMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
- m.outMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
- } else {
- windows.SetConsoleMode(m.out, m.outMode)
- }
- }
-
- m.err = windows.Handle(os.Stderr.Fd())
- if err := windows.GetConsoleMode(m.err, &m.errMode); err == nil {
- if err := windows.SetConsoleMode(m.err, m.errMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
- m.errMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
- } else {
- windows.SetConsoleMode(m.err, m.errMode)
- }
- }
-}
-
-type master struct {
- in windows.Handle
- inMode uint32
-
- out windows.Handle
- outMode uint32
-
- err windows.Handle
- errMode uint32
-}
-
-func (m *master) SetRaw() error {
- if err := makeInputRaw(m.in, m.inMode); err != nil {
- return err
- }
-
- // Set StdOut and StdErr to raw mode, we ignore failures since
- // windows.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this version of
- // Windows.
-
- windows.SetConsoleMode(m.out, m.outMode|windows.DISABLE_NEWLINE_AUTO_RETURN)
-
- windows.SetConsoleMode(m.err, m.errMode|windows.DISABLE_NEWLINE_AUTO_RETURN)
-
- return nil
-}
-
-func (m *master) Reset() error {
- var errs []error
-
- for _, s := range []struct {
- fd windows.Handle
- mode uint32
- }{
- {m.in, m.inMode},
- {m.out, m.outMode},
- {m.err, m.errMode},
- } {
- if err := windows.SetConsoleMode(s.fd, s.mode); err != nil {
- // we can't just abort on the first error, otherwise we might leave
- // the console in an unexpected state.
- errs = append(errs, fmt.Errorf("unable to restore console mode: %w", err))
- }
- }
-
- if len(errs) > 0 {
- return errs[0]
- }
-
- return nil
-}
-
-func (m *master) Size() (WinSize, error) {
- var info windows.ConsoleScreenBufferInfo
- err := windows.GetConsoleScreenBufferInfo(m.out, &info)
- if err != nil {
- return WinSize{}, fmt.Errorf("unable to get console info: %w", err)
- }
-
- winsize := WinSize{
- Width: uint16(info.Window.Right - info.Window.Left + 1),
- Height: uint16(info.Window.Bottom - info.Window.Top + 1),
- }
-
- return winsize, nil
-}
-
-func (m *master) Resize(ws WinSize) error {
- return ErrNotImplemented
-}
-
-func (m *master) ResizeFrom(c Console) error {
- return ErrNotImplemented
-}
-
-func (m *master) DisableEcho() error {
- mode := m.inMode &^ windows.ENABLE_ECHO_INPUT
- mode |= windows.ENABLE_PROCESSED_INPUT
- mode |= windows.ENABLE_LINE_INPUT
-
- if err := windows.SetConsoleMode(m.in, mode); err != nil {
- return fmt.Errorf("unable to set console to disable echo: %w", err)
- }
-
- return nil
-}
-
-func (m *master) Close() error {
- return nil
-}
-
-func (m *master) Read(b []byte) (int, error) {
- return os.Stdin.Read(b)
-}
-
-func (m *master) Write(b []byte) (int, error) {
- return os.Stdout.Write(b)
-}
-
-func (m *master) Fd() uintptr {
- return uintptr(m.in)
-}
-
-// on windows, console can only be made from os.Std{in,out,err}, hence there
-// isnt a single name here we can use. Return a dummy "console" value in this
-// case should be sufficient.
-func (m *master) Name() string {
- return "console"
-}
-
-// makeInputRaw puts the terminal (Windows Console) connected to the given
-// file descriptor into raw mode
-func makeInputRaw(fd windows.Handle, mode uint32) error {
- // See
- // -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
- // -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
-
- // Disable these modes
- mode &^= windows.ENABLE_ECHO_INPUT
- mode &^= windows.ENABLE_LINE_INPUT
- mode &^= windows.ENABLE_MOUSE_INPUT
- mode &^= windows.ENABLE_WINDOW_INPUT
- mode &^= windows.ENABLE_PROCESSED_INPUT
-
- // Enable these modes
- mode |= windows.ENABLE_EXTENDED_FLAGS
- mode |= windows.ENABLE_INSERT_MODE
- mode |= windows.ENABLE_QUICK_EDIT_MODE
-
- if vtInputSupported {
- mode |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT
- }
-
- if err := windows.SetConsoleMode(fd, mode); err != nil {
- return fmt.Errorf("unable to set console to raw mode: %w", err)
- }
-
- return nil
-}
-
-func checkConsole(f File) error {
- var mode uint32
- if err := windows.GetConsoleMode(windows.Handle(f.Fd()), &mode); err != nil {
- return err
- }
- return nil
-}
-
-func newMaster(f File) (Console, error) {
- if f != os.Stdin && f != os.Stdout && f != os.Stderr {
- return nil, errors.New("creating a console from a file is not supported on windows")
- }
- m := &master{}
- m.initStdios()
- return m, nil
-}
diff --git a/vendor/github.com/containerd/console/pty_freebsd_cgo.go b/vendor/github.com/containerd/console/pty_freebsd_cgo.go
deleted file mode 100644
index 22368623..00000000
--- a/vendor/github.com/containerd/console/pty_freebsd_cgo.go
+++ /dev/null
@@ -1,46 +0,0 @@
-//go:build freebsd && cgo
-// +build freebsd,cgo
-
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package console
-
-import (
- "fmt"
- "os"
-)
-
-/*
-#include
-#include
-#include
-*/
-import "C"
-
-// openpt allocates a new pseudo-terminal and establishes a connection with its
-// control device.
-func openpt() (*os.File, error) {
- fd, err := C.posix_openpt(C.O_RDWR)
- if err != nil {
- return nil, fmt.Errorf("posix_openpt: %w", err)
- }
- if _, err := C.grantpt(fd); err != nil {
- C.close(fd)
- return nil, fmt.Errorf("grantpt: %w", err)
- }
- return os.NewFile(uintptr(fd), ""), nil
-}
diff --git a/vendor/github.com/containerd/console/pty_freebsd_nocgo.go b/vendor/github.com/containerd/console/pty_freebsd_nocgo.go
deleted file mode 100644
index ceb90a47..00000000
--- a/vendor/github.com/containerd/console/pty_freebsd_nocgo.go
+++ /dev/null
@@ -1,37 +0,0 @@
-//go:build freebsd && !cgo
-// +build freebsd,!cgo
-
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package console
-
-import (
- "os"
-)
-
-//
-// Implementing the functions below requires cgo support. Non-cgo stubs
-// versions are defined below to enable cross-compilation of source code
-// that depends on these functions, but the resultant cross-compiled
-// binaries cannot actually be used. If the stub function(s) below are
-// actually invoked they will display an error message and cause the
-// calling process to exit.
-//
-
-func openpt() (*os.File, error) {
- panic("openpt() support requires cgo.")
-}
diff --git a/vendor/github.com/containerd/console/pty_unix.go b/vendor/github.com/containerd/console/pty_unix.go
deleted file mode 100644
index f5a5b805..00000000
--- a/vendor/github.com/containerd/console/pty_unix.go
+++ /dev/null
@@ -1,31 +0,0 @@
-//go:build darwin || linux || netbsd || openbsd
-// +build darwin linux netbsd openbsd
-
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package console
-
-import (
- "os"
-
- "golang.org/x/sys/unix"
-)
-
-// openpt allocates a new pseudo-terminal by opening the /dev/ptmx device
-func openpt() (*os.File, error) {
- return os.OpenFile("/dev/ptmx", unix.O_RDWR|unix.O_NOCTTY|unix.O_CLOEXEC, 0)
-}
diff --git a/vendor/github.com/containerd/console/pty_zos.go b/vendor/github.com/containerd/console/pty_zos.go
deleted file mode 100644
index 58f59aba..00000000
--- a/vendor/github.com/containerd/console/pty_zos.go
+++ /dev/null
@@ -1,43 +0,0 @@
-//go:build zos
-// +build zos
-
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package console
-
-import (
- "fmt"
- "os"
-)
-
-// openpt allocates a new pseudo-terminal by opening the first available /dev/ptypXX device
-func openpt() (*os.File, error) {
- var f *os.File
- var err error
- for i := 0; ; i++ {
- ptyp := fmt.Sprintf("/dev/ptyp%04d", i)
- f, err = os.OpenFile(ptyp, os.O_RDWR, 0600)
- if err == nil {
- break
- }
- if os.IsNotExist(err) {
- return nil, err
- }
- // else probably Resource Busy
- }
- return f, nil
-}
diff --git a/vendor/github.com/containerd/console/tc_darwin.go b/vendor/github.com/containerd/console/tc_darwin.go
deleted file mode 100644
index 78715458..00000000
--- a/vendor/github.com/containerd/console/tc_darwin.go
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package console
-
-import (
- "fmt"
- "os"
-
- "golang.org/x/sys/unix"
-)
-
-const (
- cmdTcGet = unix.TIOCGETA
- cmdTcSet = unix.TIOCSETA
-)
-
-// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
-// unlockpt should be called before opening the slave side of a pty.
-func unlockpt(f *os.File) error {
- return unix.IoctlSetPointerInt(int(f.Fd()), unix.TIOCPTYUNLK, 0)
-}
-
-// ptsname retrieves the name of the first available pts for the given master.
-func ptsname(f *os.File) (string, error) {
- n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCPTYGNAME)
- if err != nil {
- return "", err
- }
- return fmt.Sprintf("/dev/pts/%d", n), nil
-}
diff --git a/vendor/github.com/containerd/console/tc_freebsd_cgo.go b/vendor/github.com/containerd/console/tc_freebsd_cgo.go
deleted file mode 100644
index 33282579..00000000
--- a/vendor/github.com/containerd/console/tc_freebsd_cgo.go
+++ /dev/null
@@ -1,58 +0,0 @@
-//go:build freebsd && cgo
-// +build freebsd,cgo
-
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package console
-
-import (
- "fmt"
- "os"
-
- "golang.org/x/sys/unix"
-)
-
-/*
-#include
-#include
-*/
-import "C"
-
-const (
- cmdTcGet = unix.TIOCGETA
- cmdTcSet = unix.TIOCSETA
-)
-
-// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
-// unlockpt should be called before opening the slave side of a pty.
-func unlockpt(f *os.File) error {
- fd := C.int(f.Fd())
- if _, err := C.unlockpt(fd); err != nil {
- C.close(fd)
- return fmt.Errorf("unlockpt: %w", err)
- }
- return nil
-}
-
-// ptsname retrieves the name of the first available pts for the given master.
-func ptsname(f *os.File) (string, error) {
- n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN)
- if err != nil {
- return "", err
- }
- return fmt.Sprintf("/dev/pts/%d", n), nil
-}
diff --git a/vendor/github.com/containerd/console/tc_freebsd_nocgo.go b/vendor/github.com/containerd/console/tc_freebsd_nocgo.go
deleted file mode 100644
index 18a9b9cb..00000000
--- a/vendor/github.com/containerd/console/tc_freebsd_nocgo.go
+++ /dev/null
@@ -1,56 +0,0 @@
-//go:build freebsd && !cgo
-// +build freebsd,!cgo
-
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package console
-
-import (
- "fmt"
- "os"
-
- "golang.org/x/sys/unix"
-)
-
-const (
- cmdTcGet = unix.TIOCGETA
- cmdTcSet = unix.TIOCSETA
-)
-
-//
-// Implementing the functions below requires cgo support. Non-cgo stubs
-// versions are defined below to enable cross-compilation of source code
-// that depends on these functions, but the resultant cross-compiled
-// binaries cannot actually be used. If the stub function(s) below are
-// actually invoked they will display an error message and cause the
-// calling process to exit.
-//
-
-// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
-// unlockpt should be called before opening the slave side of a pty.
-func unlockpt(f *os.File) error {
- panic("unlockpt() support requires cgo.")
-}
-
-// ptsname retrieves the name of the first available pts for the given master.
-func ptsname(f *os.File) (string, error) {
- n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN)
- if err != nil {
- return "", err
- }
- return fmt.Sprintf("/dev/pts/%d", n), nil
-}
diff --git a/vendor/github.com/containerd/console/tc_linux.go b/vendor/github.com/containerd/console/tc_linux.go
deleted file mode 100644
index 7d552ea4..00000000
--- a/vendor/github.com/containerd/console/tc_linux.go
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package console
-
-import (
- "fmt"
- "os"
- "unsafe"
-
- "golang.org/x/sys/unix"
-)
-
-const (
- cmdTcGet = unix.TCGETS
- cmdTcSet = unix.TCSETS
-)
-
-// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
-// unlockpt should be called before opening the slave side of a pty.
-func unlockpt(f *os.File) error {
- var u int32
- // XXX do not use unix.IoctlSetPointerInt here, see commit dbd69c59b81.
- if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))); err != 0 {
- return err
- }
- return nil
-}
-
-// ptsname retrieves the name of the first available pts for the given master.
-func ptsname(f *os.File) (string, error) {
- var u uint32
- // XXX do not use unix.IoctlGetInt here, see commit dbd69c59b81.
- if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCGPTN, uintptr(unsafe.Pointer(&u))); err != 0 {
- return "", err
- }
- return fmt.Sprintf("/dev/pts/%d", u), nil
-}
diff --git a/vendor/github.com/containerd/console/tc_netbsd.go b/vendor/github.com/containerd/console/tc_netbsd.go
deleted file mode 100644
index 71227aef..00000000
--- a/vendor/github.com/containerd/console/tc_netbsd.go
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package console
-
-import (
- "bytes"
- "os"
-
- "golang.org/x/sys/unix"
-)
-
-const (
- cmdTcGet = unix.TIOCGETA
- cmdTcSet = unix.TIOCSETA
-)
-
-// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
-// unlockpt should be called before opening the slave side of a pty.
-// This does not exist on NetBSD, it does not allocate controlling terminals on open
-func unlockpt(f *os.File) error {
- return nil
-}
-
-// ptsname retrieves the name of the first available pts for the given master.
-func ptsname(f *os.File) (string, error) {
- ptm, err := unix.IoctlGetPtmget(int(f.Fd()), unix.TIOCPTSNAME)
- if err != nil {
- return "", err
- }
- return string(ptm.Sn[:bytes.IndexByte(ptm.Sn[:], 0)]), nil
-}
diff --git a/vendor/github.com/containerd/console/tc_openbsd_cgo.go b/vendor/github.com/containerd/console/tc_openbsd_cgo.go
deleted file mode 100644
index 0e76f6cc..00000000
--- a/vendor/github.com/containerd/console/tc_openbsd_cgo.go
+++ /dev/null
@@ -1,52 +0,0 @@
-//go:build openbsd && cgo
-// +build openbsd,cgo
-
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package console
-
-import (
- "os"
-
- "golang.org/x/sys/unix"
-)
-
-//#include
-import "C"
-
-const (
- cmdTcGet = unix.TIOCGETA
- cmdTcSet = unix.TIOCSETA
-)
-
-// ptsname retrieves the name of the first available pts for the given master.
-func ptsname(f *os.File) (string, error) {
- ptspath, err := C.ptsname(C.int(f.Fd()))
- if err != nil {
- return "", err
- }
- return C.GoString(ptspath), nil
-}
-
-// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
-// unlockpt should be called before opening the slave side of a pty.
-func unlockpt(f *os.File) error {
- if _, err := C.grantpt(C.int(f.Fd())); err != nil {
- return err
- }
- return nil
-}
diff --git a/vendor/github.com/containerd/console/tc_openbsd_nocgo.go b/vendor/github.com/containerd/console/tc_openbsd_nocgo.go
deleted file mode 100644
index dca92418..00000000
--- a/vendor/github.com/containerd/console/tc_openbsd_nocgo.go
+++ /dev/null
@@ -1,48 +0,0 @@
-//go:build openbsd && !cgo
-// +build openbsd,!cgo
-
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-//
-// Implementing the functions below requires cgo support. Non-cgo stubs
-// versions are defined below to enable cross-compilation of source code
-// that depends on these functions, but the resultant cross-compiled
-// binaries cannot actually be used. If the stub function(s) below are
-// actually invoked they will display an error message and cause the
-// calling process to exit.
-//
-
-package console
-
-import (
- "os"
-
- "golang.org/x/sys/unix"
-)
-
-const (
- cmdTcGet = unix.TIOCGETA
- cmdTcSet = unix.TIOCSETA
-)
-
-func ptsname(f *os.File) (string, error) {
- panic("ptsname() support requires cgo.")
-}
-
-func unlockpt(f *os.File) error {
- panic("unlockpt() support requires cgo.")
-}
diff --git a/vendor/github.com/containerd/console/tc_unix.go b/vendor/github.com/containerd/console/tc_unix.go
deleted file mode 100644
index f5053b2f..00000000
--- a/vendor/github.com/containerd/console/tc_unix.go
+++ /dev/null
@@ -1,92 +0,0 @@
-//go:build darwin || freebsd || linux || netbsd || openbsd || zos
-// +build darwin freebsd linux netbsd openbsd zos
-
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package console
-
-import (
- "golang.org/x/sys/unix"
-)
-
-func tcget(fd uintptr, p *unix.Termios) error {
- termios, err := unix.IoctlGetTermios(int(fd), cmdTcGet)
- if err != nil {
- return err
- }
- *p = *termios
- return nil
-}
-
-func tcset(fd uintptr, p *unix.Termios) error {
- return unix.IoctlSetTermios(int(fd), cmdTcSet, p)
-}
-
-func tcgwinsz(fd uintptr) (WinSize, error) {
- var ws WinSize
-
- uws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ)
- if err != nil {
- return ws, err
- }
-
- // Translate from unix.Winsize to console.WinSize
- ws.Height = uws.Row
- ws.Width = uws.Col
- ws.x = uws.Xpixel
- ws.y = uws.Ypixel
- return ws, nil
-}
-
-func tcswinsz(fd uintptr, ws WinSize) error {
- // Translate from console.WinSize to unix.Winsize
-
- var uws unix.Winsize
- uws.Row = ws.Height
- uws.Col = ws.Width
- uws.Xpixel = ws.x
- uws.Ypixel = ws.y
-
- return unix.IoctlSetWinsize(int(fd), unix.TIOCSWINSZ, &uws)
-}
-
-func setONLCR(fd uintptr, enable bool) error {
- var termios unix.Termios
- if err := tcget(fd, &termios); err != nil {
- return err
- }
- if enable {
- // Set +onlcr so we can act like a real terminal
- termios.Oflag |= unix.ONLCR
- } else {
- // Set -onlcr so we don't have to deal with \r.
- termios.Oflag &^= unix.ONLCR
- }
- return tcset(fd, &termios)
-}
-
-func cfmakeraw(t unix.Termios) unix.Termios {
- t.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON)
- t.Oflag &^= unix.OPOST
- t.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN)
- t.Cflag &^= (unix.CSIZE | unix.PARENB)
- t.Cflag &^= unix.CS8
- t.Cc[unix.VMIN] = 1
- t.Cc[unix.VTIME] = 0
-
- return t
-}
diff --git a/vendor/github.com/containerd/console/tc_zos.go b/vendor/github.com/containerd/console/tc_zos.go
deleted file mode 100644
index fc90ba5f..00000000
--- a/vendor/github.com/containerd/console/tc_zos.go
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- Copyright The containerd Authors.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package console
-
-import (
- "os"
- "strings"
-
- "golang.org/x/sys/unix"
-)
-
-const (
- cmdTcGet = unix.TCGETS
- cmdTcSet = unix.TCSETS
-)
-
-// unlockpt is a no-op on zos.
-func unlockpt(_ *os.File) error {
- return nil
-}
-
-// ptsname retrieves the name of the first available pts for the given master.
-func ptsname(f *os.File) (string, error) {
- return "/dev/ttyp" + strings.TrimPrefix(f.Name(), "/dev/ptyp"), nil
-}
diff --git a/vendor/github.com/erikgeiser/coninput/.gitignore b/vendor/github.com/erikgeiser/coninput/.gitignore
new file mode 100644
index 00000000..66fd13c9
--- /dev/null
+++ b/vendor/github.com/erikgeiser/coninput/.gitignore
@@ -0,0 +1,15 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
diff --git a/vendor/github.com/erikgeiser/coninput/.golangci.yml b/vendor/github.com/erikgeiser/coninput/.golangci.yml
new file mode 100644
index 00000000..d3ed7103
--- /dev/null
+++ b/vendor/github.com/erikgeiser/coninput/.golangci.yml
@@ -0,0 +1,24 @@
+linters:
+ enable-all: true
+ disable:
+ - golint
+ - interfacer
+ - scopelint
+ - maligned
+ - rowserrcheck
+ - funlen
+ - depguard
+ - goerr113
+ - exhaustivestruct
+ - testpackage
+ - gochecknoglobals
+ - wrapcheck
+ - forbidigo
+ - ifshort
+ - cyclop
+ - gomoddirectives
+linters-settings:
+ exhaustive:
+ default-signifies-exhaustive: true
+issues:
+ exclude-use-default: false
diff --git a/vendor/github.com/erikgeiser/coninput/BUILD.bazel b/vendor/github.com/erikgeiser/coninput/BUILD.bazel
new file mode 100644
index 00000000..4735c6fd
--- /dev/null
+++ b/vendor/github.com/erikgeiser/coninput/BUILD.bazel
@@ -0,0 +1,20 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "keycodes.go",
+ "mode.go",
+ "read.go",
+ "records.go",
+ ],
+ importmap = "github.com/kindlyops/vbs/vendor/github.com/erikgeiser/coninput",
+ importpath = "github.com/erikgeiser/coninput",
+ visibility = ["//visibility:public"],
+ deps = select({
+ "@io_bazel_rules_go//go/platform:windows": [
+ "//vendor/golang.org/x/sys/windows:go_default_library",
+ ],
+ "//conditions:default": [],
+ }),
+)
diff --git a/vendor/github.com/erikgeiser/coninput/LICENSE b/vendor/github.com/erikgeiser/coninput/LICENSE
new file mode 100644
index 00000000..83c24408
--- /dev/null
+++ b/vendor/github.com/erikgeiser/coninput/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Erik G.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/erikgeiser/coninput/README.md b/vendor/github.com/erikgeiser/coninput/README.md
new file mode 100644
index 00000000..22619d13
--- /dev/null
+++ b/vendor/github.com/erikgeiser/coninput/README.md
@@ -0,0 +1,2 @@
+# coninput
+Go library for input handling using Windows Console API
diff --git a/vendor/github.com/erikgeiser/coninput/keycodes.go b/vendor/github.com/erikgeiser/coninput/keycodes.go
new file mode 100644
index 00000000..902ee1b7
--- /dev/null
+++ b/vendor/github.com/erikgeiser/coninput/keycodes.go
@@ -0,0 +1,205 @@
+package coninput
+
+// VirtualKeyCode holds a virtual key code (see
+// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes).
+type VirtualKeyCode uint16
+
+const (
+ VK_LBUTTON VirtualKeyCode = 0x01
+ VK_RBUTTON VirtualKeyCode = 0x02
+ VK_CANCEL VirtualKeyCode = 0x03
+ VK_MBUTTON VirtualKeyCode = 0x04
+ VK_XBUTTON1 VirtualKeyCode = 0x05
+ VK_XBUTTON2 VirtualKeyCode = 0x06
+ VK_BACK VirtualKeyCode = 0x08
+ VK_TAB VirtualKeyCode = 0x09
+ VK_CLEAR VirtualKeyCode = 0x0C
+ VK_RETURN VirtualKeyCode = 0x0D
+ VK_SHIFT VirtualKeyCode = 0x10
+ VK_CONTROL VirtualKeyCode = 0x11
+ VK_MENU VirtualKeyCode = 0x12
+ VK_PAUSE VirtualKeyCode = 0x13
+ VK_CAPITAL VirtualKeyCode = 0x14
+ VK_KANA VirtualKeyCode = 0x15
+ VK_HANGEUL VirtualKeyCode = 0x15
+ VK_HANGUL VirtualKeyCode = 0x15
+ VK_IME_ON VirtualKeyCode = 0x16
+ VK_JUNJA VirtualKeyCode = 0x17
+ VK_FINAL VirtualKeyCode = 0x18
+ VK_HANJA VirtualKeyCode = 0x19
+ VK_KANJI VirtualKeyCode = 0x19
+ VK_IME_OFF VirtualKeyCode = 0x1A
+ VK_ESCAPE VirtualKeyCode = 0x1B
+ VK_CONVERT VirtualKeyCode = 0x1C
+ VK_NONCONVERT VirtualKeyCode = 0x1D
+ VK_ACCEPT VirtualKeyCode = 0x1E
+ VK_MODECHANGE VirtualKeyCode = 0x1F
+ VK_SPACE VirtualKeyCode = 0x20
+ VK_PRIOR VirtualKeyCode = 0x21
+ VK_NEXT VirtualKeyCode = 0x22
+ VK_END VirtualKeyCode = 0x23
+ VK_HOME VirtualKeyCode = 0x24
+ VK_LEFT VirtualKeyCode = 0x25
+ VK_UP VirtualKeyCode = 0x26
+ VK_RIGHT VirtualKeyCode = 0x27
+ VK_DOWN VirtualKeyCode = 0x28
+ VK_SELECT VirtualKeyCode = 0x29
+ VK_PRINT VirtualKeyCode = 0x2A
+ VK_EXECUTE VirtualKeyCode = 0x2B
+ VK_SNAPSHOT VirtualKeyCode = 0x2C
+ VK_INSERT VirtualKeyCode = 0x2D
+ VK_DELETE VirtualKeyCode = 0x2E
+ VK_HELP VirtualKeyCode = 0x2F
+ VK_0 VirtualKeyCode = 0x30
+ VK_1 VirtualKeyCode = 0x31
+ VK_2 VirtualKeyCode = 0x32
+ VK_3 VirtualKeyCode = 0x33
+ VK_4 VirtualKeyCode = 0x34
+ VK_5 VirtualKeyCode = 0x35
+ VK_6 VirtualKeyCode = 0x36
+ VK_7 VirtualKeyCode = 0x37
+ VK_8 VirtualKeyCode = 0x38
+ VK_9 VirtualKeyCode = 0x39
+ VK_A VirtualKeyCode = 0x41
+ VK_B VirtualKeyCode = 0x42
+ VK_C VirtualKeyCode = 0x43
+ VK_D VirtualKeyCode = 0x44
+ VK_E VirtualKeyCode = 0x45
+ VK_F VirtualKeyCode = 0x46
+ VK_G VirtualKeyCode = 0x47
+ VK_H VirtualKeyCode = 0x48
+ VK_I VirtualKeyCode = 0x49
+ VK_J VirtualKeyCode = 0x4A
+ VK_K VirtualKeyCode = 0x4B
+ VK_L VirtualKeyCode = 0x4C
+ VK_M VirtualKeyCode = 0x4D
+ VK_N VirtualKeyCode = 0x4E
+ VK_O VirtualKeyCode = 0x4F
+ VK_P VirtualKeyCode = 0x50
+ VK_Q VirtualKeyCode = 0x51
+ VK_R VirtualKeyCode = 0x52
+ VK_S VirtualKeyCode = 0x53
+ VK_T VirtualKeyCode = 0x54
+ VK_U VirtualKeyCode = 0x55
+ VK_V VirtualKeyCode = 0x56
+ VK_W VirtualKeyCode = 0x57
+ VK_X VirtualKeyCode = 0x58
+ VK_Y VirtualKeyCode = 0x59
+ VK_Z VirtualKeyCode = 0x5A
+ VK_LWIN VirtualKeyCode = 0x5B
+ VK_RWIN VirtualKeyCode = 0x5C
+ VK_APPS VirtualKeyCode = 0x5D
+ VK_SLEEP VirtualKeyCode = 0x5F
+ VK_NUMPAD0 VirtualKeyCode = 0x60
+ VK_NUMPAD1 VirtualKeyCode = 0x61
+ VK_NUMPAD2 VirtualKeyCode = 0x62
+ VK_NUMPAD3 VirtualKeyCode = 0x63
+ VK_NUMPAD4 VirtualKeyCode = 0x64
+ VK_NUMPAD5 VirtualKeyCode = 0x65
+ VK_NUMPAD6 VirtualKeyCode = 0x66
+ VK_NUMPAD7 VirtualKeyCode = 0x67
+ VK_NUMPAD8 VirtualKeyCode = 0x68
+ VK_NUMPAD9 VirtualKeyCode = 0x69
+ VK_MULTIPLY VirtualKeyCode = 0x6A
+ VK_ADD VirtualKeyCode = 0x6B
+ VK_SEPARATOR VirtualKeyCode = 0x6C
+ VK_SUBTRACT VirtualKeyCode = 0x6D
+ VK_DECIMAL VirtualKeyCode = 0x6E
+ VK_DIVIDE VirtualKeyCode = 0x6F
+ VK_F1 VirtualKeyCode = 0x70
+ VK_F2 VirtualKeyCode = 0x71
+ VK_F3 VirtualKeyCode = 0x72
+ VK_F4 VirtualKeyCode = 0x73
+ VK_F5 VirtualKeyCode = 0x74
+ VK_F6 VirtualKeyCode = 0x75
+ VK_F7 VirtualKeyCode = 0x76
+ VK_F8 VirtualKeyCode = 0x77
+ VK_F9 VirtualKeyCode = 0x78
+ VK_F10 VirtualKeyCode = 0x79
+ VK_F11 VirtualKeyCode = 0x7A
+ VK_F12 VirtualKeyCode = 0x7B
+ VK_F13 VirtualKeyCode = 0x7C
+ VK_F14 VirtualKeyCode = 0x7D
+ VK_F15 VirtualKeyCode = 0x7E
+ VK_F16 VirtualKeyCode = 0x7F
+ VK_F17 VirtualKeyCode = 0x80
+ VK_F18 VirtualKeyCode = 0x81
+ VK_F19 VirtualKeyCode = 0x82
+ VK_F20 VirtualKeyCode = 0x83
+ VK_F21 VirtualKeyCode = 0x84
+ VK_F22 VirtualKeyCode = 0x85
+ VK_F23 VirtualKeyCode = 0x86
+ VK_F24 VirtualKeyCode = 0x87
+ VK_NUMLOCK VirtualKeyCode = 0x90
+ VK_SCROLL VirtualKeyCode = 0x91
+ VK_OEM_NEC_EQUAL VirtualKeyCode = 0x92
+ VK_OEM_FJ_JISHO VirtualKeyCode = 0x92
+ VK_OEM_FJ_MASSHOU VirtualKeyCode = 0x93
+ VK_OEM_FJ_TOUROKU VirtualKeyCode = 0x94
+ VK_OEM_FJ_LOYA VirtualKeyCode = 0x95
+ VK_OEM_FJ_ROYA VirtualKeyCode = 0x96
+ VK_LSHIFT VirtualKeyCode = 0xA0
+ VK_RSHIFT VirtualKeyCode = 0xA1
+ VK_LCONTROL VirtualKeyCode = 0xA2
+ VK_RCONTROL VirtualKeyCode = 0xA3
+ VK_LMENU VirtualKeyCode = 0xA4
+ VK_RMENU VirtualKeyCode = 0xA5
+ VK_BROWSER_BACK VirtualKeyCode = 0xA6
+ VK_BROWSER_FORWARD VirtualKeyCode = 0xA7
+ VK_BROWSER_REFRESH VirtualKeyCode = 0xA8
+ VK_BROWSER_STOP VirtualKeyCode = 0xA9
+ VK_BROWSER_SEARCH VirtualKeyCode = 0xAA
+ VK_BROWSER_FAVORITES VirtualKeyCode = 0xAB
+ VK_BROWSER_HOME VirtualKeyCode = 0xAC
+ VK_VOLUME_MUTE VirtualKeyCode = 0xAD
+ VK_VOLUME_DOWN VirtualKeyCode = 0xAE
+ VK_VOLUME_UP VirtualKeyCode = 0xAF
+ VK_MEDIA_NEXT_TRACK VirtualKeyCode = 0xB0
+ VK_MEDIA_PREV_TRACK VirtualKeyCode = 0xB1
+ VK_MEDIA_STOP VirtualKeyCode = 0xB2
+ VK_MEDIA_PLAY_PAUSE VirtualKeyCode = 0xB3
+ VK_LAUNCH_MAIL VirtualKeyCode = 0xB4
+ VK_LAUNCH_MEDIA_SELECT VirtualKeyCode = 0xB5
+ VK_LAUNCH_APP1 VirtualKeyCode = 0xB6
+ VK_LAUNCH_APP2 VirtualKeyCode = 0xB7
+ VK_OEM_1 VirtualKeyCode = 0xBA
+ VK_OEM_PLUS VirtualKeyCode = 0xBB
+ VK_OEM_COMMA VirtualKeyCode = 0xBC
+ VK_OEM_MINUS VirtualKeyCode = 0xBD
+ VK_OEM_PERIOD VirtualKeyCode = 0xBE
+ VK_OEM_2 VirtualKeyCode = 0xBF
+ VK_OEM_3 VirtualKeyCode = 0xC0
+ VK_OEM_4 VirtualKeyCode = 0xDB
+ VK_OEM_5 VirtualKeyCode = 0xDC
+ VK_OEM_6 VirtualKeyCode = 0xDD
+ VK_OEM_7 VirtualKeyCode = 0xDE
+ VK_OEM_8 VirtualKeyCode = 0xDF
+ VK_OEM_AX VirtualKeyCode = 0xE1
+ VK_OEM_102 VirtualKeyCode = 0xE2
+ VK_ICO_HELP VirtualKeyCode = 0xE3
+ VK_ICO_00 VirtualKeyCode = 0xE4
+ VK_PROCESSKEY VirtualKeyCode = 0xE5
+ VK_ICO_CLEAR VirtualKeyCode = 0xE6
+ VK_OEM_RESET VirtualKeyCode = 0xE9
+ VK_OEM_JUMP VirtualKeyCode = 0xEA
+ VK_OEM_PA1 VirtualKeyCode = 0xEB
+ VK_OEM_PA2 VirtualKeyCode = 0xEC
+ VK_OEM_PA3 VirtualKeyCode = 0xED
+ VK_OEM_WSCTRL VirtualKeyCode = 0xEE
+ VK_OEM_CUSEL VirtualKeyCode = 0xEF
+ VK_OEM_ATTN VirtualKeyCode = 0xF0
+ VK_OEM_FINISH VirtualKeyCode = 0xF1
+ VK_OEM_COPY VirtualKeyCode = 0xF2
+ VK_OEM_AUTO VirtualKeyCode = 0xF3
+ VK_OEM_ENLW VirtualKeyCode = 0xF4
+ VK_OEM_BACKTAB VirtualKeyCode = 0xF5
+ VK_ATTN VirtualKeyCode = 0xF6
+ VK_CRSEL VirtualKeyCode = 0xF7
+ VK_EXSEL VirtualKeyCode = 0xF8
+ VK_EREOF VirtualKeyCode = 0xF9
+ VK_PLAY VirtualKeyCode = 0xFA
+ VK_ZOOM VirtualKeyCode = 0xFB
+ VK_NONAME VirtualKeyCode = 0xFC
+ VK_PA1 VirtualKeyCode = 0xFD
+ VK_OEM_CLEAR VirtualKeyCode = 0xFE
+)
diff --git a/vendor/github.com/erikgeiser/coninput/mode.go b/vendor/github.com/erikgeiser/coninput/mode.go
new file mode 100644
index 00000000..e6d8bf44
--- /dev/null
+++ b/vendor/github.com/erikgeiser/coninput/mode.go
@@ -0,0 +1,82 @@
+//go:build windows
+// +build windows
+
+package coninput
+
+import (
+ "strings"
+
+ "golang.org/x/sys/windows"
+)
+
+// AddInputModes returns the given mode with one or more additional modes enabled.
+func AddInputModes(mode uint32, enableModes ...uint32) uint32 {
+ for _, enableMode := range enableModes {
+ mode |= enableMode
+ }
+
+ return mode
+}
+
+// RemoveInputModes returns the given mode with one or more additional modes disabled.
+func RemoveInputModes(mode uint32, disableModes ...uint32) uint32 {
+ for _, disableMode := range disableModes {
+ mode &^= disableMode
+ }
+
+ return mode
+}
+
+// ToggleInputModes returns the given mode with one or more additional modes toggeled.
+func ToggleInputModes(mode uint32, toggleModes ...uint32) uint32 {
+ for _, toggeMode := range toggleModes {
+ mode ^= toggeMode
+ }
+
+ return mode
+}
+
+var inputModes = []struct {
+ mode uint32
+ name string
+}{
+ {mode: windows.ENABLE_ECHO_INPUT, name: "ENABLE_ECHO_INPUT"},
+ {mode: windows.ENABLE_INSERT_MODE, name: "ENABLE_INSERT_MODE"},
+ {mode: windows.ENABLE_LINE_INPUT, name: "ENABLE_LINE_INPUT"},
+ {mode: windows.ENABLE_MOUSE_INPUT, name: "ENABLE_MOUSE_INPUT"},
+ {mode: windows.ENABLE_PROCESSED_INPUT, name: "ENABLE_PROCESSED_INPUT"},
+ {mode: windows.ENABLE_QUICK_EDIT_MODE, name: "ENABLE_QUICK_EDIT_MODE"},
+ {mode: windows.ENABLE_WINDOW_INPUT, name: "ENABLE_WINDOW_INPUT"},
+ {mode: windows.ENABLE_VIRTUAL_TERMINAL_INPUT, name: "ENABLE_VIRTUAL_TERMINAL_INPUT"},
+}
+
+// ListInputMode returnes the isolated enabled input modes as a list.
+func ListInputModes(mode uint32) []uint32 {
+ modes := []uint32{}
+
+ for _, inputMode := range inputModes {
+ if mode&inputMode.mode > 0 {
+ modes = append(modes, inputMode.mode)
+ }
+ }
+
+ return modes
+}
+
+// ListInputMode returnes the isolated enabled input mode names as a list.
+func ListInputModeNames(mode uint32) []string {
+ modes := []string{}
+
+ for _, inputMode := range inputModes {
+ if mode&inputMode.mode > 0 {
+ modes = append(modes, inputMode.name)
+ }
+ }
+
+ return modes
+}
+
+// DescribeInputMode returns a string containing the names of each enabled input mode.
+func DescribeInputMode(mode uint32) string {
+ return strings.Join(ListInputModeNames(mode), "|")
+}
diff --git a/vendor/github.com/erikgeiser/coninput/read.go b/vendor/github.com/erikgeiser/coninput/read.go
new file mode 100644
index 00000000..b2dd82f1
--- /dev/null
+++ b/vendor/github.com/erikgeiser/coninput/read.go
@@ -0,0 +1,154 @@
+//go:build windows
+// +build windows
+
+package coninput
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+var (
+ modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
+ procReadConsoleInputW = modkernel32.NewProc("ReadConsoleInputW")
+ procPeekConsoleInputW = modkernel32.NewProc("PeekConsoleInputW")
+ procGetNumberOfConsoleInputEvents = modkernel32.NewProc("GetNumberOfConsoleInputEvents")
+ procFlushConsoleInputBuffer = modkernel32.NewProc("FlushConsoleInputBuffer")
+)
+
+// NewStdinHandle is a shortcut for windows.GetStdHandle(windows.STD_INPUT_HANDLE).
+func NewStdinHandle() (windows.Handle, error) {
+ return windows.GetStdHandle(windows.STD_INPUT_HANDLE)
+}
+
+// WinReadConsoleInput is a thin wrapper around the Windows console API function
+// ReadConsoleInput (see
+// https://docs.microsoft.com/en-us/windows/console/readconsoleinput). In most
+// cases it is more practical to either use ReadConsoleInput or
+// ReadNConsoleInputs.
+func WinReadConsoleInput(consoleInput windows.Handle, buffer *InputRecord,
+ length uint32, numberOfEventsRead *uint32) error {
+ r, _, e := syscall.Syscall6(procReadConsoleInputW.Addr(), 4,
+ uintptr(consoleInput), uintptr(unsafe.Pointer(buffer)), uintptr(length),
+ uintptr(unsafe.Pointer(numberOfEventsRead)), 0, 0)
+ if r == 0 {
+ return error(e)
+ }
+
+ return nil
+}
+
+// ReadNConsoleInputs is a wrapper around ReadConsoleInput (see
+// https://docs.microsoft.com/en-us/windows/console/readconsoleinput) that
+// automates the event buffer allocation in oder to provide io.Reader-like
+// sematics. maxEvents must be greater than zero.
+func ReadNConsoleInputs(console windows.Handle, maxEvents uint32) ([]InputRecord, error) {
+ if maxEvents == 0 {
+ return nil, fmt.Errorf("maxEvents cannot be zero")
+ }
+
+ var inputRecords = make([]InputRecord, maxEvents)
+ n, err := ReadConsoleInput(console, inputRecords)
+
+ return inputRecords[:n], err
+}
+
+// ReadConsoleInput provides an ideomatic interface to the Windows console API
+// function ReadConsoleInput (see
+// https://docs.microsoft.com/en-us/windows/console/readconsoleinput). The size
+// of inputRecords must be greater than zero.
+func ReadConsoleInput(console windows.Handle, inputRecords []InputRecord) (uint32, error) {
+ if len(inputRecords) == 0 {
+ return 0, fmt.Errorf("size of input record buffer cannot be zero")
+ }
+
+ var read uint32
+ err := WinReadConsoleInput(console, &inputRecords[0], uint32(len(inputRecords)), &read)
+
+ return read, err
+}
+
+// WinPeekConsoleInput is a thin wrapper around the Windows console API function
+// PeekConsoleInput (see
+// https://docs.microsoft.com/en-us/windows/console/peekconsoleinput). In most
+// cases it is more practical to either use PeekConsoleInput or
+// PeekNConsoleInputs.
+func WinPeekConsoleInput(consoleInput windows.Handle, buffer *InputRecord,
+ length uint32, numberOfEventsRead *uint32) error {
+ r, _, e := syscall.Syscall6(procPeekConsoleInputW.Addr(), 4,
+ uintptr(consoleInput), uintptr(unsafe.Pointer(buffer)), uintptr(length),
+ uintptr(unsafe.Pointer(numberOfEventsRead)), 0, 0)
+ if r == 0 {
+ return error(e)
+ }
+
+ return nil
+
+}
+
+// PeekNConsoleInputs is a wrapper around PeekConsoleInput (see
+// https://docs.microsoft.com/en-us/windows/console/peekconsoleinput) that
+// automates the event buffer allocation in oder to provide io.Reader-like
+// sematics. maxEvents must be greater than zero.
+func PeekNConsoleInputs(console windows.Handle, maxEvents uint32) ([]InputRecord, error) {
+ if maxEvents == 0 {
+ return nil, fmt.Errorf("maxEvents cannot be zero")
+ }
+
+ var inputRecords = make([]InputRecord, maxEvents)
+ n, err := PeekConsoleInput(console, inputRecords)
+
+ return inputRecords[:n], err
+}
+
+// PeekConsoleInput provides an ideomatic interface to the Windows console API
+// function PeekConsoleInput (see
+// https://docs.microsoft.com/en-us/windows/console/peekconsoleinput). The size
+// of inputRecords must be greater than zero.
+func PeekConsoleInput(console windows.Handle, inputRecords []InputRecord) (uint32, error) {
+ if len(inputRecords) == 0 {
+ return 0, fmt.Errorf("size of input record buffer cannot be zero")
+ }
+
+ var read uint32
+
+ err := WinPeekConsoleInput(console, &inputRecords[0], uint32(len(inputRecords)), &read)
+
+ return read, err
+}
+
+// WinGetNumberOfConsoleInputEvents provides an ideomatic interface to the
+// Windows console API function GetNumberOfConsoleInputEvents (see
+// https://docs.microsoft.com/en-us/windows/console/getnumberofconsoleinputevents).
+func WinGetNumberOfConsoleInputEvents(consoleInput windows.Handle, numberOfEvents *uint32) error {
+ r, _, e := syscall.Syscall6(procGetNumberOfConsoleInputEvents.Addr(), 2,
+ uintptr(consoleInput), uintptr(unsafe.Pointer(numberOfEvents)), 0,
+ 0, 0, 0)
+ if r == 0 {
+ return error(e)
+ }
+
+ return nil
+}
+
+// GetNumberOfConsoleInputEvents provides an ideomatic interface to the Windows
+// console API function GetNumberOfConsoleInputEvents (see
+// https://docs.microsoft.com/en-us/windows/console/getnumberofconsoleinputevents).
+func GetNumberOfConsoleInputEvents(console windows.Handle) (uint32, error) {
+ var nEvents uint32
+ err := WinGetNumberOfConsoleInputEvents(console, &nEvents)
+
+ return nEvents, err
+}
+
+func FlushConsoleInputBuffer(consoleInput windows.Handle) error {
+ r, _, e := syscall.Syscall(procFlushConsoleInputBuffer.Addr(), 1, uintptr(consoleInput), 0, 0)
+ if r == 0 {
+ return error(e)
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/erikgeiser/coninput/records.go b/vendor/github.com/erikgeiser/coninput/records.go
new file mode 100644
index 00000000..cccf7fbf
--- /dev/null
+++ b/vendor/github.com/erikgeiser/coninput/records.go
@@ -0,0 +1,486 @@
+package coninput
+
+import (
+ "encoding/binary"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+const (
+ maxEventSize = 16
+ wordPaddingBytes = 2
+)
+
+// EventType denots the type of an event
+type EventType uint16
+
+// EventUnion is the union data type that contains the data for any event.
+type EventUnion [maxEventSize]byte
+
+// InputRecord corresponds to the INPUT_RECORD structure from the Windows
+// console API (see
+// https://docs.microsoft.com/en-us/windows/console/input-record-str).
+type InputRecord struct {
+ // EventType specifies the type of event that helt in Event.
+ EventType EventType
+
+ // Padding of the 16-bit EventType to a whole 32-bit dword.
+ _ [wordPaddingBytes]byte
+
+ // Event holds the actual event data. Use Unrap to access it as its
+ // respective event type.
+ Event EventUnion
+}
+
+// String implements fmt.Stringer for InputRecord.
+func (ir InputRecord) String() string {
+ return ir.Unwrap().String()
+}
+
+// Unwrap parses the event data into an EventRecord of the respective event
+// type. The data in the returned EventRecord does not contain any references to
+// the passed InputRecord.
+func (ir InputRecord) Unwrap() EventRecord {
+ switch ir.EventType {
+ case FocusEventType:
+ return FocusEventRecord{SetFocus: ir.Event[0] > 0}
+ case KeyEventType:
+ return KeyEventRecord{
+ KeyDown: binary.LittleEndian.Uint32(ir.Event[0:4]) > 0,
+ RepeatCount: binary.LittleEndian.Uint16(ir.Event[4:6]),
+ VirtualKeyCode: VirtualKeyCode(binary.LittleEndian.Uint16(ir.Event[6:8])),
+ VirtualScanCode: VirtualKeyCode(binary.LittleEndian.Uint16(ir.Event[8:10])),
+ Char: rune(binary.LittleEndian.Uint16(ir.Event[10:12])),
+ ControlKeyState: ControlKeyState(binary.LittleEndian.Uint32(ir.Event[12:16])),
+ }
+ case MouseEventType:
+ m := MouseEventRecord{
+ MousePositon: Coord{
+ X: binary.LittleEndian.Uint16(ir.Event[0:2]),
+ Y: binary.LittleEndian.Uint16(ir.Event[2:4]),
+ },
+ ButtonState: ButtonState(binary.LittleEndian.Uint32(ir.Event[4:8])),
+ ControlKeyState: ControlKeyState(binary.LittleEndian.Uint32(ir.Event[8:12])),
+ EventFlags: EventFlags(binary.LittleEndian.Uint32(ir.Event[12:16])),
+ }
+
+ if (m.EventFlags&MOUSE_WHEELED > 0) || (m.EventFlags&MOUSE_HWHEELED > 0) {
+ if int16(highWord(uint32(m.ButtonState))) > 0 {
+ m.WheelDirection = 1
+ } else {
+ m.WheelDirection = -1
+ }
+ }
+
+ return m
+ case WindowBufferSizeEventType:
+ return WindowBufferSizeEventRecord{
+ Size: Coord{
+ X: binary.LittleEndian.Uint16(ir.Event[0:2]),
+ Y: binary.LittleEndian.Uint16(ir.Event[2:4]),
+ },
+ }
+ case MenuEventType:
+ return MenuEventRecord{
+ CommandID: binary.LittleEndian.Uint32(ir.Event[0:4]),
+ }
+ default:
+ return &UnknownEvent{InputRecord: ir}
+ }
+}
+
+// EventRecord represents one of the following event types:
+// TypeFocusEventRecord, TypeKeyEventRecord, TypeMouseEventRecord,
+// TypeWindowBufferSizeEvent, TypeMenuEventRecord and UnknownEvent.
+type EventRecord interface {
+ Type() string
+ fmt.Stringer
+}
+
+// FocusEventType is the event type for a FocusEventRecord (see
+// https://docs.microsoft.com/en-us/windows/console/input-record-str).
+const FocusEventType EventType = 0x0010
+
+// FocusEventRecord represent the FOCUS_EVENT_RECORD structure from the Windows
+// console API (see
+// https://docs.microsoft.com/en-us/windows/console/focus-event-record-str).
+// These events are used internally by the Windows console API and should be
+// ignored.
+type FocusEventRecord struct {
+ // SetFocus is reserved and should not be used.
+ SetFocus bool
+}
+
+// Ensure that FocusEventRecord satisfies EventRecord interface.
+var _ EventRecord = FocusEventRecord{}
+
+// Type ensures that FocusEventRecord satisfies EventRecord interface.
+func (e FocusEventRecord) Type() string { return "FocusEvent" }
+
+// String ensures that FocusEventRecord satisfies EventRecord and fmt.Stringer
+// interfaces.
+func (e FocusEventRecord) String() string { return fmt.Sprintf("%s[%v]", e.Type(), e.SetFocus) }
+
+// KeyEventType is the event type for a KeyEventRecord (see
+// https://docs.microsoft.com/en-us/windows/console/input-record-str).
+const KeyEventType EventType = 0x0001
+
+// KeyEventRecord represent the KEY_EVENT_RECORD structure from the Windows
+// console API (see
+// https://docs.microsoft.com/en-us/windows/console/key-event-record-str).
+type KeyEventRecord struct {
+ // KeyDown specified whether the key is pressed or released.
+ KeyDown bool
+
+ // RepeatCount indicates that a key is being held down. For example, when a
+ // key is held down, five events with RepeatCount equal to 1 may be
+ // generated, one event with RepeatCount equal to 5, or multiple events
+ // with RepeatCount greater than or equal to 1.
+ RepeatCount uint16
+
+ // VirtualKeyCode identifies the given key in a device-independent manner
+ // (see
+ // https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes).
+ VirtualKeyCode VirtualKeyCode
+
+ // VirtualScanCode represents the device-dependent value generated by the
+ // keyboard hardware.
+ VirtualScanCode VirtualKeyCode
+
+ // Char is the character that corresponds to the pressed key. Char can be
+ // zero for some keys.
+ Char rune
+
+ //ControlKeyState holds the state of the control keys.
+ ControlKeyState ControlKeyState
+}
+
+// Ensure that KeyEventRecord satisfies EventRecord interface.
+var _ EventRecord = KeyEventRecord{}
+
+// Type ensures that KeyEventRecord satisfies EventRecord interface.
+func (e KeyEventRecord) Type() string { return "KeyEvent" }
+
+// String ensures that KeyEventRecord satisfies EventRecord and fmt.Stringer
+// interfaces.
+func (e KeyEventRecord) String() string {
+ infos := []string{}
+
+ repeat := ""
+ if e.RepeatCount > 1 {
+ repeat = "x" + strconv.Itoa(int(e.RepeatCount))
+ }
+
+ infos = append(infos, fmt.Sprintf("%q%s", e.Char, repeat))
+
+ direction := "up"
+ if e.KeyDown {
+ direction = "down"
+ }
+
+ infos = append(infos, direction)
+
+ if e.ControlKeyState != NO_CONTROL_KEY {
+ infos = append(infos, e.ControlKeyState.String())
+ }
+
+ infos = append(infos, fmt.Sprintf("KeyCode: %d", e.VirtualKeyCode))
+ infos = append(infos, fmt.Sprintf("ScanCode: %d", e.VirtualScanCode))
+
+ return fmt.Sprintf("%s[%s]", e.Type(), strings.Join(infos, ", "))
+}
+
+// MenuEventType is the event type for a MenuEventRecord (see
+// https://docs.microsoft.com/en-us/windows/console/input-record-str).
+const MenuEventType EventType = 0x0008
+
+// MenuEventRecord represent the MENU_EVENT_RECORD structure from the Windows
+// console API (see
+// https://docs.microsoft.com/en-us/windows/console/menu-event-record-str).
+// These events are deprecated by the Windows console API and should be ignored.
+type MenuEventRecord struct {
+ CommandID uint32
+}
+
+// Ensure that MenuEventRecord satisfies EventRecord interface.
+var _ EventRecord = MenuEventRecord{}
+
+// Type ensures that MenuEventRecord satisfies EventRecord interface.
+func (e MenuEventRecord) Type() string { return "MenuEvent" }
+
+// String ensures that MenuEventRecord satisfies EventRecord and fmt.Stringer
+// interfaces.
+func (e MenuEventRecord) String() string { return fmt.Sprintf("MenuEvent[%d]", e.CommandID) }
+
+// MouseEventType is the event type for a MouseEventRecord (see
+// https://docs.microsoft.com/en-us/windows/console/input-record-str).
+const MouseEventType EventType = 0x0002
+
+// MouseEventRecord represent the MOUSE_EVENT_RECORD structure from the Windows
+// console API (see
+// https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str).
+type MouseEventRecord struct {
+ // MousePosition contains the location of the cursor, in terms of the
+ // console screen buffer's character-cell coordinates.
+ MousePositon Coord
+
+ // ButtonState holds the status of the mouse buttons.
+ ButtonState ButtonState
+
+ // ControlKeyState holds the state of the control keys.
+ ControlKeyState ControlKeyState
+
+ // EventFlags specify tge type of mouse event.
+ EventFlags EventFlags
+
+ // WheelDirection specified the direction in which the mouse wheel is
+ // spinning when EventFlags contains MOUSE_HWHEELED or MOUSE_WHEELED. When
+ // the event flags specify MOUSE_WHEELED it is 1 if the wheel rotated
+ // forward (away from the user) or -1 when it rotates backwards. When
+ // MOUSE_HWHEELED is specified it is 1 when the wheel rotates right and -1
+ // when it rotates left. When the EventFlags do not indicate a mouse wheel
+ // event it is 0.
+ WheelDirection int
+}
+
+// Ensure that MouseEventRecord satisfies EventRecord interface.
+var _ EventRecord = MouseEventRecord{}
+
+func (e MouseEventRecord) WheelDirectionName() string {
+ if e.EventFlags&MOUSE_WHEELED > 0 {
+ if e.WheelDirection > 0 {
+ return "Forward"
+ }
+
+ return "Backward"
+ } else if e.EventFlags&MOUSE_HWHEELED > 0 {
+ if e.WheelDirection > 0 {
+ return "Right"
+ }
+
+ return "Left"
+ }
+
+ return ""
+}
+
+// Type ensures that MouseEventRecord satisfies EventRecord interface.
+func (e MouseEventRecord) Type() string { return "MouseEvent" }
+
+// String ensures that MouseEventRecord satisfies EventRecord and fmt.Stringer
+// interfaces.
+func (e MouseEventRecord) String() string {
+ infos := []string{e.MousePositon.String()}
+
+ if e.ButtonState&0xFF != 0 {
+ infos = append(infos, e.ButtonState.String())
+ }
+
+ eventDescription := e.EventFlags.String()
+
+ wheelDirection := e.WheelDirectionName()
+ if wheelDirection != "" {
+ eventDescription += "(" + wheelDirection + ")"
+ }
+
+ infos = append(infos, eventDescription)
+
+ if e.ControlKeyState != NO_CONTROL_KEY {
+ infos = append(infos, e.ControlKeyState.String())
+ }
+
+ return fmt.Sprintf("%s[%s]", e.Type(), strings.Join(infos, ", "))
+}
+
+// WindowBufferSizeEventType is the event type for a WindowBufferSizeEventRecord
+// (see https://docs.microsoft.com/en-us/windows/console/input-record-str).
+const WindowBufferSizeEventType EventType = 0x0004
+
+// WindowBufferSizeEventRecord represent the WINDOW_BUFFER_SIZE_RECORD structure
+// from the Windows console API (see
+// https://docs.microsoft.com/en-us/windows/console/window-buffer-size-record-str).
+type WindowBufferSizeEventRecord struct {
+ // Size contains the size of the console screen buffer, in character cell columns and rows.
+ Size Coord
+}
+
+// Ensure that WindowBufferSizeEventRecord satisfies EventRecord interface.
+var _ EventRecord = WindowBufferSizeEventRecord{}
+
+// Type ensures that WindowBufferSizeEventRecord satisfies EventRecord interface.
+func (e WindowBufferSizeEventRecord) Type() string { return "WindowBufferSizeEvent" }
+
+// String ensures that WindowBufferSizeEventRecord satisfies EventRecord and fmt.Stringer
+// interfaces.
+func (e WindowBufferSizeEventRecord) String() string {
+ return fmt.Sprintf("WindowBufferSizeEvent[%s]", e.Size)
+}
+
+// UnknownEvent is generated when the event type does not match one of the
+// following types: TypeFocusEventRecord, TypeKeyEventRecord,
+// TypeMouseEventRecord, TypeWindowBufferSizeEvent, TypeMenuEventRecord and
+// UnknownEvent.
+type UnknownEvent struct {
+ InputRecord
+}
+
+// Ensure that UnknownEvent satisfies EventRecord interface.
+var _ EventRecord = UnknownEvent{}
+
+// Type ensures that UnknownEvent satisfies EventRecord interface.
+func (e UnknownEvent) Type() string { return "UnknownEvent" }
+
+// String ensures that UnknownEvent satisfies EventRecord and fmt.Stringer
+// interfaces.
+func (e UnknownEvent) String() string {
+ return fmt.Sprintf("%s[Type: %d, Data: %v]", e.Type(), e.InputRecord.EventType, e.InputRecord.Event[:])
+}
+
+// Coord represent the COORD structure from the Windows
+// console API (see https://docs.microsoft.com/en-us/windows/console/coord-str).
+type Coord struct {
+ // X is the horizontal coordinate or column value. The units depend on the function call.
+ X uint16
+ // Y is the vertical coordinate or row value. The units depend on the function call.
+ Y uint16
+}
+
+// String ensures that Coord satisfies the fmt.Stringer interface.
+func (c Coord) String() string {
+ return fmt.Sprintf("(%d, %d)", c.X, c.Y)
+}
+
+// ButtonState holds the state of the mouse buttons (see
+// https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str).
+type ButtonState uint32
+
+func (bs ButtonState) Contains(state ButtonState) bool {
+ return bs&state > 0
+}
+
+// String ensures that ButtonState satisfies the fmt.Stringer interface.
+func (bs ButtonState) String() string {
+ switch {
+ case bs&FROM_LEFT_1ST_BUTTON_PRESSED > 0:
+ return "Left"
+ case bs&FROM_LEFT_2ND_BUTTON_PRESSED > 0:
+ return "2"
+ case bs&FROM_LEFT_3RD_BUTTON_PRESSED > 0:
+ return "3"
+ case bs&FROM_LEFT_4TH_BUTTON_PRESSED > 0:
+ return "4"
+ case bs&RIGHTMOST_BUTTON_PRESSED > 0:
+ return "Right"
+ case bs&0xFF == 0:
+ return "No Button"
+ default:
+ return fmt.Sprintf("Unknown(%d)", bs)
+ }
+}
+
+func (bs ButtonState) IsReleased() bool {
+ return bs&0xff > 0
+}
+
+// Valid values for ButtonState.
+const (
+ FROM_LEFT_1ST_BUTTON_PRESSED ButtonState = 0x0001
+ RIGHTMOST_BUTTON_PRESSED ButtonState = 0x0002
+ FROM_LEFT_2ND_BUTTON_PRESSED ButtonState = 0x0004
+ FROM_LEFT_3RD_BUTTON_PRESSED ButtonState = 0x0008
+ FROM_LEFT_4TH_BUTTON_PRESSED ButtonState = 0x0010
+)
+
+// ControlKeyState holds the state of the control keys for key and mouse events
+// (see https://docs.microsoft.com/en-us/windows/console/key-event-record-str
+// and https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str).
+type ControlKeyState uint32
+
+func (cks ControlKeyState) Contains(state ControlKeyState) bool {
+ return cks&state > 0
+}
+
+// Valid values for ControlKeyState.
+const (
+ CAPSLOCK_ON ControlKeyState = 0x0080
+ ENHANCED_KEY ControlKeyState = 0x0100
+ LEFT_ALT_PRESSED ControlKeyState = 0x0002
+ LEFT_CTRL_PRESSED ControlKeyState = 0x0008
+ NUMLOCK_ON ControlKeyState = 0x0020
+ RIGHT_ALT_PRESSED ControlKeyState = 0x0001
+ RIGHT_CTRL_PRESSED ControlKeyState = 0x0004
+ SCROLLLOCK_ON ControlKeyState = 0x0040
+ SHIFT_PRESSED ControlKeyState = 0x0010
+ NO_CONTROL_KEY ControlKeyState = 0x0000
+)
+
+// String ensures that ControlKeyState satisfies the fmt.Stringer interface.
+func (cks ControlKeyState) String() string {
+ controlKeys := []string{}
+
+ switch {
+ case cks&CAPSLOCK_ON > 0:
+ controlKeys = append(controlKeys, "CapsLock")
+ case cks&ENHANCED_KEY > 0:
+ controlKeys = append(controlKeys, "Enhanced")
+ case cks&LEFT_ALT_PRESSED > 0:
+ controlKeys = append(controlKeys, "Alt")
+ case cks&LEFT_CTRL_PRESSED > 0:
+ controlKeys = append(controlKeys, "CTRL")
+ case cks&NUMLOCK_ON > 0:
+ controlKeys = append(controlKeys, "NumLock")
+ case cks&RIGHT_ALT_PRESSED > 0:
+ controlKeys = append(controlKeys, "RightAlt")
+ case cks&RIGHT_CTRL_PRESSED > 0:
+ controlKeys = append(controlKeys, "RightCTRL")
+ case cks&SCROLLLOCK_ON > 0:
+ controlKeys = append(controlKeys, "ScrollLock")
+ case cks&SHIFT_PRESSED > 0:
+ controlKeys = append(controlKeys, "Shift")
+ case cks == NO_CONTROL_KEY:
+ default:
+ return fmt.Sprintf("Unknown(%d)", cks)
+ }
+
+ return strings.Join(controlKeys, ",")
+}
+
+// EventFlags specifies the type of a mouse event (see
+// https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str).
+type EventFlags uint32
+
+// String ensures that EventFlags satisfies the fmt.Stringer interface.
+func (ef EventFlags) String() string {
+ switch {
+ case ef&DOUBLE_CLICK > 0:
+ return "DoubleClick"
+ case ef&MOUSE_WHEELED > 0:
+ return "Wheeled"
+ case ef&MOUSE_MOVED > 0:
+ return "Moved"
+ case ef&MOUSE_HWHEELED > 0:
+ return "HWheeld"
+ case ef == CLICK:
+ return "Click"
+ default:
+ return fmt.Sprintf("Unknown(%d)", ef)
+ }
+}
+
+func (ef EventFlags) Contains(flag EventFlags) bool {
+ return ef&flag > 0
+}
+
+// Valid values for EventFlags.
+const (
+ CLICK EventFlags = 0x0000
+ MOUSE_MOVED EventFlags = 0x0001
+ DOUBLE_CLICK EventFlags = 0x0002
+ MOUSE_WHEELED EventFlags = 0x0004
+ MOUSE_HWHEELED EventFlags = 0x0008
+)
+
+func highWord(data uint32) uint16 {
+ return uint16((data & 0xFFFF0000) >> 16)
+}
diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_table.go b/vendor/github.com/mattn/go-runewidth/runewidth_table.go
index e5d890c2..ad025ad5 100644
--- a/vendor/github.com/mattn/go-runewidth/runewidth_table.go
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_table.go
@@ -4,20 +4,21 @@ package runewidth
var combining = table{
{0x0300, 0x036F}, {0x0483, 0x0489}, {0x07EB, 0x07F3},
- {0x0C00, 0x0C00}, {0x0C04, 0x0C04}, {0x0D00, 0x0D01},
- {0x135D, 0x135F}, {0x1A7F, 0x1A7F}, {0x1AB0, 0x1AC0},
- {0x1B6B, 0x1B73}, {0x1DC0, 0x1DF9}, {0x1DFB, 0x1DFF},
+ {0x0C00, 0x0C00}, {0x0C04, 0x0C04}, {0x0CF3, 0x0CF3},
+ {0x0D00, 0x0D01}, {0x135D, 0x135F}, {0x1A7F, 0x1A7F},
+ {0x1AB0, 0x1ACE}, {0x1B6B, 0x1B73}, {0x1DC0, 0x1DFF},
{0x20D0, 0x20F0}, {0x2CEF, 0x2CF1}, {0x2DE0, 0x2DFF},
{0x3099, 0x309A}, {0xA66F, 0xA672}, {0xA674, 0xA67D},
{0xA69E, 0xA69F}, {0xA6F0, 0xA6F1}, {0xA8E0, 0xA8F1},
{0xFE20, 0xFE2F}, {0x101FD, 0x101FD}, {0x10376, 0x1037A},
- {0x10EAB, 0x10EAC}, {0x10F46, 0x10F50}, {0x11300, 0x11301},
- {0x1133B, 0x1133C}, {0x11366, 0x1136C}, {0x11370, 0x11374},
- {0x16AF0, 0x16AF4}, {0x1D165, 0x1D169}, {0x1D16D, 0x1D172},
+ {0x10EAB, 0x10EAC}, {0x10F46, 0x10F50}, {0x10F82, 0x10F85},
+ {0x11300, 0x11301}, {0x1133B, 0x1133C}, {0x11366, 0x1136C},
+ {0x11370, 0x11374}, {0x16AF0, 0x16AF4}, {0x1CF00, 0x1CF2D},
+ {0x1CF30, 0x1CF46}, {0x1D165, 0x1D169}, {0x1D16D, 0x1D172},
{0x1D17B, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD},
{0x1D242, 0x1D244}, {0x1E000, 0x1E006}, {0x1E008, 0x1E018},
{0x1E01B, 0x1E021}, {0x1E023, 0x1E024}, {0x1E026, 0x1E02A},
- {0x1E8D0, 0x1E8D6},
+ {0x1E08F, 0x1E08F}, {0x1E8D0, 0x1E8D6},
}
var doublewidth = table{
@@ -33,33 +34,34 @@ var doublewidth = table{
{0x2753, 0x2755}, {0x2757, 0x2757}, {0x2795, 0x2797},
{0x27B0, 0x27B0}, {0x27BF, 0x27BF}, {0x2B1B, 0x2B1C},
{0x2B50, 0x2B50}, {0x2B55, 0x2B55}, {0x2E80, 0x2E99},
- {0x2E9B, 0x2EF3}, {0x2F00, 0x2FD5}, {0x2FF0, 0x2FFB},
- {0x3000, 0x303E}, {0x3041, 0x3096}, {0x3099, 0x30FF},
- {0x3105, 0x312F}, {0x3131, 0x318E}, {0x3190, 0x31E3},
- {0x31F0, 0x321E}, {0x3220, 0x3247}, {0x3250, 0x4DBF},
- {0x4E00, 0xA48C}, {0xA490, 0xA4C6}, {0xA960, 0xA97C},
- {0xAC00, 0xD7A3}, {0xF900, 0xFAFF}, {0xFE10, 0xFE19},
- {0xFE30, 0xFE52}, {0xFE54, 0xFE66}, {0xFE68, 0xFE6B},
- {0xFF01, 0xFF60}, {0xFFE0, 0xFFE6}, {0x16FE0, 0x16FE4},
- {0x16FF0, 0x16FF1}, {0x17000, 0x187F7}, {0x18800, 0x18CD5},
- {0x18D00, 0x18D08}, {0x1B000, 0x1B11E}, {0x1B150, 0x1B152},
- {0x1B164, 0x1B167}, {0x1B170, 0x1B2FB}, {0x1F004, 0x1F004},
- {0x1F0CF, 0x1F0CF}, {0x1F18E, 0x1F18E}, {0x1F191, 0x1F19A},
- {0x1F200, 0x1F202}, {0x1F210, 0x1F23B}, {0x1F240, 0x1F248},
- {0x1F250, 0x1F251}, {0x1F260, 0x1F265}, {0x1F300, 0x1F320},
- {0x1F32D, 0x1F335}, {0x1F337, 0x1F37C}, {0x1F37E, 0x1F393},
- {0x1F3A0, 0x1F3CA}, {0x1F3CF, 0x1F3D3}, {0x1F3E0, 0x1F3F0},
- {0x1F3F4, 0x1F3F4}, {0x1F3F8, 0x1F43E}, {0x1F440, 0x1F440},
- {0x1F442, 0x1F4FC}, {0x1F4FF, 0x1F53D}, {0x1F54B, 0x1F54E},
- {0x1F550, 0x1F567}, {0x1F57A, 0x1F57A}, {0x1F595, 0x1F596},
- {0x1F5A4, 0x1F5A4}, {0x1F5FB, 0x1F64F}, {0x1F680, 0x1F6C5},
- {0x1F6CC, 0x1F6CC}, {0x1F6D0, 0x1F6D2}, {0x1F6D5, 0x1F6D7},
- {0x1F6EB, 0x1F6EC}, {0x1F6F4, 0x1F6FC}, {0x1F7E0, 0x1F7EB},
- {0x1F90C, 0x1F93A}, {0x1F93C, 0x1F945}, {0x1F947, 0x1F978},
- {0x1F97A, 0x1F9CB}, {0x1F9CD, 0x1F9FF}, {0x1FA70, 0x1FA74},
- {0x1FA78, 0x1FA7A}, {0x1FA80, 0x1FA86}, {0x1FA90, 0x1FAA8},
- {0x1FAB0, 0x1FAB6}, {0x1FAC0, 0x1FAC2}, {0x1FAD0, 0x1FAD6},
- {0x20000, 0x2FFFD}, {0x30000, 0x3FFFD},
+ {0x2E9B, 0x2EF3}, {0x2F00, 0x2FD5}, {0x2FF0, 0x303E},
+ {0x3041, 0x3096}, {0x3099, 0x30FF}, {0x3105, 0x312F},
+ {0x3131, 0x318E}, {0x3190, 0x31E3}, {0x31EF, 0x321E},
+ {0x3220, 0x3247}, {0x3250, 0x4DBF}, {0x4E00, 0xA48C},
+ {0xA490, 0xA4C6}, {0xA960, 0xA97C}, {0xAC00, 0xD7A3},
+ {0xF900, 0xFAFF}, {0xFE10, 0xFE19}, {0xFE30, 0xFE52},
+ {0xFE54, 0xFE66}, {0xFE68, 0xFE6B}, {0xFF01, 0xFF60},
+ {0xFFE0, 0xFFE6}, {0x16FE0, 0x16FE4}, {0x16FF0, 0x16FF1},
+ {0x17000, 0x187F7}, {0x18800, 0x18CD5}, {0x18D00, 0x18D08},
+ {0x1AFF0, 0x1AFF3}, {0x1AFF5, 0x1AFFB}, {0x1AFFD, 0x1AFFE},
+ {0x1B000, 0x1B122}, {0x1B132, 0x1B132}, {0x1B150, 0x1B152},
+ {0x1B155, 0x1B155}, {0x1B164, 0x1B167}, {0x1B170, 0x1B2FB},
+ {0x1F004, 0x1F004}, {0x1F0CF, 0x1F0CF}, {0x1F18E, 0x1F18E},
+ {0x1F191, 0x1F19A}, {0x1F200, 0x1F202}, {0x1F210, 0x1F23B},
+ {0x1F240, 0x1F248}, {0x1F250, 0x1F251}, {0x1F260, 0x1F265},
+ {0x1F300, 0x1F320}, {0x1F32D, 0x1F335}, {0x1F337, 0x1F37C},
+ {0x1F37E, 0x1F393}, {0x1F3A0, 0x1F3CA}, {0x1F3CF, 0x1F3D3},
+ {0x1F3E0, 0x1F3F0}, {0x1F3F4, 0x1F3F4}, {0x1F3F8, 0x1F43E},
+ {0x1F440, 0x1F440}, {0x1F442, 0x1F4FC}, {0x1F4FF, 0x1F53D},
+ {0x1F54B, 0x1F54E}, {0x1F550, 0x1F567}, {0x1F57A, 0x1F57A},
+ {0x1F595, 0x1F596}, {0x1F5A4, 0x1F5A4}, {0x1F5FB, 0x1F64F},
+ {0x1F680, 0x1F6C5}, {0x1F6CC, 0x1F6CC}, {0x1F6D0, 0x1F6D2},
+ {0x1F6D5, 0x1F6D7}, {0x1F6DC, 0x1F6DF}, {0x1F6EB, 0x1F6EC},
+ {0x1F6F4, 0x1F6FC}, {0x1F7E0, 0x1F7EB}, {0x1F7F0, 0x1F7F0},
+ {0x1F90C, 0x1F93A}, {0x1F93C, 0x1F945}, {0x1F947, 0x1F9FF},
+ {0x1FA70, 0x1FA7C}, {0x1FA80, 0x1FA88}, {0x1FA90, 0x1FABD},
+ {0x1FABF, 0x1FAC5}, {0x1FACE, 0x1FADB}, {0x1FAE0, 0x1FAE8},
+ {0x1FAF0, 0x1FAF8}, {0x20000, 0x2FFFD}, {0x30000, 0x3FFFD},
}
var ambiguous = table{
@@ -154,43 +156,43 @@ var neutral = table{
{0x0402, 0x040F}, {0x0450, 0x0450}, {0x0452, 0x052F},
{0x0531, 0x0556}, {0x0559, 0x058A}, {0x058D, 0x058F},
{0x0591, 0x05C7}, {0x05D0, 0x05EA}, {0x05EF, 0x05F4},
- {0x0600, 0x061C}, {0x061E, 0x070D}, {0x070F, 0x074A},
- {0x074D, 0x07B1}, {0x07C0, 0x07FA}, {0x07FD, 0x082D},
- {0x0830, 0x083E}, {0x0840, 0x085B}, {0x085E, 0x085E},
- {0x0860, 0x086A}, {0x08A0, 0x08B4}, {0x08B6, 0x08C7},
- {0x08D3, 0x0983}, {0x0985, 0x098C}, {0x098F, 0x0990},
- {0x0993, 0x09A8}, {0x09AA, 0x09B0}, {0x09B2, 0x09B2},
- {0x09B6, 0x09B9}, {0x09BC, 0x09C4}, {0x09C7, 0x09C8},
- {0x09CB, 0x09CE}, {0x09D7, 0x09D7}, {0x09DC, 0x09DD},
- {0x09DF, 0x09E3}, {0x09E6, 0x09FE}, {0x0A01, 0x0A03},
- {0x0A05, 0x0A0A}, {0x0A0F, 0x0A10}, {0x0A13, 0x0A28},
- {0x0A2A, 0x0A30}, {0x0A32, 0x0A33}, {0x0A35, 0x0A36},
- {0x0A38, 0x0A39}, {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A42},
- {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51},
- {0x0A59, 0x0A5C}, {0x0A5E, 0x0A5E}, {0x0A66, 0x0A76},
- {0x0A81, 0x0A83}, {0x0A85, 0x0A8D}, {0x0A8F, 0x0A91},
- {0x0A93, 0x0AA8}, {0x0AAA, 0x0AB0}, {0x0AB2, 0x0AB3},
- {0x0AB5, 0x0AB9}, {0x0ABC, 0x0AC5}, {0x0AC7, 0x0AC9},
- {0x0ACB, 0x0ACD}, {0x0AD0, 0x0AD0}, {0x0AE0, 0x0AE3},
- {0x0AE6, 0x0AF1}, {0x0AF9, 0x0AFF}, {0x0B01, 0x0B03},
- {0x0B05, 0x0B0C}, {0x0B0F, 0x0B10}, {0x0B13, 0x0B28},
- {0x0B2A, 0x0B30}, {0x0B32, 0x0B33}, {0x0B35, 0x0B39},
- {0x0B3C, 0x0B44}, {0x0B47, 0x0B48}, {0x0B4B, 0x0B4D},
- {0x0B55, 0x0B57}, {0x0B5C, 0x0B5D}, {0x0B5F, 0x0B63},
- {0x0B66, 0x0B77}, {0x0B82, 0x0B83}, {0x0B85, 0x0B8A},
- {0x0B8E, 0x0B90}, {0x0B92, 0x0B95}, {0x0B99, 0x0B9A},
- {0x0B9C, 0x0B9C}, {0x0B9E, 0x0B9F}, {0x0BA3, 0x0BA4},
- {0x0BA8, 0x0BAA}, {0x0BAE, 0x0BB9}, {0x0BBE, 0x0BC2},
- {0x0BC6, 0x0BC8}, {0x0BCA, 0x0BCD}, {0x0BD0, 0x0BD0},
- {0x0BD7, 0x0BD7}, {0x0BE6, 0x0BFA}, {0x0C00, 0x0C0C},
- {0x0C0E, 0x0C10}, {0x0C12, 0x0C28}, {0x0C2A, 0x0C39},
- {0x0C3D, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D},
- {0x0C55, 0x0C56}, {0x0C58, 0x0C5A}, {0x0C60, 0x0C63},
+ {0x0600, 0x070D}, {0x070F, 0x074A}, {0x074D, 0x07B1},
+ {0x07C0, 0x07FA}, {0x07FD, 0x082D}, {0x0830, 0x083E},
+ {0x0840, 0x085B}, {0x085E, 0x085E}, {0x0860, 0x086A},
+ {0x0870, 0x088E}, {0x0890, 0x0891}, {0x0898, 0x0983},
+ {0x0985, 0x098C}, {0x098F, 0x0990}, {0x0993, 0x09A8},
+ {0x09AA, 0x09B0}, {0x09B2, 0x09B2}, {0x09B6, 0x09B9},
+ {0x09BC, 0x09C4}, {0x09C7, 0x09C8}, {0x09CB, 0x09CE},
+ {0x09D7, 0x09D7}, {0x09DC, 0x09DD}, {0x09DF, 0x09E3},
+ {0x09E6, 0x09FE}, {0x0A01, 0x0A03}, {0x0A05, 0x0A0A},
+ {0x0A0F, 0x0A10}, {0x0A13, 0x0A28}, {0x0A2A, 0x0A30},
+ {0x0A32, 0x0A33}, {0x0A35, 0x0A36}, {0x0A38, 0x0A39},
+ {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A42}, {0x0A47, 0x0A48},
+ {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51}, {0x0A59, 0x0A5C},
+ {0x0A5E, 0x0A5E}, {0x0A66, 0x0A76}, {0x0A81, 0x0A83},
+ {0x0A85, 0x0A8D}, {0x0A8F, 0x0A91}, {0x0A93, 0x0AA8},
+ {0x0AAA, 0x0AB0}, {0x0AB2, 0x0AB3}, {0x0AB5, 0x0AB9},
+ {0x0ABC, 0x0AC5}, {0x0AC7, 0x0AC9}, {0x0ACB, 0x0ACD},
+ {0x0AD0, 0x0AD0}, {0x0AE0, 0x0AE3}, {0x0AE6, 0x0AF1},
+ {0x0AF9, 0x0AFF}, {0x0B01, 0x0B03}, {0x0B05, 0x0B0C},
+ {0x0B0F, 0x0B10}, {0x0B13, 0x0B28}, {0x0B2A, 0x0B30},
+ {0x0B32, 0x0B33}, {0x0B35, 0x0B39}, {0x0B3C, 0x0B44},
+ {0x0B47, 0x0B48}, {0x0B4B, 0x0B4D}, {0x0B55, 0x0B57},
+ {0x0B5C, 0x0B5D}, {0x0B5F, 0x0B63}, {0x0B66, 0x0B77},
+ {0x0B82, 0x0B83}, {0x0B85, 0x0B8A}, {0x0B8E, 0x0B90},
+ {0x0B92, 0x0B95}, {0x0B99, 0x0B9A}, {0x0B9C, 0x0B9C},
+ {0x0B9E, 0x0B9F}, {0x0BA3, 0x0BA4}, {0x0BA8, 0x0BAA},
+ {0x0BAE, 0x0BB9}, {0x0BBE, 0x0BC2}, {0x0BC6, 0x0BC8},
+ {0x0BCA, 0x0BCD}, {0x0BD0, 0x0BD0}, {0x0BD7, 0x0BD7},
+ {0x0BE6, 0x0BFA}, {0x0C00, 0x0C0C}, {0x0C0E, 0x0C10},
+ {0x0C12, 0x0C28}, {0x0C2A, 0x0C39}, {0x0C3C, 0x0C44},
+ {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56},
+ {0x0C58, 0x0C5A}, {0x0C5D, 0x0C5D}, {0x0C60, 0x0C63},
{0x0C66, 0x0C6F}, {0x0C77, 0x0C8C}, {0x0C8E, 0x0C90},
{0x0C92, 0x0CA8}, {0x0CAA, 0x0CB3}, {0x0CB5, 0x0CB9},
{0x0CBC, 0x0CC4}, {0x0CC6, 0x0CC8}, {0x0CCA, 0x0CCD},
- {0x0CD5, 0x0CD6}, {0x0CDE, 0x0CDE}, {0x0CE0, 0x0CE3},
- {0x0CE6, 0x0CEF}, {0x0CF1, 0x0CF2}, {0x0D00, 0x0D0C},
+ {0x0CD5, 0x0CD6}, {0x0CDD, 0x0CDE}, {0x0CE0, 0x0CE3},
+ {0x0CE6, 0x0CEF}, {0x0CF1, 0x0CF3}, {0x0D00, 0x0D0C},
{0x0D0E, 0x0D10}, {0x0D12, 0x0D44}, {0x0D46, 0x0D48},
{0x0D4A, 0x0D4F}, {0x0D54, 0x0D63}, {0x0D66, 0x0D7F},
{0x0D81, 0x0D83}, {0x0D85, 0x0D96}, {0x0D9A, 0x0DB1},
@@ -200,7 +202,7 @@ var neutral = table{
{0x0E01, 0x0E3A}, {0x0E3F, 0x0E5B}, {0x0E81, 0x0E82},
{0x0E84, 0x0E84}, {0x0E86, 0x0E8A}, {0x0E8C, 0x0EA3},
{0x0EA5, 0x0EA5}, {0x0EA7, 0x0EBD}, {0x0EC0, 0x0EC4},
- {0x0EC6, 0x0EC6}, {0x0EC8, 0x0ECD}, {0x0ED0, 0x0ED9},
+ {0x0EC6, 0x0EC6}, {0x0EC8, 0x0ECE}, {0x0ED0, 0x0ED9},
{0x0EDC, 0x0EDF}, {0x0F00, 0x0F47}, {0x0F49, 0x0F6C},
{0x0F71, 0x0F97}, {0x0F99, 0x0FBC}, {0x0FBE, 0x0FCC},
{0x0FCE, 0x0FDA}, {0x1000, 0x10C5}, {0x10C7, 0x10C7},
@@ -212,20 +214,19 @@ var neutral = table{
{0x12D8, 0x1310}, {0x1312, 0x1315}, {0x1318, 0x135A},
{0x135D, 0x137C}, {0x1380, 0x1399}, {0x13A0, 0x13F5},
{0x13F8, 0x13FD}, {0x1400, 0x169C}, {0x16A0, 0x16F8},
- {0x1700, 0x170C}, {0x170E, 0x1714}, {0x1720, 0x1736},
- {0x1740, 0x1753}, {0x1760, 0x176C}, {0x176E, 0x1770},
- {0x1772, 0x1773}, {0x1780, 0x17DD}, {0x17E0, 0x17E9},
- {0x17F0, 0x17F9}, {0x1800, 0x180E}, {0x1810, 0x1819},
- {0x1820, 0x1878}, {0x1880, 0x18AA}, {0x18B0, 0x18F5},
- {0x1900, 0x191E}, {0x1920, 0x192B}, {0x1930, 0x193B},
- {0x1940, 0x1940}, {0x1944, 0x196D}, {0x1970, 0x1974},
- {0x1980, 0x19AB}, {0x19B0, 0x19C9}, {0x19D0, 0x19DA},
- {0x19DE, 0x1A1B}, {0x1A1E, 0x1A5E}, {0x1A60, 0x1A7C},
- {0x1A7F, 0x1A89}, {0x1A90, 0x1A99}, {0x1AA0, 0x1AAD},
- {0x1AB0, 0x1AC0}, {0x1B00, 0x1B4B}, {0x1B50, 0x1B7C},
- {0x1B80, 0x1BF3}, {0x1BFC, 0x1C37}, {0x1C3B, 0x1C49},
- {0x1C4D, 0x1C88}, {0x1C90, 0x1CBA}, {0x1CBD, 0x1CC7},
- {0x1CD0, 0x1CFA}, {0x1D00, 0x1DF9}, {0x1DFB, 0x1F15},
+ {0x1700, 0x1715}, {0x171F, 0x1736}, {0x1740, 0x1753},
+ {0x1760, 0x176C}, {0x176E, 0x1770}, {0x1772, 0x1773},
+ {0x1780, 0x17DD}, {0x17E0, 0x17E9}, {0x17F0, 0x17F9},
+ {0x1800, 0x1819}, {0x1820, 0x1878}, {0x1880, 0x18AA},
+ {0x18B0, 0x18F5}, {0x1900, 0x191E}, {0x1920, 0x192B},
+ {0x1930, 0x193B}, {0x1940, 0x1940}, {0x1944, 0x196D},
+ {0x1970, 0x1974}, {0x1980, 0x19AB}, {0x19B0, 0x19C9},
+ {0x19D0, 0x19DA}, {0x19DE, 0x1A1B}, {0x1A1E, 0x1A5E},
+ {0x1A60, 0x1A7C}, {0x1A7F, 0x1A89}, {0x1A90, 0x1A99},
+ {0x1AA0, 0x1AAD}, {0x1AB0, 0x1ACE}, {0x1B00, 0x1B4C},
+ {0x1B50, 0x1B7E}, {0x1B80, 0x1BF3}, {0x1BFC, 0x1C37},
+ {0x1C3B, 0x1C49}, {0x1C4D, 0x1C88}, {0x1C90, 0x1CBA},
+ {0x1CBD, 0x1CC7}, {0x1CD0, 0x1CFA}, {0x1D00, 0x1F15},
{0x1F18, 0x1F1D}, {0x1F20, 0x1F45}, {0x1F48, 0x1F4D},
{0x1F50, 0x1F57}, {0x1F59, 0x1F59}, {0x1F5B, 0x1F5B},
{0x1F5D, 0x1F5D}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4},
@@ -237,7 +238,7 @@ var neutral = table{
{0x2036, 0x203A}, {0x203C, 0x203D}, {0x203F, 0x2064},
{0x2066, 0x2071}, {0x2075, 0x207E}, {0x2080, 0x2080},
{0x2085, 0x208E}, {0x2090, 0x209C}, {0x20A0, 0x20A8},
- {0x20AA, 0x20AB}, {0x20AD, 0x20BF}, {0x20D0, 0x20F0},
+ {0x20AA, 0x20AB}, {0x20AD, 0x20C0}, {0x20D0, 0x20F0},
{0x2100, 0x2102}, {0x2104, 0x2104}, {0x2106, 0x2108},
{0x210A, 0x2112}, {0x2114, 0x2115}, {0x2117, 0x2120},
{0x2123, 0x2125}, {0x2127, 0x212A}, {0x212C, 0x2152},
@@ -275,15 +276,15 @@ var neutral = table{
{0x2780, 0x2794}, {0x2798, 0x27AF}, {0x27B1, 0x27BE},
{0x27C0, 0x27E5}, {0x27EE, 0x2984}, {0x2987, 0x2B1A},
{0x2B1D, 0x2B4F}, {0x2B51, 0x2B54}, {0x2B5A, 0x2B73},
- {0x2B76, 0x2B95}, {0x2B97, 0x2C2E}, {0x2C30, 0x2C5E},
- {0x2C60, 0x2CF3}, {0x2CF9, 0x2D25}, {0x2D27, 0x2D27},
- {0x2D2D, 0x2D2D}, {0x2D30, 0x2D67}, {0x2D6F, 0x2D70},
- {0x2D7F, 0x2D96}, {0x2DA0, 0x2DA6}, {0x2DA8, 0x2DAE},
- {0x2DB0, 0x2DB6}, {0x2DB8, 0x2DBE}, {0x2DC0, 0x2DC6},
- {0x2DC8, 0x2DCE}, {0x2DD0, 0x2DD6}, {0x2DD8, 0x2DDE},
- {0x2DE0, 0x2E52}, {0x303F, 0x303F}, {0x4DC0, 0x4DFF},
- {0xA4D0, 0xA62B}, {0xA640, 0xA6F7}, {0xA700, 0xA7BF},
- {0xA7C2, 0xA7CA}, {0xA7F5, 0xA82C}, {0xA830, 0xA839},
+ {0x2B76, 0x2B95}, {0x2B97, 0x2CF3}, {0x2CF9, 0x2D25},
+ {0x2D27, 0x2D27}, {0x2D2D, 0x2D2D}, {0x2D30, 0x2D67},
+ {0x2D6F, 0x2D70}, {0x2D7F, 0x2D96}, {0x2DA0, 0x2DA6},
+ {0x2DA8, 0x2DAE}, {0x2DB0, 0x2DB6}, {0x2DB8, 0x2DBE},
+ {0x2DC0, 0x2DC6}, {0x2DC8, 0x2DCE}, {0x2DD0, 0x2DD6},
+ {0x2DD8, 0x2DDE}, {0x2DE0, 0x2E5D}, {0x303F, 0x303F},
+ {0x4DC0, 0x4DFF}, {0xA4D0, 0xA62B}, {0xA640, 0xA6F7},
+ {0xA700, 0xA7CA}, {0xA7D0, 0xA7D1}, {0xA7D3, 0xA7D3},
+ {0xA7D5, 0xA7D9}, {0xA7F2, 0xA82C}, {0xA830, 0xA839},
{0xA840, 0xA877}, {0xA880, 0xA8C5}, {0xA8CE, 0xA8D9},
{0xA8E0, 0xA953}, {0xA95F, 0xA95F}, {0xA980, 0xA9CD},
{0xA9CF, 0xA9D9}, {0xA9DE, 0xA9FE}, {0xAA00, 0xAA36},
@@ -294,8 +295,8 @@ var neutral = table{
{0xD7B0, 0xD7C6}, {0xD7CB, 0xD7FB}, {0xD800, 0xDFFF},
{0xFB00, 0xFB06}, {0xFB13, 0xFB17}, {0xFB1D, 0xFB36},
{0xFB38, 0xFB3C}, {0xFB3E, 0xFB3E}, {0xFB40, 0xFB41},
- {0xFB43, 0xFB44}, {0xFB46, 0xFBC1}, {0xFBD3, 0xFD3F},
- {0xFD50, 0xFD8F}, {0xFD92, 0xFDC7}, {0xFDF0, 0xFDFD},
+ {0xFB43, 0xFB44}, {0xFB46, 0xFBC2}, {0xFBD3, 0xFD8F},
+ {0xFD92, 0xFDC7}, {0xFDCF, 0xFDCF}, {0xFDF0, 0xFDFF},
{0xFE20, 0xFE2F}, {0xFE70, 0xFE74}, {0xFE76, 0xFEFC},
{0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFC}, {0x10000, 0x1000B},
{0x1000D, 0x10026}, {0x10028, 0x1003A}, {0x1003C, 0x1003D},
@@ -307,44 +308,48 @@ var neutral = table{
{0x10380, 0x1039D}, {0x1039F, 0x103C3}, {0x103C8, 0x103D5},
{0x10400, 0x1049D}, {0x104A0, 0x104A9}, {0x104B0, 0x104D3},
{0x104D8, 0x104FB}, {0x10500, 0x10527}, {0x10530, 0x10563},
- {0x1056F, 0x1056F}, {0x10600, 0x10736}, {0x10740, 0x10755},
- {0x10760, 0x10767}, {0x10800, 0x10805}, {0x10808, 0x10808},
- {0x1080A, 0x10835}, {0x10837, 0x10838}, {0x1083C, 0x1083C},
- {0x1083F, 0x10855}, {0x10857, 0x1089E}, {0x108A7, 0x108AF},
- {0x108E0, 0x108F2}, {0x108F4, 0x108F5}, {0x108FB, 0x1091B},
- {0x1091F, 0x10939}, {0x1093F, 0x1093F}, {0x10980, 0x109B7},
- {0x109BC, 0x109CF}, {0x109D2, 0x10A03}, {0x10A05, 0x10A06},
- {0x10A0C, 0x10A13}, {0x10A15, 0x10A17}, {0x10A19, 0x10A35},
- {0x10A38, 0x10A3A}, {0x10A3F, 0x10A48}, {0x10A50, 0x10A58},
- {0x10A60, 0x10A9F}, {0x10AC0, 0x10AE6}, {0x10AEB, 0x10AF6},
- {0x10B00, 0x10B35}, {0x10B39, 0x10B55}, {0x10B58, 0x10B72},
- {0x10B78, 0x10B91}, {0x10B99, 0x10B9C}, {0x10BA9, 0x10BAF},
- {0x10C00, 0x10C48}, {0x10C80, 0x10CB2}, {0x10CC0, 0x10CF2},
- {0x10CFA, 0x10D27}, {0x10D30, 0x10D39}, {0x10E60, 0x10E7E},
- {0x10E80, 0x10EA9}, {0x10EAB, 0x10EAD}, {0x10EB0, 0x10EB1},
- {0x10F00, 0x10F27}, {0x10F30, 0x10F59}, {0x10FB0, 0x10FCB},
- {0x10FE0, 0x10FF6}, {0x11000, 0x1104D}, {0x11052, 0x1106F},
- {0x1107F, 0x110C1}, {0x110CD, 0x110CD}, {0x110D0, 0x110E8},
- {0x110F0, 0x110F9}, {0x11100, 0x11134}, {0x11136, 0x11147},
- {0x11150, 0x11176}, {0x11180, 0x111DF}, {0x111E1, 0x111F4},
- {0x11200, 0x11211}, {0x11213, 0x1123E}, {0x11280, 0x11286},
- {0x11288, 0x11288}, {0x1128A, 0x1128D}, {0x1128F, 0x1129D},
- {0x1129F, 0x112A9}, {0x112B0, 0x112EA}, {0x112F0, 0x112F9},
- {0x11300, 0x11303}, {0x11305, 0x1130C}, {0x1130F, 0x11310},
- {0x11313, 0x11328}, {0x1132A, 0x11330}, {0x11332, 0x11333},
- {0x11335, 0x11339}, {0x1133B, 0x11344}, {0x11347, 0x11348},
- {0x1134B, 0x1134D}, {0x11350, 0x11350}, {0x11357, 0x11357},
- {0x1135D, 0x11363}, {0x11366, 0x1136C}, {0x11370, 0x11374},
- {0x11400, 0x1145B}, {0x1145D, 0x11461}, {0x11480, 0x114C7},
- {0x114D0, 0x114D9}, {0x11580, 0x115B5}, {0x115B8, 0x115DD},
- {0x11600, 0x11644}, {0x11650, 0x11659}, {0x11660, 0x1166C},
- {0x11680, 0x116B8}, {0x116C0, 0x116C9}, {0x11700, 0x1171A},
- {0x1171D, 0x1172B}, {0x11730, 0x1173F}, {0x11800, 0x1183B},
- {0x118A0, 0x118F2}, {0x118FF, 0x11906}, {0x11909, 0x11909},
- {0x1190C, 0x11913}, {0x11915, 0x11916}, {0x11918, 0x11935},
- {0x11937, 0x11938}, {0x1193B, 0x11946}, {0x11950, 0x11959},
- {0x119A0, 0x119A7}, {0x119AA, 0x119D7}, {0x119DA, 0x119E4},
- {0x11A00, 0x11A47}, {0x11A50, 0x11AA2}, {0x11AC0, 0x11AF8},
+ {0x1056F, 0x1057A}, {0x1057C, 0x1058A}, {0x1058C, 0x10592},
+ {0x10594, 0x10595}, {0x10597, 0x105A1}, {0x105A3, 0x105B1},
+ {0x105B3, 0x105B9}, {0x105BB, 0x105BC}, {0x10600, 0x10736},
+ {0x10740, 0x10755}, {0x10760, 0x10767}, {0x10780, 0x10785},
+ {0x10787, 0x107B0}, {0x107B2, 0x107BA}, {0x10800, 0x10805},
+ {0x10808, 0x10808}, {0x1080A, 0x10835}, {0x10837, 0x10838},
+ {0x1083C, 0x1083C}, {0x1083F, 0x10855}, {0x10857, 0x1089E},
+ {0x108A7, 0x108AF}, {0x108E0, 0x108F2}, {0x108F4, 0x108F5},
+ {0x108FB, 0x1091B}, {0x1091F, 0x10939}, {0x1093F, 0x1093F},
+ {0x10980, 0x109B7}, {0x109BC, 0x109CF}, {0x109D2, 0x10A03},
+ {0x10A05, 0x10A06}, {0x10A0C, 0x10A13}, {0x10A15, 0x10A17},
+ {0x10A19, 0x10A35}, {0x10A38, 0x10A3A}, {0x10A3F, 0x10A48},
+ {0x10A50, 0x10A58}, {0x10A60, 0x10A9F}, {0x10AC0, 0x10AE6},
+ {0x10AEB, 0x10AF6}, {0x10B00, 0x10B35}, {0x10B39, 0x10B55},
+ {0x10B58, 0x10B72}, {0x10B78, 0x10B91}, {0x10B99, 0x10B9C},
+ {0x10BA9, 0x10BAF}, {0x10C00, 0x10C48}, {0x10C80, 0x10CB2},
+ {0x10CC0, 0x10CF2}, {0x10CFA, 0x10D27}, {0x10D30, 0x10D39},
+ {0x10E60, 0x10E7E}, {0x10E80, 0x10EA9}, {0x10EAB, 0x10EAD},
+ {0x10EB0, 0x10EB1}, {0x10EFD, 0x10F27}, {0x10F30, 0x10F59},
+ {0x10F70, 0x10F89}, {0x10FB0, 0x10FCB}, {0x10FE0, 0x10FF6},
+ {0x11000, 0x1104D}, {0x11052, 0x11075}, {0x1107F, 0x110C2},
+ {0x110CD, 0x110CD}, {0x110D0, 0x110E8}, {0x110F0, 0x110F9},
+ {0x11100, 0x11134}, {0x11136, 0x11147}, {0x11150, 0x11176},
+ {0x11180, 0x111DF}, {0x111E1, 0x111F4}, {0x11200, 0x11211},
+ {0x11213, 0x11241}, {0x11280, 0x11286}, {0x11288, 0x11288},
+ {0x1128A, 0x1128D}, {0x1128F, 0x1129D}, {0x1129F, 0x112A9},
+ {0x112B0, 0x112EA}, {0x112F0, 0x112F9}, {0x11300, 0x11303},
+ {0x11305, 0x1130C}, {0x1130F, 0x11310}, {0x11313, 0x11328},
+ {0x1132A, 0x11330}, {0x11332, 0x11333}, {0x11335, 0x11339},
+ {0x1133B, 0x11344}, {0x11347, 0x11348}, {0x1134B, 0x1134D},
+ {0x11350, 0x11350}, {0x11357, 0x11357}, {0x1135D, 0x11363},
+ {0x11366, 0x1136C}, {0x11370, 0x11374}, {0x11400, 0x1145B},
+ {0x1145D, 0x11461}, {0x11480, 0x114C7}, {0x114D0, 0x114D9},
+ {0x11580, 0x115B5}, {0x115B8, 0x115DD}, {0x11600, 0x11644},
+ {0x11650, 0x11659}, {0x11660, 0x1166C}, {0x11680, 0x116B9},
+ {0x116C0, 0x116C9}, {0x11700, 0x1171A}, {0x1171D, 0x1172B},
+ {0x11730, 0x11746}, {0x11800, 0x1183B}, {0x118A0, 0x118F2},
+ {0x118FF, 0x11906}, {0x11909, 0x11909}, {0x1190C, 0x11913},
+ {0x11915, 0x11916}, {0x11918, 0x11935}, {0x11937, 0x11938},
+ {0x1193B, 0x11946}, {0x11950, 0x11959}, {0x119A0, 0x119A7},
+ {0x119AA, 0x119D7}, {0x119DA, 0x119E4}, {0x11A00, 0x11A47},
+ {0x11A50, 0x11AA2}, {0x11AB0, 0x11AF8}, {0x11B00, 0x11B09},
{0x11C00, 0x11C08}, {0x11C0A, 0x11C36}, {0x11C38, 0x11C45},
{0x11C50, 0x11C6C}, {0x11C70, 0x11C8F}, {0x11C92, 0x11CA7},
{0x11CA9, 0x11CB6}, {0x11D00, 0x11D06}, {0x11D08, 0x11D09},
@@ -352,30 +357,36 @@ var neutral = table{
{0x11D3F, 0x11D47}, {0x11D50, 0x11D59}, {0x11D60, 0x11D65},
{0x11D67, 0x11D68}, {0x11D6A, 0x11D8E}, {0x11D90, 0x11D91},
{0x11D93, 0x11D98}, {0x11DA0, 0x11DA9}, {0x11EE0, 0x11EF8},
+ {0x11F00, 0x11F10}, {0x11F12, 0x11F3A}, {0x11F3E, 0x11F59},
{0x11FB0, 0x11FB0}, {0x11FC0, 0x11FF1}, {0x11FFF, 0x12399},
{0x12400, 0x1246E}, {0x12470, 0x12474}, {0x12480, 0x12543},
- {0x13000, 0x1342E}, {0x13430, 0x13438}, {0x14400, 0x14646},
+ {0x12F90, 0x12FF2}, {0x13000, 0x13455}, {0x14400, 0x14646},
{0x16800, 0x16A38}, {0x16A40, 0x16A5E}, {0x16A60, 0x16A69},
- {0x16A6E, 0x16A6F}, {0x16AD0, 0x16AED}, {0x16AF0, 0x16AF5},
- {0x16B00, 0x16B45}, {0x16B50, 0x16B59}, {0x16B5B, 0x16B61},
- {0x16B63, 0x16B77}, {0x16B7D, 0x16B8F}, {0x16E40, 0x16E9A},
- {0x16F00, 0x16F4A}, {0x16F4F, 0x16F87}, {0x16F8F, 0x16F9F},
- {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C}, {0x1BC80, 0x1BC88},
- {0x1BC90, 0x1BC99}, {0x1BC9C, 0x1BCA3}, {0x1D000, 0x1D0F5},
- {0x1D100, 0x1D126}, {0x1D129, 0x1D1E8}, {0x1D200, 0x1D245},
- {0x1D2E0, 0x1D2F3}, {0x1D300, 0x1D356}, {0x1D360, 0x1D378},
- {0x1D400, 0x1D454}, {0x1D456, 0x1D49C}, {0x1D49E, 0x1D49F},
- {0x1D4A2, 0x1D4A2}, {0x1D4A5, 0x1D4A6}, {0x1D4A9, 0x1D4AC},
- {0x1D4AE, 0x1D4B9}, {0x1D4BB, 0x1D4BB}, {0x1D4BD, 0x1D4C3},
- {0x1D4C5, 0x1D505}, {0x1D507, 0x1D50A}, {0x1D50D, 0x1D514},
- {0x1D516, 0x1D51C}, {0x1D51E, 0x1D539}, {0x1D53B, 0x1D53E},
- {0x1D540, 0x1D544}, {0x1D546, 0x1D546}, {0x1D54A, 0x1D550},
- {0x1D552, 0x1D6A5}, {0x1D6A8, 0x1D7CB}, {0x1D7CE, 0x1DA8B},
- {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006},
- {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024},
- {0x1E026, 0x1E02A}, {0x1E100, 0x1E12C}, {0x1E130, 0x1E13D},
- {0x1E140, 0x1E149}, {0x1E14E, 0x1E14F}, {0x1E2C0, 0x1E2F9},
- {0x1E2FF, 0x1E2FF}, {0x1E800, 0x1E8C4}, {0x1E8C7, 0x1E8D6},
+ {0x16A6E, 0x16ABE}, {0x16AC0, 0x16AC9}, {0x16AD0, 0x16AED},
+ {0x16AF0, 0x16AF5}, {0x16B00, 0x16B45}, {0x16B50, 0x16B59},
+ {0x16B5B, 0x16B61}, {0x16B63, 0x16B77}, {0x16B7D, 0x16B8F},
+ {0x16E40, 0x16E9A}, {0x16F00, 0x16F4A}, {0x16F4F, 0x16F87},
+ {0x16F8F, 0x16F9F}, {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C},
+ {0x1BC80, 0x1BC88}, {0x1BC90, 0x1BC99}, {0x1BC9C, 0x1BCA3},
+ {0x1CF00, 0x1CF2D}, {0x1CF30, 0x1CF46}, {0x1CF50, 0x1CFC3},
+ {0x1D000, 0x1D0F5}, {0x1D100, 0x1D126}, {0x1D129, 0x1D1EA},
+ {0x1D200, 0x1D245}, {0x1D2C0, 0x1D2D3}, {0x1D2E0, 0x1D2F3},
+ {0x1D300, 0x1D356}, {0x1D360, 0x1D378}, {0x1D400, 0x1D454},
+ {0x1D456, 0x1D49C}, {0x1D49E, 0x1D49F}, {0x1D4A2, 0x1D4A2},
+ {0x1D4A5, 0x1D4A6}, {0x1D4A9, 0x1D4AC}, {0x1D4AE, 0x1D4B9},
+ {0x1D4BB, 0x1D4BB}, {0x1D4BD, 0x1D4C3}, {0x1D4C5, 0x1D505},
+ {0x1D507, 0x1D50A}, {0x1D50D, 0x1D514}, {0x1D516, 0x1D51C},
+ {0x1D51E, 0x1D539}, {0x1D53B, 0x1D53E}, {0x1D540, 0x1D544},
+ {0x1D546, 0x1D546}, {0x1D54A, 0x1D550}, {0x1D552, 0x1D6A5},
+ {0x1D6A8, 0x1D7CB}, {0x1D7CE, 0x1DA8B}, {0x1DA9B, 0x1DA9F},
+ {0x1DAA1, 0x1DAAF}, {0x1DF00, 0x1DF1E}, {0x1DF25, 0x1DF2A},
+ {0x1E000, 0x1E006}, {0x1E008, 0x1E018}, {0x1E01B, 0x1E021},
+ {0x1E023, 0x1E024}, {0x1E026, 0x1E02A}, {0x1E030, 0x1E06D},
+ {0x1E08F, 0x1E08F}, {0x1E100, 0x1E12C}, {0x1E130, 0x1E13D},
+ {0x1E140, 0x1E149}, {0x1E14E, 0x1E14F}, {0x1E290, 0x1E2AE},
+ {0x1E2C0, 0x1E2F9}, {0x1E2FF, 0x1E2FF}, {0x1E4D0, 0x1E4F9},
+ {0x1E7E0, 0x1E7E6}, {0x1E7E8, 0x1E7EB}, {0x1E7ED, 0x1E7EE},
+ {0x1E7F0, 0x1E7FE}, {0x1E800, 0x1E8C4}, {0x1E8C7, 0x1E8D6},
{0x1E900, 0x1E94B}, {0x1E950, 0x1E959}, {0x1E95E, 0x1E95F},
{0x1EC71, 0x1ECB4}, {0x1ED01, 0x1ED3D}, {0x1EE00, 0x1EE03},
{0x1EE05, 0x1EE1F}, {0x1EE21, 0x1EE22}, {0x1EE24, 0x1EE24},
@@ -400,8 +411,8 @@ var neutral = table{
{0x1F54F, 0x1F54F}, {0x1F568, 0x1F579}, {0x1F57B, 0x1F594},
{0x1F597, 0x1F5A3}, {0x1F5A5, 0x1F5FA}, {0x1F650, 0x1F67F},
{0x1F6C6, 0x1F6CB}, {0x1F6CD, 0x1F6CF}, {0x1F6D3, 0x1F6D4},
- {0x1F6E0, 0x1F6EA}, {0x1F6F0, 0x1F6F3}, {0x1F700, 0x1F773},
- {0x1F780, 0x1F7D8}, {0x1F800, 0x1F80B}, {0x1F810, 0x1F847},
+ {0x1F6E0, 0x1F6EA}, {0x1F6F0, 0x1F6F3}, {0x1F700, 0x1F776},
+ {0x1F77B, 0x1F7D9}, {0x1F800, 0x1F80B}, {0x1F810, 0x1F847},
{0x1F850, 0x1F859}, {0x1F860, 0x1F887}, {0x1F890, 0x1F8AD},
{0x1F8B0, 0x1F8B1}, {0x1F900, 0x1F90B}, {0x1F93B, 0x1F93B},
{0x1F946, 0x1F946}, {0x1FA00, 0x1FA53}, {0x1FA60, 0x1FA6D},
diff --git a/vendor/github.com/muesli/ansi/README.md b/vendor/github.com/muesli/ansi/README.md
index cb28c656..f9d0fe9a 100644
--- a/vendor/github.com/muesli/ansi/README.md
+++ b/vendor/github.com/muesli/ansi/README.md
@@ -1,2 +1,31 @@
# ansi
+
+[](https://github.com/muesli/ansi/releases)
+[](https://github.com/muesli/ansi/actions)
+[](https://coveralls.io/github/muesli/ansi?branch=master)
+[](https://goreportcard.com/report/muesli/ansi)
+[](https://pkg.go.dev/github.com/muesli/ansi)
+
Raw ANSI sequence helpers
+
+## ANSI Writer
+
+```go
+import "github.com/muesli/ansi"
+
+w := ansi.Writer{Forward: os.Stdout}
+w.Write([]byte("\x1b[31mHello, world!\x1b[0m"))
+w.Close()
+```
+
+## Compressor
+
+The ANSI compressor eliminates unnecessary/redundant ANSI sequences.
+
+```go
+import "github.com/muesli/ansi/compressor"
+
+w := compressor.Writer{Forward: os.Stdout}
+w.Write([]byte("\x1b[31mHello, world!\x1b[0m"))
+w.Close()
+```
diff --git a/vendor/github.com/muesli/reflow/ansi/BUILD.bazel b/vendor/github.com/muesli/reflow/ansi/BUILD.bazel
deleted file mode 100644
index 37aed71e..00000000
--- a/vendor/github.com/muesli/reflow/ansi/BUILD.bazel
+++ /dev/null
@@ -1,14 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library")
-
-go_library(
- name = "go_default_library",
- srcs = [
- "ansi.go",
- "buffer.go",
- "writer.go",
- ],
- importmap = "github.com/kindlyops/vbs/vendor/github.com/muesli/reflow/ansi",
- importpath = "github.com/muesli/reflow/ansi",
- visibility = ["//visibility:public"],
- deps = ["//vendor/github.com/mattn/go-runewidth:go_default_library"],
-)
diff --git a/vendor/github.com/muesli/reflow/ansi/ansi.go b/vendor/github.com/muesli/reflow/ansi/ansi.go
deleted file mode 100644
index f3d0700a..00000000
--- a/vendor/github.com/muesli/reflow/ansi/ansi.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package ansi
-
-const Marker = '\x1B'
-
-func IsTerminator(c rune) bool {
- return (c >= 0x40 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a)
-}
diff --git a/vendor/github.com/muesli/reflow/ansi/buffer.go b/vendor/github.com/muesli/reflow/ansi/buffer.go
deleted file mode 100644
index 471bcaf7..00000000
--- a/vendor/github.com/muesli/reflow/ansi/buffer.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package ansi
-
-import (
- "bytes"
-
- "github.com/mattn/go-runewidth"
-)
-
-// Buffer is a buffer aware of ANSI escape sequences.
-type Buffer struct {
- bytes.Buffer
-}
-
-// PrintableRuneWidth returns the cell width of all printable runes in the
-// buffer.
-func (w Buffer) PrintableRuneWidth() int {
- return PrintableRuneWidth(w.String())
-}
-
-// PrintableRuneWidth returns the cell width of the given string.
-func PrintableRuneWidth(s string) int {
- var n int
- var ansi bool
-
- for _, c := range s {
- if c == Marker {
- // ANSI escape sequence
- ansi = true
- } else if ansi {
- if IsTerminator(c) {
- // ANSI sequence terminated
- ansi = false
- }
- } else {
- n += runewidth.RuneWidth(c)
- }
- }
-
- return n
-}
diff --git a/vendor/github.com/muesli/reflow/ansi/writer.go b/vendor/github.com/muesli/reflow/ansi/writer.go
deleted file mode 100644
index a6aaa1ec..00000000
--- a/vendor/github.com/muesli/reflow/ansi/writer.go
+++ /dev/null
@@ -1,76 +0,0 @@
-package ansi
-
-import (
- "bytes"
- "io"
- "unicode/utf8"
-)
-
-type Writer struct {
- Forward io.Writer
-
- ansi bool
- ansiseq bytes.Buffer
- lastseq bytes.Buffer
- seqchanged bool
- runeBuf []byte
-}
-
-// Write is used to write content to the ANSI buffer.
-func (w *Writer) Write(b []byte) (int, error) {
- for _, c := range string(b) {
- if c == Marker {
- // ANSI escape sequence
- w.ansi = true
- w.seqchanged = true
- _, _ = w.ansiseq.WriteRune(c)
- } else if w.ansi {
- _, _ = w.ansiseq.WriteRune(c)
- if IsTerminator(c) {
- // ANSI sequence terminated
- w.ansi = false
-
- if bytes.HasSuffix(w.ansiseq.Bytes(), []byte("[0m")) {
- // reset sequence
- w.lastseq.Reset()
- w.seqchanged = false
- } else if c == 'm' {
- // color code
- _, _ = w.lastseq.Write(w.ansiseq.Bytes())
- }
-
- _, _ = w.ansiseq.WriteTo(w.Forward)
- }
- } else {
- _, err := w.writeRune(c)
- if err != nil {
- return 0, err
- }
- }
- }
-
- return len(b), nil
-}
-
-func (w *Writer) writeRune(r rune) (int, error) {
- if w.runeBuf == nil {
- w.runeBuf = make([]byte, utf8.UTFMax)
- }
- n := utf8.EncodeRune(w.runeBuf, r)
- return w.Forward.Write(w.runeBuf[:n])
-}
-
-func (w *Writer) LastSequence() string {
- return w.lastseq.String()
-}
-
-func (w *Writer) ResetAnsi() {
- if !w.seqchanged {
- return
- }
- _, _ = w.Forward.Write([]byte("\x1b[0m"))
-}
-
-func (w *Writer) RestoreAnsi() {
- _, _ = w.Forward.Write(w.lastseq.Bytes())
-}
diff --git a/vendor/github.com/muesli/reflow/truncate/BUILD.bazel b/vendor/github.com/muesli/reflow/truncate/BUILD.bazel
deleted file mode 100644
index 92f2cf2f..00000000
--- a/vendor/github.com/muesli/reflow/truncate/BUILD.bazel
+++ /dev/null
@@ -1,13 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library")
-
-go_library(
- name = "go_default_library",
- srcs = ["truncate.go"],
- importmap = "github.com/kindlyops/vbs/vendor/github.com/muesli/reflow/truncate",
- importpath = "github.com/muesli/reflow/truncate",
- visibility = ["//visibility:public"],
- deps = [
- "//vendor/github.com/mattn/go-runewidth:go_default_library",
- "//vendor/github.com/muesli/reflow/ansi:go_default_library",
- ],
-)
diff --git a/vendor/github.com/muesli/reflow/truncate/truncate.go b/vendor/github.com/muesli/reflow/truncate/truncate.go
deleted file mode 100644
index 5aab5f89..00000000
--- a/vendor/github.com/muesli/reflow/truncate/truncate.go
+++ /dev/null
@@ -1,120 +0,0 @@
-package truncate
-
-import (
- "bytes"
- "io"
-
- "github.com/mattn/go-runewidth"
-
- "github.com/muesli/reflow/ansi"
-)
-
-type Writer struct {
- width uint
- tail string
-
- ansiWriter *ansi.Writer
- buf bytes.Buffer
- ansi bool
-}
-
-func NewWriter(width uint, tail string) *Writer {
- w := &Writer{
- width: width,
- tail: tail,
- }
- w.ansiWriter = &ansi.Writer{
- Forward: &w.buf,
- }
- return w
-}
-
-func NewWriterPipe(forward io.Writer, width uint, tail string) *Writer {
- return &Writer{
- width: width,
- tail: tail,
- ansiWriter: &ansi.Writer{
- Forward: forward,
- },
- }
-}
-
-// Bytes is shorthand for declaring a new default truncate-writer instance,
-// used to immediately truncate a byte slice.
-func Bytes(b []byte, width uint) []byte {
- return BytesWithTail(b, width, []byte(""))
-}
-
-// Bytes is shorthand for declaring a new default truncate-writer instance,
-// used to immediately truncate a byte slice. A tail is then added to the
-// end of the byte slice.
-func BytesWithTail(b []byte, width uint, tail []byte) []byte {
- f := NewWriter(width, string(tail))
- _, _ = f.Write(b)
-
- return f.Bytes()
-}
-
-// String is shorthand for declaring a new default truncate-writer instance,
-// used to immediately truncate a string.
-func String(s string, width uint) string {
- return StringWithTail(s, width, "")
-}
-
-// StringWithTail is shorthand for declaring a new default truncate-writer instance,
-// used to immediately truncate a string. A tail is then added to the end of the
-// string.
-func StringWithTail(s string, width uint, tail string) string {
- return string(BytesWithTail([]byte(s), width, []byte(tail)))
-}
-
-// Write truncates content at the given printable cell width, leaving any
-// ansi sequences intact.
-func (w *Writer) Write(b []byte) (int, error) {
- tw := ansi.PrintableRuneWidth(w.tail)
- if w.width < uint(tw) {
- return w.buf.WriteString(w.tail)
- }
-
- w.width -= uint(tw)
- var curWidth uint
-
- for _, c := range string(b) {
- if c == ansi.Marker {
- // ANSI escape sequence
- w.ansi = true
- } else if w.ansi {
- if ansi.IsTerminator(c) {
- // ANSI sequence terminated
- w.ansi = false
- }
- } else {
- curWidth += uint(runewidth.RuneWidth(c))
- }
-
- if curWidth > w.width {
- n, err := w.buf.WriteString(w.tail)
- if w.ansiWriter.LastSequence() != "" {
- w.ansiWriter.ResetAnsi()
- }
- return n, err
- }
-
- _, err := w.ansiWriter.Write([]byte(string(c)))
- if err != nil {
- return 0, err
- }
- }
-
- return len(b), nil
-}
-
-// Bytes returns the truncated result as a byte slice.
-func (w *Writer) Bytes() []byte {
- return w.buf.Bytes()
-}
-
-// String returns the truncated result as a string.
-func (w *Writer) String() string {
- return w.buf.String()
-}
diff --git a/vendor/github.com/muesli/reflow/wordwrap/BUILD.bazel b/vendor/github.com/muesli/reflow/wordwrap/BUILD.bazel
deleted file mode 100644
index 2139c469..00000000
--- a/vendor/github.com/muesli/reflow/wordwrap/BUILD.bazel
+++ /dev/null
@@ -1,10 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library")
-
-go_library(
- name = "go_default_library",
- srcs = ["wordwrap.go"],
- importmap = "github.com/kindlyops/vbs/vendor/github.com/muesli/reflow/wordwrap",
- importpath = "github.com/muesli/reflow/wordwrap",
- visibility = ["//visibility:public"],
- deps = ["//vendor/github.com/muesli/reflow/ansi:go_default_library"],
-)
diff --git a/vendor/github.com/muesli/reflow/wordwrap/wordwrap.go b/vendor/github.com/muesli/reflow/wordwrap/wordwrap.go
deleted file mode 100644
index 488fb210..00000000
--- a/vendor/github.com/muesli/reflow/wordwrap/wordwrap.go
+++ /dev/null
@@ -1,167 +0,0 @@
-package wordwrap
-
-import (
- "bytes"
- "strings"
- "unicode"
-
- "github.com/muesli/reflow/ansi"
-)
-
-var (
- defaultBreakpoints = []rune{'-'}
- defaultNewline = []rune{'\n'}
-)
-
-// WordWrap contains settings and state for customisable text reflowing with
-// support for ANSI escape sequences. This means you can style your terminal
-// output without affecting the word wrapping algorithm.
-type WordWrap struct {
- Limit int
- Breakpoints []rune
- Newline []rune
- KeepNewlines bool
-
- buf bytes.Buffer
- space bytes.Buffer
- word ansi.Buffer
-
- lineLen int
- ansi bool
-}
-
-// NewWriter returns a new instance of a word-wrapping writer, initialized with
-// default settings.
-func NewWriter(limit int) *WordWrap {
- return &WordWrap{
- Limit: limit,
- Breakpoints: defaultBreakpoints,
- Newline: defaultNewline,
- KeepNewlines: true,
- }
-}
-
-// Bytes is shorthand for declaring a new default WordWrap instance,
-// used to immediately word-wrap a byte slice.
-func Bytes(b []byte, limit int) []byte {
- f := NewWriter(limit)
- _, _ = f.Write(b)
- _ = f.Close()
-
- return f.Bytes()
-}
-
-// String is shorthand for declaring a new default WordWrap instance,
-// used to immediately word-wrap a string.
-func String(s string, limit int) string {
- return string(Bytes([]byte(s), limit))
-}
-
-func (w *WordWrap) addSpace() {
- w.lineLen += w.space.Len()
- _, _ = w.buf.Write(w.space.Bytes())
- w.space.Reset()
-}
-
-func (w *WordWrap) addWord() {
- if w.word.Len() > 0 {
- w.addSpace()
- w.lineLen += w.word.PrintableRuneWidth()
- _, _ = w.buf.Write(w.word.Bytes())
- w.word.Reset()
- }
-}
-
-func (w *WordWrap) addNewLine() {
- _, _ = w.buf.WriteRune('\n')
- w.lineLen = 0
- w.space.Reset()
-}
-
-func inGroup(a []rune, c rune) bool {
- for _, v := range a {
- if v == c {
- return true
- }
- }
- return false
-}
-
-// Write is used to write more content to the word-wrap buffer.
-func (w *WordWrap) Write(b []byte) (int, error) {
- if w.Limit == 0 {
- return w.buf.Write(b)
- }
-
- s := string(b)
- if !w.KeepNewlines {
- s = strings.Replace(strings.TrimSpace(s), "\n", " ", -1)
- }
-
- for _, c := range s {
- if c == '\x1B' {
- // ANSI escape sequence
- _, _ = w.word.WriteRune(c)
- w.ansi = true
- } else if w.ansi {
- _, _ = w.word.WriteRune(c)
- if (c >= 0x40 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a) {
- // ANSI sequence terminated
- w.ansi = false
- }
- } else if inGroup(w.Newline, c) {
- // end of current line
- // see if we can add the content of the space buffer to the current line
- if w.word.Len() == 0 {
- if w.lineLen+w.space.Len() > w.Limit {
- w.lineLen = 0
- } else {
- // preserve whitespace
- _, _ = w.buf.Write(w.space.Bytes())
- }
- w.space.Reset()
- }
-
- w.addWord()
- w.addNewLine()
- } else if unicode.IsSpace(c) {
- // end of current word
- w.addWord()
- _, _ = w.space.WriteRune(c)
- } else if inGroup(w.Breakpoints, c) {
- // valid breakpoint
- w.addSpace()
- w.addWord()
- _, _ = w.buf.WriteRune(c)
- } else {
- // any other character
- _, _ = w.word.WriteRune(c)
-
- // add a line break if the current word would exceed the line's
- // character limit
- if w.lineLen+w.space.Len()+w.word.PrintableRuneWidth() > w.Limit &&
- w.word.PrintableRuneWidth() < w.Limit {
- w.addNewLine()
- }
- }
- }
-
- return len(b), nil
-}
-
-// Close will finish the word-wrap operation. Always call it before trying to
-// retrieve the final result.
-func (w *WordWrap) Close() error {
- w.addWord()
- return nil
-}
-
-// Bytes returns the word-wrapped result as a byte slice.
-func (w *WordWrap) Bytes() []byte {
- return w.buf.Bytes()
-}
-
-// String returns the word-wrapped result as a string.
-func (w *WordWrap) String() string {
- return w.buf.String()
-}
diff --git a/vendor/github.com/muesli/reflow/wrap/BUILD.bazel b/vendor/github.com/muesli/reflow/wrap/BUILD.bazel
deleted file mode 100644
index 7311ebde..00000000
--- a/vendor/github.com/muesli/reflow/wrap/BUILD.bazel
+++ /dev/null
@@ -1,13 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library")
-
-go_library(
- name = "go_default_library",
- srcs = ["wrap.go"],
- importmap = "github.com/kindlyops/vbs/vendor/github.com/muesli/reflow/wrap",
- importpath = "github.com/muesli/reflow/wrap",
- visibility = ["//visibility:public"],
- deps = [
- "//vendor/github.com/mattn/go-runewidth:go_default_library",
- "//vendor/github.com/muesli/reflow/ansi:go_default_library",
- ],
-)
diff --git a/vendor/github.com/muesli/reflow/wrap/wrap.go b/vendor/github.com/muesli/reflow/wrap/wrap.go
deleted file mode 100644
index f624c5f4..00000000
--- a/vendor/github.com/muesli/reflow/wrap/wrap.go
+++ /dev/null
@@ -1,134 +0,0 @@
-package wrap
-
-import (
- "bytes"
- "strings"
- "unicode"
-
- "github.com/mattn/go-runewidth"
- "github.com/muesli/reflow/ansi"
-)
-
-var (
- defaultNewline = []rune{'\n'}
- defaultTabWidth = 4
-)
-
-type Wrap struct {
- Limit int
- Newline []rune
- KeepNewlines bool
- PreserveSpace bool
- TabWidth int
-
- buf *bytes.Buffer
- lineLen int
- ansi bool
- forcefulNewline bool
-}
-
-// NewWriter returns a new instance of a wrapping writer, initialized with
-// default settings.
-func NewWriter(limit int) *Wrap {
- return &Wrap{
- Limit: limit,
- Newline: defaultNewline,
- KeepNewlines: true,
- // Keep whitespaces following a forceful line break. If disabled,
- // leading whitespaces in a line are only kept if the line break
- // was not forceful, meaning a line break that was already present
- // in the input
- PreserveSpace: false,
- TabWidth: defaultTabWidth,
-
- buf: &bytes.Buffer{},
- }
-}
-
-// Bytes is shorthand for declaring a new default Wrap instance,
-// used to immediately wrap a byte slice.
-func Bytes(b []byte, limit int) []byte {
- f := NewWriter(limit)
- _, _ = f.Write(b)
-
- return f.buf.Bytes()
-}
-
-func (w *Wrap) addNewLine() {
- _, _ = w.buf.WriteRune('\n')
- w.lineLen = 0
-}
-
-// String is shorthand for declaring a new default Wrap instance,
-// used to immediately wrap a string.
-func String(s string, limit int) string {
- return string(Bytes([]byte(s), limit))
-}
-
-func (w *Wrap) Write(b []byte) (int, error) {
- s := strings.Replace(string(b), "\t", strings.Repeat(" ", w.TabWidth), -1)
- if !w.KeepNewlines {
- s = strings.Replace(s, "\n", "", -1)
- }
-
- width := ansi.PrintableRuneWidth(s)
-
- if w.Limit <= 0 || w.lineLen+width <= w.Limit {
- w.lineLen += width
- return w.buf.Write(b)
- }
-
- for _, c := range s {
- if c == ansi.Marker {
- w.ansi = true
- } else if w.ansi {
- if ansi.IsTerminator(c) {
- w.ansi = false
- }
- } else if inGroup(w.Newline, c) {
- w.addNewLine()
- w.forcefulNewline = false
- continue
- } else {
- width := runewidth.RuneWidth(c)
-
- if w.lineLen+width > w.Limit {
- w.addNewLine()
- w.forcefulNewline = true
- }
-
- if w.lineLen == 0 {
- if w.forcefulNewline && !w.PreserveSpace && unicode.IsSpace(c) {
- continue
- }
- } else {
- w.forcefulNewline = false
- }
-
- w.lineLen += width
- }
-
- _, _ = w.buf.WriteRune(c)
- }
-
- return len(b), nil
-}
-
-// Bytes returns the wrapped result as a byte slice.
-func (w *Wrap) Bytes() []byte {
- return w.buf.Bytes()
-}
-
-// String returns the wrapped result as a string.
-func (w *Wrap) String() string {
- return w.buf.String()
-}
-
-func inGroup(a []rune, c rune) bool {
- for _, v := range a {
- if v == c {
- return true
- }
- }
- return false
-}
diff --git a/vendor/github.com/muesli/termenv/.golangci-soft.yml b/vendor/github.com/muesli/termenv/.golangci-soft.yml
index ef456e06..84e3d41d 100644
--- a/vendor/github.com/muesli/termenv/.golangci-soft.yml
+++ b/vendor/github.com/muesli/termenv/.golangci-soft.yml
@@ -20,10 +20,9 @@ linters:
- goconst
- godot
- godox
- - gomnd
+ - mnd
- gomoddirectives
- goprintffuncname
- - ifshort
# - lll
- misspell
- nakedret
@@ -35,13 +34,10 @@ linters:
# disable default linters, they are already enabled in .golangci.yml
disable:
- - deadcode
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- - structcheck
- typecheck
- unused
- - varcheck
diff --git a/vendor/github.com/muesli/termenv/.golangci.yml b/vendor/github.com/muesli/termenv/.golangci.yml
index a5a91d0d..684d54bf 100644
--- a/vendor/github.com/muesli/termenv/.golangci.yml
+++ b/vendor/github.com/muesli/termenv/.golangci.yml
@@ -15,7 +15,6 @@ issues:
linters:
enable:
- bodyclose
- - exportloopref
- goimports
- gosec
- nilerr
diff --git a/vendor/github.com/muesli/termenv/BUILD.bazel b/vendor/github.com/muesli/termenv/BUILD.bazel
index 10be1520..9e59c685 100644
--- a/vendor/github.com/muesli/termenv/BUILD.bazel
+++ b/vendor/github.com/muesli/termenv/BUILD.bazel
@@ -8,6 +8,7 @@ go_library(
"constants_linux.go",
"constants_solaris.go",
"constants_unix.go",
+ "constants_zos.go",
"copy.go",
"hyperlink.go",
"notification.go",
@@ -30,35 +31,9 @@ go_library(
"//vendor/github.com/aymanbagabas/go-osc52/v2:go_default_library",
"//vendor/github.com/lucasb-eyer/go-colorful:go_default_library",
"//vendor/github.com/mattn/go-isatty:go_default_library",
- "//vendor/github.com/mattn/go-runewidth:go_default_library",
+ "//vendor/github.com/rivo/uniseg:go_default_library",
+ "//vendor/golang.org/x/sys/unix:go_default_library",
] + select({
- "@io_bazel_rules_go//go/platform:android": [
- "//vendor/golang.org/x/sys/unix:go_default_library",
- ],
- "@io_bazel_rules_go//go/platform:darwin": [
- "//vendor/golang.org/x/sys/unix:go_default_library",
- ],
- "@io_bazel_rules_go//go/platform:dragonfly": [
- "//vendor/golang.org/x/sys/unix:go_default_library",
- ],
- "@io_bazel_rules_go//go/platform:freebsd": [
- "//vendor/golang.org/x/sys/unix:go_default_library",
- ],
- "@io_bazel_rules_go//go/platform:ios": [
- "//vendor/golang.org/x/sys/unix:go_default_library",
- ],
- "@io_bazel_rules_go//go/platform:linux": [
- "//vendor/golang.org/x/sys/unix:go_default_library",
- ],
- "@io_bazel_rules_go//go/platform:netbsd": [
- "//vendor/golang.org/x/sys/unix:go_default_library",
- ],
- "@io_bazel_rules_go//go/platform:openbsd": [
- "//vendor/golang.org/x/sys/unix:go_default_library",
- ],
- "@io_bazel_rules_go//go/platform:solaris": [
- "//vendor/golang.org/x/sys/unix:go_default_library",
- ],
"@io_bazel_rules_go//go/platform:windows": [
"//vendor/golang.org/x/sys/windows:go_default_library",
],
diff --git a/vendor/github.com/muesli/termenv/README.md b/vendor/github.com/muesli/termenv/README.md
index 29dcf017..fa7929d4 100644
--- a/vendor/github.com/muesli/termenv/README.md
+++ b/vendor/github.com/muesli/termenv/README.md
@@ -307,7 +307,7 @@ termenv.DisableBracketedPaste()
### Color Support
-- 24-bit (RGB): alacritty, foot, iTerm, kitty, Konsole, st, tmux, vte-based, wezterm, Windows Terminal
+- 24-bit (RGB): alacritty, foot, iTerm, kitty, Konsole, st, tmux, vte-based, wezterm, Ghostty, Windows Terminal
- 8-bit (256): rxvt, screen, xterm, Apple Terminal
- 4-bit (16): Linux Console
@@ -350,7 +350,7 @@ You can help improve this list! Check out [how to](ansi_compat.md) and open an i
| Terminal | Copy to Clipboard (OSC52) | Hyperlinks (OSC8) | Notifications (OSC777) |
| ---------------- | :-----------------------: | :---------------: | :--------------------: |
-| alacritty | ✅ | ❌[^alacritty] | ❌ |
+| alacritty | ✅ | ✅[^alacritty] | ❌ |
| foot | ✅ | ✅ | ✅ |
| kitty | ✅ | ✅ | ✅ |
| Konsole | ❌[^konsole] | ✅ | ❌ |
@@ -374,7 +374,7 @@ You can help improve this list! Check out [how to](ansi_compat.md) and open an i
[^apple]: OSC52 works with a [workaround](https://github.com/roy2220/osc52pty).
[^tmux]: OSC8 is not supported, for more info see [issue#911](https://github.com/tmux/tmux/issues/911).
[^screen]: OSC8 is not supported, for more info see [bug#50952](https://savannah.gnu.org/bugs/index.php?50952).
-[^alacritty]: OSC8 is not supported, for more info see [issue#922](https://github.com/alacritty/alacritty/issues/922).
+[^alacritty]: OSC8 is supported since [v0.11.0](https://github.com/alacritty/alacritty/releases/tag/v0.11.0)
diff --git a/vendor/github.com/muesli/termenv/ansicolors.go b/vendor/github.com/muesli/termenv/ansicolors.go
index ee303e22..1a301b0f 100644
--- a/vendor/github.com/muesli/termenv/ansicolors.go
+++ b/vendor/github.com/muesli/termenv/ansicolors.go
@@ -1,6 +1,6 @@
package termenv
-// ANSI color codes
+// ANSI color codes.
const (
ANSIBlack ANSIColor = iota
ANSIRed
diff --git a/vendor/github.com/muesli/termenv/color.go b/vendor/github.com/muesli/termenv/color.go
index 1a216e93..59e639b1 100644
--- a/vendor/github.com/muesli/termenv/color.go
+++ b/vendor/github.com/muesli/termenv/color.go
@@ -9,12 +9,10 @@ import (
"github.com/lucasb-eyer/go-colorful"
)
-var (
- // ErrInvalidColor gets returned when a color is invalid.
- ErrInvalidColor = errors.New("invalid color")
-)
+// ErrInvalidColor gets returned when a color is invalid.
+var ErrInvalidColor = errors.New("invalid color")
-// Foreground and Background sequence codes
+// Foreground and Background sequence codes.
const (
Foreground = "38"
Background = "48"
@@ -73,6 +71,8 @@ func (c NoColor) Sequence(_ bool) string {
}
// Sequence returns the ANSI Sequence for the color.
+//
+//nolint:mnd
func (c ANSIColor) Sequence(bg bool) string {
col := int(c)
bgMod := func(c int) int {
@@ -83,9 +83,9 @@ func (c ANSIColor) Sequence(bg bool) string {
}
if col < 8 {
- return fmt.Sprintf("%d", bgMod(col)+30)
+ return fmt.Sprintf("%d", bgMod(col)+30) //nolint:mnd
}
- return fmt.Sprintf("%d", bgMod(col-8)+90)
+ return fmt.Sprintf("%d", bgMod(col-8)+90) //nolint:mnd
}
// Sequence returns the ANSI Sequence for the color.
@@ -108,7 +108,7 @@ func (c RGBColor) Sequence(bg bool) string {
if bg {
prefix = Background
}
- return fmt.Sprintf("%s;2;%d;%d;%d", prefix, uint8(f.R*255), uint8(f.G*255), uint8(f.B*255))
+ return fmt.Sprintf("%s;2;%d;%d;%d", prefix, uint8(f.R*255), uint8(f.G*255), uint8(f.B*255)) //nolint:mnd
}
func xTermColor(s string) (RGBColor, error) {
@@ -158,6 +158,7 @@ func ansi256ToANSIColor(c ANSI256Color) ANSIColor {
return ANSIColor(r)
}
+//nolint:mnd
func hexToANSI256Color(c colorful.Color) ANSI256Color {
v2ci := func(v float64) int {
if v < 48 {
diff --git a/vendor/github.com/muesli/termenv/constants_zos.go b/vendor/github.com/muesli/termenv/constants_zos.go
new file mode 100644
index 00000000..4262f03b
--- /dev/null
+++ b/vendor/github.com/muesli/termenv/constants_zos.go
@@ -0,0 +1,8 @@
+package termenv
+
+import "golang.org/x/sys/unix"
+
+const (
+ tcgetattr = unix.TCGETS
+ tcsetattr = unix.TCSETS
+)
diff --git a/vendor/github.com/muesli/termenv/output.go b/vendor/github.com/muesli/termenv/output.go
index e22d369c..e4434de0 100644
--- a/vendor/github.com/muesli/termenv/output.go
+++ b/vendor/github.com/muesli/termenv/output.go
@@ -6,12 +6,12 @@ import (
"sync"
)
-var (
- // output is the default global output.
- output = NewOutput(os.Stdout)
-)
+// output is the default global output.
+var output = NewOutput(os.Stdout)
// File represents a file descriptor.
+//
+// Deprecated: Use *os.File instead.
type File interface {
io.ReadWriter
Fd() uintptr
@@ -23,7 +23,7 @@ type OutputOption = func(*Output)
// Output is a terminal output.
type Output struct {
Profile
- tty io.Writer
+ w io.Writer
environ Environ
assumeTTY bool
@@ -61,10 +61,10 @@ func SetDefaultOutput(o *Output) {
output = o
}
-// NewOutput returns a new Output for the given file descriptor.
-func NewOutput(tty io.Writer, opts ...OutputOption) *Output {
+// NewOutput returns a new Output for the given writer.
+func NewOutput(w io.Writer, opts ...OutputOption) *Output {
o := &Output{
- tty: tty,
+ w: w,
environ: &osEnviron{},
Profile: -1,
fgSync: &sync.Once{},
@@ -73,8 +73,8 @@ func NewOutput(tty io.Writer, opts ...OutputOption) *Output {
bgColor: NoColor{},
}
- if o.tty == nil {
- o.tty = os.Stdout
+ if o.w == nil {
+ o.w = os.Stdout
}
for _, opt := range opts {
opt(o)
@@ -175,20 +175,28 @@ func (o *Output) BackgroundColor() Color {
func (o *Output) HasDarkBackground() bool {
c := ConvertToRGB(o.BackgroundColor())
_, _, l := c.Hsl()
- return l < 0.5
+ return l < 0.5 //nolint:mnd
}
// TTY returns the terminal's file descriptor. This may be nil if the output is
// not a terminal.
+//
+// Deprecated: Use Writer() instead.
func (o Output) TTY() File {
- if f, ok := o.tty.(File); ok {
+ if f, ok := o.w.(File); ok {
return f
}
return nil
}
+// Writer returns the underlying writer. This may be of type io.Writer,
+// io.ReadWriter, or *os.File.
+func (o Output) Writer() io.Writer {
+ return o.w
+}
+
func (o Output) Write(p []byte) (int, error) {
- return o.tty.Write(p)
+ return o.w.Write(p) //nolint:wrapcheck
}
// WriteString writes the given string to the output.
diff --git a/vendor/github.com/muesli/termenv/profile.go b/vendor/github.com/muesli/termenv/profile.go
index fa128e20..7d38f5fb 100644
--- a/vendor/github.com/muesli/termenv/profile.go
+++ b/vendor/github.com/muesli/termenv/profile.go
@@ -12,16 +12,31 @@ import (
type Profile int
const (
- // TrueColor, 24-bit color profile
+ // TrueColor, 24-bit color profile.
TrueColor = Profile(iota)
- // ANSI256, 8-bit color profile
+ // ANSI256, 8-bit color profile.
ANSI256
- // ANSI, 4-bit color profile
+ // ANSI, 4-bit color profile.
ANSI
- // Ascii, uncolored profile
+ // Ascii, uncolored profile.
Ascii //nolint:revive
)
+// Name returns the profile name as a string.
+func (p Profile) Name() string {
+ switch p {
+ case Ascii:
+ return "Ascii"
+ case ANSI:
+ return "ANSI"
+ case ANSI256:
+ return "ANSI256"
+ case TrueColor:
+ return "TrueColor"
+ }
+ return "Unknown"
+}
+
// String returns a new Style.
func (p Profile) String(s ...string) Style {
return Style{
@@ -80,7 +95,7 @@ func (p Profile) Color(s string) Color {
return nil
}
- if i < 16 {
+ if i < 16 { //nolint:mnd
c = ANSIColor(i)
} else {
c = ANSI256Color(i)
diff --git a/vendor/github.com/muesli/termenv/screen.go b/vendor/github.com/muesli/termenv/screen.go
index a71181b6..75c11d01 100644
--- a/vendor/github.com/muesli/termenv/screen.go
+++ b/vendor/github.com/muesli/termenv/screen.go
@@ -71,234 +71,234 @@ const (
// Reset the terminal to its default style, removing any active styles.
func (o Output) Reset() {
- fmt.Fprint(o.tty, CSI+ResetSeq+"m")
+ fmt.Fprint(o.w, CSI+ResetSeq+"m") //nolint:errcheck
}
// SetForegroundColor sets the default foreground color.
func (o Output) SetForegroundColor(color Color) {
- fmt.Fprintf(o.tty, OSC+SetForegroundColorSeq, color)
+ fmt.Fprintf(o.w, OSC+SetForegroundColorSeq, color) //nolint:errcheck
}
// SetBackgroundColor sets the default background color.
func (o Output) SetBackgroundColor(color Color) {
- fmt.Fprintf(o.tty, OSC+SetBackgroundColorSeq, color)
+ fmt.Fprintf(o.w, OSC+SetBackgroundColorSeq, color) //nolint:errcheck
}
// SetCursorColor sets the cursor color.
func (o Output) SetCursorColor(color Color) {
- fmt.Fprintf(o.tty, OSC+SetCursorColorSeq, color)
+ fmt.Fprintf(o.w, OSC+SetCursorColorSeq, color) //nolint:errcheck
}
// RestoreScreen restores a previously saved screen state.
func (o Output) RestoreScreen() {
- fmt.Fprint(o.tty, CSI+RestoreScreenSeq)
+ fmt.Fprint(o.w, CSI+RestoreScreenSeq) //nolint:errcheck
}
// SaveScreen saves the screen state.
func (o Output) SaveScreen() {
- fmt.Fprint(o.tty, CSI+SaveScreenSeq)
+ fmt.Fprint(o.w, CSI+SaveScreenSeq) //nolint:errcheck
}
// AltScreen switches to the alternate screen buffer. The former view can be
// restored with ExitAltScreen().
func (o Output) AltScreen() {
- fmt.Fprint(o.tty, CSI+AltScreenSeq)
+ fmt.Fprint(o.w, CSI+AltScreenSeq) //nolint:errcheck
}
// ExitAltScreen exits the alternate screen buffer and returns to the former
// terminal view.
func (o Output) ExitAltScreen() {
- fmt.Fprint(o.tty, CSI+ExitAltScreenSeq)
+ fmt.Fprint(o.w, CSI+ExitAltScreenSeq) //nolint:errcheck
}
// ClearScreen clears the visible portion of the terminal.
func (o Output) ClearScreen() {
- fmt.Fprintf(o.tty, CSI+EraseDisplaySeq, 2)
+ fmt.Fprintf(o.w, CSI+EraseDisplaySeq, 2) //nolint:errcheck,mnd
o.MoveCursor(1, 1)
}
// MoveCursor moves the cursor to a given position.
func (o Output) MoveCursor(row int, column int) {
- fmt.Fprintf(o.tty, CSI+CursorPositionSeq, row, column)
+ fmt.Fprintf(o.w, CSI+CursorPositionSeq, row, column) //nolint:errcheck
}
// HideCursor hides the cursor.
func (o Output) HideCursor() {
- fmt.Fprint(o.tty, CSI+HideCursorSeq)
+ fmt.Fprint(o.w, CSI+HideCursorSeq) //nolint:errcheck
}
// ShowCursor shows the cursor.
func (o Output) ShowCursor() {
- fmt.Fprint(o.tty, CSI+ShowCursorSeq)
+ fmt.Fprint(o.w, CSI+ShowCursorSeq) //nolint:errcheck
}
// SaveCursorPosition saves the cursor position.
func (o Output) SaveCursorPosition() {
- fmt.Fprint(o.tty, CSI+SaveCursorPositionSeq)
+ fmt.Fprint(o.w, CSI+SaveCursorPositionSeq) //nolint:errcheck
}
// RestoreCursorPosition restores a saved cursor position.
func (o Output) RestoreCursorPosition() {
- fmt.Fprint(o.tty, CSI+RestoreCursorPositionSeq)
+ fmt.Fprint(o.w, CSI+RestoreCursorPositionSeq) //nolint:errcheck
}
// CursorUp moves the cursor up a given number of lines.
func (o Output) CursorUp(n int) {
- fmt.Fprintf(o.tty, CSI+CursorUpSeq, n)
+ fmt.Fprintf(o.w, CSI+CursorUpSeq, n) //nolint:errcheck
}
// CursorDown moves the cursor down a given number of lines.
func (o Output) CursorDown(n int) {
- fmt.Fprintf(o.tty, CSI+CursorDownSeq, n)
+ fmt.Fprintf(o.w, CSI+CursorDownSeq, n) //nolint:errcheck
}
// CursorForward moves the cursor up a given number of lines.
func (o Output) CursorForward(n int) {
- fmt.Fprintf(o.tty, CSI+CursorForwardSeq, n)
+ fmt.Fprintf(o.w, CSI+CursorForwardSeq, n) //nolint:errcheck
}
// CursorBack moves the cursor backwards a given number of cells.
func (o Output) CursorBack(n int) {
- fmt.Fprintf(o.tty, CSI+CursorBackSeq, n)
+ fmt.Fprintf(o.w, CSI+CursorBackSeq, n) //nolint:errcheck
}
// CursorNextLine moves the cursor down a given number of lines and places it at
// the beginning of the line.
func (o Output) CursorNextLine(n int) {
- fmt.Fprintf(o.tty, CSI+CursorNextLineSeq, n)
+ fmt.Fprintf(o.w, CSI+CursorNextLineSeq, n) //nolint:errcheck
}
// CursorPrevLine moves the cursor up a given number of lines and places it at
// the beginning of the line.
func (o Output) CursorPrevLine(n int) {
- fmt.Fprintf(o.tty, CSI+CursorPreviousLineSeq, n)
+ fmt.Fprintf(o.w, CSI+CursorPreviousLineSeq, n) //nolint:errcheck
}
// ClearLine clears the current line.
func (o Output) ClearLine() {
- fmt.Fprint(o.tty, CSI+EraseEntireLineSeq)
+ fmt.Fprint(o.w, CSI+EraseEntireLineSeq) //nolint:errcheck
}
// ClearLineLeft clears the line to the left of the cursor.
func (o Output) ClearLineLeft() {
- fmt.Fprint(o.tty, CSI+EraseLineLeftSeq)
+ fmt.Fprint(o.w, CSI+EraseLineLeftSeq) //nolint:errcheck
}
// ClearLineRight clears the line to the right of the cursor.
func (o Output) ClearLineRight() {
- fmt.Fprint(o.tty, CSI+EraseLineRightSeq)
+ fmt.Fprint(o.w, CSI+EraseLineRightSeq) //nolint:errcheck
}
// ClearLines clears a given number of lines.
func (o Output) ClearLines(n int) {
- clearLine := fmt.Sprintf(CSI+EraseLineSeq, 2)
+ clearLine := fmt.Sprintf(CSI+EraseLineSeq, 2) //nolint:mnd
cursorUp := fmt.Sprintf(CSI+CursorUpSeq, 1)
- fmt.Fprint(o.tty, clearLine+strings.Repeat(cursorUp+clearLine, n))
+ fmt.Fprint(o.w, clearLine+strings.Repeat(cursorUp+clearLine, n)) //nolint:errcheck
}
// ChangeScrollingRegion sets the scrolling region of the terminal.
func (o Output) ChangeScrollingRegion(top, bottom int) {
- fmt.Fprintf(o.tty, CSI+ChangeScrollingRegionSeq, top, bottom)
+ fmt.Fprintf(o.w, CSI+ChangeScrollingRegionSeq, top, bottom) //nolint:errcheck
}
// InsertLines inserts the given number of lines at the top of the scrollable
// region, pushing lines below down.
func (o Output) InsertLines(n int) {
- fmt.Fprintf(o.tty, CSI+InsertLineSeq, n)
+ fmt.Fprintf(o.w, CSI+InsertLineSeq, n) //nolint:errcheck
}
// DeleteLines deletes the given number of lines, pulling any lines in
// the scrollable region below up.
func (o Output) DeleteLines(n int) {
- fmt.Fprintf(o.tty, CSI+DeleteLineSeq, n)
+ fmt.Fprintf(o.w, CSI+DeleteLineSeq, n) //nolint:errcheck
}
// EnableMousePress enables X10 mouse mode. Button press events are sent only.
func (o Output) EnableMousePress() {
- fmt.Fprint(o.tty, CSI+EnableMousePressSeq)
+ fmt.Fprint(o.w, CSI+EnableMousePressSeq) //nolint:errcheck
}
// DisableMousePress disables X10 mouse mode.
func (o Output) DisableMousePress() {
- fmt.Fprint(o.tty, CSI+DisableMousePressSeq)
+ fmt.Fprint(o.w, CSI+DisableMousePressSeq) //nolint:errcheck
}
// EnableMouse enables Mouse Tracking mode.
func (o Output) EnableMouse() {
- fmt.Fprint(o.tty, CSI+EnableMouseSeq)
+ fmt.Fprint(o.w, CSI+EnableMouseSeq) //nolint:errcheck
}
// DisableMouse disables Mouse Tracking mode.
func (o Output) DisableMouse() {
- fmt.Fprint(o.tty, CSI+DisableMouseSeq)
+ fmt.Fprint(o.w, CSI+DisableMouseSeq) //nolint:errcheck
}
// EnableMouseHilite enables Hilite Mouse Tracking mode.
func (o Output) EnableMouseHilite() {
- fmt.Fprint(o.tty, CSI+EnableMouseHiliteSeq)
+ fmt.Fprint(o.w, CSI+EnableMouseHiliteSeq) //nolint:errcheck
}
// DisableMouseHilite disables Hilite Mouse Tracking mode.
func (o Output) DisableMouseHilite() {
- fmt.Fprint(o.tty, CSI+DisableMouseHiliteSeq)
+ fmt.Fprint(o.w, CSI+DisableMouseHiliteSeq) //nolint:errcheck
}
// EnableMouseCellMotion enables Cell Motion Mouse Tracking mode.
func (o Output) EnableMouseCellMotion() {
- fmt.Fprint(o.tty, CSI+EnableMouseCellMotionSeq)
+ fmt.Fprint(o.w, CSI+EnableMouseCellMotionSeq) //nolint:errcheck
}
// DisableMouseCellMotion disables Cell Motion Mouse Tracking mode.
func (o Output) DisableMouseCellMotion() {
- fmt.Fprint(o.tty, CSI+DisableMouseCellMotionSeq)
+ fmt.Fprint(o.w, CSI+DisableMouseCellMotionSeq) //nolint:errcheck
}
// EnableMouseAllMotion enables All Motion Mouse mode.
func (o Output) EnableMouseAllMotion() {
- fmt.Fprint(o.tty, CSI+EnableMouseAllMotionSeq)
+ fmt.Fprint(o.w, CSI+EnableMouseAllMotionSeq) //nolint:errcheck
}
// DisableMouseAllMotion disables All Motion Mouse mode.
func (o Output) DisableMouseAllMotion() {
- fmt.Fprint(o.tty, CSI+DisableMouseAllMotionSeq)
+ fmt.Fprint(o.w, CSI+DisableMouseAllMotionSeq) //nolint:errcheck
}
// EnableMouseExtendedMotion enables Extended Mouse mode (SGR). This should be
// enabled in conjunction with EnableMouseCellMotion, and EnableMouseAllMotion.
func (o Output) EnableMouseExtendedMode() {
- fmt.Fprint(o.tty, CSI+EnableMouseExtendedModeSeq)
+ fmt.Fprint(o.w, CSI+EnableMouseExtendedModeSeq) //nolint:errcheck
}
// DisableMouseExtendedMotion disables Extended Mouse mode (SGR).
func (o Output) DisableMouseExtendedMode() {
- fmt.Fprint(o.tty, CSI+DisableMouseExtendedModeSeq)
+ fmt.Fprint(o.w, CSI+DisableMouseExtendedModeSeq) //nolint:errcheck
}
// EnableMousePixelsMotion enables Pixel Motion Mouse mode (SGR-Pixels). This
// should be enabled in conjunction with EnableMouseCellMotion, and
// EnableMouseAllMotion.
func (o Output) EnableMousePixelsMode() {
- fmt.Fprint(o.tty, CSI+EnableMousePixelsModeSeq)
+ fmt.Fprint(o.w, CSI+EnableMousePixelsModeSeq) //nolint:errcheck
}
// DisableMousePixelsMotion disables Pixel Motion Mouse mode (SGR-Pixels).
func (o Output) DisableMousePixelsMode() {
- fmt.Fprint(o.tty, CSI+DisableMousePixelsModeSeq)
+ fmt.Fprint(o.w, CSI+DisableMousePixelsModeSeq) //nolint:errcheck
}
// SetWindowTitle sets the terminal window title.
func (o Output) SetWindowTitle(title string) {
- fmt.Fprintf(o.tty, OSC+SetWindowTitleSeq, title)
+ fmt.Fprintf(o.w, OSC+SetWindowTitleSeq, title) //nolint:errcheck
}
// EnableBracketedPaste enables bracketed paste.
func (o Output) EnableBracketedPaste() {
- fmt.Fprintf(o.tty, CSI+EnableBracketedPasteSeq)
+ fmt.Fprintf(o.w, CSI+EnableBracketedPasteSeq) //nolint:errcheck
}
// DisableBracketedPaste disables bracketed paste.
func (o Output) DisableBracketedPaste() {
- fmt.Fprintf(o.tty, CSI+DisableBracketedPasteSeq)
+ fmt.Fprintf(o.w, CSI+DisableBracketedPasteSeq) //nolint:errcheck
}
// Legacy functions.
diff --git a/vendor/github.com/muesli/termenv/style.go b/vendor/github.com/muesli/termenv/style.go
index 83b0b4d7..dedc1f9f 100644
--- a/vendor/github.com/muesli/termenv/style.go
+++ b/vendor/github.com/muesli/termenv/style.go
@@ -4,7 +4,7 @@ import (
"fmt"
"strings"
- "github.com/mattn/go-runewidth"
+ "github.com/rivo/uniseg"
)
// Sequence definitions.
@@ -122,5 +122,5 @@ func (t Style) CrossOut() Style {
// Width returns the width required to print all runes in Style.
func (t Style) Width() int {
- return runewidth.StringWidth(t.string)
+ return uniseg.StringWidth(t.string)
}
diff --git a/vendor/github.com/muesli/termenv/templatehelper.go b/vendor/github.com/muesli/termenv/templatehelper.go
index d75b0796..4c7c80f5 100644
--- a/vendor/github.com/muesli/termenv/templatehelper.go
+++ b/vendor/github.com/muesli/termenv/templatehelper.go
@@ -10,6 +10,8 @@ func (o Output) TemplateFuncs() template.FuncMap {
}
// TemplateFuncs contains a few useful template helpers.
+//
+//nolint:mnd
func TemplateFuncs(p Profile) template.FuncMap {
if p == Ascii {
return noopTemplateFuncs
diff --git a/vendor/github.com/muesli/termenv/termenv.go b/vendor/github.com/muesli/termenv/termenv.go
index 4ceb2717..d702cd55 100644
--- a/vendor/github.com/muesli/termenv/termenv.go
+++ b/vendor/github.com/muesli/termenv/termenv.go
@@ -2,6 +2,7 @@ package termenv
import (
"errors"
+ "os"
"github.com/mattn/go-isatty"
)
@@ -12,15 +13,15 @@ var (
)
const (
- // Escape character
+ // Escape character.
ESC = '\x1b'
- // Bell
+ // Bell.
BEL = '\a'
- // Control Sequence Introducer
+ // Control Sequence Introducer.
CSI = string(ESC) + "["
- // Operating System Command
+ // Operating System Command.
OSC = string(ESC) + "]"
- // String Terminator
+ // String Terminator.
ST = string(ESC) + `\`
)
@@ -31,11 +32,11 @@ func (o *Output) isTTY() bool {
if len(o.environ.Getenv("CI")) > 0 {
return false
}
- if o.TTY() == nil {
- return false
+ if f, ok := o.Writer().(*os.File); ok {
+ return isatty.IsTerminal(f.Fd())
}
- return isatty.IsTerminal(o.TTY().Fd())
+ return false
}
// ColorProfile returns the supported color profile:
diff --git a/vendor/github.com/muesli/termenv/termenv_posix.go b/vendor/github.com/muesli/termenv/termenv_posix.go
index b2109b74..c971dd99 100644
--- a/vendor/github.com/muesli/termenv/termenv_posix.go
+++ b/vendor/github.com/muesli/termenv/termenv_posix.go
@@ -1,5 +1,5 @@
-//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd
-// +build darwin dragonfly freebsd linux netbsd openbsd
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || zos
+// +build darwin dragonfly freebsd linux netbsd openbsd zos
package termenv
diff --git a/vendor/github.com/muesli/termenv/termenv_unix.go b/vendor/github.com/muesli/termenv/termenv_unix.go
index 24d519a5..bef49ca3 100644
--- a/vendor/github.com/muesli/termenv/termenv_unix.go
+++ b/vendor/github.com/muesli/termenv/termenv_unix.go
@@ -1,5 +1,5 @@
-//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris zos
package termenv
@@ -14,7 +14,7 @@ import (
)
const (
- // timeout for OSC queries
+ // timeout for OSC queries.
OSCTimeout = 5 * time.Second
)
@@ -50,9 +50,15 @@ func (o *Output) ColorProfile() Profile {
}
switch term {
- case "xterm-kitty", "wezterm":
+ case
+ "alacritty",
+ "contour",
+ "rio",
+ "wezterm",
+ "xterm-ghostty",
+ "xterm-kitty":
return TrueColor
- case "linux":
+ case "linux", "xterm":
return ANSI
}
@@ -69,6 +75,7 @@ func (o *Output) ColorProfile() Profile {
return Ascii
}
+//nolint:mnd
func (o Output) foregroundColor() Color {
s, err := o.termStatusReport(10)
if err == nil {
@@ -91,6 +98,7 @@ func (o Output) foregroundColor() Color {
return ANSIColor(7)
}
+//nolint:mnd
func (o Output) backgroundColor() Color {
s, err := o.termStatusReport(11)
if err == nil {
@@ -117,15 +125,15 @@ func (o *Output) waitForData(timeout time.Duration) error {
fd := o.TTY().Fd()
tv := unix.NsecToTimeval(int64(timeout))
var readfds unix.FdSet
- readfds.Set(int(fd))
+ readfds.Set(int(fd)) //nolint:gosec
for {
- n, err := unix.Select(int(fd)+1, &readfds, nil, nil, &tv)
+ n, err := unix.Select(int(fd)+1, &readfds, nil, nil, &tv) //nolint:gosec
if err == unix.EINTR {
continue
}
if err != nil {
- return err
+ return err //nolint:wrapcheck
}
if n == 0 {
return fmt.Errorf("timeout")
@@ -147,7 +155,7 @@ func (o *Output) readNextByte() (byte, error) {
var b [1]byte
n, err := o.TTY().Read(b[:])
if err != nil {
- return 0, err
+ return 0, err //nolint:wrapcheck
}
if n == 0 {
@@ -215,7 +223,7 @@ func (o *Output) readNextResponse() (response string, isOSC bool, err error) {
}
// both responses have less than 25 bytes, so if we read more, that's an error
- if len(response) > 25 {
+ if len(response) > 25 { //nolint:mnd
break
}
}
@@ -227,7 +235,7 @@ func (o Output) termStatusReport(sequence int) (string, error) {
// screen/tmux can't support OSC, because they can be connected to multiple
// terminals concurrently.
term := o.environ.Getenv("TERM")
- if strings.HasPrefix(term, "screen") || strings.HasPrefix(term, "tmux") {
+ if strings.HasPrefix(term, "screen") || strings.HasPrefix(term, "tmux") || strings.HasPrefix(term, "dumb") {
return "", ErrStatusReport
}
@@ -237,7 +245,7 @@ func (o Output) termStatusReport(sequence int) (string, error) {
}
if !o.unsafe {
- fd := int(tty.Fd())
+ fd := int(tty.Fd()) //nolint:gosec
// if in background, we can't control the terminal
if !isForeground(fd) {
return "", ErrStatusReport
@@ -258,10 +266,10 @@ func (o Output) termStatusReport(sequence int) (string, error) {
}
// first, send OSC query, which is ignored by terminal which do not support it
- fmt.Fprintf(tty, OSC+"%d;?"+ST, sequence)
+ fmt.Fprintf(tty, OSC+"%d;?"+ST, sequence) //nolint:errcheck
// then, query cursor position, should be supported by all terminals
- fmt.Fprintf(tty, CSI+"6n")
+ fmt.Fprintf(tty, CSI+"6n") //nolint:errcheck
// read the next response
res, isOSC, err := o.readNextResponse()
diff --git a/vendor/github.com/muesli/termenv/termenv_windows.go b/vendor/github.com/muesli/termenv/termenv_windows.go
index 1d9c6187..f9b1def0 100644
--- a/vendor/github.com/muesli/termenv/termenv_windows.go
+++ b/vendor/github.com/muesli/termenv/termenv_windows.go
@@ -5,6 +5,7 @@ package termenv
import (
"fmt"
+ "os"
"strconv"
"golang.org/x/sys/windows"
@@ -103,8 +104,8 @@ func EnableVirtualTerminalProcessing(o *Output) (restoreFunc func() error, err e
}
// If o is not a tty, then there is nothing to do.
- tty := o.TTY()
- if tty == nil {
+ tty, ok := o.Writer().(*os.File)
+ if tty == nil || !ok {
return
}
diff --git a/vendor/github.com/rivo/uniseg/BUILD.bazel b/vendor/github.com/rivo/uniseg/BUILD.bazel
index 6af05c29..b0e62ff0 100644
--- a/vendor/github.com/rivo/uniseg/BUILD.bazel
+++ b/vendor/github.com/rivo/uniseg/BUILD.bazel
@@ -4,8 +4,23 @@ go_library(
name = "go_default_library",
srcs = [
"doc.go",
+ "eastasianwidth.go",
+ "emojipresentation.go",
"grapheme.go",
+ "graphemeproperties.go",
+ "graphemerules.go",
+ "line.go",
+ "lineproperties.go",
+ "linerules.go",
"properties.go",
+ "sentence.go",
+ "sentenceproperties.go",
+ "sentencerules.go",
+ "step.go",
+ "width.go",
+ "word.go",
+ "wordproperties.go",
+ "wordrules.go",
],
importmap = "github.com/kindlyops/vbs/vendor/github.com/rivo/uniseg",
importpath = "github.com/rivo/uniseg",
diff --git a/vendor/github.com/rivo/uniseg/README.md b/vendor/github.com/rivo/uniseg/README.md
index f8da293e..a8191b81 100644
--- a/vendor/github.com/rivo/uniseg/README.md
+++ b/vendor/github.com/rivo/uniseg/README.md
@@ -1,15 +1,15 @@
# Unicode Text Segmentation for Go
-[](https://godoc.org/github.com/rivo/uniseg)
+[](https://pkg.go.dev/github.com/rivo/uniseg)
[](https://goreportcard.com/report/github.com/rivo/uniseg)
-This Go package implements Unicode Text Segmentation according to [Unicode Standard Annex #29](http://unicode.org/reports/tr29/) (Unicode version 12.0.0).
-
-At this point, only the determination of grapheme cluster boundaries is implemented.
+This Go package implements Unicode Text Segmentation according to [Unicode Standard Annex #29](https://unicode.org/reports/tr29/), Unicode Line Breaking according to [Unicode Standard Annex #14](https://unicode.org/reports/tr14/) (Unicode version 15.0.0), and monospace font string width calculation similar to [wcwidth](https://man7.org/linux/man-pages/man3/wcwidth.3.html).
## Background
-In Go, [strings are read-only slices of bytes](https://blog.golang.org/strings). They can be turned into Unicode code points using the `for` loop or by casting: `[]rune(str)`. However, multiple code points may be combined into one user-perceived character or what the Unicode specification calls "grapheme cluster". Here are some examples:
+### Grapheme Clusters
+
+In Go, [strings are read-only slices of bytes](https://go.dev/blog/strings). They can be turned into Unicode code points using the `for` loop or by casting: `[]rune(str)`. However, multiple code points may be combined into one user-perceived character or what the Unicode specification calls "grapheme cluster". Here are some examples:
|String|Bytes (UTF-8)|Code points (runes)|Grapheme clusters|
|-|-|-|-|
@@ -17,7 +17,23 @@ In Go, [strings are read-only slices of bytes](https://blog.golang.org/strings).
|🏳️🌈|14 bytes: `f0 9f 8f b3 ef b8 8f e2 80 8d f0 9f 8c 88`|4 code points: `1f3f3 fe0f 200d 1f308`|1 cluster: `[1f3f3 fe0f 200d 1f308]`|
|🇩🇪|8 bytes: `f0 9f 87 a9 f0 9f 87 aa`|2 code points: `1f1e9 1f1ea`|1 cluster: `[1f1e9 1f1ea]`|
-This package provides a tool to iterate over these grapheme clusters. This may be used to determine the number of user-perceived characters, to split strings in their intended places, or to extract individual characters which form a unit.
+This package provides tools to iterate over these grapheme clusters. This may be used to determine the number of user-perceived characters, to split strings in their intended places, or to extract individual characters which form a unit.
+
+### Word Boundaries
+
+Word boundaries are used in a number of different contexts. The most familiar ones are selection (double-click mouse selection), cursor movement ("move to next word" control-arrow keys), and the dialog option "Whole Word Search" for search and replace. They are also used in database queries, to determine whether elements are within a certain number of words of one another. Searching may also use word boundaries in determining matching items. This package provides tools to determine word boundaries within strings.
+
+### Sentence Boundaries
+
+Sentence boundaries are often used for triple-click or some other method of selecting or iterating through blocks of text that are larger than single words. They are also used to determine whether words occur within the same sentence in database queries. This package provides tools to determine sentence boundaries within strings.
+
+### Line Breaking
+
+Line breaking, also known as word wrapping, is the process of breaking a section of text into lines such that it will fit in the available width of a page, window or other display area. This package provides tools to determine where a string may or may not be broken and where it must be broken (for example after newline characters).
+
+### Monospace Width
+
+Most terminals or text displays / text editors using a monospace font (for example source code editors) use a fixed width for each character. Some characters such as emojis or characters found in Asian and other languages may take up more than one character cell. This package provides tools to determine the number of cells a string will take up when displayed in a monospace font. See [here](https://pkg.go.dev/github.com/rivo/uniseg#hdr-Monospace_Width) for more information.
## Installation
@@ -25,38 +41,97 @@ This package provides a tool to iterate over these grapheme clusters. This may b
go get github.com/rivo/uniseg
```
-## Basic Example
+## Examples
+
+### Counting Characters in a String
+
+```go
+n := uniseg.GraphemeClusterCount("🇩🇪🏳️🌈")
+fmt.Println(n)
+// 2
+```
+
+### Calculating the Monospace String Width
+
+```go
+width := uniseg.StringWidth("🇩🇪🏳️🌈!")
+fmt.Println(width)
+// 5
+```
+
+### Using the [`Graphemes`](https://pkg.go.dev/github.com/rivo/uniseg#Graphemes) Class
+
+This is the most convenient method of iterating over grapheme clusters:
+
+```go
+gr := uniseg.NewGraphemes("👍🏼!")
+for gr.Next() {
+ fmt.Printf("%x ", gr.Runes())
+}
+// [1f44d 1f3fc] [21]
+```
+
+### Using the [`Step`](https://pkg.go.dev/github.com/rivo/uniseg#Step) or [`StepString`](https://pkg.go.dev/github.com/rivo/uniseg#StepString) Function
+
+This avoids allocating a new `Graphemes` object but it requires the handling of states and boundaries:
```go
-package uniseg
+str := "🇩🇪🏳️🌈"
+state := -1
+var c string
+for len(str) > 0 {
+ c, str, _, state = uniseg.StepString(str, state)
+ fmt.Printf("%x ", []rune(c))
+}
+// [1f1e9 1f1ea] [1f3f3 fe0f 200d 1f308]
+```
-import (
- "fmt"
+### Advanced Examples
- "github.com/rivo/uniseg"
-)
+The [`Graphemes`](https://pkg.go.dev/github.com/rivo/uniseg#Graphemes) class offers the most convenient way to access all functionality of this package. But in some cases, it may be better to use the specialized functions directly. For example, if you're only interested in word segmentation, use [`FirstWord`](https://pkg.go.dev/github.com/rivo/uniseg#FirstWord) or [`FirstWordInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstWordInString):
-func main() {
- gr := uniseg.NewGraphemes("👍🏼!")
- for gr.Next() {
- fmt.Printf("%x ", gr.Runes())
- }
- // Output: [1f44d 1f3fc] [21]
+```go
+str := "Hello, world!"
+state := -1
+var c string
+for len(str) > 0 {
+ c, str, state = uniseg.FirstWordInString(str, state)
+ fmt.Printf("(%s)\n", c)
}
+// (Hello)
+// (,)
+// ( )
+// (world)
+// (!)
+```
+
+Similarly, use
+
+- [`FirstGraphemeCluster`](https://pkg.go.dev/github.com/rivo/uniseg#FirstGraphemeCluster) or [`FirstGraphemeClusterInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstGraphemeClusterInString) for grapheme cluster determination only,
+- [`FirstSentence`](https://pkg.go.dev/github.com/rivo/uniseg#FirstSentence) or [`FirstSentenceInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstSentenceInString) for sentence segmentation only, and
+- [`FirstLineSegment`](https://pkg.go.dev/github.com/rivo/uniseg#FirstLineSegment) or [`FirstLineSegmentInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstLineSegmentInString) for line breaking / word wrapping (although using [`Step`](https://pkg.go.dev/github.com/rivo/uniseg#Step) or [`StepString`](https://pkg.go.dev/github.com/rivo/uniseg#StepString) is preferred as it will observe grapheme cluster boundaries).
+
+If you're only interested in the width of characters, use [`FirstGraphemeCluster`](https://pkg.go.dev/github.com/rivo/uniseg#FirstGraphemeCluster) or [`FirstGraphemeClusterInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstGraphemeClusterInString). It is much faster than using [`Step`](https://pkg.go.dev/github.com/rivo/uniseg#Step), [`StepString`](https://pkg.go.dev/github.com/rivo/uniseg#StepString), or the [`Graphemes`](https://pkg.go.dev/github.com/rivo/uniseg#Graphemes) class because it does not include the logic for word / sentence / line boundaries.
+
+Finally, if you need to reverse a string while preserving grapheme clusters, use [`ReverseString`](https://pkg.go.dev/github.com/rivo/uniseg#ReverseString):
+
+```go
+fmt.Println(uniseg.ReverseString("🇩🇪🏳️🌈"))
+// 🏳️🌈🇩🇪
```
## Documentation
-Refer to https://godoc.org/github.com/rivo/uniseg for the package's documentation.
+Refer to https://pkg.go.dev/github.com/rivo/uniseg for the package's documentation.
## Dependencies
This package does not depend on any packages outside the standard library.
-## Your Feedback
+## Sponsor this Project
-Add your issue here on GitHub. Feel free to get in touch if you have any questions.
+[Become a Sponsor on GitHub](https://github.com/sponsors/rivo?metadata_source=uniseg_readme) to support this project!
-## Version
+## Your Feedback
-Version tags will be introduced once Golang modules are official. Consider this version 0.1.
+Add your issue here on GitHub, preferably before submitting any PR's. Feel free to get in touch if you have any questions.
\ No newline at end of file
diff --git a/vendor/github.com/rivo/uniseg/doc.go b/vendor/github.com/rivo/uniseg/doc.go
index 60c737d7..11224ae2 100644
--- a/vendor/github.com/rivo/uniseg/doc.go
+++ b/vendor/github.com/rivo/uniseg/doc.go
@@ -1,8 +1,108 @@
/*
-Package uniseg implements Unicode Text Segmentation according to Unicode
-Standard Annex #29 (http://unicode.org/reports/tr29/).
+Package uniseg implements Unicode Text Segmentation, Unicode Line Breaking, and
+string width calculation for monospace fonts. Unicode Text Segmentation conforms
+to Unicode Standard Annex #29 (https://unicode.org/reports/tr29/) and Unicode
+Line Breaking conforms to Unicode Standard Annex #14
+(https://unicode.org/reports/tr14/).
-At this point, only the determination of grapheme cluster boundaries is
-implemented.
+In short, using this package, you can split a string into grapheme clusters
+(what people would usually refer to as a "character"), into words, and into
+sentences. Or, in its simplest case, this package allows you to count the number
+of characters in a string, especially when it contains complex characters such
+as emojis, combining characters, or characters from Asian, Arabic, Hebrew, or
+other languages. Additionally, you can use it to implement line breaking (or
+"word wrapping"), that is, to determine where text can be broken over to the
+next line when the width of the line is not big enough to fit the entire text.
+Finally, you can use it to calculate the display width of a string for monospace
+fonts.
+
+# Getting Started
+
+If you just want to count the number of characters in a string, you can use
+[GraphemeClusterCount]. If you want to determine the display width of a string,
+you can use [StringWidth]. If you want to iterate over a string, you can use
+[Step], [StepString], or the [Graphemes] class (more convenient but less
+performant). This will provide you with all information: grapheme clusters,
+word boundaries, sentence boundaries, line breaks, and monospace character
+widths. The specialized functions [FirstGraphemeCluster],
+[FirstGraphemeClusterInString], [FirstWord], [FirstWordInString],
+[FirstSentence], and [FirstSentenceInString] can be used if only one type of
+information is needed.
+
+# Grapheme Clusters
+
+Consider the rainbow flag emoji: 🏳️🌈. On most modern systems, it appears as one
+character. But its string representation actually has 14 bytes, so counting
+bytes (or using len("🏳️🌈")) will not work as expected. Counting runes won't,
+either: The flag has 4 Unicode code points, thus 4 runes. The stdlib function
+utf8.RuneCountInString("🏳️🌈") and len([]rune("🏳️🌈")) will both return 4.
+
+The [GraphemeClusterCount] function will return 1 for the rainbow flag emoji.
+The Graphemes class and a variety of functions in this package will allow you to
+split strings into its grapheme clusters.
+
+# Word Boundaries
+
+Word boundaries are used in a number of different contexts. The most familiar
+ones are selection (double-click mouse selection), cursor movement ("move to
+next word" control-arrow keys), and the dialog option "Whole Word Search" for
+search and replace. This package provides methods for determining word
+boundaries.
+
+# Sentence Boundaries
+
+Sentence boundaries are often used for triple-click or some other method of
+selecting or iterating through blocks of text that are larger than single words.
+They are also used to determine whether words occur within the same sentence in
+database queries. This package provides methods for determining sentence
+boundaries.
+
+# Line Breaking
+
+Line breaking, also known as word wrapping, is the process of breaking a section
+of text into lines such that it will fit in the available width of a page,
+window or other display area. This package provides methods to determine the
+positions in a string where a line must be broken, may be broken, or must not be
+broken.
+
+# Monospace Width
+
+Monospace width, as referred to in this package, is the width of a string in a
+monospace font. This is commonly used in terminal user interfaces or text
+displays or editors that don't support proportional fonts. A width of 1
+corresponds to a single character cell. The C function [wcswidth()] and its
+implementation in other programming languages is in widespread use for the same
+purpose. However, there is no standard for the calculation of such widths, and
+this package differs from wcswidth() in a number of ways, presumably to generate
+more visually pleasing results.
+
+To start, we assume that every code point has a width of 1, with the following
+exceptions:
+
+ - Code points with grapheme cluster break properties Control, CR, LF, Extend,
+ and ZWJ have a width of 0.
+ - U+2E3A, Two-Em Dash, has a width of 3.
+ - U+2E3B, Three-Em Dash, has a width of 4.
+ - Characters with the East-Asian Width properties "Fullwidth" (F) and "Wide"
+ (W) have a width of 2. (Properties "Ambiguous" (A) and "Neutral" (N) both
+ have a width of 1.)
+ - Code points with grapheme cluster break property Regional Indicator have a
+ width of 2.
+ - Code points with grapheme cluster break property Extended Pictographic have
+ a width of 2, unless their Emoji Presentation flag is "No", in which case
+ the width is 1.
+
+For Hangul grapheme clusters composed of conjoining Jamo and for Regional
+Indicators (flags), all code points except the first one have a width of 0. For
+grapheme clusters starting with an Extended Pictographic, any additional code
+point will force a total width of 2, except if the Variation Selector-15
+(U+FE0E) is included, in which case the total width is always 1. Grapheme
+clusters ending with Variation Selector-16 (U+FE0F) have a width of 2.
+
+Note that whether these widths appear correct depends on your application's
+render engine, to which extent it conforms to the Unicode Standard, and its
+choice of font.
+
+[wcswidth()]: https://man7.org/linux/man-pages/man3/wcswidth.3.html
*/
package uniseg
diff --git a/vendor/github.com/rivo/uniseg/eastasianwidth.go b/vendor/github.com/rivo/uniseg/eastasianwidth.go
new file mode 100644
index 00000000..5fc54d99
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/eastasianwidth.go
@@ -0,0 +1,2588 @@
+// Code generated via go generate from gen_properties.go. DO NOT EDIT.
+
+package uniseg
+
+// eastAsianWidth are taken from
+// https://www.unicode.org/Public/15.0.0/ucd/EastAsianWidth.txt
+// and
+// https://unicode.org/Public/15.0.0/ucd/emoji/emoji-data.txt
+// ("Extended_Pictographic" only)
+// on September 5, 2023. See https://www.unicode.org/license.html for the Unicode
+// license agreement.
+var eastAsianWidth = [][3]int{
+ {0x0000, 0x001F, prN}, // Cc [32] ..
+ {0x0020, 0x0020, prNa}, // Zs SPACE
+ {0x0021, 0x0023, prNa}, // Po [3] EXCLAMATION MARK..NUMBER SIGN
+ {0x0024, 0x0024, prNa}, // Sc DOLLAR SIGN
+ {0x0025, 0x0027, prNa}, // Po [3] PERCENT SIGN..APOSTROPHE
+ {0x0028, 0x0028, prNa}, // Ps LEFT PARENTHESIS
+ {0x0029, 0x0029, prNa}, // Pe RIGHT PARENTHESIS
+ {0x002A, 0x002A, prNa}, // Po ASTERISK
+ {0x002B, 0x002B, prNa}, // Sm PLUS SIGN
+ {0x002C, 0x002C, prNa}, // Po COMMA
+ {0x002D, 0x002D, prNa}, // Pd HYPHEN-MINUS
+ {0x002E, 0x002F, prNa}, // Po [2] FULL STOP..SOLIDUS
+ {0x0030, 0x0039, prNa}, // Nd [10] DIGIT ZERO..DIGIT NINE
+ {0x003A, 0x003B, prNa}, // Po [2] COLON..SEMICOLON
+ {0x003C, 0x003E, prNa}, // Sm [3] LESS-THAN SIGN..GREATER-THAN SIGN
+ {0x003F, 0x0040, prNa}, // Po [2] QUESTION MARK..COMMERCIAL AT
+ {0x0041, 0x005A, prNa}, // Lu [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+ {0x005B, 0x005B, prNa}, // Ps LEFT SQUARE BRACKET
+ {0x005C, 0x005C, prNa}, // Po REVERSE SOLIDUS
+ {0x005D, 0x005D, prNa}, // Pe RIGHT SQUARE BRACKET
+ {0x005E, 0x005E, prNa}, // Sk CIRCUMFLEX ACCENT
+ {0x005F, 0x005F, prNa}, // Pc LOW LINE
+ {0x0060, 0x0060, prNa}, // Sk GRAVE ACCENT
+ {0x0061, 0x007A, prNa}, // Ll [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+ {0x007B, 0x007B, prNa}, // Ps LEFT CURLY BRACKET
+ {0x007C, 0x007C, prNa}, // Sm VERTICAL LINE
+ {0x007D, 0x007D, prNa}, // Pe RIGHT CURLY BRACKET
+ {0x007E, 0x007E, prNa}, // Sm TILDE
+ {0x007F, 0x007F, prN}, // Cc
+ {0x0080, 0x009F, prN}, // Cc [32] ..
+ {0x00A0, 0x00A0, prN}, // Zs NO-BREAK SPACE
+ {0x00A1, 0x00A1, prA}, // Po INVERTED EXCLAMATION MARK
+ {0x00A2, 0x00A3, prNa}, // Sc [2] CENT SIGN..POUND SIGN
+ {0x00A4, 0x00A4, prA}, // Sc CURRENCY SIGN
+ {0x00A5, 0x00A5, prNa}, // Sc YEN SIGN
+ {0x00A6, 0x00A6, prNa}, // So BROKEN BAR
+ {0x00A7, 0x00A7, prA}, // Po SECTION SIGN
+ {0x00A8, 0x00A8, prA}, // Sk DIAERESIS
+ {0x00A9, 0x00A9, prN}, // So COPYRIGHT SIGN
+ {0x00AA, 0x00AA, prA}, // Lo FEMININE ORDINAL INDICATOR
+ {0x00AB, 0x00AB, prN}, // Pi LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ {0x00AC, 0x00AC, prNa}, // Sm NOT SIGN
+ {0x00AD, 0x00AD, prA}, // Cf SOFT HYPHEN
+ {0x00AE, 0x00AE, prA}, // So REGISTERED SIGN
+ {0x00AF, 0x00AF, prNa}, // Sk MACRON
+ {0x00B0, 0x00B0, prA}, // So DEGREE SIGN
+ {0x00B1, 0x00B1, prA}, // Sm PLUS-MINUS SIGN
+ {0x00B2, 0x00B3, prA}, // No [2] SUPERSCRIPT TWO..SUPERSCRIPT THREE
+ {0x00B4, 0x00B4, prA}, // Sk ACUTE ACCENT
+ {0x00B5, 0x00B5, prN}, // Ll MICRO SIGN
+ {0x00B6, 0x00B7, prA}, // Po [2] PILCROW SIGN..MIDDLE DOT
+ {0x00B8, 0x00B8, prA}, // Sk CEDILLA
+ {0x00B9, 0x00B9, prA}, // No SUPERSCRIPT ONE
+ {0x00BA, 0x00BA, prA}, // Lo MASCULINE ORDINAL INDICATOR
+ {0x00BB, 0x00BB, prN}, // Pf RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ {0x00BC, 0x00BE, prA}, // No [3] VULGAR FRACTION ONE QUARTER..VULGAR FRACTION THREE QUARTERS
+ {0x00BF, 0x00BF, prA}, // Po INVERTED QUESTION MARK
+ {0x00C0, 0x00C5, prN}, // Lu [6] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER A WITH RING ABOVE
+ {0x00C6, 0x00C6, prA}, // Lu LATIN CAPITAL LETTER AE
+ {0x00C7, 0x00CF, prN}, // Lu [9] LATIN CAPITAL LETTER C WITH CEDILLA..LATIN CAPITAL LETTER I WITH DIAERESIS
+ {0x00D0, 0x00D0, prA}, // Lu LATIN CAPITAL LETTER ETH
+ {0x00D1, 0x00D6, prN}, // Lu [6] LATIN CAPITAL LETTER N WITH TILDE..LATIN CAPITAL LETTER O WITH DIAERESIS
+ {0x00D7, 0x00D7, prA}, // Sm MULTIPLICATION SIGN
+ {0x00D8, 0x00D8, prA}, // Lu LATIN CAPITAL LETTER O WITH STROKE
+ {0x00D9, 0x00DD, prN}, // Lu [5] LATIN CAPITAL LETTER U WITH GRAVE..LATIN CAPITAL LETTER Y WITH ACUTE
+ {0x00DE, 0x00E1, prA}, // L& [4] LATIN CAPITAL LETTER THORN..LATIN SMALL LETTER A WITH ACUTE
+ {0x00E2, 0x00E5, prN}, // Ll [4] LATIN SMALL LETTER A WITH CIRCUMFLEX..LATIN SMALL LETTER A WITH RING ABOVE
+ {0x00E6, 0x00E6, prA}, // Ll LATIN SMALL LETTER AE
+ {0x00E7, 0x00E7, prN}, // Ll LATIN SMALL LETTER C WITH CEDILLA
+ {0x00E8, 0x00EA, prA}, // Ll [3] LATIN SMALL LETTER E WITH GRAVE..LATIN SMALL LETTER E WITH CIRCUMFLEX
+ {0x00EB, 0x00EB, prN}, // Ll LATIN SMALL LETTER E WITH DIAERESIS
+ {0x00EC, 0x00ED, prA}, // Ll [2] LATIN SMALL LETTER I WITH GRAVE..LATIN SMALL LETTER I WITH ACUTE
+ {0x00EE, 0x00EF, prN}, // Ll [2] LATIN SMALL LETTER I WITH CIRCUMFLEX..LATIN SMALL LETTER I WITH DIAERESIS
+ {0x00F0, 0x00F0, prA}, // Ll LATIN SMALL LETTER ETH
+ {0x00F1, 0x00F1, prN}, // Ll LATIN SMALL LETTER N WITH TILDE
+ {0x00F2, 0x00F3, prA}, // Ll [2] LATIN SMALL LETTER O WITH GRAVE..LATIN SMALL LETTER O WITH ACUTE
+ {0x00F4, 0x00F6, prN}, // Ll [3] LATIN SMALL LETTER O WITH CIRCUMFLEX..LATIN SMALL LETTER O WITH DIAERESIS
+ {0x00F7, 0x00F7, prA}, // Sm DIVISION SIGN
+ {0x00F8, 0x00FA, prA}, // Ll [3] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER U WITH ACUTE
+ {0x00FB, 0x00FB, prN}, // Ll LATIN SMALL LETTER U WITH CIRCUMFLEX
+ {0x00FC, 0x00FC, prA}, // Ll LATIN SMALL LETTER U WITH DIAERESIS
+ {0x00FD, 0x00FD, prN}, // Ll LATIN SMALL LETTER Y WITH ACUTE
+ {0x00FE, 0x00FE, prA}, // Ll LATIN SMALL LETTER THORN
+ {0x00FF, 0x00FF, prN}, // Ll LATIN SMALL LETTER Y WITH DIAERESIS
+ {0x0100, 0x0100, prN}, // Lu LATIN CAPITAL LETTER A WITH MACRON
+ {0x0101, 0x0101, prA}, // Ll LATIN SMALL LETTER A WITH MACRON
+ {0x0102, 0x0110, prN}, // L& [15] LATIN CAPITAL LETTER A WITH BREVE..LATIN CAPITAL LETTER D WITH STROKE
+ {0x0111, 0x0111, prA}, // Ll LATIN SMALL LETTER D WITH STROKE
+ {0x0112, 0x0112, prN}, // Lu LATIN CAPITAL LETTER E WITH MACRON
+ {0x0113, 0x0113, prA}, // Ll LATIN SMALL LETTER E WITH MACRON
+ {0x0114, 0x011A, prN}, // L& [7] LATIN CAPITAL LETTER E WITH BREVE..LATIN CAPITAL LETTER E WITH CARON
+ {0x011B, 0x011B, prA}, // Ll LATIN SMALL LETTER E WITH CARON
+ {0x011C, 0x0125, prN}, // L& [10] LATIN CAPITAL LETTER G WITH CIRCUMFLEX..LATIN SMALL LETTER H WITH CIRCUMFLEX
+ {0x0126, 0x0127, prA}, // L& [2] LATIN CAPITAL LETTER H WITH STROKE..LATIN SMALL LETTER H WITH STROKE
+ {0x0128, 0x012A, prN}, // L& [3] LATIN CAPITAL LETTER I WITH TILDE..LATIN CAPITAL LETTER I WITH MACRON
+ {0x012B, 0x012B, prA}, // Ll LATIN SMALL LETTER I WITH MACRON
+ {0x012C, 0x0130, prN}, // L& [5] LATIN CAPITAL LETTER I WITH BREVE..LATIN CAPITAL LETTER I WITH DOT ABOVE
+ {0x0131, 0x0133, prA}, // L& [3] LATIN SMALL LETTER DOTLESS I..LATIN SMALL LIGATURE IJ
+ {0x0134, 0x0137, prN}, // L& [4] LATIN CAPITAL LETTER J WITH CIRCUMFLEX..LATIN SMALL LETTER K WITH CEDILLA
+ {0x0138, 0x0138, prA}, // Ll LATIN SMALL LETTER KRA
+ {0x0139, 0x013E, prN}, // L& [6] LATIN CAPITAL LETTER L WITH ACUTE..LATIN SMALL LETTER L WITH CARON
+ {0x013F, 0x0142, prA}, // L& [4] LATIN CAPITAL LETTER L WITH MIDDLE DOT..LATIN SMALL LETTER L WITH STROKE
+ {0x0143, 0x0143, prN}, // Lu LATIN CAPITAL LETTER N WITH ACUTE
+ {0x0144, 0x0144, prA}, // Ll LATIN SMALL LETTER N WITH ACUTE
+ {0x0145, 0x0147, prN}, // L& [3] LATIN CAPITAL LETTER N WITH CEDILLA..LATIN CAPITAL LETTER N WITH CARON
+ {0x0148, 0x014B, prA}, // L& [4] LATIN SMALL LETTER N WITH CARON..LATIN SMALL LETTER ENG
+ {0x014C, 0x014C, prN}, // Lu LATIN CAPITAL LETTER O WITH MACRON
+ {0x014D, 0x014D, prA}, // Ll LATIN SMALL LETTER O WITH MACRON
+ {0x014E, 0x0151, prN}, // L& [4] LATIN CAPITAL LETTER O WITH BREVE..LATIN SMALL LETTER O WITH DOUBLE ACUTE
+ {0x0152, 0x0153, prA}, // L& [2] LATIN CAPITAL LIGATURE OE..LATIN SMALL LIGATURE OE
+ {0x0154, 0x0165, prN}, // L& [18] LATIN CAPITAL LETTER R WITH ACUTE..LATIN SMALL LETTER T WITH CARON
+ {0x0166, 0x0167, prA}, // L& [2] LATIN CAPITAL LETTER T WITH STROKE..LATIN SMALL LETTER T WITH STROKE
+ {0x0168, 0x016A, prN}, // L& [3] LATIN CAPITAL LETTER U WITH TILDE..LATIN CAPITAL LETTER U WITH MACRON
+ {0x016B, 0x016B, prA}, // Ll LATIN SMALL LETTER U WITH MACRON
+ {0x016C, 0x017F, prN}, // L& [20] LATIN CAPITAL LETTER U WITH BREVE..LATIN SMALL LETTER LONG S
+ {0x0180, 0x01BA, prN}, // L& [59] LATIN SMALL LETTER B WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL
+ {0x01BB, 0x01BB, prN}, // Lo LATIN LETTER TWO WITH STROKE
+ {0x01BC, 0x01BF, prN}, // L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN
+ {0x01C0, 0x01C3, prN}, // Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK
+ {0x01C4, 0x01CD, prN}, // L& [10] LATIN CAPITAL LETTER DZ WITH CARON..LATIN CAPITAL LETTER A WITH CARON
+ {0x01CE, 0x01CE, prA}, // Ll LATIN SMALL LETTER A WITH CARON
+ {0x01CF, 0x01CF, prN}, // Lu LATIN CAPITAL LETTER I WITH CARON
+ {0x01D0, 0x01D0, prA}, // Ll LATIN SMALL LETTER I WITH CARON
+ {0x01D1, 0x01D1, prN}, // Lu LATIN CAPITAL LETTER O WITH CARON
+ {0x01D2, 0x01D2, prA}, // Ll LATIN SMALL LETTER O WITH CARON
+ {0x01D3, 0x01D3, prN}, // Lu LATIN CAPITAL LETTER U WITH CARON
+ {0x01D4, 0x01D4, prA}, // Ll LATIN SMALL LETTER U WITH CARON
+ {0x01D5, 0x01D5, prN}, // Lu LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON
+ {0x01D6, 0x01D6, prA}, // Ll LATIN SMALL LETTER U WITH DIAERESIS AND MACRON
+ {0x01D7, 0x01D7, prN}, // Lu LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE
+ {0x01D8, 0x01D8, prA}, // Ll LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE
+ {0x01D9, 0x01D9, prN}, // Lu LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON
+ {0x01DA, 0x01DA, prA}, // Ll LATIN SMALL LETTER U WITH DIAERESIS AND CARON
+ {0x01DB, 0x01DB, prN}, // Lu LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE
+ {0x01DC, 0x01DC, prA}, // Ll LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE
+ {0x01DD, 0x024F, prN}, // L& [115] LATIN SMALL LETTER TURNED E..LATIN SMALL LETTER Y WITH STROKE
+ {0x0250, 0x0250, prN}, // Ll LATIN SMALL LETTER TURNED A
+ {0x0251, 0x0251, prA}, // Ll LATIN SMALL LETTER ALPHA
+ {0x0252, 0x0260, prN}, // Ll [15] LATIN SMALL LETTER TURNED ALPHA..LATIN SMALL LETTER G WITH HOOK
+ {0x0261, 0x0261, prA}, // Ll LATIN SMALL LETTER SCRIPT G
+ {0x0262, 0x0293, prN}, // Ll [50] LATIN LETTER SMALL CAPITAL G..LATIN SMALL LETTER EZH WITH CURL
+ {0x0294, 0x0294, prN}, // Lo LATIN LETTER GLOTTAL STOP
+ {0x0295, 0x02AF, prN}, // Ll [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+ {0x02B0, 0x02C1, prN}, // Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP
+ {0x02C2, 0x02C3, prN}, // Sk [2] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER RIGHT ARROWHEAD
+ {0x02C4, 0x02C4, prA}, // Sk MODIFIER LETTER UP ARROWHEAD
+ {0x02C5, 0x02C5, prN}, // Sk MODIFIER LETTER DOWN ARROWHEAD
+ {0x02C6, 0x02C6, prN}, // Lm MODIFIER LETTER CIRCUMFLEX ACCENT
+ {0x02C7, 0x02C7, prA}, // Lm CARON
+ {0x02C8, 0x02C8, prN}, // Lm MODIFIER LETTER VERTICAL LINE
+ {0x02C9, 0x02CB, prA}, // Lm [3] MODIFIER LETTER MACRON..MODIFIER LETTER GRAVE ACCENT
+ {0x02CC, 0x02CC, prN}, // Lm MODIFIER LETTER LOW VERTICAL LINE
+ {0x02CD, 0x02CD, prA}, // Lm MODIFIER LETTER LOW MACRON
+ {0x02CE, 0x02CF, prN}, // Lm [2] MODIFIER LETTER LOW GRAVE ACCENT..MODIFIER LETTER LOW ACUTE ACCENT
+ {0x02D0, 0x02D0, prA}, // Lm MODIFIER LETTER TRIANGULAR COLON
+ {0x02D1, 0x02D1, prN}, // Lm MODIFIER LETTER HALF TRIANGULAR COLON
+ {0x02D2, 0x02D7, prN}, // Sk [6] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER MINUS SIGN
+ {0x02D8, 0x02DB, prA}, // Sk [4] BREVE..OGONEK
+ {0x02DC, 0x02DC, prN}, // Sk SMALL TILDE
+ {0x02DD, 0x02DD, prA}, // Sk DOUBLE ACUTE ACCENT
+ {0x02DE, 0x02DE, prN}, // Sk MODIFIER LETTER RHOTIC HOOK
+ {0x02DF, 0x02DF, prA}, // Sk MODIFIER LETTER CROSS ACCENT
+ {0x02E0, 0x02E4, prN}, // Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP
+ {0x02E5, 0x02EB, prN}, // Sk [7] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER YANG DEPARTING TONE MARK
+ {0x02EC, 0x02EC, prN}, // Lm MODIFIER LETTER VOICING
+ {0x02ED, 0x02ED, prN}, // Sk MODIFIER LETTER UNASPIRATED
+ {0x02EE, 0x02EE, prN}, // Lm MODIFIER LETTER DOUBLE APOSTROPHE
+ {0x02EF, 0x02FF, prN}, // Sk [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW
+ {0x0300, 0x036F, prA}, // Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X
+ {0x0370, 0x0373, prN}, // L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI
+ {0x0374, 0x0374, prN}, // Lm GREEK NUMERAL SIGN
+ {0x0375, 0x0375, prN}, // Sk GREEK LOWER NUMERAL SIGN
+ {0x0376, 0x0377, prN}, // L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+ {0x037A, 0x037A, prN}, // Lm GREEK YPOGEGRAMMENI
+ {0x037B, 0x037D, prN}, // Ll [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+ {0x037E, 0x037E, prN}, // Po GREEK QUESTION MARK
+ {0x037F, 0x037F, prN}, // Lu GREEK CAPITAL LETTER YOT
+ {0x0384, 0x0385, prN}, // Sk [2] GREEK TONOS..GREEK DIALYTIKA TONOS
+ {0x0386, 0x0386, prN}, // Lu GREEK CAPITAL LETTER ALPHA WITH TONOS
+ {0x0387, 0x0387, prN}, // Po GREEK ANO TELEIA
+ {0x0388, 0x038A, prN}, // Lu [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+ {0x038C, 0x038C, prN}, // Lu GREEK CAPITAL LETTER OMICRON WITH TONOS
+ {0x038E, 0x0390, prN}, // L& [3] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+ {0x0391, 0x03A1, prA}, // Lu [17] GREEK CAPITAL LETTER ALPHA..GREEK CAPITAL LETTER RHO
+ {0x03A3, 0x03A9, prA}, // Lu [7] GREEK CAPITAL LETTER SIGMA..GREEK CAPITAL LETTER OMEGA
+ {0x03AA, 0x03B0, prN}, // L& [7] GREEK CAPITAL LETTER IOTA WITH DIALYTIKA..GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+ {0x03B1, 0x03C1, prA}, // Ll [17] GREEK SMALL LETTER ALPHA..GREEK SMALL LETTER RHO
+ {0x03C2, 0x03C2, prN}, // Ll GREEK SMALL LETTER FINAL SIGMA
+ {0x03C3, 0x03C9, prA}, // Ll [7] GREEK SMALL LETTER SIGMA..GREEK SMALL LETTER OMEGA
+ {0x03CA, 0x03F5, prN}, // L& [44] GREEK SMALL LETTER IOTA WITH DIALYTIKA..GREEK LUNATE EPSILON SYMBOL
+ {0x03F6, 0x03F6, prN}, // Sm GREEK REVERSED LUNATE EPSILON SYMBOL
+ {0x03F7, 0x03FF, prN}, // L& [9] GREEK CAPITAL LETTER SHO..GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL
+ {0x0400, 0x0400, prN}, // Lu CYRILLIC CAPITAL LETTER IE WITH GRAVE
+ {0x0401, 0x0401, prA}, // Lu CYRILLIC CAPITAL LETTER IO
+ {0x0402, 0x040F, prN}, // Lu [14] CYRILLIC CAPITAL LETTER DJE..CYRILLIC CAPITAL LETTER DZHE
+ {0x0410, 0x044F, prA}, // L& [64] CYRILLIC CAPITAL LETTER A..CYRILLIC SMALL LETTER YA
+ {0x0450, 0x0450, prN}, // Ll CYRILLIC SMALL LETTER IE WITH GRAVE
+ {0x0451, 0x0451, prA}, // Ll CYRILLIC SMALL LETTER IO
+ {0x0452, 0x0481, prN}, // L& [48] CYRILLIC SMALL LETTER DJE..CYRILLIC SMALL LETTER KOPPA
+ {0x0482, 0x0482, prN}, // So CYRILLIC THOUSANDS SIGN
+ {0x0483, 0x0487, prN}, // Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE
+ {0x0488, 0x0489, prN}, // Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN
+ {0x048A, 0x04FF, prN}, // L& [118] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER HA WITH STROKE
+ {0x0500, 0x052F, prN}, // L& [48] CYRILLIC CAPITAL LETTER KOMI DE..CYRILLIC SMALL LETTER EL WITH DESCENDER
+ {0x0531, 0x0556, prN}, // Lu [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+ {0x0559, 0x0559, prN}, // Lm ARMENIAN MODIFIER LETTER LEFT HALF RING
+ {0x055A, 0x055F, prN}, // Po [6] ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK
+ {0x0560, 0x0588, prN}, // Ll [41] ARMENIAN SMALL LETTER TURNED AYB..ARMENIAN SMALL LETTER YI WITH STROKE
+ {0x0589, 0x0589, prN}, // Po ARMENIAN FULL STOP
+ {0x058A, 0x058A, prN}, // Pd ARMENIAN HYPHEN
+ {0x058D, 0x058E, prN}, // So [2] RIGHT-FACING ARMENIAN ETERNITY SIGN..LEFT-FACING ARMENIAN ETERNITY SIGN
+ {0x058F, 0x058F, prN}, // Sc ARMENIAN DRAM SIGN
+ {0x0591, 0x05BD, prN}, // Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG
+ {0x05BE, 0x05BE, prN}, // Pd HEBREW PUNCTUATION MAQAF
+ {0x05BF, 0x05BF, prN}, // Mn HEBREW POINT RAFE
+ {0x05C0, 0x05C0, prN}, // Po HEBREW PUNCTUATION PASEQ
+ {0x05C1, 0x05C2, prN}, // Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT
+ {0x05C3, 0x05C3, prN}, // Po HEBREW PUNCTUATION SOF PASUQ
+ {0x05C4, 0x05C5, prN}, // Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT
+ {0x05C6, 0x05C6, prN}, // Po HEBREW PUNCTUATION NUN HAFUKHA
+ {0x05C7, 0x05C7, prN}, // Mn HEBREW POINT QAMATS QATAN
+ {0x05D0, 0x05EA, prN}, // Lo [27] HEBREW LETTER ALEF..HEBREW LETTER TAV
+ {0x05EF, 0x05F2, prN}, // Lo [4] HEBREW YOD TRIANGLE..HEBREW LIGATURE YIDDISH DOUBLE YOD
+ {0x05F3, 0x05F4, prN}, // Po [2] HEBREW PUNCTUATION GERESH..HEBREW PUNCTUATION GERSHAYIM
+ {0x0600, 0x0605, prN}, // Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE
+ {0x0606, 0x0608, prN}, // Sm [3] ARABIC-INDIC CUBE ROOT..ARABIC RAY
+ {0x0609, 0x060A, prN}, // Po [2] ARABIC-INDIC PER MILLE SIGN..ARABIC-INDIC PER TEN THOUSAND SIGN
+ {0x060B, 0x060B, prN}, // Sc AFGHANI SIGN
+ {0x060C, 0x060D, prN}, // Po [2] ARABIC COMMA..ARABIC DATE SEPARATOR
+ {0x060E, 0x060F, prN}, // So [2] ARABIC POETIC VERSE SIGN..ARABIC SIGN MISRA
+ {0x0610, 0x061A, prN}, // Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA
+ {0x061B, 0x061B, prN}, // Po ARABIC SEMICOLON
+ {0x061C, 0x061C, prN}, // Cf ARABIC LETTER MARK
+ {0x061D, 0x061F, prN}, // Po [3] ARABIC END OF TEXT MARK..ARABIC QUESTION MARK
+ {0x0620, 0x063F, prN}, // Lo [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
+ {0x0640, 0x0640, prN}, // Lm ARABIC TATWEEL
+ {0x0641, 0x064A, prN}, // Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH
+ {0x064B, 0x065F, prN}, // Mn [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW
+ {0x0660, 0x0669, prN}, // Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
+ {0x066A, 0x066D, prN}, // Po [4] ARABIC PERCENT SIGN..ARABIC FIVE POINTED STAR
+ {0x066E, 0x066F, prN}, // Lo [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF
+ {0x0670, 0x0670, prN}, // Mn ARABIC LETTER SUPERSCRIPT ALEF
+ {0x0671, 0x06D3, prN}, // Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
+ {0x06D4, 0x06D4, prN}, // Po ARABIC FULL STOP
+ {0x06D5, 0x06D5, prN}, // Lo ARABIC LETTER AE
+ {0x06D6, 0x06DC, prN}, // Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN
+ {0x06DD, 0x06DD, prN}, // Cf ARABIC END OF AYAH
+ {0x06DE, 0x06DE, prN}, // So ARABIC START OF RUB EL HIZB
+ {0x06DF, 0x06E4, prN}, // Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA
+ {0x06E5, 0x06E6, prN}, // Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH
+ {0x06E7, 0x06E8, prN}, // Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON
+ {0x06E9, 0x06E9, prN}, // So ARABIC PLACE OF SAJDAH
+ {0x06EA, 0x06ED, prN}, // Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM
+ {0x06EE, 0x06EF, prN}, // Lo [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V
+ {0x06F0, 0x06F9, prN}, // Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
+ {0x06FA, 0x06FC, prN}, // Lo [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW
+ {0x06FD, 0x06FE, prN}, // So [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN
+ {0x06FF, 0x06FF, prN}, // Lo ARABIC LETTER HEH WITH INVERTED V
+ {0x0700, 0x070D, prN}, // Po [14] SYRIAC END OF PARAGRAPH..SYRIAC HARKLEAN ASTERISCUS
+ {0x070F, 0x070F, prN}, // Cf SYRIAC ABBREVIATION MARK
+ {0x0710, 0x0710, prN}, // Lo SYRIAC LETTER ALAPH
+ {0x0711, 0x0711, prN}, // Mn SYRIAC LETTER SUPERSCRIPT ALAPH
+ {0x0712, 0x072F, prN}, // Lo [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH
+ {0x0730, 0x074A, prN}, // Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH
+ {0x074D, 0x074F, prN}, // Lo [3] SYRIAC LETTER SOGDIAN ZHAIN..SYRIAC LETTER SOGDIAN FE
+ {0x0750, 0x077F, prN}, // Lo [48] ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS ABOVE
+ {0x0780, 0x07A5, prN}, // Lo [38] THAANA LETTER HAA..THAANA LETTER WAAVU
+ {0x07A6, 0x07B0, prN}, // Mn [11] THAANA ABAFILI..THAANA SUKUN
+ {0x07B1, 0x07B1, prN}, // Lo THAANA LETTER NAA
+ {0x07C0, 0x07C9, prN}, // Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE
+ {0x07CA, 0x07EA, prN}, // Lo [33] NKO LETTER A..NKO LETTER JONA RA
+ {0x07EB, 0x07F3, prN}, // Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+ {0x07F4, 0x07F5, prN}, // Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE
+ {0x07F6, 0x07F6, prN}, // So NKO SYMBOL OO DENNEN
+ {0x07F7, 0x07F9, prN}, // Po [3] NKO SYMBOL GBAKURUNEN..NKO EXCLAMATION MARK
+ {0x07FA, 0x07FA, prN}, // Lm NKO LAJANYALAN
+ {0x07FD, 0x07FD, prN}, // Mn NKO DANTAYALAN
+ {0x07FE, 0x07FF, prN}, // Sc [2] NKO DOROME SIGN..NKO TAMAN SIGN
+ {0x0800, 0x0815, prN}, // Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF
+ {0x0816, 0x0819, prN}, // Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH
+ {0x081A, 0x081A, prN}, // Lm SAMARITAN MODIFIER LETTER EPENTHETIC YUT
+ {0x081B, 0x0823, prN}, // Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A
+ {0x0824, 0x0824, prN}, // Lm SAMARITAN MODIFIER LETTER SHORT A
+ {0x0825, 0x0827, prN}, // Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U
+ {0x0828, 0x0828, prN}, // Lm SAMARITAN MODIFIER LETTER I
+ {0x0829, 0x082D, prN}, // Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA
+ {0x0830, 0x083E, prN}, // Po [15] SAMARITAN PUNCTUATION NEQUDAA..SAMARITAN PUNCTUATION ANNAAU
+ {0x0840, 0x0858, prN}, // Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN
+ {0x0859, 0x085B, prN}, // Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK
+ {0x085E, 0x085E, prN}, // Po MANDAIC PUNCTUATION
+ {0x0860, 0x086A, prN}, // Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA
+ {0x0870, 0x0887, prN}, // Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT
+ {0x0888, 0x0888, prN}, // Sk ARABIC RAISED ROUND DOT
+ {0x0889, 0x088E, prN}, // Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL
+ {0x0890, 0x0891, prN}, // Cf [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE
+ {0x0898, 0x089F, prN}, // Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA
+ {0x08A0, 0x08C8, prN}, // Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF
+ {0x08C9, 0x08C9, prN}, // Lm ARABIC SMALL FARSI YEH
+ {0x08CA, 0x08E1, prN}, // Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA
+ {0x08E2, 0x08E2, prN}, // Cf ARABIC DISPUTED END OF AYAH
+ {0x08E3, 0x08FF, prN}, // Mn [29] ARABIC TURNED DAMMA BELOW..ARABIC MARK SIDEWAYS NOON GHUNNA
+ {0x0900, 0x0902, prN}, // Mn [3] DEVANAGARI SIGN INVERTED CANDRABINDU..DEVANAGARI SIGN ANUSVARA
+ {0x0903, 0x0903, prN}, // Mc DEVANAGARI SIGN VISARGA
+ {0x0904, 0x0939, prN}, // Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA
+ {0x093A, 0x093A, prN}, // Mn DEVANAGARI VOWEL SIGN OE
+ {0x093B, 0x093B, prN}, // Mc DEVANAGARI VOWEL SIGN OOE
+ {0x093C, 0x093C, prN}, // Mn DEVANAGARI SIGN NUKTA
+ {0x093D, 0x093D, prN}, // Lo DEVANAGARI SIGN AVAGRAHA
+ {0x093E, 0x0940, prN}, // Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II
+ {0x0941, 0x0948, prN}, // Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI
+ {0x0949, 0x094C, prN}, // Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU
+ {0x094D, 0x094D, prN}, // Mn DEVANAGARI SIGN VIRAMA
+ {0x094E, 0x094F, prN}, // Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW
+ {0x0950, 0x0950, prN}, // Lo DEVANAGARI OM
+ {0x0951, 0x0957, prN}, // Mn [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE
+ {0x0958, 0x0961, prN}, // Lo [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL
+ {0x0962, 0x0963, prN}, // Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL
+ {0x0964, 0x0965, prN}, // Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA
+ {0x0966, 0x096F, prN}, // Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
+ {0x0970, 0x0970, prN}, // Po DEVANAGARI ABBREVIATION SIGN
+ {0x0971, 0x0971, prN}, // Lm DEVANAGARI SIGN HIGH SPACING DOT
+ {0x0972, 0x097F, prN}, // Lo [14] DEVANAGARI LETTER CANDRA A..DEVANAGARI LETTER BBA
+ {0x0980, 0x0980, prN}, // Lo BENGALI ANJI
+ {0x0981, 0x0981, prN}, // Mn BENGALI SIGN CANDRABINDU
+ {0x0982, 0x0983, prN}, // Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA
+ {0x0985, 0x098C, prN}, // Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L
+ {0x098F, 0x0990, prN}, // Lo [2] BENGALI LETTER E..BENGALI LETTER AI
+ {0x0993, 0x09A8, prN}, // Lo [22] BENGALI LETTER O..BENGALI LETTER NA
+ {0x09AA, 0x09B0, prN}, // Lo [7] BENGALI LETTER PA..BENGALI LETTER RA
+ {0x09B2, 0x09B2, prN}, // Lo BENGALI LETTER LA
+ {0x09B6, 0x09B9, prN}, // Lo [4] BENGALI LETTER SHA..BENGALI LETTER HA
+ {0x09BC, 0x09BC, prN}, // Mn BENGALI SIGN NUKTA
+ {0x09BD, 0x09BD, prN}, // Lo BENGALI SIGN AVAGRAHA
+ {0x09BE, 0x09C0, prN}, // Mc [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II
+ {0x09C1, 0x09C4, prN}, // Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR
+ {0x09C7, 0x09C8, prN}, // Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI
+ {0x09CB, 0x09CC, prN}, // Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU
+ {0x09CD, 0x09CD, prN}, // Mn BENGALI SIGN VIRAMA
+ {0x09CE, 0x09CE, prN}, // Lo BENGALI LETTER KHANDA TA
+ {0x09D7, 0x09D7, prN}, // Mc BENGALI AU LENGTH MARK
+ {0x09DC, 0x09DD, prN}, // Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA
+ {0x09DF, 0x09E1, prN}, // Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL
+ {0x09E2, 0x09E3, prN}, // Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+ {0x09E6, 0x09EF, prN}, // Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
+ {0x09F0, 0x09F1, prN}, // Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL
+ {0x09F2, 0x09F3, prN}, // Sc [2] BENGALI RUPEE MARK..BENGALI RUPEE SIGN
+ {0x09F4, 0x09F9, prN}, // No [6] BENGALI CURRENCY NUMERATOR ONE..BENGALI CURRENCY DENOMINATOR SIXTEEN
+ {0x09FA, 0x09FA, prN}, // So BENGALI ISSHAR
+ {0x09FB, 0x09FB, prN}, // Sc BENGALI GANDA MARK
+ {0x09FC, 0x09FC, prN}, // Lo BENGALI LETTER VEDIC ANUSVARA
+ {0x09FD, 0x09FD, prN}, // Po BENGALI ABBREVIATION SIGN
+ {0x09FE, 0x09FE, prN}, // Mn BENGALI SANDHI MARK
+ {0x0A01, 0x0A02, prN}, // Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
+ {0x0A03, 0x0A03, prN}, // Mc GURMUKHI SIGN VISARGA
+ {0x0A05, 0x0A0A, prN}, // Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU
+ {0x0A0F, 0x0A10, prN}, // Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI
+ {0x0A13, 0x0A28, prN}, // Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA
+ {0x0A2A, 0x0A30, prN}, // Lo [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA
+ {0x0A32, 0x0A33, prN}, // Lo [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA
+ {0x0A35, 0x0A36, prN}, // Lo [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA
+ {0x0A38, 0x0A39, prN}, // Lo [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA
+ {0x0A3C, 0x0A3C, prN}, // Mn GURMUKHI SIGN NUKTA
+ {0x0A3E, 0x0A40, prN}, // Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II
+ {0x0A41, 0x0A42, prN}, // Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
+ {0x0A47, 0x0A48, prN}, // Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI
+ {0x0A4B, 0x0A4D, prN}, // Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA
+ {0x0A51, 0x0A51, prN}, // Mn GURMUKHI SIGN UDAAT
+ {0x0A59, 0x0A5C, prN}, // Lo [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA
+ {0x0A5E, 0x0A5E, prN}, // Lo GURMUKHI LETTER FA
+ {0x0A66, 0x0A6F, prN}, // Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
+ {0x0A70, 0x0A71, prN}, // Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK
+ {0x0A72, 0x0A74, prN}, // Lo [3] GURMUKHI IRI..GURMUKHI EK ONKAR
+ {0x0A75, 0x0A75, prN}, // Mn GURMUKHI SIGN YAKASH
+ {0x0A76, 0x0A76, prN}, // Po GURMUKHI ABBREVIATION SIGN
+ {0x0A81, 0x0A82, prN}, // Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA
+ {0x0A83, 0x0A83, prN}, // Mc GUJARATI SIGN VISARGA
+ {0x0A85, 0x0A8D, prN}, // Lo [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E
+ {0x0A8F, 0x0A91, prN}, // Lo [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O
+ {0x0A93, 0x0AA8, prN}, // Lo [22] GUJARATI LETTER O..GUJARATI LETTER NA
+ {0x0AAA, 0x0AB0, prN}, // Lo [7] GUJARATI LETTER PA..GUJARATI LETTER RA
+ {0x0AB2, 0x0AB3, prN}, // Lo [2] GUJARATI LETTER LA..GUJARATI LETTER LLA
+ {0x0AB5, 0x0AB9, prN}, // Lo [5] GUJARATI LETTER VA..GUJARATI LETTER HA
+ {0x0ABC, 0x0ABC, prN}, // Mn GUJARATI SIGN NUKTA
+ {0x0ABD, 0x0ABD, prN}, // Lo GUJARATI SIGN AVAGRAHA
+ {0x0ABE, 0x0AC0, prN}, // Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II
+ {0x0AC1, 0x0AC5, prN}, // Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E
+ {0x0AC7, 0x0AC8, prN}, // Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI
+ {0x0AC9, 0x0AC9, prN}, // Mc GUJARATI VOWEL SIGN CANDRA O
+ {0x0ACB, 0x0ACC, prN}, // Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU
+ {0x0ACD, 0x0ACD, prN}, // Mn GUJARATI SIGN VIRAMA
+ {0x0AD0, 0x0AD0, prN}, // Lo GUJARATI OM
+ {0x0AE0, 0x0AE1, prN}, // Lo [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL
+ {0x0AE2, 0x0AE3, prN}, // Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+ {0x0AE6, 0x0AEF, prN}, // Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
+ {0x0AF0, 0x0AF0, prN}, // Po GUJARATI ABBREVIATION SIGN
+ {0x0AF1, 0x0AF1, prN}, // Sc GUJARATI RUPEE SIGN
+ {0x0AF9, 0x0AF9, prN}, // Lo GUJARATI LETTER ZHA
+ {0x0AFA, 0x0AFF, prN}, // Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE
+ {0x0B01, 0x0B01, prN}, // Mn ORIYA SIGN CANDRABINDU
+ {0x0B02, 0x0B03, prN}, // Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA
+ {0x0B05, 0x0B0C, prN}, // Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L
+ {0x0B0F, 0x0B10, prN}, // Lo [2] ORIYA LETTER E..ORIYA LETTER AI
+ {0x0B13, 0x0B28, prN}, // Lo [22] ORIYA LETTER O..ORIYA LETTER NA
+ {0x0B2A, 0x0B30, prN}, // Lo [7] ORIYA LETTER PA..ORIYA LETTER RA
+ {0x0B32, 0x0B33, prN}, // Lo [2] ORIYA LETTER LA..ORIYA LETTER LLA
+ {0x0B35, 0x0B39, prN}, // Lo [5] ORIYA LETTER VA..ORIYA LETTER HA
+ {0x0B3C, 0x0B3C, prN}, // Mn ORIYA SIGN NUKTA
+ {0x0B3D, 0x0B3D, prN}, // Lo ORIYA SIGN AVAGRAHA
+ {0x0B3E, 0x0B3E, prN}, // Mc ORIYA VOWEL SIGN AA
+ {0x0B3F, 0x0B3F, prN}, // Mn ORIYA VOWEL SIGN I
+ {0x0B40, 0x0B40, prN}, // Mc ORIYA VOWEL SIGN II
+ {0x0B41, 0x0B44, prN}, // Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR
+ {0x0B47, 0x0B48, prN}, // Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI
+ {0x0B4B, 0x0B4C, prN}, // Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU
+ {0x0B4D, 0x0B4D, prN}, // Mn ORIYA SIGN VIRAMA
+ {0x0B55, 0x0B56, prN}, // Mn [2] ORIYA SIGN OVERLINE..ORIYA AI LENGTH MARK
+ {0x0B57, 0x0B57, prN}, // Mc ORIYA AU LENGTH MARK
+ {0x0B5C, 0x0B5D, prN}, // Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA
+ {0x0B5F, 0x0B61, prN}, // Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL
+ {0x0B62, 0x0B63, prN}, // Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL
+ {0x0B66, 0x0B6F, prN}, // Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE
+ {0x0B70, 0x0B70, prN}, // So ORIYA ISSHAR
+ {0x0B71, 0x0B71, prN}, // Lo ORIYA LETTER WA
+ {0x0B72, 0x0B77, prN}, // No [6] ORIYA FRACTION ONE QUARTER..ORIYA FRACTION THREE SIXTEENTHS
+ {0x0B82, 0x0B82, prN}, // Mn TAMIL SIGN ANUSVARA
+ {0x0B83, 0x0B83, prN}, // Lo TAMIL SIGN VISARGA
+ {0x0B85, 0x0B8A, prN}, // Lo [6] TAMIL LETTER A..TAMIL LETTER UU
+ {0x0B8E, 0x0B90, prN}, // Lo [3] TAMIL LETTER E..TAMIL LETTER AI
+ {0x0B92, 0x0B95, prN}, // Lo [4] TAMIL LETTER O..TAMIL LETTER KA
+ {0x0B99, 0x0B9A, prN}, // Lo [2] TAMIL LETTER NGA..TAMIL LETTER CA
+ {0x0B9C, 0x0B9C, prN}, // Lo TAMIL LETTER JA
+ {0x0B9E, 0x0B9F, prN}, // Lo [2] TAMIL LETTER NYA..TAMIL LETTER TTA
+ {0x0BA3, 0x0BA4, prN}, // Lo [2] TAMIL LETTER NNA..TAMIL LETTER TA
+ {0x0BA8, 0x0BAA, prN}, // Lo [3] TAMIL LETTER NA..TAMIL LETTER PA
+ {0x0BAE, 0x0BB9, prN}, // Lo [12] TAMIL LETTER MA..TAMIL LETTER HA
+ {0x0BBE, 0x0BBF, prN}, // Mc [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I
+ {0x0BC0, 0x0BC0, prN}, // Mn TAMIL VOWEL SIGN II
+ {0x0BC1, 0x0BC2, prN}, // Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU
+ {0x0BC6, 0x0BC8, prN}, // Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI
+ {0x0BCA, 0x0BCC, prN}, // Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU
+ {0x0BCD, 0x0BCD, prN}, // Mn TAMIL SIGN VIRAMA
+ {0x0BD0, 0x0BD0, prN}, // Lo TAMIL OM
+ {0x0BD7, 0x0BD7, prN}, // Mc TAMIL AU LENGTH MARK
+ {0x0BE6, 0x0BEF, prN}, // Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
+ {0x0BF0, 0x0BF2, prN}, // No [3] TAMIL NUMBER TEN..TAMIL NUMBER ONE THOUSAND
+ {0x0BF3, 0x0BF8, prN}, // So [6] TAMIL DAY SIGN..TAMIL AS ABOVE SIGN
+ {0x0BF9, 0x0BF9, prN}, // Sc TAMIL RUPEE SIGN
+ {0x0BFA, 0x0BFA, prN}, // So TAMIL NUMBER SIGN
+ {0x0C00, 0x0C00, prN}, // Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE
+ {0x0C01, 0x0C03, prN}, // Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA
+ {0x0C04, 0x0C04, prN}, // Mn TELUGU SIGN COMBINING ANUSVARA ABOVE
+ {0x0C05, 0x0C0C, prN}, // Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L
+ {0x0C0E, 0x0C10, prN}, // Lo [3] TELUGU LETTER E..TELUGU LETTER AI
+ {0x0C12, 0x0C28, prN}, // Lo [23] TELUGU LETTER O..TELUGU LETTER NA
+ {0x0C2A, 0x0C39, prN}, // Lo [16] TELUGU LETTER PA..TELUGU LETTER HA
+ {0x0C3C, 0x0C3C, prN}, // Mn TELUGU SIGN NUKTA
+ {0x0C3D, 0x0C3D, prN}, // Lo TELUGU SIGN AVAGRAHA
+ {0x0C3E, 0x0C40, prN}, // Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
+ {0x0C41, 0x0C44, prN}, // Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR
+ {0x0C46, 0x0C48, prN}, // Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
+ {0x0C4A, 0x0C4D, prN}, // Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA
+ {0x0C55, 0x0C56, prN}, // Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK
+ {0x0C58, 0x0C5A, prN}, // Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA
+ {0x0C5D, 0x0C5D, prN}, // Lo TELUGU LETTER NAKAARA POLLU
+ {0x0C60, 0x0C61, prN}, // Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL
+ {0x0C62, 0x0C63, prN}, // Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL
+ {0x0C66, 0x0C6F, prN}, // Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
+ {0x0C77, 0x0C77, prN}, // Po TELUGU SIGN SIDDHAM
+ {0x0C78, 0x0C7E, prN}, // No [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR
+ {0x0C7F, 0x0C7F, prN}, // So TELUGU SIGN TUUMU
+ {0x0C80, 0x0C80, prN}, // Lo KANNADA SIGN SPACING CANDRABINDU
+ {0x0C81, 0x0C81, prN}, // Mn KANNADA SIGN CANDRABINDU
+ {0x0C82, 0x0C83, prN}, // Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA
+ {0x0C84, 0x0C84, prN}, // Po KANNADA SIGN SIDDHAM
+ {0x0C85, 0x0C8C, prN}, // Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L
+ {0x0C8E, 0x0C90, prN}, // Lo [3] KANNADA LETTER E..KANNADA LETTER AI
+ {0x0C92, 0x0CA8, prN}, // Lo [23] KANNADA LETTER O..KANNADA LETTER NA
+ {0x0CAA, 0x0CB3, prN}, // Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA
+ {0x0CB5, 0x0CB9, prN}, // Lo [5] KANNADA LETTER VA..KANNADA LETTER HA
+ {0x0CBC, 0x0CBC, prN}, // Mn KANNADA SIGN NUKTA
+ {0x0CBD, 0x0CBD, prN}, // Lo KANNADA SIGN AVAGRAHA
+ {0x0CBE, 0x0CBE, prN}, // Mc KANNADA VOWEL SIGN AA
+ {0x0CBF, 0x0CBF, prN}, // Mn KANNADA VOWEL SIGN I
+ {0x0CC0, 0x0CC4, prN}, // Mc [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR
+ {0x0CC6, 0x0CC6, prN}, // Mn KANNADA VOWEL SIGN E
+ {0x0CC7, 0x0CC8, prN}, // Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI
+ {0x0CCA, 0x0CCB, prN}, // Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO
+ {0x0CCC, 0x0CCD, prN}, // Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA
+ {0x0CD5, 0x0CD6, prN}, // Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
+ {0x0CDD, 0x0CDE, prN}, // Lo [2] KANNADA LETTER NAKAARA POLLU..KANNADA LETTER FA
+ {0x0CE0, 0x0CE1, prN}, // Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL
+ {0x0CE2, 0x0CE3, prN}, // Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
+ {0x0CE6, 0x0CEF, prN}, // Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
+ {0x0CF1, 0x0CF2, prN}, // Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA
+ {0x0CF3, 0x0CF3, prN}, // Mc KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT
+ {0x0D00, 0x0D01, prN}, // Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU
+ {0x0D02, 0x0D03, prN}, // Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
+ {0x0D04, 0x0D0C, prN}, // Lo [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L
+ {0x0D0E, 0x0D10, prN}, // Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI
+ {0x0D12, 0x0D3A, prN}, // Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA
+ {0x0D3B, 0x0D3C, prN}, // Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA
+ {0x0D3D, 0x0D3D, prN}, // Lo MALAYALAM SIGN AVAGRAHA
+ {0x0D3E, 0x0D40, prN}, // Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II
+ {0x0D41, 0x0D44, prN}, // Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
+ {0x0D46, 0x0D48, prN}, // Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI
+ {0x0D4A, 0x0D4C, prN}, // Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU
+ {0x0D4D, 0x0D4D, prN}, // Mn MALAYALAM SIGN VIRAMA
+ {0x0D4E, 0x0D4E, prN}, // Lo MALAYALAM LETTER DOT REPH
+ {0x0D4F, 0x0D4F, prN}, // So MALAYALAM SIGN PARA
+ {0x0D54, 0x0D56, prN}, // Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL
+ {0x0D57, 0x0D57, prN}, // Mc MALAYALAM AU LENGTH MARK
+ {0x0D58, 0x0D5E, prN}, // No [7] MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH..MALAYALAM FRACTION ONE FIFTH
+ {0x0D5F, 0x0D61, prN}, // Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL
+ {0x0D62, 0x0D63, prN}, // Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL
+ {0x0D66, 0x0D6F, prN}, // Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
+ {0x0D70, 0x0D78, prN}, // No [9] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE SIXTEENTHS
+ {0x0D79, 0x0D79, prN}, // So MALAYALAM DATE MARK
+ {0x0D7A, 0x0D7F, prN}, // Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K
+ {0x0D81, 0x0D81, prN}, // Mn SINHALA SIGN CANDRABINDU
+ {0x0D82, 0x0D83, prN}, // Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA
+ {0x0D85, 0x0D96, prN}, // Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA
+ {0x0D9A, 0x0DB1, prN}, // Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA
+ {0x0DB3, 0x0DBB, prN}, // Lo [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA
+ {0x0DBD, 0x0DBD, prN}, // Lo SINHALA LETTER DANTAJA LAYANNA
+ {0x0DC0, 0x0DC6, prN}, // Lo [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA
+ {0x0DCA, 0x0DCA, prN}, // Mn SINHALA SIGN AL-LAKUNA
+ {0x0DCF, 0x0DD1, prN}, // Mc [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA
+ {0x0DD2, 0x0DD4, prN}, // Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA
+ {0x0DD6, 0x0DD6, prN}, // Mn SINHALA VOWEL SIGN DIGA PAA-PILLA
+ {0x0DD8, 0x0DDF, prN}, // Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA
+ {0x0DE6, 0x0DEF, prN}, // Nd [10] SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE
+ {0x0DF2, 0x0DF3, prN}, // Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA
+ {0x0DF4, 0x0DF4, prN}, // Po SINHALA PUNCTUATION KUNDDALIYA
+ {0x0E01, 0x0E30, prN}, // Lo [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A
+ {0x0E31, 0x0E31, prN}, // Mn THAI CHARACTER MAI HAN-AKAT
+ {0x0E32, 0x0E33, prN}, // Lo [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM
+ {0x0E34, 0x0E3A, prN}, // Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU
+ {0x0E3F, 0x0E3F, prN}, // Sc THAI CURRENCY SYMBOL BAHT
+ {0x0E40, 0x0E45, prN}, // Lo [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO
+ {0x0E46, 0x0E46, prN}, // Lm THAI CHARACTER MAIYAMOK
+ {0x0E47, 0x0E4E, prN}, // Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN
+ {0x0E4F, 0x0E4F, prN}, // Po THAI CHARACTER FONGMAN
+ {0x0E50, 0x0E59, prN}, // Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE
+ {0x0E5A, 0x0E5B, prN}, // Po [2] THAI CHARACTER ANGKHANKHU..THAI CHARACTER KHOMUT
+ {0x0E81, 0x0E82, prN}, // Lo [2] LAO LETTER KO..LAO LETTER KHO SUNG
+ {0x0E84, 0x0E84, prN}, // Lo LAO LETTER KHO TAM
+ {0x0E86, 0x0E8A, prN}, // Lo [5] LAO LETTER PALI GHA..LAO LETTER SO TAM
+ {0x0E8C, 0x0EA3, prN}, // Lo [24] LAO LETTER PALI JHA..LAO LETTER LO LING
+ {0x0EA5, 0x0EA5, prN}, // Lo LAO LETTER LO LOOT
+ {0x0EA7, 0x0EB0, prN}, // Lo [10] LAO LETTER WO..LAO VOWEL SIGN A
+ {0x0EB1, 0x0EB1, prN}, // Mn LAO VOWEL SIGN MAI KAN
+ {0x0EB2, 0x0EB3, prN}, // Lo [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM
+ {0x0EB4, 0x0EBC, prN}, // Mn [9] LAO VOWEL SIGN I..LAO SEMIVOWEL SIGN LO
+ {0x0EBD, 0x0EBD, prN}, // Lo LAO SEMIVOWEL SIGN NYO
+ {0x0EC0, 0x0EC4, prN}, // Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI
+ {0x0EC6, 0x0EC6, prN}, // Lm LAO KO LA
+ {0x0EC8, 0x0ECE, prN}, // Mn [7] LAO TONE MAI EK..LAO YAMAKKAN
+ {0x0ED0, 0x0ED9, prN}, // Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE
+ {0x0EDC, 0x0EDF, prN}, // Lo [4] LAO HO NO..LAO LETTER KHMU NYO
+ {0x0F00, 0x0F00, prN}, // Lo TIBETAN SYLLABLE OM
+ {0x0F01, 0x0F03, prN}, // So [3] TIBETAN MARK GTER YIG MGO TRUNCATED A..TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA
+ {0x0F04, 0x0F12, prN}, // Po [15] TIBETAN MARK INITIAL YIG MGO MDUN MA..TIBETAN MARK RGYA GRAM SHAD
+ {0x0F13, 0x0F13, prN}, // So TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN
+ {0x0F14, 0x0F14, prN}, // Po TIBETAN MARK GTER TSHEG
+ {0x0F15, 0x0F17, prN}, // So [3] TIBETAN LOGOTYPE SIGN CHAD RTAGS..TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS
+ {0x0F18, 0x0F19, prN}, // Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS
+ {0x0F1A, 0x0F1F, prN}, // So [6] TIBETAN SIGN RDEL DKAR GCIG..TIBETAN SIGN RDEL DKAR RDEL NAG
+ {0x0F20, 0x0F29, prN}, // Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
+ {0x0F2A, 0x0F33, prN}, // No [10] TIBETAN DIGIT HALF ONE..TIBETAN DIGIT HALF ZERO
+ {0x0F34, 0x0F34, prN}, // So TIBETAN MARK BSDUS RTAGS
+ {0x0F35, 0x0F35, prN}, // Mn TIBETAN MARK NGAS BZUNG NYI ZLA
+ {0x0F36, 0x0F36, prN}, // So TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN
+ {0x0F37, 0x0F37, prN}, // Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS
+ {0x0F38, 0x0F38, prN}, // So TIBETAN MARK CHE MGO
+ {0x0F39, 0x0F39, prN}, // Mn TIBETAN MARK TSA -PHRU
+ {0x0F3A, 0x0F3A, prN}, // Ps TIBETAN MARK GUG RTAGS GYON
+ {0x0F3B, 0x0F3B, prN}, // Pe TIBETAN MARK GUG RTAGS GYAS
+ {0x0F3C, 0x0F3C, prN}, // Ps TIBETAN MARK ANG KHANG GYON
+ {0x0F3D, 0x0F3D, prN}, // Pe TIBETAN MARK ANG KHANG GYAS
+ {0x0F3E, 0x0F3F, prN}, // Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES
+ {0x0F40, 0x0F47, prN}, // Lo [8] TIBETAN LETTER KA..TIBETAN LETTER JA
+ {0x0F49, 0x0F6C, prN}, // Lo [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA
+ {0x0F71, 0x0F7E, prN}, // Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO
+ {0x0F7F, 0x0F7F, prN}, // Mc TIBETAN SIGN RNAM BCAD
+ {0x0F80, 0x0F84, prN}, // Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA
+ {0x0F85, 0x0F85, prN}, // Po TIBETAN MARK PALUTA
+ {0x0F86, 0x0F87, prN}, // Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS
+ {0x0F88, 0x0F8C, prN}, // Lo [5] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN INVERTED MCHU CAN
+ {0x0F8D, 0x0F97, prN}, // Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA
+ {0x0F99, 0x0FBC, prN}, // Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA
+ {0x0FBE, 0x0FC5, prN}, // So [8] TIBETAN KU RU KHA..TIBETAN SYMBOL RDO RJE
+ {0x0FC6, 0x0FC6, prN}, // Mn TIBETAN SYMBOL PADMA GDAN
+ {0x0FC7, 0x0FCC, prN}, // So [6] TIBETAN SYMBOL RDO RJE RGYA GRAM..TIBETAN SYMBOL NOR BU BZHI -KHYIL
+ {0x0FCE, 0x0FCF, prN}, // So [2] TIBETAN SIGN RDEL NAG RDEL DKAR..TIBETAN SIGN RDEL NAG GSUM
+ {0x0FD0, 0x0FD4, prN}, // Po [5] TIBETAN MARK BSKA- SHOG GI MGO RGYAN..TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA
+ {0x0FD5, 0x0FD8, prN}, // So [4] RIGHT-FACING SVASTI SIGN..LEFT-FACING SVASTI SIGN WITH DOTS
+ {0x0FD9, 0x0FDA, prN}, // Po [2] TIBETAN MARK LEADING MCHAN RTAGS..TIBETAN MARK TRAILING MCHAN RTAGS
+ {0x1000, 0x102A, prN}, // Lo [43] MYANMAR LETTER KA..MYANMAR LETTER AU
+ {0x102B, 0x102C, prN}, // Mc [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA
+ {0x102D, 0x1030, prN}, // Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU
+ {0x1031, 0x1031, prN}, // Mc MYANMAR VOWEL SIGN E
+ {0x1032, 0x1037, prN}, // Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW
+ {0x1038, 0x1038, prN}, // Mc MYANMAR SIGN VISARGA
+ {0x1039, 0x103A, prN}, // Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT
+ {0x103B, 0x103C, prN}, // Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA
+ {0x103D, 0x103E, prN}, // Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA
+ {0x103F, 0x103F, prN}, // Lo MYANMAR LETTER GREAT SA
+ {0x1040, 0x1049, prN}, // Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
+ {0x104A, 0x104F, prN}, // Po [6] MYANMAR SIGN LITTLE SECTION..MYANMAR SYMBOL GENITIVE
+ {0x1050, 0x1055, prN}, // Lo [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL
+ {0x1056, 0x1057, prN}, // Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR
+ {0x1058, 0x1059, prN}, // Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL
+ {0x105A, 0x105D, prN}, // Lo [4] MYANMAR LETTER MON NGA..MYANMAR LETTER MON BBE
+ {0x105E, 0x1060, prN}, // Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA
+ {0x1061, 0x1061, prN}, // Lo MYANMAR LETTER SGAW KAREN SHA
+ {0x1062, 0x1064, prN}, // Mc [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO
+ {0x1065, 0x1066, prN}, // Lo [2] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR LETTER WESTERN PWO KAREN PWA
+ {0x1067, 0x106D, prN}, // Mc [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5
+ {0x106E, 0x1070, prN}, // Lo [3] MYANMAR LETTER EASTERN PWO KAREN NNA..MYANMAR LETTER EASTERN PWO KAREN GHWA
+ {0x1071, 0x1074, prN}, // Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE
+ {0x1075, 0x1081, prN}, // Lo [13] MYANMAR LETTER SHAN KA..MYANMAR LETTER SHAN HA
+ {0x1082, 0x1082, prN}, // Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA
+ {0x1083, 0x1084, prN}, // Mc [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E
+ {0x1085, 0x1086, prN}, // Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y
+ {0x1087, 0x108C, prN}, // Mc [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3
+ {0x108D, 0x108D, prN}, // Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE
+ {0x108E, 0x108E, prN}, // Lo MYANMAR LETTER RUMAI PALAUNG FA
+ {0x108F, 0x108F, prN}, // Mc MYANMAR SIGN RUMAI PALAUNG TONE-5
+ {0x1090, 0x1099, prN}, // Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
+ {0x109A, 0x109C, prN}, // Mc [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A
+ {0x109D, 0x109D, prN}, // Mn MYANMAR VOWEL SIGN AITON AI
+ {0x109E, 0x109F, prN}, // So [2] MYANMAR SYMBOL SHAN ONE..MYANMAR SYMBOL SHAN EXCLAMATION
+ {0x10A0, 0x10C5, prN}, // Lu [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+ {0x10C7, 0x10C7, prN}, // Lu GEORGIAN CAPITAL LETTER YN
+ {0x10CD, 0x10CD, prN}, // Lu GEORGIAN CAPITAL LETTER AEN
+ {0x10D0, 0x10FA, prN}, // Ll [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN
+ {0x10FB, 0x10FB, prN}, // Po GEORGIAN PARAGRAPH SEPARATOR
+ {0x10FC, 0x10FC, prN}, // Lm MODIFIER LETTER GEORGIAN NAR
+ {0x10FD, 0x10FF, prN}, // Ll [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN
+ {0x1100, 0x115F, prW}, // Lo [96] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG FILLER
+ {0x1160, 0x11FF, prN}, // Lo [160] HANGUL JUNGSEONG FILLER..HANGUL JONGSEONG SSANGNIEUN
+ {0x1200, 0x1248, prN}, // Lo [73] ETHIOPIC SYLLABLE HA..ETHIOPIC SYLLABLE QWA
+ {0x124A, 0x124D, prN}, // Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE
+ {0x1250, 0x1256, prN}, // Lo [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO
+ {0x1258, 0x1258, prN}, // Lo ETHIOPIC SYLLABLE QHWA
+ {0x125A, 0x125D, prN}, // Lo [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE
+ {0x1260, 0x1288, prN}, // Lo [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA
+ {0x128A, 0x128D, prN}, // Lo [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE
+ {0x1290, 0x12B0, prN}, // Lo [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA
+ {0x12B2, 0x12B5, prN}, // Lo [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE
+ {0x12B8, 0x12BE, prN}, // Lo [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO
+ {0x12C0, 0x12C0, prN}, // Lo ETHIOPIC SYLLABLE KXWA
+ {0x12C2, 0x12C5, prN}, // Lo [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE
+ {0x12C8, 0x12D6, prN}, // Lo [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O
+ {0x12D8, 0x1310, prN}, // Lo [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA
+ {0x1312, 0x1315, prN}, // Lo [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE
+ {0x1318, 0x135A, prN}, // Lo [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA
+ {0x135D, 0x135F, prN}, // Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK
+ {0x1360, 0x1368, prN}, // Po [9] ETHIOPIC SECTION MARK..ETHIOPIC PARAGRAPH SEPARATOR
+ {0x1369, 0x137C, prN}, // No [20] ETHIOPIC DIGIT ONE..ETHIOPIC NUMBER TEN THOUSAND
+ {0x1380, 0x138F, prN}, // Lo [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE
+ {0x1390, 0x1399, prN}, // So [10] ETHIOPIC TONAL MARK YIZET..ETHIOPIC TONAL MARK KURT
+ {0x13A0, 0x13F5, prN}, // Lu [86] CHEROKEE LETTER A..CHEROKEE LETTER MV
+ {0x13F8, 0x13FD, prN}, // Ll [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV
+ {0x1400, 0x1400, prN}, // Pd CANADIAN SYLLABICS HYPHEN
+ {0x1401, 0x166C, prN}, // Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA
+ {0x166D, 0x166D, prN}, // So CANADIAN SYLLABICS CHI SIGN
+ {0x166E, 0x166E, prN}, // Po CANADIAN SYLLABICS FULL STOP
+ {0x166F, 0x167F, prN}, // Lo [17] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS BLACKFOOT W
+ {0x1680, 0x1680, prN}, // Zs OGHAM SPACE MARK
+ {0x1681, 0x169A, prN}, // Lo [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH
+ {0x169B, 0x169B, prN}, // Ps OGHAM FEATHER MARK
+ {0x169C, 0x169C, prN}, // Pe OGHAM REVERSED FEATHER MARK
+ {0x16A0, 0x16EA, prN}, // Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X
+ {0x16EB, 0x16ED, prN}, // Po [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION
+ {0x16EE, 0x16F0, prN}, // Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL
+ {0x16F1, 0x16F8, prN}, // Lo [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC
+ {0x1700, 0x1711, prN}, // Lo [18] TAGALOG LETTER A..TAGALOG LETTER HA
+ {0x1712, 0x1714, prN}, // Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA
+ {0x1715, 0x1715, prN}, // Mc TAGALOG SIGN PAMUDPOD
+ {0x171F, 0x171F, prN}, // Lo TAGALOG LETTER ARCHAIC RA
+ {0x1720, 0x1731, prN}, // Lo [18] HANUNOO LETTER A..HANUNOO LETTER HA
+ {0x1732, 0x1733, prN}, // Mn [2] HANUNOO VOWEL SIGN I..HANUNOO VOWEL SIGN U
+ {0x1734, 0x1734, prN}, // Mc HANUNOO SIGN PAMUDPOD
+ {0x1735, 0x1736, prN}, // Po [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION
+ {0x1740, 0x1751, prN}, // Lo [18] BUHID LETTER A..BUHID LETTER HA
+ {0x1752, 0x1753, prN}, // Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U
+ {0x1760, 0x176C, prN}, // Lo [13] TAGBANWA LETTER A..TAGBANWA LETTER YA
+ {0x176E, 0x1770, prN}, // Lo [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA
+ {0x1772, 0x1773, prN}, // Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U
+ {0x1780, 0x17B3, prN}, // Lo [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU
+ {0x17B4, 0x17B5, prN}, // Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+ {0x17B6, 0x17B6, prN}, // Mc KHMER VOWEL SIGN AA
+ {0x17B7, 0x17BD, prN}, // Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA
+ {0x17BE, 0x17C5, prN}, // Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU
+ {0x17C6, 0x17C6, prN}, // Mn KHMER SIGN NIKAHIT
+ {0x17C7, 0x17C8, prN}, // Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU
+ {0x17C9, 0x17D3, prN}, // Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT
+ {0x17D4, 0x17D6, prN}, // Po [3] KHMER SIGN KHAN..KHMER SIGN CAMNUC PII KUUH
+ {0x17D7, 0x17D7, prN}, // Lm KHMER SIGN LEK TOO
+ {0x17D8, 0x17DA, prN}, // Po [3] KHMER SIGN BEYYAL..KHMER SIGN KOOMUUT
+ {0x17DB, 0x17DB, prN}, // Sc KHMER CURRENCY SYMBOL RIEL
+ {0x17DC, 0x17DC, prN}, // Lo KHMER SIGN AVAKRAHASANYA
+ {0x17DD, 0x17DD, prN}, // Mn KHMER SIGN ATTHACAN
+ {0x17E0, 0x17E9, prN}, // Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
+ {0x17F0, 0x17F9, prN}, // No [10] KHMER SYMBOL LEK ATTAK SON..KHMER SYMBOL LEK ATTAK PRAM-BUON
+ {0x1800, 0x1805, prN}, // Po [6] MONGOLIAN BIRGA..MONGOLIAN FOUR DOTS
+ {0x1806, 0x1806, prN}, // Pd MONGOLIAN TODO SOFT HYPHEN
+ {0x1807, 0x180A, prN}, // Po [4] MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER..MONGOLIAN NIRUGU
+ {0x180B, 0x180D, prN}, // Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+ {0x180E, 0x180E, prN}, // Cf MONGOLIAN VOWEL SEPARATOR
+ {0x180F, 0x180F, prN}, // Mn MONGOLIAN FREE VARIATION SELECTOR FOUR
+ {0x1810, 0x1819, prN}, // Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
+ {0x1820, 0x1842, prN}, // Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI
+ {0x1843, 0x1843, prN}, // Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN
+ {0x1844, 0x1878, prN}, // Lo [53] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER CHA WITH TWO DOTS
+ {0x1880, 0x1884, prN}, // Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA
+ {0x1885, 0x1886, prN}, // Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
+ {0x1887, 0x18A8, prN}, // Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA
+ {0x18A9, 0x18A9, prN}, // Mn MONGOLIAN LETTER ALI GALI DAGALGA
+ {0x18AA, 0x18AA, prN}, // Lo MONGOLIAN LETTER MANCHU ALI GALI LHA
+ {0x18B0, 0x18F5, prN}, // Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S
+ {0x1900, 0x191E, prN}, // Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA
+ {0x1920, 0x1922, prN}, // Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U
+ {0x1923, 0x1926, prN}, // Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU
+ {0x1927, 0x1928, prN}, // Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O
+ {0x1929, 0x192B, prN}, // Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA
+ {0x1930, 0x1931, prN}, // Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA
+ {0x1932, 0x1932, prN}, // Mn LIMBU SMALL LETTER ANUSVARA
+ {0x1933, 0x1938, prN}, // Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA
+ {0x1939, 0x193B, prN}, // Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I
+ {0x1940, 0x1940, prN}, // So LIMBU SIGN LOO
+ {0x1944, 0x1945, prN}, // Po [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK
+ {0x1946, 0x194F, prN}, // Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
+ {0x1950, 0x196D, prN}, // Lo [30] TAI LE LETTER KA..TAI LE LETTER AI
+ {0x1970, 0x1974, prN}, // Lo [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6
+ {0x1980, 0x19AB, prN}, // Lo [44] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW SUA
+ {0x19B0, 0x19C9, prN}, // Lo [26] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE TONE MARK-2
+ {0x19D0, 0x19D9, prN}, // Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
+ {0x19DA, 0x19DA, prN}, // No NEW TAI LUE THAM DIGIT ONE
+ {0x19DE, 0x19DF, prN}, // So [2] NEW TAI LUE SIGN LAE..NEW TAI LUE SIGN LAEV
+ {0x19E0, 0x19FF, prN}, // So [32] KHMER SYMBOL PATHAMASAT..KHMER SYMBOL DAP-PRAM ROC
+ {0x1A00, 0x1A16, prN}, // Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA
+ {0x1A17, 0x1A18, prN}, // Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U
+ {0x1A19, 0x1A1A, prN}, // Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O
+ {0x1A1B, 0x1A1B, prN}, // Mn BUGINESE VOWEL SIGN AE
+ {0x1A1E, 0x1A1F, prN}, // Po [2] BUGINESE PALLAWA..BUGINESE END OF SECTION
+ {0x1A20, 0x1A54, prN}, // Lo [53] TAI THAM LETTER HIGH KA..TAI THAM LETTER GREAT SA
+ {0x1A55, 0x1A55, prN}, // Mc TAI THAM CONSONANT SIGN MEDIAL RA
+ {0x1A56, 0x1A56, prN}, // Mn TAI THAM CONSONANT SIGN MEDIAL LA
+ {0x1A57, 0x1A57, prN}, // Mc TAI THAM CONSONANT SIGN LA TANG LAI
+ {0x1A58, 0x1A5E, prN}, // Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA
+ {0x1A60, 0x1A60, prN}, // Mn TAI THAM SIGN SAKOT
+ {0x1A61, 0x1A61, prN}, // Mc TAI THAM VOWEL SIGN A
+ {0x1A62, 0x1A62, prN}, // Mn TAI THAM VOWEL SIGN MAI SAT
+ {0x1A63, 0x1A64, prN}, // Mc [2] TAI THAM VOWEL SIGN AA..TAI THAM VOWEL SIGN TALL AA
+ {0x1A65, 0x1A6C, prN}, // Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW
+ {0x1A6D, 0x1A72, prN}, // Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI
+ {0x1A73, 0x1A7C, prN}, // Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN
+ {0x1A7F, 0x1A7F, prN}, // Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT
+ {0x1A80, 0x1A89, prN}, // Nd [10] TAI THAM HORA DIGIT ZERO..TAI THAM HORA DIGIT NINE
+ {0x1A90, 0x1A99, prN}, // Nd [10] TAI THAM THAM DIGIT ZERO..TAI THAM THAM DIGIT NINE
+ {0x1AA0, 0x1AA6, prN}, // Po [7] TAI THAM SIGN WIANG..TAI THAM SIGN REVERSED ROTATED RANA
+ {0x1AA7, 0x1AA7, prN}, // Lm TAI THAM SIGN MAI YAMOK
+ {0x1AA8, 0x1AAD, prN}, // Po [6] TAI THAM SIGN KAAN..TAI THAM SIGN CAANG
+ {0x1AB0, 0x1ABD, prN}, // Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW
+ {0x1ABE, 0x1ABE, prN}, // Me COMBINING PARENTHESES OVERLAY
+ {0x1ABF, 0x1ACE, prN}, // Mn [16] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER INSULAR T
+ {0x1B00, 0x1B03, prN}, // Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
+ {0x1B04, 0x1B04, prN}, // Mc BALINESE SIGN BISAH
+ {0x1B05, 0x1B33, prN}, // Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA
+ {0x1B34, 0x1B34, prN}, // Mn BALINESE SIGN REREKAN
+ {0x1B35, 0x1B35, prN}, // Mc BALINESE VOWEL SIGN TEDUNG
+ {0x1B36, 0x1B3A, prN}, // Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA
+ {0x1B3B, 0x1B3B, prN}, // Mc BALINESE VOWEL SIGN RA REPA TEDUNG
+ {0x1B3C, 0x1B3C, prN}, // Mn BALINESE VOWEL SIGN LA LENGA
+ {0x1B3D, 0x1B41, prN}, // Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG
+ {0x1B42, 0x1B42, prN}, // Mn BALINESE VOWEL SIGN PEPET
+ {0x1B43, 0x1B44, prN}, // Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG
+ {0x1B45, 0x1B4C, prN}, // Lo [8] BALINESE LETTER KAF SASAK..BALINESE LETTER ARCHAIC JNYA
+ {0x1B50, 0x1B59, prN}, // Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
+ {0x1B5A, 0x1B60, prN}, // Po [7] BALINESE PANTI..BALINESE PAMENENG
+ {0x1B61, 0x1B6A, prN}, // So [10] BALINESE MUSICAL SYMBOL DONG..BALINESE MUSICAL SYMBOL DANG GEDE
+ {0x1B6B, 0x1B73, prN}, // Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
+ {0x1B74, 0x1B7C, prN}, // So [9] BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG..BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING
+ {0x1B7D, 0x1B7E, prN}, // Po [2] BALINESE PANTI LANTANG..BALINESE PAMADA LANTANG
+ {0x1B80, 0x1B81, prN}, // Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR
+ {0x1B82, 0x1B82, prN}, // Mc SUNDANESE SIGN PANGWISAD
+ {0x1B83, 0x1BA0, prN}, // Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA
+ {0x1BA1, 0x1BA1, prN}, // Mc SUNDANESE CONSONANT SIGN PAMINGKAL
+ {0x1BA2, 0x1BA5, prN}, // Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU
+ {0x1BA6, 0x1BA7, prN}, // Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG
+ {0x1BA8, 0x1BA9, prN}, // Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
+ {0x1BAA, 0x1BAA, prN}, // Mc SUNDANESE SIGN PAMAAEH
+ {0x1BAB, 0x1BAD, prN}, // Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA
+ {0x1BAE, 0x1BAF, prN}, // Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA
+ {0x1BB0, 0x1BB9, prN}, // Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
+ {0x1BBA, 0x1BBF, prN}, // Lo [6] SUNDANESE AVAGRAHA..SUNDANESE LETTER FINAL M
+ {0x1BC0, 0x1BE5, prN}, // Lo [38] BATAK LETTER A..BATAK LETTER U
+ {0x1BE6, 0x1BE6, prN}, // Mn BATAK SIGN TOMPI
+ {0x1BE7, 0x1BE7, prN}, // Mc BATAK VOWEL SIGN E
+ {0x1BE8, 0x1BE9, prN}, // Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE
+ {0x1BEA, 0x1BEC, prN}, // Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O
+ {0x1BED, 0x1BED, prN}, // Mn BATAK VOWEL SIGN KARO O
+ {0x1BEE, 0x1BEE, prN}, // Mc BATAK VOWEL SIGN U
+ {0x1BEF, 0x1BF1, prN}, // Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H
+ {0x1BF2, 0x1BF3, prN}, // Mc [2] BATAK PANGOLAT..BATAK PANONGONAN
+ {0x1BFC, 0x1BFF, prN}, // Po [4] BATAK SYMBOL BINDU NA METEK..BATAK SYMBOL BINDU PANGOLAT
+ {0x1C00, 0x1C23, prN}, // Lo [36] LEPCHA LETTER KA..LEPCHA LETTER A
+ {0x1C24, 0x1C2B, prN}, // Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU
+ {0x1C2C, 0x1C33, prN}, // Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T
+ {0x1C34, 0x1C35, prN}, // Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG
+ {0x1C36, 0x1C37, prN}, // Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA
+ {0x1C3B, 0x1C3F, prN}, // Po [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK
+ {0x1C40, 0x1C49, prN}, // Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
+ {0x1C4D, 0x1C4F, prN}, // Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA
+ {0x1C50, 0x1C59, prN}, // Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
+ {0x1C5A, 0x1C77, prN}, // Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH
+ {0x1C78, 0x1C7D, prN}, // Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD
+ {0x1C7E, 0x1C7F, prN}, // Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD
+ {0x1C80, 0x1C88, prN}, // Ll [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK
+ {0x1C90, 0x1CBA, prN}, // Lu [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN
+ {0x1CBD, 0x1CBF, prN}, // Lu [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN
+ {0x1CC0, 0x1CC7, prN}, // Po [8] SUNDANESE PUNCTUATION BINDU SURYA..SUNDANESE PUNCTUATION BINDU BA SATANGA
+ {0x1CD0, 0x1CD2, prN}, // Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA
+ {0x1CD3, 0x1CD3, prN}, // Po VEDIC SIGN NIHSHVASA
+ {0x1CD4, 0x1CE0, prN}, // Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA
+ {0x1CE1, 0x1CE1, prN}, // Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA
+ {0x1CE2, 0x1CE8, prN}, // Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL
+ {0x1CE9, 0x1CEC, prN}, // Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL
+ {0x1CED, 0x1CED, prN}, // Mn VEDIC SIGN TIRYAK
+ {0x1CEE, 0x1CF3, prN}, // Lo [6] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ROTATED ARDHAVISARGA
+ {0x1CF4, 0x1CF4, prN}, // Mn VEDIC TONE CANDRA ABOVE
+ {0x1CF5, 0x1CF6, prN}, // Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA
+ {0x1CF7, 0x1CF7, prN}, // Mc VEDIC SIGN ATIKRAMA
+ {0x1CF8, 0x1CF9, prN}, // Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
+ {0x1CFA, 0x1CFA, prN}, // Lo VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA
+ {0x1D00, 0x1D2B, prN}, // Ll [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL
+ {0x1D2C, 0x1D6A, prN}, // Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI
+ {0x1D6B, 0x1D77, prN}, // Ll [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G
+ {0x1D78, 0x1D78, prN}, // Lm MODIFIER LETTER CYRILLIC EN
+ {0x1D79, 0x1D7F, prN}, // Ll [7] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER UPSILON WITH STROKE
+ {0x1D80, 0x1D9A, prN}, // Ll [27] LATIN SMALL LETTER B WITH PALATAL HOOK..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
+ {0x1D9B, 0x1DBF, prN}, // Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA
+ {0x1DC0, 0x1DFF, prN}, // Mn [64] COMBINING DOTTED GRAVE ACCENT..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
+ {0x1E00, 0x1EFF, prN}, // L& [256] LATIN CAPITAL LETTER A WITH RING BELOW..LATIN SMALL LETTER Y WITH LOOP
+ {0x1F00, 0x1F15, prN}, // L& [22] GREEK SMALL LETTER ALPHA WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+ {0x1F18, 0x1F1D, prN}, // Lu [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+ {0x1F20, 0x1F45, prN}, // L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+ {0x1F48, 0x1F4D, prN}, // Lu [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+ {0x1F50, 0x1F57, prN}, // Ll [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+ {0x1F59, 0x1F59, prN}, // Lu GREEK CAPITAL LETTER UPSILON WITH DASIA
+ {0x1F5B, 0x1F5B, prN}, // Lu GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+ {0x1F5D, 0x1F5D, prN}, // Lu GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+ {0x1F5F, 0x1F7D, prN}, // L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA
+ {0x1F80, 0x1FB4, prN}, // L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+ {0x1FB6, 0x1FBC, prN}, // L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+ {0x1FBD, 0x1FBD, prN}, // Sk GREEK KORONIS
+ {0x1FBE, 0x1FBE, prN}, // Ll GREEK PROSGEGRAMMENI
+ {0x1FBF, 0x1FC1, prN}, // Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI
+ {0x1FC2, 0x1FC4, prN}, // Ll [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+ {0x1FC6, 0x1FCC, prN}, // L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+ {0x1FCD, 0x1FCF, prN}, // Sk [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI
+ {0x1FD0, 0x1FD3, prN}, // Ll [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+ {0x1FD6, 0x1FDB, prN}, // L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA
+ {0x1FDD, 0x1FDF, prN}, // Sk [3] GREEK DASIA AND VARIA..GREEK DASIA AND PERISPOMENI
+ {0x1FE0, 0x1FEC, prN}, // L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+ {0x1FED, 0x1FEF, prN}, // Sk [3] GREEK DIALYTIKA AND VARIA..GREEK VARIA
+ {0x1FF2, 0x1FF4, prN}, // Ll [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+ {0x1FF6, 0x1FFC, prN}, // L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+ {0x1FFD, 0x1FFE, prN}, // Sk [2] GREEK OXIA..GREEK DASIA
+ {0x2000, 0x200A, prN}, // Zs [11] EN QUAD..HAIR SPACE
+ {0x200B, 0x200F, prN}, // Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
+ {0x2010, 0x2010, prA}, // Pd HYPHEN
+ {0x2011, 0x2012, prN}, // Pd [2] NON-BREAKING HYPHEN..FIGURE DASH
+ {0x2013, 0x2015, prA}, // Pd [3] EN DASH..HORIZONTAL BAR
+ {0x2016, 0x2016, prA}, // Po DOUBLE VERTICAL LINE
+ {0x2017, 0x2017, prN}, // Po DOUBLE LOW LINE
+ {0x2018, 0x2018, prA}, // Pi LEFT SINGLE QUOTATION MARK
+ {0x2019, 0x2019, prA}, // Pf RIGHT SINGLE QUOTATION MARK
+ {0x201A, 0x201A, prN}, // Ps SINGLE LOW-9 QUOTATION MARK
+ {0x201B, 0x201B, prN}, // Pi SINGLE HIGH-REVERSED-9 QUOTATION MARK
+ {0x201C, 0x201C, prA}, // Pi LEFT DOUBLE QUOTATION MARK
+ {0x201D, 0x201D, prA}, // Pf RIGHT DOUBLE QUOTATION MARK
+ {0x201E, 0x201E, prN}, // Ps DOUBLE LOW-9 QUOTATION MARK
+ {0x201F, 0x201F, prN}, // Pi DOUBLE HIGH-REVERSED-9 QUOTATION MARK
+ {0x2020, 0x2022, prA}, // Po [3] DAGGER..BULLET
+ {0x2023, 0x2023, prN}, // Po TRIANGULAR BULLET
+ {0x2024, 0x2027, prA}, // Po [4] ONE DOT LEADER..HYPHENATION POINT
+ {0x2028, 0x2028, prN}, // Zl LINE SEPARATOR
+ {0x2029, 0x2029, prN}, // Zp PARAGRAPH SEPARATOR
+ {0x202A, 0x202E, prN}, // Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
+ {0x202F, 0x202F, prN}, // Zs NARROW NO-BREAK SPACE
+ {0x2030, 0x2030, prA}, // Po PER MILLE SIGN
+ {0x2031, 0x2031, prN}, // Po PER TEN THOUSAND SIGN
+ {0x2032, 0x2033, prA}, // Po [2] PRIME..DOUBLE PRIME
+ {0x2034, 0x2034, prN}, // Po TRIPLE PRIME
+ {0x2035, 0x2035, prA}, // Po REVERSED PRIME
+ {0x2036, 0x2038, prN}, // Po [3] REVERSED DOUBLE PRIME..CARET
+ {0x2039, 0x2039, prN}, // Pi SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ {0x203A, 0x203A, prN}, // Pf SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ {0x203B, 0x203B, prA}, // Po REFERENCE MARK
+ {0x203C, 0x203D, prN}, // Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG
+ {0x203E, 0x203E, prA}, // Po OVERLINE
+ {0x203F, 0x2040, prN}, // Pc [2] UNDERTIE..CHARACTER TIE
+ {0x2041, 0x2043, prN}, // Po [3] CARET INSERTION POINT..HYPHEN BULLET
+ {0x2044, 0x2044, prN}, // Sm FRACTION SLASH
+ {0x2045, 0x2045, prN}, // Ps LEFT SQUARE BRACKET WITH QUILL
+ {0x2046, 0x2046, prN}, // Pe RIGHT SQUARE BRACKET WITH QUILL
+ {0x2047, 0x2051, prN}, // Po [11] DOUBLE QUESTION MARK..TWO ASTERISKS ALIGNED VERTICALLY
+ {0x2052, 0x2052, prN}, // Sm COMMERCIAL MINUS SIGN
+ {0x2053, 0x2053, prN}, // Po SWUNG DASH
+ {0x2054, 0x2054, prN}, // Pc INVERTED UNDERTIE
+ {0x2055, 0x205E, prN}, // Po [10] FLOWER PUNCTUATION MARK..VERTICAL FOUR DOTS
+ {0x205F, 0x205F, prN}, // Zs MEDIUM MATHEMATICAL SPACE
+ {0x2060, 0x2064, prN}, // Cf [5] WORD JOINER..INVISIBLE PLUS
+ {0x2066, 0x206F, prN}, // Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES
+ {0x2070, 0x2070, prN}, // No SUPERSCRIPT ZERO
+ {0x2071, 0x2071, prN}, // Lm SUPERSCRIPT LATIN SMALL LETTER I
+ {0x2074, 0x2074, prA}, // No SUPERSCRIPT FOUR
+ {0x2075, 0x2079, prN}, // No [5] SUPERSCRIPT FIVE..SUPERSCRIPT NINE
+ {0x207A, 0x207C, prN}, // Sm [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN
+ {0x207D, 0x207D, prN}, // Ps SUPERSCRIPT LEFT PARENTHESIS
+ {0x207E, 0x207E, prN}, // Pe SUPERSCRIPT RIGHT PARENTHESIS
+ {0x207F, 0x207F, prA}, // Lm SUPERSCRIPT LATIN SMALL LETTER N
+ {0x2080, 0x2080, prN}, // No SUBSCRIPT ZERO
+ {0x2081, 0x2084, prA}, // No [4] SUBSCRIPT ONE..SUBSCRIPT FOUR
+ {0x2085, 0x2089, prN}, // No [5] SUBSCRIPT FIVE..SUBSCRIPT NINE
+ {0x208A, 0x208C, prN}, // Sm [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN
+ {0x208D, 0x208D, prN}, // Ps SUBSCRIPT LEFT PARENTHESIS
+ {0x208E, 0x208E, prN}, // Pe SUBSCRIPT RIGHT PARENTHESIS
+ {0x2090, 0x209C, prN}, // Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T
+ {0x20A0, 0x20A8, prN}, // Sc [9] EURO-CURRENCY SIGN..RUPEE SIGN
+ {0x20A9, 0x20A9, prH}, // Sc WON SIGN
+ {0x20AA, 0x20AB, prN}, // Sc [2] NEW SHEQEL SIGN..DONG SIGN
+ {0x20AC, 0x20AC, prA}, // Sc EURO SIGN
+ {0x20AD, 0x20C0, prN}, // Sc [20] KIP SIGN..SOM SIGN
+ {0x20D0, 0x20DC, prN}, // Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE
+ {0x20DD, 0x20E0, prN}, // Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH
+ {0x20E1, 0x20E1, prN}, // Mn COMBINING LEFT RIGHT ARROW ABOVE
+ {0x20E2, 0x20E4, prN}, // Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE
+ {0x20E5, 0x20F0, prN}, // Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE
+ {0x2100, 0x2101, prN}, // So [2] ACCOUNT OF..ADDRESSED TO THE SUBJECT
+ {0x2102, 0x2102, prN}, // Lu DOUBLE-STRUCK CAPITAL C
+ {0x2103, 0x2103, prA}, // So DEGREE CELSIUS
+ {0x2104, 0x2104, prN}, // So CENTRE LINE SYMBOL
+ {0x2105, 0x2105, prA}, // So CARE OF
+ {0x2106, 0x2106, prN}, // So CADA UNA
+ {0x2107, 0x2107, prN}, // Lu EULER CONSTANT
+ {0x2108, 0x2108, prN}, // So SCRUPLE
+ {0x2109, 0x2109, prA}, // So DEGREE FAHRENHEIT
+ {0x210A, 0x2112, prN}, // L& [9] SCRIPT SMALL G..SCRIPT CAPITAL L
+ {0x2113, 0x2113, prA}, // Ll SCRIPT SMALL L
+ {0x2114, 0x2114, prN}, // So L B BAR SYMBOL
+ {0x2115, 0x2115, prN}, // Lu DOUBLE-STRUCK CAPITAL N
+ {0x2116, 0x2116, prA}, // So NUMERO SIGN
+ {0x2117, 0x2117, prN}, // So SOUND RECORDING COPYRIGHT
+ {0x2118, 0x2118, prN}, // Sm SCRIPT CAPITAL P
+ {0x2119, 0x211D, prN}, // Lu [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R
+ {0x211E, 0x2120, prN}, // So [3] PRESCRIPTION TAKE..SERVICE MARK
+ {0x2121, 0x2122, prA}, // So [2] TELEPHONE SIGN..TRADE MARK SIGN
+ {0x2123, 0x2123, prN}, // So VERSICLE
+ {0x2124, 0x2124, prN}, // Lu DOUBLE-STRUCK CAPITAL Z
+ {0x2125, 0x2125, prN}, // So OUNCE SIGN
+ {0x2126, 0x2126, prA}, // Lu OHM SIGN
+ {0x2127, 0x2127, prN}, // So INVERTED OHM SIGN
+ {0x2128, 0x2128, prN}, // Lu BLACK-LETTER CAPITAL Z
+ {0x2129, 0x2129, prN}, // So TURNED GREEK SMALL LETTER IOTA
+ {0x212A, 0x212A, prN}, // Lu KELVIN SIGN
+ {0x212B, 0x212B, prA}, // Lu ANGSTROM SIGN
+ {0x212C, 0x212D, prN}, // Lu [2] SCRIPT CAPITAL B..BLACK-LETTER CAPITAL C
+ {0x212E, 0x212E, prN}, // So ESTIMATED SYMBOL
+ {0x212F, 0x2134, prN}, // L& [6] SCRIPT SMALL E..SCRIPT SMALL O
+ {0x2135, 0x2138, prN}, // Lo [4] ALEF SYMBOL..DALET SYMBOL
+ {0x2139, 0x2139, prN}, // Ll INFORMATION SOURCE
+ {0x213A, 0x213B, prN}, // So [2] ROTATED CAPITAL Q..FACSIMILE SIGN
+ {0x213C, 0x213F, prN}, // L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI
+ {0x2140, 0x2144, prN}, // Sm [5] DOUBLE-STRUCK N-ARY SUMMATION..TURNED SANS-SERIF CAPITAL Y
+ {0x2145, 0x2149, prN}, // L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J
+ {0x214A, 0x214A, prN}, // So PROPERTY LINE
+ {0x214B, 0x214B, prN}, // Sm TURNED AMPERSAND
+ {0x214C, 0x214D, prN}, // So [2] PER SIGN..AKTIESELSKAB
+ {0x214E, 0x214E, prN}, // Ll TURNED SMALL F
+ {0x214F, 0x214F, prN}, // So SYMBOL FOR SAMARITAN SOURCE
+ {0x2150, 0x2152, prN}, // No [3] VULGAR FRACTION ONE SEVENTH..VULGAR FRACTION ONE TENTH
+ {0x2153, 0x2154, prA}, // No [2] VULGAR FRACTION ONE THIRD..VULGAR FRACTION TWO THIRDS
+ {0x2155, 0x215A, prN}, // No [6] VULGAR FRACTION ONE FIFTH..VULGAR FRACTION FIVE SIXTHS
+ {0x215B, 0x215E, prA}, // No [4] VULGAR FRACTION ONE EIGHTH..VULGAR FRACTION SEVEN EIGHTHS
+ {0x215F, 0x215F, prN}, // No FRACTION NUMERATOR ONE
+ {0x2160, 0x216B, prA}, // Nl [12] ROMAN NUMERAL ONE..ROMAN NUMERAL TWELVE
+ {0x216C, 0x216F, prN}, // Nl [4] ROMAN NUMERAL FIFTY..ROMAN NUMERAL ONE THOUSAND
+ {0x2170, 0x2179, prA}, // Nl [10] SMALL ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL TEN
+ {0x217A, 0x2182, prN}, // Nl [9] SMALL ROMAN NUMERAL ELEVEN..ROMAN NUMERAL TEN THOUSAND
+ {0x2183, 0x2184, prN}, // L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C
+ {0x2185, 0x2188, prN}, // Nl [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND
+ {0x2189, 0x2189, prA}, // No VULGAR FRACTION ZERO THIRDS
+ {0x218A, 0x218B, prN}, // So [2] TURNED DIGIT TWO..TURNED DIGIT THREE
+ {0x2190, 0x2194, prA}, // Sm [5] LEFTWARDS ARROW..LEFT RIGHT ARROW
+ {0x2195, 0x2199, prA}, // So [5] UP DOWN ARROW..SOUTH WEST ARROW
+ {0x219A, 0x219B, prN}, // Sm [2] LEFTWARDS ARROW WITH STROKE..RIGHTWARDS ARROW WITH STROKE
+ {0x219C, 0x219F, prN}, // So [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW
+ {0x21A0, 0x21A0, prN}, // Sm RIGHTWARDS TWO HEADED ARROW
+ {0x21A1, 0x21A2, prN}, // So [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL
+ {0x21A3, 0x21A3, prN}, // Sm RIGHTWARDS ARROW WITH TAIL
+ {0x21A4, 0x21A5, prN}, // So [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR
+ {0x21A6, 0x21A6, prN}, // Sm RIGHTWARDS ARROW FROM BAR
+ {0x21A7, 0x21AD, prN}, // So [7] DOWNWARDS ARROW FROM BAR..LEFT RIGHT WAVE ARROW
+ {0x21AE, 0x21AE, prN}, // Sm LEFT RIGHT ARROW WITH STROKE
+ {0x21AF, 0x21B7, prN}, // So [9] DOWNWARDS ZIGZAG ARROW..CLOCKWISE TOP SEMICIRCLE ARROW
+ {0x21B8, 0x21B9, prA}, // So [2] NORTH WEST ARROW TO LONG BAR..LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR
+ {0x21BA, 0x21CD, prN}, // So [20] ANTICLOCKWISE OPEN CIRCLE ARROW..LEFTWARDS DOUBLE ARROW WITH STROKE
+ {0x21CE, 0x21CF, prN}, // Sm [2] LEFT RIGHT DOUBLE ARROW WITH STROKE..RIGHTWARDS DOUBLE ARROW WITH STROKE
+ {0x21D0, 0x21D1, prN}, // So [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW
+ {0x21D2, 0x21D2, prA}, // Sm RIGHTWARDS DOUBLE ARROW
+ {0x21D3, 0x21D3, prN}, // So DOWNWARDS DOUBLE ARROW
+ {0x21D4, 0x21D4, prA}, // Sm LEFT RIGHT DOUBLE ARROW
+ {0x21D5, 0x21E6, prN}, // So [18] UP DOWN DOUBLE ARROW..LEFTWARDS WHITE ARROW
+ {0x21E7, 0x21E7, prA}, // So UPWARDS WHITE ARROW
+ {0x21E8, 0x21F3, prN}, // So [12] RIGHTWARDS WHITE ARROW..UP DOWN WHITE ARROW
+ {0x21F4, 0x21FF, prN}, // Sm [12] RIGHT ARROW WITH SMALL CIRCLE..LEFT RIGHT OPEN-HEADED ARROW
+ {0x2200, 0x2200, prA}, // Sm FOR ALL
+ {0x2201, 0x2201, prN}, // Sm COMPLEMENT
+ {0x2202, 0x2203, prA}, // Sm [2] PARTIAL DIFFERENTIAL..THERE EXISTS
+ {0x2204, 0x2206, prN}, // Sm [3] THERE DOES NOT EXIST..INCREMENT
+ {0x2207, 0x2208, prA}, // Sm [2] NABLA..ELEMENT OF
+ {0x2209, 0x220A, prN}, // Sm [2] NOT AN ELEMENT OF..SMALL ELEMENT OF
+ {0x220B, 0x220B, prA}, // Sm CONTAINS AS MEMBER
+ {0x220C, 0x220E, prN}, // Sm [3] DOES NOT CONTAIN AS MEMBER..END OF PROOF
+ {0x220F, 0x220F, prA}, // Sm N-ARY PRODUCT
+ {0x2210, 0x2210, prN}, // Sm N-ARY COPRODUCT
+ {0x2211, 0x2211, prA}, // Sm N-ARY SUMMATION
+ {0x2212, 0x2214, prN}, // Sm [3] MINUS SIGN..DOT PLUS
+ {0x2215, 0x2215, prA}, // Sm DIVISION SLASH
+ {0x2216, 0x2219, prN}, // Sm [4] SET MINUS..BULLET OPERATOR
+ {0x221A, 0x221A, prA}, // Sm SQUARE ROOT
+ {0x221B, 0x221C, prN}, // Sm [2] CUBE ROOT..FOURTH ROOT
+ {0x221D, 0x2220, prA}, // Sm [4] PROPORTIONAL TO..ANGLE
+ {0x2221, 0x2222, prN}, // Sm [2] MEASURED ANGLE..SPHERICAL ANGLE
+ {0x2223, 0x2223, prA}, // Sm DIVIDES
+ {0x2224, 0x2224, prN}, // Sm DOES NOT DIVIDE
+ {0x2225, 0x2225, prA}, // Sm PARALLEL TO
+ {0x2226, 0x2226, prN}, // Sm NOT PARALLEL TO
+ {0x2227, 0x222C, prA}, // Sm [6] LOGICAL AND..DOUBLE INTEGRAL
+ {0x222D, 0x222D, prN}, // Sm TRIPLE INTEGRAL
+ {0x222E, 0x222E, prA}, // Sm CONTOUR INTEGRAL
+ {0x222F, 0x2233, prN}, // Sm [5] SURFACE INTEGRAL..ANTICLOCKWISE CONTOUR INTEGRAL
+ {0x2234, 0x2237, prA}, // Sm [4] THEREFORE..PROPORTION
+ {0x2238, 0x223B, prN}, // Sm [4] DOT MINUS..HOMOTHETIC
+ {0x223C, 0x223D, prA}, // Sm [2] TILDE OPERATOR..REVERSED TILDE
+ {0x223E, 0x2247, prN}, // Sm [10] INVERTED LAZY S..NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO
+ {0x2248, 0x2248, prA}, // Sm ALMOST EQUAL TO
+ {0x2249, 0x224B, prN}, // Sm [3] NOT ALMOST EQUAL TO..TRIPLE TILDE
+ {0x224C, 0x224C, prA}, // Sm ALL EQUAL TO
+ {0x224D, 0x2251, prN}, // Sm [5] EQUIVALENT TO..GEOMETRICALLY EQUAL TO
+ {0x2252, 0x2252, prA}, // Sm APPROXIMATELY EQUAL TO OR THE IMAGE OF
+ {0x2253, 0x225F, prN}, // Sm [13] IMAGE OF OR APPROXIMATELY EQUAL TO..QUESTIONED EQUAL TO
+ {0x2260, 0x2261, prA}, // Sm [2] NOT EQUAL TO..IDENTICAL TO
+ {0x2262, 0x2263, prN}, // Sm [2] NOT IDENTICAL TO..STRICTLY EQUIVALENT TO
+ {0x2264, 0x2267, prA}, // Sm [4] LESS-THAN OR EQUAL TO..GREATER-THAN OVER EQUAL TO
+ {0x2268, 0x2269, prN}, // Sm [2] LESS-THAN BUT NOT EQUAL TO..GREATER-THAN BUT NOT EQUAL TO
+ {0x226A, 0x226B, prA}, // Sm [2] MUCH LESS-THAN..MUCH GREATER-THAN
+ {0x226C, 0x226D, prN}, // Sm [2] BETWEEN..NOT EQUIVALENT TO
+ {0x226E, 0x226F, prA}, // Sm [2] NOT LESS-THAN..NOT GREATER-THAN
+ {0x2270, 0x2281, prN}, // Sm [18] NEITHER LESS-THAN NOR EQUAL TO..DOES NOT SUCCEED
+ {0x2282, 0x2283, prA}, // Sm [2] SUBSET OF..SUPERSET OF
+ {0x2284, 0x2285, prN}, // Sm [2] NOT A SUBSET OF..NOT A SUPERSET OF
+ {0x2286, 0x2287, prA}, // Sm [2] SUBSET OF OR EQUAL TO..SUPERSET OF OR EQUAL TO
+ {0x2288, 0x2294, prN}, // Sm [13] NEITHER A SUBSET OF NOR EQUAL TO..SQUARE CUP
+ {0x2295, 0x2295, prA}, // Sm CIRCLED PLUS
+ {0x2296, 0x2298, prN}, // Sm [3] CIRCLED MINUS..CIRCLED DIVISION SLASH
+ {0x2299, 0x2299, prA}, // Sm CIRCLED DOT OPERATOR
+ {0x229A, 0x22A4, prN}, // Sm [11] CIRCLED RING OPERATOR..DOWN TACK
+ {0x22A5, 0x22A5, prA}, // Sm UP TACK
+ {0x22A6, 0x22BE, prN}, // Sm [25] ASSERTION..RIGHT ANGLE WITH ARC
+ {0x22BF, 0x22BF, prA}, // Sm RIGHT TRIANGLE
+ {0x22C0, 0x22FF, prN}, // Sm [64] N-ARY LOGICAL AND..Z NOTATION BAG MEMBERSHIP
+ {0x2300, 0x2307, prN}, // So [8] DIAMETER SIGN..WAVY LINE
+ {0x2308, 0x2308, prN}, // Ps LEFT CEILING
+ {0x2309, 0x2309, prN}, // Pe RIGHT CEILING
+ {0x230A, 0x230A, prN}, // Ps LEFT FLOOR
+ {0x230B, 0x230B, prN}, // Pe RIGHT FLOOR
+ {0x230C, 0x2311, prN}, // So [6] BOTTOM RIGHT CROP..SQUARE LOZENGE
+ {0x2312, 0x2312, prA}, // So ARC
+ {0x2313, 0x2319, prN}, // So [7] SEGMENT..TURNED NOT SIGN
+ {0x231A, 0x231B, prW}, // So [2] WATCH..HOURGLASS
+ {0x231C, 0x231F, prN}, // So [4] TOP LEFT CORNER..BOTTOM RIGHT CORNER
+ {0x2320, 0x2321, prN}, // Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL
+ {0x2322, 0x2328, prN}, // So [7] FROWN..KEYBOARD
+ {0x2329, 0x2329, prW}, // Ps LEFT-POINTING ANGLE BRACKET
+ {0x232A, 0x232A, prW}, // Pe RIGHT-POINTING ANGLE BRACKET
+ {0x232B, 0x237B, prN}, // So [81] ERASE TO THE LEFT..NOT CHECK MARK
+ {0x237C, 0x237C, prN}, // Sm RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW
+ {0x237D, 0x239A, prN}, // So [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL
+ {0x239B, 0x23B3, prN}, // Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM
+ {0x23B4, 0x23DB, prN}, // So [40] TOP SQUARE BRACKET..FUSE
+ {0x23DC, 0x23E1, prN}, // Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET
+ {0x23E2, 0x23E8, prN}, // So [7] WHITE TRAPEZIUM..DECIMAL EXPONENT SYMBOL
+ {0x23E9, 0x23EC, prW}, // So [4] BLACK RIGHT-POINTING DOUBLE TRIANGLE..BLACK DOWN-POINTING DOUBLE TRIANGLE
+ {0x23ED, 0x23EF, prN}, // So [3] BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR..BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR
+ {0x23F0, 0x23F0, prW}, // So ALARM CLOCK
+ {0x23F1, 0x23F2, prN}, // So [2] STOPWATCH..TIMER CLOCK
+ {0x23F3, 0x23F3, prW}, // So HOURGLASS WITH FLOWING SAND
+ {0x23F4, 0x23FF, prN}, // So [12] BLACK MEDIUM LEFT-POINTING TRIANGLE..OBSERVER EYE SYMBOL
+ {0x2400, 0x2426, prN}, // So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO
+ {0x2440, 0x244A, prN}, // So [11] OCR HOOK..OCR DOUBLE BACKSLASH
+ {0x2460, 0x249B, prA}, // No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP
+ {0x249C, 0x24E9, prA}, // So [78] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z
+ {0x24EA, 0x24EA, prN}, // No CIRCLED DIGIT ZERO
+ {0x24EB, 0x24FF, prA}, // No [21] NEGATIVE CIRCLED NUMBER ELEVEN..NEGATIVE CIRCLED DIGIT ZERO
+ {0x2500, 0x254B, prA}, // So [76] BOX DRAWINGS LIGHT HORIZONTAL..BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL
+ {0x254C, 0x254F, prN}, // So [4] BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL..BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL
+ {0x2550, 0x2573, prA}, // So [36] BOX DRAWINGS DOUBLE HORIZONTAL..BOX DRAWINGS LIGHT DIAGONAL CROSS
+ {0x2574, 0x257F, prN}, // So [12] BOX DRAWINGS LIGHT LEFT..BOX DRAWINGS HEAVY UP AND LIGHT DOWN
+ {0x2580, 0x258F, prA}, // So [16] UPPER HALF BLOCK..LEFT ONE EIGHTH BLOCK
+ {0x2590, 0x2591, prN}, // So [2] RIGHT HALF BLOCK..LIGHT SHADE
+ {0x2592, 0x2595, prA}, // So [4] MEDIUM SHADE..RIGHT ONE EIGHTH BLOCK
+ {0x2596, 0x259F, prN}, // So [10] QUADRANT LOWER LEFT..QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT
+ {0x25A0, 0x25A1, prA}, // So [2] BLACK SQUARE..WHITE SQUARE
+ {0x25A2, 0x25A2, prN}, // So WHITE SQUARE WITH ROUNDED CORNERS
+ {0x25A3, 0x25A9, prA}, // So [7] WHITE SQUARE CONTAINING BLACK SMALL SQUARE..SQUARE WITH DIAGONAL CROSSHATCH FILL
+ {0x25AA, 0x25B1, prN}, // So [8] BLACK SMALL SQUARE..WHITE PARALLELOGRAM
+ {0x25B2, 0x25B3, prA}, // So [2] BLACK UP-POINTING TRIANGLE..WHITE UP-POINTING TRIANGLE
+ {0x25B4, 0x25B5, prN}, // So [2] BLACK UP-POINTING SMALL TRIANGLE..WHITE UP-POINTING SMALL TRIANGLE
+ {0x25B6, 0x25B6, prA}, // So BLACK RIGHT-POINTING TRIANGLE
+ {0x25B7, 0x25B7, prA}, // Sm WHITE RIGHT-POINTING TRIANGLE
+ {0x25B8, 0x25BB, prN}, // So [4] BLACK RIGHT-POINTING SMALL TRIANGLE..WHITE RIGHT-POINTING POINTER
+ {0x25BC, 0x25BD, prA}, // So [2] BLACK DOWN-POINTING TRIANGLE..WHITE DOWN-POINTING TRIANGLE
+ {0x25BE, 0x25BF, prN}, // So [2] BLACK DOWN-POINTING SMALL TRIANGLE..WHITE DOWN-POINTING SMALL TRIANGLE
+ {0x25C0, 0x25C0, prA}, // So BLACK LEFT-POINTING TRIANGLE
+ {0x25C1, 0x25C1, prA}, // Sm WHITE LEFT-POINTING TRIANGLE
+ {0x25C2, 0x25C5, prN}, // So [4] BLACK LEFT-POINTING SMALL TRIANGLE..WHITE LEFT-POINTING POINTER
+ {0x25C6, 0x25C8, prA}, // So [3] BLACK DIAMOND..WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND
+ {0x25C9, 0x25CA, prN}, // So [2] FISHEYE..LOZENGE
+ {0x25CB, 0x25CB, prA}, // So WHITE CIRCLE
+ {0x25CC, 0x25CD, prN}, // So [2] DOTTED CIRCLE..CIRCLE WITH VERTICAL FILL
+ {0x25CE, 0x25D1, prA}, // So [4] BULLSEYE..CIRCLE WITH RIGHT HALF BLACK
+ {0x25D2, 0x25E1, prN}, // So [16] CIRCLE WITH LOWER HALF BLACK..LOWER HALF CIRCLE
+ {0x25E2, 0x25E5, prA}, // So [4] BLACK LOWER RIGHT TRIANGLE..BLACK UPPER RIGHT TRIANGLE
+ {0x25E6, 0x25EE, prN}, // So [9] WHITE BULLET..UP-POINTING TRIANGLE WITH RIGHT HALF BLACK
+ {0x25EF, 0x25EF, prA}, // So LARGE CIRCLE
+ {0x25F0, 0x25F7, prN}, // So [8] WHITE SQUARE WITH UPPER LEFT QUADRANT..WHITE CIRCLE WITH UPPER RIGHT QUADRANT
+ {0x25F8, 0x25FC, prN}, // Sm [5] UPPER LEFT TRIANGLE..BLACK MEDIUM SQUARE
+ {0x25FD, 0x25FE, prW}, // Sm [2] WHITE MEDIUM SMALL SQUARE..BLACK MEDIUM SMALL SQUARE
+ {0x25FF, 0x25FF, prN}, // Sm LOWER RIGHT TRIANGLE
+ {0x2600, 0x2604, prN}, // So [5] BLACK SUN WITH RAYS..COMET
+ {0x2605, 0x2606, prA}, // So [2] BLACK STAR..WHITE STAR
+ {0x2607, 0x2608, prN}, // So [2] LIGHTNING..THUNDERSTORM
+ {0x2609, 0x2609, prA}, // So SUN
+ {0x260A, 0x260D, prN}, // So [4] ASCENDING NODE..OPPOSITION
+ {0x260E, 0x260F, prA}, // So [2] BLACK TELEPHONE..WHITE TELEPHONE
+ {0x2610, 0x2613, prN}, // So [4] BALLOT BOX..SALTIRE
+ {0x2614, 0x2615, prW}, // So [2] UMBRELLA WITH RAIN DROPS..HOT BEVERAGE
+ {0x2616, 0x261B, prN}, // So [6] WHITE SHOGI PIECE..BLACK RIGHT POINTING INDEX
+ {0x261C, 0x261C, prA}, // So WHITE LEFT POINTING INDEX
+ {0x261D, 0x261D, prN}, // So WHITE UP POINTING INDEX
+ {0x261E, 0x261E, prA}, // So WHITE RIGHT POINTING INDEX
+ {0x261F, 0x263F, prN}, // So [33] WHITE DOWN POINTING INDEX..MERCURY
+ {0x2640, 0x2640, prA}, // So FEMALE SIGN
+ {0x2641, 0x2641, prN}, // So EARTH
+ {0x2642, 0x2642, prA}, // So MALE SIGN
+ {0x2643, 0x2647, prN}, // So [5] JUPITER..PLUTO
+ {0x2648, 0x2653, prW}, // So [12] ARIES..PISCES
+ {0x2654, 0x265F, prN}, // So [12] WHITE CHESS KING..BLACK CHESS PAWN
+ {0x2660, 0x2661, prA}, // So [2] BLACK SPADE SUIT..WHITE HEART SUIT
+ {0x2662, 0x2662, prN}, // So WHITE DIAMOND SUIT
+ {0x2663, 0x2665, prA}, // So [3] BLACK CLUB SUIT..BLACK HEART SUIT
+ {0x2666, 0x2666, prN}, // So BLACK DIAMOND SUIT
+ {0x2667, 0x266A, prA}, // So [4] WHITE CLUB SUIT..EIGHTH NOTE
+ {0x266B, 0x266B, prN}, // So BEAMED EIGHTH NOTES
+ {0x266C, 0x266D, prA}, // So [2] BEAMED SIXTEENTH NOTES..MUSIC FLAT SIGN
+ {0x266E, 0x266E, prN}, // So MUSIC NATURAL SIGN
+ {0x266F, 0x266F, prA}, // Sm MUSIC SHARP SIGN
+ {0x2670, 0x267E, prN}, // So [15] WEST SYRIAC CROSS..PERMANENT PAPER SIGN
+ {0x267F, 0x267F, prW}, // So WHEELCHAIR SYMBOL
+ {0x2680, 0x2692, prN}, // So [19] DIE FACE-1..HAMMER AND PICK
+ {0x2693, 0x2693, prW}, // So ANCHOR
+ {0x2694, 0x269D, prN}, // So [10] CROSSED SWORDS..OUTLINED WHITE STAR
+ {0x269E, 0x269F, prA}, // So [2] THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT
+ {0x26A0, 0x26A0, prN}, // So WARNING SIGN
+ {0x26A1, 0x26A1, prW}, // So HIGH VOLTAGE SIGN
+ {0x26A2, 0x26A9, prN}, // So [8] DOUBLED FEMALE SIGN..HORIZONTAL MALE WITH STROKE SIGN
+ {0x26AA, 0x26AB, prW}, // So [2] MEDIUM WHITE CIRCLE..MEDIUM BLACK CIRCLE
+ {0x26AC, 0x26BC, prN}, // So [17] MEDIUM SMALL WHITE CIRCLE..SESQUIQUADRATE
+ {0x26BD, 0x26BE, prW}, // So [2] SOCCER BALL..BASEBALL
+ {0x26BF, 0x26BF, prA}, // So SQUARED KEY
+ {0x26C0, 0x26C3, prN}, // So [4] WHITE DRAUGHTS MAN..BLACK DRAUGHTS KING
+ {0x26C4, 0x26C5, prW}, // So [2] SNOWMAN WITHOUT SNOW..SUN BEHIND CLOUD
+ {0x26C6, 0x26CD, prA}, // So [8] RAIN..DISABLED CAR
+ {0x26CE, 0x26CE, prW}, // So OPHIUCHUS
+ {0x26CF, 0x26D3, prA}, // So [5] PICK..CHAINS
+ {0x26D4, 0x26D4, prW}, // So NO ENTRY
+ {0x26D5, 0x26E1, prA}, // So [13] ALTERNATE ONE-WAY LEFT WAY TRAFFIC..RESTRICTED LEFT ENTRY-2
+ {0x26E2, 0x26E2, prN}, // So ASTRONOMICAL SYMBOL FOR URANUS
+ {0x26E3, 0x26E3, prA}, // So HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE
+ {0x26E4, 0x26E7, prN}, // So [4] PENTAGRAM..INVERTED PENTAGRAM
+ {0x26E8, 0x26E9, prA}, // So [2] BLACK CROSS ON SHIELD..SHINTO SHRINE
+ {0x26EA, 0x26EA, prW}, // So CHURCH
+ {0x26EB, 0x26F1, prA}, // So [7] CASTLE..UMBRELLA ON GROUND
+ {0x26F2, 0x26F3, prW}, // So [2] FOUNTAIN..FLAG IN HOLE
+ {0x26F4, 0x26F4, prA}, // So FERRY
+ {0x26F5, 0x26F5, prW}, // So SAILBOAT
+ {0x26F6, 0x26F9, prA}, // So [4] SQUARE FOUR CORNERS..PERSON WITH BALL
+ {0x26FA, 0x26FA, prW}, // So TENT
+ {0x26FB, 0x26FC, prA}, // So [2] JAPANESE BANK SYMBOL..HEADSTONE GRAVEYARD SYMBOL
+ {0x26FD, 0x26FD, prW}, // So FUEL PUMP
+ {0x26FE, 0x26FF, prA}, // So [2] CUP ON BLACK SQUARE..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE
+ {0x2700, 0x2704, prN}, // So [5] BLACK SAFETY SCISSORS..WHITE SCISSORS
+ {0x2705, 0x2705, prW}, // So WHITE HEAVY CHECK MARK
+ {0x2706, 0x2709, prN}, // So [4] TELEPHONE LOCATION SIGN..ENVELOPE
+ {0x270A, 0x270B, prW}, // So [2] RAISED FIST..RAISED HAND
+ {0x270C, 0x2727, prN}, // So [28] VICTORY HAND..WHITE FOUR POINTED STAR
+ {0x2728, 0x2728, prW}, // So SPARKLES
+ {0x2729, 0x273C, prN}, // So [20] STRESS OUTLINED WHITE STAR..OPEN CENTRE TEARDROP-SPOKED ASTERISK
+ {0x273D, 0x273D, prA}, // So HEAVY TEARDROP-SPOKED ASTERISK
+ {0x273E, 0x274B, prN}, // So [14] SIX PETALLED BLACK AND WHITE FLORETTE..HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK
+ {0x274C, 0x274C, prW}, // So CROSS MARK
+ {0x274D, 0x274D, prN}, // So SHADOWED WHITE CIRCLE
+ {0x274E, 0x274E, prW}, // So NEGATIVE SQUARED CROSS MARK
+ {0x274F, 0x2752, prN}, // So [4] LOWER RIGHT DROP-SHADOWED WHITE SQUARE..UPPER RIGHT SHADOWED WHITE SQUARE
+ {0x2753, 0x2755, prW}, // So [3] BLACK QUESTION MARK ORNAMENT..WHITE EXCLAMATION MARK ORNAMENT
+ {0x2756, 0x2756, prN}, // So BLACK DIAMOND MINUS WHITE X
+ {0x2757, 0x2757, prW}, // So HEAVY EXCLAMATION MARK SYMBOL
+ {0x2758, 0x2767, prN}, // So [16] LIGHT VERTICAL BAR..ROTATED FLORAL HEART BULLET
+ {0x2768, 0x2768, prN}, // Ps MEDIUM LEFT PARENTHESIS ORNAMENT
+ {0x2769, 0x2769, prN}, // Pe MEDIUM RIGHT PARENTHESIS ORNAMENT
+ {0x276A, 0x276A, prN}, // Ps MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT
+ {0x276B, 0x276B, prN}, // Pe MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT
+ {0x276C, 0x276C, prN}, // Ps MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT
+ {0x276D, 0x276D, prN}, // Pe MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT
+ {0x276E, 0x276E, prN}, // Ps HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT
+ {0x276F, 0x276F, prN}, // Pe HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT
+ {0x2770, 0x2770, prN}, // Ps HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT
+ {0x2771, 0x2771, prN}, // Pe HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT
+ {0x2772, 0x2772, prN}, // Ps LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT
+ {0x2773, 0x2773, prN}, // Pe LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT
+ {0x2774, 0x2774, prN}, // Ps MEDIUM LEFT CURLY BRACKET ORNAMENT
+ {0x2775, 0x2775, prN}, // Pe MEDIUM RIGHT CURLY BRACKET ORNAMENT
+ {0x2776, 0x277F, prA}, // No [10] DINGBAT NEGATIVE CIRCLED DIGIT ONE..DINGBAT NEGATIVE CIRCLED NUMBER TEN
+ {0x2780, 0x2793, prN}, // No [20] DINGBAT CIRCLED SANS-SERIF DIGIT ONE..DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN
+ {0x2794, 0x2794, prN}, // So HEAVY WIDE-HEADED RIGHTWARDS ARROW
+ {0x2795, 0x2797, prW}, // So [3] HEAVY PLUS SIGN..HEAVY DIVISION SIGN
+ {0x2798, 0x27AF, prN}, // So [24] HEAVY SOUTH EAST ARROW..NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW
+ {0x27B0, 0x27B0, prW}, // So CURLY LOOP
+ {0x27B1, 0x27BE, prN}, // So [14] NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW..OPEN-OUTLINED RIGHTWARDS ARROW
+ {0x27BF, 0x27BF, prW}, // So DOUBLE CURLY LOOP
+ {0x27C0, 0x27C4, prN}, // Sm [5] THREE DIMENSIONAL ANGLE..OPEN SUPERSET
+ {0x27C5, 0x27C5, prN}, // Ps LEFT S-SHAPED BAG DELIMITER
+ {0x27C6, 0x27C6, prN}, // Pe RIGHT S-SHAPED BAG DELIMITER
+ {0x27C7, 0x27E5, prN}, // Sm [31] OR WITH DOT INSIDE..WHITE SQUARE WITH RIGHTWARDS TICK
+ {0x27E6, 0x27E6, prNa}, // Ps MATHEMATICAL LEFT WHITE SQUARE BRACKET
+ {0x27E7, 0x27E7, prNa}, // Pe MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+ {0x27E8, 0x27E8, prNa}, // Ps MATHEMATICAL LEFT ANGLE BRACKET
+ {0x27E9, 0x27E9, prNa}, // Pe MATHEMATICAL RIGHT ANGLE BRACKET
+ {0x27EA, 0x27EA, prNa}, // Ps MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
+ {0x27EB, 0x27EB, prNa}, // Pe MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
+ {0x27EC, 0x27EC, prNa}, // Ps MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET
+ {0x27ED, 0x27ED, prNa}, // Pe MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET
+ {0x27EE, 0x27EE, prN}, // Ps MATHEMATICAL LEFT FLATTENED PARENTHESIS
+ {0x27EF, 0x27EF, prN}, // Pe MATHEMATICAL RIGHT FLATTENED PARENTHESIS
+ {0x27F0, 0x27FF, prN}, // Sm [16] UPWARDS QUADRUPLE ARROW..LONG RIGHTWARDS SQUIGGLE ARROW
+ {0x2800, 0x28FF, prN}, // So [256] BRAILLE PATTERN BLANK..BRAILLE PATTERN DOTS-12345678
+ {0x2900, 0x297F, prN}, // Sm [128] RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE..DOWN FISH TAIL
+ {0x2980, 0x2982, prN}, // Sm [3] TRIPLE VERTICAL BAR DELIMITER..Z NOTATION TYPE COLON
+ {0x2983, 0x2983, prN}, // Ps LEFT WHITE CURLY BRACKET
+ {0x2984, 0x2984, prN}, // Pe RIGHT WHITE CURLY BRACKET
+ {0x2985, 0x2985, prNa}, // Ps LEFT WHITE PARENTHESIS
+ {0x2986, 0x2986, prNa}, // Pe RIGHT WHITE PARENTHESIS
+ {0x2987, 0x2987, prN}, // Ps Z NOTATION LEFT IMAGE BRACKET
+ {0x2988, 0x2988, prN}, // Pe Z NOTATION RIGHT IMAGE BRACKET
+ {0x2989, 0x2989, prN}, // Ps Z NOTATION LEFT BINDING BRACKET
+ {0x298A, 0x298A, prN}, // Pe Z NOTATION RIGHT BINDING BRACKET
+ {0x298B, 0x298B, prN}, // Ps LEFT SQUARE BRACKET WITH UNDERBAR
+ {0x298C, 0x298C, prN}, // Pe RIGHT SQUARE BRACKET WITH UNDERBAR
+ {0x298D, 0x298D, prN}, // Ps LEFT SQUARE BRACKET WITH TICK IN TOP CORNER
+ {0x298E, 0x298E, prN}, // Pe RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+ {0x298F, 0x298F, prN}, // Ps LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+ {0x2990, 0x2990, prN}, // Pe RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER
+ {0x2991, 0x2991, prN}, // Ps LEFT ANGLE BRACKET WITH DOT
+ {0x2992, 0x2992, prN}, // Pe RIGHT ANGLE BRACKET WITH DOT
+ {0x2993, 0x2993, prN}, // Ps LEFT ARC LESS-THAN BRACKET
+ {0x2994, 0x2994, prN}, // Pe RIGHT ARC GREATER-THAN BRACKET
+ {0x2995, 0x2995, prN}, // Ps DOUBLE LEFT ARC GREATER-THAN BRACKET
+ {0x2996, 0x2996, prN}, // Pe DOUBLE RIGHT ARC LESS-THAN BRACKET
+ {0x2997, 0x2997, prN}, // Ps LEFT BLACK TORTOISE SHELL BRACKET
+ {0x2998, 0x2998, prN}, // Pe RIGHT BLACK TORTOISE SHELL BRACKET
+ {0x2999, 0x29D7, prN}, // Sm [63] DOTTED FENCE..BLACK HOURGLASS
+ {0x29D8, 0x29D8, prN}, // Ps LEFT WIGGLY FENCE
+ {0x29D9, 0x29D9, prN}, // Pe RIGHT WIGGLY FENCE
+ {0x29DA, 0x29DA, prN}, // Ps LEFT DOUBLE WIGGLY FENCE
+ {0x29DB, 0x29DB, prN}, // Pe RIGHT DOUBLE WIGGLY FENCE
+ {0x29DC, 0x29FB, prN}, // Sm [32] INCOMPLETE INFINITY..TRIPLE PLUS
+ {0x29FC, 0x29FC, prN}, // Ps LEFT-POINTING CURVED ANGLE BRACKET
+ {0x29FD, 0x29FD, prN}, // Pe RIGHT-POINTING CURVED ANGLE BRACKET
+ {0x29FE, 0x29FF, prN}, // Sm [2] TINY..MINY
+ {0x2A00, 0x2AFF, prN}, // Sm [256] N-ARY CIRCLED DOT OPERATOR..N-ARY WHITE VERTICAL BAR
+ {0x2B00, 0x2B1A, prN}, // So [27] NORTH EAST WHITE ARROW..DOTTED SQUARE
+ {0x2B1B, 0x2B1C, prW}, // So [2] BLACK LARGE SQUARE..WHITE LARGE SQUARE
+ {0x2B1D, 0x2B2F, prN}, // So [19] BLACK VERY SMALL SQUARE..WHITE VERTICAL ELLIPSE
+ {0x2B30, 0x2B44, prN}, // Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET
+ {0x2B45, 0x2B46, prN}, // So [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW
+ {0x2B47, 0x2B4C, prN}, // Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR
+ {0x2B4D, 0x2B4F, prN}, // So [3] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..SHORT BACKSLANTED SOUTH ARROW
+ {0x2B50, 0x2B50, prW}, // So WHITE MEDIUM STAR
+ {0x2B51, 0x2B54, prN}, // So [4] BLACK SMALL STAR..WHITE RIGHT-POINTING PENTAGON
+ {0x2B55, 0x2B55, prW}, // So HEAVY LARGE CIRCLE
+ {0x2B56, 0x2B59, prA}, // So [4] HEAVY OVAL WITH OVAL INSIDE..HEAVY CIRCLED SALTIRE
+ {0x2B5A, 0x2B73, prN}, // So [26] SLANTED NORTH ARROW WITH HOOKED HEAD..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR
+ {0x2B76, 0x2B95, prN}, // So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW
+ {0x2B97, 0x2BFF, prN}, // So [105] SYMBOL FOR TYPE A ELECTRONICS..HELLSCHREIBER PAUSE SYMBOL
+ {0x2C00, 0x2C5F, prN}, // L& [96] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC SMALL LETTER CAUDATE CHRIVI
+ {0x2C60, 0x2C7B, prN}, // L& [28] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN LETTER SMALL CAPITAL TURNED E
+ {0x2C7C, 0x2C7D, prN}, // Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V
+ {0x2C7E, 0x2C7F, prN}, // Lu [2] LATIN CAPITAL LETTER S WITH SWASH TAIL..LATIN CAPITAL LETTER Z WITH SWASH TAIL
+ {0x2C80, 0x2CE4, prN}, // L& [101] COPTIC CAPITAL LETTER ALFA..COPTIC SYMBOL KAI
+ {0x2CE5, 0x2CEA, prN}, // So [6] COPTIC SYMBOL MI RO..COPTIC SYMBOL SHIMA SIMA
+ {0x2CEB, 0x2CEE, prN}, // L& [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA
+ {0x2CEF, 0x2CF1, prN}, // Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS
+ {0x2CF2, 0x2CF3, prN}, // L& [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI
+ {0x2CF9, 0x2CFC, prN}, // Po [4] COPTIC OLD NUBIAN FULL STOP..COPTIC OLD NUBIAN VERSE DIVIDER
+ {0x2CFD, 0x2CFD, prN}, // No COPTIC FRACTION ONE HALF
+ {0x2CFE, 0x2CFF, prN}, // Po [2] COPTIC FULL STOP..COPTIC MORPHOLOGICAL DIVIDER
+ {0x2D00, 0x2D25, prN}, // Ll [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+ {0x2D27, 0x2D27, prN}, // Ll GEORGIAN SMALL LETTER YN
+ {0x2D2D, 0x2D2D, prN}, // Ll GEORGIAN SMALL LETTER AEN
+ {0x2D30, 0x2D67, prN}, // Lo [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO
+ {0x2D6F, 0x2D6F, prN}, // Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK
+ {0x2D70, 0x2D70, prN}, // Po TIFINAGH SEPARATOR MARK
+ {0x2D7F, 0x2D7F, prN}, // Mn TIFINAGH CONSONANT JOINER
+ {0x2D80, 0x2D96, prN}, // Lo [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE
+ {0x2DA0, 0x2DA6, prN}, // Lo [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO
+ {0x2DA8, 0x2DAE, prN}, // Lo [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO
+ {0x2DB0, 0x2DB6, prN}, // Lo [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO
+ {0x2DB8, 0x2DBE, prN}, // Lo [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO
+ {0x2DC0, 0x2DC6, prN}, // Lo [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO
+ {0x2DC8, 0x2DCE, prN}, // Lo [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO
+ {0x2DD0, 0x2DD6, prN}, // Lo [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO
+ {0x2DD8, 0x2DDE, prN}, // Lo [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO
+ {0x2DE0, 0x2DFF, prN}, // Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
+ {0x2E00, 0x2E01, prN}, // Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER
+ {0x2E02, 0x2E02, prN}, // Pi LEFT SUBSTITUTION BRACKET
+ {0x2E03, 0x2E03, prN}, // Pf RIGHT SUBSTITUTION BRACKET
+ {0x2E04, 0x2E04, prN}, // Pi LEFT DOTTED SUBSTITUTION BRACKET
+ {0x2E05, 0x2E05, prN}, // Pf RIGHT DOTTED SUBSTITUTION BRACKET
+ {0x2E06, 0x2E08, prN}, // Po [3] RAISED INTERPOLATION MARKER..DOTTED TRANSPOSITION MARKER
+ {0x2E09, 0x2E09, prN}, // Pi LEFT TRANSPOSITION BRACKET
+ {0x2E0A, 0x2E0A, prN}, // Pf RIGHT TRANSPOSITION BRACKET
+ {0x2E0B, 0x2E0B, prN}, // Po RAISED SQUARE
+ {0x2E0C, 0x2E0C, prN}, // Pi LEFT RAISED OMISSION BRACKET
+ {0x2E0D, 0x2E0D, prN}, // Pf RIGHT RAISED OMISSION BRACKET
+ {0x2E0E, 0x2E16, prN}, // Po [9] EDITORIAL CORONIS..DOTTED RIGHT-POINTING ANGLE
+ {0x2E17, 0x2E17, prN}, // Pd DOUBLE OBLIQUE HYPHEN
+ {0x2E18, 0x2E19, prN}, // Po [2] INVERTED INTERROBANG..PALM BRANCH
+ {0x2E1A, 0x2E1A, prN}, // Pd HYPHEN WITH DIAERESIS
+ {0x2E1B, 0x2E1B, prN}, // Po TILDE WITH RING ABOVE
+ {0x2E1C, 0x2E1C, prN}, // Pi LEFT LOW PARAPHRASE BRACKET
+ {0x2E1D, 0x2E1D, prN}, // Pf RIGHT LOW PARAPHRASE BRACKET
+ {0x2E1E, 0x2E1F, prN}, // Po [2] TILDE WITH DOT ABOVE..TILDE WITH DOT BELOW
+ {0x2E20, 0x2E20, prN}, // Pi LEFT VERTICAL BAR WITH QUILL
+ {0x2E21, 0x2E21, prN}, // Pf RIGHT VERTICAL BAR WITH QUILL
+ {0x2E22, 0x2E22, prN}, // Ps TOP LEFT HALF BRACKET
+ {0x2E23, 0x2E23, prN}, // Pe TOP RIGHT HALF BRACKET
+ {0x2E24, 0x2E24, prN}, // Ps BOTTOM LEFT HALF BRACKET
+ {0x2E25, 0x2E25, prN}, // Pe BOTTOM RIGHT HALF BRACKET
+ {0x2E26, 0x2E26, prN}, // Ps LEFT SIDEWAYS U BRACKET
+ {0x2E27, 0x2E27, prN}, // Pe RIGHT SIDEWAYS U BRACKET
+ {0x2E28, 0x2E28, prN}, // Ps LEFT DOUBLE PARENTHESIS
+ {0x2E29, 0x2E29, prN}, // Pe RIGHT DOUBLE PARENTHESIS
+ {0x2E2A, 0x2E2E, prN}, // Po [5] TWO DOTS OVER ONE DOT PUNCTUATION..REVERSED QUESTION MARK
+ {0x2E2F, 0x2E2F, prN}, // Lm VERTICAL TILDE
+ {0x2E30, 0x2E39, prN}, // Po [10] RING POINT..TOP HALF SECTION SIGN
+ {0x2E3A, 0x2E3B, prN}, // Pd [2] TWO-EM DASH..THREE-EM DASH
+ {0x2E3C, 0x2E3F, prN}, // Po [4] STENOGRAPHIC FULL STOP..CAPITULUM
+ {0x2E40, 0x2E40, prN}, // Pd DOUBLE HYPHEN
+ {0x2E41, 0x2E41, prN}, // Po REVERSED COMMA
+ {0x2E42, 0x2E42, prN}, // Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK
+ {0x2E43, 0x2E4F, prN}, // Po [13] DASH WITH LEFT UPTURN..CORNISH VERSE DIVIDER
+ {0x2E50, 0x2E51, prN}, // So [2] CROSS PATTY WITH RIGHT CROSSBAR..CROSS PATTY WITH LEFT CROSSBAR
+ {0x2E52, 0x2E54, prN}, // Po [3] TIRONIAN SIGN CAPITAL ET..MEDIEVAL QUESTION MARK
+ {0x2E55, 0x2E55, prN}, // Ps LEFT SQUARE BRACKET WITH STROKE
+ {0x2E56, 0x2E56, prN}, // Pe RIGHT SQUARE BRACKET WITH STROKE
+ {0x2E57, 0x2E57, prN}, // Ps LEFT SQUARE BRACKET WITH DOUBLE STROKE
+ {0x2E58, 0x2E58, prN}, // Pe RIGHT SQUARE BRACKET WITH DOUBLE STROKE
+ {0x2E59, 0x2E59, prN}, // Ps TOP HALF LEFT PARENTHESIS
+ {0x2E5A, 0x2E5A, prN}, // Pe TOP HALF RIGHT PARENTHESIS
+ {0x2E5B, 0x2E5B, prN}, // Ps BOTTOM HALF LEFT PARENTHESIS
+ {0x2E5C, 0x2E5C, prN}, // Pe BOTTOM HALF RIGHT PARENTHESIS
+ {0x2E5D, 0x2E5D, prN}, // Pd OBLIQUE HYPHEN
+ {0x2E80, 0x2E99, prW}, // So [26] CJK RADICAL REPEAT..CJK RADICAL RAP
+ {0x2E9B, 0x2EF3, prW}, // So [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE
+ {0x2F00, 0x2FD5, prW}, // So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE
+ {0x2FF0, 0x2FFB, prW}, // So [12] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID
+ {0x3000, 0x3000, prF}, // Zs IDEOGRAPHIC SPACE
+ {0x3001, 0x3003, prW}, // Po [3] IDEOGRAPHIC COMMA..DITTO MARK
+ {0x3004, 0x3004, prW}, // So JAPANESE INDUSTRIAL STANDARD SYMBOL
+ {0x3005, 0x3005, prW}, // Lm IDEOGRAPHIC ITERATION MARK
+ {0x3006, 0x3006, prW}, // Lo IDEOGRAPHIC CLOSING MARK
+ {0x3007, 0x3007, prW}, // Nl IDEOGRAPHIC NUMBER ZERO
+ {0x3008, 0x3008, prW}, // Ps LEFT ANGLE BRACKET
+ {0x3009, 0x3009, prW}, // Pe RIGHT ANGLE BRACKET
+ {0x300A, 0x300A, prW}, // Ps LEFT DOUBLE ANGLE BRACKET
+ {0x300B, 0x300B, prW}, // Pe RIGHT DOUBLE ANGLE BRACKET
+ {0x300C, 0x300C, prW}, // Ps LEFT CORNER BRACKET
+ {0x300D, 0x300D, prW}, // Pe RIGHT CORNER BRACKET
+ {0x300E, 0x300E, prW}, // Ps LEFT WHITE CORNER BRACKET
+ {0x300F, 0x300F, prW}, // Pe RIGHT WHITE CORNER BRACKET
+ {0x3010, 0x3010, prW}, // Ps LEFT BLACK LENTICULAR BRACKET
+ {0x3011, 0x3011, prW}, // Pe RIGHT BLACK LENTICULAR BRACKET
+ {0x3012, 0x3013, prW}, // So [2] POSTAL MARK..GETA MARK
+ {0x3014, 0x3014, prW}, // Ps LEFT TORTOISE SHELL BRACKET
+ {0x3015, 0x3015, prW}, // Pe RIGHT TORTOISE SHELL BRACKET
+ {0x3016, 0x3016, prW}, // Ps LEFT WHITE LENTICULAR BRACKET
+ {0x3017, 0x3017, prW}, // Pe RIGHT WHITE LENTICULAR BRACKET
+ {0x3018, 0x3018, prW}, // Ps LEFT WHITE TORTOISE SHELL BRACKET
+ {0x3019, 0x3019, prW}, // Pe RIGHT WHITE TORTOISE SHELL BRACKET
+ {0x301A, 0x301A, prW}, // Ps LEFT WHITE SQUARE BRACKET
+ {0x301B, 0x301B, prW}, // Pe RIGHT WHITE SQUARE BRACKET
+ {0x301C, 0x301C, prW}, // Pd WAVE DASH
+ {0x301D, 0x301D, prW}, // Ps REVERSED DOUBLE PRIME QUOTATION MARK
+ {0x301E, 0x301F, prW}, // Pe [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK
+ {0x3020, 0x3020, prW}, // So POSTAL MARK FACE
+ {0x3021, 0x3029, prW}, // Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE
+ {0x302A, 0x302D, prW}, // Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK
+ {0x302E, 0x302F, prW}, // Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK
+ {0x3030, 0x3030, prW}, // Pd WAVY DASH
+ {0x3031, 0x3035, prW}, // Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF
+ {0x3036, 0x3037, prW}, // So [2] CIRCLED POSTAL MARK..IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL
+ {0x3038, 0x303A, prW}, // Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY
+ {0x303B, 0x303B, prW}, // Lm VERTICAL IDEOGRAPHIC ITERATION MARK
+ {0x303C, 0x303C, prW}, // Lo MASU MARK
+ {0x303D, 0x303D, prW}, // Po PART ALTERNATION MARK
+ {0x303E, 0x303E, prW}, // So IDEOGRAPHIC VARIATION INDICATOR
+ {0x303F, 0x303F, prN}, // So IDEOGRAPHIC HALF FILL SPACE
+ {0x3041, 0x3096, prW}, // Lo [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE
+ {0x3099, 0x309A, prW}, // Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+ {0x309B, 0x309C, prW}, // Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+ {0x309D, 0x309E, prW}, // Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK
+ {0x309F, 0x309F, prW}, // Lo HIRAGANA DIGRAPH YORI
+ {0x30A0, 0x30A0, prW}, // Pd KATAKANA-HIRAGANA DOUBLE HYPHEN
+ {0x30A1, 0x30FA, prW}, // Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO
+ {0x30FB, 0x30FB, prW}, // Po KATAKANA MIDDLE DOT
+ {0x30FC, 0x30FE, prW}, // Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK
+ {0x30FF, 0x30FF, prW}, // Lo KATAKANA DIGRAPH KOTO
+ {0x3105, 0x312F, prW}, // Lo [43] BOPOMOFO LETTER B..BOPOMOFO LETTER NN
+ {0x3131, 0x318E, prW}, // Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE
+ {0x3190, 0x3191, prW}, // So [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK
+ {0x3192, 0x3195, prW}, // No [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK
+ {0x3196, 0x319F, prW}, // So [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK
+ {0x31A0, 0x31BF, prW}, // Lo [32] BOPOMOFO LETTER BU..BOPOMOFO LETTER AH
+ {0x31C0, 0x31E3, prW}, // So [36] CJK STROKE T..CJK STROKE Q
+ {0x31F0, 0x31FF, prW}, // Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO
+ {0x3200, 0x321E, prW}, // So [31] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED KOREAN CHARACTER O HU
+ {0x3220, 0x3229, prW}, // No [10] PARENTHESIZED IDEOGRAPH ONE..PARENTHESIZED IDEOGRAPH TEN
+ {0x322A, 0x3247, prW}, // So [30] PARENTHESIZED IDEOGRAPH MOON..CIRCLED IDEOGRAPH KOTO
+ {0x3248, 0x324F, prA}, // No [8] CIRCLED NUMBER TEN ON BLACK SQUARE..CIRCLED NUMBER EIGHTY ON BLACK SQUARE
+ {0x3250, 0x3250, prW}, // So PARTNERSHIP SIGN
+ {0x3251, 0x325F, prW}, // No [15] CIRCLED NUMBER TWENTY ONE..CIRCLED NUMBER THIRTY FIVE
+ {0x3260, 0x327F, prW}, // So [32] CIRCLED HANGUL KIYEOK..KOREAN STANDARD SYMBOL
+ {0x3280, 0x3289, prW}, // No [10] CIRCLED IDEOGRAPH ONE..CIRCLED IDEOGRAPH TEN
+ {0x328A, 0x32B0, prW}, // So [39] CIRCLED IDEOGRAPH MOON..CIRCLED IDEOGRAPH NIGHT
+ {0x32B1, 0x32BF, prW}, // No [15] CIRCLED NUMBER THIRTY SIX..CIRCLED NUMBER FIFTY
+ {0x32C0, 0x32FF, prW}, // So [64] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..SQUARE ERA NAME REIWA
+ {0x3300, 0x33FF, prW}, // So [256] SQUARE APAATO..SQUARE GAL
+ {0x3400, 0x4DBF, prW}, // Lo [6592] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DBF
+ {0x4DC0, 0x4DFF, prN}, // So [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION
+ {0x4E00, 0x9FFF, prW}, // Lo [20992] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFF
+ {0xA000, 0xA014, prW}, // Lo [21] YI SYLLABLE IT..YI SYLLABLE E
+ {0xA015, 0xA015, prW}, // Lm YI SYLLABLE WU
+ {0xA016, 0xA48C, prW}, // Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR
+ {0xA490, 0xA4C6, prW}, // So [55] YI RADICAL QOT..YI RADICAL KE
+ {0xA4D0, 0xA4F7, prN}, // Lo [40] LISU LETTER BA..LISU LETTER OE
+ {0xA4F8, 0xA4FD, prN}, // Lm [6] LISU LETTER TONE MYA TI..LISU LETTER TONE MYA JEU
+ {0xA4FE, 0xA4FF, prN}, // Po [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP
+ {0xA500, 0xA60B, prN}, // Lo [268] VAI SYLLABLE EE..VAI SYLLABLE NG
+ {0xA60C, 0xA60C, prN}, // Lm VAI SYLLABLE LENGTHENER
+ {0xA60D, 0xA60F, prN}, // Po [3] VAI COMMA..VAI QUESTION MARK
+ {0xA610, 0xA61F, prN}, // Lo [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG
+ {0xA620, 0xA629, prN}, // Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE
+ {0xA62A, 0xA62B, prN}, // Lo [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO
+ {0xA640, 0xA66D, prN}, // L& [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+ {0xA66E, 0xA66E, prN}, // Lo CYRILLIC LETTER MULTIOCULAR O
+ {0xA66F, 0xA66F, prN}, // Mn COMBINING CYRILLIC VZMET
+ {0xA670, 0xA672, prN}, // Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN
+ {0xA673, 0xA673, prN}, // Po SLAVONIC ASTERISK
+ {0xA674, 0xA67D, prN}, // Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK
+ {0xA67E, 0xA67E, prN}, // Po CYRILLIC KAVYKA
+ {0xA67F, 0xA67F, prN}, // Lm CYRILLIC PAYEROK
+ {0xA680, 0xA69B, prN}, // L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O
+ {0xA69C, 0xA69D, prN}, // Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN
+ {0xA69E, 0xA69F, prN}, // Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E
+ {0xA6A0, 0xA6E5, prN}, // Lo [70] BAMUM LETTER A..BAMUM LETTER KI
+ {0xA6E6, 0xA6EF, prN}, // Nl [10] BAMUM LETTER MO..BAMUM LETTER KOGHOM
+ {0xA6F0, 0xA6F1, prN}, // Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS
+ {0xA6F2, 0xA6F7, prN}, // Po [6] BAMUM NJAEMLI..BAMUM QUESTION MARK
+ {0xA700, 0xA716, prN}, // Sk [23] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR
+ {0xA717, 0xA71F, prN}, // Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK
+ {0xA720, 0xA721, prN}, // Sk [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE
+ {0xA722, 0xA76F, prN}, // L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON
+ {0xA770, 0xA770, prN}, // Lm MODIFIER LETTER US
+ {0xA771, 0xA787, prN}, // L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T
+ {0xA788, 0xA788, prN}, // Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT
+ {0xA789, 0xA78A, prN}, // Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN
+ {0xA78B, 0xA78E, prN}, // L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT
+ {0xA78F, 0xA78F, prN}, // Lo LATIN LETTER SINOLOGICAL DOT
+ {0xA790, 0xA7CA, prN}, // L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY
+ {0xA7D0, 0xA7D1, prN}, // L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G
+ {0xA7D3, 0xA7D3, prN}, // Ll LATIN SMALL LETTER DOUBLE THORN
+ {0xA7D5, 0xA7D9, prN}, // L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S
+ {0xA7F2, 0xA7F4, prN}, // Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q
+ {0xA7F5, 0xA7F6, prN}, // L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H
+ {0xA7F7, 0xA7F7, prN}, // Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I
+ {0xA7F8, 0xA7F9, prN}, // Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
+ {0xA7FA, 0xA7FA, prN}, // Ll LATIN LETTER SMALL CAPITAL TURNED M
+ {0xA7FB, 0xA7FF, prN}, // Lo [5] LATIN EPIGRAPHIC LETTER REVERSED F..LATIN EPIGRAPHIC LETTER ARCHAIC M
+ {0xA800, 0xA801, prN}, // Lo [2] SYLOTI NAGRI LETTER A..SYLOTI NAGRI LETTER I
+ {0xA802, 0xA802, prN}, // Mn SYLOTI NAGRI SIGN DVISVARA
+ {0xA803, 0xA805, prN}, // Lo [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O
+ {0xA806, 0xA806, prN}, // Mn SYLOTI NAGRI SIGN HASANTA
+ {0xA807, 0xA80A, prN}, // Lo [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO
+ {0xA80B, 0xA80B, prN}, // Mn SYLOTI NAGRI SIGN ANUSVARA
+ {0xA80C, 0xA822, prN}, // Lo [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO
+ {0xA823, 0xA824, prN}, // Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I
+ {0xA825, 0xA826, prN}, // Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
+ {0xA827, 0xA827, prN}, // Mc SYLOTI NAGRI VOWEL SIGN OO
+ {0xA828, 0xA82B, prN}, // So [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI POETRY MARK-4
+ {0xA82C, 0xA82C, prN}, // Mn SYLOTI NAGRI SIGN ALTERNATE HASANTA
+ {0xA830, 0xA835, prN}, // No [6] NORTH INDIC FRACTION ONE QUARTER..NORTH INDIC FRACTION THREE SIXTEENTHS
+ {0xA836, 0xA837, prN}, // So [2] NORTH INDIC QUARTER MARK..NORTH INDIC PLACEHOLDER MARK
+ {0xA838, 0xA838, prN}, // Sc NORTH INDIC RUPEE MARK
+ {0xA839, 0xA839, prN}, // So NORTH INDIC QUANTITY MARK
+ {0xA840, 0xA873, prN}, // Lo [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU
+ {0xA874, 0xA877, prN}, // Po [4] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA MARK DOUBLE SHAD
+ {0xA880, 0xA881, prN}, // Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA
+ {0xA882, 0xA8B3, prN}, // Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA
+ {0xA8B4, 0xA8C3, prN}, // Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU
+ {0xA8C4, 0xA8C5, prN}, // Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU
+ {0xA8CE, 0xA8CF, prN}, // Po [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA
+ {0xA8D0, 0xA8D9, prN}, // Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
+ {0xA8E0, 0xA8F1, prN}, // Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA
+ {0xA8F2, 0xA8F7, prN}, // Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA
+ {0xA8F8, 0xA8FA, prN}, // Po [3] DEVANAGARI SIGN PUSHPIKA..DEVANAGARI CARET
+ {0xA8FB, 0xA8FB, prN}, // Lo DEVANAGARI HEADSTROKE
+ {0xA8FC, 0xA8FC, prN}, // Po DEVANAGARI SIGN SIDDHAM
+ {0xA8FD, 0xA8FE, prN}, // Lo [2] DEVANAGARI JAIN OM..DEVANAGARI LETTER AY
+ {0xA8FF, 0xA8FF, prN}, // Mn DEVANAGARI VOWEL SIGN AY
+ {0xA900, 0xA909, prN}, // Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
+ {0xA90A, 0xA925, prN}, // Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO
+ {0xA926, 0xA92D, prN}, // Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU
+ {0xA92E, 0xA92F, prN}, // Po [2] KAYAH LI SIGN CWI..KAYAH LI SIGN SHYA
+ {0xA930, 0xA946, prN}, // Lo [23] REJANG LETTER KA..REJANG LETTER A
+ {0xA947, 0xA951, prN}, // Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
+ {0xA952, 0xA953, prN}, // Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA
+ {0xA95F, 0xA95F, prN}, // Po REJANG SECTION MARK
+ {0xA960, 0xA97C, prW}, // Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH
+ {0xA980, 0xA982, prN}, // Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR
+ {0xA983, 0xA983, prN}, // Mc JAVANESE SIGN WIGNYAN
+ {0xA984, 0xA9B2, prN}, // Lo [47] JAVANESE LETTER A..JAVANESE LETTER HA
+ {0xA9B3, 0xA9B3, prN}, // Mn JAVANESE SIGN CECAK TELU
+ {0xA9B4, 0xA9B5, prN}, // Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG
+ {0xA9B6, 0xA9B9, prN}, // Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT
+ {0xA9BA, 0xA9BB, prN}, // Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE
+ {0xA9BC, 0xA9BD, prN}, // Mn [2] JAVANESE VOWEL SIGN PEPET..JAVANESE CONSONANT SIGN KERET
+ {0xA9BE, 0xA9C0, prN}, // Mc [3] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE PANGKON
+ {0xA9C1, 0xA9CD, prN}, // Po [13] JAVANESE LEFT RERENGGAN..JAVANESE TURNED PADA PISELEH
+ {0xA9CF, 0xA9CF, prN}, // Lm JAVANESE PANGRANGKEP
+ {0xA9D0, 0xA9D9, prN}, // Nd [10] JAVANESE DIGIT ZERO..JAVANESE DIGIT NINE
+ {0xA9DE, 0xA9DF, prN}, // Po [2] JAVANESE PADA TIRTA TUMETES..JAVANESE PADA ISEN-ISEN
+ {0xA9E0, 0xA9E4, prN}, // Lo [5] MYANMAR LETTER SHAN GHA..MYANMAR LETTER SHAN BHA
+ {0xA9E5, 0xA9E5, prN}, // Mn MYANMAR SIGN SHAN SAW
+ {0xA9E6, 0xA9E6, prN}, // Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION
+ {0xA9E7, 0xA9EF, prN}, // Lo [9] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING NNA
+ {0xA9F0, 0xA9F9, prN}, // Nd [10] MYANMAR TAI LAING DIGIT ZERO..MYANMAR TAI LAING DIGIT NINE
+ {0xA9FA, 0xA9FE, prN}, // Lo [5] MYANMAR LETTER TAI LAING LLA..MYANMAR LETTER TAI LAING BHA
+ {0xAA00, 0xAA28, prN}, // Lo [41] CHAM LETTER A..CHAM LETTER HA
+ {0xAA29, 0xAA2E, prN}, // Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE
+ {0xAA2F, 0xAA30, prN}, // Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI
+ {0xAA31, 0xAA32, prN}, // Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE
+ {0xAA33, 0xAA34, prN}, // Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA
+ {0xAA35, 0xAA36, prN}, // Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA
+ {0xAA40, 0xAA42, prN}, // Lo [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG
+ {0xAA43, 0xAA43, prN}, // Mn CHAM CONSONANT SIGN FINAL NG
+ {0xAA44, 0xAA4B, prN}, // Lo [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS
+ {0xAA4C, 0xAA4C, prN}, // Mn CHAM CONSONANT SIGN FINAL M
+ {0xAA4D, 0xAA4D, prN}, // Mc CHAM CONSONANT SIGN FINAL H
+ {0xAA50, 0xAA59, prN}, // Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
+ {0xAA5C, 0xAA5F, prN}, // Po [4] CHAM PUNCTUATION SPIRAL..CHAM PUNCTUATION TRIPLE DANDA
+ {0xAA60, 0xAA6F, prN}, // Lo [16] MYANMAR LETTER KHAMTI GA..MYANMAR LETTER KHAMTI FA
+ {0xAA70, 0xAA70, prN}, // Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION
+ {0xAA71, 0xAA76, prN}, // Lo [6] MYANMAR LETTER KHAMTI XA..MYANMAR LOGOGRAM KHAMTI HM
+ {0xAA77, 0xAA79, prN}, // So [3] MYANMAR SYMBOL AITON EXCLAMATION..MYANMAR SYMBOL AITON TWO
+ {0xAA7A, 0xAA7A, prN}, // Lo MYANMAR LETTER AITON RA
+ {0xAA7B, 0xAA7B, prN}, // Mc MYANMAR SIGN PAO KAREN TONE
+ {0xAA7C, 0xAA7C, prN}, // Mn MYANMAR SIGN TAI LAING TONE-2
+ {0xAA7D, 0xAA7D, prN}, // Mc MYANMAR SIGN TAI LAING TONE-5
+ {0xAA7E, 0xAA7F, prN}, // Lo [2] MYANMAR LETTER SHWE PALAUNG CHA..MYANMAR LETTER SHWE PALAUNG SHA
+ {0xAA80, 0xAAAF, prN}, // Lo [48] TAI VIET LETTER LOW KO..TAI VIET LETTER HIGH O
+ {0xAAB0, 0xAAB0, prN}, // Mn TAI VIET MAI KANG
+ {0xAAB1, 0xAAB1, prN}, // Lo TAI VIET VOWEL AA
+ {0xAAB2, 0xAAB4, prN}, // Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U
+ {0xAAB5, 0xAAB6, prN}, // Lo [2] TAI VIET VOWEL E..TAI VIET VOWEL O
+ {0xAAB7, 0xAAB8, prN}, // Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA
+ {0xAAB9, 0xAABD, prN}, // Lo [5] TAI VIET VOWEL UEA..TAI VIET VOWEL AN
+ {0xAABE, 0xAABF, prN}, // Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK
+ {0xAAC0, 0xAAC0, prN}, // Lo TAI VIET TONE MAI NUENG
+ {0xAAC1, 0xAAC1, prN}, // Mn TAI VIET TONE MAI THO
+ {0xAAC2, 0xAAC2, prN}, // Lo TAI VIET TONE MAI SONG
+ {0xAADB, 0xAADC, prN}, // Lo [2] TAI VIET SYMBOL KON..TAI VIET SYMBOL NUENG
+ {0xAADD, 0xAADD, prN}, // Lm TAI VIET SYMBOL SAM
+ {0xAADE, 0xAADF, prN}, // Po [2] TAI VIET SYMBOL HO HOI..TAI VIET SYMBOL KOI KOI
+ {0xAAE0, 0xAAEA, prN}, // Lo [11] MEETEI MAYEK LETTER E..MEETEI MAYEK LETTER SSA
+ {0xAAEB, 0xAAEB, prN}, // Mc MEETEI MAYEK VOWEL SIGN II
+ {0xAAEC, 0xAAED, prN}, // Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI
+ {0xAAEE, 0xAAEF, prN}, // Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU
+ {0xAAF0, 0xAAF1, prN}, // Po [2] MEETEI MAYEK CHEIKHAN..MEETEI MAYEK AHANG KHUDAM
+ {0xAAF2, 0xAAF2, prN}, // Lo MEETEI MAYEK ANJI
+ {0xAAF3, 0xAAF4, prN}, // Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK
+ {0xAAF5, 0xAAF5, prN}, // Mc MEETEI MAYEK VOWEL SIGN VISARGA
+ {0xAAF6, 0xAAF6, prN}, // Mn MEETEI MAYEK VIRAMA
+ {0xAB01, 0xAB06, prN}, // Lo [6] ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO
+ {0xAB09, 0xAB0E, prN}, // Lo [6] ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO
+ {0xAB11, 0xAB16, prN}, // Lo [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO
+ {0xAB20, 0xAB26, prN}, // Lo [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO
+ {0xAB28, 0xAB2E, prN}, // Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO
+ {0xAB30, 0xAB5A, prN}, // Ll [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG
+ {0xAB5B, 0xAB5B, prN}, // Sk MODIFIER BREVE WITH INVERTED BREVE
+ {0xAB5C, 0xAB5F, prN}, // Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
+ {0xAB60, 0xAB68, prN}, // Ll [9] LATIN SMALL LETTER SAKHA YAT..LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE
+ {0xAB69, 0xAB69, prN}, // Lm MODIFIER LETTER SMALL TURNED W
+ {0xAB6A, 0xAB6B, prN}, // Sk [2] MODIFIER LETTER LEFT TACK..MODIFIER LETTER RIGHT TACK
+ {0xAB70, 0xABBF, prN}, // Ll [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
+ {0xABC0, 0xABE2, prN}, // Lo [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM
+ {0xABE3, 0xABE4, prN}, // Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP
+ {0xABE5, 0xABE5, prN}, // Mn MEETEI MAYEK VOWEL SIGN ANAP
+ {0xABE6, 0xABE7, prN}, // Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP
+ {0xABE8, 0xABE8, prN}, // Mn MEETEI MAYEK VOWEL SIGN UNAP
+ {0xABE9, 0xABEA, prN}, // Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG
+ {0xABEB, 0xABEB, prN}, // Po MEETEI MAYEK CHEIKHEI
+ {0xABEC, 0xABEC, prN}, // Mc MEETEI MAYEK LUM IYEK
+ {0xABED, 0xABED, prN}, // Mn MEETEI MAYEK APUN IYEK
+ {0xABF0, 0xABF9, prN}, // Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT NINE
+ {0xAC00, 0xD7A3, prW}, // Lo [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH
+ {0xD7B0, 0xD7C6, prN}, // Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E
+ {0xD7CB, 0xD7FB, prN}, // Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH
+ {0xD800, 0xDB7F, prN}, // Cs [896] ..
+ {0xDB80, 0xDBFF, prN}, // Cs [128] ..
+ {0xDC00, 0xDFFF, prN}, // Cs [1024] ..
+ {0xE000, 0xF8FF, prA}, // Co [6400] ..
+ {0xF900, 0xFA6D, prW}, // Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D
+ {0xFA6E, 0xFA6F, prW}, // Cn [2] ..
+ {0xFA70, 0xFAD9, prW}, // Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9
+ {0xFADA, 0xFAFF, prW}, // Cn [38] ..
+ {0xFB00, 0xFB06, prN}, // Ll [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+ {0xFB13, 0xFB17, prN}, // Ll [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+ {0xFB1D, 0xFB1D, prN}, // Lo HEBREW LETTER YOD WITH HIRIQ
+ {0xFB1E, 0xFB1E, prN}, // Mn HEBREW POINT JUDEO-SPANISH VARIKA
+ {0xFB1F, 0xFB28, prN}, // Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV
+ {0xFB29, 0xFB29, prN}, // Sm HEBREW LETTER ALTERNATIVE PLUS SIGN
+ {0xFB2A, 0xFB36, prN}, // Lo [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH
+ {0xFB38, 0xFB3C, prN}, // Lo [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH
+ {0xFB3E, 0xFB3E, prN}, // Lo HEBREW LETTER MEM WITH DAGESH
+ {0xFB40, 0xFB41, prN}, // Lo [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH
+ {0xFB43, 0xFB44, prN}, // Lo [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH
+ {0xFB46, 0xFB4F, prN}, // Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATURE ALEF LAMED
+ {0xFB50, 0xFBB1, prN}, // Lo [98] ARABIC LETTER ALEF WASLA ISOLATED FORM..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM
+ {0xFBB2, 0xFBC2, prN}, // Sk [17] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL WASLA ABOVE
+ {0xFBD3, 0xFD3D, prN}, // Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM
+ {0xFD3E, 0xFD3E, prN}, // Pe ORNATE LEFT PARENTHESIS
+ {0xFD3F, 0xFD3F, prN}, // Ps ORNATE RIGHT PARENTHESIS
+ {0xFD40, 0xFD4F, prN}, // So [16] ARABIC LIGATURE RAHIMAHU ALLAAH..ARABIC LIGATURE RAHIMAHUM ALLAAH
+ {0xFD50, 0xFD8F, prN}, // Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM
+ {0xFD92, 0xFDC7, prN}, // Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM
+ {0xFDCF, 0xFDCF, prN}, // So ARABIC LIGATURE SALAAMUHU ALAYNAA
+ {0xFDF0, 0xFDFB, prN}, // Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU
+ {0xFDFC, 0xFDFC, prN}, // Sc RIAL SIGN
+ {0xFDFD, 0xFDFF, prN}, // So [3] ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM..ARABIC LIGATURE AZZA WA JALL
+ {0xFE00, 0xFE0F, prA}, // Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+ {0xFE10, 0xFE16, prW}, // Po [7] PRESENTATION FORM FOR VERTICAL COMMA..PRESENTATION FORM FOR VERTICAL QUESTION MARK
+ {0xFE17, 0xFE17, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET
+ {0xFE18, 0xFE18, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET
+ {0xFE19, 0xFE19, prW}, // Po PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS
+ {0xFE20, 0xFE2F, prN}, // Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF
+ {0xFE30, 0xFE30, prW}, // Po PRESENTATION FORM FOR VERTICAL TWO DOT LEADER
+ {0xFE31, 0xFE32, prW}, // Pd [2] PRESENTATION FORM FOR VERTICAL EM DASH..PRESENTATION FORM FOR VERTICAL EN DASH
+ {0xFE33, 0xFE34, prW}, // Pc [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE
+ {0xFE35, 0xFE35, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS
+ {0xFE36, 0xFE36, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS
+ {0xFE37, 0xFE37, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET
+ {0xFE38, 0xFE38, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET
+ {0xFE39, 0xFE39, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET
+ {0xFE3A, 0xFE3A, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET
+ {0xFE3B, 0xFE3B, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET
+ {0xFE3C, 0xFE3C, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET
+ {0xFE3D, 0xFE3D, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET
+ {0xFE3E, 0xFE3E, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET
+ {0xFE3F, 0xFE3F, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET
+ {0xFE40, 0xFE40, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET
+ {0xFE41, 0xFE41, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET
+ {0xFE42, 0xFE42, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET
+ {0xFE43, 0xFE43, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET
+ {0xFE44, 0xFE44, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET
+ {0xFE45, 0xFE46, prW}, // Po [2] SESAME DOT..WHITE SESAME DOT
+ {0xFE47, 0xFE47, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET
+ {0xFE48, 0xFE48, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET
+ {0xFE49, 0xFE4C, prW}, // Po [4] DASHED OVERLINE..DOUBLE WAVY OVERLINE
+ {0xFE4D, 0xFE4F, prW}, // Pc [3] DASHED LOW LINE..WAVY LOW LINE
+ {0xFE50, 0xFE52, prW}, // Po [3] SMALL COMMA..SMALL FULL STOP
+ {0xFE54, 0xFE57, prW}, // Po [4] SMALL SEMICOLON..SMALL EXCLAMATION MARK
+ {0xFE58, 0xFE58, prW}, // Pd SMALL EM DASH
+ {0xFE59, 0xFE59, prW}, // Ps SMALL LEFT PARENTHESIS
+ {0xFE5A, 0xFE5A, prW}, // Pe SMALL RIGHT PARENTHESIS
+ {0xFE5B, 0xFE5B, prW}, // Ps SMALL LEFT CURLY BRACKET
+ {0xFE5C, 0xFE5C, prW}, // Pe SMALL RIGHT CURLY BRACKET
+ {0xFE5D, 0xFE5D, prW}, // Ps SMALL LEFT TORTOISE SHELL BRACKET
+ {0xFE5E, 0xFE5E, prW}, // Pe SMALL RIGHT TORTOISE SHELL BRACKET
+ {0xFE5F, 0xFE61, prW}, // Po [3] SMALL NUMBER SIGN..SMALL ASTERISK
+ {0xFE62, 0xFE62, prW}, // Sm SMALL PLUS SIGN
+ {0xFE63, 0xFE63, prW}, // Pd SMALL HYPHEN-MINUS
+ {0xFE64, 0xFE66, prW}, // Sm [3] SMALL LESS-THAN SIGN..SMALL EQUALS SIGN
+ {0xFE68, 0xFE68, prW}, // Po SMALL REVERSE SOLIDUS
+ {0xFE69, 0xFE69, prW}, // Sc SMALL DOLLAR SIGN
+ {0xFE6A, 0xFE6B, prW}, // Po [2] SMALL PERCENT SIGN..SMALL COMMERCIAL AT
+ {0xFE70, 0xFE74, prN}, // Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM
+ {0xFE76, 0xFEFC, prN}, // Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM
+ {0xFEFF, 0xFEFF, prN}, // Cf ZERO WIDTH NO-BREAK SPACE
+ {0xFF01, 0xFF03, prF}, // Po [3] FULLWIDTH EXCLAMATION MARK..FULLWIDTH NUMBER SIGN
+ {0xFF04, 0xFF04, prF}, // Sc FULLWIDTH DOLLAR SIGN
+ {0xFF05, 0xFF07, prF}, // Po [3] FULLWIDTH PERCENT SIGN..FULLWIDTH APOSTROPHE
+ {0xFF08, 0xFF08, prF}, // Ps FULLWIDTH LEFT PARENTHESIS
+ {0xFF09, 0xFF09, prF}, // Pe FULLWIDTH RIGHT PARENTHESIS
+ {0xFF0A, 0xFF0A, prF}, // Po FULLWIDTH ASTERISK
+ {0xFF0B, 0xFF0B, prF}, // Sm FULLWIDTH PLUS SIGN
+ {0xFF0C, 0xFF0C, prF}, // Po FULLWIDTH COMMA
+ {0xFF0D, 0xFF0D, prF}, // Pd FULLWIDTH HYPHEN-MINUS
+ {0xFF0E, 0xFF0F, prF}, // Po [2] FULLWIDTH FULL STOP..FULLWIDTH SOLIDUS
+ {0xFF10, 0xFF19, prF}, // Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
+ {0xFF1A, 0xFF1B, prF}, // Po [2] FULLWIDTH COLON..FULLWIDTH SEMICOLON
+ {0xFF1C, 0xFF1E, prF}, // Sm [3] FULLWIDTH LESS-THAN SIGN..FULLWIDTH GREATER-THAN SIGN
+ {0xFF1F, 0xFF20, prF}, // Po [2] FULLWIDTH QUESTION MARK..FULLWIDTH COMMERCIAL AT
+ {0xFF21, 0xFF3A, prF}, // Lu [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+ {0xFF3B, 0xFF3B, prF}, // Ps FULLWIDTH LEFT SQUARE BRACKET
+ {0xFF3C, 0xFF3C, prF}, // Po FULLWIDTH REVERSE SOLIDUS
+ {0xFF3D, 0xFF3D, prF}, // Pe FULLWIDTH RIGHT SQUARE BRACKET
+ {0xFF3E, 0xFF3E, prF}, // Sk FULLWIDTH CIRCUMFLEX ACCENT
+ {0xFF3F, 0xFF3F, prF}, // Pc FULLWIDTH LOW LINE
+ {0xFF40, 0xFF40, prF}, // Sk FULLWIDTH GRAVE ACCENT
+ {0xFF41, 0xFF5A, prF}, // Ll [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+ {0xFF5B, 0xFF5B, prF}, // Ps FULLWIDTH LEFT CURLY BRACKET
+ {0xFF5C, 0xFF5C, prF}, // Sm FULLWIDTH VERTICAL LINE
+ {0xFF5D, 0xFF5D, prF}, // Pe FULLWIDTH RIGHT CURLY BRACKET
+ {0xFF5E, 0xFF5E, prF}, // Sm FULLWIDTH TILDE
+ {0xFF5F, 0xFF5F, prF}, // Ps FULLWIDTH LEFT WHITE PARENTHESIS
+ {0xFF60, 0xFF60, prF}, // Pe FULLWIDTH RIGHT WHITE PARENTHESIS
+ {0xFF61, 0xFF61, prH}, // Po HALFWIDTH IDEOGRAPHIC FULL STOP
+ {0xFF62, 0xFF62, prH}, // Ps HALFWIDTH LEFT CORNER BRACKET
+ {0xFF63, 0xFF63, prH}, // Pe HALFWIDTH RIGHT CORNER BRACKET
+ {0xFF64, 0xFF65, prH}, // Po [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDLE DOT
+ {0xFF66, 0xFF6F, prH}, // Lo [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU
+ {0xFF70, 0xFF70, prH}, // Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
+ {0xFF71, 0xFF9D, prH}, // Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N
+ {0xFF9E, 0xFF9F, prH}, // Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+ {0xFFA0, 0xFFBE, prH}, // Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH
+ {0xFFC2, 0xFFC7, prH}, // Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E
+ {0xFFCA, 0xFFCF, prH}, // Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE
+ {0xFFD2, 0xFFD7, prH}, // Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU
+ {0xFFDA, 0xFFDC, prH}, // Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I
+ {0xFFE0, 0xFFE1, prF}, // Sc [2] FULLWIDTH CENT SIGN..FULLWIDTH POUND SIGN
+ {0xFFE2, 0xFFE2, prF}, // Sm FULLWIDTH NOT SIGN
+ {0xFFE3, 0xFFE3, prF}, // Sk FULLWIDTH MACRON
+ {0xFFE4, 0xFFE4, prF}, // So FULLWIDTH BROKEN BAR
+ {0xFFE5, 0xFFE6, prF}, // Sc [2] FULLWIDTH YEN SIGN..FULLWIDTH WON SIGN
+ {0xFFE8, 0xFFE8, prH}, // So HALFWIDTH FORMS LIGHT VERTICAL
+ {0xFFE9, 0xFFEC, prH}, // Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW
+ {0xFFED, 0xFFEE, prH}, // So [2] HALFWIDTH BLACK SQUARE..HALFWIDTH WHITE CIRCLE
+ {0xFFF9, 0xFFFB, prN}, // Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR
+ {0xFFFC, 0xFFFC, prN}, // So OBJECT REPLACEMENT CHARACTER
+ {0xFFFD, 0xFFFD, prA}, // So REPLACEMENT CHARACTER
+ {0x10000, 0x1000B, prN}, // Lo [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE
+ {0x1000D, 0x10026, prN}, // Lo [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO
+ {0x10028, 0x1003A, prN}, // Lo [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO
+ {0x1003C, 0x1003D, prN}, // Lo [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE
+ {0x1003F, 0x1004D, prN}, // Lo [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO
+ {0x10050, 0x1005D, prN}, // Lo [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089
+ {0x10080, 0x100FA, prN}, // Lo [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305
+ {0x10100, 0x10102, prN}, // Po [3] AEGEAN WORD SEPARATOR LINE..AEGEAN CHECK MARK
+ {0x10107, 0x10133, prN}, // No [45] AEGEAN NUMBER ONE..AEGEAN NUMBER NINETY THOUSAND
+ {0x10137, 0x1013F, prN}, // So [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT
+ {0x10140, 0x10174, prN}, // Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS
+ {0x10175, 0x10178, prN}, // No [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN
+ {0x10179, 0x10189, prN}, // So [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN
+ {0x1018A, 0x1018B, prN}, // No [2] GREEK ZERO SIGN..GREEK ONE QUARTER SIGN
+ {0x1018C, 0x1018E, prN}, // So [3] GREEK SINUSOID SIGN..NOMISMA SIGN
+ {0x10190, 0x1019C, prN}, // So [13] ROMAN SEXTANS SIGN..ASCIA SYMBOL
+ {0x101A0, 0x101A0, prN}, // So GREEK SYMBOL TAU RHO
+ {0x101D0, 0x101FC, prN}, // So [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND
+ {0x101FD, 0x101FD, prN}, // Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
+ {0x10280, 0x1029C, prN}, // Lo [29] LYCIAN LETTER A..LYCIAN LETTER X
+ {0x102A0, 0x102D0, prN}, // Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3
+ {0x102E0, 0x102E0, prN}, // Mn COPTIC EPACT THOUSANDS MARK
+ {0x102E1, 0x102FB, prN}, // No [27] COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED
+ {0x10300, 0x1031F, prN}, // Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS
+ {0x10320, 0x10323, prN}, // No [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY
+ {0x1032D, 0x1032F, prN}, // Lo [3] OLD ITALIC LETTER YE..OLD ITALIC LETTER SOUTHERN TSE
+ {0x10330, 0x10340, prN}, // Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA
+ {0x10341, 0x10341, prN}, // Nl GOTHIC LETTER NINETY
+ {0x10342, 0x10349, prN}, // Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL
+ {0x1034A, 0x1034A, prN}, // Nl GOTHIC LETTER NINE HUNDRED
+ {0x10350, 0x10375, prN}, // Lo [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA
+ {0x10376, 0x1037A, prN}, // Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII
+ {0x10380, 0x1039D, prN}, // Lo [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU
+ {0x1039F, 0x1039F, prN}, // Po UGARITIC WORD DIVIDER
+ {0x103A0, 0x103C3, prN}, // Lo [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA
+ {0x103C8, 0x103CF, prN}, // Lo [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH
+ {0x103D0, 0x103D0, prN}, // Po OLD PERSIAN WORD DIVIDER
+ {0x103D1, 0x103D5, prN}, // Nl [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED
+ {0x10400, 0x1044F, prN}, // L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW
+ {0x10450, 0x1047F, prN}, // Lo [48] SHAVIAN LETTER PEEP..SHAVIAN LETTER YEW
+ {0x10480, 0x1049D, prN}, // Lo [30] OSMANYA LETTER ALEF..OSMANYA LETTER OO
+ {0x104A0, 0x104A9, prN}, // Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
+ {0x104B0, 0x104D3, prN}, // Lu [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA
+ {0x104D8, 0x104FB, prN}, // Ll [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA
+ {0x10500, 0x10527, prN}, // Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE
+ {0x10530, 0x10563, prN}, // Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW
+ {0x1056F, 0x1056F, prN}, // Po CAUCASIAN ALBANIAN CITATION MARK
+ {0x10570, 0x1057A, prN}, // Lu [11] VITHKUQI CAPITAL LETTER A..VITHKUQI CAPITAL LETTER GA
+ {0x1057C, 0x1058A, prN}, // Lu [15] VITHKUQI CAPITAL LETTER HA..VITHKUQI CAPITAL LETTER RE
+ {0x1058C, 0x10592, prN}, // Lu [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE
+ {0x10594, 0x10595, prN}, // Lu [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE
+ {0x10597, 0x105A1, prN}, // Ll [11] VITHKUQI SMALL LETTER A..VITHKUQI SMALL LETTER GA
+ {0x105A3, 0x105B1, prN}, // Ll [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE
+ {0x105B3, 0x105B9, prN}, // Ll [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE
+ {0x105BB, 0x105BC, prN}, // Ll [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE
+ {0x10600, 0x10736, prN}, // Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664
+ {0x10740, 0x10755, prN}, // Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE
+ {0x10760, 0x10767, prN}, // Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807
+ {0x10780, 0x10785, prN}, // Lm [6] MODIFIER LETTER SMALL CAPITAL AA..MODIFIER LETTER SMALL B WITH HOOK
+ {0x10787, 0x107B0, prN}, // Lm [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK
+ {0x107B2, 0x107BA, prN}, // Lm [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL
+ {0x10800, 0x10805, prN}, // Lo [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA
+ {0x10808, 0x10808, prN}, // Lo CYPRIOT SYLLABLE JO
+ {0x1080A, 0x10835, prN}, // Lo [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO
+ {0x10837, 0x10838, prN}, // Lo [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE
+ {0x1083C, 0x1083C, prN}, // Lo CYPRIOT SYLLABLE ZA
+ {0x1083F, 0x1083F, prN}, // Lo CYPRIOT SYLLABLE ZO
+ {0x10840, 0x10855, prN}, // Lo [22] IMPERIAL ARAMAIC LETTER ALEPH..IMPERIAL ARAMAIC LETTER TAW
+ {0x10857, 0x10857, prN}, // Po IMPERIAL ARAMAIC SECTION SIGN
+ {0x10858, 0x1085F, prN}, // No [8] IMPERIAL ARAMAIC NUMBER ONE..IMPERIAL ARAMAIC NUMBER TEN THOUSAND
+ {0x10860, 0x10876, prN}, // Lo [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW
+ {0x10877, 0x10878, prN}, // So [2] PALMYRENE LEFT-POINTING FLEURON..PALMYRENE RIGHT-POINTING FLEURON
+ {0x10879, 0x1087F, prN}, // No [7] PALMYRENE NUMBER ONE..PALMYRENE NUMBER TWENTY
+ {0x10880, 0x1089E, prN}, // Lo [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW
+ {0x108A7, 0x108AF, prN}, // No [9] NABATAEAN NUMBER ONE..NABATAEAN NUMBER ONE HUNDRED
+ {0x108E0, 0x108F2, prN}, // Lo [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH
+ {0x108F4, 0x108F5, prN}, // Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW
+ {0x108FB, 0x108FF, prN}, // No [5] HATRAN NUMBER ONE..HATRAN NUMBER ONE HUNDRED
+ {0x10900, 0x10915, prN}, // Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU
+ {0x10916, 0x1091B, prN}, // No [6] PHOENICIAN NUMBER ONE..PHOENICIAN NUMBER THREE
+ {0x1091F, 0x1091F, prN}, // Po PHOENICIAN WORD SEPARATOR
+ {0x10920, 0x10939, prN}, // Lo [26] LYDIAN LETTER A..LYDIAN LETTER C
+ {0x1093F, 0x1093F, prN}, // Po LYDIAN TRIANGULAR MARK
+ {0x10980, 0x1099F, prN}, // Lo [32] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC HIEROGLYPHIC SYMBOL VIDJ-2
+ {0x109A0, 0x109B7, prN}, // Lo [24] MEROITIC CURSIVE LETTER A..MEROITIC CURSIVE LETTER DA
+ {0x109BC, 0x109BD, prN}, // No [2] MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS..MEROITIC CURSIVE FRACTION ONE HALF
+ {0x109BE, 0x109BF, prN}, // Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN
+ {0x109C0, 0x109CF, prN}, // No [16] MEROITIC CURSIVE NUMBER ONE..MEROITIC CURSIVE NUMBER SEVENTY
+ {0x109D2, 0x109FF, prN}, // No [46] MEROITIC CURSIVE NUMBER ONE HUNDRED..MEROITIC CURSIVE FRACTION TEN TWELFTHS
+ {0x10A00, 0x10A00, prN}, // Lo KHAROSHTHI LETTER A
+ {0x10A01, 0x10A03, prN}, // Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
+ {0x10A05, 0x10A06, prN}, // Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
+ {0x10A0C, 0x10A0F, prN}, // Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
+ {0x10A10, 0x10A13, prN}, // Lo [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA
+ {0x10A15, 0x10A17, prN}, // Lo [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA
+ {0x10A19, 0x10A35, prN}, // Lo [29] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER VHA
+ {0x10A38, 0x10A3A, prN}, // Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
+ {0x10A3F, 0x10A3F, prN}, // Mn KHAROSHTHI VIRAMA
+ {0x10A40, 0x10A48, prN}, // No [9] KHAROSHTHI DIGIT ONE..KHAROSHTHI FRACTION ONE HALF
+ {0x10A50, 0x10A58, prN}, // Po [9] KHAROSHTHI PUNCTUATION DOT..KHAROSHTHI PUNCTUATION LINES
+ {0x10A60, 0x10A7C, prN}, // Lo [29] OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH
+ {0x10A7D, 0x10A7E, prN}, // No [2] OLD SOUTH ARABIAN NUMBER ONE..OLD SOUTH ARABIAN NUMBER FIFTY
+ {0x10A7F, 0x10A7F, prN}, // Po OLD SOUTH ARABIAN NUMERIC INDICATOR
+ {0x10A80, 0x10A9C, prN}, // Lo [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH
+ {0x10A9D, 0x10A9F, prN}, // No [3] OLD NORTH ARABIAN NUMBER ONE..OLD NORTH ARABIAN NUMBER TWENTY
+ {0x10AC0, 0x10AC7, prN}, // Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW
+ {0x10AC8, 0x10AC8, prN}, // So MANICHAEAN SIGN UD
+ {0x10AC9, 0x10AE4, prN}, // Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW
+ {0x10AE5, 0x10AE6, prN}, // Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
+ {0x10AEB, 0x10AEF, prN}, // No [5] MANICHAEAN NUMBER ONE..MANICHAEAN NUMBER ONE HUNDRED
+ {0x10AF0, 0x10AF6, prN}, // Po [7] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION LINE FILLER
+ {0x10B00, 0x10B35, prN}, // Lo [54] AVESTAN LETTER A..AVESTAN LETTER HE
+ {0x10B39, 0x10B3F, prN}, // Po [7] AVESTAN ABBREVIATION MARK..LARGE ONE RING OVER TWO RINGS PUNCTUATION
+ {0x10B40, 0x10B55, prN}, // Lo [22] INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW
+ {0x10B58, 0x10B5F, prN}, // No [8] INSCRIPTIONAL PARTHIAN NUMBER ONE..INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND
+ {0x10B60, 0x10B72, prN}, // Lo [19] INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW
+ {0x10B78, 0x10B7F, prN}, // No [8] INSCRIPTIONAL PAHLAVI NUMBER ONE..INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND
+ {0x10B80, 0x10B91, prN}, // Lo [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW
+ {0x10B99, 0x10B9C, prN}, // Po [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT
+ {0x10BA9, 0x10BAF, prN}, // No [7] PSALTER PAHLAVI NUMBER ONE..PSALTER PAHLAVI NUMBER ONE HUNDRED
+ {0x10C00, 0x10C48, prN}, // Lo [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH
+ {0x10C80, 0x10CB2, prN}, // Lu [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US
+ {0x10CC0, 0x10CF2, prN}, // Ll [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US
+ {0x10CFA, 0x10CFF, prN}, // No [6] OLD HUNGARIAN NUMBER ONE..OLD HUNGARIAN NUMBER ONE THOUSAND
+ {0x10D00, 0x10D23, prN}, // Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA
+ {0x10D24, 0x10D27, prN}, // Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
+ {0x10D30, 0x10D39, prN}, // Nd [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE
+ {0x10E60, 0x10E7E, prN}, // No [31] RUMI DIGIT ONE..RUMI FRACTION TWO THIRDS
+ {0x10E80, 0x10EA9, prN}, // Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET
+ {0x10EAB, 0x10EAC, prN}, // Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK
+ {0x10EAD, 0x10EAD, prN}, // Pd YEZIDI HYPHENATION MARK
+ {0x10EB0, 0x10EB1, prN}, // Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE
+ {0x10EFD, 0x10EFF, prN}, // Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA
+ {0x10F00, 0x10F1C, prN}, // Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL
+ {0x10F1D, 0x10F26, prN}, // No [10] OLD SOGDIAN NUMBER ONE..OLD SOGDIAN FRACTION ONE HALF
+ {0x10F27, 0x10F27, prN}, // Lo OLD SOGDIAN LIGATURE AYIN-DALETH
+ {0x10F30, 0x10F45, prN}, // Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN
+ {0x10F46, 0x10F50, prN}, // Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW
+ {0x10F51, 0x10F54, prN}, // No [4] SOGDIAN NUMBER ONE..SOGDIAN NUMBER ONE HUNDRED
+ {0x10F55, 0x10F59, prN}, // Po [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT
+ {0x10F70, 0x10F81, prN}, // Lo [18] OLD UYGHUR LETTER ALEPH..OLD UYGHUR LETTER LESH
+ {0x10F82, 0x10F85, prN}, // Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW
+ {0x10F86, 0x10F89, prN}, // Po [4] OLD UYGHUR PUNCTUATION BAR..OLD UYGHUR PUNCTUATION FOUR DOTS
+ {0x10FB0, 0x10FC4, prN}, // Lo [21] CHORASMIAN LETTER ALEPH..CHORASMIAN LETTER TAW
+ {0x10FC5, 0x10FCB, prN}, // No [7] CHORASMIAN NUMBER ONE..CHORASMIAN NUMBER ONE HUNDRED
+ {0x10FE0, 0x10FF6, prN}, // Lo [23] ELYMAIC LETTER ALEPH..ELYMAIC LIGATURE ZAYIN-YODH
+ {0x11000, 0x11000, prN}, // Mc BRAHMI SIGN CANDRABINDU
+ {0x11001, 0x11001, prN}, // Mn BRAHMI SIGN ANUSVARA
+ {0x11002, 0x11002, prN}, // Mc BRAHMI SIGN VISARGA
+ {0x11003, 0x11037, prN}, // Lo [53] BRAHMI SIGN JIHVAMULIYA..BRAHMI LETTER OLD TAMIL NNNA
+ {0x11038, 0x11046, prN}, // Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA
+ {0x11047, 0x1104D, prN}, // Po [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS
+ {0x11052, 0x11065, prN}, // No [20] BRAHMI NUMBER ONE..BRAHMI NUMBER ONE THOUSAND
+ {0x11066, 0x1106F, prN}, // Nd [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE
+ {0x11070, 0x11070, prN}, // Mn BRAHMI SIGN OLD TAMIL VIRAMA
+ {0x11071, 0x11072, prN}, // Lo [2] BRAHMI LETTER OLD TAMIL SHORT E..BRAHMI LETTER OLD TAMIL SHORT O
+ {0x11073, 0x11074, prN}, // Mn [2] BRAHMI VOWEL SIGN OLD TAMIL SHORT E..BRAHMI VOWEL SIGN OLD TAMIL SHORT O
+ {0x11075, 0x11075, prN}, // Lo BRAHMI LETTER OLD TAMIL LLA
+ {0x1107F, 0x1107F, prN}, // Mn BRAHMI NUMBER JOINER
+ {0x11080, 0x11081, prN}, // Mn [2] KAITHI SIGN CANDRABINDU..KAITHI SIGN ANUSVARA
+ {0x11082, 0x11082, prN}, // Mc KAITHI SIGN VISARGA
+ {0x11083, 0x110AF, prN}, // Lo [45] KAITHI LETTER A..KAITHI LETTER HA
+ {0x110B0, 0x110B2, prN}, // Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II
+ {0x110B3, 0x110B6, prN}, // Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI
+ {0x110B7, 0x110B8, prN}, // Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU
+ {0x110B9, 0x110BA, prN}, // Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA
+ {0x110BB, 0x110BC, prN}, // Po [2] KAITHI ABBREVIATION SIGN..KAITHI ENUMERATION SIGN
+ {0x110BD, 0x110BD, prN}, // Cf KAITHI NUMBER SIGN
+ {0x110BE, 0x110C1, prN}, // Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA
+ {0x110C2, 0x110C2, prN}, // Mn KAITHI VOWEL SIGN VOCALIC R
+ {0x110CD, 0x110CD, prN}, // Cf KAITHI NUMBER SIGN ABOVE
+ {0x110D0, 0x110E8, prN}, // Lo [25] SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE
+ {0x110F0, 0x110F9, prN}, // Nd [10] SORA SOMPENG DIGIT ZERO..SORA SOMPENG DIGIT NINE
+ {0x11100, 0x11102, prN}, // Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA
+ {0x11103, 0x11126, prN}, // Lo [36] CHAKMA LETTER AA..CHAKMA LETTER HAA
+ {0x11127, 0x1112B, prN}, // Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU
+ {0x1112C, 0x1112C, prN}, // Mc CHAKMA VOWEL SIGN E
+ {0x1112D, 0x11134, prN}, // Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA
+ {0x11136, 0x1113F, prN}, // Nd [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE
+ {0x11140, 0x11143, prN}, // Po [4] CHAKMA SECTION MARK..CHAKMA QUESTION MARK
+ {0x11144, 0x11144, prN}, // Lo CHAKMA LETTER LHAA
+ {0x11145, 0x11146, prN}, // Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI
+ {0x11147, 0x11147, prN}, // Lo CHAKMA LETTER VAA
+ {0x11150, 0x11172, prN}, // Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA
+ {0x11173, 0x11173, prN}, // Mn MAHAJANI SIGN NUKTA
+ {0x11174, 0x11175, prN}, // Po [2] MAHAJANI ABBREVIATION SIGN..MAHAJANI SECTION MARK
+ {0x11176, 0x11176, prN}, // Lo MAHAJANI LIGATURE SHRI
+ {0x11180, 0x11181, prN}, // Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA
+ {0x11182, 0x11182, prN}, // Mc SHARADA SIGN VISARGA
+ {0x11183, 0x111B2, prN}, // Lo [48] SHARADA LETTER A..SHARADA LETTER HA
+ {0x111B3, 0x111B5, prN}, // Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II
+ {0x111B6, 0x111BE, prN}, // Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O
+ {0x111BF, 0x111C0, prN}, // Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA
+ {0x111C1, 0x111C4, prN}, // Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM
+ {0x111C5, 0x111C8, prN}, // Po [4] SHARADA DANDA..SHARADA SEPARATOR
+ {0x111C9, 0x111CC, prN}, // Mn [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK
+ {0x111CD, 0x111CD, prN}, // Po SHARADA SUTRA MARK
+ {0x111CE, 0x111CE, prN}, // Mc SHARADA VOWEL SIGN PRISHTHAMATRA E
+ {0x111CF, 0x111CF, prN}, // Mn SHARADA SIGN INVERTED CANDRABINDU
+ {0x111D0, 0x111D9, prN}, // Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE
+ {0x111DA, 0x111DA, prN}, // Lo SHARADA EKAM
+ {0x111DB, 0x111DB, prN}, // Po SHARADA SIGN SIDDHAM
+ {0x111DC, 0x111DC, prN}, // Lo SHARADA HEADSTROKE
+ {0x111DD, 0x111DF, prN}, // Po [3] SHARADA CONTINUATION SIGN..SHARADA SECTION MARK-2
+ {0x111E1, 0x111F4, prN}, // No [20] SINHALA ARCHAIC DIGIT ONE..SINHALA ARCHAIC NUMBER ONE THOUSAND
+ {0x11200, 0x11211, prN}, // Lo [18] KHOJKI LETTER A..KHOJKI LETTER JJA
+ {0x11213, 0x1122B, prN}, // Lo [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA
+ {0x1122C, 0x1122E, prN}, // Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II
+ {0x1122F, 0x11231, prN}, // Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI
+ {0x11232, 0x11233, prN}, // Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU
+ {0x11234, 0x11234, prN}, // Mn KHOJKI SIGN ANUSVARA
+ {0x11235, 0x11235, prN}, // Mc KHOJKI SIGN VIRAMA
+ {0x11236, 0x11237, prN}, // Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA
+ {0x11238, 0x1123D, prN}, // Po [6] KHOJKI DANDA..KHOJKI ABBREVIATION SIGN
+ {0x1123E, 0x1123E, prN}, // Mn KHOJKI SIGN SUKUN
+ {0x1123F, 0x11240, prN}, // Lo [2] KHOJKI LETTER QA..KHOJKI LETTER SHORT I
+ {0x11241, 0x11241, prN}, // Mn KHOJKI VOWEL SIGN VOCALIC R
+ {0x11280, 0x11286, prN}, // Lo [7] MULTANI LETTER A..MULTANI LETTER GA
+ {0x11288, 0x11288, prN}, // Lo MULTANI LETTER GHA
+ {0x1128A, 0x1128D, prN}, // Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA
+ {0x1128F, 0x1129D, prN}, // Lo [15] MULTANI LETTER NYA..MULTANI LETTER BA
+ {0x1129F, 0x112A8, prN}, // Lo [10] MULTANI LETTER BHA..MULTANI LETTER RHA
+ {0x112A9, 0x112A9, prN}, // Po MULTANI SECTION MARK
+ {0x112B0, 0x112DE, prN}, // Lo [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA
+ {0x112DF, 0x112DF, prN}, // Mn KHUDAWADI SIGN ANUSVARA
+ {0x112E0, 0x112E2, prN}, // Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II
+ {0x112E3, 0x112EA, prN}, // Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA
+ {0x112F0, 0x112F9, prN}, // Nd [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE
+ {0x11300, 0x11301, prN}, // Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU
+ {0x11302, 0x11303, prN}, // Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA
+ {0x11305, 0x1130C, prN}, // Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L
+ {0x1130F, 0x11310, prN}, // Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI
+ {0x11313, 0x11328, prN}, // Lo [22] GRANTHA LETTER OO..GRANTHA LETTER NA
+ {0x1132A, 0x11330, prN}, // Lo [7] GRANTHA LETTER PA..GRANTHA LETTER RA
+ {0x11332, 0x11333, prN}, // Lo [2] GRANTHA LETTER LA..GRANTHA LETTER LLA
+ {0x11335, 0x11339, prN}, // Lo [5] GRANTHA LETTER VA..GRANTHA LETTER HA
+ {0x1133B, 0x1133C, prN}, // Mn [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA
+ {0x1133D, 0x1133D, prN}, // Lo GRANTHA SIGN AVAGRAHA
+ {0x1133E, 0x1133F, prN}, // Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I
+ {0x11340, 0x11340, prN}, // Mn GRANTHA VOWEL SIGN II
+ {0x11341, 0x11344, prN}, // Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR
+ {0x11347, 0x11348, prN}, // Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI
+ {0x1134B, 0x1134D, prN}, // Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA
+ {0x11350, 0x11350, prN}, // Lo GRANTHA OM
+ {0x11357, 0x11357, prN}, // Mc GRANTHA AU LENGTH MARK
+ {0x1135D, 0x11361, prN}, // Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL
+ {0x11362, 0x11363, prN}, // Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL
+ {0x11366, 0x1136C, prN}, // Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX
+ {0x11370, 0x11374, prN}, // Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA
+ {0x11400, 0x11434, prN}, // Lo [53] NEWA LETTER A..NEWA LETTER HA
+ {0x11435, 0x11437, prN}, // Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II
+ {0x11438, 0x1143F, prN}, // Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI
+ {0x11440, 0x11441, prN}, // Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU
+ {0x11442, 0x11444, prN}, // Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA
+ {0x11445, 0x11445, prN}, // Mc NEWA SIGN VISARGA
+ {0x11446, 0x11446, prN}, // Mn NEWA SIGN NUKTA
+ {0x11447, 0x1144A, prN}, // Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI
+ {0x1144B, 0x1144F, prN}, // Po [5] NEWA DANDA..NEWA ABBREVIATION SIGN
+ {0x11450, 0x11459, prN}, // Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE
+ {0x1145A, 0x1145B, prN}, // Po [2] NEWA DOUBLE COMMA..NEWA PLACEHOLDER MARK
+ {0x1145D, 0x1145D, prN}, // Po NEWA INSERTION SIGN
+ {0x1145E, 0x1145E, prN}, // Mn NEWA SANDHI MARK
+ {0x1145F, 0x11461, prN}, // Lo [3] NEWA LETTER VEDIC ANUSVARA..NEWA SIGN UPADHMANIYA
+ {0x11480, 0x114AF, prN}, // Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA
+ {0x114B0, 0x114B2, prN}, // Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II
+ {0x114B3, 0x114B8, prN}, // Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL
+ {0x114B9, 0x114B9, prN}, // Mc TIRHUTA VOWEL SIGN E
+ {0x114BA, 0x114BA, prN}, // Mn TIRHUTA VOWEL SIGN SHORT E
+ {0x114BB, 0x114BE, prN}, // Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU
+ {0x114BF, 0x114C0, prN}, // Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA
+ {0x114C1, 0x114C1, prN}, // Mc TIRHUTA SIGN VISARGA
+ {0x114C2, 0x114C3, prN}, // Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA
+ {0x114C4, 0x114C5, prN}, // Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG
+ {0x114C6, 0x114C6, prN}, // Po TIRHUTA ABBREVIATION SIGN
+ {0x114C7, 0x114C7, prN}, // Lo TIRHUTA OM
+ {0x114D0, 0x114D9, prN}, // Nd [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE
+ {0x11580, 0x115AE, prN}, // Lo [47] SIDDHAM LETTER A..SIDDHAM LETTER HA
+ {0x115AF, 0x115B1, prN}, // Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II
+ {0x115B2, 0x115B5, prN}, // Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR
+ {0x115B8, 0x115BB, prN}, // Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU
+ {0x115BC, 0x115BD, prN}, // Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA
+ {0x115BE, 0x115BE, prN}, // Mc SIDDHAM SIGN VISARGA
+ {0x115BF, 0x115C0, prN}, // Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA
+ {0x115C1, 0x115D7, prN}, // Po [23] SIDDHAM SIGN SIDDHAM..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES
+ {0x115D8, 0x115DB, prN}, // Lo [4] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM LETTER ALTERNATE U
+ {0x115DC, 0x115DD, prN}, // Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU
+ {0x11600, 0x1162F, prN}, // Lo [48] MODI LETTER A..MODI LETTER LLA
+ {0x11630, 0x11632, prN}, // Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II
+ {0x11633, 0x1163A, prN}, // Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI
+ {0x1163B, 0x1163C, prN}, // Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU
+ {0x1163D, 0x1163D, prN}, // Mn MODI SIGN ANUSVARA
+ {0x1163E, 0x1163E, prN}, // Mc MODI SIGN VISARGA
+ {0x1163F, 0x11640, prN}, // Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA
+ {0x11641, 0x11643, prN}, // Po [3] MODI DANDA..MODI ABBREVIATION SIGN
+ {0x11644, 0x11644, prN}, // Lo MODI SIGN HUVA
+ {0x11650, 0x11659, prN}, // Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE
+ {0x11660, 0x1166C, prN}, // Po [13] MONGOLIAN BIRGA WITH ORNAMENT..MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT
+ {0x11680, 0x116AA, prN}, // Lo [43] TAKRI LETTER A..TAKRI LETTER RRA
+ {0x116AB, 0x116AB, prN}, // Mn TAKRI SIGN ANUSVARA
+ {0x116AC, 0x116AC, prN}, // Mc TAKRI SIGN VISARGA
+ {0x116AD, 0x116AD, prN}, // Mn TAKRI VOWEL SIGN AA
+ {0x116AE, 0x116AF, prN}, // Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II
+ {0x116B0, 0x116B5, prN}, // Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU
+ {0x116B6, 0x116B6, prN}, // Mc TAKRI SIGN VIRAMA
+ {0x116B7, 0x116B7, prN}, // Mn TAKRI SIGN NUKTA
+ {0x116B8, 0x116B8, prN}, // Lo TAKRI LETTER ARCHAIC KHA
+ {0x116B9, 0x116B9, prN}, // Po TAKRI ABBREVIATION SIGN
+ {0x116C0, 0x116C9, prN}, // Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE
+ {0x11700, 0x1171A, prN}, // Lo [27] AHOM LETTER KA..AHOM LETTER ALTERNATE BA
+ {0x1171D, 0x1171F, prN}, // Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA
+ {0x11720, 0x11721, prN}, // Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA
+ {0x11722, 0x11725, prN}, // Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU
+ {0x11726, 0x11726, prN}, // Mc AHOM VOWEL SIGN E
+ {0x11727, 0x1172B, prN}, // Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER
+ {0x11730, 0x11739, prN}, // Nd [10] AHOM DIGIT ZERO..AHOM DIGIT NINE
+ {0x1173A, 0x1173B, prN}, // No [2] AHOM NUMBER TEN..AHOM NUMBER TWENTY
+ {0x1173C, 0x1173E, prN}, // Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI
+ {0x1173F, 0x1173F, prN}, // So AHOM SYMBOL VI
+ {0x11740, 0x11746, prN}, // Lo [7] AHOM LETTER CA..AHOM LETTER LLA
+ {0x11800, 0x1182B, prN}, // Lo [44] DOGRA LETTER A..DOGRA LETTER RRA
+ {0x1182C, 0x1182E, prN}, // Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II
+ {0x1182F, 0x11837, prN}, // Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA
+ {0x11838, 0x11838, prN}, // Mc DOGRA SIGN VISARGA
+ {0x11839, 0x1183A, prN}, // Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA
+ {0x1183B, 0x1183B, prN}, // Po DOGRA ABBREVIATION SIGN
+ {0x118A0, 0x118DF, prN}, // L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO
+ {0x118E0, 0x118E9, prN}, // Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE
+ {0x118EA, 0x118F2, prN}, // No [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY
+ {0x118FF, 0x118FF, prN}, // Lo WARANG CITI OM
+ {0x11900, 0x11906, prN}, // Lo [7] DIVES AKURU LETTER A..DIVES AKURU LETTER E
+ {0x11909, 0x11909, prN}, // Lo DIVES AKURU LETTER O
+ {0x1190C, 0x11913, prN}, // Lo [8] DIVES AKURU LETTER KA..DIVES AKURU LETTER JA
+ {0x11915, 0x11916, prN}, // Lo [2] DIVES AKURU LETTER NYA..DIVES AKURU LETTER TTA
+ {0x11918, 0x1192F, prN}, // Lo [24] DIVES AKURU LETTER DDA..DIVES AKURU LETTER ZA
+ {0x11930, 0x11935, prN}, // Mc [6] DIVES AKURU VOWEL SIGN AA..DIVES AKURU VOWEL SIGN E
+ {0x11937, 0x11938, prN}, // Mc [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O
+ {0x1193B, 0x1193C, prN}, // Mn [2] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN CANDRABINDU
+ {0x1193D, 0x1193D, prN}, // Mc DIVES AKURU SIGN HALANTA
+ {0x1193E, 0x1193E, prN}, // Mn DIVES AKURU VIRAMA
+ {0x1193F, 0x1193F, prN}, // Lo DIVES AKURU PREFIXED NASAL SIGN
+ {0x11940, 0x11940, prN}, // Mc DIVES AKURU MEDIAL YA
+ {0x11941, 0x11941, prN}, // Lo DIVES AKURU INITIAL RA
+ {0x11942, 0x11942, prN}, // Mc DIVES AKURU MEDIAL RA
+ {0x11943, 0x11943, prN}, // Mn DIVES AKURU SIGN NUKTA
+ {0x11944, 0x11946, prN}, // Po [3] DIVES AKURU DOUBLE DANDA..DIVES AKURU END OF TEXT MARK
+ {0x11950, 0x11959, prN}, // Nd [10] DIVES AKURU DIGIT ZERO..DIVES AKURU DIGIT NINE
+ {0x119A0, 0x119A7, prN}, // Lo [8] NANDINAGARI LETTER A..NANDINAGARI LETTER VOCALIC RR
+ {0x119AA, 0x119D0, prN}, // Lo [39] NANDINAGARI LETTER E..NANDINAGARI LETTER RRA
+ {0x119D1, 0x119D3, prN}, // Mc [3] NANDINAGARI VOWEL SIGN AA..NANDINAGARI VOWEL SIGN II
+ {0x119D4, 0x119D7, prN}, // Mn [4] NANDINAGARI VOWEL SIGN U..NANDINAGARI VOWEL SIGN VOCALIC RR
+ {0x119DA, 0x119DB, prN}, // Mn [2] NANDINAGARI VOWEL SIGN E..NANDINAGARI VOWEL SIGN AI
+ {0x119DC, 0x119DF, prN}, // Mc [4] NANDINAGARI VOWEL SIGN O..NANDINAGARI SIGN VISARGA
+ {0x119E0, 0x119E0, prN}, // Mn NANDINAGARI SIGN VIRAMA
+ {0x119E1, 0x119E1, prN}, // Lo NANDINAGARI SIGN AVAGRAHA
+ {0x119E2, 0x119E2, prN}, // Po NANDINAGARI SIGN SIDDHAM
+ {0x119E3, 0x119E3, prN}, // Lo NANDINAGARI HEADSTROKE
+ {0x119E4, 0x119E4, prN}, // Mc NANDINAGARI VOWEL SIGN PRISHTHAMATRA E
+ {0x11A00, 0x11A00, prN}, // Lo ZANABAZAR SQUARE LETTER A
+ {0x11A01, 0x11A0A, prN}, // Mn [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK
+ {0x11A0B, 0x11A32, prN}, // Lo [40] ZANABAZAR SQUARE LETTER KA..ZANABAZAR SQUARE LETTER KSSA
+ {0x11A33, 0x11A38, prN}, // Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA
+ {0x11A39, 0x11A39, prN}, // Mc ZANABAZAR SQUARE SIGN VISARGA
+ {0x11A3A, 0x11A3A, prN}, // Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA
+ {0x11A3B, 0x11A3E, prN}, // Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA
+ {0x11A3F, 0x11A46, prN}, // Po [8] ZANABAZAR SQUARE INITIAL HEAD MARK..ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK
+ {0x11A47, 0x11A47, prN}, // Mn ZANABAZAR SQUARE SUBJOINER
+ {0x11A50, 0x11A50, prN}, // Lo SOYOMBO LETTER A
+ {0x11A51, 0x11A56, prN}, // Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE
+ {0x11A57, 0x11A58, prN}, // Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU
+ {0x11A59, 0x11A5B, prN}, // Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK
+ {0x11A5C, 0x11A89, prN}, // Lo [46] SOYOMBO LETTER KA..SOYOMBO CLUSTER-INITIAL LETTER SA
+ {0x11A8A, 0x11A96, prN}, // Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA
+ {0x11A97, 0x11A97, prN}, // Mc SOYOMBO SIGN VISARGA
+ {0x11A98, 0x11A99, prN}, // Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER
+ {0x11A9A, 0x11A9C, prN}, // Po [3] SOYOMBO MARK TSHEG..SOYOMBO MARK DOUBLE SHAD
+ {0x11A9D, 0x11A9D, prN}, // Lo SOYOMBO MARK PLUTA
+ {0x11A9E, 0x11AA2, prN}, // Po [5] SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO TERMINAL MARK-2
+ {0x11AB0, 0x11ABF, prN}, // Lo [16] CANADIAN SYLLABICS NATTILIK HI..CANADIAN SYLLABICS SPA
+ {0x11AC0, 0x11AF8, prN}, // Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL
+ {0x11B00, 0x11B09, prN}, // Po [10] DEVANAGARI HEAD MARK..DEVANAGARI SIGN MINDU
+ {0x11C00, 0x11C08, prN}, // Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L
+ {0x11C0A, 0x11C2E, prN}, // Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA
+ {0x11C2F, 0x11C2F, prN}, // Mc BHAIKSUKI VOWEL SIGN AA
+ {0x11C30, 0x11C36, prN}, // Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L
+ {0x11C38, 0x11C3D, prN}, // Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA
+ {0x11C3E, 0x11C3E, prN}, // Mc BHAIKSUKI SIGN VISARGA
+ {0x11C3F, 0x11C3F, prN}, // Mn BHAIKSUKI SIGN VIRAMA
+ {0x11C40, 0x11C40, prN}, // Lo BHAIKSUKI SIGN AVAGRAHA
+ {0x11C41, 0x11C45, prN}, // Po [5] BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2
+ {0x11C50, 0x11C59, prN}, // Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE
+ {0x11C5A, 0x11C6C, prN}, // No [19] BHAIKSUKI NUMBER ONE..BHAIKSUKI HUNDREDS UNIT MARK
+ {0x11C70, 0x11C71, prN}, // Po [2] MARCHEN HEAD MARK..MARCHEN MARK SHAD
+ {0x11C72, 0x11C8F, prN}, // Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A
+ {0x11C92, 0x11CA7, prN}, // Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA
+ {0x11CA9, 0x11CA9, prN}, // Mc MARCHEN SUBJOINED LETTER YA
+ {0x11CAA, 0x11CB0, prN}, // Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA
+ {0x11CB1, 0x11CB1, prN}, // Mc MARCHEN VOWEL SIGN I
+ {0x11CB2, 0x11CB3, prN}, // Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E
+ {0x11CB4, 0x11CB4, prN}, // Mc MARCHEN VOWEL SIGN O
+ {0x11CB5, 0x11CB6, prN}, // Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU
+ {0x11D00, 0x11D06, prN}, // Lo [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E
+ {0x11D08, 0x11D09, prN}, // Lo [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O
+ {0x11D0B, 0x11D30, prN}, // Lo [38] MASARAM GONDI LETTER AU..MASARAM GONDI LETTER TRA
+ {0x11D31, 0x11D36, prN}, // Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R
+ {0x11D3A, 0x11D3A, prN}, // Mn MASARAM GONDI VOWEL SIGN E
+ {0x11D3C, 0x11D3D, prN}, // Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O
+ {0x11D3F, 0x11D45, prN}, // Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA
+ {0x11D46, 0x11D46, prN}, // Lo MASARAM GONDI REPHA
+ {0x11D47, 0x11D47, prN}, // Mn MASARAM GONDI RA-KARA
+ {0x11D50, 0x11D59, prN}, // Nd [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE
+ {0x11D60, 0x11D65, prN}, // Lo [6] GUNJALA GONDI LETTER A..GUNJALA GONDI LETTER UU
+ {0x11D67, 0x11D68, prN}, // Lo [2] GUNJALA GONDI LETTER EE..GUNJALA GONDI LETTER AI
+ {0x11D6A, 0x11D89, prN}, // Lo [32] GUNJALA GONDI LETTER OO..GUNJALA GONDI LETTER SA
+ {0x11D8A, 0x11D8E, prN}, // Mc [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU
+ {0x11D90, 0x11D91, prN}, // Mn [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI
+ {0x11D93, 0x11D94, prN}, // Mc [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU
+ {0x11D95, 0x11D95, prN}, // Mn GUNJALA GONDI SIGN ANUSVARA
+ {0x11D96, 0x11D96, prN}, // Mc GUNJALA GONDI SIGN VISARGA
+ {0x11D97, 0x11D97, prN}, // Mn GUNJALA GONDI VIRAMA
+ {0x11D98, 0x11D98, prN}, // Lo GUNJALA GONDI OM
+ {0x11DA0, 0x11DA9, prN}, // Nd [10] GUNJALA GONDI DIGIT ZERO..GUNJALA GONDI DIGIT NINE
+ {0x11EE0, 0x11EF2, prN}, // Lo [19] MAKASAR LETTER KA..MAKASAR ANGKA
+ {0x11EF3, 0x11EF4, prN}, // Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U
+ {0x11EF5, 0x11EF6, prN}, // Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O
+ {0x11EF7, 0x11EF8, prN}, // Po [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION
+ {0x11F00, 0x11F01, prN}, // Mn [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA
+ {0x11F02, 0x11F02, prN}, // Lo KAWI SIGN REPHA
+ {0x11F03, 0x11F03, prN}, // Mc KAWI SIGN VISARGA
+ {0x11F04, 0x11F10, prN}, // Lo [13] KAWI LETTER A..KAWI LETTER O
+ {0x11F12, 0x11F33, prN}, // Lo [34] KAWI LETTER KA..KAWI LETTER JNYA
+ {0x11F34, 0x11F35, prN}, // Mc [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA
+ {0x11F36, 0x11F3A, prN}, // Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R
+ {0x11F3E, 0x11F3F, prN}, // Mc [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI
+ {0x11F40, 0x11F40, prN}, // Mn KAWI VOWEL SIGN EU
+ {0x11F41, 0x11F41, prN}, // Mc KAWI SIGN KILLER
+ {0x11F42, 0x11F42, prN}, // Mn KAWI CONJOINER
+ {0x11F43, 0x11F4F, prN}, // Po [13] KAWI DANDA..KAWI PUNCTUATION CLOSING SPIRAL
+ {0x11F50, 0x11F59, prN}, // Nd [10] KAWI DIGIT ZERO..KAWI DIGIT NINE
+ {0x11FB0, 0x11FB0, prN}, // Lo LISU LETTER YHA
+ {0x11FC0, 0x11FD4, prN}, // No [21] TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH..TAMIL FRACTION DOWNSCALING FACTOR KIIZH
+ {0x11FD5, 0x11FDC, prN}, // So [8] TAMIL SIGN NEL..TAMIL SIGN MUKKURUNI
+ {0x11FDD, 0x11FE0, prN}, // Sc [4] TAMIL SIGN KAACU..TAMIL SIGN VARAAKAN
+ {0x11FE1, 0x11FF1, prN}, // So [17] TAMIL SIGN PAARAM..TAMIL SIGN VAKAIYARAA
+ {0x11FFF, 0x11FFF, prN}, // Po TAMIL PUNCTUATION END OF TEXT
+ {0x12000, 0x12399, prN}, // Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U
+ {0x12400, 0x1246E, prN}, // Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM
+ {0x12470, 0x12474, prN}, // Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON
+ {0x12480, 0x12543, prN}, // Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU
+ {0x12F90, 0x12FF0, prN}, // Lo [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114
+ {0x12FF1, 0x12FF2, prN}, // Po [2] CYPRO-MINOAN SIGN CM301..CYPRO-MINOAN SIGN CM302
+ {0x13000, 0x1342F, prN}, // Lo [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D
+ {0x13430, 0x1343F, prN}, // Cf [16] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE
+ {0x13440, 0x13440, prN}, // Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY
+ {0x13441, 0x13446, prN}, // Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN
+ {0x13447, 0x13455, prN}, // Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED
+ {0x14400, 0x14646, prN}, // Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530
+ {0x16800, 0x16A38, prN}, // Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ
+ {0x16A40, 0x16A5E, prN}, // Lo [31] MRO LETTER TA..MRO LETTER TEK
+ {0x16A60, 0x16A69, prN}, // Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE
+ {0x16A6E, 0x16A6F, prN}, // Po [2] MRO DANDA..MRO DOUBLE DANDA
+ {0x16A70, 0x16ABE, prN}, // Lo [79] TANGSA LETTER OZ..TANGSA LETTER ZA
+ {0x16AC0, 0x16AC9, prN}, // Nd [10] TANGSA DIGIT ZERO..TANGSA DIGIT NINE
+ {0x16AD0, 0x16AED, prN}, // Lo [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I
+ {0x16AF0, 0x16AF4, prN}, // Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
+ {0x16AF5, 0x16AF5, prN}, // Po BASSA VAH FULL STOP
+ {0x16B00, 0x16B2F, prN}, // Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU
+ {0x16B30, 0x16B36, prN}, // Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
+ {0x16B37, 0x16B3B, prN}, // Po [5] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS FEEM
+ {0x16B3C, 0x16B3F, prN}, // So [4] PAHAWH HMONG SIGN XYEEM NTXIV..PAHAWH HMONG SIGN XYEEM FAIB
+ {0x16B40, 0x16B43, prN}, // Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM
+ {0x16B44, 0x16B44, prN}, // Po PAHAWH HMONG SIGN XAUS
+ {0x16B45, 0x16B45, prN}, // So PAHAWH HMONG SIGN CIM TSOV ROG
+ {0x16B50, 0x16B59, prN}, // Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE
+ {0x16B5B, 0x16B61, prN}, // No [7] PAHAWH HMONG NUMBER TENS..PAHAWH HMONG NUMBER TRILLIONS
+ {0x16B63, 0x16B77, prN}, // Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS
+ {0x16B7D, 0x16B8F, prN}, // Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ
+ {0x16E40, 0x16E7F, prN}, // L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y
+ {0x16E80, 0x16E96, prN}, // No [23] MEDEFAIDRIN DIGIT ZERO..MEDEFAIDRIN DIGIT THREE ALTERNATE FORM
+ {0x16E97, 0x16E9A, prN}, // Po [4] MEDEFAIDRIN COMMA..MEDEFAIDRIN EXCLAMATION OH
+ {0x16F00, 0x16F4A, prN}, // Lo [75] MIAO LETTER PA..MIAO LETTER RTE
+ {0x16F4F, 0x16F4F, prN}, // Mn MIAO SIGN CONSONANT MODIFIER BAR
+ {0x16F50, 0x16F50, prN}, // Lo MIAO LETTER NASALIZATION
+ {0x16F51, 0x16F87, prN}, // Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI
+ {0x16F8F, 0x16F92, prN}, // Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
+ {0x16F93, 0x16F9F, prN}, // Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8
+ {0x16FE0, 0x16FE1, prW}, // Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK
+ {0x16FE2, 0x16FE2, prW}, // Po OLD CHINESE HOOK MARK
+ {0x16FE3, 0x16FE3, prW}, // Lm OLD CHINESE ITERATION MARK
+ {0x16FE4, 0x16FE4, prW}, // Mn KHITAN SMALL SCRIPT FILLER
+ {0x16FF0, 0x16FF1, prW}, // Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY
+ {0x17000, 0x187F7, prW}, // Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7
+ {0x18800, 0x18AFF, prW}, // Lo [768] TANGUT COMPONENT-001..TANGUT COMPONENT-768
+ {0x18B00, 0x18CD5, prW}, // Lo [470] KHITAN SMALL SCRIPT CHARACTER-18B00..KHITAN SMALL SCRIPT CHARACTER-18CD5
+ {0x18D00, 0x18D08, prW}, // Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08
+ {0x1AFF0, 0x1AFF3, prW}, // Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5
+ {0x1AFF5, 0x1AFFB, prW}, // Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5
+ {0x1AFFD, 0x1AFFE, prW}, // Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8
+ {0x1B000, 0x1B0FF, prW}, // Lo [256] KATAKANA LETTER ARCHAIC E..HENTAIGANA LETTER RE-2
+ {0x1B100, 0x1B122, prW}, // Lo [35] HENTAIGANA LETTER RE-3..KATAKANA LETTER ARCHAIC WU
+ {0x1B132, 0x1B132, prW}, // Lo HIRAGANA LETTER SMALL KO
+ {0x1B150, 0x1B152, prW}, // Lo [3] HIRAGANA LETTER SMALL WI..HIRAGANA LETTER SMALL WO
+ {0x1B155, 0x1B155, prW}, // Lo KATAKANA LETTER SMALL KO
+ {0x1B164, 0x1B167, prW}, // Lo [4] KATAKANA LETTER SMALL WI..KATAKANA LETTER SMALL N
+ {0x1B170, 0x1B2FB, prW}, // Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB
+ {0x1BC00, 0x1BC6A, prN}, // Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M
+ {0x1BC70, 0x1BC7C, prN}, // Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK
+ {0x1BC80, 0x1BC88, prN}, // Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL
+ {0x1BC90, 0x1BC99, prN}, // Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW
+ {0x1BC9C, 0x1BC9C, prN}, // So DUPLOYAN SIGN O WITH CROSS
+ {0x1BC9D, 0x1BC9E, prN}, // Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK
+ {0x1BC9F, 0x1BC9F, prN}, // Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP
+ {0x1BCA0, 0x1BCA3, prN}, // Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
+ {0x1CF00, 0x1CF2D, prN}, // Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT
+ {0x1CF30, 0x1CF46, prN}, // Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG
+ {0x1CF50, 0x1CFC3, prN}, // So [116] ZNAMENNY NEUME KRYUK..ZNAMENNY NEUME PAUK
+ {0x1D000, 0x1D0F5, prN}, // So [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO
+ {0x1D100, 0x1D126, prN}, // So [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2
+ {0x1D129, 0x1D164, prN}, // So [60] MUSICAL SYMBOL MULTIPLE MEASURE REST..MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE
+ {0x1D165, 0x1D166, prN}, // Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM
+ {0x1D167, 0x1D169, prN}, // Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3
+ {0x1D16A, 0x1D16C, prN}, // So [3] MUSICAL SYMBOL FINGERED TREMOLO-1..MUSICAL SYMBOL FINGERED TREMOLO-3
+ {0x1D16D, 0x1D172, prN}, // Mc [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5
+ {0x1D173, 0x1D17A, prN}, // Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
+ {0x1D17B, 0x1D182, prN}, // Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE
+ {0x1D183, 0x1D184, prN}, // So [2] MUSICAL SYMBOL ARPEGGIATO UP..MUSICAL SYMBOL ARPEGGIATO DOWN
+ {0x1D185, 0x1D18B, prN}, // Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
+ {0x1D18C, 0x1D1A9, prN}, // So [30] MUSICAL SYMBOL RINFORZANDO..MUSICAL SYMBOL DEGREE SLASH
+ {0x1D1AA, 0x1D1AD, prN}, // Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
+ {0x1D1AE, 0x1D1EA, prN}, // So [61] MUSICAL SYMBOL PEDAL MARK..MUSICAL SYMBOL KORON
+ {0x1D200, 0x1D241, prN}, // So [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54
+ {0x1D242, 0x1D244, prN}, // Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME
+ {0x1D245, 0x1D245, prN}, // So GREEK MUSICAL LEIMMA
+ {0x1D2C0, 0x1D2D3, prN}, // No [20] KAKTOVIK NUMERAL ZERO..KAKTOVIK NUMERAL NINETEEN
+ {0x1D2E0, 0x1D2F3, prN}, // No [20] MAYAN NUMERAL ZERO..MAYAN NUMERAL NINETEEN
+ {0x1D300, 0x1D356, prN}, // So [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING
+ {0x1D360, 0x1D378, prN}, // No [25] COUNTING ROD UNIT DIGIT ONE..TALLY MARK FIVE
+ {0x1D400, 0x1D454, prN}, // L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G
+ {0x1D456, 0x1D49C, prN}, // L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A
+ {0x1D49E, 0x1D49F, prN}, // Lu [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D
+ {0x1D4A2, 0x1D4A2, prN}, // Lu MATHEMATICAL SCRIPT CAPITAL G
+ {0x1D4A5, 0x1D4A6, prN}, // Lu [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K
+ {0x1D4A9, 0x1D4AC, prN}, // Lu [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q
+ {0x1D4AE, 0x1D4B9, prN}, // L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D
+ {0x1D4BB, 0x1D4BB, prN}, // Ll MATHEMATICAL SCRIPT SMALL F
+ {0x1D4BD, 0x1D4C3, prN}, // Ll [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N
+ {0x1D4C5, 0x1D505, prN}, // L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B
+ {0x1D507, 0x1D50A, prN}, // Lu [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G
+ {0x1D50D, 0x1D514, prN}, // Lu [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q
+ {0x1D516, 0x1D51C, prN}, // Lu [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y
+ {0x1D51E, 0x1D539, prN}, // L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+ {0x1D53B, 0x1D53E, prN}, // Lu [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+ {0x1D540, 0x1D544, prN}, // Lu [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+ {0x1D546, 0x1D546, prN}, // Lu MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+ {0x1D54A, 0x1D550, prN}, // Lu [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+ {0x1D552, 0x1D6A5, prN}, // L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J
+ {0x1D6A8, 0x1D6C0, prN}, // Lu [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA
+ {0x1D6C1, 0x1D6C1, prN}, // Sm MATHEMATICAL BOLD NABLA
+ {0x1D6C2, 0x1D6DA, prN}, // Ll [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA
+ {0x1D6DB, 0x1D6DB, prN}, // Sm MATHEMATICAL BOLD PARTIAL DIFFERENTIAL
+ {0x1D6DC, 0x1D6FA, prN}, // L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA
+ {0x1D6FB, 0x1D6FB, prN}, // Sm MATHEMATICAL ITALIC NABLA
+ {0x1D6FC, 0x1D714, prN}, // Ll [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA
+ {0x1D715, 0x1D715, prN}, // Sm MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL
+ {0x1D716, 0x1D734, prN}, // L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA
+ {0x1D735, 0x1D735, prN}, // Sm MATHEMATICAL BOLD ITALIC NABLA
+ {0x1D736, 0x1D74E, prN}, // Ll [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA
+ {0x1D74F, 0x1D74F, prN}, // Sm MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL
+ {0x1D750, 0x1D76E, prN}, // L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA
+ {0x1D76F, 0x1D76F, prN}, // Sm MATHEMATICAL SANS-SERIF BOLD NABLA
+ {0x1D770, 0x1D788, prN}, // Ll [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA
+ {0x1D789, 0x1D789, prN}, // Sm MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL
+ {0x1D78A, 0x1D7A8, prN}, // L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA
+ {0x1D7A9, 0x1D7A9, prN}, // Sm MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA
+ {0x1D7AA, 0x1D7C2, prN}, // Ll [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA
+ {0x1D7C3, 0x1D7C3, prN}, // Sm MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL
+ {0x1D7C4, 0x1D7CB, prN}, // L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA
+ {0x1D7CE, 0x1D7FF, prN}, // Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
+ {0x1D800, 0x1D9FF, prN}, // So [512] SIGNWRITING HAND-FIST INDEX..SIGNWRITING HEAD
+ {0x1DA00, 0x1DA36, prN}, // Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN
+ {0x1DA37, 0x1DA3A, prN}, // So [4] SIGNWRITING AIR BLOW SMALL ROTATIONS..SIGNWRITING BREATH EXHALE
+ {0x1DA3B, 0x1DA6C, prN}, // Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT
+ {0x1DA6D, 0x1DA74, prN}, // So [8] SIGNWRITING SHOULDER HIP SPINE..SIGNWRITING TORSO-FLOORPLANE TWISTING
+ {0x1DA75, 0x1DA75, prN}, // Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS
+ {0x1DA76, 0x1DA83, prN}, // So [14] SIGNWRITING LIMB COMBINATION..SIGNWRITING LOCATION DEPTH
+ {0x1DA84, 0x1DA84, prN}, // Mn SIGNWRITING LOCATION HEAD NECK
+ {0x1DA85, 0x1DA86, prN}, // So [2] SIGNWRITING LOCATION TORSO..SIGNWRITING LOCATION LIMBS DIGITS
+ {0x1DA87, 0x1DA8B, prN}, // Po [5] SIGNWRITING COMMA..SIGNWRITING PARENTHESIS
+ {0x1DA9B, 0x1DA9F, prN}, // Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6
+ {0x1DAA1, 0x1DAAF, prN}, // Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16
+ {0x1DF00, 0x1DF09, prN}, // Ll [10] LATIN SMALL LETTER FENG DIGRAPH WITH TRILL..LATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOOK
+ {0x1DF0A, 0x1DF0A, prN}, // Lo LATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOK
+ {0x1DF0B, 0x1DF1E, prN}, // Ll [20] LATIN SMALL LETTER ESH WITH DOUBLE BAR..LATIN SMALL LETTER S WITH CURL
+ {0x1DF25, 0x1DF2A, prN}, // Ll [6] LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK..LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK
+ {0x1E000, 0x1E006, prN}, // Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE
+ {0x1E008, 0x1E018, prN}, // Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU
+ {0x1E01B, 0x1E021, prN}, // Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI
+ {0x1E023, 0x1E024, prN}, // Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS
+ {0x1E026, 0x1E02A, prN}, // Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA
+ {0x1E030, 0x1E06D, prN}, // Lm [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE
+ {0x1E08F, 0x1E08F, prN}, // Mn COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+ {0x1E100, 0x1E12C, prN}, // Lo [45] NYIAKENG PUACHUE HMONG LETTER MA..NYIAKENG PUACHUE HMONG LETTER W
+ {0x1E130, 0x1E136, prN}, // Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D
+ {0x1E137, 0x1E13D, prN}, // Lm [7] NYIAKENG PUACHUE HMONG SIGN FOR PERSON..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER
+ {0x1E140, 0x1E149, prN}, // Nd [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE
+ {0x1E14E, 0x1E14E, prN}, // Lo NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ
+ {0x1E14F, 0x1E14F, prN}, // So NYIAKENG PUACHUE HMONG CIRCLED CA
+ {0x1E290, 0x1E2AD, prN}, // Lo [30] TOTO LETTER PA..TOTO LETTER A
+ {0x1E2AE, 0x1E2AE, prN}, // Mn TOTO SIGN RISING TONE
+ {0x1E2C0, 0x1E2EB, prN}, // Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH
+ {0x1E2EC, 0x1E2EF, prN}, // Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI
+ {0x1E2F0, 0x1E2F9, prN}, // Nd [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE
+ {0x1E2FF, 0x1E2FF, prN}, // Sc WANCHO NGUN SIGN
+ {0x1E4D0, 0x1E4EA, prN}, // Lo [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL
+ {0x1E4EB, 0x1E4EB, prN}, // Lm NAG MUNDARI SIGN OJOD
+ {0x1E4EC, 0x1E4EF, prN}, // Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH
+ {0x1E4F0, 0x1E4F9, prN}, // Nd [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE
+ {0x1E7E0, 0x1E7E6, prN}, // Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO
+ {0x1E7E8, 0x1E7EB, prN}, // Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE
+ {0x1E7ED, 0x1E7EE, prN}, // Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE
+ {0x1E7F0, 0x1E7FE, prN}, // Lo [15] ETHIOPIC SYLLABLE GURAGE QWI..ETHIOPIC SYLLABLE GURAGE PWEE
+ {0x1E800, 0x1E8C4, prN}, // Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON
+ {0x1E8C7, 0x1E8CF, prN}, // No [9] MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE
+ {0x1E8D0, 0x1E8D6, prN}, // Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS
+ {0x1E900, 0x1E943, prN}, // L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA
+ {0x1E944, 0x1E94A, prN}, // Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA
+ {0x1E94B, 0x1E94B, prN}, // Lm ADLAM NASALIZATION MARK
+ {0x1E950, 0x1E959, prN}, // Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE
+ {0x1E95E, 0x1E95F, prN}, // Po [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK
+ {0x1EC71, 0x1ECAB, prN}, // No [59] INDIC SIYAQ NUMBER ONE..INDIC SIYAQ NUMBER PREFIXED NINE
+ {0x1ECAC, 0x1ECAC, prN}, // So INDIC SIYAQ PLACEHOLDER
+ {0x1ECAD, 0x1ECAF, prN}, // No [3] INDIC SIYAQ FRACTION ONE QUARTER..INDIC SIYAQ FRACTION THREE QUARTERS
+ {0x1ECB0, 0x1ECB0, prN}, // Sc INDIC SIYAQ RUPEE MARK
+ {0x1ECB1, 0x1ECB4, prN}, // No [4] INDIC SIYAQ NUMBER ALTERNATE ONE..INDIC SIYAQ ALTERNATE LAKH MARK
+ {0x1ED01, 0x1ED2D, prN}, // No [45] OTTOMAN SIYAQ NUMBER ONE..OTTOMAN SIYAQ NUMBER NINETY THOUSAND
+ {0x1ED2E, 0x1ED2E, prN}, // So OTTOMAN SIYAQ MARRATAN
+ {0x1ED2F, 0x1ED3D, prN}, // No [15] OTTOMAN SIYAQ ALTERNATE NUMBER TWO..OTTOMAN SIYAQ FRACTION ONE SIXTH
+ {0x1EE00, 0x1EE03, prN}, // Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL
+ {0x1EE05, 0x1EE1F, prN}, // Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF
+ {0x1EE21, 0x1EE22, prN}, // Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM
+ {0x1EE24, 0x1EE24, prN}, // Lo ARABIC MATHEMATICAL INITIAL HEH
+ {0x1EE27, 0x1EE27, prN}, // Lo ARABIC MATHEMATICAL INITIAL HAH
+ {0x1EE29, 0x1EE32, prN}, // Lo [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF
+ {0x1EE34, 0x1EE37, prN}, // Lo [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH
+ {0x1EE39, 0x1EE39, prN}, // Lo ARABIC MATHEMATICAL INITIAL DAD
+ {0x1EE3B, 0x1EE3B, prN}, // Lo ARABIC MATHEMATICAL INITIAL GHAIN
+ {0x1EE42, 0x1EE42, prN}, // Lo ARABIC MATHEMATICAL TAILED JEEM
+ {0x1EE47, 0x1EE47, prN}, // Lo ARABIC MATHEMATICAL TAILED HAH
+ {0x1EE49, 0x1EE49, prN}, // Lo ARABIC MATHEMATICAL TAILED YEH
+ {0x1EE4B, 0x1EE4B, prN}, // Lo ARABIC MATHEMATICAL TAILED LAM
+ {0x1EE4D, 0x1EE4F, prN}, // Lo [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN
+ {0x1EE51, 0x1EE52, prN}, // Lo [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF
+ {0x1EE54, 0x1EE54, prN}, // Lo ARABIC MATHEMATICAL TAILED SHEEN
+ {0x1EE57, 0x1EE57, prN}, // Lo ARABIC MATHEMATICAL TAILED KHAH
+ {0x1EE59, 0x1EE59, prN}, // Lo ARABIC MATHEMATICAL TAILED DAD
+ {0x1EE5B, 0x1EE5B, prN}, // Lo ARABIC MATHEMATICAL TAILED GHAIN
+ {0x1EE5D, 0x1EE5D, prN}, // Lo ARABIC MATHEMATICAL TAILED DOTLESS NOON
+ {0x1EE5F, 0x1EE5F, prN}, // Lo ARABIC MATHEMATICAL TAILED DOTLESS QAF
+ {0x1EE61, 0x1EE62, prN}, // Lo [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM
+ {0x1EE64, 0x1EE64, prN}, // Lo ARABIC MATHEMATICAL STRETCHED HEH
+ {0x1EE67, 0x1EE6A, prN}, // Lo [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF
+ {0x1EE6C, 0x1EE72, prN}, // Lo [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF
+ {0x1EE74, 0x1EE77, prN}, // Lo [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH
+ {0x1EE79, 0x1EE7C, prN}, // Lo [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH
+ {0x1EE7E, 0x1EE7E, prN}, // Lo ARABIC MATHEMATICAL STRETCHED DOTLESS FEH
+ {0x1EE80, 0x1EE89, prN}, // Lo [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH
+ {0x1EE8B, 0x1EE9B, prN}, // Lo [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN
+ {0x1EEA1, 0x1EEA3, prN}, // Lo [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL
+ {0x1EEA5, 0x1EEA9, prN}, // Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH
+ {0x1EEAB, 0x1EEBB, prN}, // Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN
+ {0x1EEF0, 0x1EEF1, prN}, // Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL
+ {0x1F000, 0x1F003, prN}, // So [4] MAHJONG TILE EAST WIND..MAHJONG TILE NORTH WIND
+ {0x1F004, 0x1F004, prW}, // So MAHJONG TILE RED DRAGON
+ {0x1F005, 0x1F02B, prN}, // So [39] MAHJONG TILE GREEN DRAGON..MAHJONG TILE BACK
+ {0x1F030, 0x1F093, prN}, // So [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06
+ {0x1F0A0, 0x1F0AE, prN}, // So [15] PLAYING CARD BACK..PLAYING CARD KING OF SPADES
+ {0x1F0B1, 0x1F0BF, prN}, // So [15] PLAYING CARD ACE OF HEARTS..PLAYING CARD RED JOKER
+ {0x1F0C1, 0x1F0CE, prN}, // So [14] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD KING OF DIAMONDS
+ {0x1F0CF, 0x1F0CF, prW}, // So PLAYING CARD BLACK JOKER
+ {0x1F0D1, 0x1F0F5, prN}, // So [37] PLAYING CARD ACE OF CLUBS..PLAYING CARD TRUMP-21
+ {0x1F100, 0x1F10A, prA}, // No [11] DIGIT ZERO FULL STOP..DIGIT NINE COMMA
+ {0x1F10B, 0x1F10C, prN}, // No [2] DINGBAT CIRCLED SANS-SERIF DIGIT ZERO..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO
+ {0x1F10D, 0x1F10F, prN}, // So [3] CIRCLED ZERO WITH SLASH..CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH
+ {0x1F110, 0x1F12D, prA}, // So [30] PARENTHESIZED LATIN CAPITAL LETTER A..CIRCLED CD
+ {0x1F12E, 0x1F12F, prN}, // So [2] CIRCLED WZ..COPYLEFT SYMBOL
+ {0x1F130, 0x1F169, prA}, // So [58] SQUARED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z
+ {0x1F16A, 0x1F16F, prN}, // So [6] RAISED MC SIGN..CIRCLED HUMAN FIGURE
+ {0x1F170, 0x1F18D, prA}, // So [30] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED SA
+ {0x1F18E, 0x1F18E, prW}, // So NEGATIVE SQUARED AB
+ {0x1F18F, 0x1F190, prA}, // So [2] NEGATIVE SQUARED WC..SQUARE DJ
+ {0x1F191, 0x1F19A, prW}, // So [10] SQUARED CL..SQUARED VS
+ {0x1F19B, 0x1F1AC, prA}, // So [18] SQUARED THREE D..SQUARED VOD
+ {0x1F1AD, 0x1F1AD, prN}, // So MASK WORK SYMBOL
+ {0x1F1E6, 0x1F1FF, prN}, // So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z
+ {0x1F200, 0x1F202, prW}, // So [3] SQUARE HIRAGANA HOKA..SQUARED KATAKANA SA
+ {0x1F210, 0x1F23B, prW}, // So [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D
+ {0x1F240, 0x1F248, prW}, // So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557
+ {0x1F250, 0x1F251, prW}, // So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT
+ {0x1F260, 0x1F265, prW}, // So [6] ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI
+ {0x1F300, 0x1F320, prW}, // So [33] CYCLONE..SHOOTING STAR
+ {0x1F321, 0x1F32C, prN}, // So [12] THERMOMETER..WIND BLOWING FACE
+ {0x1F32D, 0x1F335, prW}, // So [9] HOT DOG..CACTUS
+ {0x1F336, 0x1F336, prN}, // So HOT PEPPER
+ {0x1F337, 0x1F37C, prW}, // So [70] TULIP..BABY BOTTLE
+ {0x1F37D, 0x1F37D, prN}, // So FORK AND KNIFE WITH PLATE
+ {0x1F37E, 0x1F393, prW}, // So [22] BOTTLE WITH POPPING CORK..GRADUATION CAP
+ {0x1F394, 0x1F39F, prN}, // So [12] HEART WITH TIP ON THE LEFT..ADMISSION TICKETS
+ {0x1F3A0, 0x1F3CA, prW}, // So [43] CAROUSEL HORSE..SWIMMER
+ {0x1F3CB, 0x1F3CE, prN}, // So [4] WEIGHT LIFTER..RACING CAR
+ {0x1F3CF, 0x1F3D3, prW}, // So [5] CRICKET BAT AND BALL..TABLE TENNIS PADDLE AND BALL
+ {0x1F3D4, 0x1F3DF, prN}, // So [12] SNOW CAPPED MOUNTAIN..STADIUM
+ {0x1F3E0, 0x1F3F0, prW}, // So [17] HOUSE BUILDING..EUROPEAN CASTLE
+ {0x1F3F1, 0x1F3F3, prN}, // So [3] WHITE PENNANT..WAVING WHITE FLAG
+ {0x1F3F4, 0x1F3F4, prW}, // So WAVING BLACK FLAG
+ {0x1F3F5, 0x1F3F7, prN}, // So [3] ROSETTE..LABEL
+ {0x1F3F8, 0x1F3FA, prW}, // So [3] BADMINTON RACQUET AND SHUTTLECOCK..AMPHORA
+ {0x1F3FB, 0x1F3FF, prW}, // Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6
+ {0x1F400, 0x1F43E, prW}, // So [63] RAT..PAW PRINTS
+ {0x1F43F, 0x1F43F, prN}, // So CHIPMUNK
+ {0x1F440, 0x1F440, prW}, // So EYES
+ {0x1F441, 0x1F441, prN}, // So EYE
+ {0x1F442, 0x1F4FC, prW}, // So [187] EAR..VIDEOCASSETTE
+ {0x1F4FD, 0x1F4FE, prN}, // So [2] FILM PROJECTOR..PORTABLE STEREO
+ {0x1F4FF, 0x1F53D, prW}, // So [63] PRAYER BEADS..DOWN-POINTING SMALL RED TRIANGLE
+ {0x1F53E, 0x1F54A, prN}, // So [13] LOWER RIGHT SHADOWED WHITE CIRCLE..DOVE OF PEACE
+ {0x1F54B, 0x1F54E, prW}, // So [4] KAABA..MENORAH WITH NINE BRANCHES
+ {0x1F54F, 0x1F54F, prN}, // So BOWL OF HYGIEIA
+ {0x1F550, 0x1F567, prW}, // So [24] CLOCK FACE ONE OCLOCK..CLOCK FACE TWELVE-THIRTY
+ {0x1F568, 0x1F579, prN}, // So [18] RIGHT SPEAKER..JOYSTICK
+ {0x1F57A, 0x1F57A, prW}, // So MAN DANCING
+ {0x1F57B, 0x1F594, prN}, // So [26] LEFT HAND TELEPHONE RECEIVER..REVERSED VICTORY HAND
+ {0x1F595, 0x1F596, prW}, // So [2] REVERSED HAND WITH MIDDLE FINGER EXTENDED..RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS
+ {0x1F597, 0x1F5A3, prN}, // So [13] WHITE DOWN POINTING LEFT HAND INDEX..BLACK DOWN POINTING BACKHAND INDEX
+ {0x1F5A4, 0x1F5A4, prW}, // So BLACK HEART
+ {0x1F5A5, 0x1F5FA, prN}, // So [86] DESKTOP COMPUTER..WORLD MAP
+ {0x1F5FB, 0x1F5FF, prW}, // So [5] MOUNT FUJI..MOYAI
+ {0x1F600, 0x1F64F, prW}, // So [80] GRINNING FACE..PERSON WITH FOLDED HANDS
+ {0x1F650, 0x1F67F, prN}, // So [48] NORTH WEST POINTING LEAF..REVERSE CHECKER BOARD
+ {0x1F680, 0x1F6C5, prW}, // So [70] ROCKET..LEFT LUGGAGE
+ {0x1F6C6, 0x1F6CB, prN}, // So [6] TRIANGLE WITH ROUNDED CORNERS..COUCH AND LAMP
+ {0x1F6CC, 0x1F6CC, prW}, // So SLEEPING ACCOMMODATION
+ {0x1F6CD, 0x1F6CF, prN}, // So [3] SHOPPING BAGS..BED
+ {0x1F6D0, 0x1F6D2, prW}, // So [3] PLACE OF WORSHIP..SHOPPING TROLLEY
+ {0x1F6D3, 0x1F6D4, prN}, // So [2] STUPA..PAGODA
+ {0x1F6D5, 0x1F6D7, prW}, // So [3] HINDU TEMPLE..ELEVATOR
+ {0x1F6DC, 0x1F6DF, prW}, // So [4] WIRELESS..RING BUOY
+ {0x1F6E0, 0x1F6EA, prN}, // So [11] HAMMER AND WRENCH..NORTHEAST-POINTING AIRPLANE
+ {0x1F6EB, 0x1F6EC, prW}, // So [2] AIRPLANE DEPARTURE..AIRPLANE ARRIVING
+ {0x1F6F0, 0x1F6F3, prN}, // So [4] SATELLITE..PASSENGER SHIP
+ {0x1F6F4, 0x1F6FC, prW}, // So [9] SCOOTER..ROLLER SKATE
+ {0x1F700, 0x1F776, prN}, // So [119] ALCHEMICAL SYMBOL FOR QUINTESSENCE..LUNAR ECLIPSE
+ {0x1F77B, 0x1F77F, prN}, // So [5] HAUMEA..ORCUS
+ {0x1F780, 0x1F7D9, prN}, // So [90] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..NINE POINTED WHITE STAR
+ {0x1F7E0, 0x1F7EB, prW}, // So [12] LARGE ORANGE CIRCLE..LARGE BROWN SQUARE
+ {0x1F7F0, 0x1F7F0, prW}, // So HEAVY EQUALS SIGN
+ {0x1F800, 0x1F80B, prN}, // So [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD
+ {0x1F810, 0x1F847, prN}, // So [56] LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD..DOWNWARDS HEAVY ARROW
+ {0x1F850, 0x1F859, prN}, // So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW
+ {0x1F860, 0x1F887, prN}, // So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW
+ {0x1F890, 0x1F8AD, prN}, // So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS
+ {0x1F8B0, 0x1F8B1, prN}, // So [2] ARROW POINTING UPWARDS THEN NORTH WEST..ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST
+ {0x1F900, 0x1F90B, prN}, // So [12] CIRCLED CROSS FORMEE WITH FOUR DOTS..DOWNWARD FACING NOTCHED HOOK WITH DOT
+ {0x1F90C, 0x1F93A, prW}, // So [47] PINCHED FINGERS..FENCER
+ {0x1F93B, 0x1F93B, prN}, // So MODERN PENTATHLON
+ {0x1F93C, 0x1F945, prW}, // So [10] WRESTLERS..GOAL NET
+ {0x1F946, 0x1F946, prN}, // So RIFLE
+ {0x1F947, 0x1F9FF, prW}, // So [185] FIRST PLACE MEDAL..NAZAR AMULET
+ {0x1FA00, 0x1FA53, prN}, // So [84] NEUTRAL CHESS KING..BLACK CHESS KNIGHT-BISHOP
+ {0x1FA60, 0x1FA6D, prN}, // So [14] XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER
+ {0x1FA70, 0x1FA7C, prW}, // So [13] BALLET SHOES..CRUTCH
+ {0x1FA80, 0x1FA88, prW}, // So [9] YO-YO..FLUTE
+ {0x1FA90, 0x1FABD, prW}, // So [46] RINGED PLANET..WING
+ {0x1FABF, 0x1FAC5, prW}, // So [7] GOOSE..PERSON WITH CROWN
+ {0x1FACE, 0x1FADB, prW}, // So [14] MOOSE..PEA POD
+ {0x1FAE0, 0x1FAE8, prW}, // So [9] MELTING FACE..SHAKING FACE
+ {0x1FAF0, 0x1FAF8, prW}, // So [9] HAND WITH INDEX FINGER AND THUMB CROSSED..RIGHTWARDS PUSHING HAND
+ {0x1FB00, 0x1FB92, prN}, // So [147] BLOCK SEXTANT-1..UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK
+ {0x1FB94, 0x1FBCA, prN}, // So [55] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..WHITE UP-POINTING CHEVRON
+ {0x1FBF0, 0x1FBF9, prN}, // Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE
+ {0x20000, 0x2A6DF, prW}, // Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF
+ {0x2A6E0, 0x2A6FF, prW}, // Cn [32] ..
+ {0x2A700, 0x2B739, prW}, // Lo [4154] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B739
+ {0x2B73A, 0x2B73F, prW}, // Cn [6] ..
+ {0x2B740, 0x2B81D, prW}, // Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D
+ {0x2B81E, 0x2B81F, prW}, // Cn [2] ..
+ {0x2B820, 0x2CEA1, prW}, // Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1
+ {0x2CEA2, 0x2CEAF, prW}, // Cn [14] ..
+ {0x2CEB0, 0x2EBE0, prW}, // Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0
+ {0x2EBE1, 0x2F7FF, prW}, // Cn [3103] ..
+ {0x2F800, 0x2FA1D, prW}, // Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
+ {0x2FA1E, 0x2FA1F, prW}, // Cn [2] ..
+ {0x2FA20, 0x2FFFD, prW}, // Cn [1502] ..
+ {0x30000, 0x3134A, prW}, // Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A
+ {0x3134B, 0x3134F, prW}, // Cn [5] ..
+ {0x31350, 0x323AF, prW}, // Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF
+ {0x323B0, 0x3FFFD, prW}, // Cn [56398] ..
+ {0xE0001, 0xE0001, prN}, // Cf LANGUAGE TAG
+ {0xE0020, 0xE007F, prN}, // Cf [96] TAG SPACE..CANCEL TAG
+ {0xE0100, 0xE01EF, prA}, // Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+ {0xF0000, 0xFFFFD, prA}, // Co [65534] ..
+ {0x100000, 0x10FFFD, prA}, // Co [65534] ..
+}
diff --git a/vendor/github.com/rivo/uniseg/emojipresentation.go b/vendor/github.com/rivo/uniseg/emojipresentation.go
new file mode 100644
index 00000000..9b5f499c
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/emojipresentation.go
@@ -0,0 +1,295 @@
+// Code generated via go generate from gen_properties.go. DO NOT EDIT.
+
+package uniseg
+
+// emojiPresentation are taken from
+//
+// and
+// https://unicode.org/Public/15.0.0/ucd/emoji/emoji-data.txt
+// ("Extended_Pictographic" only)
+// on September 5, 2023. See https://www.unicode.org/license.html for the Unicode
+// license agreement.
+var emojiPresentation = [][3]int{
+ {0x231A, 0x231B, prEmojiPresentation}, // E0.6 [2] (⌚..⌛) watch..hourglass done
+ {0x23E9, 0x23EC, prEmojiPresentation}, // E0.6 [4] (⏩..⏬) fast-forward button..fast down button
+ {0x23F0, 0x23F0, prEmojiPresentation}, // E0.6 [1] (⏰) alarm clock
+ {0x23F3, 0x23F3, prEmojiPresentation}, // E0.6 [1] (⏳) hourglass not done
+ {0x25FD, 0x25FE, prEmojiPresentation}, // E0.6 [2] (◽..◾) white medium-small square..black medium-small square
+ {0x2614, 0x2615, prEmojiPresentation}, // E0.6 [2] (☔..☕) umbrella with rain drops..hot beverage
+ {0x2648, 0x2653, prEmojiPresentation}, // E0.6 [12] (♈..♓) Aries..Pisces
+ {0x267F, 0x267F, prEmojiPresentation}, // E0.6 [1] (♿) wheelchair symbol
+ {0x2693, 0x2693, prEmojiPresentation}, // E0.6 [1] (⚓) anchor
+ {0x26A1, 0x26A1, prEmojiPresentation}, // E0.6 [1] (⚡) high voltage
+ {0x26AA, 0x26AB, prEmojiPresentation}, // E0.6 [2] (⚪..⚫) white circle..black circle
+ {0x26BD, 0x26BE, prEmojiPresentation}, // E0.6 [2] (⚽..⚾) soccer ball..baseball
+ {0x26C4, 0x26C5, prEmojiPresentation}, // E0.6 [2] (⛄..⛅) snowman without snow..sun behind cloud
+ {0x26CE, 0x26CE, prEmojiPresentation}, // E0.6 [1] (⛎) Ophiuchus
+ {0x26D4, 0x26D4, prEmojiPresentation}, // E0.6 [1] (⛔) no entry
+ {0x26EA, 0x26EA, prEmojiPresentation}, // E0.6 [1] (⛪) church
+ {0x26F2, 0x26F3, prEmojiPresentation}, // E0.6 [2] (⛲..⛳) fountain..flag in hole
+ {0x26F5, 0x26F5, prEmojiPresentation}, // E0.6 [1] (⛵) sailboat
+ {0x26FA, 0x26FA, prEmojiPresentation}, // E0.6 [1] (⛺) tent
+ {0x26FD, 0x26FD, prEmojiPresentation}, // E0.6 [1] (⛽) fuel pump
+ {0x2705, 0x2705, prEmojiPresentation}, // E0.6 [1] (✅) check mark button
+ {0x270A, 0x270B, prEmojiPresentation}, // E0.6 [2] (✊..✋) raised fist..raised hand
+ {0x2728, 0x2728, prEmojiPresentation}, // E0.6 [1] (✨) sparkles
+ {0x274C, 0x274C, prEmojiPresentation}, // E0.6 [1] (❌) cross mark
+ {0x274E, 0x274E, prEmojiPresentation}, // E0.6 [1] (❎) cross mark button
+ {0x2753, 0x2755, prEmojiPresentation}, // E0.6 [3] (❓..❕) red question mark..white exclamation mark
+ {0x2757, 0x2757, prEmojiPresentation}, // E0.6 [1] (❗) red exclamation mark
+ {0x2795, 0x2797, prEmojiPresentation}, // E0.6 [3] (➕..➗) plus..divide
+ {0x27B0, 0x27B0, prEmojiPresentation}, // E0.6 [1] (➰) curly loop
+ {0x27BF, 0x27BF, prEmojiPresentation}, // E1.0 [1] (➿) double curly loop
+ {0x2B1B, 0x2B1C, prEmojiPresentation}, // E0.6 [2] (⬛..⬜) black large square..white large square
+ {0x2B50, 0x2B50, prEmojiPresentation}, // E0.6 [1] (⭐) star
+ {0x2B55, 0x2B55, prEmojiPresentation}, // E0.6 [1] (⭕) hollow red circle
+ {0x1F004, 0x1F004, prEmojiPresentation}, // E0.6 [1] (🀄) mahjong red dragon
+ {0x1F0CF, 0x1F0CF, prEmojiPresentation}, // E0.6 [1] (🃏) joker
+ {0x1F18E, 0x1F18E, prEmojiPresentation}, // E0.6 [1] (🆎) AB button (blood type)
+ {0x1F191, 0x1F19A, prEmojiPresentation}, // E0.6 [10] (🆑..🆚) CL button..VS button
+ {0x1F1E6, 0x1F1FF, prEmojiPresentation}, // E0.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z
+ {0x1F201, 0x1F201, prEmojiPresentation}, // E0.6 [1] (🈁) Japanese “here” button
+ {0x1F21A, 0x1F21A, prEmojiPresentation}, // E0.6 [1] (🈚) Japanese “free of charge” button
+ {0x1F22F, 0x1F22F, prEmojiPresentation}, // E0.6 [1] (🈯) Japanese “reserved” button
+ {0x1F232, 0x1F236, prEmojiPresentation}, // E0.6 [5] (🈲..🈶) Japanese “prohibited” button..Japanese “not free of charge” button
+ {0x1F238, 0x1F23A, prEmojiPresentation}, // E0.6 [3] (🈸..🈺) Japanese “application” button..Japanese “open for business” button
+ {0x1F250, 0x1F251, prEmojiPresentation}, // E0.6 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button
+ {0x1F300, 0x1F30C, prEmojiPresentation}, // E0.6 [13] (🌀..🌌) cyclone..milky way
+ {0x1F30D, 0x1F30E, prEmojiPresentation}, // E0.7 [2] (🌍..🌎) globe showing Europe-Africa..globe showing Americas
+ {0x1F30F, 0x1F30F, prEmojiPresentation}, // E0.6 [1] (🌏) globe showing Asia-Australia
+ {0x1F310, 0x1F310, prEmojiPresentation}, // E1.0 [1] (🌐) globe with meridians
+ {0x1F311, 0x1F311, prEmojiPresentation}, // E0.6 [1] (🌑) new moon
+ {0x1F312, 0x1F312, prEmojiPresentation}, // E1.0 [1] (🌒) waxing crescent moon
+ {0x1F313, 0x1F315, prEmojiPresentation}, // E0.6 [3] (🌓..🌕) first quarter moon..full moon
+ {0x1F316, 0x1F318, prEmojiPresentation}, // E1.0 [3] (🌖..🌘) waning gibbous moon..waning crescent moon
+ {0x1F319, 0x1F319, prEmojiPresentation}, // E0.6 [1] (🌙) crescent moon
+ {0x1F31A, 0x1F31A, prEmojiPresentation}, // E1.0 [1] (🌚) new moon face
+ {0x1F31B, 0x1F31B, prEmojiPresentation}, // E0.6 [1] (🌛) first quarter moon face
+ {0x1F31C, 0x1F31C, prEmojiPresentation}, // E0.7 [1] (🌜) last quarter moon face
+ {0x1F31D, 0x1F31E, prEmojiPresentation}, // E1.0 [2] (🌝..🌞) full moon face..sun with face
+ {0x1F31F, 0x1F320, prEmojiPresentation}, // E0.6 [2] (🌟..🌠) glowing star..shooting star
+ {0x1F32D, 0x1F32F, prEmojiPresentation}, // E1.0 [3] (🌭..🌯) hot dog..burrito
+ {0x1F330, 0x1F331, prEmojiPresentation}, // E0.6 [2] (🌰..🌱) chestnut..seedling
+ {0x1F332, 0x1F333, prEmojiPresentation}, // E1.0 [2] (🌲..🌳) evergreen tree..deciduous tree
+ {0x1F334, 0x1F335, prEmojiPresentation}, // E0.6 [2] (🌴..🌵) palm tree..cactus
+ {0x1F337, 0x1F34A, prEmojiPresentation}, // E0.6 [20] (🌷..🍊) tulip..tangerine
+ {0x1F34B, 0x1F34B, prEmojiPresentation}, // E1.0 [1] (🍋) lemon
+ {0x1F34C, 0x1F34F, prEmojiPresentation}, // E0.6 [4] (🍌..🍏) banana..green apple
+ {0x1F350, 0x1F350, prEmojiPresentation}, // E1.0 [1] (🍐) pear
+ {0x1F351, 0x1F37B, prEmojiPresentation}, // E0.6 [43] (🍑..🍻) peach..clinking beer mugs
+ {0x1F37C, 0x1F37C, prEmojiPresentation}, // E1.0 [1] (🍼) baby bottle
+ {0x1F37E, 0x1F37F, prEmojiPresentation}, // E1.0 [2] (🍾..🍿) bottle with popping cork..popcorn
+ {0x1F380, 0x1F393, prEmojiPresentation}, // E0.6 [20] (🎀..🎓) ribbon..graduation cap
+ {0x1F3A0, 0x1F3C4, prEmojiPresentation}, // E0.6 [37] (🎠..🏄) carousel horse..person surfing
+ {0x1F3C5, 0x1F3C5, prEmojiPresentation}, // E1.0 [1] (🏅) sports medal
+ {0x1F3C6, 0x1F3C6, prEmojiPresentation}, // E0.6 [1] (🏆) trophy
+ {0x1F3C7, 0x1F3C7, prEmojiPresentation}, // E1.0 [1] (🏇) horse racing
+ {0x1F3C8, 0x1F3C8, prEmojiPresentation}, // E0.6 [1] (🏈) american football
+ {0x1F3C9, 0x1F3C9, prEmojiPresentation}, // E1.0 [1] (🏉) rugby football
+ {0x1F3CA, 0x1F3CA, prEmojiPresentation}, // E0.6 [1] (🏊) person swimming
+ {0x1F3CF, 0x1F3D3, prEmojiPresentation}, // E1.0 [5] (🏏..🏓) cricket game..ping pong
+ {0x1F3E0, 0x1F3E3, prEmojiPresentation}, // E0.6 [4] (🏠..🏣) house..Japanese post office
+ {0x1F3E4, 0x1F3E4, prEmojiPresentation}, // E1.0 [1] (🏤) post office
+ {0x1F3E5, 0x1F3F0, prEmojiPresentation}, // E0.6 [12] (🏥..🏰) hospital..castle
+ {0x1F3F4, 0x1F3F4, prEmojiPresentation}, // E1.0 [1] (🏴) black flag
+ {0x1F3F8, 0x1F407, prEmojiPresentation}, // E1.0 [16] (🏸..🐇) badminton..rabbit
+ {0x1F408, 0x1F408, prEmojiPresentation}, // E0.7 [1] (🐈) cat
+ {0x1F409, 0x1F40B, prEmojiPresentation}, // E1.0 [3] (🐉..🐋) dragon..whale
+ {0x1F40C, 0x1F40E, prEmojiPresentation}, // E0.6 [3] (🐌..🐎) snail..horse
+ {0x1F40F, 0x1F410, prEmojiPresentation}, // E1.0 [2] (🐏..🐐) ram..goat
+ {0x1F411, 0x1F412, prEmojiPresentation}, // E0.6 [2] (🐑..🐒) ewe..monkey
+ {0x1F413, 0x1F413, prEmojiPresentation}, // E1.0 [1] (🐓) rooster
+ {0x1F414, 0x1F414, prEmojiPresentation}, // E0.6 [1] (🐔) chicken
+ {0x1F415, 0x1F415, prEmojiPresentation}, // E0.7 [1] (🐕) dog
+ {0x1F416, 0x1F416, prEmojiPresentation}, // E1.0 [1] (🐖) pig
+ {0x1F417, 0x1F429, prEmojiPresentation}, // E0.6 [19] (🐗..🐩) boar..poodle
+ {0x1F42A, 0x1F42A, prEmojiPresentation}, // E1.0 [1] (🐪) camel
+ {0x1F42B, 0x1F43E, prEmojiPresentation}, // E0.6 [20] (🐫..🐾) two-hump camel..paw prints
+ {0x1F440, 0x1F440, prEmojiPresentation}, // E0.6 [1] (👀) eyes
+ {0x1F442, 0x1F464, prEmojiPresentation}, // E0.6 [35] (👂..👤) ear..bust in silhouette
+ {0x1F465, 0x1F465, prEmojiPresentation}, // E1.0 [1] (👥) busts in silhouette
+ {0x1F466, 0x1F46B, prEmojiPresentation}, // E0.6 [6] (👦..👫) boy..woman and man holding hands
+ {0x1F46C, 0x1F46D, prEmojiPresentation}, // E1.0 [2] (👬..👭) men holding hands..women holding hands
+ {0x1F46E, 0x1F4AC, prEmojiPresentation}, // E0.6 [63] (👮..💬) police officer..speech balloon
+ {0x1F4AD, 0x1F4AD, prEmojiPresentation}, // E1.0 [1] (💭) thought balloon
+ {0x1F4AE, 0x1F4B5, prEmojiPresentation}, // E0.6 [8] (💮..💵) white flower..dollar banknote
+ {0x1F4B6, 0x1F4B7, prEmojiPresentation}, // E1.0 [2] (💶..💷) euro banknote..pound banknote
+ {0x1F4B8, 0x1F4EB, prEmojiPresentation}, // E0.6 [52] (💸..📫) money with wings..closed mailbox with raised flag
+ {0x1F4EC, 0x1F4ED, prEmojiPresentation}, // E0.7 [2] (📬..📭) open mailbox with raised flag..open mailbox with lowered flag
+ {0x1F4EE, 0x1F4EE, prEmojiPresentation}, // E0.6 [1] (📮) postbox
+ {0x1F4EF, 0x1F4EF, prEmojiPresentation}, // E1.0 [1] (📯) postal horn
+ {0x1F4F0, 0x1F4F4, prEmojiPresentation}, // E0.6 [5] (📰..📴) newspaper..mobile phone off
+ {0x1F4F5, 0x1F4F5, prEmojiPresentation}, // E1.0 [1] (📵) no mobile phones
+ {0x1F4F6, 0x1F4F7, prEmojiPresentation}, // E0.6 [2] (📶..📷) antenna bars..camera
+ {0x1F4F8, 0x1F4F8, prEmojiPresentation}, // E1.0 [1] (📸) camera with flash
+ {0x1F4F9, 0x1F4FC, prEmojiPresentation}, // E0.6 [4] (📹..📼) video camera..videocassette
+ {0x1F4FF, 0x1F502, prEmojiPresentation}, // E1.0 [4] (📿..🔂) prayer beads..repeat single button
+ {0x1F503, 0x1F503, prEmojiPresentation}, // E0.6 [1] (🔃) clockwise vertical arrows
+ {0x1F504, 0x1F507, prEmojiPresentation}, // E1.0 [4] (🔄..🔇) counterclockwise arrows button..muted speaker
+ {0x1F508, 0x1F508, prEmojiPresentation}, // E0.7 [1] (🔈) speaker low volume
+ {0x1F509, 0x1F509, prEmojiPresentation}, // E1.0 [1] (🔉) speaker medium volume
+ {0x1F50A, 0x1F514, prEmojiPresentation}, // E0.6 [11] (🔊..🔔) speaker high volume..bell
+ {0x1F515, 0x1F515, prEmojiPresentation}, // E1.0 [1] (🔕) bell with slash
+ {0x1F516, 0x1F52B, prEmojiPresentation}, // E0.6 [22] (🔖..🔫) bookmark..water pistol
+ {0x1F52C, 0x1F52D, prEmojiPresentation}, // E1.0 [2] (🔬..🔭) microscope..telescope
+ {0x1F52E, 0x1F53D, prEmojiPresentation}, // E0.6 [16] (🔮..🔽) crystal ball..downwards button
+ {0x1F54B, 0x1F54E, prEmojiPresentation}, // E1.0 [4] (🕋..🕎) kaaba..menorah
+ {0x1F550, 0x1F55B, prEmojiPresentation}, // E0.6 [12] (🕐..🕛) one o’clock..twelve o’clock
+ {0x1F55C, 0x1F567, prEmojiPresentation}, // E0.7 [12] (🕜..🕧) one-thirty..twelve-thirty
+ {0x1F57A, 0x1F57A, prEmojiPresentation}, // E3.0 [1] (🕺) man dancing
+ {0x1F595, 0x1F596, prEmojiPresentation}, // E1.0 [2] (🖕..🖖) middle finger..vulcan salute
+ {0x1F5A4, 0x1F5A4, prEmojiPresentation}, // E3.0 [1] (🖤) black heart
+ {0x1F5FB, 0x1F5FF, prEmojiPresentation}, // E0.6 [5] (🗻..🗿) mount fuji..moai
+ {0x1F600, 0x1F600, prEmojiPresentation}, // E1.0 [1] (😀) grinning face
+ {0x1F601, 0x1F606, prEmojiPresentation}, // E0.6 [6] (😁..😆) beaming face with smiling eyes..grinning squinting face
+ {0x1F607, 0x1F608, prEmojiPresentation}, // E1.0 [2] (😇..😈) smiling face with halo..smiling face with horns
+ {0x1F609, 0x1F60D, prEmojiPresentation}, // E0.6 [5] (😉..😍) winking face..smiling face with heart-eyes
+ {0x1F60E, 0x1F60E, prEmojiPresentation}, // E1.0 [1] (😎) smiling face with sunglasses
+ {0x1F60F, 0x1F60F, prEmojiPresentation}, // E0.6 [1] (😏) smirking face
+ {0x1F610, 0x1F610, prEmojiPresentation}, // E0.7 [1] (😐) neutral face
+ {0x1F611, 0x1F611, prEmojiPresentation}, // E1.0 [1] (😑) expressionless face
+ {0x1F612, 0x1F614, prEmojiPresentation}, // E0.6 [3] (😒..😔) unamused face..pensive face
+ {0x1F615, 0x1F615, prEmojiPresentation}, // E1.0 [1] (😕) confused face
+ {0x1F616, 0x1F616, prEmojiPresentation}, // E0.6 [1] (😖) confounded face
+ {0x1F617, 0x1F617, prEmojiPresentation}, // E1.0 [1] (😗) kissing face
+ {0x1F618, 0x1F618, prEmojiPresentation}, // E0.6 [1] (😘) face blowing a kiss
+ {0x1F619, 0x1F619, prEmojiPresentation}, // E1.0 [1] (😙) kissing face with smiling eyes
+ {0x1F61A, 0x1F61A, prEmojiPresentation}, // E0.6 [1] (😚) kissing face with closed eyes
+ {0x1F61B, 0x1F61B, prEmojiPresentation}, // E1.0 [1] (😛) face with tongue
+ {0x1F61C, 0x1F61E, prEmojiPresentation}, // E0.6 [3] (😜..😞) winking face with tongue..disappointed face
+ {0x1F61F, 0x1F61F, prEmojiPresentation}, // E1.0 [1] (😟) worried face
+ {0x1F620, 0x1F625, prEmojiPresentation}, // E0.6 [6] (😠..😥) angry face..sad but relieved face
+ {0x1F626, 0x1F627, prEmojiPresentation}, // E1.0 [2] (😦..😧) frowning face with open mouth..anguished face
+ {0x1F628, 0x1F62B, prEmojiPresentation}, // E0.6 [4] (😨..😫) fearful face..tired face
+ {0x1F62C, 0x1F62C, prEmojiPresentation}, // E1.0 [1] (😬) grimacing face
+ {0x1F62D, 0x1F62D, prEmojiPresentation}, // E0.6 [1] (😭) loudly crying face
+ {0x1F62E, 0x1F62F, prEmojiPresentation}, // E1.0 [2] (😮..😯) face with open mouth..hushed face
+ {0x1F630, 0x1F633, prEmojiPresentation}, // E0.6 [4] (😰..😳) anxious face with sweat..flushed face
+ {0x1F634, 0x1F634, prEmojiPresentation}, // E1.0 [1] (😴) sleeping face
+ {0x1F635, 0x1F635, prEmojiPresentation}, // E0.6 [1] (😵) face with crossed-out eyes
+ {0x1F636, 0x1F636, prEmojiPresentation}, // E1.0 [1] (😶) face without mouth
+ {0x1F637, 0x1F640, prEmojiPresentation}, // E0.6 [10] (😷..🙀) face with medical mask..weary cat
+ {0x1F641, 0x1F644, prEmojiPresentation}, // E1.0 [4] (🙁..🙄) slightly frowning face..face with rolling eyes
+ {0x1F645, 0x1F64F, prEmojiPresentation}, // E0.6 [11] (🙅..🙏) person gesturing NO..folded hands
+ {0x1F680, 0x1F680, prEmojiPresentation}, // E0.6 [1] (🚀) rocket
+ {0x1F681, 0x1F682, prEmojiPresentation}, // E1.0 [2] (🚁..🚂) helicopter..locomotive
+ {0x1F683, 0x1F685, prEmojiPresentation}, // E0.6 [3] (🚃..🚅) railway car..bullet train
+ {0x1F686, 0x1F686, prEmojiPresentation}, // E1.0 [1] (🚆) train
+ {0x1F687, 0x1F687, prEmojiPresentation}, // E0.6 [1] (🚇) metro
+ {0x1F688, 0x1F688, prEmojiPresentation}, // E1.0 [1] (🚈) light rail
+ {0x1F689, 0x1F689, prEmojiPresentation}, // E0.6 [1] (🚉) station
+ {0x1F68A, 0x1F68B, prEmojiPresentation}, // E1.0 [2] (🚊..🚋) tram..tram car
+ {0x1F68C, 0x1F68C, prEmojiPresentation}, // E0.6 [1] (🚌) bus
+ {0x1F68D, 0x1F68D, prEmojiPresentation}, // E0.7 [1] (🚍) oncoming bus
+ {0x1F68E, 0x1F68E, prEmojiPresentation}, // E1.0 [1] (🚎) trolleybus
+ {0x1F68F, 0x1F68F, prEmojiPresentation}, // E0.6 [1] (🚏) bus stop
+ {0x1F690, 0x1F690, prEmojiPresentation}, // E1.0 [1] (🚐) minibus
+ {0x1F691, 0x1F693, prEmojiPresentation}, // E0.6 [3] (🚑..🚓) ambulance..police car
+ {0x1F694, 0x1F694, prEmojiPresentation}, // E0.7 [1] (🚔) oncoming police car
+ {0x1F695, 0x1F695, prEmojiPresentation}, // E0.6 [1] (🚕) taxi
+ {0x1F696, 0x1F696, prEmojiPresentation}, // E1.0 [1] (🚖) oncoming taxi
+ {0x1F697, 0x1F697, prEmojiPresentation}, // E0.6 [1] (🚗) automobile
+ {0x1F698, 0x1F698, prEmojiPresentation}, // E0.7 [1] (🚘) oncoming automobile
+ {0x1F699, 0x1F69A, prEmojiPresentation}, // E0.6 [2] (🚙..🚚) sport utility vehicle..delivery truck
+ {0x1F69B, 0x1F6A1, prEmojiPresentation}, // E1.0 [7] (🚛..🚡) articulated lorry..aerial tramway
+ {0x1F6A2, 0x1F6A2, prEmojiPresentation}, // E0.6 [1] (🚢) ship
+ {0x1F6A3, 0x1F6A3, prEmojiPresentation}, // E1.0 [1] (🚣) person rowing boat
+ {0x1F6A4, 0x1F6A5, prEmojiPresentation}, // E0.6 [2] (🚤..🚥) speedboat..horizontal traffic light
+ {0x1F6A6, 0x1F6A6, prEmojiPresentation}, // E1.0 [1] (🚦) vertical traffic light
+ {0x1F6A7, 0x1F6AD, prEmojiPresentation}, // E0.6 [7] (🚧..🚭) construction..no smoking
+ {0x1F6AE, 0x1F6B1, prEmojiPresentation}, // E1.0 [4] (🚮..🚱) litter in bin sign..non-potable water
+ {0x1F6B2, 0x1F6B2, prEmojiPresentation}, // E0.6 [1] (🚲) bicycle
+ {0x1F6B3, 0x1F6B5, prEmojiPresentation}, // E1.0 [3] (🚳..🚵) no bicycles..person mountain biking
+ {0x1F6B6, 0x1F6B6, prEmojiPresentation}, // E0.6 [1] (🚶) person walking
+ {0x1F6B7, 0x1F6B8, prEmojiPresentation}, // E1.0 [2] (🚷..🚸) no pedestrians..children crossing
+ {0x1F6B9, 0x1F6BE, prEmojiPresentation}, // E0.6 [6] (🚹..🚾) men’s room..water closet
+ {0x1F6BF, 0x1F6BF, prEmojiPresentation}, // E1.0 [1] (🚿) shower
+ {0x1F6C0, 0x1F6C0, prEmojiPresentation}, // E0.6 [1] (🛀) person taking bath
+ {0x1F6C1, 0x1F6C5, prEmojiPresentation}, // E1.0 [5] (🛁..🛅) bathtub..left luggage
+ {0x1F6CC, 0x1F6CC, prEmojiPresentation}, // E1.0 [1] (🛌) person in bed
+ {0x1F6D0, 0x1F6D0, prEmojiPresentation}, // E1.0 [1] (🛐) place of worship
+ {0x1F6D1, 0x1F6D2, prEmojiPresentation}, // E3.0 [2] (🛑..🛒) stop sign..shopping cart
+ {0x1F6D5, 0x1F6D5, prEmojiPresentation}, // E12.0 [1] (🛕) hindu temple
+ {0x1F6D6, 0x1F6D7, prEmojiPresentation}, // E13.0 [2] (🛖..🛗) hut..elevator
+ {0x1F6DC, 0x1F6DC, prEmojiPresentation}, // E15.0 [1] (🛜) wireless
+ {0x1F6DD, 0x1F6DF, prEmojiPresentation}, // E14.0 [3] (🛝..🛟) playground slide..ring buoy
+ {0x1F6EB, 0x1F6EC, prEmojiPresentation}, // E1.0 [2] (🛫..🛬) airplane departure..airplane arrival
+ {0x1F6F4, 0x1F6F6, prEmojiPresentation}, // E3.0 [3] (🛴..🛶) kick scooter..canoe
+ {0x1F6F7, 0x1F6F8, prEmojiPresentation}, // E5.0 [2] (🛷..🛸) sled..flying saucer
+ {0x1F6F9, 0x1F6F9, prEmojiPresentation}, // E11.0 [1] (🛹) skateboard
+ {0x1F6FA, 0x1F6FA, prEmojiPresentation}, // E12.0 [1] (🛺) auto rickshaw
+ {0x1F6FB, 0x1F6FC, prEmojiPresentation}, // E13.0 [2] (🛻..🛼) pickup truck..roller skate
+ {0x1F7E0, 0x1F7EB, prEmojiPresentation}, // E12.0 [12] (🟠..🟫) orange circle..brown square
+ {0x1F7F0, 0x1F7F0, prEmojiPresentation}, // E14.0 [1] (🟰) heavy equals sign
+ {0x1F90C, 0x1F90C, prEmojiPresentation}, // E13.0 [1] (🤌) pinched fingers
+ {0x1F90D, 0x1F90F, prEmojiPresentation}, // E12.0 [3] (🤍..🤏) white heart..pinching hand
+ {0x1F910, 0x1F918, prEmojiPresentation}, // E1.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns
+ {0x1F919, 0x1F91E, prEmojiPresentation}, // E3.0 [6] (🤙..🤞) call me hand..crossed fingers
+ {0x1F91F, 0x1F91F, prEmojiPresentation}, // E5.0 [1] (🤟) love-you gesture
+ {0x1F920, 0x1F927, prEmojiPresentation}, // E3.0 [8] (🤠..🤧) cowboy hat face..sneezing face
+ {0x1F928, 0x1F92F, prEmojiPresentation}, // E5.0 [8] (🤨..🤯) face with raised eyebrow..exploding head
+ {0x1F930, 0x1F930, prEmojiPresentation}, // E3.0 [1] (🤰) pregnant woman
+ {0x1F931, 0x1F932, prEmojiPresentation}, // E5.0 [2] (🤱..🤲) breast-feeding..palms up together
+ {0x1F933, 0x1F93A, prEmojiPresentation}, // E3.0 [8] (🤳..🤺) selfie..person fencing
+ {0x1F93C, 0x1F93E, prEmojiPresentation}, // E3.0 [3] (🤼..🤾) people wrestling..person playing handball
+ {0x1F93F, 0x1F93F, prEmojiPresentation}, // E12.0 [1] (🤿) diving mask
+ {0x1F940, 0x1F945, prEmojiPresentation}, // E3.0 [6] (🥀..🥅) wilted flower..goal net
+ {0x1F947, 0x1F94B, prEmojiPresentation}, // E3.0 [5] (🥇..🥋) 1st place medal..martial arts uniform
+ {0x1F94C, 0x1F94C, prEmojiPresentation}, // E5.0 [1] (🥌) curling stone
+ {0x1F94D, 0x1F94F, prEmojiPresentation}, // E11.0 [3] (🥍..🥏) lacrosse..flying disc
+ {0x1F950, 0x1F95E, prEmojiPresentation}, // E3.0 [15] (🥐..🥞) croissant..pancakes
+ {0x1F95F, 0x1F96B, prEmojiPresentation}, // E5.0 [13] (🥟..🥫) dumpling..canned food
+ {0x1F96C, 0x1F970, prEmojiPresentation}, // E11.0 [5] (🥬..🥰) leafy green..smiling face with hearts
+ {0x1F971, 0x1F971, prEmojiPresentation}, // E12.0 [1] (🥱) yawning face
+ {0x1F972, 0x1F972, prEmojiPresentation}, // E13.0 [1] (🥲) smiling face with tear
+ {0x1F973, 0x1F976, prEmojiPresentation}, // E11.0 [4] (🥳..🥶) partying face..cold face
+ {0x1F977, 0x1F978, prEmojiPresentation}, // E13.0 [2] (🥷..🥸) ninja..disguised face
+ {0x1F979, 0x1F979, prEmojiPresentation}, // E14.0 [1] (🥹) face holding back tears
+ {0x1F97A, 0x1F97A, prEmojiPresentation}, // E11.0 [1] (🥺) pleading face
+ {0x1F97B, 0x1F97B, prEmojiPresentation}, // E12.0 [1] (🥻) sari
+ {0x1F97C, 0x1F97F, prEmojiPresentation}, // E11.0 [4] (🥼..🥿) lab coat..flat shoe
+ {0x1F980, 0x1F984, prEmojiPresentation}, // E1.0 [5] (🦀..🦄) crab..unicorn
+ {0x1F985, 0x1F991, prEmojiPresentation}, // E3.0 [13] (🦅..🦑) eagle..squid
+ {0x1F992, 0x1F997, prEmojiPresentation}, // E5.0 [6] (🦒..🦗) giraffe..cricket
+ {0x1F998, 0x1F9A2, prEmojiPresentation}, // E11.0 [11] (🦘..🦢) kangaroo..swan
+ {0x1F9A3, 0x1F9A4, prEmojiPresentation}, // E13.0 [2] (🦣..🦤) mammoth..dodo
+ {0x1F9A5, 0x1F9AA, prEmojiPresentation}, // E12.0 [6] (🦥..🦪) sloth..oyster
+ {0x1F9AB, 0x1F9AD, prEmojiPresentation}, // E13.0 [3] (🦫..🦭) beaver..seal
+ {0x1F9AE, 0x1F9AF, prEmojiPresentation}, // E12.0 [2] (🦮..🦯) guide dog..white cane
+ {0x1F9B0, 0x1F9B9, prEmojiPresentation}, // E11.0 [10] (🦰..🦹) red hair..supervillain
+ {0x1F9BA, 0x1F9BF, prEmojiPresentation}, // E12.0 [6] (🦺..🦿) safety vest..mechanical leg
+ {0x1F9C0, 0x1F9C0, prEmojiPresentation}, // E1.0 [1] (🧀) cheese wedge
+ {0x1F9C1, 0x1F9C2, prEmojiPresentation}, // E11.0 [2] (🧁..🧂) cupcake..salt
+ {0x1F9C3, 0x1F9CA, prEmojiPresentation}, // E12.0 [8] (🧃..🧊) beverage box..ice
+ {0x1F9CB, 0x1F9CB, prEmojiPresentation}, // E13.0 [1] (🧋) bubble tea
+ {0x1F9CC, 0x1F9CC, prEmojiPresentation}, // E14.0 [1] (🧌) troll
+ {0x1F9CD, 0x1F9CF, prEmojiPresentation}, // E12.0 [3] (🧍..🧏) person standing..deaf person
+ {0x1F9D0, 0x1F9E6, prEmojiPresentation}, // E5.0 [23] (🧐..🧦) face with monocle..socks
+ {0x1F9E7, 0x1F9FF, prEmojiPresentation}, // E11.0 [25] (🧧..🧿) red envelope..nazar amulet
+ {0x1FA70, 0x1FA73, prEmojiPresentation}, // E12.0 [4] (🩰..🩳) ballet shoes..shorts
+ {0x1FA74, 0x1FA74, prEmojiPresentation}, // E13.0 [1] (🩴) thong sandal
+ {0x1FA75, 0x1FA77, prEmojiPresentation}, // E15.0 [3] (🩵..🩷) light blue heart..pink heart
+ {0x1FA78, 0x1FA7A, prEmojiPresentation}, // E12.0 [3] (🩸..🩺) drop of blood..stethoscope
+ {0x1FA7B, 0x1FA7C, prEmojiPresentation}, // E14.0 [2] (🩻..🩼) x-ray..crutch
+ {0x1FA80, 0x1FA82, prEmojiPresentation}, // E12.0 [3] (🪀..🪂) yo-yo..parachute
+ {0x1FA83, 0x1FA86, prEmojiPresentation}, // E13.0 [4] (🪃..🪆) boomerang..nesting dolls
+ {0x1FA87, 0x1FA88, prEmojiPresentation}, // E15.0 [2] (🪇..🪈) maracas..flute
+ {0x1FA90, 0x1FA95, prEmojiPresentation}, // E12.0 [6] (🪐..🪕) ringed planet..banjo
+ {0x1FA96, 0x1FAA8, prEmojiPresentation}, // E13.0 [19] (🪖..🪨) military helmet..rock
+ {0x1FAA9, 0x1FAAC, prEmojiPresentation}, // E14.0 [4] (🪩..🪬) mirror ball..hamsa
+ {0x1FAAD, 0x1FAAF, prEmojiPresentation}, // E15.0 [3] (🪭..🪯) folding hand fan..khanda
+ {0x1FAB0, 0x1FAB6, prEmojiPresentation}, // E13.0 [7] (🪰..🪶) fly..feather
+ {0x1FAB7, 0x1FABA, prEmojiPresentation}, // E14.0 [4] (🪷..🪺) lotus..nest with eggs
+ {0x1FABB, 0x1FABD, prEmojiPresentation}, // E15.0 [3] (🪻..🪽) hyacinth..wing
+ {0x1FABF, 0x1FABF, prEmojiPresentation}, // E15.0 [1] (🪿) goose
+ {0x1FAC0, 0x1FAC2, prEmojiPresentation}, // E13.0 [3] (🫀..🫂) anatomical heart..people hugging
+ {0x1FAC3, 0x1FAC5, prEmojiPresentation}, // E14.0 [3] (🫃..🫅) pregnant man..person with crown
+ {0x1FACE, 0x1FACF, prEmojiPresentation}, // E15.0 [2] (🫎..🫏) moose..donkey
+ {0x1FAD0, 0x1FAD6, prEmojiPresentation}, // E13.0 [7] (🫐..🫖) blueberries..teapot
+ {0x1FAD7, 0x1FAD9, prEmojiPresentation}, // E14.0 [3] (🫗..🫙) pouring liquid..jar
+ {0x1FADA, 0x1FADB, prEmojiPresentation}, // E15.0 [2] (🫚..🫛) ginger root..pea pod
+ {0x1FAE0, 0x1FAE7, prEmojiPresentation}, // E14.0 [8] (🫠..🫧) melting face..bubbles
+ {0x1FAE8, 0x1FAE8, prEmojiPresentation}, // E15.0 [1] (🫨) shaking face
+ {0x1FAF0, 0x1FAF6, prEmojiPresentation}, // E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands
+ {0x1FAF7, 0x1FAF8, prEmojiPresentation}, // E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand
+}
diff --git a/vendor/github.com/rivo/uniseg/gen_breaktest.go b/vendor/github.com/rivo/uniseg/gen_breaktest.go
new file mode 100644
index 00000000..6bfbeb5e
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/gen_breaktest.go
@@ -0,0 +1,215 @@
+//go:build generate
+
+// This program generates a Go containing a slice of test cases based on the
+// Unicode Character Database auxiliary data files. The command line arguments
+// are as follows:
+//
+// 1. The name of the Unicode data file (just the filename, without extension).
+// 2. The name of the locally generated Go file.
+// 3. The name of the slice containing the test cases.
+// 4. The name of the generator, for logging purposes.
+//
+//go:generate go run gen_breaktest.go GraphemeBreakTest graphemebreak_test.go graphemeBreakTestCases graphemes
+//go:generate go run gen_breaktest.go WordBreakTest wordbreak_test.go wordBreakTestCases words
+//go:generate go run gen_breaktest.go SentenceBreakTest sentencebreak_test.go sentenceBreakTestCases sentences
+//go:generate go run gen_breaktest.go LineBreakTest linebreak_test.go lineBreakTestCases lines
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "go/format"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ "time"
+)
+
+// We want to test against a specific version rather than the latest. When the
+// package is upgraded to a new version, change these to generate new tests.
+const (
+ testCaseURL = `https://www.unicode.org/Public/15.0.0/ucd/auxiliary/%s.txt`
+)
+
+func main() {
+ if len(os.Args) < 5 {
+ fmt.Println("Not enough arguments, see code for details")
+ os.Exit(1)
+ }
+
+ log.SetPrefix("gen_breaktest (" + os.Args[4] + "): ")
+ log.SetFlags(0)
+
+ // Read text of testcases and parse into Go source code.
+ src, err := parse(fmt.Sprintf(testCaseURL, os.Args[1]))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Format the Go code.
+ formatted, err := format.Source(src)
+ if err != nil {
+ log.Fatalln("gofmt:", err)
+ }
+
+ // Write it out.
+ log.Print("Writing to ", os.Args[2])
+ if err := ioutil.WriteFile(os.Args[2], formatted, 0644); err != nil {
+ log.Fatal(err)
+ }
+}
+
+// parse reads a break text file, either from a local file or from a URL. It
+// parses the file data into Go source code representing the test cases.
+func parse(url string) ([]byte, error) {
+ log.Printf("Parsing %s", url)
+ res, err := http.Get(url)
+ if err != nil {
+ return nil, err
+ }
+ body := res.Body
+ defer body.Close()
+
+ buf := new(bytes.Buffer)
+ buf.Grow(120 << 10)
+ buf.WriteString(`// Code generated via go generate from gen_breaktest.go. DO NOT EDIT.
+
+package uniseg
+
+// ` + os.Args[3] + ` are Grapheme testcases taken from
+// ` + url + `
+// on ` + time.Now().Format("January 2, 2006") + `. See
+// https://www.unicode.org/license.html for the Unicode license agreement.
+var ` + os.Args[3] + ` = []testCase {
+`)
+
+ sc := bufio.NewScanner(body)
+ num := 1
+ var line []byte
+ original := make([]byte, 0, 64)
+ expected := make([]byte, 0, 64)
+ for sc.Scan() {
+ num++
+ line = sc.Bytes()
+ if len(line) == 0 || line[0] == '#' {
+ continue
+ }
+ var comment []byte
+ if i := bytes.IndexByte(line, '#'); i >= 0 {
+ comment = bytes.TrimSpace(line[i+1:])
+ line = bytes.TrimSpace(line[:i])
+ }
+ original, expected, err := parseRuneSequence(line, original[:0], expected[:0])
+ if err != nil {
+ return nil, fmt.Errorf(`line %d: %v: %q`, num, err, line)
+ }
+ fmt.Fprintf(buf, "\t{original: \"%s\", expected: %s}, // %s\n", original, expected, comment)
+ }
+ if err := sc.Err(); err != nil {
+ return nil, err
+ }
+
+ // Check for final "# EOF", useful check if we're streaming via HTTP
+ if !bytes.Equal(line, []byte("# EOF")) {
+ return nil, fmt.Errorf(`line %d: exected "# EOF" as final line, got %q`, num, line)
+ }
+ buf.WriteString("}\n")
+ return buf.Bytes(), nil
+}
+
+// Used by parseRuneSequence to match input via bytes.HasPrefix.
+var (
+ prefixBreak = []byte("÷ ")
+ prefixDontBreak = []byte("× ")
+ breakOk = []byte("÷")
+ breakNo = []byte("×")
+)
+
+// parseRuneSequence parses a rune + breaking opportunity sequence from b
+// and appends the Go code for testcase.original to orig
+// and appends the Go code for testcase.expected to exp.
+// It retuns the new orig and exp slices.
+//
+// E.g. for the input b="÷ 0020 × 0308 ÷ 1F1E6 ÷"
+// it will append
+//
+// "\u0020\u0308\U0001F1E6"
+//
+// and "[][]rune{{0x0020,0x0308},{0x1F1E6},}"
+// to orig and exp respectively.
+//
+// The formatting of exp is expected to be cleaned up by gofmt or format.Source.
+// Note we explicitly require the sequence to start with ÷ and we implicitly
+// require it to end with ÷.
+func parseRuneSequence(b, orig, exp []byte) ([]byte, []byte, error) {
+ // Check for and remove first ÷ or ×.
+ if !bytes.HasPrefix(b, prefixBreak) && !bytes.HasPrefix(b, prefixDontBreak) {
+ return nil, nil, errors.New("expected ÷ or × as first character")
+ }
+ if bytes.HasPrefix(b, prefixBreak) {
+ b = b[len(prefixBreak):]
+ } else {
+ b = b[len(prefixDontBreak):]
+ }
+
+ boundary := true
+ exp = append(exp, "[][]rune{"...)
+ for len(b) > 0 {
+ if boundary {
+ exp = append(exp, '{')
+ }
+ exp = append(exp, "0x"...)
+ // Find end of hex digits.
+ var i int
+ for i = 0; i < len(b) && b[i] != ' '; i++ {
+ if d := b[i]; ('0' <= d || d <= '9') ||
+ ('A' <= d || d <= 'F') ||
+ ('a' <= d || d <= 'f') {
+ continue
+ }
+ return nil, nil, errors.New("bad hex digit")
+ }
+ switch i {
+ case 4:
+ orig = append(orig, "\\u"...)
+ case 5:
+ orig = append(orig, "\\U000"...)
+ default:
+ return nil, nil, errors.New("unsupport code point hex length")
+ }
+ orig = append(orig, b[:i]...)
+ exp = append(exp, b[:i]...)
+ b = b[i:]
+
+ // Check for space between hex and ÷ or ×.
+ if len(b) < 1 || b[0] != ' ' {
+ return nil, nil, errors.New("bad input")
+ }
+ b = b[1:]
+
+ // Check for next boundary.
+ switch {
+ case bytes.HasPrefix(b, breakOk):
+ boundary = true
+ b = b[len(breakOk):]
+ case bytes.HasPrefix(b, breakNo):
+ boundary = false
+ b = b[len(breakNo):]
+ default:
+ return nil, nil, errors.New("missing ÷ or ×")
+ }
+ if boundary {
+ exp = append(exp, '}')
+ }
+ exp = append(exp, ',')
+ if len(b) > 0 && b[0] == ' ' {
+ b = b[1:]
+ }
+ }
+ exp = append(exp, '}')
+ return orig, exp, nil
+}
diff --git a/vendor/github.com/rivo/uniseg/gen_properties.go b/vendor/github.com/rivo/uniseg/gen_properties.go
new file mode 100644
index 00000000..8992d2c5
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/gen_properties.go
@@ -0,0 +1,261 @@
+//go:build generate
+
+// This program generates a property file in Go file from Unicode Character
+// Database auxiliary data files. The command line arguments are as follows:
+//
+// 1. The name of the Unicode data file (just the filename, without extension).
+// Can be "-" (to skip) if the emoji flag is included.
+// 2. The name of the locally generated Go file.
+// 3. The name of the slice mapping code points to properties.
+// 4. The name of the generator, for logging purposes.
+// 5. (Optional) Flags, comma-separated. The following flags are available:
+// - "emojis=": include the specified emoji properties (e.g.
+// "Extended_Pictographic").
+// - "gencat": include general category properties.
+//
+//go:generate go run gen_properties.go auxiliary/GraphemeBreakProperty graphemeproperties.go graphemeCodePoints graphemes emojis=Extended_Pictographic
+//go:generate go run gen_properties.go auxiliary/WordBreakProperty wordproperties.go workBreakCodePoints words emojis=Extended_Pictographic
+//go:generate go run gen_properties.go auxiliary/SentenceBreakProperty sentenceproperties.go sentenceBreakCodePoints sentences
+//go:generate go run gen_properties.go LineBreak lineproperties.go lineBreakCodePoints lines gencat
+//go:generate go run gen_properties.go EastAsianWidth eastasianwidth.go eastAsianWidth eastasianwidth
+//go:generate go run gen_properties.go - emojipresentation.go emojiPresentation emojipresentation emojis=Emoji_Presentation
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "go/format"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// We want to test against a specific version rather than the latest. When the
+// package is upgraded to a new version, change these to generate new tests.
+const (
+ propertyURL = `https://www.unicode.org/Public/15.0.0/ucd/%s.txt`
+ emojiURL = `https://unicode.org/Public/15.0.0/ucd/emoji/emoji-data.txt`
+)
+
+// The regular expression for a line containing a code point range property.
+var propertyPattern = regexp.MustCompile(`^([0-9A-F]{4,6})(\.\.([0-9A-F]{4,6}))?\s*;\s*([A-Za-z0-9_]+)\s*#\s(.+)$`)
+
+func main() {
+ if len(os.Args) < 5 {
+ fmt.Println("Not enough arguments, see code for details")
+ os.Exit(1)
+ }
+
+ log.SetPrefix("gen_properties (" + os.Args[4] + "): ")
+ log.SetFlags(0)
+
+ // Parse flags.
+ flags := make(map[string]string)
+ if len(os.Args) >= 6 {
+ for _, flag := range strings.Split(os.Args[5], ",") {
+ flagFields := strings.Split(flag, "=")
+ if len(flagFields) == 1 {
+ flags[flagFields[0]] = "yes"
+ } else {
+ flags[flagFields[0]] = flagFields[1]
+ }
+ }
+ }
+
+ // Parse the text file and generate Go source code from it.
+ _, includeGeneralCategory := flags["gencat"]
+ var mainURL string
+ if os.Args[1] != "-" {
+ mainURL = fmt.Sprintf(propertyURL, os.Args[1])
+ }
+ src, err := parse(mainURL, flags["emojis"], includeGeneralCategory)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Format the Go code.
+ formatted, err := format.Source([]byte(src))
+ if err != nil {
+ log.Fatal("gofmt:", err)
+ }
+
+ // Save it to the (local) target file.
+ log.Print("Writing to ", os.Args[2])
+ if err := ioutil.WriteFile(os.Args[2], formatted, 0644); err != nil {
+ log.Fatal(err)
+ }
+}
+
+// parse parses the Unicode Properties text files located at the given URLs and
+// returns their equivalent Go source code to be used in the uniseg package. If
+// "emojiProperty" is not an empty string, emoji code points for that emoji
+// property (e.g. "Extended_Pictographic") will be included. In those cases, you
+// may pass an empty "propertyURL" to skip parsing the main properties file. If
+// "includeGeneralCategory" is true, the Unicode General Category property will
+// be extracted from the comments and included in the output.
+func parse(propertyURL, emojiProperty string, includeGeneralCategory bool) (string, error) {
+ if propertyURL == "" && emojiProperty == "" {
+ return "", errors.New("no properties to parse")
+ }
+
+ // Temporary buffer to hold properties.
+ var properties [][4]string
+
+ // Open the first URL.
+ if propertyURL != "" {
+ log.Printf("Parsing %s", propertyURL)
+ res, err := http.Get(propertyURL)
+ if err != nil {
+ return "", err
+ }
+ in1 := res.Body
+ defer in1.Close()
+
+ // Parse it.
+ scanner := bufio.NewScanner(in1)
+ num := 0
+ for scanner.Scan() {
+ num++
+ line := strings.TrimSpace(scanner.Text())
+
+ // Skip comments and empty lines.
+ if strings.HasPrefix(line, "#") || line == "" {
+ continue
+ }
+
+ // Everything else must be a code point range, a property and a comment.
+ from, to, property, comment, err := parseProperty(line)
+ if err != nil {
+ return "", fmt.Errorf("%s line %d: %v", os.Args[4], num, err)
+ }
+ properties = append(properties, [4]string{from, to, property, comment})
+ }
+ if err := scanner.Err(); err != nil {
+ return "", err
+ }
+ }
+
+ // Open the second URL.
+ if emojiProperty != "" {
+ log.Printf("Parsing %s", emojiURL)
+ res, err := http.Get(emojiURL)
+ if err != nil {
+ return "", err
+ }
+ in2 := res.Body
+ defer in2.Close()
+
+ // Parse it.
+ scanner := bufio.NewScanner(in2)
+ num := 0
+ for scanner.Scan() {
+ num++
+ line := scanner.Text()
+
+ // Skip comments, empty lines, and everything not containing
+ // "Extended_Pictographic".
+ if strings.HasPrefix(line, "#") || line == "" || !strings.Contains(line, emojiProperty) {
+ continue
+ }
+
+ // Everything else must be a code point range, a property and a comment.
+ from, to, property, comment, err := parseProperty(line)
+ if err != nil {
+ return "", fmt.Errorf("emojis line %d: %v", num, err)
+ }
+ properties = append(properties, [4]string{from, to, property, comment})
+ }
+ if err := scanner.Err(); err != nil {
+ return "", err
+ }
+ }
+
+ // Avoid overflow during binary search.
+ if len(properties) >= 1<<31 {
+ return "", errors.New("too many properties")
+ }
+
+ // Sort properties.
+ sort.Slice(properties, func(i, j int) bool {
+ left, _ := strconv.ParseUint(properties[i][0], 16, 64)
+ right, _ := strconv.ParseUint(properties[j][0], 16, 64)
+ return left < right
+ })
+
+ // Header.
+ var (
+ buf bytes.Buffer
+ emojiComment string
+ )
+ columns := 3
+ if includeGeneralCategory {
+ columns = 4
+ }
+ if emojiURL != "" {
+ emojiComment = `
+// and
+// ` + emojiURL + `
+// ("Extended_Pictographic" only)`
+ }
+ buf.WriteString(`// Code generated via go generate from gen_properties.go. DO NOT EDIT.
+
+package uniseg
+
+// ` + os.Args[3] + ` are taken from
+// ` + propertyURL + emojiComment + `
+// on ` + time.Now().Format("January 2, 2006") + `. See https://www.unicode.org/license.html for the Unicode
+// license agreement.
+var ` + os.Args[3] + ` = [][` + strconv.Itoa(columns) + `]int{
+ `)
+
+ // Properties.
+ for _, prop := range properties {
+ if includeGeneralCategory {
+ generalCategory := "gc" + prop[3][:2]
+ if generalCategory == "gcL&" {
+ generalCategory = "gcLC"
+ }
+ prop[3] = prop[3][3:]
+ fmt.Fprintf(&buf, "{0x%s,0x%s,%s,%s}, // %s\n", prop[0], prop[1], translateProperty("pr", prop[2]), generalCategory, prop[3])
+ } else {
+ fmt.Fprintf(&buf, "{0x%s,0x%s,%s}, // %s\n", prop[0], prop[1], translateProperty("pr", prop[2]), prop[3])
+ }
+ }
+
+ // Tail.
+ buf.WriteString("}")
+
+ return buf.String(), nil
+}
+
+// parseProperty parses a line of the Unicode properties text file containing a
+// property for a code point range and returns it along with its comment.
+func parseProperty(line string) (from, to, property, comment string, err error) {
+ fields := propertyPattern.FindStringSubmatch(line)
+ if fields == nil {
+ err = errors.New("no property found")
+ return
+ }
+ from = fields[1]
+ to = fields[3]
+ if to == "" {
+ to = from
+ }
+ property = fields[4]
+ comment = fields[5]
+ return
+}
+
+// translateProperty translates a property name as used in the Unicode data file
+// to a variable used in the Go code.
+func translateProperty(prefix, property string) string {
+ return prefix + strings.ReplaceAll(property, "_", "")
+}
diff --git a/vendor/github.com/rivo/uniseg/grapheme.go b/vendor/github.com/rivo/uniseg/grapheme.go
index 207157f5..b12403d4 100644
--- a/vendor/github.com/rivo/uniseg/grapheme.go
+++ b/vendor/github.com/rivo/uniseg/grapheme.go
@@ -2,267 +2,330 @@ package uniseg
import "unicode/utf8"
-// The states of the grapheme cluster parser.
-const (
- grAny = iota
- grCR
- grControlLF
- grL
- grLVV
- grLVTT
- grPrepend
- grExtendedPictographic
- grExtendedPictographicZWJ
- grRIOdd
- grRIEven
-)
-
-// The grapheme cluster parser's breaking instructions.
-const (
- grNoBoundary = iota
- grBoundary
-)
-
-// The grapheme cluster parser's state transitions. Maps (state, property) to
-// (new state, breaking instruction, rule number). The breaking instruction
-// always refers to the boundary between the last and next code point.
+// Graphemes implements an iterator over Unicode grapheme clusters, or
+// user-perceived characters. While iterating, it also provides information
+// about word boundaries, sentence boundaries, line breaks, and monospace
+// character widths.
//
-// This map is queried as follows:
+// After constructing the class via [NewGraphemes] for a given string "str",
+// [Graphemes.Next] is called for every grapheme cluster in a loop until it
+// returns false. Inside the loop, information about the grapheme cluster as
+// well as boundary information and character width is available via the various
+// methods (see examples below).
//
-// 1. Find specific state + specific property. Stop if found.
-// 2. Find specific state + any property.
-// 3. Find any state + specific property.
-// 4. If only (2) or (3) (but not both) was found, stop.
-// 5. If both (2) and (3) were found, use state and breaking instruction from
-// the transition with the lower rule number, prefer (3) if rule numbers
-// are equal. Stop.
-// 6. Assume grAny and grBoundary.
-var grTransitions = map[[2]int][3]int{
- // GB5
- {grAny, prCR}: {grCR, grBoundary, 50},
- {grAny, prLF}: {grControlLF, grBoundary, 50},
- {grAny, prControl}: {grControlLF, grBoundary, 50},
-
- // GB4
- {grCR, prAny}: {grAny, grBoundary, 40},
- {grControlLF, prAny}: {grAny, grBoundary, 40},
-
- // GB3.
- {grCR, prLF}: {grAny, grNoBoundary, 30},
-
- // GB6.
- {grAny, prL}: {grL, grBoundary, 9990},
- {grL, prL}: {grL, grNoBoundary, 60},
- {grL, prV}: {grLVV, grNoBoundary, 60},
- {grL, prLV}: {grLVV, grNoBoundary, 60},
- {grL, prLVT}: {grLVTT, grNoBoundary, 60},
-
- // GB7.
- {grAny, prLV}: {grLVV, grBoundary, 9990},
- {grAny, prV}: {grLVV, grBoundary, 9990},
- {grLVV, prV}: {grLVV, grNoBoundary, 70},
- {grLVV, prT}: {grLVTT, grNoBoundary, 70},
-
- // GB8.
- {grAny, prLVT}: {grLVTT, grBoundary, 9990},
- {grAny, prT}: {grLVTT, grBoundary, 9990},
- {grLVTT, prT}: {grLVTT, grNoBoundary, 80},
-
- // GB9.
- {grAny, prExtend}: {grAny, grNoBoundary, 90},
- {grAny, prZWJ}: {grAny, grNoBoundary, 90},
-
- // GB9a.
- {grAny, prSpacingMark}: {grAny, grNoBoundary, 91},
-
- // GB9b.
- {grAny, prPreprend}: {grPrepend, grBoundary, 9990},
- {grPrepend, prAny}: {grAny, grNoBoundary, 92},
-
- // GB11.
- {grAny, prExtendedPictographic}: {grExtendedPictographic, grBoundary, 9990},
- {grExtendedPictographic, prExtend}: {grExtendedPictographic, grNoBoundary, 110},
- {grExtendedPictographic, prZWJ}: {grExtendedPictographicZWJ, grNoBoundary, 110},
- {grExtendedPictographicZWJ, prExtendedPictographic}: {grExtendedPictographic, grNoBoundary, 110},
-
- // GB12 / GB13.
- {grAny, prRegionalIndicator}: {grRIOdd, grBoundary, 9990},
- {grRIOdd, prRegionalIndicator}: {grRIEven, grNoBoundary, 120},
- {grRIEven, prRegionalIndicator}: {grRIOdd, grBoundary, 120},
-}
-
-// Graphemes implements an iterator over Unicode extended grapheme clusters,
-// specified in the Unicode Standard Annex #29. Grapheme clusters correspond to
-// "user-perceived characters". These characters often consist of multiple
-// code points (e.g. the "woman kissing woman" emoji consists of 8 code points:
-// woman + ZWJ + heavy black heart (2 code points) + ZWJ + kiss mark + ZWJ +
-// woman) and the rules described in Annex #29 must be applied to group those
-// code points into clusters perceived by the user as one character.
+// This class basically wraps the [StepString] parser and provides a convenient
+// interface to it. If you are only interested in some parts of this package's
+// functionality, using the specialized functions starting with "First" is
+// almost always faster.
type Graphemes struct {
- // The code points over which this class iterates.
- codePoints []rune
+ // The original string.
+ original string
+
+ // The remaining string to be parsed.
+ remaining string
- // The (byte-based) indices of the code points into the original string plus
- // len(original string). Thus, len(indices) = len(codePoints) + 1.
- indices []int
+ // The current grapheme cluster.
+ cluster string
- // The current grapheme cluster to be returned. These are indices into
- // codePoints/indices. If start == end, we either haven't started iterating
- // yet (0) or the iteration has already completed (1).
- start, end int
+ // The byte offset of the current grapheme cluster relative to the original
+ // string.
+ offset int
- // The index of the next code point to be parsed.
- pos int
+ // The current boundary information of the [Step] parser.
+ boundaries int
- // The current state of the code point parser.
+ // The current state of the [Step] parser.
state int
}
// NewGraphemes returns a new grapheme cluster iterator.
-func NewGraphemes(s string) *Graphemes {
- l := utf8.RuneCountInString(s)
- codePoints := make([]rune, l)
- indices := make([]int, l+1)
- i := 0
- for pos, r := range s {
- codePoints[i] = r
- indices[i] = pos
- i++
+func NewGraphemes(str string) *Graphemes {
+ return &Graphemes{
+ original: str,
+ remaining: str,
+ state: -1,
}
- indices[l] = len(s)
- g := &Graphemes{
- codePoints: codePoints,
- indices: indices,
- }
- g.Next() // Parse ahead.
- return g
}
// Next advances the iterator by one grapheme cluster and returns false if no
// clusters are left. This function must be called before the first cluster is
// accessed.
func (g *Graphemes) Next() bool {
- g.start = g.end
-
- // The state transition gives us a boundary instruction BEFORE the next code
- // point so we always need to stay ahead by one code point.
-
- // Parse the next code point.
- for g.pos <= len(g.codePoints) {
- // GB2.
- if g.pos == len(g.codePoints) {
- g.end = g.pos
- g.pos++
- break
- }
-
- // Determine the property of the next character.
- nextProperty := property(g.codePoints[g.pos])
- g.pos++
-
- // Find the applicable transition.
- var boundary bool
- transition, ok := grTransitions[[2]int{g.state, nextProperty}]
- if ok {
- // We have a specific transition. We'll use it.
- g.state = transition[0]
- boundary = transition[1] == grBoundary
- } else {
- // No specific transition found. Try the less specific ones.
- transAnyProp, okAnyProp := grTransitions[[2]int{g.state, prAny}]
- transAnyState, okAnyState := grTransitions[[2]int{grAny, nextProperty}]
- if okAnyProp && okAnyState {
- // Both apply. We'll use a mix (see comments for grTransitions).
- g.state = transAnyState[0]
- boundary = transAnyState[1] == grBoundary
- if transAnyProp[2] < transAnyState[2] {
- g.state = transAnyProp[0]
- boundary = transAnyProp[1] == grBoundary
- }
- } else if okAnyProp {
- // We only have a specific state.
- g.state = transAnyProp[0]
- boundary = transAnyProp[1] == grBoundary
- // This branch will probably never be reached because okAnyState will
- // always be true given the current transition map. But we keep it here
- // for future modifications to the transition map where this may not be
- // true anymore.
- } else if okAnyState {
- // We only have a specific property.
- g.state = transAnyState[0]
- boundary = transAnyState[1] == grBoundary
- } else {
- // No known transition. GB999: Any x Any.
- g.state = grAny
- boundary = true
- }
- }
-
- // If we found a cluster boundary, let's stop here. The current cluster will
- // be the one that just ended.
- if g.pos-1 == 0 /* GB1 */ || boundary {
- g.end = g.pos - 1
- break
- }
+ if len(g.remaining) == 0 {
+ // We're already past the end.
+ g.state = -2
+ g.cluster = ""
+ return false
}
-
- return g.start != g.end
+ g.offset += len(g.cluster)
+ g.cluster, g.remaining, g.boundaries, g.state = StepString(g.remaining, g.state)
+ return true
}
// Runes returns a slice of runes (code points) which corresponds to the current
-// grapheme cluster. If the iterator is already past the end or Next() has not
-// yet been called, nil is returned.
+// grapheme cluster. If the iterator is already past the end or [Graphemes.Next]
+// has not yet been called, nil is returned.
func (g *Graphemes) Runes() []rune {
- if g.start == g.end {
+ if g.state < 0 {
return nil
}
- return g.codePoints[g.start:g.end]
+ return []rune(g.cluster)
}
// Str returns a substring of the original string which corresponds to the
-// current grapheme cluster. If the iterator is already past the end or Next()
-// has not yet been called, an empty string is returned.
+// current grapheme cluster. If the iterator is already past the end or
+// [Graphemes.Next] has not yet been called, an empty string is returned.
func (g *Graphemes) Str() string {
- if g.start == g.end {
- return ""
- }
- return string(g.codePoints[g.start:g.end])
+ return g.cluster
}
// Bytes returns a byte slice which corresponds to the current grapheme cluster.
-// If the iterator is already past the end or Next() has not yet been called,
-// nil is returned.
+// If the iterator is already past the end or [Graphemes.Next] has not yet been
+// called, nil is returned.
func (g *Graphemes) Bytes() []byte {
- if g.start == g.end {
+ if g.state < 0 {
return nil
}
- return []byte(string(g.codePoints[g.start:g.end]))
+ return []byte(g.cluster)
}
// Positions returns the interval of the current grapheme cluster as byte
// positions into the original string. The first returned value "from" indexes
// the first byte and the second returned value "to" indexes the first byte that
// is not included anymore, i.e. str[from:to] is the current grapheme cluster of
-// the original string "str". If Next() has not yet been called, both values are
-// 0. If the iterator is already past the end, both values are 1.
+// the original string "str". If [Graphemes.Next] has not yet been called, both
+// values are 0. If the iterator is already past the end, both values are 1.
func (g *Graphemes) Positions() (int, int) {
- return g.indices[g.start], g.indices[g.end]
+ if g.state == -1 {
+ return 0, 0
+ } else if g.state == -2 {
+ return 1, 1
+ }
+ return g.offset, g.offset + len(g.cluster)
+}
+
+// IsWordBoundary returns true if a word ends after the current grapheme
+// cluster.
+func (g *Graphemes) IsWordBoundary() bool {
+ if g.state < 0 {
+ return true
+ }
+ return g.boundaries&MaskWord != 0
+}
+
+// IsSentenceBoundary returns true if a sentence ends after the current
+// grapheme cluster.
+func (g *Graphemes) IsSentenceBoundary() bool {
+ if g.state < 0 {
+ return true
+ }
+ return g.boundaries&MaskSentence != 0
+}
+
+// LineBreak returns whether the line can be broken after the current grapheme
+// cluster. A value of [LineDontBreak] means the line may not be broken, a value
+// of [LineMustBreak] means the line must be broken, and a value of
+// [LineCanBreak] means the line may or may not be broken.
+func (g *Graphemes) LineBreak() int {
+ if g.state == -1 {
+ return LineDontBreak
+ }
+ if g.state == -2 {
+ return LineMustBreak
+ }
+ return g.boundaries & MaskLine
+}
+
+// Width returns the monospace width of the current grapheme cluster.
+func (g *Graphemes) Width() int {
+ if g.state < 0 {
+ return 0
+ }
+ return g.boundaries >> ShiftWidth
}
// Reset puts the iterator into its initial state such that the next call to
-// Next() sets it to the first grapheme cluster again.
+// [Graphemes.Next] sets it to the first grapheme cluster again.
func (g *Graphemes) Reset() {
- g.start, g.end, g.pos, g.state = 0, 0, 0, grAny
- g.Next() // Parse ahead again.
+ g.state = -1
+ g.offset = 0
+ g.cluster = ""
+ g.remaining = g.original
}
// GraphemeClusterCount returns the number of user-perceived characters
-// (grapheme clusters) for the given string. To calculate this number, it
-// iterates through the string using the Graphemes iterator.
+// (grapheme clusters) for the given string.
func GraphemeClusterCount(s string) (n int) {
- g := NewGraphemes(s)
- for g.Next() {
+ state := -1
+ for len(s) > 0 {
+ _, s, _, state = FirstGraphemeClusterInString(s, state)
n++
}
return
}
+
+// ReverseString reverses the given string while observing grapheme cluster
+// boundaries.
+func ReverseString(s string) string {
+ str := []byte(s)
+ reversed := make([]byte, len(str))
+ state := -1
+ index := len(str)
+ for len(str) > 0 {
+ var cluster []byte
+ cluster, str, _, state = FirstGraphemeCluster(str, state)
+ index -= len(cluster)
+ copy(reversed[index:], cluster)
+ if index <= len(str)/2 {
+ break
+ }
+ }
+ return string(reversed)
+}
+
+// The number of bits the grapheme property must be shifted to make place for
+// grapheme states.
+const shiftGraphemePropState = 4
+
+// FirstGraphemeCluster returns the first grapheme cluster found in the given
+// byte slice according to the rules of [Unicode Standard Annex #29, Grapheme
+// Cluster Boundaries]. This function can be called continuously to extract all
+// grapheme clusters from a byte slice, as illustrated in the example below.
+//
+// If you don't know the current state, for example when calling the function
+// for the first time, you must pass -1. For consecutive calls, pass the state
+// and rest slice returned by the previous call.
+//
+// The "rest" slice is the sub-slice of the original byte slice "b" starting
+// after the last byte of the identified grapheme cluster. If the length of the
+// "rest" slice is 0, the entire byte slice "b" has been processed. The
+// "cluster" byte slice is the sub-slice of the input slice containing the
+// identified grapheme cluster.
+//
+// The returned width is the width of the grapheme cluster for most monospace
+// fonts where a value of 1 represents one character cell.
+//
+// Given an empty byte slice "b", the function returns nil values.
+//
+// While slightly less convenient than using the Graphemes class, this function
+// has much better performance and makes no allocations. It lends itself well to
+// large byte slices.
+//
+// [Unicode Standard Annex #29, Grapheme Cluster Boundaries]: http://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries
+func FirstGraphemeCluster(b []byte, state int) (cluster, rest []byte, width, newState int) {
+ // An empty byte slice returns nothing.
+ if len(b) == 0 {
+ return
+ }
+
+ // Extract the first rune.
+ r, length := utf8.DecodeRune(b)
+ if len(b) <= length { // If we're already past the end, there is nothing else to parse.
+ var prop int
+ if state < 0 {
+ prop = propertyGraphemes(r)
+ } else {
+ prop = state >> shiftGraphemePropState
+ }
+ return b, nil, runeWidth(r, prop), grAny | (prop << shiftGraphemePropState)
+ }
+
+ // If we don't know the state, determine it now.
+ var firstProp int
+ if state < 0 {
+ state, firstProp, _ = transitionGraphemeState(state, r)
+ } else {
+ firstProp = state >> shiftGraphemePropState
+ }
+ width += runeWidth(r, firstProp)
+
+ // Transition until we find a boundary.
+ for {
+ var (
+ prop int
+ boundary bool
+ )
+
+ r, l := utf8.DecodeRune(b[length:])
+ state, prop, boundary = transitionGraphemeState(state&maskGraphemeState, r)
+
+ if boundary {
+ return b[:length], b[length:], width, state | (prop << shiftGraphemePropState)
+ }
+
+ if firstProp == prExtendedPictographic {
+ if r == vs15 {
+ width = 1
+ } else if r == vs16 {
+ width = 2
+ }
+ } else if firstProp != prRegionalIndicator && firstProp != prL {
+ width += runeWidth(r, prop)
+ }
+
+ length += l
+ if len(b) <= length {
+ return b, nil, width, grAny | (prop << shiftGraphemePropState)
+ }
+ }
+}
+
+// FirstGraphemeClusterInString is like [FirstGraphemeCluster] but its input and
+// outputs are strings.
+func FirstGraphemeClusterInString(str string, state int) (cluster, rest string, width, newState int) {
+ // An empty string returns nothing.
+ if len(str) == 0 {
+ return
+ }
+
+ // Extract the first rune.
+ r, length := utf8.DecodeRuneInString(str)
+ if len(str) <= length { // If we're already past the end, there is nothing else to parse.
+ var prop int
+ if state < 0 {
+ prop = propertyGraphemes(r)
+ } else {
+ prop = state >> shiftGraphemePropState
+ }
+ return str, "", runeWidth(r, prop), grAny | (prop << shiftGraphemePropState)
+ }
+
+ // If we don't know the state, determine it now.
+ var firstProp int
+ if state < 0 {
+ state, firstProp, _ = transitionGraphemeState(state, r)
+ } else {
+ firstProp = state >> shiftGraphemePropState
+ }
+ width += runeWidth(r, firstProp)
+
+ // Transition until we find a boundary.
+ for {
+ var (
+ prop int
+ boundary bool
+ )
+
+ r, l := utf8.DecodeRuneInString(str[length:])
+ state, prop, boundary = transitionGraphemeState(state&maskGraphemeState, r)
+
+ if boundary {
+ return str[:length], str[length:], width, state | (prop << shiftGraphemePropState)
+ }
+
+ if firstProp == prExtendedPictographic {
+ if r == vs15 {
+ width = 1
+ } else if r == vs16 {
+ width = 2
+ }
+ } else if firstProp != prRegionalIndicator && firstProp != prL {
+ width += runeWidth(r, prop)
+ }
+
+ length += l
+ if len(str) <= length {
+ return str, "", width, grAny | (prop << shiftGraphemePropState)
+ }
+ }
+}
diff --git a/vendor/github.com/rivo/uniseg/graphemeproperties.go b/vendor/github.com/rivo/uniseg/graphemeproperties.go
new file mode 100644
index 00000000..0aff4a61
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/graphemeproperties.go
@@ -0,0 +1,1915 @@
+// Code generated via go generate from gen_properties.go. DO NOT EDIT.
+
+package uniseg
+
+// graphemeCodePoints are taken from
+// https://www.unicode.org/Public/15.0.0/ucd/auxiliary/GraphemeBreakProperty.txt
+// and
+// https://unicode.org/Public/15.0.0/ucd/emoji/emoji-data.txt
+// ("Extended_Pictographic" only)
+// on September 5, 2023. See https://www.unicode.org/license.html for the Unicode
+// license agreement.
+var graphemeCodePoints = [][3]int{
+ {0x0000, 0x0009, prControl}, // Cc [10] ..
+ {0x000A, 0x000A, prLF}, // Cc
+ {0x000B, 0x000C, prControl}, // Cc [2] ..
+ {0x000D, 0x000D, prCR}, // Cc
+ {0x000E, 0x001F, prControl}, // Cc [18] ..
+ {0x007F, 0x009F, prControl}, // Cc [33] ..
+ {0x00A9, 0x00A9, prExtendedPictographic}, // E0.6 [1] (©️) copyright
+ {0x00AD, 0x00AD, prControl}, // Cf SOFT HYPHEN
+ {0x00AE, 0x00AE, prExtendedPictographic}, // E0.6 [1] (®️) registered
+ {0x0300, 0x036F, prExtend}, // Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X
+ {0x0483, 0x0487, prExtend}, // Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE
+ {0x0488, 0x0489, prExtend}, // Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN
+ {0x0591, 0x05BD, prExtend}, // Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG
+ {0x05BF, 0x05BF, prExtend}, // Mn HEBREW POINT RAFE
+ {0x05C1, 0x05C2, prExtend}, // Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT
+ {0x05C4, 0x05C5, prExtend}, // Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT
+ {0x05C7, 0x05C7, prExtend}, // Mn HEBREW POINT QAMATS QATAN
+ {0x0600, 0x0605, prPrepend}, // Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE
+ {0x0610, 0x061A, prExtend}, // Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA
+ {0x061C, 0x061C, prControl}, // Cf ARABIC LETTER MARK
+ {0x064B, 0x065F, prExtend}, // Mn [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW
+ {0x0670, 0x0670, prExtend}, // Mn ARABIC LETTER SUPERSCRIPT ALEF
+ {0x06D6, 0x06DC, prExtend}, // Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN
+ {0x06DD, 0x06DD, prPrepend}, // Cf ARABIC END OF AYAH
+ {0x06DF, 0x06E4, prExtend}, // Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA
+ {0x06E7, 0x06E8, prExtend}, // Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON
+ {0x06EA, 0x06ED, prExtend}, // Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM
+ {0x070F, 0x070F, prPrepend}, // Cf SYRIAC ABBREVIATION MARK
+ {0x0711, 0x0711, prExtend}, // Mn SYRIAC LETTER SUPERSCRIPT ALAPH
+ {0x0730, 0x074A, prExtend}, // Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH
+ {0x07A6, 0x07B0, prExtend}, // Mn [11] THAANA ABAFILI..THAANA SUKUN
+ {0x07EB, 0x07F3, prExtend}, // Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+ {0x07FD, 0x07FD, prExtend}, // Mn NKO DANTAYALAN
+ {0x0816, 0x0819, prExtend}, // Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH
+ {0x081B, 0x0823, prExtend}, // Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A
+ {0x0825, 0x0827, prExtend}, // Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U
+ {0x0829, 0x082D, prExtend}, // Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA
+ {0x0859, 0x085B, prExtend}, // Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK
+ {0x0890, 0x0891, prPrepend}, // Cf [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE
+ {0x0898, 0x089F, prExtend}, // Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA
+ {0x08CA, 0x08E1, prExtend}, // Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA
+ {0x08E2, 0x08E2, prPrepend}, // Cf ARABIC DISPUTED END OF AYAH
+ {0x08E3, 0x0902, prExtend}, // Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA
+ {0x0903, 0x0903, prSpacingMark}, // Mc DEVANAGARI SIGN VISARGA
+ {0x093A, 0x093A, prExtend}, // Mn DEVANAGARI VOWEL SIGN OE
+ {0x093B, 0x093B, prSpacingMark}, // Mc DEVANAGARI VOWEL SIGN OOE
+ {0x093C, 0x093C, prExtend}, // Mn DEVANAGARI SIGN NUKTA
+ {0x093E, 0x0940, prSpacingMark}, // Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II
+ {0x0941, 0x0948, prExtend}, // Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI
+ {0x0949, 0x094C, prSpacingMark}, // Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU
+ {0x094D, 0x094D, prExtend}, // Mn DEVANAGARI SIGN VIRAMA
+ {0x094E, 0x094F, prSpacingMark}, // Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW
+ {0x0951, 0x0957, prExtend}, // Mn [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE
+ {0x0962, 0x0963, prExtend}, // Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL
+ {0x0981, 0x0981, prExtend}, // Mn BENGALI SIGN CANDRABINDU
+ {0x0982, 0x0983, prSpacingMark}, // Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA
+ {0x09BC, 0x09BC, prExtend}, // Mn BENGALI SIGN NUKTA
+ {0x09BE, 0x09BE, prExtend}, // Mc BENGALI VOWEL SIGN AA
+ {0x09BF, 0x09C0, prSpacingMark}, // Mc [2] BENGALI VOWEL SIGN I..BENGALI VOWEL SIGN II
+ {0x09C1, 0x09C4, prExtend}, // Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR
+ {0x09C7, 0x09C8, prSpacingMark}, // Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI
+ {0x09CB, 0x09CC, prSpacingMark}, // Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU
+ {0x09CD, 0x09CD, prExtend}, // Mn BENGALI SIGN VIRAMA
+ {0x09D7, 0x09D7, prExtend}, // Mc BENGALI AU LENGTH MARK
+ {0x09E2, 0x09E3, prExtend}, // Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+ {0x09FE, 0x09FE, prExtend}, // Mn BENGALI SANDHI MARK
+ {0x0A01, 0x0A02, prExtend}, // Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
+ {0x0A03, 0x0A03, prSpacingMark}, // Mc GURMUKHI SIGN VISARGA
+ {0x0A3C, 0x0A3C, prExtend}, // Mn GURMUKHI SIGN NUKTA
+ {0x0A3E, 0x0A40, prSpacingMark}, // Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II
+ {0x0A41, 0x0A42, prExtend}, // Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
+ {0x0A47, 0x0A48, prExtend}, // Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI
+ {0x0A4B, 0x0A4D, prExtend}, // Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA
+ {0x0A51, 0x0A51, prExtend}, // Mn GURMUKHI SIGN UDAAT
+ {0x0A70, 0x0A71, prExtend}, // Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK
+ {0x0A75, 0x0A75, prExtend}, // Mn GURMUKHI SIGN YAKASH
+ {0x0A81, 0x0A82, prExtend}, // Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA
+ {0x0A83, 0x0A83, prSpacingMark}, // Mc GUJARATI SIGN VISARGA
+ {0x0ABC, 0x0ABC, prExtend}, // Mn GUJARATI SIGN NUKTA
+ {0x0ABE, 0x0AC0, prSpacingMark}, // Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II
+ {0x0AC1, 0x0AC5, prExtend}, // Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E
+ {0x0AC7, 0x0AC8, prExtend}, // Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI
+ {0x0AC9, 0x0AC9, prSpacingMark}, // Mc GUJARATI VOWEL SIGN CANDRA O
+ {0x0ACB, 0x0ACC, prSpacingMark}, // Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU
+ {0x0ACD, 0x0ACD, prExtend}, // Mn GUJARATI SIGN VIRAMA
+ {0x0AE2, 0x0AE3, prExtend}, // Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+ {0x0AFA, 0x0AFF, prExtend}, // Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE
+ {0x0B01, 0x0B01, prExtend}, // Mn ORIYA SIGN CANDRABINDU
+ {0x0B02, 0x0B03, prSpacingMark}, // Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA
+ {0x0B3C, 0x0B3C, prExtend}, // Mn ORIYA SIGN NUKTA
+ {0x0B3E, 0x0B3E, prExtend}, // Mc ORIYA VOWEL SIGN AA
+ {0x0B3F, 0x0B3F, prExtend}, // Mn ORIYA VOWEL SIGN I
+ {0x0B40, 0x0B40, prSpacingMark}, // Mc ORIYA VOWEL SIGN II
+ {0x0B41, 0x0B44, prExtend}, // Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR
+ {0x0B47, 0x0B48, prSpacingMark}, // Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI
+ {0x0B4B, 0x0B4C, prSpacingMark}, // Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU
+ {0x0B4D, 0x0B4D, prExtend}, // Mn ORIYA SIGN VIRAMA
+ {0x0B55, 0x0B56, prExtend}, // Mn [2] ORIYA SIGN OVERLINE..ORIYA AI LENGTH MARK
+ {0x0B57, 0x0B57, prExtend}, // Mc ORIYA AU LENGTH MARK
+ {0x0B62, 0x0B63, prExtend}, // Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL
+ {0x0B82, 0x0B82, prExtend}, // Mn TAMIL SIGN ANUSVARA
+ {0x0BBE, 0x0BBE, prExtend}, // Mc TAMIL VOWEL SIGN AA
+ {0x0BBF, 0x0BBF, prSpacingMark}, // Mc TAMIL VOWEL SIGN I
+ {0x0BC0, 0x0BC0, prExtend}, // Mn TAMIL VOWEL SIGN II
+ {0x0BC1, 0x0BC2, prSpacingMark}, // Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU
+ {0x0BC6, 0x0BC8, prSpacingMark}, // Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI
+ {0x0BCA, 0x0BCC, prSpacingMark}, // Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU
+ {0x0BCD, 0x0BCD, prExtend}, // Mn TAMIL SIGN VIRAMA
+ {0x0BD7, 0x0BD7, prExtend}, // Mc TAMIL AU LENGTH MARK
+ {0x0C00, 0x0C00, prExtend}, // Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE
+ {0x0C01, 0x0C03, prSpacingMark}, // Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA
+ {0x0C04, 0x0C04, prExtend}, // Mn TELUGU SIGN COMBINING ANUSVARA ABOVE
+ {0x0C3C, 0x0C3C, prExtend}, // Mn TELUGU SIGN NUKTA
+ {0x0C3E, 0x0C40, prExtend}, // Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
+ {0x0C41, 0x0C44, prSpacingMark}, // Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR
+ {0x0C46, 0x0C48, prExtend}, // Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
+ {0x0C4A, 0x0C4D, prExtend}, // Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA
+ {0x0C55, 0x0C56, prExtend}, // Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK
+ {0x0C62, 0x0C63, prExtend}, // Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL
+ {0x0C81, 0x0C81, prExtend}, // Mn KANNADA SIGN CANDRABINDU
+ {0x0C82, 0x0C83, prSpacingMark}, // Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA
+ {0x0CBC, 0x0CBC, prExtend}, // Mn KANNADA SIGN NUKTA
+ {0x0CBE, 0x0CBE, prSpacingMark}, // Mc KANNADA VOWEL SIGN AA
+ {0x0CBF, 0x0CBF, prExtend}, // Mn KANNADA VOWEL SIGN I
+ {0x0CC0, 0x0CC1, prSpacingMark}, // Mc [2] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN U
+ {0x0CC2, 0x0CC2, prExtend}, // Mc KANNADA VOWEL SIGN UU
+ {0x0CC3, 0x0CC4, prSpacingMark}, // Mc [2] KANNADA VOWEL SIGN VOCALIC R..KANNADA VOWEL SIGN VOCALIC RR
+ {0x0CC6, 0x0CC6, prExtend}, // Mn KANNADA VOWEL SIGN E
+ {0x0CC7, 0x0CC8, prSpacingMark}, // Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI
+ {0x0CCA, 0x0CCB, prSpacingMark}, // Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO
+ {0x0CCC, 0x0CCD, prExtend}, // Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA
+ {0x0CD5, 0x0CD6, prExtend}, // Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
+ {0x0CE2, 0x0CE3, prExtend}, // Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
+ {0x0CF3, 0x0CF3, prSpacingMark}, // Mc KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT
+ {0x0D00, 0x0D01, prExtend}, // Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU
+ {0x0D02, 0x0D03, prSpacingMark}, // Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
+ {0x0D3B, 0x0D3C, prExtend}, // Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA
+ {0x0D3E, 0x0D3E, prExtend}, // Mc MALAYALAM VOWEL SIGN AA
+ {0x0D3F, 0x0D40, prSpacingMark}, // Mc [2] MALAYALAM VOWEL SIGN I..MALAYALAM VOWEL SIGN II
+ {0x0D41, 0x0D44, prExtend}, // Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
+ {0x0D46, 0x0D48, prSpacingMark}, // Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI
+ {0x0D4A, 0x0D4C, prSpacingMark}, // Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU
+ {0x0D4D, 0x0D4D, prExtend}, // Mn MALAYALAM SIGN VIRAMA
+ {0x0D4E, 0x0D4E, prPrepend}, // Lo MALAYALAM LETTER DOT REPH
+ {0x0D57, 0x0D57, prExtend}, // Mc MALAYALAM AU LENGTH MARK
+ {0x0D62, 0x0D63, prExtend}, // Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL
+ {0x0D81, 0x0D81, prExtend}, // Mn SINHALA SIGN CANDRABINDU
+ {0x0D82, 0x0D83, prSpacingMark}, // Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA
+ {0x0DCA, 0x0DCA, prExtend}, // Mn SINHALA SIGN AL-LAKUNA
+ {0x0DCF, 0x0DCF, prExtend}, // Mc SINHALA VOWEL SIGN AELA-PILLA
+ {0x0DD0, 0x0DD1, prSpacingMark}, // Mc [2] SINHALA VOWEL SIGN KETTI AEDA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA
+ {0x0DD2, 0x0DD4, prExtend}, // Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA
+ {0x0DD6, 0x0DD6, prExtend}, // Mn SINHALA VOWEL SIGN DIGA PAA-PILLA
+ {0x0DD8, 0x0DDE, prSpacingMark}, // Mc [7] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA
+ {0x0DDF, 0x0DDF, prExtend}, // Mc SINHALA VOWEL SIGN GAYANUKITTA
+ {0x0DF2, 0x0DF3, prSpacingMark}, // Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA
+ {0x0E31, 0x0E31, prExtend}, // Mn THAI CHARACTER MAI HAN-AKAT
+ {0x0E33, 0x0E33, prSpacingMark}, // Lo THAI CHARACTER SARA AM
+ {0x0E34, 0x0E3A, prExtend}, // Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU
+ {0x0E47, 0x0E4E, prExtend}, // Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN
+ {0x0EB1, 0x0EB1, prExtend}, // Mn LAO VOWEL SIGN MAI KAN
+ {0x0EB3, 0x0EB3, prSpacingMark}, // Lo LAO VOWEL SIGN AM
+ {0x0EB4, 0x0EBC, prExtend}, // Mn [9] LAO VOWEL SIGN I..LAO SEMIVOWEL SIGN LO
+ {0x0EC8, 0x0ECE, prExtend}, // Mn [7] LAO TONE MAI EK..LAO YAMAKKAN
+ {0x0F18, 0x0F19, prExtend}, // Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS
+ {0x0F35, 0x0F35, prExtend}, // Mn TIBETAN MARK NGAS BZUNG NYI ZLA
+ {0x0F37, 0x0F37, prExtend}, // Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS
+ {0x0F39, 0x0F39, prExtend}, // Mn TIBETAN MARK TSA -PHRU
+ {0x0F3E, 0x0F3F, prSpacingMark}, // Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES
+ {0x0F71, 0x0F7E, prExtend}, // Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO
+ {0x0F7F, 0x0F7F, prSpacingMark}, // Mc TIBETAN SIGN RNAM BCAD
+ {0x0F80, 0x0F84, prExtend}, // Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA
+ {0x0F86, 0x0F87, prExtend}, // Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS
+ {0x0F8D, 0x0F97, prExtend}, // Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA
+ {0x0F99, 0x0FBC, prExtend}, // Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA
+ {0x0FC6, 0x0FC6, prExtend}, // Mn TIBETAN SYMBOL PADMA GDAN
+ {0x102D, 0x1030, prExtend}, // Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU
+ {0x1031, 0x1031, prSpacingMark}, // Mc MYANMAR VOWEL SIGN E
+ {0x1032, 0x1037, prExtend}, // Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW
+ {0x1039, 0x103A, prExtend}, // Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT
+ {0x103B, 0x103C, prSpacingMark}, // Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA
+ {0x103D, 0x103E, prExtend}, // Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA
+ {0x1056, 0x1057, prSpacingMark}, // Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR
+ {0x1058, 0x1059, prExtend}, // Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL
+ {0x105E, 0x1060, prExtend}, // Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA
+ {0x1071, 0x1074, prExtend}, // Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE
+ {0x1082, 0x1082, prExtend}, // Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA
+ {0x1084, 0x1084, prSpacingMark}, // Mc MYANMAR VOWEL SIGN SHAN E
+ {0x1085, 0x1086, prExtend}, // Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y
+ {0x108D, 0x108D, prExtend}, // Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE
+ {0x109D, 0x109D, prExtend}, // Mn MYANMAR VOWEL SIGN AITON AI
+ {0x1100, 0x115F, prL}, // Lo [96] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG FILLER
+ {0x1160, 0x11A7, prV}, // Lo [72] HANGUL JUNGSEONG FILLER..HANGUL JUNGSEONG O-YAE
+ {0x11A8, 0x11FF, prT}, // Lo [88] HANGUL JONGSEONG KIYEOK..HANGUL JONGSEONG SSANGNIEUN
+ {0x135D, 0x135F, prExtend}, // Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK
+ {0x1712, 0x1714, prExtend}, // Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA
+ {0x1715, 0x1715, prSpacingMark}, // Mc TAGALOG SIGN PAMUDPOD
+ {0x1732, 0x1733, prExtend}, // Mn [2] HANUNOO VOWEL SIGN I..HANUNOO VOWEL SIGN U
+ {0x1734, 0x1734, prSpacingMark}, // Mc HANUNOO SIGN PAMUDPOD
+ {0x1752, 0x1753, prExtend}, // Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U
+ {0x1772, 0x1773, prExtend}, // Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U
+ {0x17B4, 0x17B5, prExtend}, // Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+ {0x17B6, 0x17B6, prSpacingMark}, // Mc KHMER VOWEL SIGN AA
+ {0x17B7, 0x17BD, prExtend}, // Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA
+ {0x17BE, 0x17C5, prSpacingMark}, // Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU
+ {0x17C6, 0x17C6, prExtend}, // Mn KHMER SIGN NIKAHIT
+ {0x17C7, 0x17C8, prSpacingMark}, // Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU
+ {0x17C9, 0x17D3, prExtend}, // Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT
+ {0x17DD, 0x17DD, prExtend}, // Mn KHMER SIGN ATTHACAN
+ {0x180B, 0x180D, prExtend}, // Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+ {0x180E, 0x180E, prControl}, // Cf MONGOLIAN VOWEL SEPARATOR
+ {0x180F, 0x180F, prExtend}, // Mn MONGOLIAN FREE VARIATION SELECTOR FOUR
+ {0x1885, 0x1886, prExtend}, // Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
+ {0x18A9, 0x18A9, prExtend}, // Mn MONGOLIAN LETTER ALI GALI DAGALGA
+ {0x1920, 0x1922, prExtend}, // Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U
+ {0x1923, 0x1926, prSpacingMark}, // Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU
+ {0x1927, 0x1928, prExtend}, // Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O
+ {0x1929, 0x192B, prSpacingMark}, // Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA
+ {0x1930, 0x1931, prSpacingMark}, // Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA
+ {0x1932, 0x1932, prExtend}, // Mn LIMBU SMALL LETTER ANUSVARA
+ {0x1933, 0x1938, prSpacingMark}, // Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA
+ {0x1939, 0x193B, prExtend}, // Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I
+ {0x1A17, 0x1A18, prExtend}, // Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U
+ {0x1A19, 0x1A1A, prSpacingMark}, // Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O
+ {0x1A1B, 0x1A1B, prExtend}, // Mn BUGINESE VOWEL SIGN AE
+ {0x1A55, 0x1A55, prSpacingMark}, // Mc TAI THAM CONSONANT SIGN MEDIAL RA
+ {0x1A56, 0x1A56, prExtend}, // Mn TAI THAM CONSONANT SIGN MEDIAL LA
+ {0x1A57, 0x1A57, prSpacingMark}, // Mc TAI THAM CONSONANT SIGN LA TANG LAI
+ {0x1A58, 0x1A5E, prExtend}, // Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA
+ {0x1A60, 0x1A60, prExtend}, // Mn TAI THAM SIGN SAKOT
+ {0x1A62, 0x1A62, prExtend}, // Mn TAI THAM VOWEL SIGN MAI SAT
+ {0x1A65, 0x1A6C, prExtend}, // Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW
+ {0x1A6D, 0x1A72, prSpacingMark}, // Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI
+ {0x1A73, 0x1A7C, prExtend}, // Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN
+ {0x1A7F, 0x1A7F, prExtend}, // Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT
+ {0x1AB0, 0x1ABD, prExtend}, // Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW
+ {0x1ABE, 0x1ABE, prExtend}, // Me COMBINING PARENTHESES OVERLAY
+ {0x1ABF, 0x1ACE, prExtend}, // Mn [16] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER INSULAR T
+ {0x1B00, 0x1B03, prExtend}, // Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
+ {0x1B04, 0x1B04, prSpacingMark}, // Mc BALINESE SIGN BISAH
+ {0x1B34, 0x1B34, prExtend}, // Mn BALINESE SIGN REREKAN
+ {0x1B35, 0x1B35, prExtend}, // Mc BALINESE VOWEL SIGN TEDUNG
+ {0x1B36, 0x1B3A, prExtend}, // Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA
+ {0x1B3B, 0x1B3B, prSpacingMark}, // Mc BALINESE VOWEL SIGN RA REPA TEDUNG
+ {0x1B3C, 0x1B3C, prExtend}, // Mn BALINESE VOWEL SIGN LA LENGA
+ {0x1B3D, 0x1B41, prSpacingMark}, // Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG
+ {0x1B42, 0x1B42, prExtend}, // Mn BALINESE VOWEL SIGN PEPET
+ {0x1B43, 0x1B44, prSpacingMark}, // Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG
+ {0x1B6B, 0x1B73, prExtend}, // Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
+ {0x1B80, 0x1B81, prExtend}, // Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR
+ {0x1B82, 0x1B82, prSpacingMark}, // Mc SUNDANESE SIGN PANGWISAD
+ {0x1BA1, 0x1BA1, prSpacingMark}, // Mc SUNDANESE CONSONANT SIGN PAMINGKAL
+ {0x1BA2, 0x1BA5, prExtend}, // Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU
+ {0x1BA6, 0x1BA7, prSpacingMark}, // Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG
+ {0x1BA8, 0x1BA9, prExtend}, // Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
+ {0x1BAA, 0x1BAA, prSpacingMark}, // Mc SUNDANESE SIGN PAMAAEH
+ {0x1BAB, 0x1BAD, prExtend}, // Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA
+ {0x1BE6, 0x1BE6, prExtend}, // Mn BATAK SIGN TOMPI
+ {0x1BE7, 0x1BE7, prSpacingMark}, // Mc BATAK VOWEL SIGN E
+ {0x1BE8, 0x1BE9, prExtend}, // Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE
+ {0x1BEA, 0x1BEC, prSpacingMark}, // Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O
+ {0x1BED, 0x1BED, prExtend}, // Mn BATAK VOWEL SIGN KARO O
+ {0x1BEE, 0x1BEE, prSpacingMark}, // Mc BATAK VOWEL SIGN U
+ {0x1BEF, 0x1BF1, prExtend}, // Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H
+ {0x1BF2, 0x1BF3, prSpacingMark}, // Mc [2] BATAK PANGOLAT..BATAK PANONGONAN
+ {0x1C24, 0x1C2B, prSpacingMark}, // Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU
+ {0x1C2C, 0x1C33, prExtend}, // Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T
+ {0x1C34, 0x1C35, prSpacingMark}, // Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG
+ {0x1C36, 0x1C37, prExtend}, // Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA
+ {0x1CD0, 0x1CD2, prExtend}, // Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA
+ {0x1CD4, 0x1CE0, prExtend}, // Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA
+ {0x1CE1, 0x1CE1, prSpacingMark}, // Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA
+ {0x1CE2, 0x1CE8, prExtend}, // Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL
+ {0x1CED, 0x1CED, prExtend}, // Mn VEDIC SIGN TIRYAK
+ {0x1CF4, 0x1CF4, prExtend}, // Mn VEDIC TONE CANDRA ABOVE
+ {0x1CF7, 0x1CF7, prSpacingMark}, // Mc VEDIC SIGN ATIKRAMA
+ {0x1CF8, 0x1CF9, prExtend}, // Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
+ {0x1DC0, 0x1DFF, prExtend}, // Mn [64] COMBINING DOTTED GRAVE ACCENT..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
+ {0x200B, 0x200B, prControl}, // Cf ZERO WIDTH SPACE
+ {0x200C, 0x200C, prExtend}, // Cf ZERO WIDTH NON-JOINER
+ {0x200D, 0x200D, prZWJ}, // Cf ZERO WIDTH JOINER
+ {0x200E, 0x200F, prControl}, // Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK
+ {0x2028, 0x2028, prControl}, // Zl LINE SEPARATOR
+ {0x2029, 0x2029, prControl}, // Zp PARAGRAPH SEPARATOR
+ {0x202A, 0x202E, prControl}, // Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
+ {0x203C, 0x203C, prExtendedPictographic}, // E0.6 [1] (‼️) double exclamation mark
+ {0x2049, 0x2049, prExtendedPictographic}, // E0.6 [1] (⁉️) exclamation question mark
+ {0x2060, 0x2064, prControl}, // Cf [5] WORD JOINER..INVISIBLE PLUS
+ {0x2065, 0x2065, prControl}, // Cn
+ {0x2066, 0x206F, prControl}, // Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES
+ {0x20D0, 0x20DC, prExtend}, // Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE
+ {0x20DD, 0x20E0, prExtend}, // Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH
+ {0x20E1, 0x20E1, prExtend}, // Mn COMBINING LEFT RIGHT ARROW ABOVE
+ {0x20E2, 0x20E4, prExtend}, // Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE
+ {0x20E5, 0x20F0, prExtend}, // Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE
+ {0x2122, 0x2122, prExtendedPictographic}, // E0.6 [1] (™️) trade mark
+ {0x2139, 0x2139, prExtendedPictographic}, // E0.6 [1] (ℹ️) information
+ {0x2194, 0x2199, prExtendedPictographic}, // E0.6 [6] (↔️..↙️) left-right arrow..down-left arrow
+ {0x21A9, 0x21AA, prExtendedPictographic}, // E0.6 [2] (↩️..↪️) right arrow curving left..left arrow curving right
+ {0x231A, 0x231B, prExtendedPictographic}, // E0.6 [2] (⌚..⌛) watch..hourglass done
+ {0x2328, 0x2328, prExtendedPictographic}, // E1.0 [1] (⌨️) keyboard
+ {0x2388, 0x2388, prExtendedPictographic}, // E0.0 [1] (⎈) HELM SYMBOL
+ {0x23CF, 0x23CF, prExtendedPictographic}, // E1.0 [1] (⏏️) eject button
+ {0x23E9, 0x23EC, prExtendedPictographic}, // E0.6 [4] (⏩..⏬) fast-forward button..fast down button
+ {0x23ED, 0x23EE, prExtendedPictographic}, // E0.7 [2] (⏭️..⏮️) next track button..last track button
+ {0x23EF, 0x23EF, prExtendedPictographic}, // E1.0 [1] (⏯️) play or pause button
+ {0x23F0, 0x23F0, prExtendedPictographic}, // E0.6 [1] (⏰) alarm clock
+ {0x23F1, 0x23F2, prExtendedPictographic}, // E1.0 [2] (⏱️..⏲️) stopwatch..timer clock
+ {0x23F3, 0x23F3, prExtendedPictographic}, // E0.6 [1] (⏳) hourglass not done
+ {0x23F8, 0x23FA, prExtendedPictographic}, // E0.7 [3] (⏸️..⏺️) pause button..record button
+ {0x24C2, 0x24C2, prExtendedPictographic}, // E0.6 [1] (Ⓜ️) circled M
+ {0x25AA, 0x25AB, prExtendedPictographic}, // E0.6 [2] (▪️..▫️) black small square..white small square
+ {0x25B6, 0x25B6, prExtendedPictographic}, // E0.6 [1] (▶️) play button
+ {0x25C0, 0x25C0, prExtendedPictographic}, // E0.6 [1] (◀️) reverse button
+ {0x25FB, 0x25FE, prExtendedPictographic}, // E0.6 [4] (◻️..◾) white medium square..black medium-small square
+ {0x2600, 0x2601, prExtendedPictographic}, // E0.6 [2] (☀️..☁️) sun..cloud
+ {0x2602, 0x2603, prExtendedPictographic}, // E0.7 [2] (☂️..☃️) umbrella..snowman
+ {0x2604, 0x2604, prExtendedPictographic}, // E1.0 [1] (☄️) comet
+ {0x2605, 0x2605, prExtendedPictographic}, // E0.0 [1] (★) BLACK STAR
+ {0x2607, 0x260D, prExtendedPictographic}, // E0.0 [7] (☇..☍) LIGHTNING..OPPOSITION
+ {0x260E, 0x260E, prExtendedPictographic}, // E0.6 [1] (☎️) telephone
+ {0x260F, 0x2610, prExtendedPictographic}, // E0.0 [2] (☏..☐) WHITE TELEPHONE..BALLOT BOX
+ {0x2611, 0x2611, prExtendedPictographic}, // E0.6 [1] (☑️) check box with check
+ {0x2612, 0x2612, prExtendedPictographic}, // E0.0 [1] (☒) BALLOT BOX WITH X
+ {0x2614, 0x2615, prExtendedPictographic}, // E0.6 [2] (☔..☕) umbrella with rain drops..hot beverage
+ {0x2616, 0x2617, prExtendedPictographic}, // E0.0 [2] (☖..☗) WHITE SHOGI PIECE..BLACK SHOGI PIECE
+ {0x2618, 0x2618, prExtendedPictographic}, // E1.0 [1] (☘️) shamrock
+ {0x2619, 0x261C, prExtendedPictographic}, // E0.0 [4] (☙..☜) REVERSED ROTATED FLORAL HEART BULLET..WHITE LEFT POINTING INDEX
+ {0x261D, 0x261D, prExtendedPictographic}, // E0.6 [1] (☝️) index pointing up
+ {0x261E, 0x261F, prExtendedPictographic}, // E0.0 [2] (☞..☟) WHITE RIGHT POINTING INDEX..WHITE DOWN POINTING INDEX
+ {0x2620, 0x2620, prExtendedPictographic}, // E1.0 [1] (☠️) skull and crossbones
+ {0x2621, 0x2621, prExtendedPictographic}, // E0.0 [1] (☡) CAUTION SIGN
+ {0x2622, 0x2623, prExtendedPictographic}, // E1.0 [2] (☢️..☣️) radioactive..biohazard
+ {0x2624, 0x2625, prExtendedPictographic}, // E0.0 [2] (☤..☥) CADUCEUS..ANKH
+ {0x2626, 0x2626, prExtendedPictographic}, // E1.0 [1] (☦️) orthodox cross
+ {0x2627, 0x2629, prExtendedPictographic}, // E0.0 [3] (☧..☩) CHI RHO..CROSS OF JERUSALEM
+ {0x262A, 0x262A, prExtendedPictographic}, // E0.7 [1] (☪️) star and crescent
+ {0x262B, 0x262D, prExtendedPictographic}, // E0.0 [3] (☫..☭) FARSI SYMBOL..HAMMER AND SICKLE
+ {0x262E, 0x262E, prExtendedPictographic}, // E1.0 [1] (☮️) peace symbol
+ {0x262F, 0x262F, prExtendedPictographic}, // E0.7 [1] (☯️) yin yang
+ {0x2630, 0x2637, prExtendedPictographic}, // E0.0 [8] (☰..☷) TRIGRAM FOR HEAVEN..TRIGRAM FOR EARTH
+ {0x2638, 0x2639, prExtendedPictographic}, // E0.7 [2] (☸️..☹️) wheel of dharma..frowning face
+ {0x263A, 0x263A, prExtendedPictographic}, // E0.6 [1] (☺️) smiling face
+ {0x263B, 0x263F, prExtendedPictographic}, // E0.0 [5] (☻..☿) BLACK SMILING FACE..MERCURY
+ {0x2640, 0x2640, prExtendedPictographic}, // E4.0 [1] (♀️) female sign
+ {0x2641, 0x2641, prExtendedPictographic}, // E0.0 [1] (♁) EARTH
+ {0x2642, 0x2642, prExtendedPictographic}, // E4.0 [1] (♂️) male sign
+ {0x2643, 0x2647, prExtendedPictographic}, // E0.0 [5] (♃..♇) JUPITER..PLUTO
+ {0x2648, 0x2653, prExtendedPictographic}, // E0.6 [12] (♈..♓) Aries..Pisces
+ {0x2654, 0x265E, prExtendedPictographic}, // E0.0 [11] (♔..♞) WHITE CHESS KING..BLACK CHESS KNIGHT
+ {0x265F, 0x265F, prExtendedPictographic}, // E11.0 [1] (♟️) chess pawn
+ {0x2660, 0x2660, prExtendedPictographic}, // E0.6 [1] (♠️) spade suit
+ {0x2661, 0x2662, prExtendedPictographic}, // E0.0 [2] (♡..♢) WHITE HEART SUIT..WHITE DIAMOND SUIT
+ {0x2663, 0x2663, prExtendedPictographic}, // E0.6 [1] (♣️) club suit
+ {0x2664, 0x2664, prExtendedPictographic}, // E0.0 [1] (♤) WHITE SPADE SUIT
+ {0x2665, 0x2666, prExtendedPictographic}, // E0.6 [2] (♥️..♦️) heart suit..diamond suit
+ {0x2667, 0x2667, prExtendedPictographic}, // E0.0 [1] (♧) WHITE CLUB SUIT
+ {0x2668, 0x2668, prExtendedPictographic}, // E0.6 [1] (♨️) hot springs
+ {0x2669, 0x267A, prExtendedPictographic}, // E0.0 [18] (♩..♺) QUARTER NOTE..RECYCLING SYMBOL FOR GENERIC MATERIALS
+ {0x267B, 0x267B, prExtendedPictographic}, // E0.6 [1] (♻️) recycling symbol
+ {0x267C, 0x267D, prExtendedPictographic}, // E0.0 [2] (♼..♽) RECYCLED PAPER SYMBOL..PARTIALLY-RECYCLED PAPER SYMBOL
+ {0x267E, 0x267E, prExtendedPictographic}, // E11.0 [1] (♾️) infinity
+ {0x267F, 0x267F, prExtendedPictographic}, // E0.6 [1] (♿) wheelchair symbol
+ {0x2680, 0x2685, prExtendedPictographic}, // E0.0 [6] (⚀..⚅) DIE FACE-1..DIE FACE-6
+ {0x2690, 0x2691, prExtendedPictographic}, // E0.0 [2] (⚐..⚑) WHITE FLAG..BLACK FLAG
+ {0x2692, 0x2692, prExtendedPictographic}, // E1.0 [1] (⚒️) hammer and pick
+ {0x2693, 0x2693, prExtendedPictographic}, // E0.6 [1] (⚓) anchor
+ {0x2694, 0x2694, prExtendedPictographic}, // E1.0 [1] (⚔️) crossed swords
+ {0x2695, 0x2695, prExtendedPictographic}, // E4.0 [1] (⚕️) medical symbol
+ {0x2696, 0x2697, prExtendedPictographic}, // E1.0 [2] (⚖️..⚗️) balance scale..alembic
+ {0x2698, 0x2698, prExtendedPictographic}, // E0.0 [1] (⚘) FLOWER
+ {0x2699, 0x2699, prExtendedPictographic}, // E1.0 [1] (⚙️) gear
+ {0x269A, 0x269A, prExtendedPictographic}, // E0.0 [1] (⚚) STAFF OF HERMES
+ {0x269B, 0x269C, prExtendedPictographic}, // E1.0 [2] (⚛️..⚜️) atom symbol..fleur-de-lis
+ {0x269D, 0x269F, prExtendedPictographic}, // E0.0 [3] (⚝..⚟) OUTLINED WHITE STAR..THREE LINES CONVERGING LEFT
+ {0x26A0, 0x26A1, prExtendedPictographic}, // E0.6 [2] (⚠️..⚡) warning..high voltage
+ {0x26A2, 0x26A6, prExtendedPictographic}, // E0.0 [5] (⚢..⚦) DOUBLED FEMALE SIGN..MALE WITH STROKE SIGN
+ {0x26A7, 0x26A7, prExtendedPictographic}, // E13.0 [1] (⚧️) transgender symbol
+ {0x26A8, 0x26A9, prExtendedPictographic}, // E0.0 [2] (⚨..⚩) VERTICAL MALE WITH STROKE SIGN..HORIZONTAL MALE WITH STROKE SIGN
+ {0x26AA, 0x26AB, prExtendedPictographic}, // E0.6 [2] (⚪..⚫) white circle..black circle
+ {0x26AC, 0x26AF, prExtendedPictographic}, // E0.0 [4] (⚬..⚯) MEDIUM SMALL WHITE CIRCLE..UNMARRIED PARTNERSHIP SYMBOL
+ {0x26B0, 0x26B1, prExtendedPictographic}, // E1.0 [2] (⚰️..⚱️) coffin..funeral urn
+ {0x26B2, 0x26BC, prExtendedPictographic}, // E0.0 [11] (⚲..⚼) NEUTER..SESQUIQUADRATE
+ {0x26BD, 0x26BE, prExtendedPictographic}, // E0.6 [2] (⚽..⚾) soccer ball..baseball
+ {0x26BF, 0x26C3, prExtendedPictographic}, // E0.0 [5] (⚿..⛃) SQUARED KEY..BLACK DRAUGHTS KING
+ {0x26C4, 0x26C5, prExtendedPictographic}, // E0.6 [2] (⛄..⛅) snowman without snow..sun behind cloud
+ {0x26C6, 0x26C7, prExtendedPictographic}, // E0.0 [2] (⛆..⛇) RAIN..BLACK SNOWMAN
+ {0x26C8, 0x26C8, prExtendedPictographic}, // E0.7 [1] (⛈️) cloud with lightning and rain
+ {0x26C9, 0x26CD, prExtendedPictographic}, // E0.0 [5] (⛉..⛍) TURNED WHITE SHOGI PIECE..DISABLED CAR
+ {0x26CE, 0x26CE, prExtendedPictographic}, // E0.6 [1] (⛎) Ophiuchus
+ {0x26CF, 0x26CF, prExtendedPictographic}, // E0.7 [1] (⛏️) pick
+ {0x26D0, 0x26D0, prExtendedPictographic}, // E0.0 [1] (⛐) CAR SLIDING
+ {0x26D1, 0x26D1, prExtendedPictographic}, // E0.7 [1] (⛑️) rescue worker’s helmet
+ {0x26D2, 0x26D2, prExtendedPictographic}, // E0.0 [1] (⛒) CIRCLED CROSSING LANES
+ {0x26D3, 0x26D3, prExtendedPictographic}, // E0.7 [1] (⛓️) chains
+ {0x26D4, 0x26D4, prExtendedPictographic}, // E0.6 [1] (⛔) no entry
+ {0x26D5, 0x26E8, prExtendedPictographic}, // E0.0 [20] (⛕..⛨) ALTERNATE ONE-WAY LEFT WAY TRAFFIC..BLACK CROSS ON SHIELD
+ {0x26E9, 0x26E9, prExtendedPictographic}, // E0.7 [1] (⛩️) shinto shrine
+ {0x26EA, 0x26EA, prExtendedPictographic}, // E0.6 [1] (⛪) church
+ {0x26EB, 0x26EF, prExtendedPictographic}, // E0.0 [5] (⛫..⛯) CASTLE..MAP SYMBOL FOR LIGHTHOUSE
+ {0x26F0, 0x26F1, prExtendedPictographic}, // E0.7 [2] (⛰️..⛱️) mountain..umbrella on ground
+ {0x26F2, 0x26F3, prExtendedPictographic}, // E0.6 [2] (⛲..⛳) fountain..flag in hole
+ {0x26F4, 0x26F4, prExtendedPictographic}, // E0.7 [1] (⛴️) ferry
+ {0x26F5, 0x26F5, prExtendedPictographic}, // E0.6 [1] (⛵) sailboat
+ {0x26F6, 0x26F6, prExtendedPictographic}, // E0.0 [1] (⛶) SQUARE FOUR CORNERS
+ {0x26F7, 0x26F9, prExtendedPictographic}, // E0.7 [3] (⛷️..⛹️) skier..person bouncing ball
+ {0x26FA, 0x26FA, prExtendedPictographic}, // E0.6 [1] (⛺) tent
+ {0x26FB, 0x26FC, prExtendedPictographic}, // E0.0 [2] (⛻..⛼) JAPANESE BANK SYMBOL..HEADSTONE GRAVEYARD SYMBOL
+ {0x26FD, 0x26FD, prExtendedPictographic}, // E0.6 [1] (⛽) fuel pump
+ {0x26FE, 0x2701, prExtendedPictographic}, // E0.0 [4] (⛾..✁) CUP ON BLACK SQUARE..UPPER BLADE SCISSORS
+ {0x2702, 0x2702, prExtendedPictographic}, // E0.6 [1] (✂️) scissors
+ {0x2703, 0x2704, prExtendedPictographic}, // E0.0 [2] (✃..✄) LOWER BLADE SCISSORS..WHITE SCISSORS
+ {0x2705, 0x2705, prExtendedPictographic}, // E0.6 [1] (✅) check mark button
+ {0x2708, 0x270C, prExtendedPictographic}, // E0.6 [5] (✈️..✌️) airplane..victory hand
+ {0x270D, 0x270D, prExtendedPictographic}, // E0.7 [1] (✍️) writing hand
+ {0x270E, 0x270E, prExtendedPictographic}, // E0.0 [1] (✎) LOWER RIGHT PENCIL
+ {0x270F, 0x270F, prExtendedPictographic}, // E0.6 [1] (✏️) pencil
+ {0x2710, 0x2711, prExtendedPictographic}, // E0.0 [2] (✐..✑) UPPER RIGHT PENCIL..WHITE NIB
+ {0x2712, 0x2712, prExtendedPictographic}, // E0.6 [1] (✒️) black nib
+ {0x2714, 0x2714, prExtendedPictographic}, // E0.6 [1] (✔️) check mark
+ {0x2716, 0x2716, prExtendedPictographic}, // E0.6 [1] (✖️) multiply
+ {0x271D, 0x271D, prExtendedPictographic}, // E0.7 [1] (✝️) latin cross
+ {0x2721, 0x2721, prExtendedPictographic}, // E0.7 [1] (✡️) star of David
+ {0x2728, 0x2728, prExtendedPictographic}, // E0.6 [1] (✨) sparkles
+ {0x2733, 0x2734, prExtendedPictographic}, // E0.6 [2] (✳️..✴️) eight-spoked asterisk..eight-pointed star
+ {0x2744, 0x2744, prExtendedPictographic}, // E0.6 [1] (❄️) snowflake
+ {0x2747, 0x2747, prExtendedPictographic}, // E0.6 [1] (❇️) sparkle
+ {0x274C, 0x274C, prExtendedPictographic}, // E0.6 [1] (❌) cross mark
+ {0x274E, 0x274E, prExtendedPictographic}, // E0.6 [1] (❎) cross mark button
+ {0x2753, 0x2755, prExtendedPictographic}, // E0.6 [3] (❓..❕) red question mark..white exclamation mark
+ {0x2757, 0x2757, prExtendedPictographic}, // E0.6 [1] (❗) red exclamation mark
+ {0x2763, 0x2763, prExtendedPictographic}, // E1.0 [1] (❣️) heart exclamation
+ {0x2764, 0x2764, prExtendedPictographic}, // E0.6 [1] (❤️) red heart
+ {0x2765, 0x2767, prExtendedPictographic}, // E0.0 [3] (❥..❧) ROTATED HEAVY BLACK HEART BULLET..ROTATED FLORAL HEART BULLET
+ {0x2795, 0x2797, prExtendedPictographic}, // E0.6 [3] (➕..➗) plus..divide
+ {0x27A1, 0x27A1, prExtendedPictographic}, // E0.6 [1] (➡️) right arrow
+ {0x27B0, 0x27B0, prExtendedPictographic}, // E0.6 [1] (➰) curly loop
+ {0x27BF, 0x27BF, prExtendedPictographic}, // E1.0 [1] (➿) double curly loop
+ {0x2934, 0x2935, prExtendedPictographic}, // E0.6 [2] (⤴️..⤵️) right arrow curving up..right arrow curving down
+ {0x2B05, 0x2B07, prExtendedPictographic}, // E0.6 [3] (⬅️..⬇️) left arrow..down arrow
+ {0x2B1B, 0x2B1C, prExtendedPictographic}, // E0.6 [2] (⬛..⬜) black large square..white large square
+ {0x2B50, 0x2B50, prExtendedPictographic}, // E0.6 [1] (⭐) star
+ {0x2B55, 0x2B55, prExtendedPictographic}, // E0.6 [1] (⭕) hollow red circle
+ {0x2CEF, 0x2CF1, prExtend}, // Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS
+ {0x2D7F, 0x2D7F, prExtend}, // Mn TIFINAGH CONSONANT JOINER
+ {0x2DE0, 0x2DFF, prExtend}, // Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
+ {0x302A, 0x302D, prExtend}, // Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK
+ {0x302E, 0x302F, prExtend}, // Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK
+ {0x3030, 0x3030, prExtendedPictographic}, // E0.6 [1] (〰️) wavy dash
+ {0x303D, 0x303D, prExtendedPictographic}, // E0.6 [1] (〽️) part alternation mark
+ {0x3099, 0x309A, prExtend}, // Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+ {0x3297, 0x3297, prExtendedPictographic}, // E0.6 [1] (㊗️) Japanese “congratulations” button
+ {0x3299, 0x3299, prExtendedPictographic}, // E0.6 [1] (㊙️) Japanese “secret” button
+ {0xA66F, 0xA66F, prExtend}, // Mn COMBINING CYRILLIC VZMET
+ {0xA670, 0xA672, prExtend}, // Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN
+ {0xA674, 0xA67D, prExtend}, // Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK
+ {0xA69E, 0xA69F, prExtend}, // Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E
+ {0xA6F0, 0xA6F1, prExtend}, // Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS
+ {0xA802, 0xA802, prExtend}, // Mn SYLOTI NAGRI SIGN DVISVARA
+ {0xA806, 0xA806, prExtend}, // Mn SYLOTI NAGRI SIGN HASANTA
+ {0xA80B, 0xA80B, prExtend}, // Mn SYLOTI NAGRI SIGN ANUSVARA
+ {0xA823, 0xA824, prSpacingMark}, // Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I
+ {0xA825, 0xA826, prExtend}, // Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
+ {0xA827, 0xA827, prSpacingMark}, // Mc SYLOTI NAGRI VOWEL SIGN OO
+ {0xA82C, 0xA82C, prExtend}, // Mn SYLOTI NAGRI SIGN ALTERNATE HASANTA
+ {0xA880, 0xA881, prSpacingMark}, // Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA
+ {0xA8B4, 0xA8C3, prSpacingMark}, // Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU
+ {0xA8C4, 0xA8C5, prExtend}, // Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU
+ {0xA8E0, 0xA8F1, prExtend}, // Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA
+ {0xA8FF, 0xA8FF, prExtend}, // Mn DEVANAGARI VOWEL SIGN AY
+ {0xA926, 0xA92D, prExtend}, // Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU
+ {0xA947, 0xA951, prExtend}, // Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
+ {0xA952, 0xA953, prSpacingMark}, // Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA
+ {0xA960, 0xA97C, prL}, // Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH
+ {0xA980, 0xA982, prExtend}, // Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR
+ {0xA983, 0xA983, prSpacingMark}, // Mc JAVANESE SIGN WIGNYAN
+ {0xA9B3, 0xA9B3, prExtend}, // Mn JAVANESE SIGN CECAK TELU
+ {0xA9B4, 0xA9B5, prSpacingMark}, // Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG
+ {0xA9B6, 0xA9B9, prExtend}, // Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT
+ {0xA9BA, 0xA9BB, prSpacingMark}, // Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE
+ {0xA9BC, 0xA9BD, prExtend}, // Mn [2] JAVANESE VOWEL SIGN PEPET..JAVANESE CONSONANT SIGN KERET
+ {0xA9BE, 0xA9C0, prSpacingMark}, // Mc [3] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE PANGKON
+ {0xA9E5, 0xA9E5, prExtend}, // Mn MYANMAR SIGN SHAN SAW
+ {0xAA29, 0xAA2E, prExtend}, // Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE
+ {0xAA2F, 0xAA30, prSpacingMark}, // Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI
+ {0xAA31, 0xAA32, prExtend}, // Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE
+ {0xAA33, 0xAA34, prSpacingMark}, // Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA
+ {0xAA35, 0xAA36, prExtend}, // Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA
+ {0xAA43, 0xAA43, prExtend}, // Mn CHAM CONSONANT SIGN FINAL NG
+ {0xAA4C, 0xAA4C, prExtend}, // Mn CHAM CONSONANT SIGN FINAL M
+ {0xAA4D, 0xAA4D, prSpacingMark}, // Mc CHAM CONSONANT SIGN FINAL H
+ {0xAA7C, 0xAA7C, prExtend}, // Mn MYANMAR SIGN TAI LAING TONE-2
+ {0xAAB0, 0xAAB0, prExtend}, // Mn TAI VIET MAI KANG
+ {0xAAB2, 0xAAB4, prExtend}, // Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U
+ {0xAAB7, 0xAAB8, prExtend}, // Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA
+ {0xAABE, 0xAABF, prExtend}, // Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK
+ {0xAAC1, 0xAAC1, prExtend}, // Mn TAI VIET TONE MAI THO
+ {0xAAEB, 0xAAEB, prSpacingMark}, // Mc MEETEI MAYEK VOWEL SIGN II
+ {0xAAEC, 0xAAED, prExtend}, // Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI
+ {0xAAEE, 0xAAEF, prSpacingMark}, // Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU
+ {0xAAF5, 0xAAF5, prSpacingMark}, // Mc MEETEI MAYEK VOWEL SIGN VISARGA
+ {0xAAF6, 0xAAF6, prExtend}, // Mn MEETEI MAYEK VIRAMA
+ {0xABE3, 0xABE4, prSpacingMark}, // Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP
+ {0xABE5, 0xABE5, prExtend}, // Mn MEETEI MAYEK VOWEL SIGN ANAP
+ {0xABE6, 0xABE7, prSpacingMark}, // Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP
+ {0xABE8, 0xABE8, prExtend}, // Mn MEETEI MAYEK VOWEL SIGN UNAP
+ {0xABE9, 0xABEA, prSpacingMark}, // Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG
+ {0xABEC, 0xABEC, prSpacingMark}, // Mc MEETEI MAYEK LUM IYEK
+ {0xABED, 0xABED, prExtend}, // Mn MEETEI MAYEK APUN IYEK
+ {0xAC00, 0xAC00, prLV}, // Lo HANGUL SYLLABLE GA
+ {0xAC01, 0xAC1B, prLVT}, // Lo [27] HANGUL SYLLABLE GAG..HANGUL SYLLABLE GAH
+ {0xAC1C, 0xAC1C, prLV}, // Lo HANGUL SYLLABLE GAE
+ {0xAC1D, 0xAC37, prLVT}, // Lo [27] HANGUL SYLLABLE GAEG..HANGUL SYLLABLE GAEH
+ {0xAC38, 0xAC38, prLV}, // Lo HANGUL SYLLABLE GYA
+ {0xAC39, 0xAC53, prLVT}, // Lo [27] HANGUL SYLLABLE GYAG..HANGUL SYLLABLE GYAH
+ {0xAC54, 0xAC54, prLV}, // Lo HANGUL SYLLABLE GYAE
+ {0xAC55, 0xAC6F, prLVT}, // Lo [27] HANGUL SYLLABLE GYAEG..HANGUL SYLLABLE GYAEH
+ {0xAC70, 0xAC70, prLV}, // Lo HANGUL SYLLABLE GEO
+ {0xAC71, 0xAC8B, prLVT}, // Lo [27] HANGUL SYLLABLE GEOG..HANGUL SYLLABLE GEOH
+ {0xAC8C, 0xAC8C, prLV}, // Lo HANGUL SYLLABLE GE
+ {0xAC8D, 0xACA7, prLVT}, // Lo [27] HANGUL SYLLABLE GEG..HANGUL SYLLABLE GEH
+ {0xACA8, 0xACA8, prLV}, // Lo HANGUL SYLLABLE GYEO
+ {0xACA9, 0xACC3, prLVT}, // Lo [27] HANGUL SYLLABLE GYEOG..HANGUL SYLLABLE GYEOH
+ {0xACC4, 0xACC4, prLV}, // Lo HANGUL SYLLABLE GYE
+ {0xACC5, 0xACDF, prLVT}, // Lo [27] HANGUL SYLLABLE GYEG..HANGUL SYLLABLE GYEH
+ {0xACE0, 0xACE0, prLV}, // Lo HANGUL SYLLABLE GO
+ {0xACE1, 0xACFB, prLVT}, // Lo [27] HANGUL SYLLABLE GOG..HANGUL SYLLABLE GOH
+ {0xACFC, 0xACFC, prLV}, // Lo HANGUL SYLLABLE GWA
+ {0xACFD, 0xAD17, prLVT}, // Lo [27] HANGUL SYLLABLE GWAG..HANGUL SYLLABLE GWAH
+ {0xAD18, 0xAD18, prLV}, // Lo HANGUL SYLLABLE GWAE
+ {0xAD19, 0xAD33, prLVT}, // Lo [27] HANGUL SYLLABLE GWAEG..HANGUL SYLLABLE GWAEH
+ {0xAD34, 0xAD34, prLV}, // Lo HANGUL SYLLABLE GOE
+ {0xAD35, 0xAD4F, prLVT}, // Lo [27] HANGUL SYLLABLE GOEG..HANGUL SYLLABLE GOEH
+ {0xAD50, 0xAD50, prLV}, // Lo HANGUL SYLLABLE GYO
+ {0xAD51, 0xAD6B, prLVT}, // Lo [27] HANGUL SYLLABLE GYOG..HANGUL SYLLABLE GYOH
+ {0xAD6C, 0xAD6C, prLV}, // Lo HANGUL SYLLABLE GU
+ {0xAD6D, 0xAD87, prLVT}, // Lo [27] HANGUL SYLLABLE GUG..HANGUL SYLLABLE GUH
+ {0xAD88, 0xAD88, prLV}, // Lo HANGUL SYLLABLE GWEO
+ {0xAD89, 0xADA3, prLVT}, // Lo [27] HANGUL SYLLABLE GWEOG..HANGUL SYLLABLE GWEOH
+ {0xADA4, 0xADA4, prLV}, // Lo HANGUL SYLLABLE GWE
+ {0xADA5, 0xADBF, prLVT}, // Lo [27] HANGUL SYLLABLE GWEG..HANGUL SYLLABLE GWEH
+ {0xADC0, 0xADC0, prLV}, // Lo HANGUL SYLLABLE GWI
+ {0xADC1, 0xADDB, prLVT}, // Lo [27] HANGUL SYLLABLE GWIG..HANGUL SYLLABLE GWIH
+ {0xADDC, 0xADDC, prLV}, // Lo HANGUL SYLLABLE GYU
+ {0xADDD, 0xADF7, prLVT}, // Lo [27] HANGUL SYLLABLE GYUG..HANGUL SYLLABLE GYUH
+ {0xADF8, 0xADF8, prLV}, // Lo HANGUL SYLLABLE GEU
+ {0xADF9, 0xAE13, prLVT}, // Lo [27] HANGUL SYLLABLE GEUG..HANGUL SYLLABLE GEUH
+ {0xAE14, 0xAE14, prLV}, // Lo HANGUL SYLLABLE GYI
+ {0xAE15, 0xAE2F, prLVT}, // Lo [27] HANGUL SYLLABLE GYIG..HANGUL SYLLABLE GYIH
+ {0xAE30, 0xAE30, prLV}, // Lo HANGUL SYLLABLE GI
+ {0xAE31, 0xAE4B, prLVT}, // Lo [27] HANGUL SYLLABLE GIG..HANGUL SYLLABLE GIH
+ {0xAE4C, 0xAE4C, prLV}, // Lo HANGUL SYLLABLE GGA
+ {0xAE4D, 0xAE67, prLVT}, // Lo [27] HANGUL SYLLABLE GGAG..HANGUL SYLLABLE GGAH
+ {0xAE68, 0xAE68, prLV}, // Lo HANGUL SYLLABLE GGAE
+ {0xAE69, 0xAE83, prLVT}, // Lo [27] HANGUL SYLLABLE GGAEG..HANGUL SYLLABLE GGAEH
+ {0xAE84, 0xAE84, prLV}, // Lo HANGUL SYLLABLE GGYA
+ {0xAE85, 0xAE9F, prLVT}, // Lo [27] HANGUL SYLLABLE GGYAG..HANGUL SYLLABLE GGYAH
+ {0xAEA0, 0xAEA0, prLV}, // Lo HANGUL SYLLABLE GGYAE
+ {0xAEA1, 0xAEBB, prLVT}, // Lo [27] HANGUL SYLLABLE GGYAEG..HANGUL SYLLABLE GGYAEH
+ {0xAEBC, 0xAEBC, prLV}, // Lo HANGUL SYLLABLE GGEO
+ {0xAEBD, 0xAED7, prLVT}, // Lo [27] HANGUL SYLLABLE GGEOG..HANGUL SYLLABLE GGEOH
+ {0xAED8, 0xAED8, prLV}, // Lo HANGUL SYLLABLE GGE
+ {0xAED9, 0xAEF3, prLVT}, // Lo [27] HANGUL SYLLABLE GGEG..HANGUL SYLLABLE GGEH
+ {0xAEF4, 0xAEF4, prLV}, // Lo HANGUL SYLLABLE GGYEO
+ {0xAEF5, 0xAF0F, prLVT}, // Lo [27] HANGUL SYLLABLE GGYEOG..HANGUL SYLLABLE GGYEOH
+ {0xAF10, 0xAF10, prLV}, // Lo HANGUL SYLLABLE GGYE
+ {0xAF11, 0xAF2B, prLVT}, // Lo [27] HANGUL SYLLABLE GGYEG..HANGUL SYLLABLE GGYEH
+ {0xAF2C, 0xAF2C, prLV}, // Lo HANGUL SYLLABLE GGO
+ {0xAF2D, 0xAF47, prLVT}, // Lo [27] HANGUL SYLLABLE GGOG..HANGUL SYLLABLE GGOH
+ {0xAF48, 0xAF48, prLV}, // Lo HANGUL SYLLABLE GGWA
+ {0xAF49, 0xAF63, prLVT}, // Lo [27] HANGUL SYLLABLE GGWAG..HANGUL SYLLABLE GGWAH
+ {0xAF64, 0xAF64, prLV}, // Lo HANGUL SYLLABLE GGWAE
+ {0xAF65, 0xAF7F, prLVT}, // Lo [27] HANGUL SYLLABLE GGWAEG..HANGUL SYLLABLE GGWAEH
+ {0xAF80, 0xAF80, prLV}, // Lo HANGUL SYLLABLE GGOE
+ {0xAF81, 0xAF9B, prLVT}, // Lo [27] HANGUL SYLLABLE GGOEG..HANGUL SYLLABLE GGOEH
+ {0xAF9C, 0xAF9C, prLV}, // Lo HANGUL SYLLABLE GGYO
+ {0xAF9D, 0xAFB7, prLVT}, // Lo [27] HANGUL SYLLABLE GGYOG..HANGUL SYLLABLE GGYOH
+ {0xAFB8, 0xAFB8, prLV}, // Lo HANGUL SYLLABLE GGU
+ {0xAFB9, 0xAFD3, prLVT}, // Lo [27] HANGUL SYLLABLE GGUG..HANGUL SYLLABLE GGUH
+ {0xAFD4, 0xAFD4, prLV}, // Lo HANGUL SYLLABLE GGWEO
+ {0xAFD5, 0xAFEF, prLVT}, // Lo [27] HANGUL SYLLABLE GGWEOG..HANGUL SYLLABLE GGWEOH
+ {0xAFF0, 0xAFF0, prLV}, // Lo HANGUL SYLLABLE GGWE
+ {0xAFF1, 0xB00B, prLVT}, // Lo [27] HANGUL SYLLABLE GGWEG..HANGUL SYLLABLE GGWEH
+ {0xB00C, 0xB00C, prLV}, // Lo HANGUL SYLLABLE GGWI
+ {0xB00D, 0xB027, prLVT}, // Lo [27] HANGUL SYLLABLE GGWIG..HANGUL SYLLABLE GGWIH
+ {0xB028, 0xB028, prLV}, // Lo HANGUL SYLLABLE GGYU
+ {0xB029, 0xB043, prLVT}, // Lo [27] HANGUL SYLLABLE GGYUG..HANGUL SYLLABLE GGYUH
+ {0xB044, 0xB044, prLV}, // Lo HANGUL SYLLABLE GGEU
+ {0xB045, 0xB05F, prLVT}, // Lo [27] HANGUL SYLLABLE GGEUG..HANGUL SYLLABLE GGEUH
+ {0xB060, 0xB060, prLV}, // Lo HANGUL SYLLABLE GGYI
+ {0xB061, 0xB07B, prLVT}, // Lo [27] HANGUL SYLLABLE GGYIG..HANGUL SYLLABLE GGYIH
+ {0xB07C, 0xB07C, prLV}, // Lo HANGUL SYLLABLE GGI
+ {0xB07D, 0xB097, prLVT}, // Lo [27] HANGUL SYLLABLE GGIG..HANGUL SYLLABLE GGIH
+ {0xB098, 0xB098, prLV}, // Lo HANGUL SYLLABLE NA
+ {0xB099, 0xB0B3, prLVT}, // Lo [27] HANGUL SYLLABLE NAG..HANGUL SYLLABLE NAH
+ {0xB0B4, 0xB0B4, prLV}, // Lo HANGUL SYLLABLE NAE
+ {0xB0B5, 0xB0CF, prLVT}, // Lo [27] HANGUL SYLLABLE NAEG..HANGUL SYLLABLE NAEH
+ {0xB0D0, 0xB0D0, prLV}, // Lo HANGUL SYLLABLE NYA
+ {0xB0D1, 0xB0EB, prLVT}, // Lo [27] HANGUL SYLLABLE NYAG..HANGUL SYLLABLE NYAH
+ {0xB0EC, 0xB0EC, prLV}, // Lo HANGUL SYLLABLE NYAE
+ {0xB0ED, 0xB107, prLVT}, // Lo [27] HANGUL SYLLABLE NYAEG..HANGUL SYLLABLE NYAEH
+ {0xB108, 0xB108, prLV}, // Lo HANGUL SYLLABLE NEO
+ {0xB109, 0xB123, prLVT}, // Lo [27] HANGUL SYLLABLE NEOG..HANGUL SYLLABLE NEOH
+ {0xB124, 0xB124, prLV}, // Lo HANGUL SYLLABLE NE
+ {0xB125, 0xB13F, prLVT}, // Lo [27] HANGUL SYLLABLE NEG..HANGUL SYLLABLE NEH
+ {0xB140, 0xB140, prLV}, // Lo HANGUL SYLLABLE NYEO
+ {0xB141, 0xB15B, prLVT}, // Lo [27] HANGUL SYLLABLE NYEOG..HANGUL SYLLABLE NYEOH
+ {0xB15C, 0xB15C, prLV}, // Lo HANGUL SYLLABLE NYE
+ {0xB15D, 0xB177, prLVT}, // Lo [27] HANGUL SYLLABLE NYEG..HANGUL SYLLABLE NYEH
+ {0xB178, 0xB178, prLV}, // Lo HANGUL SYLLABLE NO
+ {0xB179, 0xB193, prLVT}, // Lo [27] HANGUL SYLLABLE NOG..HANGUL SYLLABLE NOH
+ {0xB194, 0xB194, prLV}, // Lo HANGUL SYLLABLE NWA
+ {0xB195, 0xB1AF, prLVT}, // Lo [27] HANGUL SYLLABLE NWAG..HANGUL SYLLABLE NWAH
+ {0xB1B0, 0xB1B0, prLV}, // Lo HANGUL SYLLABLE NWAE
+ {0xB1B1, 0xB1CB, prLVT}, // Lo [27] HANGUL SYLLABLE NWAEG..HANGUL SYLLABLE NWAEH
+ {0xB1CC, 0xB1CC, prLV}, // Lo HANGUL SYLLABLE NOE
+ {0xB1CD, 0xB1E7, prLVT}, // Lo [27] HANGUL SYLLABLE NOEG..HANGUL SYLLABLE NOEH
+ {0xB1E8, 0xB1E8, prLV}, // Lo HANGUL SYLLABLE NYO
+ {0xB1E9, 0xB203, prLVT}, // Lo [27] HANGUL SYLLABLE NYOG..HANGUL SYLLABLE NYOH
+ {0xB204, 0xB204, prLV}, // Lo HANGUL SYLLABLE NU
+ {0xB205, 0xB21F, prLVT}, // Lo [27] HANGUL SYLLABLE NUG..HANGUL SYLLABLE NUH
+ {0xB220, 0xB220, prLV}, // Lo HANGUL SYLLABLE NWEO
+ {0xB221, 0xB23B, prLVT}, // Lo [27] HANGUL SYLLABLE NWEOG..HANGUL SYLLABLE NWEOH
+ {0xB23C, 0xB23C, prLV}, // Lo HANGUL SYLLABLE NWE
+ {0xB23D, 0xB257, prLVT}, // Lo [27] HANGUL SYLLABLE NWEG..HANGUL SYLLABLE NWEH
+ {0xB258, 0xB258, prLV}, // Lo HANGUL SYLLABLE NWI
+ {0xB259, 0xB273, prLVT}, // Lo [27] HANGUL SYLLABLE NWIG..HANGUL SYLLABLE NWIH
+ {0xB274, 0xB274, prLV}, // Lo HANGUL SYLLABLE NYU
+ {0xB275, 0xB28F, prLVT}, // Lo [27] HANGUL SYLLABLE NYUG..HANGUL SYLLABLE NYUH
+ {0xB290, 0xB290, prLV}, // Lo HANGUL SYLLABLE NEU
+ {0xB291, 0xB2AB, prLVT}, // Lo [27] HANGUL SYLLABLE NEUG..HANGUL SYLLABLE NEUH
+ {0xB2AC, 0xB2AC, prLV}, // Lo HANGUL SYLLABLE NYI
+ {0xB2AD, 0xB2C7, prLVT}, // Lo [27] HANGUL SYLLABLE NYIG..HANGUL SYLLABLE NYIH
+ {0xB2C8, 0xB2C8, prLV}, // Lo HANGUL SYLLABLE NI
+ {0xB2C9, 0xB2E3, prLVT}, // Lo [27] HANGUL SYLLABLE NIG..HANGUL SYLLABLE NIH
+ {0xB2E4, 0xB2E4, prLV}, // Lo HANGUL SYLLABLE DA
+ {0xB2E5, 0xB2FF, prLVT}, // Lo [27] HANGUL SYLLABLE DAG..HANGUL SYLLABLE DAH
+ {0xB300, 0xB300, prLV}, // Lo HANGUL SYLLABLE DAE
+ {0xB301, 0xB31B, prLVT}, // Lo [27] HANGUL SYLLABLE DAEG..HANGUL SYLLABLE DAEH
+ {0xB31C, 0xB31C, prLV}, // Lo HANGUL SYLLABLE DYA
+ {0xB31D, 0xB337, prLVT}, // Lo [27] HANGUL SYLLABLE DYAG..HANGUL SYLLABLE DYAH
+ {0xB338, 0xB338, prLV}, // Lo HANGUL SYLLABLE DYAE
+ {0xB339, 0xB353, prLVT}, // Lo [27] HANGUL SYLLABLE DYAEG..HANGUL SYLLABLE DYAEH
+ {0xB354, 0xB354, prLV}, // Lo HANGUL SYLLABLE DEO
+ {0xB355, 0xB36F, prLVT}, // Lo [27] HANGUL SYLLABLE DEOG..HANGUL SYLLABLE DEOH
+ {0xB370, 0xB370, prLV}, // Lo HANGUL SYLLABLE DE
+ {0xB371, 0xB38B, prLVT}, // Lo [27] HANGUL SYLLABLE DEG..HANGUL SYLLABLE DEH
+ {0xB38C, 0xB38C, prLV}, // Lo HANGUL SYLLABLE DYEO
+ {0xB38D, 0xB3A7, prLVT}, // Lo [27] HANGUL SYLLABLE DYEOG..HANGUL SYLLABLE DYEOH
+ {0xB3A8, 0xB3A8, prLV}, // Lo HANGUL SYLLABLE DYE
+ {0xB3A9, 0xB3C3, prLVT}, // Lo [27] HANGUL SYLLABLE DYEG..HANGUL SYLLABLE DYEH
+ {0xB3C4, 0xB3C4, prLV}, // Lo HANGUL SYLLABLE DO
+ {0xB3C5, 0xB3DF, prLVT}, // Lo [27] HANGUL SYLLABLE DOG..HANGUL SYLLABLE DOH
+ {0xB3E0, 0xB3E0, prLV}, // Lo HANGUL SYLLABLE DWA
+ {0xB3E1, 0xB3FB, prLVT}, // Lo [27] HANGUL SYLLABLE DWAG..HANGUL SYLLABLE DWAH
+ {0xB3FC, 0xB3FC, prLV}, // Lo HANGUL SYLLABLE DWAE
+ {0xB3FD, 0xB417, prLVT}, // Lo [27] HANGUL SYLLABLE DWAEG..HANGUL SYLLABLE DWAEH
+ {0xB418, 0xB418, prLV}, // Lo HANGUL SYLLABLE DOE
+ {0xB419, 0xB433, prLVT}, // Lo [27] HANGUL SYLLABLE DOEG..HANGUL SYLLABLE DOEH
+ {0xB434, 0xB434, prLV}, // Lo HANGUL SYLLABLE DYO
+ {0xB435, 0xB44F, prLVT}, // Lo [27] HANGUL SYLLABLE DYOG..HANGUL SYLLABLE DYOH
+ {0xB450, 0xB450, prLV}, // Lo HANGUL SYLLABLE DU
+ {0xB451, 0xB46B, prLVT}, // Lo [27] HANGUL SYLLABLE DUG..HANGUL SYLLABLE DUH
+ {0xB46C, 0xB46C, prLV}, // Lo HANGUL SYLLABLE DWEO
+ {0xB46D, 0xB487, prLVT}, // Lo [27] HANGUL SYLLABLE DWEOG..HANGUL SYLLABLE DWEOH
+ {0xB488, 0xB488, prLV}, // Lo HANGUL SYLLABLE DWE
+ {0xB489, 0xB4A3, prLVT}, // Lo [27] HANGUL SYLLABLE DWEG..HANGUL SYLLABLE DWEH
+ {0xB4A4, 0xB4A4, prLV}, // Lo HANGUL SYLLABLE DWI
+ {0xB4A5, 0xB4BF, prLVT}, // Lo [27] HANGUL SYLLABLE DWIG..HANGUL SYLLABLE DWIH
+ {0xB4C0, 0xB4C0, prLV}, // Lo HANGUL SYLLABLE DYU
+ {0xB4C1, 0xB4DB, prLVT}, // Lo [27] HANGUL SYLLABLE DYUG..HANGUL SYLLABLE DYUH
+ {0xB4DC, 0xB4DC, prLV}, // Lo HANGUL SYLLABLE DEU
+ {0xB4DD, 0xB4F7, prLVT}, // Lo [27] HANGUL SYLLABLE DEUG..HANGUL SYLLABLE DEUH
+ {0xB4F8, 0xB4F8, prLV}, // Lo HANGUL SYLLABLE DYI
+ {0xB4F9, 0xB513, prLVT}, // Lo [27] HANGUL SYLLABLE DYIG..HANGUL SYLLABLE DYIH
+ {0xB514, 0xB514, prLV}, // Lo HANGUL SYLLABLE DI
+ {0xB515, 0xB52F, prLVT}, // Lo [27] HANGUL SYLLABLE DIG..HANGUL SYLLABLE DIH
+ {0xB530, 0xB530, prLV}, // Lo HANGUL SYLLABLE DDA
+ {0xB531, 0xB54B, prLVT}, // Lo [27] HANGUL SYLLABLE DDAG..HANGUL SYLLABLE DDAH
+ {0xB54C, 0xB54C, prLV}, // Lo HANGUL SYLLABLE DDAE
+ {0xB54D, 0xB567, prLVT}, // Lo [27] HANGUL SYLLABLE DDAEG..HANGUL SYLLABLE DDAEH
+ {0xB568, 0xB568, prLV}, // Lo HANGUL SYLLABLE DDYA
+ {0xB569, 0xB583, prLVT}, // Lo [27] HANGUL SYLLABLE DDYAG..HANGUL SYLLABLE DDYAH
+ {0xB584, 0xB584, prLV}, // Lo HANGUL SYLLABLE DDYAE
+ {0xB585, 0xB59F, prLVT}, // Lo [27] HANGUL SYLLABLE DDYAEG..HANGUL SYLLABLE DDYAEH
+ {0xB5A0, 0xB5A0, prLV}, // Lo HANGUL SYLLABLE DDEO
+ {0xB5A1, 0xB5BB, prLVT}, // Lo [27] HANGUL SYLLABLE DDEOG..HANGUL SYLLABLE DDEOH
+ {0xB5BC, 0xB5BC, prLV}, // Lo HANGUL SYLLABLE DDE
+ {0xB5BD, 0xB5D7, prLVT}, // Lo [27] HANGUL SYLLABLE DDEG..HANGUL SYLLABLE DDEH
+ {0xB5D8, 0xB5D8, prLV}, // Lo HANGUL SYLLABLE DDYEO
+ {0xB5D9, 0xB5F3, prLVT}, // Lo [27] HANGUL SYLLABLE DDYEOG..HANGUL SYLLABLE DDYEOH
+ {0xB5F4, 0xB5F4, prLV}, // Lo HANGUL SYLLABLE DDYE
+ {0xB5F5, 0xB60F, prLVT}, // Lo [27] HANGUL SYLLABLE DDYEG..HANGUL SYLLABLE DDYEH
+ {0xB610, 0xB610, prLV}, // Lo HANGUL SYLLABLE DDO
+ {0xB611, 0xB62B, prLVT}, // Lo [27] HANGUL SYLLABLE DDOG..HANGUL SYLLABLE DDOH
+ {0xB62C, 0xB62C, prLV}, // Lo HANGUL SYLLABLE DDWA
+ {0xB62D, 0xB647, prLVT}, // Lo [27] HANGUL SYLLABLE DDWAG..HANGUL SYLLABLE DDWAH
+ {0xB648, 0xB648, prLV}, // Lo HANGUL SYLLABLE DDWAE
+ {0xB649, 0xB663, prLVT}, // Lo [27] HANGUL SYLLABLE DDWAEG..HANGUL SYLLABLE DDWAEH
+ {0xB664, 0xB664, prLV}, // Lo HANGUL SYLLABLE DDOE
+ {0xB665, 0xB67F, prLVT}, // Lo [27] HANGUL SYLLABLE DDOEG..HANGUL SYLLABLE DDOEH
+ {0xB680, 0xB680, prLV}, // Lo HANGUL SYLLABLE DDYO
+ {0xB681, 0xB69B, prLVT}, // Lo [27] HANGUL SYLLABLE DDYOG..HANGUL SYLLABLE DDYOH
+ {0xB69C, 0xB69C, prLV}, // Lo HANGUL SYLLABLE DDU
+ {0xB69D, 0xB6B7, prLVT}, // Lo [27] HANGUL SYLLABLE DDUG..HANGUL SYLLABLE DDUH
+ {0xB6B8, 0xB6B8, prLV}, // Lo HANGUL SYLLABLE DDWEO
+ {0xB6B9, 0xB6D3, prLVT}, // Lo [27] HANGUL SYLLABLE DDWEOG..HANGUL SYLLABLE DDWEOH
+ {0xB6D4, 0xB6D4, prLV}, // Lo HANGUL SYLLABLE DDWE
+ {0xB6D5, 0xB6EF, prLVT}, // Lo [27] HANGUL SYLLABLE DDWEG..HANGUL SYLLABLE DDWEH
+ {0xB6F0, 0xB6F0, prLV}, // Lo HANGUL SYLLABLE DDWI
+ {0xB6F1, 0xB70B, prLVT}, // Lo [27] HANGUL SYLLABLE DDWIG..HANGUL SYLLABLE DDWIH
+ {0xB70C, 0xB70C, prLV}, // Lo HANGUL SYLLABLE DDYU
+ {0xB70D, 0xB727, prLVT}, // Lo [27] HANGUL SYLLABLE DDYUG..HANGUL SYLLABLE DDYUH
+ {0xB728, 0xB728, prLV}, // Lo HANGUL SYLLABLE DDEU
+ {0xB729, 0xB743, prLVT}, // Lo [27] HANGUL SYLLABLE DDEUG..HANGUL SYLLABLE DDEUH
+ {0xB744, 0xB744, prLV}, // Lo HANGUL SYLLABLE DDYI
+ {0xB745, 0xB75F, prLVT}, // Lo [27] HANGUL SYLLABLE DDYIG..HANGUL SYLLABLE DDYIH
+ {0xB760, 0xB760, prLV}, // Lo HANGUL SYLLABLE DDI
+ {0xB761, 0xB77B, prLVT}, // Lo [27] HANGUL SYLLABLE DDIG..HANGUL SYLLABLE DDIH
+ {0xB77C, 0xB77C, prLV}, // Lo HANGUL SYLLABLE RA
+ {0xB77D, 0xB797, prLVT}, // Lo [27] HANGUL SYLLABLE RAG..HANGUL SYLLABLE RAH
+ {0xB798, 0xB798, prLV}, // Lo HANGUL SYLLABLE RAE
+ {0xB799, 0xB7B3, prLVT}, // Lo [27] HANGUL SYLLABLE RAEG..HANGUL SYLLABLE RAEH
+ {0xB7B4, 0xB7B4, prLV}, // Lo HANGUL SYLLABLE RYA
+ {0xB7B5, 0xB7CF, prLVT}, // Lo [27] HANGUL SYLLABLE RYAG..HANGUL SYLLABLE RYAH
+ {0xB7D0, 0xB7D0, prLV}, // Lo HANGUL SYLLABLE RYAE
+ {0xB7D1, 0xB7EB, prLVT}, // Lo [27] HANGUL SYLLABLE RYAEG..HANGUL SYLLABLE RYAEH
+ {0xB7EC, 0xB7EC, prLV}, // Lo HANGUL SYLLABLE REO
+ {0xB7ED, 0xB807, prLVT}, // Lo [27] HANGUL SYLLABLE REOG..HANGUL SYLLABLE REOH
+ {0xB808, 0xB808, prLV}, // Lo HANGUL SYLLABLE RE
+ {0xB809, 0xB823, prLVT}, // Lo [27] HANGUL SYLLABLE REG..HANGUL SYLLABLE REH
+ {0xB824, 0xB824, prLV}, // Lo HANGUL SYLLABLE RYEO
+ {0xB825, 0xB83F, prLVT}, // Lo [27] HANGUL SYLLABLE RYEOG..HANGUL SYLLABLE RYEOH
+ {0xB840, 0xB840, prLV}, // Lo HANGUL SYLLABLE RYE
+ {0xB841, 0xB85B, prLVT}, // Lo [27] HANGUL SYLLABLE RYEG..HANGUL SYLLABLE RYEH
+ {0xB85C, 0xB85C, prLV}, // Lo HANGUL SYLLABLE RO
+ {0xB85D, 0xB877, prLVT}, // Lo [27] HANGUL SYLLABLE ROG..HANGUL SYLLABLE ROH
+ {0xB878, 0xB878, prLV}, // Lo HANGUL SYLLABLE RWA
+ {0xB879, 0xB893, prLVT}, // Lo [27] HANGUL SYLLABLE RWAG..HANGUL SYLLABLE RWAH
+ {0xB894, 0xB894, prLV}, // Lo HANGUL SYLLABLE RWAE
+ {0xB895, 0xB8AF, prLVT}, // Lo [27] HANGUL SYLLABLE RWAEG..HANGUL SYLLABLE RWAEH
+ {0xB8B0, 0xB8B0, prLV}, // Lo HANGUL SYLLABLE ROE
+ {0xB8B1, 0xB8CB, prLVT}, // Lo [27] HANGUL SYLLABLE ROEG..HANGUL SYLLABLE ROEH
+ {0xB8CC, 0xB8CC, prLV}, // Lo HANGUL SYLLABLE RYO
+ {0xB8CD, 0xB8E7, prLVT}, // Lo [27] HANGUL SYLLABLE RYOG..HANGUL SYLLABLE RYOH
+ {0xB8E8, 0xB8E8, prLV}, // Lo HANGUL SYLLABLE RU
+ {0xB8E9, 0xB903, prLVT}, // Lo [27] HANGUL SYLLABLE RUG..HANGUL SYLLABLE RUH
+ {0xB904, 0xB904, prLV}, // Lo HANGUL SYLLABLE RWEO
+ {0xB905, 0xB91F, prLVT}, // Lo [27] HANGUL SYLLABLE RWEOG..HANGUL SYLLABLE RWEOH
+ {0xB920, 0xB920, prLV}, // Lo HANGUL SYLLABLE RWE
+ {0xB921, 0xB93B, prLVT}, // Lo [27] HANGUL SYLLABLE RWEG..HANGUL SYLLABLE RWEH
+ {0xB93C, 0xB93C, prLV}, // Lo HANGUL SYLLABLE RWI
+ {0xB93D, 0xB957, prLVT}, // Lo [27] HANGUL SYLLABLE RWIG..HANGUL SYLLABLE RWIH
+ {0xB958, 0xB958, prLV}, // Lo HANGUL SYLLABLE RYU
+ {0xB959, 0xB973, prLVT}, // Lo [27] HANGUL SYLLABLE RYUG..HANGUL SYLLABLE RYUH
+ {0xB974, 0xB974, prLV}, // Lo HANGUL SYLLABLE REU
+ {0xB975, 0xB98F, prLVT}, // Lo [27] HANGUL SYLLABLE REUG..HANGUL SYLLABLE REUH
+ {0xB990, 0xB990, prLV}, // Lo HANGUL SYLLABLE RYI
+ {0xB991, 0xB9AB, prLVT}, // Lo [27] HANGUL SYLLABLE RYIG..HANGUL SYLLABLE RYIH
+ {0xB9AC, 0xB9AC, prLV}, // Lo HANGUL SYLLABLE RI
+ {0xB9AD, 0xB9C7, prLVT}, // Lo [27] HANGUL SYLLABLE RIG..HANGUL SYLLABLE RIH
+ {0xB9C8, 0xB9C8, prLV}, // Lo HANGUL SYLLABLE MA
+ {0xB9C9, 0xB9E3, prLVT}, // Lo [27] HANGUL SYLLABLE MAG..HANGUL SYLLABLE MAH
+ {0xB9E4, 0xB9E4, prLV}, // Lo HANGUL SYLLABLE MAE
+ {0xB9E5, 0xB9FF, prLVT}, // Lo [27] HANGUL SYLLABLE MAEG..HANGUL SYLLABLE MAEH
+ {0xBA00, 0xBA00, prLV}, // Lo HANGUL SYLLABLE MYA
+ {0xBA01, 0xBA1B, prLVT}, // Lo [27] HANGUL SYLLABLE MYAG..HANGUL SYLLABLE MYAH
+ {0xBA1C, 0xBA1C, prLV}, // Lo HANGUL SYLLABLE MYAE
+ {0xBA1D, 0xBA37, prLVT}, // Lo [27] HANGUL SYLLABLE MYAEG..HANGUL SYLLABLE MYAEH
+ {0xBA38, 0xBA38, prLV}, // Lo HANGUL SYLLABLE MEO
+ {0xBA39, 0xBA53, prLVT}, // Lo [27] HANGUL SYLLABLE MEOG..HANGUL SYLLABLE MEOH
+ {0xBA54, 0xBA54, prLV}, // Lo HANGUL SYLLABLE ME
+ {0xBA55, 0xBA6F, prLVT}, // Lo [27] HANGUL SYLLABLE MEG..HANGUL SYLLABLE MEH
+ {0xBA70, 0xBA70, prLV}, // Lo HANGUL SYLLABLE MYEO
+ {0xBA71, 0xBA8B, prLVT}, // Lo [27] HANGUL SYLLABLE MYEOG..HANGUL SYLLABLE MYEOH
+ {0xBA8C, 0xBA8C, prLV}, // Lo HANGUL SYLLABLE MYE
+ {0xBA8D, 0xBAA7, prLVT}, // Lo [27] HANGUL SYLLABLE MYEG..HANGUL SYLLABLE MYEH
+ {0xBAA8, 0xBAA8, prLV}, // Lo HANGUL SYLLABLE MO
+ {0xBAA9, 0xBAC3, prLVT}, // Lo [27] HANGUL SYLLABLE MOG..HANGUL SYLLABLE MOH
+ {0xBAC4, 0xBAC4, prLV}, // Lo HANGUL SYLLABLE MWA
+ {0xBAC5, 0xBADF, prLVT}, // Lo [27] HANGUL SYLLABLE MWAG..HANGUL SYLLABLE MWAH
+ {0xBAE0, 0xBAE0, prLV}, // Lo HANGUL SYLLABLE MWAE
+ {0xBAE1, 0xBAFB, prLVT}, // Lo [27] HANGUL SYLLABLE MWAEG..HANGUL SYLLABLE MWAEH
+ {0xBAFC, 0xBAFC, prLV}, // Lo HANGUL SYLLABLE MOE
+ {0xBAFD, 0xBB17, prLVT}, // Lo [27] HANGUL SYLLABLE MOEG..HANGUL SYLLABLE MOEH
+ {0xBB18, 0xBB18, prLV}, // Lo HANGUL SYLLABLE MYO
+ {0xBB19, 0xBB33, prLVT}, // Lo [27] HANGUL SYLLABLE MYOG..HANGUL SYLLABLE MYOH
+ {0xBB34, 0xBB34, prLV}, // Lo HANGUL SYLLABLE MU
+ {0xBB35, 0xBB4F, prLVT}, // Lo [27] HANGUL SYLLABLE MUG..HANGUL SYLLABLE MUH
+ {0xBB50, 0xBB50, prLV}, // Lo HANGUL SYLLABLE MWEO
+ {0xBB51, 0xBB6B, prLVT}, // Lo [27] HANGUL SYLLABLE MWEOG..HANGUL SYLLABLE MWEOH
+ {0xBB6C, 0xBB6C, prLV}, // Lo HANGUL SYLLABLE MWE
+ {0xBB6D, 0xBB87, prLVT}, // Lo [27] HANGUL SYLLABLE MWEG..HANGUL SYLLABLE MWEH
+ {0xBB88, 0xBB88, prLV}, // Lo HANGUL SYLLABLE MWI
+ {0xBB89, 0xBBA3, prLVT}, // Lo [27] HANGUL SYLLABLE MWIG..HANGUL SYLLABLE MWIH
+ {0xBBA4, 0xBBA4, prLV}, // Lo HANGUL SYLLABLE MYU
+ {0xBBA5, 0xBBBF, prLVT}, // Lo [27] HANGUL SYLLABLE MYUG..HANGUL SYLLABLE MYUH
+ {0xBBC0, 0xBBC0, prLV}, // Lo HANGUL SYLLABLE MEU
+ {0xBBC1, 0xBBDB, prLVT}, // Lo [27] HANGUL SYLLABLE MEUG..HANGUL SYLLABLE MEUH
+ {0xBBDC, 0xBBDC, prLV}, // Lo HANGUL SYLLABLE MYI
+ {0xBBDD, 0xBBF7, prLVT}, // Lo [27] HANGUL SYLLABLE MYIG..HANGUL SYLLABLE MYIH
+ {0xBBF8, 0xBBF8, prLV}, // Lo HANGUL SYLLABLE MI
+ {0xBBF9, 0xBC13, prLVT}, // Lo [27] HANGUL SYLLABLE MIG..HANGUL SYLLABLE MIH
+ {0xBC14, 0xBC14, prLV}, // Lo HANGUL SYLLABLE BA
+ {0xBC15, 0xBC2F, prLVT}, // Lo [27] HANGUL SYLLABLE BAG..HANGUL SYLLABLE BAH
+ {0xBC30, 0xBC30, prLV}, // Lo HANGUL SYLLABLE BAE
+ {0xBC31, 0xBC4B, prLVT}, // Lo [27] HANGUL SYLLABLE BAEG..HANGUL SYLLABLE BAEH
+ {0xBC4C, 0xBC4C, prLV}, // Lo HANGUL SYLLABLE BYA
+ {0xBC4D, 0xBC67, prLVT}, // Lo [27] HANGUL SYLLABLE BYAG..HANGUL SYLLABLE BYAH
+ {0xBC68, 0xBC68, prLV}, // Lo HANGUL SYLLABLE BYAE
+ {0xBC69, 0xBC83, prLVT}, // Lo [27] HANGUL SYLLABLE BYAEG..HANGUL SYLLABLE BYAEH
+ {0xBC84, 0xBC84, prLV}, // Lo HANGUL SYLLABLE BEO
+ {0xBC85, 0xBC9F, prLVT}, // Lo [27] HANGUL SYLLABLE BEOG..HANGUL SYLLABLE BEOH
+ {0xBCA0, 0xBCA0, prLV}, // Lo HANGUL SYLLABLE BE
+ {0xBCA1, 0xBCBB, prLVT}, // Lo [27] HANGUL SYLLABLE BEG..HANGUL SYLLABLE BEH
+ {0xBCBC, 0xBCBC, prLV}, // Lo HANGUL SYLLABLE BYEO
+ {0xBCBD, 0xBCD7, prLVT}, // Lo [27] HANGUL SYLLABLE BYEOG..HANGUL SYLLABLE BYEOH
+ {0xBCD8, 0xBCD8, prLV}, // Lo HANGUL SYLLABLE BYE
+ {0xBCD9, 0xBCF3, prLVT}, // Lo [27] HANGUL SYLLABLE BYEG..HANGUL SYLLABLE BYEH
+ {0xBCF4, 0xBCF4, prLV}, // Lo HANGUL SYLLABLE BO
+ {0xBCF5, 0xBD0F, prLVT}, // Lo [27] HANGUL SYLLABLE BOG..HANGUL SYLLABLE BOH
+ {0xBD10, 0xBD10, prLV}, // Lo HANGUL SYLLABLE BWA
+ {0xBD11, 0xBD2B, prLVT}, // Lo [27] HANGUL SYLLABLE BWAG..HANGUL SYLLABLE BWAH
+ {0xBD2C, 0xBD2C, prLV}, // Lo HANGUL SYLLABLE BWAE
+ {0xBD2D, 0xBD47, prLVT}, // Lo [27] HANGUL SYLLABLE BWAEG..HANGUL SYLLABLE BWAEH
+ {0xBD48, 0xBD48, prLV}, // Lo HANGUL SYLLABLE BOE
+ {0xBD49, 0xBD63, prLVT}, // Lo [27] HANGUL SYLLABLE BOEG..HANGUL SYLLABLE BOEH
+ {0xBD64, 0xBD64, prLV}, // Lo HANGUL SYLLABLE BYO
+ {0xBD65, 0xBD7F, prLVT}, // Lo [27] HANGUL SYLLABLE BYOG..HANGUL SYLLABLE BYOH
+ {0xBD80, 0xBD80, prLV}, // Lo HANGUL SYLLABLE BU
+ {0xBD81, 0xBD9B, prLVT}, // Lo [27] HANGUL SYLLABLE BUG..HANGUL SYLLABLE BUH
+ {0xBD9C, 0xBD9C, prLV}, // Lo HANGUL SYLLABLE BWEO
+ {0xBD9D, 0xBDB7, prLVT}, // Lo [27] HANGUL SYLLABLE BWEOG..HANGUL SYLLABLE BWEOH
+ {0xBDB8, 0xBDB8, prLV}, // Lo HANGUL SYLLABLE BWE
+ {0xBDB9, 0xBDD3, prLVT}, // Lo [27] HANGUL SYLLABLE BWEG..HANGUL SYLLABLE BWEH
+ {0xBDD4, 0xBDD4, prLV}, // Lo HANGUL SYLLABLE BWI
+ {0xBDD5, 0xBDEF, prLVT}, // Lo [27] HANGUL SYLLABLE BWIG..HANGUL SYLLABLE BWIH
+ {0xBDF0, 0xBDF0, prLV}, // Lo HANGUL SYLLABLE BYU
+ {0xBDF1, 0xBE0B, prLVT}, // Lo [27] HANGUL SYLLABLE BYUG..HANGUL SYLLABLE BYUH
+ {0xBE0C, 0xBE0C, prLV}, // Lo HANGUL SYLLABLE BEU
+ {0xBE0D, 0xBE27, prLVT}, // Lo [27] HANGUL SYLLABLE BEUG..HANGUL SYLLABLE BEUH
+ {0xBE28, 0xBE28, prLV}, // Lo HANGUL SYLLABLE BYI
+ {0xBE29, 0xBE43, prLVT}, // Lo [27] HANGUL SYLLABLE BYIG..HANGUL SYLLABLE BYIH
+ {0xBE44, 0xBE44, prLV}, // Lo HANGUL SYLLABLE BI
+ {0xBE45, 0xBE5F, prLVT}, // Lo [27] HANGUL SYLLABLE BIG..HANGUL SYLLABLE BIH
+ {0xBE60, 0xBE60, prLV}, // Lo HANGUL SYLLABLE BBA
+ {0xBE61, 0xBE7B, prLVT}, // Lo [27] HANGUL SYLLABLE BBAG..HANGUL SYLLABLE BBAH
+ {0xBE7C, 0xBE7C, prLV}, // Lo HANGUL SYLLABLE BBAE
+ {0xBE7D, 0xBE97, prLVT}, // Lo [27] HANGUL SYLLABLE BBAEG..HANGUL SYLLABLE BBAEH
+ {0xBE98, 0xBE98, prLV}, // Lo HANGUL SYLLABLE BBYA
+ {0xBE99, 0xBEB3, prLVT}, // Lo [27] HANGUL SYLLABLE BBYAG..HANGUL SYLLABLE BBYAH
+ {0xBEB4, 0xBEB4, prLV}, // Lo HANGUL SYLLABLE BBYAE
+ {0xBEB5, 0xBECF, prLVT}, // Lo [27] HANGUL SYLLABLE BBYAEG..HANGUL SYLLABLE BBYAEH
+ {0xBED0, 0xBED0, prLV}, // Lo HANGUL SYLLABLE BBEO
+ {0xBED1, 0xBEEB, prLVT}, // Lo [27] HANGUL SYLLABLE BBEOG..HANGUL SYLLABLE BBEOH
+ {0xBEEC, 0xBEEC, prLV}, // Lo HANGUL SYLLABLE BBE
+ {0xBEED, 0xBF07, prLVT}, // Lo [27] HANGUL SYLLABLE BBEG..HANGUL SYLLABLE BBEH
+ {0xBF08, 0xBF08, prLV}, // Lo HANGUL SYLLABLE BBYEO
+ {0xBF09, 0xBF23, prLVT}, // Lo [27] HANGUL SYLLABLE BBYEOG..HANGUL SYLLABLE BBYEOH
+ {0xBF24, 0xBF24, prLV}, // Lo HANGUL SYLLABLE BBYE
+ {0xBF25, 0xBF3F, prLVT}, // Lo [27] HANGUL SYLLABLE BBYEG..HANGUL SYLLABLE BBYEH
+ {0xBF40, 0xBF40, prLV}, // Lo HANGUL SYLLABLE BBO
+ {0xBF41, 0xBF5B, prLVT}, // Lo [27] HANGUL SYLLABLE BBOG..HANGUL SYLLABLE BBOH
+ {0xBF5C, 0xBF5C, prLV}, // Lo HANGUL SYLLABLE BBWA
+ {0xBF5D, 0xBF77, prLVT}, // Lo [27] HANGUL SYLLABLE BBWAG..HANGUL SYLLABLE BBWAH
+ {0xBF78, 0xBF78, prLV}, // Lo HANGUL SYLLABLE BBWAE
+ {0xBF79, 0xBF93, prLVT}, // Lo [27] HANGUL SYLLABLE BBWAEG..HANGUL SYLLABLE BBWAEH
+ {0xBF94, 0xBF94, prLV}, // Lo HANGUL SYLLABLE BBOE
+ {0xBF95, 0xBFAF, prLVT}, // Lo [27] HANGUL SYLLABLE BBOEG..HANGUL SYLLABLE BBOEH
+ {0xBFB0, 0xBFB0, prLV}, // Lo HANGUL SYLLABLE BBYO
+ {0xBFB1, 0xBFCB, prLVT}, // Lo [27] HANGUL SYLLABLE BBYOG..HANGUL SYLLABLE BBYOH
+ {0xBFCC, 0xBFCC, prLV}, // Lo HANGUL SYLLABLE BBU
+ {0xBFCD, 0xBFE7, prLVT}, // Lo [27] HANGUL SYLLABLE BBUG..HANGUL SYLLABLE BBUH
+ {0xBFE8, 0xBFE8, prLV}, // Lo HANGUL SYLLABLE BBWEO
+ {0xBFE9, 0xC003, prLVT}, // Lo [27] HANGUL SYLLABLE BBWEOG..HANGUL SYLLABLE BBWEOH
+ {0xC004, 0xC004, prLV}, // Lo HANGUL SYLLABLE BBWE
+ {0xC005, 0xC01F, prLVT}, // Lo [27] HANGUL SYLLABLE BBWEG..HANGUL SYLLABLE BBWEH
+ {0xC020, 0xC020, prLV}, // Lo HANGUL SYLLABLE BBWI
+ {0xC021, 0xC03B, prLVT}, // Lo [27] HANGUL SYLLABLE BBWIG..HANGUL SYLLABLE BBWIH
+ {0xC03C, 0xC03C, prLV}, // Lo HANGUL SYLLABLE BBYU
+ {0xC03D, 0xC057, prLVT}, // Lo [27] HANGUL SYLLABLE BBYUG..HANGUL SYLLABLE BBYUH
+ {0xC058, 0xC058, prLV}, // Lo HANGUL SYLLABLE BBEU
+ {0xC059, 0xC073, prLVT}, // Lo [27] HANGUL SYLLABLE BBEUG..HANGUL SYLLABLE BBEUH
+ {0xC074, 0xC074, prLV}, // Lo HANGUL SYLLABLE BBYI
+ {0xC075, 0xC08F, prLVT}, // Lo [27] HANGUL SYLLABLE BBYIG..HANGUL SYLLABLE BBYIH
+ {0xC090, 0xC090, prLV}, // Lo HANGUL SYLLABLE BBI
+ {0xC091, 0xC0AB, prLVT}, // Lo [27] HANGUL SYLLABLE BBIG..HANGUL SYLLABLE BBIH
+ {0xC0AC, 0xC0AC, prLV}, // Lo HANGUL SYLLABLE SA
+ {0xC0AD, 0xC0C7, prLVT}, // Lo [27] HANGUL SYLLABLE SAG..HANGUL SYLLABLE SAH
+ {0xC0C8, 0xC0C8, prLV}, // Lo HANGUL SYLLABLE SAE
+ {0xC0C9, 0xC0E3, prLVT}, // Lo [27] HANGUL SYLLABLE SAEG..HANGUL SYLLABLE SAEH
+ {0xC0E4, 0xC0E4, prLV}, // Lo HANGUL SYLLABLE SYA
+ {0xC0E5, 0xC0FF, prLVT}, // Lo [27] HANGUL SYLLABLE SYAG..HANGUL SYLLABLE SYAH
+ {0xC100, 0xC100, prLV}, // Lo HANGUL SYLLABLE SYAE
+ {0xC101, 0xC11B, prLVT}, // Lo [27] HANGUL SYLLABLE SYAEG..HANGUL SYLLABLE SYAEH
+ {0xC11C, 0xC11C, prLV}, // Lo HANGUL SYLLABLE SEO
+ {0xC11D, 0xC137, prLVT}, // Lo [27] HANGUL SYLLABLE SEOG..HANGUL SYLLABLE SEOH
+ {0xC138, 0xC138, prLV}, // Lo HANGUL SYLLABLE SE
+ {0xC139, 0xC153, prLVT}, // Lo [27] HANGUL SYLLABLE SEG..HANGUL SYLLABLE SEH
+ {0xC154, 0xC154, prLV}, // Lo HANGUL SYLLABLE SYEO
+ {0xC155, 0xC16F, prLVT}, // Lo [27] HANGUL SYLLABLE SYEOG..HANGUL SYLLABLE SYEOH
+ {0xC170, 0xC170, prLV}, // Lo HANGUL SYLLABLE SYE
+ {0xC171, 0xC18B, prLVT}, // Lo [27] HANGUL SYLLABLE SYEG..HANGUL SYLLABLE SYEH
+ {0xC18C, 0xC18C, prLV}, // Lo HANGUL SYLLABLE SO
+ {0xC18D, 0xC1A7, prLVT}, // Lo [27] HANGUL SYLLABLE SOG..HANGUL SYLLABLE SOH
+ {0xC1A8, 0xC1A8, prLV}, // Lo HANGUL SYLLABLE SWA
+ {0xC1A9, 0xC1C3, prLVT}, // Lo [27] HANGUL SYLLABLE SWAG..HANGUL SYLLABLE SWAH
+ {0xC1C4, 0xC1C4, prLV}, // Lo HANGUL SYLLABLE SWAE
+ {0xC1C5, 0xC1DF, prLVT}, // Lo [27] HANGUL SYLLABLE SWAEG..HANGUL SYLLABLE SWAEH
+ {0xC1E0, 0xC1E0, prLV}, // Lo HANGUL SYLLABLE SOE
+ {0xC1E1, 0xC1FB, prLVT}, // Lo [27] HANGUL SYLLABLE SOEG..HANGUL SYLLABLE SOEH
+ {0xC1FC, 0xC1FC, prLV}, // Lo HANGUL SYLLABLE SYO
+ {0xC1FD, 0xC217, prLVT}, // Lo [27] HANGUL SYLLABLE SYOG..HANGUL SYLLABLE SYOH
+ {0xC218, 0xC218, prLV}, // Lo HANGUL SYLLABLE SU
+ {0xC219, 0xC233, prLVT}, // Lo [27] HANGUL SYLLABLE SUG..HANGUL SYLLABLE SUH
+ {0xC234, 0xC234, prLV}, // Lo HANGUL SYLLABLE SWEO
+ {0xC235, 0xC24F, prLVT}, // Lo [27] HANGUL SYLLABLE SWEOG..HANGUL SYLLABLE SWEOH
+ {0xC250, 0xC250, prLV}, // Lo HANGUL SYLLABLE SWE
+ {0xC251, 0xC26B, prLVT}, // Lo [27] HANGUL SYLLABLE SWEG..HANGUL SYLLABLE SWEH
+ {0xC26C, 0xC26C, prLV}, // Lo HANGUL SYLLABLE SWI
+ {0xC26D, 0xC287, prLVT}, // Lo [27] HANGUL SYLLABLE SWIG..HANGUL SYLLABLE SWIH
+ {0xC288, 0xC288, prLV}, // Lo HANGUL SYLLABLE SYU
+ {0xC289, 0xC2A3, prLVT}, // Lo [27] HANGUL SYLLABLE SYUG..HANGUL SYLLABLE SYUH
+ {0xC2A4, 0xC2A4, prLV}, // Lo HANGUL SYLLABLE SEU
+ {0xC2A5, 0xC2BF, prLVT}, // Lo [27] HANGUL SYLLABLE SEUG..HANGUL SYLLABLE SEUH
+ {0xC2C0, 0xC2C0, prLV}, // Lo HANGUL SYLLABLE SYI
+ {0xC2C1, 0xC2DB, prLVT}, // Lo [27] HANGUL SYLLABLE SYIG..HANGUL SYLLABLE SYIH
+ {0xC2DC, 0xC2DC, prLV}, // Lo HANGUL SYLLABLE SI
+ {0xC2DD, 0xC2F7, prLVT}, // Lo [27] HANGUL SYLLABLE SIG..HANGUL SYLLABLE SIH
+ {0xC2F8, 0xC2F8, prLV}, // Lo HANGUL SYLLABLE SSA
+ {0xC2F9, 0xC313, prLVT}, // Lo [27] HANGUL SYLLABLE SSAG..HANGUL SYLLABLE SSAH
+ {0xC314, 0xC314, prLV}, // Lo HANGUL SYLLABLE SSAE
+ {0xC315, 0xC32F, prLVT}, // Lo [27] HANGUL SYLLABLE SSAEG..HANGUL SYLLABLE SSAEH
+ {0xC330, 0xC330, prLV}, // Lo HANGUL SYLLABLE SSYA
+ {0xC331, 0xC34B, prLVT}, // Lo [27] HANGUL SYLLABLE SSYAG..HANGUL SYLLABLE SSYAH
+ {0xC34C, 0xC34C, prLV}, // Lo HANGUL SYLLABLE SSYAE
+ {0xC34D, 0xC367, prLVT}, // Lo [27] HANGUL SYLLABLE SSYAEG..HANGUL SYLLABLE SSYAEH
+ {0xC368, 0xC368, prLV}, // Lo HANGUL SYLLABLE SSEO
+ {0xC369, 0xC383, prLVT}, // Lo [27] HANGUL SYLLABLE SSEOG..HANGUL SYLLABLE SSEOH
+ {0xC384, 0xC384, prLV}, // Lo HANGUL SYLLABLE SSE
+ {0xC385, 0xC39F, prLVT}, // Lo [27] HANGUL SYLLABLE SSEG..HANGUL SYLLABLE SSEH
+ {0xC3A0, 0xC3A0, prLV}, // Lo HANGUL SYLLABLE SSYEO
+ {0xC3A1, 0xC3BB, prLVT}, // Lo [27] HANGUL SYLLABLE SSYEOG..HANGUL SYLLABLE SSYEOH
+ {0xC3BC, 0xC3BC, prLV}, // Lo HANGUL SYLLABLE SSYE
+ {0xC3BD, 0xC3D7, prLVT}, // Lo [27] HANGUL SYLLABLE SSYEG..HANGUL SYLLABLE SSYEH
+ {0xC3D8, 0xC3D8, prLV}, // Lo HANGUL SYLLABLE SSO
+ {0xC3D9, 0xC3F3, prLVT}, // Lo [27] HANGUL SYLLABLE SSOG..HANGUL SYLLABLE SSOH
+ {0xC3F4, 0xC3F4, prLV}, // Lo HANGUL SYLLABLE SSWA
+ {0xC3F5, 0xC40F, prLVT}, // Lo [27] HANGUL SYLLABLE SSWAG..HANGUL SYLLABLE SSWAH
+ {0xC410, 0xC410, prLV}, // Lo HANGUL SYLLABLE SSWAE
+ {0xC411, 0xC42B, prLVT}, // Lo [27] HANGUL SYLLABLE SSWAEG..HANGUL SYLLABLE SSWAEH
+ {0xC42C, 0xC42C, prLV}, // Lo HANGUL SYLLABLE SSOE
+ {0xC42D, 0xC447, prLVT}, // Lo [27] HANGUL SYLLABLE SSOEG..HANGUL SYLLABLE SSOEH
+ {0xC448, 0xC448, prLV}, // Lo HANGUL SYLLABLE SSYO
+ {0xC449, 0xC463, prLVT}, // Lo [27] HANGUL SYLLABLE SSYOG..HANGUL SYLLABLE SSYOH
+ {0xC464, 0xC464, prLV}, // Lo HANGUL SYLLABLE SSU
+ {0xC465, 0xC47F, prLVT}, // Lo [27] HANGUL SYLLABLE SSUG..HANGUL SYLLABLE SSUH
+ {0xC480, 0xC480, prLV}, // Lo HANGUL SYLLABLE SSWEO
+ {0xC481, 0xC49B, prLVT}, // Lo [27] HANGUL SYLLABLE SSWEOG..HANGUL SYLLABLE SSWEOH
+ {0xC49C, 0xC49C, prLV}, // Lo HANGUL SYLLABLE SSWE
+ {0xC49D, 0xC4B7, prLVT}, // Lo [27] HANGUL SYLLABLE SSWEG..HANGUL SYLLABLE SSWEH
+ {0xC4B8, 0xC4B8, prLV}, // Lo HANGUL SYLLABLE SSWI
+ {0xC4B9, 0xC4D3, prLVT}, // Lo [27] HANGUL SYLLABLE SSWIG..HANGUL SYLLABLE SSWIH
+ {0xC4D4, 0xC4D4, prLV}, // Lo HANGUL SYLLABLE SSYU
+ {0xC4D5, 0xC4EF, prLVT}, // Lo [27] HANGUL SYLLABLE SSYUG..HANGUL SYLLABLE SSYUH
+ {0xC4F0, 0xC4F0, prLV}, // Lo HANGUL SYLLABLE SSEU
+ {0xC4F1, 0xC50B, prLVT}, // Lo [27] HANGUL SYLLABLE SSEUG..HANGUL SYLLABLE SSEUH
+ {0xC50C, 0xC50C, prLV}, // Lo HANGUL SYLLABLE SSYI
+ {0xC50D, 0xC527, prLVT}, // Lo [27] HANGUL SYLLABLE SSYIG..HANGUL SYLLABLE SSYIH
+ {0xC528, 0xC528, prLV}, // Lo HANGUL SYLLABLE SSI
+ {0xC529, 0xC543, prLVT}, // Lo [27] HANGUL SYLLABLE SSIG..HANGUL SYLLABLE SSIH
+ {0xC544, 0xC544, prLV}, // Lo HANGUL SYLLABLE A
+ {0xC545, 0xC55F, prLVT}, // Lo [27] HANGUL SYLLABLE AG..HANGUL SYLLABLE AH
+ {0xC560, 0xC560, prLV}, // Lo HANGUL SYLLABLE AE
+ {0xC561, 0xC57B, prLVT}, // Lo [27] HANGUL SYLLABLE AEG..HANGUL SYLLABLE AEH
+ {0xC57C, 0xC57C, prLV}, // Lo HANGUL SYLLABLE YA
+ {0xC57D, 0xC597, prLVT}, // Lo [27] HANGUL SYLLABLE YAG..HANGUL SYLLABLE YAH
+ {0xC598, 0xC598, prLV}, // Lo HANGUL SYLLABLE YAE
+ {0xC599, 0xC5B3, prLVT}, // Lo [27] HANGUL SYLLABLE YAEG..HANGUL SYLLABLE YAEH
+ {0xC5B4, 0xC5B4, prLV}, // Lo HANGUL SYLLABLE EO
+ {0xC5B5, 0xC5CF, prLVT}, // Lo [27] HANGUL SYLLABLE EOG..HANGUL SYLLABLE EOH
+ {0xC5D0, 0xC5D0, prLV}, // Lo HANGUL SYLLABLE E
+ {0xC5D1, 0xC5EB, prLVT}, // Lo [27] HANGUL SYLLABLE EG..HANGUL SYLLABLE EH
+ {0xC5EC, 0xC5EC, prLV}, // Lo HANGUL SYLLABLE YEO
+ {0xC5ED, 0xC607, prLVT}, // Lo [27] HANGUL SYLLABLE YEOG..HANGUL SYLLABLE YEOH
+ {0xC608, 0xC608, prLV}, // Lo HANGUL SYLLABLE YE
+ {0xC609, 0xC623, prLVT}, // Lo [27] HANGUL SYLLABLE YEG..HANGUL SYLLABLE YEH
+ {0xC624, 0xC624, prLV}, // Lo HANGUL SYLLABLE O
+ {0xC625, 0xC63F, prLVT}, // Lo [27] HANGUL SYLLABLE OG..HANGUL SYLLABLE OH
+ {0xC640, 0xC640, prLV}, // Lo HANGUL SYLLABLE WA
+ {0xC641, 0xC65B, prLVT}, // Lo [27] HANGUL SYLLABLE WAG..HANGUL SYLLABLE WAH
+ {0xC65C, 0xC65C, prLV}, // Lo HANGUL SYLLABLE WAE
+ {0xC65D, 0xC677, prLVT}, // Lo [27] HANGUL SYLLABLE WAEG..HANGUL SYLLABLE WAEH
+ {0xC678, 0xC678, prLV}, // Lo HANGUL SYLLABLE OE
+ {0xC679, 0xC693, prLVT}, // Lo [27] HANGUL SYLLABLE OEG..HANGUL SYLLABLE OEH
+ {0xC694, 0xC694, prLV}, // Lo HANGUL SYLLABLE YO
+ {0xC695, 0xC6AF, prLVT}, // Lo [27] HANGUL SYLLABLE YOG..HANGUL SYLLABLE YOH
+ {0xC6B0, 0xC6B0, prLV}, // Lo HANGUL SYLLABLE U
+ {0xC6B1, 0xC6CB, prLVT}, // Lo [27] HANGUL SYLLABLE UG..HANGUL SYLLABLE UH
+ {0xC6CC, 0xC6CC, prLV}, // Lo HANGUL SYLLABLE WEO
+ {0xC6CD, 0xC6E7, prLVT}, // Lo [27] HANGUL SYLLABLE WEOG..HANGUL SYLLABLE WEOH
+ {0xC6E8, 0xC6E8, prLV}, // Lo HANGUL SYLLABLE WE
+ {0xC6E9, 0xC703, prLVT}, // Lo [27] HANGUL SYLLABLE WEG..HANGUL SYLLABLE WEH
+ {0xC704, 0xC704, prLV}, // Lo HANGUL SYLLABLE WI
+ {0xC705, 0xC71F, prLVT}, // Lo [27] HANGUL SYLLABLE WIG..HANGUL SYLLABLE WIH
+ {0xC720, 0xC720, prLV}, // Lo HANGUL SYLLABLE YU
+ {0xC721, 0xC73B, prLVT}, // Lo [27] HANGUL SYLLABLE YUG..HANGUL SYLLABLE YUH
+ {0xC73C, 0xC73C, prLV}, // Lo HANGUL SYLLABLE EU
+ {0xC73D, 0xC757, prLVT}, // Lo [27] HANGUL SYLLABLE EUG..HANGUL SYLLABLE EUH
+ {0xC758, 0xC758, prLV}, // Lo HANGUL SYLLABLE YI
+ {0xC759, 0xC773, prLVT}, // Lo [27] HANGUL SYLLABLE YIG..HANGUL SYLLABLE YIH
+ {0xC774, 0xC774, prLV}, // Lo HANGUL SYLLABLE I
+ {0xC775, 0xC78F, prLVT}, // Lo [27] HANGUL SYLLABLE IG..HANGUL SYLLABLE IH
+ {0xC790, 0xC790, prLV}, // Lo HANGUL SYLLABLE JA
+ {0xC791, 0xC7AB, prLVT}, // Lo [27] HANGUL SYLLABLE JAG..HANGUL SYLLABLE JAH
+ {0xC7AC, 0xC7AC, prLV}, // Lo HANGUL SYLLABLE JAE
+ {0xC7AD, 0xC7C7, prLVT}, // Lo [27] HANGUL SYLLABLE JAEG..HANGUL SYLLABLE JAEH
+ {0xC7C8, 0xC7C8, prLV}, // Lo HANGUL SYLLABLE JYA
+ {0xC7C9, 0xC7E3, prLVT}, // Lo [27] HANGUL SYLLABLE JYAG..HANGUL SYLLABLE JYAH
+ {0xC7E4, 0xC7E4, prLV}, // Lo HANGUL SYLLABLE JYAE
+ {0xC7E5, 0xC7FF, prLVT}, // Lo [27] HANGUL SYLLABLE JYAEG..HANGUL SYLLABLE JYAEH
+ {0xC800, 0xC800, prLV}, // Lo HANGUL SYLLABLE JEO
+ {0xC801, 0xC81B, prLVT}, // Lo [27] HANGUL SYLLABLE JEOG..HANGUL SYLLABLE JEOH
+ {0xC81C, 0xC81C, prLV}, // Lo HANGUL SYLLABLE JE
+ {0xC81D, 0xC837, prLVT}, // Lo [27] HANGUL SYLLABLE JEG..HANGUL SYLLABLE JEH
+ {0xC838, 0xC838, prLV}, // Lo HANGUL SYLLABLE JYEO
+ {0xC839, 0xC853, prLVT}, // Lo [27] HANGUL SYLLABLE JYEOG..HANGUL SYLLABLE JYEOH
+ {0xC854, 0xC854, prLV}, // Lo HANGUL SYLLABLE JYE
+ {0xC855, 0xC86F, prLVT}, // Lo [27] HANGUL SYLLABLE JYEG..HANGUL SYLLABLE JYEH
+ {0xC870, 0xC870, prLV}, // Lo HANGUL SYLLABLE JO
+ {0xC871, 0xC88B, prLVT}, // Lo [27] HANGUL SYLLABLE JOG..HANGUL SYLLABLE JOH
+ {0xC88C, 0xC88C, prLV}, // Lo HANGUL SYLLABLE JWA
+ {0xC88D, 0xC8A7, prLVT}, // Lo [27] HANGUL SYLLABLE JWAG..HANGUL SYLLABLE JWAH
+ {0xC8A8, 0xC8A8, prLV}, // Lo HANGUL SYLLABLE JWAE
+ {0xC8A9, 0xC8C3, prLVT}, // Lo [27] HANGUL SYLLABLE JWAEG..HANGUL SYLLABLE JWAEH
+ {0xC8C4, 0xC8C4, prLV}, // Lo HANGUL SYLLABLE JOE
+ {0xC8C5, 0xC8DF, prLVT}, // Lo [27] HANGUL SYLLABLE JOEG..HANGUL SYLLABLE JOEH
+ {0xC8E0, 0xC8E0, prLV}, // Lo HANGUL SYLLABLE JYO
+ {0xC8E1, 0xC8FB, prLVT}, // Lo [27] HANGUL SYLLABLE JYOG..HANGUL SYLLABLE JYOH
+ {0xC8FC, 0xC8FC, prLV}, // Lo HANGUL SYLLABLE JU
+ {0xC8FD, 0xC917, prLVT}, // Lo [27] HANGUL SYLLABLE JUG..HANGUL SYLLABLE JUH
+ {0xC918, 0xC918, prLV}, // Lo HANGUL SYLLABLE JWEO
+ {0xC919, 0xC933, prLVT}, // Lo [27] HANGUL SYLLABLE JWEOG..HANGUL SYLLABLE JWEOH
+ {0xC934, 0xC934, prLV}, // Lo HANGUL SYLLABLE JWE
+ {0xC935, 0xC94F, prLVT}, // Lo [27] HANGUL SYLLABLE JWEG..HANGUL SYLLABLE JWEH
+ {0xC950, 0xC950, prLV}, // Lo HANGUL SYLLABLE JWI
+ {0xC951, 0xC96B, prLVT}, // Lo [27] HANGUL SYLLABLE JWIG..HANGUL SYLLABLE JWIH
+ {0xC96C, 0xC96C, prLV}, // Lo HANGUL SYLLABLE JYU
+ {0xC96D, 0xC987, prLVT}, // Lo [27] HANGUL SYLLABLE JYUG..HANGUL SYLLABLE JYUH
+ {0xC988, 0xC988, prLV}, // Lo HANGUL SYLLABLE JEU
+ {0xC989, 0xC9A3, prLVT}, // Lo [27] HANGUL SYLLABLE JEUG..HANGUL SYLLABLE JEUH
+ {0xC9A4, 0xC9A4, prLV}, // Lo HANGUL SYLLABLE JYI
+ {0xC9A5, 0xC9BF, prLVT}, // Lo [27] HANGUL SYLLABLE JYIG..HANGUL SYLLABLE JYIH
+ {0xC9C0, 0xC9C0, prLV}, // Lo HANGUL SYLLABLE JI
+ {0xC9C1, 0xC9DB, prLVT}, // Lo [27] HANGUL SYLLABLE JIG..HANGUL SYLLABLE JIH
+ {0xC9DC, 0xC9DC, prLV}, // Lo HANGUL SYLLABLE JJA
+ {0xC9DD, 0xC9F7, prLVT}, // Lo [27] HANGUL SYLLABLE JJAG..HANGUL SYLLABLE JJAH
+ {0xC9F8, 0xC9F8, prLV}, // Lo HANGUL SYLLABLE JJAE
+ {0xC9F9, 0xCA13, prLVT}, // Lo [27] HANGUL SYLLABLE JJAEG..HANGUL SYLLABLE JJAEH
+ {0xCA14, 0xCA14, prLV}, // Lo HANGUL SYLLABLE JJYA
+ {0xCA15, 0xCA2F, prLVT}, // Lo [27] HANGUL SYLLABLE JJYAG..HANGUL SYLLABLE JJYAH
+ {0xCA30, 0xCA30, prLV}, // Lo HANGUL SYLLABLE JJYAE
+ {0xCA31, 0xCA4B, prLVT}, // Lo [27] HANGUL SYLLABLE JJYAEG..HANGUL SYLLABLE JJYAEH
+ {0xCA4C, 0xCA4C, prLV}, // Lo HANGUL SYLLABLE JJEO
+ {0xCA4D, 0xCA67, prLVT}, // Lo [27] HANGUL SYLLABLE JJEOG..HANGUL SYLLABLE JJEOH
+ {0xCA68, 0xCA68, prLV}, // Lo HANGUL SYLLABLE JJE
+ {0xCA69, 0xCA83, prLVT}, // Lo [27] HANGUL SYLLABLE JJEG..HANGUL SYLLABLE JJEH
+ {0xCA84, 0xCA84, prLV}, // Lo HANGUL SYLLABLE JJYEO
+ {0xCA85, 0xCA9F, prLVT}, // Lo [27] HANGUL SYLLABLE JJYEOG..HANGUL SYLLABLE JJYEOH
+ {0xCAA0, 0xCAA0, prLV}, // Lo HANGUL SYLLABLE JJYE
+ {0xCAA1, 0xCABB, prLVT}, // Lo [27] HANGUL SYLLABLE JJYEG..HANGUL SYLLABLE JJYEH
+ {0xCABC, 0xCABC, prLV}, // Lo HANGUL SYLLABLE JJO
+ {0xCABD, 0xCAD7, prLVT}, // Lo [27] HANGUL SYLLABLE JJOG..HANGUL SYLLABLE JJOH
+ {0xCAD8, 0xCAD8, prLV}, // Lo HANGUL SYLLABLE JJWA
+ {0xCAD9, 0xCAF3, prLVT}, // Lo [27] HANGUL SYLLABLE JJWAG..HANGUL SYLLABLE JJWAH
+ {0xCAF4, 0xCAF4, prLV}, // Lo HANGUL SYLLABLE JJWAE
+ {0xCAF5, 0xCB0F, prLVT}, // Lo [27] HANGUL SYLLABLE JJWAEG..HANGUL SYLLABLE JJWAEH
+ {0xCB10, 0xCB10, prLV}, // Lo HANGUL SYLLABLE JJOE
+ {0xCB11, 0xCB2B, prLVT}, // Lo [27] HANGUL SYLLABLE JJOEG..HANGUL SYLLABLE JJOEH
+ {0xCB2C, 0xCB2C, prLV}, // Lo HANGUL SYLLABLE JJYO
+ {0xCB2D, 0xCB47, prLVT}, // Lo [27] HANGUL SYLLABLE JJYOG..HANGUL SYLLABLE JJYOH
+ {0xCB48, 0xCB48, prLV}, // Lo HANGUL SYLLABLE JJU
+ {0xCB49, 0xCB63, prLVT}, // Lo [27] HANGUL SYLLABLE JJUG..HANGUL SYLLABLE JJUH
+ {0xCB64, 0xCB64, prLV}, // Lo HANGUL SYLLABLE JJWEO
+ {0xCB65, 0xCB7F, prLVT}, // Lo [27] HANGUL SYLLABLE JJWEOG..HANGUL SYLLABLE JJWEOH
+ {0xCB80, 0xCB80, prLV}, // Lo HANGUL SYLLABLE JJWE
+ {0xCB81, 0xCB9B, prLVT}, // Lo [27] HANGUL SYLLABLE JJWEG..HANGUL SYLLABLE JJWEH
+ {0xCB9C, 0xCB9C, prLV}, // Lo HANGUL SYLLABLE JJWI
+ {0xCB9D, 0xCBB7, prLVT}, // Lo [27] HANGUL SYLLABLE JJWIG..HANGUL SYLLABLE JJWIH
+ {0xCBB8, 0xCBB8, prLV}, // Lo HANGUL SYLLABLE JJYU
+ {0xCBB9, 0xCBD3, prLVT}, // Lo [27] HANGUL SYLLABLE JJYUG..HANGUL SYLLABLE JJYUH
+ {0xCBD4, 0xCBD4, prLV}, // Lo HANGUL SYLLABLE JJEU
+ {0xCBD5, 0xCBEF, prLVT}, // Lo [27] HANGUL SYLLABLE JJEUG..HANGUL SYLLABLE JJEUH
+ {0xCBF0, 0xCBF0, prLV}, // Lo HANGUL SYLLABLE JJYI
+ {0xCBF1, 0xCC0B, prLVT}, // Lo [27] HANGUL SYLLABLE JJYIG..HANGUL SYLLABLE JJYIH
+ {0xCC0C, 0xCC0C, prLV}, // Lo HANGUL SYLLABLE JJI
+ {0xCC0D, 0xCC27, prLVT}, // Lo [27] HANGUL SYLLABLE JJIG..HANGUL SYLLABLE JJIH
+ {0xCC28, 0xCC28, prLV}, // Lo HANGUL SYLLABLE CA
+ {0xCC29, 0xCC43, prLVT}, // Lo [27] HANGUL SYLLABLE CAG..HANGUL SYLLABLE CAH
+ {0xCC44, 0xCC44, prLV}, // Lo HANGUL SYLLABLE CAE
+ {0xCC45, 0xCC5F, prLVT}, // Lo [27] HANGUL SYLLABLE CAEG..HANGUL SYLLABLE CAEH
+ {0xCC60, 0xCC60, prLV}, // Lo HANGUL SYLLABLE CYA
+ {0xCC61, 0xCC7B, prLVT}, // Lo [27] HANGUL SYLLABLE CYAG..HANGUL SYLLABLE CYAH
+ {0xCC7C, 0xCC7C, prLV}, // Lo HANGUL SYLLABLE CYAE
+ {0xCC7D, 0xCC97, prLVT}, // Lo [27] HANGUL SYLLABLE CYAEG..HANGUL SYLLABLE CYAEH
+ {0xCC98, 0xCC98, prLV}, // Lo HANGUL SYLLABLE CEO
+ {0xCC99, 0xCCB3, prLVT}, // Lo [27] HANGUL SYLLABLE CEOG..HANGUL SYLLABLE CEOH
+ {0xCCB4, 0xCCB4, prLV}, // Lo HANGUL SYLLABLE CE
+ {0xCCB5, 0xCCCF, prLVT}, // Lo [27] HANGUL SYLLABLE CEG..HANGUL SYLLABLE CEH
+ {0xCCD0, 0xCCD0, prLV}, // Lo HANGUL SYLLABLE CYEO
+ {0xCCD1, 0xCCEB, prLVT}, // Lo [27] HANGUL SYLLABLE CYEOG..HANGUL SYLLABLE CYEOH
+ {0xCCEC, 0xCCEC, prLV}, // Lo HANGUL SYLLABLE CYE
+ {0xCCED, 0xCD07, prLVT}, // Lo [27] HANGUL SYLLABLE CYEG..HANGUL SYLLABLE CYEH
+ {0xCD08, 0xCD08, prLV}, // Lo HANGUL SYLLABLE CO
+ {0xCD09, 0xCD23, prLVT}, // Lo [27] HANGUL SYLLABLE COG..HANGUL SYLLABLE COH
+ {0xCD24, 0xCD24, prLV}, // Lo HANGUL SYLLABLE CWA
+ {0xCD25, 0xCD3F, prLVT}, // Lo [27] HANGUL SYLLABLE CWAG..HANGUL SYLLABLE CWAH
+ {0xCD40, 0xCD40, prLV}, // Lo HANGUL SYLLABLE CWAE
+ {0xCD41, 0xCD5B, prLVT}, // Lo [27] HANGUL SYLLABLE CWAEG..HANGUL SYLLABLE CWAEH
+ {0xCD5C, 0xCD5C, prLV}, // Lo HANGUL SYLLABLE COE
+ {0xCD5D, 0xCD77, prLVT}, // Lo [27] HANGUL SYLLABLE COEG..HANGUL SYLLABLE COEH
+ {0xCD78, 0xCD78, prLV}, // Lo HANGUL SYLLABLE CYO
+ {0xCD79, 0xCD93, prLVT}, // Lo [27] HANGUL SYLLABLE CYOG..HANGUL SYLLABLE CYOH
+ {0xCD94, 0xCD94, prLV}, // Lo HANGUL SYLLABLE CU
+ {0xCD95, 0xCDAF, prLVT}, // Lo [27] HANGUL SYLLABLE CUG..HANGUL SYLLABLE CUH
+ {0xCDB0, 0xCDB0, prLV}, // Lo HANGUL SYLLABLE CWEO
+ {0xCDB1, 0xCDCB, prLVT}, // Lo [27] HANGUL SYLLABLE CWEOG..HANGUL SYLLABLE CWEOH
+ {0xCDCC, 0xCDCC, prLV}, // Lo HANGUL SYLLABLE CWE
+ {0xCDCD, 0xCDE7, prLVT}, // Lo [27] HANGUL SYLLABLE CWEG..HANGUL SYLLABLE CWEH
+ {0xCDE8, 0xCDE8, prLV}, // Lo HANGUL SYLLABLE CWI
+ {0xCDE9, 0xCE03, prLVT}, // Lo [27] HANGUL SYLLABLE CWIG..HANGUL SYLLABLE CWIH
+ {0xCE04, 0xCE04, prLV}, // Lo HANGUL SYLLABLE CYU
+ {0xCE05, 0xCE1F, prLVT}, // Lo [27] HANGUL SYLLABLE CYUG..HANGUL SYLLABLE CYUH
+ {0xCE20, 0xCE20, prLV}, // Lo HANGUL SYLLABLE CEU
+ {0xCE21, 0xCE3B, prLVT}, // Lo [27] HANGUL SYLLABLE CEUG..HANGUL SYLLABLE CEUH
+ {0xCE3C, 0xCE3C, prLV}, // Lo HANGUL SYLLABLE CYI
+ {0xCE3D, 0xCE57, prLVT}, // Lo [27] HANGUL SYLLABLE CYIG..HANGUL SYLLABLE CYIH
+ {0xCE58, 0xCE58, prLV}, // Lo HANGUL SYLLABLE CI
+ {0xCE59, 0xCE73, prLVT}, // Lo [27] HANGUL SYLLABLE CIG..HANGUL SYLLABLE CIH
+ {0xCE74, 0xCE74, prLV}, // Lo HANGUL SYLLABLE KA
+ {0xCE75, 0xCE8F, prLVT}, // Lo [27] HANGUL SYLLABLE KAG..HANGUL SYLLABLE KAH
+ {0xCE90, 0xCE90, prLV}, // Lo HANGUL SYLLABLE KAE
+ {0xCE91, 0xCEAB, prLVT}, // Lo [27] HANGUL SYLLABLE KAEG..HANGUL SYLLABLE KAEH
+ {0xCEAC, 0xCEAC, prLV}, // Lo HANGUL SYLLABLE KYA
+ {0xCEAD, 0xCEC7, prLVT}, // Lo [27] HANGUL SYLLABLE KYAG..HANGUL SYLLABLE KYAH
+ {0xCEC8, 0xCEC8, prLV}, // Lo HANGUL SYLLABLE KYAE
+ {0xCEC9, 0xCEE3, prLVT}, // Lo [27] HANGUL SYLLABLE KYAEG..HANGUL SYLLABLE KYAEH
+ {0xCEE4, 0xCEE4, prLV}, // Lo HANGUL SYLLABLE KEO
+ {0xCEE5, 0xCEFF, prLVT}, // Lo [27] HANGUL SYLLABLE KEOG..HANGUL SYLLABLE KEOH
+ {0xCF00, 0xCF00, prLV}, // Lo HANGUL SYLLABLE KE
+ {0xCF01, 0xCF1B, prLVT}, // Lo [27] HANGUL SYLLABLE KEG..HANGUL SYLLABLE KEH
+ {0xCF1C, 0xCF1C, prLV}, // Lo HANGUL SYLLABLE KYEO
+ {0xCF1D, 0xCF37, prLVT}, // Lo [27] HANGUL SYLLABLE KYEOG..HANGUL SYLLABLE KYEOH
+ {0xCF38, 0xCF38, prLV}, // Lo HANGUL SYLLABLE KYE
+ {0xCF39, 0xCF53, prLVT}, // Lo [27] HANGUL SYLLABLE KYEG..HANGUL SYLLABLE KYEH
+ {0xCF54, 0xCF54, prLV}, // Lo HANGUL SYLLABLE KO
+ {0xCF55, 0xCF6F, prLVT}, // Lo [27] HANGUL SYLLABLE KOG..HANGUL SYLLABLE KOH
+ {0xCF70, 0xCF70, prLV}, // Lo HANGUL SYLLABLE KWA
+ {0xCF71, 0xCF8B, prLVT}, // Lo [27] HANGUL SYLLABLE KWAG..HANGUL SYLLABLE KWAH
+ {0xCF8C, 0xCF8C, prLV}, // Lo HANGUL SYLLABLE KWAE
+ {0xCF8D, 0xCFA7, prLVT}, // Lo [27] HANGUL SYLLABLE KWAEG..HANGUL SYLLABLE KWAEH
+ {0xCFA8, 0xCFA8, prLV}, // Lo HANGUL SYLLABLE KOE
+ {0xCFA9, 0xCFC3, prLVT}, // Lo [27] HANGUL SYLLABLE KOEG..HANGUL SYLLABLE KOEH
+ {0xCFC4, 0xCFC4, prLV}, // Lo HANGUL SYLLABLE KYO
+ {0xCFC5, 0xCFDF, prLVT}, // Lo [27] HANGUL SYLLABLE KYOG..HANGUL SYLLABLE KYOH
+ {0xCFE0, 0xCFE0, prLV}, // Lo HANGUL SYLLABLE KU
+ {0xCFE1, 0xCFFB, prLVT}, // Lo [27] HANGUL SYLLABLE KUG..HANGUL SYLLABLE KUH
+ {0xCFFC, 0xCFFC, prLV}, // Lo HANGUL SYLLABLE KWEO
+ {0xCFFD, 0xD017, prLVT}, // Lo [27] HANGUL SYLLABLE KWEOG..HANGUL SYLLABLE KWEOH
+ {0xD018, 0xD018, prLV}, // Lo HANGUL SYLLABLE KWE
+ {0xD019, 0xD033, prLVT}, // Lo [27] HANGUL SYLLABLE KWEG..HANGUL SYLLABLE KWEH
+ {0xD034, 0xD034, prLV}, // Lo HANGUL SYLLABLE KWI
+ {0xD035, 0xD04F, prLVT}, // Lo [27] HANGUL SYLLABLE KWIG..HANGUL SYLLABLE KWIH
+ {0xD050, 0xD050, prLV}, // Lo HANGUL SYLLABLE KYU
+ {0xD051, 0xD06B, prLVT}, // Lo [27] HANGUL SYLLABLE KYUG..HANGUL SYLLABLE KYUH
+ {0xD06C, 0xD06C, prLV}, // Lo HANGUL SYLLABLE KEU
+ {0xD06D, 0xD087, prLVT}, // Lo [27] HANGUL SYLLABLE KEUG..HANGUL SYLLABLE KEUH
+ {0xD088, 0xD088, prLV}, // Lo HANGUL SYLLABLE KYI
+ {0xD089, 0xD0A3, prLVT}, // Lo [27] HANGUL SYLLABLE KYIG..HANGUL SYLLABLE KYIH
+ {0xD0A4, 0xD0A4, prLV}, // Lo HANGUL SYLLABLE KI
+ {0xD0A5, 0xD0BF, prLVT}, // Lo [27] HANGUL SYLLABLE KIG..HANGUL SYLLABLE KIH
+ {0xD0C0, 0xD0C0, prLV}, // Lo HANGUL SYLLABLE TA
+ {0xD0C1, 0xD0DB, prLVT}, // Lo [27] HANGUL SYLLABLE TAG..HANGUL SYLLABLE TAH
+ {0xD0DC, 0xD0DC, prLV}, // Lo HANGUL SYLLABLE TAE
+ {0xD0DD, 0xD0F7, prLVT}, // Lo [27] HANGUL SYLLABLE TAEG..HANGUL SYLLABLE TAEH
+ {0xD0F8, 0xD0F8, prLV}, // Lo HANGUL SYLLABLE TYA
+ {0xD0F9, 0xD113, prLVT}, // Lo [27] HANGUL SYLLABLE TYAG..HANGUL SYLLABLE TYAH
+ {0xD114, 0xD114, prLV}, // Lo HANGUL SYLLABLE TYAE
+ {0xD115, 0xD12F, prLVT}, // Lo [27] HANGUL SYLLABLE TYAEG..HANGUL SYLLABLE TYAEH
+ {0xD130, 0xD130, prLV}, // Lo HANGUL SYLLABLE TEO
+ {0xD131, 0xD14B, prLVT}, // Lo [27] HANGUL SYLLABLE TEOG..HANGUL SYLLABLE TEOH
+ {0xD14C, 0xD14C, prLV}, // Lo HANGUL SYLLABLE TE
+ {0xD14D, 0xD167, prLVT}, // Lo [27] HANGUL SYLLABLE TEG..HANGUL SYLLABLE TEH
+ {0xD168, 0xD168, prLV}, // Lo HANGUL SYLLABLE TYEO
+ {0xD169, 0xD183, prLVT}, // Lo [27] HANGUL SYLLABLE TYEOG..HANGUL SYLLABLE TYEOH
+ {0xD184, 0xD184, prLV}, // Lo HANGUL SYLLABLE TYE
+ {0xD185, 0xD19F, prLVT}, // Lo [27] HANGUL SYLLABLE TYEG..HANGUL SYLLABLE TYEH
+ {0xD1A0, 0xD1A0, prLV}, // Lo HANGUL SYLLABLE TO
+ {0xD1A1, 0xD1BB, prLVT}, // Lo [27] HANGUL SYLLABLE TOG..HANGUL SYLLABLE TOH
+ {0xD1BC, 0xD1BC, prLV}, // Lo HANGUL SYLLABLE TWA
+ {0xD1BD, 0xD1D7, prLVT}, // Lo [27] HANGUL SYLLABLE TWAG..HANGUL SYLLABLE TWAH
+ {0xD1D8, 0xD1D8, prLV}, // Lo HANGUL SYLLABLE TWAE
+ {0xD1D9, 0xD1F3, prLVT}, // Lo [27] HANGUL SYLLABLE TWAEG..HANGUL SYLLABLE TWAEH
+ {0xD1F4, 0xD1F4, prLV}, // Lo HANGUL SYLLABLE TOE
+ {0xD1F5, 0xD20F, prLVT}, // Lo [27] HANGUL SYLLABLE TOEG..HANGUL SYLLABLE TOEH
+ {0xD210, 0xD210, prLV}, // Lo HANGUL SYLLABLE TYO
+ {0xD211, 0xD22B, prLVT}, // Lo [27] HANGUL SYLLABLE TYOG..HANGUL SYLLABLE TYOH
+ {0xD22C, 0xD22C, prLV}, // Lo HANGUL SYLLABLE TU
+ {0xD22D, 0xD247, prLVT}, // Lo [27] HANGUL SYLLABLE TUG..HANGUL SYLLABLE TUH
+ {0xD248, 0xD248, prLV}, // Lo HANGUL SYLLABLE TWEO
+ {0xD249, 0xD263, prLVT}, // Lo [27] HANGUL SYLLABLE TWEOG..HANGUL SYLLABLE TWEOH
+ {0xD264, 0xD264, prLV}, // Lo HANGUL SYLLABLE TWE
+ {0xD265, 0xD27F, prLVT}, // Lo [27] HANGUL SYLLABLE TWEG..HANGUL SYLLABLE TWEH
+ {0xD280, 0xD280, prLV}, // Lo HANGUL SYLLABLE TWI
+ {0xD281, 0xD29B, prLVT}, // Lo [27] HANGUL SYLLABLE TWIG..HANGUL SYLLABLE TWIH
+ {0xD29C, 0xD29C, prLV}, // Lo HANGUL SYLLABLE TYU
+ {0xD29D, 0xD2B7, prLVT}, // Lo [27] HANGUL SYLLABLE TYUG..HANGUL SYLLABLE TYUH
+ {0xD2B8, 0xD2B8, prLV}, // Lo HANGUL SYLLABLE TEU
+ {0xD2B9, 0xD2D3, prLVT}, // Lo [27] HANGUL SYLLABLE TEUG..HANGUL SYLLABLE TEUH
+ {0xD2D4, 0xD2D4, prLV}, // Lo HANGUL SYLLABLE TYI
+ {0xD2D5, 0xD2EF, prLVT}, // Lo [27] HANGUL SYLLABLE TYIG..HANGUL SYLLABLE TYIH
+ {0xD2F0, 0xD2F0, prLV}, // Lo HANGUL SYLLABLE TI
+ {0xD2F1, 0xD30B, prLVT}, // Lo [27] HANGUL SYLLABLE TIG..HANGUL SYLLABLE TIH
+ {0xD30C, 0xD30C, prLV}, // Lo HANGUL SYLLABLE PA
+ {0xD30D, 0xD327, prLVT}, // Lo [27] HANGUL SYLLABLE PAG..HANGUL SYLLABLE PAH
+ {0xD328, 0xD328, prLV}, // Lo HANGUL SYLLABLE PAE
+ {0xD329, 0xD343, prLVT}, // Lo [27] HANGUL SYLLABLE PAEG..HANGUL SYLLABLE PAEH
+ {0xD344, 0xD344, prLV}, // Lo HANGUL SYLLABLE PYA
+ {0xD345, 0xD35F, prLVT}, // Lo [27] HANGUL SYLLABLE PYAG..HANGUL SYLLABLE PYAH
+ {0xD360, 0xD360, prLV}, // Lo HANGUL SYLLABLE PYAE
+ {0xD361, 0xD37B, prLVT}, // Lo [27] HANGUL SYLLABLE PYAEG..HANGUL SYLLABLE PYAEH
+ {0xD37C, 0xD37C, prLV}, // Lo HANGUL SYLLABLE PEO
+ {0xD37D, 0xD397, prLVT}, // Lo [27] HANGUL SYLLABLE PEOG..HANGUL SYLLABLE PEOH
+ {0xD398, 0xD398, prLV}, // Lo HANGUL SYLLABLE PE
+ {0xD399, 0xD3B3, prLVT}, // Lo [27] HANGUL SYLLABLE PEG..HANGUL SYLLABLE PEH
+ {0xD3B4, 0xD3B4, prLV}, // Lo HANGUL SYLLABLE PYEO
+ {0xD3B5, 0xD3CF, prLVT}, // Lo [27] HANGUL SYLLABLE PYEOG..HANGUL SYLLABLE PYEOH
+ {0xD3D0, 0xD3D0, prLV}, // Lo HANGUL SYLLABLE PYE
+ {0xD3D1, 0xD3EB, prLVT}, // Lo [27] HANGUL SYLLABLE PYEG..HANGUL SYLLABLE PYEH
+ {0xD3EC, 0xD3EC, prLV}, // Lo HANGUL SYLLABLE PO
+ {0xD3ED, 0xD407, prLVT}, // Lo [27] HANGUL SYLLABLE POG..HANGUL SYLLABLE POH
+ {0xD408, 0xD408, prLV}, // Lo HANGUL SYLLABLE PWA
+ {0xD409, 0xD423, prLVT}, // Lo [27] HANGUL SYLLABLE PWAG..HANGUL SYLLABLE PWAH
+ {0xD424, 0xD424, prLV}, // Lo HANGUL SYLLABLE PWAE
+ {0xD425, 0xD43F, prLVT}, // Lo [27] HANGUL SYLLABLE PWAEG..HANGUL SYLLABLE PWAEH
+ {0xD440, 0xD440, prLV}, // Lo HANGUL SYLLABLE POE
+ {0xD441, 0xD45B, prLVT}, // Lo [27] HANGUL SYLLABLE POEG..HANGUL SYLLABLE POEH
+ {0xD45C, 0xD45C, prLV}, // Lo HANGUL SYLLABLE PYO
+ {0xD45D, 0xD477, prLVT}, // Lo [27] HANGUL SYLLABLE PYOG..HANGUL SYLLABLE PYOH
+ {0xD478, 0xD478, prLV}, // Lo HANGUL SYLLABLE PU
+ {0xD479, 0xD493, prLVT}, // Lo [27] HANGUL SYLLABLE PUG..HANGUL SYLLABLE PUH
+ {0xD494, 0xD494, prLV}, // Lo HANGUL SYLLABLE PWEO
+ {0xD495, 0xD4AF, prLVT}, // Lo [27] HANGUL SYLLABLE PWEOG..HANGUL SYLLABLE PWEOH
+ {0xD4B0, 0xD4B0, prLV}, // Lo HANGUL SYLLABLE PWE
+ {0xD4B1, 0xD4CB, prLVT}, // Lo [27] HANGUL SYLLABLE PWEG..HANGUL SYLLABLE PWEH
+ {0xD4CC, 0xD4CC, prLV}, // Lo HANGUL SYLLABLE PWI
+ {0xD4CD, 0xD4E7, prLVT}, // Lo [27] HANGUL SYLLABLE PWIG..HANGUL SYLLABLE PWIH
+ {0xD4E8, 0xD4E8, prLV}, // Lo HANGUL SYLLABLE PYU
+ {0xD4E9, 0xD503, prLVT}, // Lo [27] HANGUL SYLLABLE PYUG..HANGUL SYLLABLE PYUH
+ {0xD504, 0xD504, prLV}, // Lo HANGUL SYLLABLE PEU
+ {0xD505, 0xD51F, prLVT}, // Lo [27] HANGUL SYLLABLE PEUG..HANGUL SYLLABLE PEUH
+ {0xD520, 0xD520, prLV}, // Lo HANGUL SYLLABLE PYI
+ {0xD521, 0xD53B, prLVT}, // Lo [27] HANGUL SYLLABLE PYIG..HANGUL SYLLABLE PYIH
+ {0xD53C, 0xD53C, prLV}, // Lo HANGUL SYLLABLE PI
+ {0xD53D, 0xD557, prLVT}, // Lo [27] HANGUL SYLLABLE PIG..HANGUL SYLLABLE PIH
+ {0xD558, 0xD558, prLV}, // Lo HANGUL SYLLABLE HA
+ {0xD559, 0xD573, prLVT}, // Lo [27] HANGUL SYLLABLE HAG..HANGUL SYLLABLE HAH
+ {0xD574, 0xD574, prLV}, // Lo HANGUL SYLLABLE HAE
+ {0xD575, 0xD58F, prLVT}, // Lo [27] HANGUL SYLLABLE HAEG..HANGUL SYLLABLE HAEH
+ {0xD590, 0xD590, prLV}, // Lo HANGUL SYLLABLE HYA
+ {0xD591, 0xD5AB, prLVT}, // Lo [27] HANGUL SYLLABLE HYAG..HANGUL SYLLABLE HYAH
+ {0xD5AC, 0xD5AC, prLV}, // Lo HANGUL SYLLABLE HYAE
+ {0xD5AD, 0xD5C7, prLVT}, // Lo [27] HANGUL SYLLABLE HYAEG..HANGUL SYLLABLE HYAEH
+ {0xD5C8, 0xD5C8, prLV}, // Lo HANGUL SYLLABLE HEO
+ {0xD5C9, 0xD5E3, prLVT}, // Lo [27] HANGUL SYLLABLE HEOG..HANGUL SYLLABLE HEOH
+ {0xD5E4, 0xD5E4, prLV}, // Lo HANGUL SYLLABLE HE
+ {0xD5E5, 0xD5FF, prLVT}, // Lo [27] HANGUL SYLLABLE HEG..HANGUL SYLLABLE HEH
+ {0xD600, 0xD600, prLV}, // Lo HANGUL SYLLABLE HYEO
+ {0xD601, 0xD61B, prLVT}, // Lo [27] HANGUL SYLLABLE HYEOG..HANGUL SYLLABLE HYEOH
+ {0xD61C, 0xD61C, prLV}, // Lo HANGUL SYLLABLE HYE
+ {0xD61D, 0xD637, prLVT}, // Lo [27] HANGUL SYLLABLE HYEG..HANGUL SYLLABLE HYEH
+ {0xD638, 0xD638, prLV}, // Lo HANGUL SYLLABLE HO
+ {0xD639, 0xD653, prLVT}, // Lo [27] HANGUL SYLLABLE HOG..HANGUL SYLLABLE HOH
+ {0xD654, 0xD654, prLV}, // Lo HANGUL SYLLABLE HWA
+ {0xD655, 0xD66F, prLVT}, // Lo [27] HANGUL SYLLABLE HWAG..HANGUL SYLLABLE HWAH
+ {0xD670, 0xD670, prLV}, // Lo HANGUL SYLLABLE HWAE
+ {0xD671, 0xD68B, prLVT}, // Lo [27] HANGUL SYLLABLE HWAEG..HANGUL SYLLABLE HWAEH
+ {0xD68C, 0xD68C, prLV}, // Lo HANGUL SYLLABLE HOE
+ {0xD68D, 0xD6A7, prLVT}, // Lo [27] HANGUL SYLLABLE HOEG..HANGUL SYLLABLE HOEH
+ {0xD6A8, 0xD6A8, prLV}, // Lo HANGUL SYLLABLE HYO
+ {0xD6A9, 0xD6C3, prLVT}, // Lo [27] HANGUL SYLLABLE HYOG..HANGUL SYLLABLE HYOH
+ {0xD6C4, 0xD6C4, prLV}, // Lo HANGUL SYLLABLE HU
+ {0xD6C5, 0xD6DF, prLVT}, // Lo [27] HANGUL SYLLABLE HUG..HANGUL SYLLABLE HUH
+ {0xD6E0, 0xD6E0, prLV}, // Lo HANGUL SYLLABLE HWEO
+ {0xD6E1, 0xD6FB, prLVT}, // Lo [27] HANGUL SYLLABLE HWEOG..HANGUL SYLLABLE HWEOH
+ {0xD6FC, 0xD6FC, prLV}, // Lo HANGUL SYLLABLE HWE
+ {0xD6FD, 0xD717, prLVT}, // Lo [27] HANGUL SYLLABLE HWEG..HANGUL SYLLABLE HWEH
+ {0xD718, 0xD718, prLV}, // Lo HANGUL SYLLABLE HWI
+ {0xD719, 0xD733, prLVT}, // Lo [27] HANGUL SYLLABLE HWIG..HANGUL SYLLABLE HWIH
+ {0xD734, 0xD734, prLV}, // Lo HANGUL SYLLABLE HYU
+ {0xD735, 0xD74F, prLVT}, // Lo [27] HANGUL SYLLABLE HYUG..HANGUL SYLLABLE HYUH
+ {0xD750, 0xD750, prLV}, // Lo HANGUL SYLLABLE HEU
+ {0xD751, 0xD76B, prLVT}, // Lo [27] HANGUL SYLLABLE HEUG..HANGUL SYLLABLE HEUH
+ {0xD76C, 0xD76C, prLV}, // Lo HANGUL SYLLABLE HYI
+ {0xD76D, 0xD787, prLVT}, // Lo [27] HANGUL SYLLABLE HYIG..HANGUL SYLLABLE HYIH
+ {0xD788, 0xD788, prLV}, // Lo HANGUL SYLLABLE HI
+ {0xD789, 0xD7A3, prLVT}, // Lo [27] HANGUL SYLLABLE HIG..HANGUL SYLLABLE HIH
+ {0xD7B0, 0xD7C6, prV}, // Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E
+ {0xD7CB, 0xD7FB, prT}, // Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH
+ {0xFB1E, 0xFB1E, prExtend}, // Mn HEBREW POINT JUDEO-SPANISH VARIKA
+ {0xFE00, 0xFE0F, prExtend}, // Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+ {0xFE20, 0xFE2F, prExtend}, // Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF
+ {0xFEFF, 0xFEFF, prControl}, // Cf ZERO WIDTH NO-BREAK SPACE
+ {0xFF9E, 0xFF9F, prExtend}, // Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+ {0xFFF0, 0xFFF8, prControl}, // Cn [9] ..
+ {0xFFF9, 0xFFFB, prControl}, // Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR
+ {0x101FD, 0x101FD, prExtend}, // Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
+ {0x102E0, 0x102E0, prExtend}, // Mn COPTIC EPACT THOUSANDS MARK
+ {0x10376, 0x1037A, prExtend}, // Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII
+ {0x10A01, 0x10A03, prExtend}, // Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
+ {0x10A05, 0x10A06, prExtend}, // Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
+ {0x10A0C, 0x10A0F, prExtend}, // Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
+ {0x10A38, 0x10A3A, prExtend}, // Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
+ {0x10A3F, 0x10A3F, prExtend}, // Mn KHAROSHTHI VIRAMA
+ {0x10AE5, 0x10AE6, prExtend}, // Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
+ {0x10D24, 0x10D27, prExtend}, // Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
+ {0x10EAB, 0x10EAC, prExtend}, // Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK
+ {0x10EFD, 0x10EFF, prExtend}, // Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA
+ {0x10F46, 0x10F50, prExtend}, // Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW
+ {0x10F82, 0x10F85, prExtend}, // Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW
+ {0x11000, 0x11000, prSpacingMark}, // Mc BRAHMI SIGN CANDRABINDU
+ {0x11001, 0x11001, prExtend}, // Mn BRAHMI SIGN ANUSVARA
+ {0x11002, 0x11002, prSpacingMark}, // Mc BRAHMI SIGN VISARGA
+ {0x11038, 0x11046, prExtend}, // Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA
+ {0x11070, 0x11070, prExtend}, // Mn BRAHMI SIGN OLD TAMIL VIRAMA
+ {0x11073, 0x11074, prExtend}, // Mn [2] BRAHMI VOWEL SIGN OLD TAMIL SHORT E..BRAHMI VOWEL SIGN OLD TAMIL SHORT O
+ {0x1107F, 0x11081, prExtend}, // Mn [3] BRAHMI NUMBER JOINER..KAITHI SIGN ANUSVARA
+ {0x11082, 0x11082, prSpacingMark}, // Mc KAITHI SIGN VISARGA
+ {0x110B0, 0x110B2, prSpacingMark}, // Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II
+ {0x110B3, 0x110B6, prExtend}, // Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI
+ {0x110B7, 0x110B8, prSpacingMark}, // Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU
+ {0x110B9, 0x110BA, prExtend}, // Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA
+ {0x110BD, 0x110BD, prPrepend}, // Cf KAITHI NUMBER SIGN
+ {0x110C2, 0x110C2, prExtend}, // Mn KAITHI VOWEL SIGN VOCALIC R
+ {0x110CD, 0x110CD, prPrepend}, // Cf KAITHI NUMBER SIGN ABOVE
+ {0x11100, 0x11102, prExtend}, // Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA
+ {0x11127, 0x1112B, prExtend}, // Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU
+ {0x1112C, 0x1112C, prSpacingMark}, // Mc CHAKMA VOWEL SIGN E
+ {0x1112D, 0x11134, prExtend}, // Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA
+ {0x11145, 0x11146, prSpacingMark}, // Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI
+ {0x11173, 0x11173, prExtend}, // Mn MAHAJANI SIGN NUKTA
+ {0x11180, 0x11181, prExtend}, // Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA
+ {0x11182, 0x11182, prSpacingMark}, // Mc SHARADA SIGN VISARGA
+ {0x111B3, 0x111B5, prSpacingMark}, // Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II
+ {0x111B6, 0x111BE, prExtend}, // Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O
+ {0x111BF, 0x111C0, prSpacingMark}, // Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA
+ {0x111C2, 0x111C3, prPrepend}, // Lo [2] SHARADA SIGN JIHVAMULIYA..SHARADA SIGN UPADHMANIYA
+ {0x111C9, 0x111CC, prExtend}, // Mn [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK
+ {0x111CE, 0x111CE, prSpacingMark}, // Mc SHARADA VOWEL SIGN PRISHTHAMATRA E
+ {0x111CF, 0x111CF, prExtend}, // Mn SHARADA SIGN INVERTED CANDRABINDU
+ {0x1122C, 0x1122E, prSpacingMark}, // Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II
+ {0x1122F, 0x11231, prExtend}, // Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI
+ {0x11232, 0x11233, prSpacingMark}, // Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU
+ {0x11234, 0x11234, prExtend}, // Mn KHOJKI SIGN ANUSVARA
+ {0x11235, 0x11235, prSpacingMark}, // Mc KHOJKI SIGN VIRAMA
+ {0x11236, 0x11237, prExtend}, // Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA
+ {0x1123E, 0x1123E, prExtend}, // Mn KHOJKI SIGN SUKUN
+ {0x11241, 0x11241, prExtend}, // Mn KHOJKI VOWEL SIGN VOCALIC R
+ {0x112DF, 0x112DF, prExtend}, // Mn KHUDAWADI SIGN ANUSVARA
+ {0x112E0, 0x112E2, prSpacingMark}, // Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II
+ {0x112E3, 0x112EA, prExtend}, // Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA
+ {0x11300, 0x11301, prExtend}, // Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU
+ {0x11302, 0x11303, prSpacingMark}, // Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA
+ {0x1133B, 0x1133C, prExtend}, // Mn [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA
+ {0x1133E, 0x1133E, prExtend}, // Mc GRANTHA VOWEL SIGN AA
+ {0x1133F, 0x1133F, prSpacingMark}, // Mc GRANTHA VOWEL SIGN I
+ {0x11340, 0x11340, prExtend}, // Mn GRANTHA VOWEL SIGN II
+ {0x11341, 0x11344, prSpacingMark}, // Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR
+ {0x11347, 0x11348, prSpacingMark}, // Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI
+ {0x1134B, 0x1134D, prSpacingMark}, // Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA
+ {0x11357, 0x11357, prExtend}, // Mc GRANTHA AU LENGTH MARK
+ {0x11362, 0x11363, prSpacingMark}, // Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL
+ {0x11366, 0x1136C, prExtend}, // Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX
+ {0x11370, 0x11374, prExtend}, // Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA
+ {0x11435, 0x11437, prSpacingMark}, // Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II
+ {0x11438, 0x1143F, prExtend}, // Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI
+ {0x11440, 0x11441, prSpacingMark}, // Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU
+ {0x11442, 0x11444, prExtend}, // Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA
+ {0x11445, 0x11445, prSpacingMark}, // Mc NEWA SIGN VISARGA
+ {0x11446, 0x11446, prExtend}, // Mn NEWA SIGN NUKTA
+ {0x1145E, 0x1145E, prExtend}, // Mn NEWA SANDHI MARK
+ {0x114B0, 0x114B0, prExtend}, // Mc TIRHUTA VOWEL SIGN AA
+ {0x114B1, 0x114B2, prSpacingMark}, // Mc [2] TIRHUTA VOWEL SIGN I..TIRHUTA VOWEL SIGN II
+ {0x114B3, 0x114B8, prExtend}, // Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL
+ {0x114B9, 0x114B9, prSpacingMark}, // Mc TIRHUTA VOWEL SIGN E
+ {0x114BA, 0x114BA, prExtend}, // Mn TIRHUTA VOWEL SIGN SHORT E
+ {0x114BB, 0x114BC, prSpacingMark}, // Mc [2] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN O
+ {0x114BD, 0x114BD, prExtend}, // Mc TIRHUTA VOWEL SIGN SHORT O
+ {0x114BE, 0x114BE, prSpacingMark}, // Mc TIRHUTA VOWEL SIGN AU
+ {0x114BF, 0x114C0, prExtend}, // Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA
+ {0x114C1, 0x114C1, prSpacingMark}, // Mc TIRHUTA SIGN VISARGA
+ {0x114C2, 0x114C3, prExtend}, // Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA
+ {0x115AF, 0x115AF, prExtend}, // Mc SIDDHAM VOWEL SIGN AA
+ {0x115B0, 0x115B1, prSpacingMark}, // Mc [2] SIDDHAM VOWEL SIGN I..SIDDHAM VOWEL SIGN II
+ {0x115B2, 0x115B5, prExtend}, // Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR
+ {0x115B8, 0x115BB, prSpacingMark}, // Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU
+ {0x115BC, 0x115BD, prExtend}, // Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA
+ {0x115BE, 0x115BE, prSpacingMark}, // Mc SIDDHAM SIGN VISARGA
+ {0x115BF, 0x115C0, prExtend}, // Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA
+ {0x115DC, 0x115DD, prExtend}, // Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU
+ {0x11630, 0x11632, prSpacingMark}, // Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II
+ {0x11633, 0x1163A, prExtend}, // Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI
+ {0x1163B, 0x1163C, prSpacingMark}, // Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU
+ {0x1163D, 0x1163D, prExtend}, // Mn MODI SIGN ANUSVARA
+ {0x1163E, 0x1163E, prSpacingMark}, // Mc MODI SIGN VISARGA
+ {0x1163F, 0x11640, prExtend}, // Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA
+ {0x116AB, 0x116AB, prExtend}, // Mn TAKRI SIGN ANUSVARA
+ {0x116AC, 0x116AC, prSpacingMark}, // Mc TAKRI SIGN VISARGA
+ {0x116AD, 0x116AD, prExtend}, // Mn TAKRI VOWEL SIGN AA
+ {0x116AE, 0x116AF, prSpacingMark}, // Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II
+ {0x116B0, 0x116B5, prExtend}, // Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU
+ {0x116B6, 0x116B6, prSpacingMark}, // Mc TAKRI SIGN VIRAMA
+ {0x116B7, 0x116B7, prExtend}, // Mn TAKRI SIGN NUKTA
+ {0x1171D, 0x1171F, prExtend}, // Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA
+ {0x11722, 0x11725, prExtend}, // Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU
+ {0x11726, 0x11726, prSpacingMark}, // Mc AHOM VOWEL SIGN E
+ {0x11727, 0x1172B, prExtend}, // Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER
+ {0x1182C, 0x1182E, prSpacingMark}, // Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II
+ {0x1182F, 0x11837, prExtend}, // Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA
+ {0x11838, 0x11838, prSpacingMark}, // Mc DOGRA SIGN VISARGA
+ {0x11839, 0x1183A, prExtend}, // Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA
+ {0x11930, 0x11930, prExtend}, // Mc DIVES AKURU VOWEL SIGN AA
+ {0x11931, 0x11935, prSpacingMark}, // Mc [5] DIVES AKURU VOWEL SIGN I..DIVES AKURU VOWEL SIGN E
+ {0x11937, 0x11938, prSpacingMark}, // Mc [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O
+ {0x1193B, 0x1193C, prExtend}, // Mn [2] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN CANDRABINDU
+ {0x1193D, 0x1193D, prSpacingMark}, // Mc DIVES AKURU SIGN HALANTA
+ {0x1193E, 0x1193E, prExtend}, // Mn DIVES AKURU VIRAMA
+ {0x1193F, 0x1193F, prPrepend}, // Lo DIVES AKURU PREFIXED NASAL SIGN
+ {0x11940, 0x11940, prSpacingMark}, // Mc DIVES AKURU MEDIAL YA
+ {0x11941, 0x11941, prPrepend}, // Lo DIVES AKURU INITIAL RA
+ {0x11942, 0x11942, prSpacingMark}, // Mc DIVES AKURU MEDIAL RA
+ {0x11943, 0x11943, prExtend}, // Mn DIVES AKURU SIGN NUKTA
+ {0x119D1, 0x119D3, prSpacingMark}, // Mc [3] NANDINAGARI VOWEL SIGN AA..NANDINAGARI VOWEL SIGN II
+ {0x119D4, 0x119D7, prExtend}, // Mn [4] NANDINAGARI VOWEL SIGN U..NANDINAGARI VOWEL SIGN VOCALIC RR
+ {0x119DA, 0x119DB, prExtend}, // Mn [2] NANDINAGARI VOWEL SIGN E..NANDINAGARI VOWEL SIGN AI
+ {0x119DC, 0x119DF, prSpacingMark}, // Mc [4] NANDINAGARI VOWEL SIGN O..NANDINAGARI SIGN VISARGA
+ {0x119E0, 0x119E0, prExtend}, // Mn NANDINAGARI SIGN VIRAMA
+ {0x119E4, 0x119E4, prSpacingMark}, // Mc NANDINAGARI VOWEL SIGN PRISHTHAMATRA E
+ {0x11A01, 0x11A0A, prExtend}, // Mn [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK
+ {0x11A33, 0x11A38, prExtend}, // Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA
+ {0x11A39, 0x11A39, prSpacingMark}, // Mc ZANABAZAR SQUARE SIGN VISARGA
+ {0x11A3A, 0x11A3A, prPrepend}, // Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA
+ {0x11A3B, 0x11A3E, prExtend}, // Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA
+ {0x11A47, 0x11A47, prExtend}, // Mn ZANABAZAR SQUARE SUBJOINER
+ {0x11A51, 0x11A56, prExtend}, // Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE
+ {0x11A57, 0x11A58, prSpacingMark}, // Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU
+ {0x11A59, 0x11A5B, prExtend}, // Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK
+ {0x11A84, 0x11A89, prPrepend}, // Lo [6] SOYOMBO SIGN JIHVAMULIYA..SOYOMBO CLUSTER-INITIAL LETTER SA
+ {0x11A8A, 0x11A96, prExtend}, // Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA
+ {0x11A97, 0x11A97, prSpacingMark}, // Mc SOYOMBO SIGN VISARGA
+ {0x11A98, 0x11A99, prExtend}, // Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER
+ {0x11C2F, 0x11C2F, prSpacingMark}, // Mc BHAIKSUKI VOWEL SIGN AA
+ {0x11C30, 0x11C36, prExtend}, // Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L
+ {0x11C38, 0x11C3D, prExtend}, // Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA
+ {0x11C3E, 0x11C3E, prSpacingMark}, // Mc BHAIKSUKI SIGN VISARGA
+ {0x11C3F, 0x11C3F, prExtend}, // Mn BHAIKSUKI SIGN VIRAMA
+ {0x11C92, 0x11CA7, prExtend}, // Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA
+ {0x11CA9, 0x11CA9, prSpacingMark}, // Mc MARCHEN SUBJOINED LETTER YA
+ {0x11CAA, 0x11CB0, prExtend}, // Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA
+ {0x11CB1, 0x11CB1, prSpacingMark}, // Mc MARCHEN VOWEL SIGN I
+ {0x11CB2, 0x11CB3, prExtend}, // Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E
+ {0x11CB4, 0x11CB4, prSpacingMark}, // Mc MARCHEN VOWEL SIGN O
+ {0x11CB5, 0x11CB6, prExtend}, // Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU
+ {0x11D31, 0x11D36, prExtend}, // Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R
+ {0x11D3A, 0x11D3A, prExtend}, // Mn MASARAM GONDI VOWEL SIGN E
+ {0x11D3C, 0x11D3D, prExtend}, // Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O
+ {0x11D3F, 0x11D45, prExtend}, // Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA
+ {0x11D46, 0x11D46, prPrepend}, // Lo MASARAM GONDI REPHA
+ {0x11D47, 0x11D47, prExtend}, // Mn MASARAM GONDI RA-KARA
+ {0x11D8A, 0x11D8E, prSpacingMark}, // Mc [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU
+ {0x11D90, 0x11D91, prExtend}, // Mn [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI
+ {0x11D93, 0x11D94, prSpacingMark}, // Mc [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU
+ {0x11D95, 0x11D95, prExtend}, // Mn GUNJALA GONDI SIGN ANUSVARA
+ {0x11D96, 0x11D96, prSpacingMark}, // Mc GUNJALA GONDI SIGN VISARGA
+ {0x11D97, 0x11D97, prExtend}, // Mn GUNJALA GONDI VIRAMA
+ {0x11EF3, 0x11EF4, prExtend}, // Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U
+ {0x11EF5, 0x11EF6, prSpacingMark}, // Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O
+ {0x11F00, 0x11F01, prExtend}, // Mn [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA
+ {0x11F02, 0x11F02, prPrepend}, // Lo KAWI SIGN REPHA
+ {0x11F03, 0x11F03, prSpacingMark}, // Mc KAWI SIGN VISARGA
+ {0x11F34, 0x11F35, prSpacingMark}, // Mc [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA
+ {0x11F36, 0x11F3A, prExtend}, // Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R
+ {0x11F3E, 0x11F3F, prSpacingMark}, // Mc [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI
+ {0x11F40, 0x11F40, prExtend}, // Mn KAWI VOWEL SIGN EU
+ {0x11F41, 0x11F41, prSpacingMark}, // Mc KAWI SIGN KILLER
+ {0x11F42, 0x11F42, prExtend}, // Mn KAWI CONJOINER
+ {0x13430, 0x1343F, prControl}, // Cf [16] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE
+ {0x13440, 0x13440, prExtend}, // Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY
+ {0x13447, 0x13455, prExtend}, // Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED
+ {0x16AF0, 0x16AF4, prExtend}, // Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
+ {0x16B30, 0x16B36, prExtend}, // Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
+ {0x16F4F, 0x16F4F, prExtend}, // Mn MIAO SIGN CONSONANT MODIFIER BAR
+ {0x16F51, 0x16F87, prSpacingMark}, // Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI
+ {0x16F8F, 0x16F92, prExtend}, // Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
+ {0x16FE4, 0x16FE4, prExtend}, // Mn KHITAN SMALL SCRIPT FILLER
+ {0x16FF0, 0x16FF1, prSpacingMark}, // Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY
+ {0x1BC9D, 0x1BC9E, prExtend}, // Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK
+ {0x1BCA0, 0x1BCA3, prControl}, // Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
+ {0x1CF00, 0x1CF2D, prExtend}, // Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT
+ {0x1CF30, 0x1CF46, prExtend}, // Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG
+ {0x1D165, 0x1D165, prExtend}, // Mc MUSICAL SYMBOL COMBINING STEM
+ {0x1D166, 0x1D166, prSpacingMark}, // Mc MUSICAL SYMBOL COMBINING SPRECHGESANG STEM
+ {0x1D167, 0x1D169, prExtend}, // Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3
+ {0x1D16D, 0x1D16D, prSpacingMark}, // Mc MUSICAL SYMBOL COMBINING AUGMENTATION DOT
+ {0x1D16E, 0x1D172, prExtend}, // Mc [5] MUSICAL SYMBOL COMBINING FLAG-1..MUSICAL SYMBOL COMBINING FLAG-5
+ {0x1D173, 0x1D17A, prControl}, // Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
+ {0x1D17B, 0x1D182, prExtend}, // Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE
+ {0x1D185, 0x1D18B, prExtend}, // Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
+ {0x1D1AA, 0x1D1AD, prExtend}, // Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
+ {0x1D242, 0x1D244, prExtend}, // Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME
+ {0x1DA00, 0x1DA36, prExtend}, // Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN
+ {0x1DA3B, 0x1DA6C, prExtend}, // Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT
+ {0x1DA75, 0x1DA75, prExtend}, // Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS
+ {0x1DA84, 0x1DA84, prExtend}, // Mn SIGNWRITING LOCATION HEAD NECK
+ {0x1DA9B, 0x1DA9F, prExtend}, // Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6
+ {0x1DAA1, 0x1DAAF, prExtend}, // Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16
+ {0x1E000, 0x1E006, prExtend}, // Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE
+ {0x1E008, 0x1E018, prExtend}, // Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU
+ {0x1E01B, 0x1E021, prExtend}, // Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI
+ {0x1E023, 0x1E024, prExtend}, // Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS
+ {0x1E026, 0x1E02A, prExtend}, // Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA
+ {0x1E08F, 0x1E08F, prExtend}, // Mn COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+ {0x1E130, 0x1E136, prExtend}, // Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D
+ {0x1E2AE, 0x1E2AE, prExtend}, // Mn TOTO SIGN RISING TONE
+ {0x1E2EC, 0x1E2EF, prExtend}, // Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI
+ {0x1E4EC, 0x1E4EF, prExtend}, // Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH
+ {0x1E8D0, 0x1E8D6, prExtend}, // Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS
+ {0x1E944, 0x1E94A, prExtend}, // Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA
+ {0x1F000, 0x1F003, prExtendedPictographic}, // E0.0 [4] (🀀..🀃) MAHJONG TILE EAST WIND..MAHJONG TILE NORTH WIND
+ {0x1F004, 0x1F004, prExtendedPictographic}, // E0.6 [1] (🀄) mahjong red dragon
+ {0x1F005, 0x1F0CE, prExtendedPictographic}, // E0.0 [202] (🀅..🃎) MAHJONG TILE GREEN DRAGON..PLAYING CARD KING OF DIAMONDS
+ {0x1F0CF, 0x1F0CF, prExtendedPictographic}, // E0.6 [1] (🃏) joker
+ {0x1F0D0, 0x1F0FF, prExtendedPictographic}, // E0.0 [48] (..) ..
+ {0x1F10D, 0x1F10F, prExtendedPictographic}, // E0.0 [3] (🄍..🄏) CIRCLED ZERO WITH SLASH..CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH
+ {0x1F12F, 0x1F12F, prExtendedPictographic}, // E0.0 [1] (🄯) COPYLEFT SYMBOL
+ {0x1F16C, 0x1F16F, prExtendedPictographic}, // E0.0 [4] (🅬..🅯) RAISED MR SIGN..CIRCLED HUMAN FIGURE
+ {0x1F170, 0x1F171, prExtendedPictographic}, // E0.6 [2] (🅰️..🅱️) A button (blood type)..B button (blood type)
+ {0x1F17E, 0x1F17F, prExtendedPictographic}, // E0.6 [2] (🅾️..🅿️) O button (blood type)..P button
+ {0x1F18E, 0x1F18E, prExtendedPictographic}, // E0.6 [1] (🆎) AB button (blood type)
+ {0x1F191, 0x1F19A, prExtendedPictographic}, // E0.6 [10] (🆑..🆚) CL button..VS button
+ {0x1F1AD, 0x1F1E5, prExtendedPictographic}, // E0.0 [57] (🆭..) MASK WORK SYMBOL..
+ {0x1F1E6, 0x1F1FF, prRegionalIndicator}, // So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z
+ {0x1F201, 0x1F202, prExtendedPictographic}, // E0.6 [2] (🈁..🈂️) Japanese “here” button..Japanese “service charge” button
+ {0x1F203, 0x1F20F, prExtendedPictographic}, // E0.0 [13] (..) ..
+ {0x1F21A, 0x1F21A, prExtendedPictographic}, // E0.6 [1] (🈚) Japanese “free of charge” button
+ {0x1F22F, 0x1F22F, prExtendedPictographic}, // E0.6 [1] (🈯) Japanese “reserved” button
+ {0x1F232, 0x1F23A, prExtendedPictographic}, // E0.6 [9] (🈲..🈺) Japanese “prohibited” button..Japanese “open for business” button
+ {0x1F23C, 0x1F23F, prExtendedPictographic}, // E0.0 [4] (..) ..
+ {0x1F249, 0x1F24F, prExtendedPictographic}, // E0.0 [7] (..) ..
+ {0x1F250, 0x1F251, prExtendedPictographic}, // E0.6 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button
+ {0x1F252, 0x1F2FF, prExtendedPictographic}, // E0.0 [174] (..) ..
+ {0x1F300, 0x1F30C, prExtendedPictographic}, // E0.6 [13] (🌀..🌌) cyclone..milky way
+ {0x1F30D, 0x1F30E, prExtendedPictographic}, // E0.7 [2] (🌍..🌎) globe showing Europe-Africa..globe showing Americas
+ {0x1F30F, 0x1F30F, prExtendedPictographic}, // E0.6 [1] (🌏) globe showing Asia-Australia
+ {0x1F310, 0x1F310, prExtendedPictographic}, // E1.0 [1] (🌐) globe with meridians
+ {0x1F311, 0x1F311, prExtendedPictographic}, // E0.6 [1] (🌑) new moon
+ {0x1F312, 0x1F312, prExtendedPictographic}, // E1.0 [1] (🌒) waxing crescent moon
+ {0x1F313, 0x1F315, prExtendedPictographic}, // E0.6 [3] (🌓..🌕) first quarter moon..full moon
+ {0x1F316, 0x1F318, prExtendedPictographic}, // E1.0 [3] (🌖..🌘) waning gibbous moon..waning crescent moon
+ {0x1F319, 0x1F319, prExtendedPictographic}, // E0.6 [1] (🌙) crescent moon
+ {0x1F31A, 0x1F31A, prExtendedPictographic}, // E1.0 [1] (🌚) new moon face
+ {0x1F31B, 0x1F31B, prExtendedPictographic}, // E0.6 [1] (🌛) first quarter moon face
+ {0x1F31C, 0x1F31C, prExtendedPictographic}, // E0.7 [1] (🌜) last quarter moon face
+ {0x1F31D, 0x1F31E, prExtendedPictographic}, // E1.0 [2] (🌝..🌞) full moon face..sun with face
+ {0x1F31F, 0x1F320, prExtendedPictographic}, // E0.6 [2] (🌟..🌠) glowing star..shooting star
+ {0x1F321, 0x1F321, prExtendedPictographic}, // E0.7 [1] (🌡️) thermometer
+ {0x1F322, 0x1F323, prExtendedPictographic}, // E0.0 [2] (🌢..🌣) BLACK DROPLET..WHITE SUN
+ {0x1F324, 0x1F32C, prExtendedPictographic}, // E0.7 [9] (🌤️..🌬️) sun behind small cloud..wind face
+ {0x1F32D, 0x1F32F, prExtendedPictographic}, // E1.0 [3] (🌭..🌯) hot dog..burrito
+ {0x1F330, 0x1F331, prExtendedPictographic}, // E0.6 [2] (🌰..🌱) chestnut..seedling
+ {0x1F332, 0x1F333, prExtendedPictographic}, // E1.0 [2] (🌲..🌳) evergreen tree..deciduous tree
+ {0x1F334, 0x1F335, prExtendedPictographic}, // E0.6 [2] (🌴..🌵) palm tree..cactus
+ {0x1F336, 0x1F336, prExtendedPictographic}, // E0.7 [1] (🌶️) hot pepper
+ {0x1F337, 0x1F34A, prExtendedPictographic}, // E0.6 [20] (🌷..🍊) tulip..tangerine
+ {0x1F34B, 0x1F34B, prExtendedPictographic}, // E1.0 [1] (🍋) lemon
+ {0x1F34C, 0x1F34F, prExtendedPictographic}, // E0.6 [4] (🍌..🍏) banana..green apple
+ {0x1F350, 0x1F350, prExtendedPictographic}, // E1.0 [1] (🍐) pear
+ {0x1F351, 0x1F37B, prExtendedPictographic}, // E0.6 [43] (🍑..🍻) peach..clinking beer mugs
+ {0x1F37C, 0x1F37C, prExtendedPictographic}, // E1.0 [1] (🍼) baby bottle
+ {0x1F37D, 0x1F37D, prExtendedPictographic}, // E0.7 [1] (🍽️) fork and knife with plate
+ {0x1F37E, 0x1F37F, prExtendedPictographic}, // E1.0 [2] (🍾..🍿) bottle with popping cork..popcorn
+ {0x1F380, 0x1F393, prExtendedPictographic}, // E0.6 [20] (🎀..🎓) ribbon..graduation cap
+ {0x1F394, 0x1F395, prExtendedPictographic}, // E0.0 [2] (🎔..🎕) HEART WITH TIP ON THE LEFT..BOUQUET OF FLOWERS
+ {0x1F396, 0x1F397, prExtendedPictographic}, // E0.7 [2] (🎖️..🎗️) military medal..reminder ribbon
+ {0x1F398, 0x1F398, prExtendedPictographic}, // E0.0 [1] (🎘) MUSICAL KEYBOARD WITH JACKS
+ {0x1F399, 0x1F39B, prExtendedPictographic}, // E0.7 [3] (🎙️..🎛️) studio microphone..control knobs
+ {0x1F39C, 0x1F39D, prExtendedPictographic}, // E0.0 [2] (🎜..🎝) BEAMED ASCENDING MUSICAL NOTES..BEAMED DESCENDING MUSICAL NOTES
+ {0x1F39E, 0x1F39F, prExtendedPictographic}, // E0.7 [2] (🎞️..🎟️) film frames..admission tickets
+ {0x1F3A0, 0x1F3C4, prExtendedPictographic}, // E0.6 [37] (🎠..🏄) carousel horse..person surfing
+ {0x1F3C5, 0x1F3C5, prExtendedPictographic}, // E1.0 [1] (🏅) sports medal
+ {0x1F3C6, 0x1F3C6, prExtendedPictographic}, // E0.6 [1] (🏆) trophy
+ {0x1F3C7, 0x1F3C7, prExtendedPictographic}, // E1.0 [1] (🏇) horse racing
+ {0x1F3C8, 0x1F3C8, prExtendedPictographic}, // E0.6 [1] (🏈) american football
+ {0x1F3C9, 0x1F3C9, prExtendedPictographic}, // E1.0 [1] (🏉) rugby football
+ {0x1F3CA, 0x1F3CA, prExtendedPictographic}, // E0.6 [1] (🏊) person swimming
+ {0x1F3CB, 0x1F3CE, prExtendedPictographic}, // E0.7 [4] (🏋️..🏎️) person lifting weights..racing car
+ {0x1F3CF, 0x1F3D3, prExtendedPictographic}, // E1.0 [5] (🏏..🏓) cricket game..ping pong
+ {0x1F3D4, 0x1F3DF, prExtendedPictographic}, // E0.7 [12] (🏔️..🏟️) snow-capped mountain..stadium
+ {0x1F3E0, 0x1F3E3, prExtendedPictographic}, // E0.6 [4] (🏠..🏣) house..Japanese post office
+ {0x1F3E4, 0x1F3E4, prExtendedPictographic}, // E1.0 [1] (🏤) post office
+ {0x1F3E5, 0x1F3F0, prExtendedPictographic}, // E0.6 [12] (🏥..🏰) hospital..castle
+ {0x1F3F1, 0x1F3F2, prExtendedPictographic}, // E0.0 [2] (🏱..🏲) WHITE PENNANT..BLACK PENNANT
+ {0x1F3F3, 0x1F3F3, prExtendedPictographic}, // E0.7 [1] (🏳️) white flag
+ {0x1F3F4, 0x1F3F4, prExtendedPictographic}, // E1.0 [1] (🏴) black flag
+ {0x1F3F5, 0x1F3F5, prExtendedPictographic}, // E0.7 [1] (🏵️) rosette
+ {0x1F3F6, 0x1F3F6, prExtendedPictographic}, // E0.0 [1] (🏶) BLACK ROSETTE
+ {0x1F3F7, 0x1F3F7, prExtendedPictographic}, // E0.7 [1] (🏷️) label
+ {0x1F3F8, 0x1F3FA, prExtendedPictographic}, // E1.0 [3] (🏸..🏺) badminton..amphora
+ {0x1F3FB, 0x1F3FF, prExtend}, // Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6
+ {0x1F400, 0x1F407, prExtendedPictographic}, // E1.0 [8] (🐀..🐇) rat..rabbit
+ {0x1F408, 0x1F408, prExtendedPictographic}, // E0.7 [1] (🐈) cat
+ {0x1F409, 0x1F40B, prExtendedPictographic}, // E1.0 [3] (🐉..🐋) dragon..whale
+ {0x1F40C, 0x1F40E, prExtendedPictographic}, // E0.6 [3] (🐌..🐎) snail..horse
+ {0x1F40F, 0x1F410, prExtendedPictographic}, // E1.0 [2] (🐏..🐐) ram..goat
+ {0x1F411, 0x1F412, prExtendedPictographic}, // E0.6 [2] (🐑..🐒) ewe..monkey
+ {0x1F413, 0x1F413, prExtendedPictographic}, // E1.0 [1] (🐓) rooster
+ {0x1F414, 0x1F414, prExtendedPictographic}, // E0.6 [1] (🐔) chicken
+ {0x1F415, 0x1F415, prExtendedPictographic}, // E0.7 [1] (🐕) dog
+ {0x1F416, 0x1F416, prExtendedPictographic}, // E1.0 [1] (🐖) pig
+ {0x1F417, 0x1F429, prExtendedPictographic}, // E0.6 [19] (🐗..🐩) boar..poodle
+ {0x1F42A, 0x1F42A, prExtendedPictographic}, // E1.0 [1] (🐪) camel
+ {0x1F42B, 0x1F43E, prExtendedPictographic}, // E0.6 [20] (🐫..🐾) two-hump camel..paw prints
+ {0x1F43F, 0x1F43F, prExtendedPictographic}, // E0.7 [1] (🐿️) chipmunk
+ {0x1F440, 0x1F440, prExtendedPictographic}, // E0.6 [1] (👀) eyes
+ {0x1F441, 0x1F441, prExtendedPictographic}, // E0.7 [1] (👁️) eye
+ {0x1F442, 0x1F464, prExtendedPictographic}, // E0.6 [35] (👂..👤) ear..bust in silhouette
+ {0x1F465, 0x1F465, prExtendedPictographic}, // E1.0 [1] (👥) busts in silhouette
+ {0x1F466, 0x1F46B, prExtendedPictographic}, // E0.6 [6] (👦..👫) boy..woman and man holding hands
+ {0x1F46C, 0x1F46D, prExtendedPictographic}, // E1.0 [2] (👬..👭) men holding hands..women holding hands
+ {0x1F46E, 0x1F4AC, prExtendedPictographic}, // E0.6 [63] (👮..💬) police officer..speech balloon
+ {0x1F4AD, 0x1F4AD, prExtendedPictographic}, // E1.0 [1] (💭) thought balloon
+ {0x1F4AE, 0x1F4B5, prExtendedPictographic}, // E0.6 [8] (💮..💵) white flower..dollar banknote
+ {0x1F4B6, 0x1F4B7, prExtendedPictographic}, // E1.0 [2] (💶..💷) euro banknote..pound banknote
+ {0x1F4B8, 0x1F4EB, prExtendedPictographic}, // E0.6 [52] (💸..📫) money with wings..closed mailbox with raised flag
+ {0x1F4EC, 0x1F4ED, prExtendedPictographic}, // E0.7 [2] (📬..📭) open mailbox with raised flag..open mailbox with lowered flag
+ {0x1F4EE, 0x1F4EE, prExtendedPictographic}, // E0.6 [1] (📮) postbox
+ {0x1F4EF, 0x1F4EF, prExtendedPictographic}, // E1.0 [1] (📯) postal horn
+ {0x1F4F0, 0x1F4F4, prExtendedPictographic}, // E0.6 [5] (📰..📴) newspaper..mobile phone off
+ {0x1F4F5, 0x1F4F5, prExtendedPictographic}, // E1.0 [1] (📵) no mobile phones
+ {0x1F4F6, 0x1F4F7, prExtendedPictographic}, // E0.6 [2] (📶..📷) antenna bars..camera
+ {0x1F4F8, 0x1F4F8, prExtendedPictographic}, // E1.0 [1] (📸) camera with flash
+ {0x1F4F9, 0x1F4FC, prExtendedPictographic}, // E0.6 [4] (📹..📼) video camera..videocassette
+ {0x1F4FD, 0x1F4FD, prExtendedPictographic}, // E0.7 [1] (📽️) film projector
+ {0x1F4FE, 0x1F4FE, prExtendedPictographic}, // E0.0 [1] (📾) PORTABLE STEREO
+ {0x1F4FF, 0x1F502, prExtendedPictographic}, // E1.0 [4] (📿..🔂) prayer beads..repeat single button
+ {0x1F503, 0x1F503, prExtendedPictographic}, // E0.6 [1] (🔃) clockwise vertical arrows
+ {0x1F504, 0x1F507, prExtendedPictographic}, // E1.0 [4] (🔄..🔇) counterclockwise arrows button..muted speaker
+ {0x1F508, 0x1F508, prExtendedPictographic}, // E0.7 [1] (🔈) speaker low volume
+ {0x1F509, 0x1F509, prExtendedPictographic}, // E1.0 [1] (🔉) speaker medium volume
+ {0x1F50A, 0x1F514, prExtendedPictographic}, // E0.6 [11] (🔊..🔔) speaker high volume..bell
+ {0x1F515, 0x1F515, prExtendedPictographic}, // E1.0 [1] (🔕) bell with slash
+ {0x1F516, 0x1F52B, prExtendedPictographic}, // E0.6 [22] (🔖..🔫) bookmark..water pistol
+ {0x1F52C, 0x1F52D, prExtendedPictographic}, // E1.0 [2] (🔬..🔭) microscope..telescope
+ {0x1F52E, 0x1F53D, prExtendedPictographic}, // E0.6 [16] (🔮..🔽) crystal ball..downwards button
+ {0x1F546, 0x1F548, prExtendedPictographic}, // E0.0 [3] (🕆..🕈) WHITE LATIN CROSS..CELTIC CROSS
+ {0x1F549, 0x1F54A, prExtendedPictographic}, // E0.7 [2] (🕉️..🕊️) om..dove
+ {0x1F54B, 0x1F54E, prExtendedPictographic}, // E1.0 [4] (🕋..🕎) kaaba..menorah
+ {0x1F54F, 0x1F54F, prExtendedPictographic}, // E0.0 [1] (🕏) BOWL OF HYGIEIA
+ {0x1F550, 0x1F55B, prExtendedPictographic}, // E0.6 [12] (🕐..🕛) one o’clock..twelve o’clock
+ {0x1F55C, 0x1F567, prExtendedPictographic}, // E0.7 [12] (🕜..🕧) one-thirty..twelve-thirty
+ {0x1F568, 0x1F56E, prExtendedPictographic}, // E0.0 [7] (🕨..🕮) RIGHT SPEAKER..BOOK
+ {0x1F56F, 0x1F570, prExtendedPictographic}, // E0.7 [2] (🕯️..🕰️) candle..mantelpiece clock
+ {0x1F571, 0x1F572, prExtendedPictographic}, // E0.0 [2] (🕱..🕲) BLACK SKULL AND CROSSBONES..NO PIRACY
+ {0x1F573, 0x1F579, prExtendedPictographic}, // E0.7 [7] (🕳️..🕹️) hole..joystick
+ {0x1F57A, 0x1F57A, prExtendedPictographic}, // E3.0 [1] (🕺) man dancing
+ {0x1F57B, 0x1F586, prExtendedPictographic}, // E0.0 [12] (🕻..🖆) LEFT HAND TELEPHONE RECEIVER..PEN OVER STAMPED ENVELOPE
+ {0x1F587, 0x1F587, prExtendedPictographic}, // E0.7 [1] (🖇️) linked paperclips
+ {0x1F588, 0x1F589, prExtendedPictographic}, // E0.0 [2] (🖈..🖉) BLACK PUSHPIN..LOWER LEFT PENCIL
+ {0x1F58A, 0x1F58D, prExtendedPictographic}, // E0.7 [4] (🖊️..🖍️) pen..crayon
+ {0x1F58E, 0x1F58F, prExtendedPictographic}, // E0.0 [2] (🖎..🖏) LEFT WRITING HAND..TURNED OK HAND SIGN
+ {0x1F590, 0x1F590, prExtendedPictographic}, // E0.7 [1] (🖐️) hand with fingers splayed
+ {0x1F591, 0x1F594, prExtendedPictographic}, // E0.0 [4] (🖑..🖔) REVERSED RAISED HAND WITH FINGERS SPLAYED..REVERSED VICTORY HAND
+ {0x1F595, 0x1F596, prExtendedPictographic}, // E1.0 [2] (🖕..🖖) middle finger..vulcan salute
+ {0x1F597, 0x1F5A3, prExtendedPictographic}, // E0.0 [13] (🖗..🖣) WHITE DOWN POINTING LEFT HAND INDEX..BLACK DOWN POINTING BACKHAND INDEX
+ {0x1F5A4, 0x1F5A4, prExtendedPictographic}, // E3.0 [1] (🖤) black heart
+ {0x1F5A5, 0x1F5A5, prExtendedPictographic}, // E0.7 [1] (🖥️) desktop computer
+ {0x1F5A6, 0x1F5A7, prExtendedPictographic}, // E0.0 [2] (🖦..🖧) KEYBOARD AND MOUSE..THREE NETWORKED COMPUTERS
+ {0x1F5A8, 0x1F5A8, prExtendedPictographic}, // E0.7 [1] (🖨️) printer
+ {0x1F5A9, 0x1F5B0, prExtendedPictographic}, // E0.0 [8] (🖩..🖰) POCKET CALCULATOR..TWO BUTTON MOUSE
+ {0x1F5B1, 0x1F5B2, prExtendedPictographic}, // E0.7 [2] (🖱️..🖲️) computer mouse..trackball
+ {0x1F5B3, 0x1F5BB, prExtendedPictographic}, // E0.0 [9] (🖳..🖻) OLD PERSONAL COMPUTER..DOCUMENT WITH PICTURE
+ {0x1F5BC, 0x1F5BC, prExtendedPictographic}, // E0.7 [1] (🖼️) framed picture
+ {0x1F5BD, 0x1F5C1, prExtendedPictographic}, // E0.0 [5] (🖽..🗁) FRAME WITH TILES..OPEN FOLDER
+ {0x1F5C2, 0x1F5C4, prExtendedPictographic}, // E0.7 [3] (🗂️..🗄️) card index dividers..file cabinet
+ {0x1F5C5, 0x1F5D0, prExtendedPictographic}, // E0.0 [12] (🗅..🗐) EMPTY NOTE..PAGES
+ {0x1F5D1, 0x1F5D3, prExtendedPictographic}, // E0.7 [3] (🗑️..🗓️) wastebasket..spiral calendar
+ {0x1F5D4, 0x1F5DB, prExtendedPictographic}, // E0.0 [8] (🗔..🗛) DESKTOP WINDOW..DECREASE FONT SIZE SYMBOL
+ {0x1F5DC, 0x1F5DE, prExtendedPictographic}, // E0.7 [3] (🗜️..🗞️) clamp..rolled-up newspaper
+ {0x1F5DF, 0x1F5E0, prExtendedPictographic}, // E0.0 [2] (🗟..🗠) PAGE WITH CIRCLED TEXT..STOCK CHART
+ {0x1F5E1, 0x1F5E1, prExtendedPictographic}, // E0.7 [1] (🗡️) dagger
+ {0x1F5E2, 0x1F5E2, prExtendedPictographic}, // E0.0 [1] (🗢) LIPS
+ {0x1F5E3, 0x1F5E3, prExtendedPictographic}, // E0.7 [1] (🗣️) speaking head
+ {0x1F5E4, 0x1F5E7, prExtendedPictographic}, // E0.0 [4] (🗤..🗧) THREE RAYS ABOVE..THREE RAYS RIGHT
+ {0x1F5E8, 0x1F5E8, prExtendedPictographic}, // E2.0 [1] (🗨️) left speech bubble
+ {0x1F5E9, 0x1F5EE, prExtendedPictographic}, // E0.0 [6] (🗩..🗮) RIGHT SPEECH BUBBLE..LEFT ANGER BUBBLE
+ {0x1F5EF, 0x1F5EF, prExtendedPictographic}, // E0.7 [1] (🗯️) right anger bubble
+ {0x1F5F0, 0x1F5F2, prExtendedPictographic}, // E0.0 [3] (🗰..🗲) MOOD BUBBLE..LIGHTNING MOOD
+ {0x1F5F3, 0x1F5F3, prExtendedPictographic}, // E0.7 [1] (🗳️) ballot box with ballot
+ {0x1F5F4, 0x1F5F9, prExtendedPictographic}, // E0.0 [6] (🗴..🗹) BALLOT SCRIPT X..BALLOT BOX WITH BOLD CHECK
+ {0x1F5FA, 0x1F5FA, prExtendedPictographic}, // E0.7 [1] (🗺️) world map
+ {0x1F5FB, 0x1F5FF, prExtendedPictographic}, // E0.6 [5] (🗻..🗿) mount fuji..moai
+ {0x1F600, 0x1F600, prExtendedPictographic}, // E1.0 [1] (😀) grinning face
+ {0x1F601, 0x1F606, prExtendedPictographic}, // E0.6 [6] (😁..😆) beaming face with smiling eyes..grinning squinting face
+ {0x1F607, 0x1F608, prExtendedPictographic}, // E1.0 [2] (😇..😈) smiling face with halo..smiling face with horns
+ {0x1F609, 0x1F60D, prExtendedPictographic}, // E0.6 [5] (😉..😍) winking face..smiling face with heart-eyes
+ {0x1F60E, 0x1F60E, prExtendedPictographic}, // E1.0 [1] (😎) smiling face with sunglasses
+ {0x1F60F, 0x1F60F, prExtendedPictographic}, // E0.6 [1] (😏) smirking face
+ {0x1F610, 0x1F610, prExtendedPictographic}, // E0.7 [1] (😐) neutral face
+ {0x1F611, 0x1F611, prExtendedPictographic}, // E1.0 [1] (😑) expressionless face
+ {0x1F612, 0x1F614, prExtendedPictographic}, // E0.6 [3] (😒..😔) unamused face..pensive face
+ {0x1F615, 0x1F615, prExtendedPictographic}, // E1.0 [1] (😕) confused face
+ {0x1F616, 0x1F616, prExtendedPictographic}, // E0.6 [1] (😖) confounded face
+ {0x1F617, 0x1F617, prExtendedPictographic}, // E1.0 [1] (😗) kissing face
+ {0x1F618, 0x1F618, prExtendedPictographic}, // E0.6 [1] (😘) face blowing a kiss
+ {0x1F619, 0x1F619, prExtendedPictographic}, // E1.0 [1] (😙) kissing face with smiling eyes
+ {0x1F61A, 0x1F61A, prExtendedPictographic}, // E0.6 [1] (😚) kissing face with closed eyes
+ {0x1F61B, 0x1F61B, prExtendedPictographic}, // E1.0 [1] (😛) face with tongue
+ {0x1F61C, 0x1F61E, prExtendedPictographic}, // E0.6 [3] (😜..😞) winking face with tongue..disappointed face
+ {0x1F61F, 0x1F61F, prExtendedPictographic}, // E1.0 [1] (😟) worried face
+ {0x1F620, 0x1F625, prExtendedPictographic}, // E0.6 [6] (😠..😥) angry face..sad but relieved face
+ {0x1F626, 0x1F627, prExtendedPictographic}, // E1.0 [2] (😦..😧) frowning face with open mouth..anguished face
+ {0x1F628, 0x1F62B, prExtendedPictographic}, // E0.6 [4] (😨..😫) fearful face..tired face
+ {0x1F62C, 0x1F62C, prExtendedPictographic}, // E1.0 [1] (😬) grimacing face
+ {0x1F62D, 0x1F62D, prExtendedPictographic}, // E0.6 [1] (😭) loudly crying face
+ {0x1F62E, 0x1F62F, prExtendedPictographic}, // E1.0 [2] (😮..😯) face with open mouth..hushed face
+ {0x1F630, 0x1F633, prExtendedPictographic}, // E0.6 [4] (😰..😳) anxious face with sweat..flushed face
+ {0x1F634, 0x1F634, prExtendedPictographic}, // E1.0 [1] (😴) sleeping face
+ {0x1F635, 0x1F635, prExtendedPictographic}, // E0.6 [1] (😵) face with crossed-out eyes
+ {0x1F636, 0x1F636, prExtendedPictographic}, // E1.0 [1] (😶) face without mouth
+ {0x1F637, 0x1F640, prExtendedPictographic}, // E0.6 [10] (😷..🙀) face with medical mask..weary cat
+ {0x1F641, 0x1F644, prExtendedPictographic}, // E1.0 [4] (🙁..🙄) slightly frowning face..face with rolling eyes
+ {0x1F645, 0x1F64F, prExtendedPictographic}, // E0.6 [11] (🙅..🙏) person gesturing NO..folded hands
+ {0x1F680, 0x1F680, prExtendedPictographic}, // E0.6 [1] (🚀) rocket
+ {0x1F681, 0x1F682, prExtendedPictographic}, // E1.0 [2] (🚁..🚂) helicopter..locomotive
+ {0x1F683, 0x1F685, prExtendedPictographic}, // E0.6 [3] (🚃..🚅) railway car..bullet train
+ {0x1F686, 0x1F686, prExtendedPictographic}, // E1.0 [1] (🚆) train
+ {0x1F687, 0x1F687, prExtendedPictographic}, // E0.6 [1] (🚇) metro
+ {0x1F688, 0x1F688, prExtendedPictographic}, // E1.0 [1] (🚈) light rail
+ {0x1F689, 0x1F689, prExtendedPictographic}, // E0.6 [1] (🚉) station
+ {0x1F68A, 0x1F68B, prExtendedPictographic}, // E1.0 [2] (🚊..🚋) tram..tram car
+ {0x1F68C, 0x1F68C, prExtendedPictographic}, // E0.6 [1] (🚌) bus
+ {0x1F68D, 0x1F68D, prExtendedPictographic}, // E0.7 [1] (🚍) oncoming bus
+ {0x1F68E, 0x1F68E, prExtendedPictographic}, // E1.0 [1] (🚎) trolleybus
+ {0x1F68F, 0x1F68F, prExtendedPictographic}, // E0.6 [1] (🚏) bus stop
+ {0x1F690, 0x1F690, prExtendedPictographic}, // E1.0 [1] (🚐) minibus
+ {0x1F691, 0x1F693, prExtendedPictographic}, // E0.6 [3] (🚑..🚓) ambulance..police car
+ {0x1F694, 0x1F694, prExtendedPictographic}, // E0.7 [1] (🚔) oncoming police car
+ {0x1F695, 0x1F695, prExtendedPictographic}, // E0.6 [1] (🚕) taxi
+ {0x1F696, 0x1F696, prExtendedPictographic}, // E1.0 [1] (🚖) oncoming taxi
+ {0x1F697, 0x1F697, prExtendedPictographic}, // E0.6 [1] (🚗) automobile
+ {0x1F698, 0x1F698, prExtendedPictographic}, // E0.7 [1] (🚘) oncoming automobile
+ {0x1F699, 0x1F69A, prExtendedPictographic}, // E0.6 [2] (🚙..🚚) sport utility vehicle..delivery truck
+ {0x1F69B, 0x1F6A1, prExtendedPictographic}, // E1.0 [7] (🚛..🚡) articulated lorry..aerial tramway
+ {0x1F6A2, 0x1F6A2, prExtendedPictographic}, // E0.6 [1] (🚢) ship
+ {0x1F6A3, 0x1F6A3, prExtendedPictographic}, // E1.0 [1] (🚣) person rowing boat
+ {0x1F6A4, 0x1F6A5, prExtendedPictographic}, // E0.6 [2] (🚤..🚥) speedboat..horizontal traffic light
+ {0x1F6A6, 0x1F6A6, prExtendedPictographic}, // E1.0 [1] (🚦) vertical traffic light
+ {0x1F6A7, 0x1F6AD, prExtendedPictographic}, // E0.6 [7] (🚧..🚭) construction..no smoking
+ {0x1F6AE, 0x1F6B1, prExtendedPictographic}, // E1.0 [4] (🚮..🚱) litter in bin sign..non-potable water
+ {0x1F6B2, 0x1F6B2, prExtendedPictographic}, // E0.6 [1] (🚲) bicycle
+ {0x1F6B3, 0x1F6B5, prExtendedPictographic}, // E1.0 [3] (🚳..🚵) no bicycles..person mountain biking
+ {0x1F6B6, 0x1F6B6, prExtendedPictographic}, // E0.6 [1] (🚶) person walking
+ {0x1F6B7, 0x1F6B8, prExtendedPictographic}, // E1.0 [2] (🚷..🚸) no pedestrians..children crossing
+ {0x1F6B9, 0x1F6BE, prExtendedPictographic}, // E0.6 [6] (🚹..🚾) men’s room..water closet
+ {0x1F6BF, 0x1F6BF, prExtendedPictographic}, // E1.0 [1] (🚿) shower
+ {0x1F6C0, 0x1F6C0, prExtendedPictographic}, // E0.6 [1] (🛀) person taking bath
+ {0x1F6C1, 0x1F6C5, prExtendedPictographic}, // E1.0 [5] (🛁..🛅) bathtub..left luggage
+ {0x1F6C6, 0x1F6CA, prExtendedPictographic}, // E0.0 [5] (🛆..🛊) TRIANGLE WITH ROUNDED CORNERS..GIRLS SYMBOL
+ {0x1F6CB, 0x1F6CB, prExtendedPictographic}, // E0.7 [1] (🛋️) couch and lamp
+ {0x1F6CC, 0x1F6CC, prExtendedPictographic}, // E1.0 [1] (🛌) person in bed
+ {0x1F6CD, 0x1F6CF, prExtendedPictographic}, // E0.7 [3] (🛍️..🛏️) shopping bags..bed
+ {0x1F6D0, 0x1F6D0, prExtendedPictographic}, // E1.0 [1] (🛐) place of worship
+ {0x1F6D1, 0x1F6D2, prExtendedPictographic}, // E3.0 [2] (🛑..🛒) stop sign..shopping cart
+ {0x1F6D3, 0x1F6D4, prExtendedPictographic}, // E0.0 [2] (🛓..🛔) STUPA..PAGODA
+ {0x1F6D5, 0x1F6D5, prExtendedPictographic}, // E12.0 [1] (🛕) hindu temple
+ {0x1F6D6, 0x1F6D7, prExtendedPictographic}, // E13.0 [2] (🛖..🛗) hut..elevator
+ {0x1F6D8, 0x1F6DB, prExtendedPictographic}, // E0.0 [4] (..) ..
+ {0x1F6DC, 0x1F6DC, prExtendedPictographic}, // E15.0 [1] (🛜) wireless
+ {0x1F6DD, 0x1F6DF, prExtendedPictographic}, // E14.0 [3] (🛝..🛟) playground slide..ring buoy
+ {0x1F6E0, 0x1F6E5, prExtendedPictographic}, // E0.7 [6] (🛠️..🛥️) hammer and wrench..motor boat
+ {0x1F6E6, 0x1F6E8, prExtendedPictographic}, // E0.0 [3] (🛦..🛨) UP-POINTING MILITARY AIRPLANE..UP-POINTING SMALL AIRPLANE
+ {0x1F6E9, 0x1F6E9, prExtendedPictographic}, // E0.7 [1] (🛩️) small airplane
+ {0x1F6EA, 0x1F6EA, prExtendedPictographic}, // E0.0 [1] (🛪) NORTHEAST-POINTING AIRPLANE
+ {0x1F6EB, 0x1F6EC, prExtendedPictographic}, // E1.0 [2] (🛫..🛬) airplane departure..airplane arrival
+ {0x1F6ED, 0x1F6EF, prExtendedPictographic}, // E0.0 [3] (..) ..
+ {0x1F6F0, 0x1F6F0, prExtendedPictographic}, // E0.7 [1] (🛰️) satellite
+ {0x1F6F1, 0x1F6F2, prExtendedPictographic}, // E0.0 [2] (🛱..🛲) ONCOMING FIRE ENGINE..DIESEL LOCOMOTIVE
+ {0x1F6F3, 0x1F6F3, prExtendedPictographic}, // E0.7 [1] (🛳️) passenger ship
+ {0x1F6F4, 0x1F6F6, prExtendedPictographic}, // E3.0 [3] (🛴..🛶) kick scooter..canoe
+ {0x1F6F7, 0x1F6F8, prExtendedPictographic}, // E5.0 [2] (🛷..🛸) sled..flying saucer
+ {0x1F6F9, 0x1F6F9, prExtendedPictographic}, // E11.0 [1] (🛹) skateboard
+ {0x1F6FA, 0x1F6FA, prExtendedPictographic}, // E12.0 [1] (🛺) auto rickshaw
+ {0x1F6FB, 0x1F6FC, prExtendedPictographic}, // E13.0 [2] (🛻..🛼) pickup truck..roller skate
+ {0x1F6FD, 0x1F6FF, prExtendedPictographic}, // E0.0 [3] (..) ..
+ {0x1F774, 0x1F77F, prExtendedPictographic}, // E0.0 [12] (🝴..🝿) LOT OF FORTUNE..ORCUS
+ {0x1F7D5, 0x1F7DF, prExtendedPictographic}, // E0.0 [11] (🟕..) CIRCLED TRIANGLE..
+ {0x1F7E0, 0x1F7EB, prExtendedPictographic}, // E12.0 [12] (🟠..🟫) orange circle..brown square
+ {0x1F7EC, 0x1F7EF, prExtendedPictographic}, // E0.0 [4] (..) ..
+ {0x1F7F0, 0x1F7F0, prExtendedPictographic}, // E14.0 [1] (🟰) heavy equals sign
+ {0x1F7F1, 0x1F7FF, prExtendedPictographic}, // E0.0 [15] (..) ..
+ {0x1F80C, 0x1F80F, prExtendedPictographic}, // E0.0 [4] (..) ..
+ {0x1F848, 0x1F84F, prExtendedPictographic}, // E0.0 [8] (..) ..
+ {0x1F85A, 0x1F85F, prExtendedPictographic}, // E0.0 [6] (..) ..
+ {0x1F888, 0x1F88F, prExtendedPictographic}, // E0.0 [8] (..) ..
+ {0x1F8AE, 0x1F8FF, prExtendedPictographic}, // E0.0 [82] (..) ..
+ {0x1F90C, 0x1F90C, prExtendedPictographic}, // E13.0 [1] (🤌) pinched fingers
+ {0x1F90D, 0x1F90F, prExtendedPictographic}, // E12.0 [3] (🤍..🤏) white heart..pinching hand
+ {0x1F910, 0x1F918, prExtendedPictographic}, // E1.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns
+ {0x1F919, 0x1F91E, prExtendedPictographic}, // E3.0 [6] (🤙..🤞) call me hand..crossed fingers
+ {0x1F91F, 0x1F91F, prExtendedPictographic}, // E5.0 [1] (🤟) love-you gesture
+ {0x1F920, 0x1F927, prExtendedPictographic}, // E3.0 [8] (🤠..🤧) cowboy hat face..sneezing face
+ {0x1F928, 0x1F92F, prExtendedPictographic}, // E5.0 [8] (🤨..🤯) face with raised eyebrow..exploding head
+ {0x1F930, 0x1F930, prExtendedPictographic}, // E3.0 [1] (🤰) pregnant woman
+ {0x1F931, 0x1F932, prExtendedPictographic}, // E5.0 [2] (🤱..🤲) breast-feeding..palms up together
+ {0x1F933, 0x1F93A, prExtendedPictographic}, // E3.0 [8] (🤳..🤺) selfie..person fencing
+ {0x1F93C, 0x1F93E, prExtendedPictographic}, // E3.0 [3] (🤼..🤾) people wrestling..person playing handball
+ {0x1F93F, 0x1F93F, prExtendedPictographic}, // E12.0 [1] (🤿) diving mask
+ {0x1F940, 0x1F945, prExtendedPictographic}, // E3.0 [6] (🥀..🥅) wilted flower..goal net
+ {0x1F947, 0x1F94B, prExtendedPictographic}, // E3.0 [5] (🥇..🥋) 1st place medal..martial arts uniform
+ {0x1F94C, 0x1F94C, prExtendedPictographic}, // E5.0 [1] (🥌) curling stone
+ {0x1F94D, 0x1F94F, prExtendedPictographic}, // E11.0 [3] (🥍..🥏) lacrosse..flying disc
+ {0x1F950, 0x1F95E, prExtendedPictographic}, // E3.0 [15] (🥐..🥞) croissant..pancakes
+ {0x1F95F, 0x1F96B, prExtendedPictographic}, // E5.0 [13] (🥟..🥫) dumpling..canned food
+ {0x1F96C, 0x1F970, prExtendedPictographic}, // E11.0 [5] (🥬..🥰) leafy green..smiling face with hearts
+ {0x1F971, 0x1F971, prExtendedPictographic}, // E12.0 [1] (🥱) yawning face
+ {0x1F972, 0x1F972, prExtendedPictographic}, // E13.0 [1] (🥲) smiling face with tear
+ {0x1F973, 0x1F976, prExtendedPictographic}, // E11.0 [4] (🥳..🥶) partying face..cold face
+ {0x1F977, 0x1F978, prExtendedPictographic}, // E13.0 [2] (🥷..🥸) ninja..disguised face
+ {0x1F979, 0x1F979, prExtendedPictographic}, // E14.0 [1] (🥹) face holding back tears
+ {0x1F97A, 0x1F97A, prExtendedPictographic}, // E11.0 [1] (🥺) pleading face
+ {0x1F97B, 0x1F97B, prExtendedPictographic}, // E12.0 [1] (🥻) sari
+ {0x1F97C, 0x1F97F, prExtendedPictographic}, // E11.0 [4] (🥼..🥿) lab coat..flat shoe
+ {0x1F980, 0x1F984, prExtendedPictographic}, // E1.0 [5] (🦀..🦄) crab..unicorn
+ {0x1F985, 0x1F991, prExtendedPictographic}, // E3.0 [13] (🦅..🦑) eagle..squid
+ {0x1F992, 0x1F997, prExtendedPictographic}, // E5.0 [6] (🦒..🦗) giraffe..cricket
+ {0x1F998, 0x1F9A2, prExtendedPictographic}, // E11.0 [11] (🦘..🦢) kangaroo..swan
+ {0x1F9A3, 0x1F9A4, prExtendedPictographic}, // E13.0 [2] (🦣..🦤) mammoth..dodo
+ {0x1F9A5, 0x1F9AA, prExtendedPictographic}, // E12.0 [6] (🦥..🦪) sloth..oyster
+ {0x1F9AB, 0x1F9AD, prExtendedPictographic}, // E13.0 [3] (🦫..🦭) beaver..seal
+ {0x1F9AE, 0x1F9AF, prExtendedPictographic}, // E12.0 [2] (🦮..🦯) guide dog..white cane
+ {0x1F9B0, 0x1F9B9, prExtendedPictographic}, // E11.0 [10] (🦰..🦹) red hair..supervillain
+ {0x1F9BA, 0x1F9BF, prExtendedPictographic}, // E12.0 [6] (🦺..🦿) safety vest..mechanical leg
+ {0x1F9C0, 0x1F9C0, prExtendedPictographic}, // E1.0 [1] (🧀) cheese wedge
+ {0x1F9C1, 0x1F9C2, prExtendedPictographic}, // E11.0 [2] (🧁..🧂) cupcake..salt
+ {0x1F9C3, 0x1F9CA, prExtendedPictographic}, // E12.0 [8] (🧃..🧊) beverage box..ice
+ {0x1F9CB, 0x1F9CB, prExtendedPictographic}, // E13.0 [1] (🧋) bubble tea
+ {0x1F9CC, 0x1F9CC, prExtendedPictographic}, // E14.0 [1] (🧌) troll
+ {0x1F9CD, 0x1F9CF, prExtendedPictographic}, // E12.0 [3] (🧍..🧏) person standing..deaf person
+ {0x1F9D0, 0x1F9E6, prExtendedPictographic}, // E5.0 [23] (🧐..🧦) face with monocle..socks
+ {0x1F9E7, 0x1F9FF, prExtendedPictographic}, // E11.0 [25] (🧧..🧿) red envelope..nazar amulet
+ {0x1FA00, 0x1FA6F, prExtendedPictographic}, // E0.0 [112] (🨀..) NEUTRAL CHESS KING..
+ {0x1FA70, 0x1FA73, prExtendedPictographic}, // E12.0 [4] (🩰..🩳) ballet shoes..shorts
+ {0x1FA74, 0x1FA74, prExtendedPictographic}, // E13.0 [1] (🩴) thong sandal
+ {0x1FA75, 0x1FA77, prExtendedPictographic}, // E15.0 [3] (🩵..🩷) light blue heart..pink heart
+ {0x1FA78, 0x1FA7A, prExtendedPictographic}, // E12.0 [3] (🩸..🩺) drop of blood..stethoscope
+ {0x1FA7B, 0x1FA7C, prExtendedPictographic}, // E14.0 [2] (🩻..🩼) x-ray..crutch
+ {0x1FA7D, 0x1FA7F, prExtendedPictographic}, // E0.0 [3] (..) ..
+ {0x1FA80, 0x1FA82, prExtendedPictographic}, // E12.0 [3] (🪀..🪂) yo-yo..parachute
+ {0x1FA83, 0x1FA86, prExtendedPictographic}, // E13.0 [4] (🪃..🪆) boomerang..nesting dolls
+ {0x1FA87, 0x1FA88, prExtendedPictographic}, // E15.0 [2] (🪇..🪈) maracas..flute
+ {0x1FA89, 0x1FA8F, prExtendedPictographic}, // E0.0 [7] (..) ..
+ {0x1FA90, 0x1FA95, prExtendedPictographic}, // E12.0 [6] (🪐..🪕) ringed planet..banjo
+ {0x1FA96, 0x1FAA8, prExtendedPictographic}, // E13.0 [19] (🪖..🪨) military helmet..rock
+ {0x1FAA9, 0x1FAAC, prExtendedPictographic}, // E14.0 [4] (🪩..🪬) mirror ball..hamsa
+ {0x1FAAD, 0x1FAAF, prExtendedPictographic}, // E15.0 [3] (🪭..🪯) folding hand fan..khanda
+ {0x1FAB0, 0x1FAB6, prExtendedPictographic}, // E13.0 [7] (🪰..🪶) fly..feather
+ {0x1FAB7, 0x1FABA, prExtendedPictographic}, // E14.0 [4] (🪷..🪺) lotus..nest with eggs
+ {0x1FABB, 0x1FABD, prExtendedPictographic}, // E15.0 [3] (🪻..🪽) hyacinth..wing
+ {0x1FABE, 0x1FABE, prExtendedPictographic}, // E0.0 [1] ()
+ {0x1FABF, 0x1FABF, prExtendedPictographic}, // E15.0 [1] (🪿) goose
+ {0x1FAC0, 0x1FAC2, prExtendedPictographic}, // E13.0 [3] (🫀..🫂) anatomical heart..people hugging
+ {0x1FAC3, 0x1FAC5, prExtendedPictographic}, // E14.0 [3] (🫃..🫅) pregnant man..person with crown
+ {0x1FAC6, 0x1FACD, prExtendedPictographic}, // E0.0 [8] (..) ..
+ {0x1FACE, 0x1FACF, prExtendedPictographic}, // E15.0 [2] (🫎..🫏) moose..donkey
+ {0x1FAD0, 0x1FAD6, prExtendedPictographic}, // E13.0 [7] (🫐..🫖) blueberries..teapot
+ {0x1FAD7, 0x1FAD9, prExtendedPictographic}, // E14.0 [3] (🫗..🫙) pouring liquid..jar
+ {0x1FADA, 0x1FADB, prExtendedPictographic}, // E15.0 [2] (🫚..🫛) ginger root..pea pod
+ {0x1FADC, 0x1FADF, prExtendedPictographic}, // E0.0 [4] (..) ..
+ {0x1FAE0, 0x1FAE7, prExtendedPictographic}, // E14.0 [8] (🫠..🫧) melting face..bubbles
+ {0x1FAE8, 0x1FAE8, prExtendedPictographic}, // E15.0 [1] (🫨) shaking face
+ {0x1FAE9, 0x1FAEF, prExtendedPictographic}, // E0.0 [7] (..) ..
+ {0x1FAF0, 0x1FAF6, prExtendedPictographic}, // E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands
+ {0x1FAF7, 0x1FAF8, prExtendedPictographic}, // E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand
+ {0x1FAF9, 0x1FAFF, prExtendedPictographic}, // E0.0 [7] (..) ..
+ {0x1FC00, 0x1FFFD, prExtendedPictographic}, // E0.0[1022] (..) ..
+ {0xE0000, 0xE0000, prControl}, // Cn
+ {0xE0001, 0xE0001, prControl}, // Cf LANGUAGE TAG
+ {0xE0002, 0xE001F, prControl}, // Cn [30] ..
+ {0xE0020, 0xE007F, prExtend}, // Cf [96] TAG SPACE..CANCEL TAG
+ {0xE0080, 0xE00FF, prControl}, // Cn [128] ..
+ {0xE0100, 0xE01EF, prExtend}, // Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+ {0xE01F0, 0xE0FFF, prControl}, // Cn [3600] ..
+}
diff --git a/vendor/github.com/rivo/uniseg/graphemerules.go b/vendor/github.com/rivo/uniseg/graphemerules.go
new file mode 100644
index 00000000..5d399d29
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/graphemerules.go
@@ -0,0 +1,176 @@
+package uniseg
+
+// The states of the grapheme cluster parser.
+const (
+ grAny = iota
+ grCR
+ grControlLF
+ grL
+ grLVV
+ grLVTT
+ grPrepend
+ grExtendedPictographic
+ grExtendedPictographicZWJ
+ grRIOdd
+ grRIEven
+)
+
+// The grapheme cluster parser's breaking instructions.
+const (
+ grNoBoundary = iota
+ grBoundary
+)
+
+// grTransitions implements the grapheme cluster parser's state transitions.
+// Maps state and property to a new state, a breaking instruction, and rule
+// number. The breaking instruction always refers to the boundary between the
+// last and next code point. Returns negative values if no transition is found.
+//
+// This function is used as follows:
+//
+// 1. Find specific state + specific property. Stop if found.
+// 2. Find specific state + any property.
+// 3. Find any state + specific property.
+// 4. If only (2) or (3) (but not both) was found, stop.
+// 5. If both (2) and (3) were found, use state from (3) and breaking instruction
+// from the transition with the lower rule number, prefer (3) if rule numbers
+// are equal. Stop.
+// 6. Assume grAny and grBoundary.
+//
+// Unicode version 15.0.0.
+func grTransitions(state, prop int) (newState int, newProp int, boundary int) {
+ // It turns out that using a big switch statement is much faster than using
+ // a map.
+
+ switch uint64(state) | uint64(prop)<<32 {
+ // GB5
+ case grAny | prCR<<32:
+ return grCR, grBoundary, 50
+ case grAny | prLF<<32:
+ return grControlLF, grBoundary, 50
+ case grAny | prControl<<32:
+ return grControlLF, grBoundary, 50
+
+ // GB4
+ case grCR | prAny<<32:
+ return grAny, grBoundary, 40
+ case grControlLF | prAny<<32:
+ return grAny, grBoundary, 40
+
+ // GB3
+ case grCR | prLF<<32:
+ return grControlLF, grNoBoundary, 30
+
+ // GB6
+ case grAny | prL<<32:
+ return grL, grBoundary, 9990
+ case grL | prL<<32:
+ return grL, grNoBoundary, 60
+ case grL | prV<<32:
+ return grLVV, grNoBoundary, 60
+ case grL | prLV<<32:
+ return grLVV, grNoBoundary, 60
+ case grL | prLVT<<32:
+ return grLVTT, grNoBoundary, 60
+
+ // GB7
+ case grAny | prLV<<32:
+ return grLVV, grBoundary, 9990
+ case grAny | prV<<32:
+ return grLVV, grBoundary, 9990
+ case grLVV | prV<<32:
+ return grLVV, grNoBoundary, 70
+ case grLVV | prT<<32:
+ return grLVTT, grNoBoundary, 70
+
+ // GB8
+ case grAny | prLVT<<32:
+ return grLVTT, grBoundary, 9990
+ case grAny | prT<<32:
+ return grLVTT, grBoundary, 9990
+ case grLVTT | prT<<32:
+ return grLVTT, grNoBoundary, 80
+
+ // GB9
+ case grAny | prExtend<<32:
+ return grAny, grNoBoundary, 90
+ case grAny | prZWJ<<32:
+ return grAny, grNoBoundary, 90
+
+ // GB9a
+ case grAny | prSpacingMark<<32:
+ return grAny, grNoBoundary, 91
+
+ // GB9b
+ case grAny | prPrepend<<32:
+ return grPrepend, grBoundary, 9990
+ case grPrepend | prAny<<32:
+ return grAny, grNoBoundary, 92
+
+ // GB11
+ case grAny | prExtendedPictographic<<32:
+ return grExtendedPictographic, grBoundary, 9990
+ case grExtendedPictographic | prExtend<<32:
+ return grExtendedPictographic, grNoBoundary, 110
+ case grExtendedPictographic | prZWJ<<32:
+ return grExtendedPictographicZWJ, grNoBoundary, 110
+ case grExtendedPictographicZWJ | prExtendedPictographic<<32:
+ return grExtendedPictographic, grNoBoundary, 110
+
+ // GB12 / GB13
+ case grAny | prRegionalIndicator<<32:
+ return grRIOdd, grBoundary, 9990
+ case grRIOdd | prRegionalIndicator<<32:
+ return grRIEven, grNoBoundary, 120
+ case grRIEven | prRegionalIndicator<<32:
+ return grRIOdd, grBoundary, 120
+ default:
+ return -1, -1, -1
+ }
+}
+
+// transitionGraphemeState determines the new state of the grapheme cluster
+// parser given the current state and the next code point. It also returns the
+// code point's grapheme property (the value mapped by the [graphemeCodePoints]
+// table) and whether a cluster boundary was detected.
+func transitionGraphemeState(state int, r rune) (newState, prop int, boundary bool) {
+ // Determine the property of the next character.
+ prop = propertyGraphemes(r)
+
+ // Find the applicable transition.
+ nextState, nextProp, _ := grTransitions(state, prop)
+ if nextState >= 0 {
+ // We have a specific transition. We'll use it.
+ return nextState, prop, nextProp == grBoundary
+ }
+
+ // No specific transition found. Try the less specific ones.
+ anyPropState, anyPropProp, anyPropRule := grTransitions(state, prAny)
+ anyStateState, anyStateProp, anyStateRule := grTransitions(grAny, prop)
+ if anyPropState >= 0 && anyStateState >= 0 {
+ // Both apply. We'll use a mix (see comments for grTransitions).
+ newState = anyStateState
+ boundary = anyStateProp == grBoundary
+ if anyPropRule < anyStateRule {
+ boundary = anyPropProp == grBoundary
+ }
+ return
+ }
+
+ if anyPropState >= 0 {
+ // We only have a specific state.
+ return anyPropState, prop, anyPropProp == grBoundary
+ // This branch will probably never be reached because okAnyState will
+ // always be true given the current transition map. But we keep it here
+ // for future modifications to the transition map where this may not be
+ // true anymore.
+ }
+
+ if anyStateState >= 0 {
+ // We only have a specific property.
+ return anyStateState, prop, anyStateProp == grBoundary
+ }
+
+ // No known transition. GB999: Any ÷ Any.
+ return grAny, prop, true
+}
diff --git a/vendor/github.com/rivo/uniseg/line.go b/vendor/github.com/rivo/uniseg/line.go
new file mode 100644
index 00000000..7a46318d
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/line.go
@@ -0,0 +1,134 @@
+package uniseg
+
+import "unicode/utf8"
+
+// FirstLineSegment returns the prefix of the given byte slice after which a
+// decision to break the string over to the next line can or must be made,
+// according to the rules of [Unicode Standard Annex #14]. This is used to
+// implement line breaking.
+//
+// Line breaking, also known as word wrapping, is the process of breaking a
+// section of text into lines such that it will fit in the available width of a
+// page, window or other display area.
+//
+// The returned "segment" may not be broken into smaller parts, unless no other
+// breaking opportunities present themselves, in which case you may break by
+// grapheme clusters (using the [FirstGraphemeCluster] function to determine the
+// grapheme clusters).
+//
+// The "mustBreak" flag indicates whether you MUST break the line after the
+// given segment (true), for example after newline characters, or you MAY break
+// the line after the given segment (false).
+//
+// This function can be called continuously to extract all non-breaking sub-sets
+// from a byte slice, as illustrated in the example below.
+//
+// If you don't know the current state, for example when calling the function
+// for the first time, you must pass -1. For consecutive calls, pass the state
+// and rest slice returned by the previous call.
+//
+// The "rest" slice is the sub-slice of the original byte slice "b" starting
+// after the last byte of the identified line segment. If the length of the
+// "rest" slice is 0, the entire byte slice "b" has been processed. The
+// "segment" byte slice is the sub-slice of the input slice containing the
+// identified line segment.
+//
+// Given an empty byte slice "b", the function returns nil values.
+//
+// Note that in accordance with [UAX #14 LB3], the final segment will end with
+// "mustBreak" set to true. You can choose to ignore this by checking if the
+// length of the "rest" slice is 0 and calling [HasTrailingLineBreak] or
+// [HasTrailingLineBreakInString] on the last rune.
+//
+// Note also that this algorithm may break within grapheme clusters. This is
+// addressed in Section 8.2 Example 6 of UAX #14. To avoid this, you can use
+// the [Step] function instead.
+//
+// [Unicode Standard Annex #14]: https://www.unicode.org/reports/tr14/
+// [UAX #14 LB3]: https://www.unicode.org/reports/tr14/#Algorithm
+func FirstLineSegment(b []byte, state int) (segment, rest []byte, mustBreak bool, newState int) {
+ // An empty byte slice returns nothing.
+ if len(b) == 0 {
+ return
+ }
+
+ // Extract the first rune.
+ r, length := utf8.DecodeRune(b)
+ if len(b) <= length { // If we're already past the end, there is nothing else to parse.
+ return b, nil, true, lbAny // LB3.
+ }
+
+ // If we don't know the state, determine it now.
+ if state < 0 {
+ state, _ = transitionLineBreakState(state, r, b[length:], "")
+ }
+
+ // Transition until we find a boundary.
+ var boundary int
+ for {
+ r, l := utf8.DecodeRune(b[length:])
+ state, boundary = transitionLineBreakState(state, r, b[length+l:], "")
+
+ if boundary != LineDontBreak {
+ return b[:length], b[length:], boundary == LineMustBreak, state
+ }
+
+ length += l
+ if len(b) <= length {
+ return b, nil, true, lbAny // LB3
+ }
+ }
+}
+
+// FirstLineSegmentInString is like [FirstLineSegment] but its input and outputs
+// are strings.
+func FirstLineSegmentInString(str string, state int) (segment, rest string, mustBreak bool, newState int) {
+ // An empty byte slice returns nothing.
+ if len(str) == 0 {
+ return
+ }
+
+ // Extract the first rune.
+ r, length := utf8.DecodeRuneInString(str)
+ if len(str) <= length { // If we're already past the end, there is nothing else to parse.
+ return str, "", true, lbAny // LB3.
+ }
+
+ // If we don't know the state, determine it now.
+ if state < 0 {
+ state, _ = transitionLineBreakState(state, r, nil, str[length:])
+ }
+
+ // Transition until we find a boundary.
+ var boundary int
+ for {
+ r, l := utf8.DecodeRuneInString(str[length:])
+ state, boundary = transitionLineBreakState(state, r, nil, str[length+l:])
+
+ if boundary != LineDontBreak {
+ return str[:length], str[length:], boundary == LineMustBreak, state
+ }
+
+ length += l
+ if len(str) <= length {
+ return str, "", true, lbAny // LB3.
+ }
+ }
+}
+
+// HasTrailingLineBreak returns true if the last rune in the given byte slice is
+// one of the hard line break code points defined in LB4 and LB5 of [UAX #14].
+//
+// [UAX #14]: https://www.unicode.org/reports/tr14/#Algorithm
+func HasTrailingLineBreak(b []byte) bool {
+ r, _ := utf8.DecodeLastRune(b)
+ property, _ := propertyLineBreak(r)
+ return property == prBK || property == prCR || property == prLF || property == prNL
+}
+
+// HasTrailingLineBreakInString is like [HasTrailingLineBreak] but for a string.
+func HasTrailingLineBreakInString(str string) bool {
+ r, _ := utf8.DecodeLastRuneInString(str)
+ property, _ := propertyLineBreak(r)
+ return property == prBK || property == prCR || property == prLF || property == prNL
+}
diff --git a/vendor/github.com/rivo/uniseg/lineproperties.go b/vendor/github.com/rivo/uniseg/lineproperties.go
new file mode 100644
index 00000000..ac7fac4c
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/lineproperties.go
@@ -0,0 +1,3554 @@
+// Code generated via go generate from gen_properties.go. DO NOT EDIT.
+
+package uniseg
+
+// lineBreakCodePoints are taken from
+// https://www.unicode.org/Public/15.0.0/ucd/LineBreak.txt
+// and
+// https://unicode.org/Public/15.0.0/ucd/emoji/emoji-data.txt
+// ("Extended_Pictographic" only)
+// on September 5, 2023. See https://www.unicode.org/license.html for the Unicode
+// license agreement.
+var lineBreakCodePoints = [][4]int{
+ {0x0000, 0x0008, prCM, gcCc}, // [9] ..
+ {0x0009, 0x0009, prBA, gcCc}, //
+ {0x000A, 0x000A, prLF, gcCc}, //
+ {0x000B, 0x000C, prBK, gcCc}, // [2] ..
+ {0x000D, 0x000D, prCR, gcCc}, //
+ {0x000E, 0x001F, prCM, gcCc}, // [18] ..
+ {0x0020, 0x0020, prSP, gcZs}, // SPACE
+ {0x0021, 0x0021, prEX, gcPo}, // EXCLAMATION MARK
+ {0x0022, 0x0022, prQU, gcPo}, // QUOTATION MARK
+ {0x0023, 0x0023, prAL, gcPo}, // NUMBER SIGN
+ {0x0024, 0x0024, prPR, gcSc}, // DOLLAR SIGN
+ {0x0025, 0x0025, prPO, gcPo}, // PERCENT SIGN
+ {0x0026, 0x0026, prAL, gcPo}, // AMPERSAND
+ {0x0027, 0x0027, prQU, gcPo}, // APOSTROPHE
+ {0x0028, 0x0028, prOP, gcPs}, // LEFT PARENTHESIS
+ {0x0029, 0x0029, prCP, gcPe}, // RIGHT PARENTHESIS
+ {0x002A, 0x002A, prAL, gcPo}, // ASTERISK
+ {0x002B, 0x002B, prPR, gcSm}, // PLUS SIGN
+ {0x002C, 0x002C, prIS, gcPo}, // COMMA
+ {0x002D, 0x002D, prHY, gcPd}, // HYPHEN-MINUS
+ {0x002E, 0x002E, prIS, gcPo}, // FULL STOP
+ {0x002F, 0x002F, prSY, gcPo}, // SOLIDUS
+ {0x0030, 0x0039, prNU, gcNd}, // [10] DIGIT ZERO..DIGIT NINE
+ {0x003A, 0x003B, prIS, gcPo}, // [2] COLON..SEMICOLON
+ {0x003C, 0x003E, prAL, gcSm}, // [3] LESS-THAN SIGN..GREATER-THAN SIGN
+ {0x003F, 0x003F, prEX, gcPo}, // QUESTION MARK
+ {0x0040, 0x0040, prAL, gcPo}, // COMMERCIAL AT
+ {0x0041, 0x005A, prAL, gcLu}, // [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+ {0x005B, 0x005B, prOP, gcPs}, // LEFT SQUARE BRACKET
+ {0x005C, 0x005C, prPR, gcPo}, // REVERSE SOLIDUS
+ {0x005D, 0x005D, prCP, gcPe}, // RIGHT SQUARE BRACKET
+ {0x005E, 0x005E, prAL, gcSk}, // CIRCUMFLEX ACCENT
+ {0x005F, 0x005F, prAL, gcPc}, // LOW LINE
+ {0x0060, 0x0060, prAL, gcSk}, // GRAVE ACCENT
+ {0x0061, 0x007A, prAL, gcLl}, // [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+ {0x007B, 0x007B, prOP, gcPs}, // LEFT CURLY BRACKET
+ {0x007C, 0x007C, prBA, gcSm}, // VERTICAL LINE
+ {0x007D, 0x007D, prCL, gcPe}, // RIGHT CURLY BRACKET
+ {0x007E, 0x007E, prAL, gcSm}, // TILDE
+ {0x007F, 0x007F, prCM, gcCc}, //
+ {0x0080, 0x0084, prCM, gcCc}, // [5] ..
+ {0x0085, 0x0085, prNL, gcCc}, //
+ {0x0086, 0x009F, prCM, gcCc}, // [26] ..
+ {0x00A0, 0x00A0, prGL, gcZs}, // NO-BREAK SPACE
+ {0x00A1, 0x00A1, prOP, gcPo}, // INVERTED EXCLAMATION MARK
+ {0x00A2, 0x00A2, prPO, gcSc}, // CENT SIGN
+ {0x00A3, 0x00A5, prPR, gcSc}, // [3] POUND SIGN..YEN SIGN
+ {0x00A6, 0x00A6, prAL, gcSo}, // BROKEN BAR
+ {0x00A7, 0x00A7, prAI, gcPo}, // SECTION SIGN
+ {0x00A8, 0x00A8, prAI, gcSk}, // DIAERESIS
+ {0x00A9, 0x00A9, prAL, gcSo}, // COPYRIGHT SIGN
+ {0x00AA, 0x00AA, prAI, gcLo}, // FEMININE ORDINAL INDICATOR
+ {0x00AB, 0x00AB, prQU, gcPi}, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ {0x00AC, 0x00AC, prAL, gcSm}, // NOT SIGN
+ {0x00AD, 0x00AD, prBA, gcCf}, // SOFT HYPHEN
+ {0x00AE, 0x00AE, prAL, gcSo}, // REGISTERED SIGN
+ {0x00AF, 0x00AF, prAL, gcSk}, // MACRON
+ {0x00B0, 0x00B0, prPO, gcSo}, // DEGREE SIGN
+ {0x00B1, 0x00B1, prPR, gcSm}, // PLUS-MINUS SIGN
+ {0x00B2, 0x00B3, prAI, gcNo}, // [2] SUPERSCRIPT TWO..SUPERSCRIPT THREE
+ {0x00B4, 0x00B4, prBB, gcSk}, // ACUTE ACCENT
+ {0x00B5, 0x00B5, prAL, gcLl}, // MICRO SIGN
+ {0x00B6, 0x00B7, prAI, gcPo}, // [2] PILCROW SIGN..MIDDLE DOT
+ {0x00B8, 0x00B8, prAI, gcSk}, // CEDILLA
+ {0x00B9, 0x00B9, prAI, gcNo}, // SUPERSCRIPT ONE
+ {0x00BA, 0x00BA, prAI, gcLo}, // MASCULINE ORDINAL INDICATOR
+ {0x00BB, 0x00BB, prQU, gcPf}, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ {0x00BC, 0x00BE, prAI, gcNo}, // [3] VULGAR FRACTION ONE QUARTER..VULGAR FRACTION THREE QUARTERS
+ {0x00BF, 0x00BF, prOP, gcPo}, // INVERTED QUESTION MARK
+ {0x00C0, 0x00D6, prAL, gcLu}, // [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
+ {0x00D7, 0x00D7, prAI, gcSm}, // MULTIPLICATION SIGN
+ {0x00D8, 0x00F6, prAL, gcLC}, // [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS
+ {0x00F7, 0x00F7, prAI, gcSm}, // DIVISION SIGN
+ {0x00F8, 0x00FF, prAL, gcLl}, // [8] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER Y WITH DIAERESIS
+ {0x0100, 0x017F, prAL, gcLC}, // [128] LATIN CAPITAL LETTER A WITH MACRON..LATIN SMALL LETTER LONG S
+ {0x0180, 0x01BA, prAL, gcLC}, // [59] LATIN SMALL LETTER B WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL
+ {0x01BB, 0x01BB, prAL, gcLo}, // LATIN LETTER TWO WITH STROKE
+ {0x01BC, 0x01BF, prAL, gcLC}, // [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN
+ {0x01C0, 0x01C3, prAL, gcLo}, // [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK
+ {0x01C4, 0x024F, prAL, gcLC}, // [140] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER Y WITH STROKE
+ {0x0250, 0x0293, prAL, gcLl}, // [68] LATIN SMALL LETTER TURNED A..LATIN SMALL LETTER EZH WITH CURL
+ {0x0294, 0x0294, prAL, gcLo}, // LATIN LETTER GLOTTAL STOP
+ {0x0295, 0x02AF, prAL, gcLl}, // [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+ {0x02B0, 0x02C1, prAL, gcLm}, // [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP
+ {0x02C2, 0x02C5, prAL, gcSk}, // [4] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER DOWN ARROWHEAD
+ {0x02C6, 0x02C6, prAL, gcLm}, // MODIFIER LETTER CIRCUMFLEX ACCENT
+ {0x02C7, 0x02C7, prAI, gcLm}, // CARON
+ {0x02C8, 0x02C8, prBB, gcLm}, // MODIFIER LETTER VERTICAL LINE
+ {0x02C9, 0x02CB, prAI, gcLm}, // [3] MODIFIER LETTER MACRON..MODIFIER LETTER GRAVE ACCENT
+ {0x02CC, 0x02CC, prBB, gcLm}, // MODIFIER LETTER LOW VERTICAL LINE
+ {0x02CD, 0x02CD, prAI, gcLm}, // MODIFIER LETTER LOW MACRON
+ {0x02CE, 0x02CF, prAL, gcLm}, // [2] MODIFIER LETTER LOW GRAVE ACCENT..MODIFIER LETTER LOW ACUTE ACCENT
+ {0x02D0, 0x02D0, prAI, gcLm}, // MODIFIER LETTER TRIANGULAR COLON
+ {0x02D1, 0x02D1, prAL, gcLm}, // MODIFIER LETTER HALF TRIANGULAR COLON
+ {0x02D2, 0x02D7, prAL, gcSk}, // [6] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER MINUS SIGN
+ {0x02D8, 0x02DB, prAI, gcSk}, // [4] BREVE..OGONEK
+ {0x02DC, 0x02DC, prAL, gcSk}, // SMALL TILDE
+ {0x02DD, 0x02DD, prAI, gcSk}, // DOUBLE ACUTE ACCENT
+ {0x02DE, 0x02DE, prAL, gcSk}, // MODIFIER LETTER RHOTIC HOOK
+ {0x02DF, 0x02DF, prBB, gcSk}, // MODIFIER LETTER CROSS ACCENT
+ {0x02E0, 0x02E4, prAL, gcLm}, // [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP
+ {0x02E5, 0x02EB, prAL, gcSk}, // [7] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER YANG DEPARTING TONE MARK
+ {0x02EC, 0x02EC, prAL, gcLm}, // MODIFIER LETTER VOICING
+ {0x02ED, 0x02ED, prAL, gcSk}, // MODIFIER LETTER UNASPIRATED
+ {0x02EE, 0x02EE, prAL, gcLm}, // MODIFIER LETTER DOUBLE APOSTROPHE
+ {0x02EF, 0x02FF, prAL, gcSk}, // [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW
+ {0x0300, 0x034E, prCM, gcMn}, // [79] COMBINING GRAVE ACCENT..COMBINING UPWARDS ARROW BELOW
+ {0x034F, 0x034F, prGL, gcMn}, // COMBINING GRAPHEME JOINER
+ {0x0350, 0x035B, prCM, gcMn}, // [12] COMBINING RIGHT ARROWHEAD ABOVE..COMBINING ZIGZAG ABOVE
+ {0x035C, 0x0362, prGL, gcMn}, // [7] COMBINING DOUBLE BREVE BELOW..COMBINING DOUBLE RIGHTWARDS ARROW BELOW
+ {0x0363, 0x036F, prCM, gcMn}, // [13] COMBINING LATIN SMALL LETTER A..COMBINING LATIN SMALL LETTER X
+ {0x0370, 0x0373, prAL, gcLC}, // [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI
+ {0x0374, 0x0374, prAL, gcLm}, // GREEK NUMERAL SIGN
+ {0x0375, 0x0375, prAL, gcSk}, // GREEK LOWER NUMERAL SIGN
+ {0x0376, 0x0377, prAL, gcLC}, // [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+ {0x037A, 0x037A, prAL, gcLm}, // GREEK YPOGEGRAMMENI
+ {0x037B, 0x037D, prAL, gcLl}, // [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+ {0x037E, 0x037E, prIS, gcPo}, // GREEK QUESTION MARK
+ {0x037F, 0x037F, prAL, gcLu}, // GREEK CAPITAL LETTER YOT
+ {0x0384, 0x0385, prAL, gcSk}, // [2] GREEK TONOS..GREEK DIALYTIKA TONOS
+ {0x0386, 0x0386, prAL, gcLu}, // GREEK CAPITAL LETTER ALPHA WITH TONOS
+ {0x0387, 0x0387, prAL, gcPo}, // GREEK ANO TELEIA
+ {0x0388, 0x038A, prAL, gcLu}, // [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+ {0x038C, 0x038C, prAL, gcLu}, // GREEK CAPITAL LETTER OMICRON WITH TONOS
+ {0x038E, 0x03A1, prAL, gcLC}, // [20] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER RHO
+ {0x03A3, 0x03F5, prAL, gcLC}, // [83] GREEK CAPITAL LETTER SIGMA..GREEK LUNATE EPSILON SYMBOL
+ {0x03F6, 0x03F6, prAL, gcSm}, // GREEK REVERSED LUNATE EPSILON SYMBOL
+ {0x03F7, 0x03FF, prAL, gcLC}, // [9] GREEK CAPITAL LETTER SHO..GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL
+ {0x0400, 0x0481, prAL, gcLC}, // [130] CYRILLIC CAPITAL LETTER IE WITH GRAVE..CYRILLIC SMALL LETTER KOPPA
+ {0x0482, 0x0482, prAL, gcSo}, // CYRILLIC THOUSANDS SIGN
+ {0x0483, 0x0487, prCM, gcMn}, // [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE
+ {0x0488, 0x0489, prCM, gcMe}, // [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN
+ {0x048A, 0x04FF, prAL, gcLC}, // [118] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER HA WITH STROKE
+ {0x0500, 0x052F, prAL, gcLC}, // [48] CYRILLIC CAPITAL LETTER KOMI DE..CYRILLIC SMALL LETTER EL WITH DESCENDER
+ {0x0531, 0x0556, prAL, gcLu}, // [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+ {0x0559, 0x0559, prAL, gcLm}, // ARMENIAN MODIFIER LETTER LEFT HALF RING
+ {0x055A, 0x055F, prAL, gcPo}, // [6] ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK
+ {0x0560, 0x0588, prAL, gcLl}, // [41] ARMENIAN SMALL LETTER TURNED AYB..ARMENIAN SMALL LETTER YI WITH STROKE
+ {0x0589, 0x0589, prIS, gcPo}, // ARMENIAN FULL STOP
+ {0x058A, 0x058A, prBA, gcPd}, // ARMENIAN HYPHEN
+ {0x058D, 0x058E, prAL, gcSo}, // [2] RIGHT-FACING ARMENIAN ETERNITY SIGN..LEFT-FACING ARMENIAN ETERNITY SIGN
+ {0x058F, 0x058F, prPR, gcSc}, // ARMENIAN DRAM SIGN
+ {0x0591, 0x05BD, prCM, gcMn}, // [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG
+ {0x05BE, 0x05BE, prBA, gcPd}, // HEBREW PUNCTUATION MAQAF
+ {0x05BF, 0x05BF, prCM, gcMn}, // HEBREW POINT RAFE
+ {0x05C0, 0x05C0, prAL, gcPo}, // HEBREW PUNCTUATION PASEQ
+ {0x05C1, 0x05C2, prCM, gcMn}, // [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT
+ {0x05C3, 0x05C3, prAL, gcPo}, // HEBREW PUNCTUATION SOF PASUQ
+ {0x05C4, 0x05C5, prCM, gcMn}, // [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT
+ {0x05C6, 0x05C6, prEX, gcPo}, // HEBREW PUNCTUATION NUN HAFUKHA
+ {0x05C7, 0x05C7, prCM, gcMn}, // HEBREW POINT QAMATS QATAN
+ {0x05D0, 0x05EA, prHL, gcLo}, // [27] HEBREW LETTER ALEF..HEBREW LETTER TAV
+ {0x05EF, 0x05F2, prHL, gcLo}, // [4] HEBREW YOD TRIANGLE..HEBREW LIGATURE YIDDISH DOUBLE YOD
+ {0x05F3, 0x05F4, prAL, gcPo}, // [2] HEBREW PUNCTUATION GERESH..HEBREW PUNCTUATION GERSHAYIM
+ {0x0600, 0x0605, prAL, gcCf}, // [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE
+ {0x0606, 0x0608, prAL, gcSm}, // [3] ARABIC-INDIC CUBE ROOT..ARABIC RAY
+ {0x0609, 0x060A, prPO, gcPo}, // [2] ARABIC-INDIC PER MILLE SIGN..ARABIC-INDIC PER TEN THOUSAND SIGN
+ {0x060B, 0x060B, prPO, gcSc}, // AFGHANI SIGN
+ {0x060C, 0x060D, prIS, gcPo}, // [2] ARABIC COMMA..ARABIC DATE SEPARATOR
+ {0x060E, 0x060F, prAL, gcSo}, // [2] ARABIC POETIC VERSE SIGN..ARABIC SIGN MISRA
+ {0x0610, 0x061A, prCM, gcMn}, // [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA
+ {0x061B, 0x061B, prEX, gcPo}, // ARABIC SEMICOLON
+ {0x061C, 0x061C, prCM, gcCf}, // ARABIC LETTER MARK
+ {0x061D, 0x061F, prEX, gcPo}, // [3] ARABIC END OF TEXT MARK..ARABIC QUESTION MARK
+ {0x0620, 0x063F, prAL, gcLo}, // [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
+ {0x0640, 0x0640, prAL, gcLm}, // ARABIC TATWEEL
+ {0x0641, 0x064A, prAL, gcLo}, // [10] ARABIC LETTER FEH..ARABIC LETTER YEH
+ {0x064B, 0x065F, prCM, gcMn}, // [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW
+ {0x0660, 0x0669, prNU, gcNd}, // [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
+ {0x066A, 0x066A, prPO, gcPo}, // ARABIC PERCENT SIGN
+ {0x066B, 0x066C, prNU, gcPo}, // [2] ARABIC DECIMAL SEPARATOR..ARABIC THOUSANDS SEPARATOR
+ {0x066D, 0x066D, prAL, gcPo}, // ARABIC FIVE POINTED STAR
+ {0x066E, 0x066F, prAL, gcLo}, // [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF
+ {0x0670, 0x0670, prCM, gcMn}, // ARABIC LETTER SUPERSCRIPT ALEF
+ {0x0671, 0x06D3, prAL, gcLo}, // [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
+ {0x06D4, 0x06D4, prEX, gcPo}, // ARABIC FULL STOP
+ {0x06D5, 0x06D5, prAL, gcLo}, // ARABIC LETTER AE
+ {0x06D6, 0x06DC, prCM, gcMn}, // [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN
+ {0x06DD, 0x06DD, prAL, gcCf}, // ARABIC END OF AYAH
+ {0x06DE, 0x06DE, prAL, gcSo}, // ARABIC START OF RUB EL HIZB
+ {0x06DF, 0x06E4, prCM, gcMn}, // [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA
+ {0x06E5, 0x06E6, prAL, gcLm}, // [2] ARABIC SMALL WAW..ARABIC SMALL YEH
+ {0x06E7, 0x06E8, prCM, gcMn}, // [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON
+ {0x06E9, 0x06E9, prAL, gcSo}, // ARABIC PLACE OF SAJDAH
+ {0x06EA, 0x06ED, prCM, gcMn}, // [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM
+ {0x06EE, 0x06EF, prAL, gcLo}, // [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V
+ {0x06F0, 0x06F9, prNU, gcNd}, // [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
+ {0x06FA, 0x06FC, prAL, gcLo}, // [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW
+ {0x06FD, 0x06FE, prAL, gcSo}, // [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN
+ {0x06FF, 0x06FF, prAL, gcLo}, // ARABIC LETTER HEH WITH INVERTED V
+ {0x0700, 0x070D, prAL, gcPo}, // [14] SYRIAC END OF PARAGRAPH..SYRIAC HARKLEAN ASTERISCUS
+ {0x070F, 0x070F, prAL, gcCf}, // SYRIAC ABBREVIATION MARK
+ {0x0710, 0x0710, prAL, gcLo}, // SYRIAC LETTER ALAPH
+ {0x0711, 0x0711, prCM, gcMn}, // SYRIAC LETTER SUPERSCRIPT ALAPH
+ {0x0712, 0x072F, prAL, gcLo}, // [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH
+ {0x0730, 0x074A, prCM, gcMn}, // [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH
+ {0x074D, 0x074F, prAL, gcLo}, // [3] SYRIAC LETTER SOGDIAN ZHAIN..SYRIAC LETTER SOGDIAN FE
+ {0x0750, 0x077F, prAL, gcLo}, // [48] ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS ABOVE
+ {0x0780, 0x07A5, prAL, gcLo}, // [38] THAANA LETTER HAA..THAANA LETTER WAAVU
+ {0x07A6, 0x07B0, prCM, gcMn}, // [11] THAANA ABAFILI..THAANA SUKUN
+ {0x07B1, 0x07B1, prAL, gcLo}, // THAANA LETTER NAA
+ {0x07C0, 0x07C9, prNU, gcNd}, // [10] NKO DIGIT ZERO..NKO DIGIT NINE
+ {0x07CA, 0x07EA, prAL, gcLo}, // [33] NKO LETTER A..NKO LETTER JONA RA
+ {0x07EB, 0x07F3, prCM, gcMn}, // [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+ {0x07F4, 0x07F5, prAL, gcLm}, // [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE
+ {0x07F6, 0x07F6, prAL, gcSo}, // NKO SYMBOL OO DENNEN
+ {0x07F7, 0x07F7, prAL, gcPo}, // NKO SYMBOL GBAKURUNEN
+ {0x07F8, 0x07F8, prIS, gcPo}, // NKO COMMA
+ {0x07F9, 0x07F9, prEX, gcPo}, // NKO EXCLAMATION MARK
+ {0x07FA, 0x07FA, prAL, gcLm}, // NKO LAJANYALAN
+ {0x07FD, 0x07FD, prCM, gcMn}, // NKO DANTAYALAN
+ {0x07FE, 0x07FF, prPR, gcSc}, // [2] NKO DOROME SIGN..NKO TAMAN SIGN
+ {0x0800, 0x0815, prAL, gcLo}, // [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF
+ {0x0816, 0x0819, prCM, gcMn}, // [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH
+ {0x081A, 0x081A, prAL, gcLm}, // SAMARITAN MODIFIER LETTER EPENTHETIC YUT
+ {0x081B, 0x0823, prCM, gcMn}, // [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A
+ {0x0824, 0x0824, prAL, gcLm}, // SAMARITAN MODIFIER LETTER SHORT A
+ {0x0825, 0x0827, prCM, gcMn}, // [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U
+ {0x0828, 0x0828, prAL, gcLm}, // SAMARITAN MODIFIER LETTER I
+ {0x0829, 0x082D, prCM, gcMn}, // [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA
+ {0x0830, 0x083E, prAL, gcPo}, // [15] SAMARITAN PUNCTUATION NEQUDAA..SAMARITAN PUNCTUATION ANNAAU
+ {0x0840, 0x0858, prAL, gcLo}, // [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN
+ {0x0859, 0x085B, prCM, gcMn}, // [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK
+ {0x085E, 0x085E, prAL, gcPo}, // MANDAIC PUNCTUATION
+ {0x0860, 0x086A, prAL, gcLo}, // [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA
+ {0x0870, 0x0887, prAL, gcLo}, // [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT
+ {0x0888, 0x0888, prAL, gcSk}, // ARABIC RAISED ROUND DOT
+ {0x0889, 0x088E, prAL, gcLo}, // [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL
+ {0x0890, 0x0891, prAL, gcCf}, // [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE
+ {0x0898, 0x089F, prCM, gcMn}, // [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA
+ {0x08A0, 0x08C8, prAL, gcLo}, // [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF
+ {0x08C9, 0x08C9, prAL, gcLm}, // ARABIC SMALL FARSI YEH
+ {0x08CA, 0x08E1, prCM, gcMn}, // [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA
+ {0x08E2, 0x08E2, prAL, gcCf}, // ARABIC DISPUTED END OF AYAH
+ {0x08E3, 0x08FF, prCM, gcMn}, // [29] ARABIC TURNED DAMMA BELOW..ARABIC MARK SIDEWAYS NOON GHUNNA
+ {0x0900, 0x0902, prCM, gcMn}, // [3] DEVANAGARI SIGN INVERTED CANDRABINDU..DEVANAGARI SIGN ANUSVARA
+ {0x0903, 0x0903, prCM, gcMc}, // DEVANAGARI SIGN VISARGA
+ {0x0904, 0x0939, prAL, gcLo}, // [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA
+ {0x093A, 0x093A, prCM, gcMn}, // DEVANAGARI VOWEL SIGN OE
+ {0x093B, 0x093B, prCM, gcMc}, // DEVANAGARI VOWEL SIGN OOE
+ {0x093C, 0x093C, prCM, gcMn}, // DEVANAGARI SIGN NUKTA
+ {0x093D, 0x093D, prAL, gcLo}, // DEVANAGARI SIGN AVAGRAHA
+ {0x093E, 0x0940, prCM, gcMc}, // [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II
+ {0x0941, 0x0948, prCM, gcMn}, // [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI
+ {0x0949, 0x094C, prCM, gcMc}, // [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU
+ {0x094D, 0x094D, prCM, gcMn}, // DEVANAGARI SIGN VIRAMA
+ {0x094E, 0x094F, prCM, gcMc}, // [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW
+ {0x0950, 0x0950, prAL, gcLo}, // DEVANAGARI OM
+ {0x0951, 0x0957, prCM, gcMn}, // [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE
+ {0x0958, 0x0961, prAL, gcLo}, // [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL
+ {0x0962, 0x0963, prCM, gcMn}, // [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL
+ {0x0964, 0x0965, prBA, gcPo}, // [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA
+ {0x0966, 0x096F, prNU, gcNd}, // [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
+ {0x0970, 0x0970, prAL, gcPo}, // DEVANAGARI ABBREVIATION SIGN
+ {0x0971, 0x0971, prAL, gcLm}, // DEVANAGARI SIGN HIGH SPACING DOT
+ {0x0972, 0x097F, prAL, gcLo}, // [14] DEVANAGARI LETTER CANDRA A..DEVANAGARI LETTER BBA
+ {0x0980, 0x0980, prAL, gcLo}, // BENGALI ANJI
+ {0x0981, 0x0981, prCM, gcMn}, // BENGALI SIGN CANDRABINDU
+ {0x0982, 0x0983, prCM, gcMc}, // [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA
+ {0x0985, 0x098C, prAL, gcLo}, // [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L
+ {0x098F, 0x0990, prAL, gcLo}, // [2] BENGALI LETTER E..BENGALI LETTER AI
+ {0x0993, 0x09A8, prAL, gcLo}, // [22] BENGALI LETTER O..BENGALI LETTER NA
+ {0x09AA, 0x09B0, prAL, gcLo}, // [7] BENGALI LETTER PA..BENGALI LETTER RA
+ {0x09B2, 0x09B2, prAL, gcLo}, // BENGALI LETTER LA
+ {0x09B6, 0x09B9, prAL, gcLo}, // [4] BENGALI LETTER SHA..BENGALI LETTER HA
+ {0x09BC, 0x09BC, prCM, gcMn}, // BENGALI SIGN NUKTA
+ {0x09BD, 0x09BD, prAL, gcLo}, // BENGALI SIGN AVAGRAHA
+ {0x09BE, 0x09C0, prCM, gcMc}, // [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II
+ {0x09C1, 0x09C4, prCM, gcMn}, // [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR
+ {0x09C7, 0x09C8, prCM, gcMc}, // [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI
+ {0x09CB, 0x09CC, prCM, gcMc}, // [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU
+ {0x09CD, 0x09CD, prCM, gcMn}, // BENGALI SIGN VIRAMA
+ {0x09CE, 0x09CE, prAL, gcLo}, // BENGALI LETTER KHANDA TA
+ {0x09D7, 0x09D7, prCM, gcMc}, // BENGALI AU LENGTH MARK
+ {0x09DC, 0x09DD, prAL, gcLo}, // [2] BENGALI LETTER RRA..BENGALI LETTER RHA
+ {0x09DF, 0x09E1, prAL, gcLo}, // [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL
+ {0x09E2, 0x09E3, prCM, gcMn}, // [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+ {0x09E6, 0x09EF, prNU, gcNd}, // [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
+ {0x09F0, 0x09F1, prAL, gcLo}, // [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL
+ {0x09F2, 0x09F3, prPO, gcSc}, // [2] BENGALI RUPEE MARK..BENGALI RUPEE SIGN
+ {0x09F4, 0x09F8, prAL, gcNo}, // [5] BENGALI CURRENCY NUMERATOR ONE..BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR
+ {0x09F9, 0x09F9, prPO, gcNo}, // BENGALI CURRENCY DENOMINATOR SIXTEEN
+ {0x09FA, 0x09FA, prAL, gcSo}, // BENGALI ISSHAR
+ {0x09FB, 0x09FB, prPR, gcSc}, // BENGALI GANDA MARK
+ {0x09FC, 0x09FC, prAL, gcLo}, // BENGALI LETTER VEDIC ANUSVARA
+ {0x09FD, 0x09FD, prAL, gcPo}, // BENGALI ABBREVIATION SIGN
+ {0x09FE, 0x09FE, prCM, gcMn}, // BENGALI SANDHI MARK
+ {0x0A01, 0x0A02, prCM, gcMn}, // [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
+ {0x0A03, 0x0A03, prCM, gcMc}, // GURMUKHI SIGN VISARGA
+ {0x0A05, 0x0A0A, prAL, gcLo}, // [6] GURMUKHI LETTER A..GURMUKHI LETTER UU
+ {0x0A0F, 0x0A10, prAL, gcLo}, // [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI
+ {0x0A13, 0x0A28, prAL, gcLo}, // [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA
+ {0x0A2A, 0x0A30, prAL, gcLo}, // [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA
+ {0x0A32, 0x0A33, prAL, gcLo}, // [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA
+ {0x0A35, 0x0A36, prAL, gcLo}, // [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA
+ {0x0A38, 0x0A39, prAL, gcLo}, // [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA
+ {0x0A3C, 0x0A3C, prCM, gcMn}, // GURMUKHI SIGN NUKTA
+ {0x0A3E, 0x0A40, prCM, gcMc}, // [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II
+ {0x0A41, 0x0A42, prCM, gcMn}, // [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
+ {0x0A47, 0x0A48, prCM, gcMn}, // [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI
+ {0x0A4B, 0x0A4D, prCM, gcMn}, // [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA
+ {0x0A51, 0x0A51, prCM, gcMn}, // GURMUKHI SIGN UDAAT
+ {0x0A59, 0x0A5C, prAL, gcLo}, // [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA
+ {0x0A5E, 0x0A5E, prAL, gcLo}, // GURMUKHI LETTER FA
+ {0x0A66, 0x0A6F, prNU, gcNd}, // [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
+ {0x0A70, 0x0A71, prCM, gcMn}, // [2] GURMUKHI TIPPI..GURMUKHI ADDAK
+ {0x0A72, 0x0A74, prAL, gcLo}, // [3] GURMUKHI IRI..GURMUKHI EK ONKAR
+ {0x0A75, 0x0A75, prCM, gcMn}, // GURMUKHI SIGN YAKASH
+ {0x0A76, 0x0A76, prAL, gcPo}, // GURMUKHI ABBREVIATION SIGN
+ {0x0A81, 0x0A82, prCM, gcMn}, // [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA
+ {0x0A83, 0x0A83, prCM, gcMc}, // GUJARATI SIGN VISARGA
+ {0x0A85, 0x0A8D, prAL, gcLo}, // [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E
+ {0x0A8F, 0x0A91, prAL, gcLo}, // [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O
+ {0x0A93, 0x0AA8, prAL, gcLo}, // [22] GUJARATI LETTER O..GUJARATI LETTER NA
+ {0x0AAA, 0x0AB0, prAL, gcLo}, // [7] GUJARATI LETTER PA..GUJARATI LETTER RA
+ {0x0AB2, 0x0AB3, prAL, gcLo}, // [2] GUJARATI LETTER LA..GUJARATI LETTER LLA
+ {0x0AB5, 0x0AB9, prAL, gcLo}, // [5] GUJARATI LETTER VA..GUJARATI LETTER HA
+ {0x0ABC, 0x0ABC, prCM, gcMn}, // GUJARATI SIGN NUKTA
+ {0x0ABD, 0x0ABD, prAL, gcLo}, // GUJARATI SIGN AVAGRAHA
+ {0x0ABE, 0x0AC0, prCM, gcMc}, // [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II
+ {0x0AC1, 0x0AC5, prCM, gcMn}, // [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E
+ {0x0AC7, 0x0AC8, prCM, gcMn}, // [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI
+ {0x0AC9, 0x0AC9, prCM, gcMc}, // GUJARATI VOWEL SIGN CANDRA O
+ {0x0ACB, 0x0ACC, prCM, gcMc}, // [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU
+ {0x0ACD, 0x0ACD, prCM, gcMn}, // GUJARATI SIGN VIRAMA
+ {0x0AD0, 0x0AD0, prAL, gcLo}, // GUJARATI OM
+ {0x0AE0, 0x0AE1, prAL, gcLo}, // [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL
+ {0x0AE2, 0x0AE3, prCM, gcMn}, // [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+ {0x0AE6, 0x0AEF, prNU, gcNd}, // [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
+ {0x0AF0, 0x0AF0, prAL, gcPo}, // GUJARATI ABBREVIATION SIGN
+ {0x0AF1, 0x0AF1, prPR, gcSc}, // GUJARATI RUPEE SIGN
+ {0x0AF9, 0x0AF9, prAL, gcLo}, // GUJARATI LETTER ZHA
+ {0x0AFA, 0x0AFF, prCM, gcMn}, // [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE
+ {0x0B01, 0x0B01, prCM, gcMn}, // ORIYA SIGN CANDRABINDU
+ {0x0B02, 0x0B03, prCM, gcMc}, // [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA
+ {0x0B05, 0x0B0C, prAL, gcLo}, // [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L
+ {0x0B0F, 0x0B10, prAL, gcLo}, // [2] ORIYA LETTER E..ORIYA LETTER AI
+ {0x0B13, 0x0B28, prAL, gcLo}, // [22] ORIYA LETTER O..ORIYA LETTER NA
+ {0x0B2A, 0x0B30, prAL, gcLo}, // [7] ORIYA LETTER PA..ORIYA LETTER RA
+ {0x0B32, 0x0B33, prAL, gcLo}, // [2] ORIYA LETTER LA..ORIYA LETTER LLA
+ {0x0B35, 0x0B39, prAL, gcLo}, // [5] ORIYA LETTER VA..ORIYA LETTER HA
+ {0x0B3C, 0x0B3C, prCM, gcMn}, // ORIYA SIGN NUKTA
+ {0x0B3D, 0x0B3D, prAL, gcLo}, // ORIYA SIGN AVAGRAHA
+ {0x0B3E, 0x0B3E, prCM, gcMc}, // ORIYA VOWEL SIGN AA
+ {0x0B3F, 0x0B3F, prCM, gcMn}, // ORIYA VOWEL SIGN I
+ {0x0B40, 0x0B40, prCM, gcMc}, // ORIYA VOWEL SIGN II
+ {0x0B41, 0x0B44, prCM, gcMn}, // [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR
+ {0x0B47, 0x0B48, prCM, gcMc}, // [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI
+ {0x0B4B, 0x0B4C, prCM, gcMc}, // [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU
+ {0x0B4D, 0x0B4D, prCM, gcMn}, // ORIYA SIGN VIRAMA
+ {0x0B55, 0x0B56, prCM, gcMn}, // [2] ORIYA SIGN OVERLINE..ORIYA AI LENGTH MARK
+ {0x0B57, 0x0B57, prCM, gcMc}, // ORIYA AU LENGTH MARK
+ {0x0B5C, 0x0B5D, prAL, gcLo}, // [2] ORIYA LETTER RRA..ORIYA LETTER RHA
+ {0x0B5F, 0x0B61, prAL, gcLo}, // [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL
+ {0x0B62, 0x0B63, prCM, gcMn}, // [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL
+ {0x0B66, 0x0B6F, prNU, gcNd}, // [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE
+ {0x0B70, 0x0B70, prAL, gcSo}, // ORIYA ISSHAR
+ {0x0B71, 0x0B71, prAL, gcLo}, // ORIYA LETTER WA
+ {0x0B72, 0x0B77, prAL, gcNo}, // [6] ORIYA FRACTION ONE QUARTER..ORIYA FRACTION THREE SIXTEENTHS
+ {0x0B82, 0x0B82, prCM, gcMn}, // TAMIL SIGN ANUSVARA
+ {0x0B83, 0x0B83, prAL, gcLo}, // TAMIL SIGN VISARGA
+ {0x0B85, 0x0B8A, prAL, gcLo}, // [6] TAMIL LETTER A..TAMIL LETTER UU
+ {0x0B8E, 0x0B90, prAL, gcLo}, // [3] TAMIL LETTER E..TAMIL LETTER AI
+ {0x0B92, 0x0B95, prAL, gcLo}, // [4] TAMIL LETTER O..TAMIL LETTER KA
+ {0x0B99, 0x0B9A, prAL, gcLo}, // [2] TAMIL LETTER NGA..TAMIL LETTER CA
+ {0x0B9C, 0x0B9C, prAL, gcLo}, // TAMIL LETTER JA
+ {0x0B9E, 0x0B9F, prAL, gcLo}, // [2] TAMIL LETTER NYA..TAMIL LETTER TTA
+ {0x0BA3, 0x0BA4, prAL, gcLo}, // [2] TAMIL LETTER NNA..TAMIL LETTER TA
+ {0x0BA8, 0x0BAA, prAL, gcLo}, // [3] TAMIL LETTER NA..TAMIL LETTER PA
+ {0x0BAE, 0x0BB9, prAL, gcLo}, // [12] TAMIL LETTER MA..TAMIL LETTER HA
+ {0x0BBE, 0x0BBF, prCM, gcMc}, // [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I
+ {0x0BC0, 0x0BC0, prCM, gcMn}, // TAMIL VOWEL SIGN II
+ {0x0BC1, 0x0BC2, prCM, gcMc}, // [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU
+ {0x0BC6, 0x0BC8, prCM, gcMc}, // [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI
+ {0x0BCA, 0x0BCC, prCM, gcMc}, // [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU
+ {0x0BCD, 0x0BCD, prCM, gcMn}, // TAMIL SIGN VIRAMA
+ {0x0BD0, 0x0BD0, prAL, gcLo}, // TAMIL OM
+ {0x0BD7, 0x0BD7, prCM, gcMc}, // TAMIL AU LENGTH MARK
+ {0x0BE6, 0x0BEF, prNU, gcNd}, // [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
+ {0x0BF0, 0x0BF2, prAL, gcNo}, // [3] TAMIL NUMBER TEN..TAMIL NUMBER ONE THOUSAND
+ {0x0BF3, 0x0BF8, prAL, gcSo}, // [6] TAMIL DAY SIGN..TAMIL AS ABOVE SIGN
+ {0x0BF9, 0x0BF9, prPR, gcSc}, // TAMIL RUPEE SIGN
+ {0x0BFA, 0x0BFA, prAL, gcSo}, // TAMIL NUMBER SIGN
+ {0x0C00, 0x0C00, prCM, gcMn}, // TELUGU SIGN COMBINING CANDRABINDU ABOVE
+ {0x0C01, 0x0C03, prCM, gcMc}, // [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA
+ {0x0C04, 0x0C04, prCM, gcMn}, // TELUGU SIGN COMBINING ANUSVARA ABOVE
+ {0x0C05, 0x0C0C, prAL, gcLo}, // [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L
+ {0x0C0E, 0x0C10, prAL, gcLo}, // [3] TELUGU LETTER E..TELUGU LETTER AI
+ {0x0C12, 0x0C28, prAL, gcLo}, // [23] TELUGU LETTER O..TELUGU LETTER NA
+ {0x0C2A, 0x0C39, prAL, gcLo}, // [16] TELUGU LETTER PA..TELUGU LETTER HA
+ {0x0C3C, 0x0C3C, prCM, gcMn}, // TELUGU SIGN NUKTA
+ {0x0C3D, 0x0C3D, prAL, gcLo}, // TELUGU SIGN AVAGRAHA
+ {0x0C3E, 0x0C40, prCM, gcMn}, // [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
+ {0x0C41, 0x0C44, prCM, gcMc}, // [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR
+ {0x0C46, 0x0C48, prCM, gcMn}, // [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
+ {0x0C4A, 0x0C4D, prCM, gcMn}, // [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA
+ {0x0C55, 0x0C56, prCM, gcMn}, // [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK
+ {0x0C58, 0x0C5A, prAL, gcLo}, // [3] TELUGU LETTER TSA..TELUGU LETTER RRRA
+ {0x0C5D, 0x0C5D, prAL, gcLo}, // TELUGU LETTER NAKAARA POLLU
+ {0x0C60, 0x0C61, prAL, gcLo}, // [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL
+ {0x0C62, 0x0C63, prCM, gcMn}, // [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL
+ {0x0C66, 0x0C6F, prNU, gcNd}, // [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
+ {0x0C77, 0x0C77, prBB, gcPo}, // TELUGU SIGN SIDDHAM
+ {0x0C78, 0x0C7E, prAL, gcNo}, // [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR
+ {0x0C7F, 0x0C7F, prAL, gcSo}, // TELUGU SIGN TUUMU
+ {0x0C80, 0x0C80, prAL, gcLo}, // KANNADA SIGN SPACING CANDRABINDU
+ {0x0C81, 0x0C81, prCM, gcMn}, // KANNADA SIGN CANDRABINDU
+ {0x0C82, 0x0C83, prCM, gcMc}, // [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA
+ {0x0C84, 0x0C84, prBB, gcPo}, // KANNADA SIGN SIDDHAM
+ {0x0C85, 0x0C8C, prAL, gcLo}, // [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L
+ {0x0C8E, 0x0C90, prAL, gcLo}, // [3] KANNADA LETTER E..KANNADA LETTER AI
+ {0x0C92, 0x0CA8, prAL, gcLo}, // [23] KANNADA LETTER O..KANNADA LETTER NA
+ {0x0CAA, 0x0CB3, prAL, gcLo}, // [10] KANNADA LETTER PA..KANNADA LETTER LLA
+ {0x0CB5, 0x0CB9, prAL, gcLo}, // [5] KANNADA LETTER VA..KANNADA LETTER HA
+ {0x0CBC, 0x0CBC, prCM, gcMn}, // KANNADA SIGN NUKTA
+ {0x0CBD, 0x0CBD, prAL, gcLo}, // KANNADA SIGN AVAGRAHA
+ {0x0CBE, 0x0CBE, prCM, gcMc}, // KANNADA VOWEL SIGN AA
+ {0x0CBF, 0x0CBF, prCM, gcMn}, // KANNADA VOWEL SIGN I
+ {0x0CC0, 0x0CC4, prCM, gcMc}, // [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR
+ {0x0CC6, 0x0CC6, prCM, gcMn}, // KANNADA VOWEL SIGN E
+ {0x0CC7, 0x0CC8, prCM, gcMc}, // [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI
+ {0x0CCA, 0x0CCB, prCM, gcMc}, // [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO
+ {0x0CCC, 0x0CCD, prCM, gcMn}, // [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA
+ {0x0CD5, 0x0CD6, prCM, gcMc}, // [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
+ {0x0CDD, 0x0CDE, prAL, gcLo}, // [2] KANNADA LETTER NAKAARA POLLU..KANNADA LETTER FA
+ {0x0CE0, 0x0CE1, prAL, gcLo}, // [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL
+ {0x0CE2, 0x0CE3, prCM, gcMn}, // [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
+ {0x0CE6, 0x0CEF, prNU, gcNd}, // [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
+ {0x0CF1, 0x0CF2, prAL, gcLo}, // [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA
+ {0x0CF3, 0x0CF3, prCM, gcMc}, // KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT
+ {0x0D00, 0x0D01, prCM, gcMn}, // [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU
+ {0x0D02, 0x0D03, prCM, gcMc}, // [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
+ {0x0D04, 0x0D0C, prAL, gcLo}, // [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L
+ {0x0D0E, 0x0D10, prAL, gcLo}, // [3] MALAYALAM LETTER E..MALAYALAM LETTER AI
+ {0x0D12, 0x0D3A, prAL, gcLo}, // [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA
+ {0x0D3B, 0x0D3C, prCM, gcMn}, // [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA
+ {0x0D3D, 0x0D3D, prAL, gcLo}, // MALAYALAM SIGN AVAGRAHA
+ {0x0D3E, 0x0D40, prCM, gcMc}, // [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II
+ {0x0D41, 0x0D44, prCM, gcMn}, // [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
+ {0x0D46, 0x0D48, prCM, gcMc}, // [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI
+ {0x0D4A, 0x0D4C, prCM, gcMc}, // [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU
+ {0x0D4D, 0x0D4D, prCM, gcMn}, // MALAYALAM SIGN VIRAMA
+ {0x0D4E, 0x0D4E, prAL, gcLo}, // MALAYALAM LETTER DOT REPH
+ {0x0D4F, 0x0D4F, prAL, gcSo}, // MALAYALAM SIGN PARA
+ {0x0D54, 0x0D56, prAL, gcLo}, // [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL
+ {0x0D57, 0x0D57, prCM, gcMc}, // MALAYALAM AU LENGTH MARK
+ {0x0D58, 0x0D5E, prAL, gcNo}, // [7] MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH..MALAYALAM FRACTION ONE FIFTH
+ {0x0D5F, 0x0D61, prAL, gcLo}, // [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL
+ {0x0D62, 0x0D63, prCM, gcMn}, // [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL
+ {0x0D66, 0x0D6F, prNU, gcNd}, // [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
+ {0x0D70, 0x0D78, prAL, gcNo}, // [9] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE SIXTEENTHS
+ {0x0D79, 0x0D79, prPO, gcSo}, // MALAYALAM DATE MARK
+ {0x0D7A, 0x0D7F, prAL, gcLo}, // [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K
+ {0x0D81, 0x0D81, prCM, gcMn}, // SINHALA SIGN CANDRABINDU
+ {0x0D82, 0x0D83, prCM, gcMc}, // [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA
+ {0x0D85, 0x0D96, prAL, gcLo}, // [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA
+ {0x0D9A, 0x0DB1, prAL, gcLo}, // [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA
+ {0x0DB3, 0x0DBB, prAL, gcLo}, // [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA
+ {0x0DBD, 0x0DBD, prAL, gcLo}, // SINHALA LETTER DANTAJA LAYANNA
+ {0x0DC0, 0x0DC6, prAL, gcLo}, // [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA
+ {0x0DCA, 0x0DCA, prCM, gcMn}, // SINHALA SIGN AL-LAKUNA
+ {0x0DCF, 0x0DD1, prCM, gcMc}, // [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA
+ {0x0DD2, 0x0DD4, prCM, gcMn}, // [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA
+ {0x0DD6, 0x0DD6, prCM, gcMn}, // SINHALA VOWEL SIGN DIGA PAA-PILLA
+ {0x0DD8, 0x0DDF, prCM, gcMc}, // [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA
+ {0x0DE6, 0x0DEF, prNU, gcNd}, // [10] SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE
+ {0x0DF2, 0x0DF3, prCM, gcMc}, // [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA
+ {0x0DF4, 0x0DF4, prAL, gcPo}, // SINHALA PUNCTUATION KUNDDALIYA
+ {0x0E01, 0x0E30, prSA, gcLo}, // [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A
+ {0x0E31, 0x0E31, prSA, gcMn}, // THAI CHARACTER MAI HAN-AKAT
+ {0x0E32, 0x0E33, prSA, gcLo}, // [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM
+ {0x0E34, 0x0E3A, prSA, gcMn}, // [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU
+ {0x0E3F, 0x0E3F, prPR, gcSc}, // THAI CURRENCY SYMBOL BAHT
+ {0x0E40, 0x0E45, prSA, gcLo}, // [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO
+ {0x0E46, 0x0E46, prSA, gcLm}, // THAI CHARACTER MAIYAMOK
+ {0x0E47, 0x0E4E, prSA, gcMn}, // [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN
+ {0x0E4F, 0x0E4F, prAL, gcPo}, // THAI CHARACTER FONGMAN
+ {0x0E50, 0x0E59, prNU, gcNd}, // [10] THAI DIGIT ZERO..THAI DIGIT NINE
+ {0x0E5A, 0x0E5B, prBA, gcPo}, // [2] THAI CHARACTER ANGKHANKHU..THAI CHARACTER KHOMUT
+ {0x0E81, 0x0E82, prSA, gcLo}, // [2] LAO LETTER KO..LAO LETTER KHO SUNG
+ {0x0E84, 0x0E84, prSA, gcLo}, // LAO LETTER KHO TAM
+ {0x0E86, 0x0E8A, prSA, gcLo}, // [5] LAO LETTER PALI GHA..LAO LETTER SO TAM
+ {0x0E8C, 0x0EA3, prSA, gcLo}, // [24] LAO LETTER PALI JHA..LAO LETTER LO LING
+ {0x0EA5, 0x0EA5, prSA, gcLo}, // LAO LETTER LO LOOT
+ {0x0EA7, 0x0EB0, prSA, gcLo}, // [10] LAO LETTER WO..LAO VOWEL SIGN A
+ {0x0EB1, 0x0EB1, prSA, gcMn}, // LAO VOWEL SIGN MAI KAN
+ {0x0EB2, 0x0EB3, prSA, gcLo}, // [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM
+ {0x0EB4, 0x0EBC, prSA, gcMn}, // [9] LAO VOWEL SIGN I..LAO SEMIVOWEL SIGN LO
+ {0x0EBD, 0x0EBD, prSA, gcLo}, // LAO SEMIVOWEL SIGN NYO
+ {0x0EC0, 0x0EC4, prSA, gcLo}, // [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI
+ {0x0EC6, 0x0EC6, prSA, gcLm}, // LAO KO LA
+ {0x0EC8, 0x0ECE, prSA, gcMn}, // [7] LAO TONE MAI EK..LAO YAMAKKAN
+ {0x0ED0, 0x0ED9, prNU, gcNd}, // [10] LAO DIGIT ZERO..LAO DIGIT NINE
+ {0x0EDC, 0x0EDF, prSA, gcLo}, // [4] LAO HO NO..LAO LETTER KHMU NYO
+ {0x0F00, 0x0F00, prAL, gcLo}, // TIBETAN SYLLABLE OM
+ {0x0F01, 0x0F03, prBB, gcSo}, // [3] TIBETAN MARK GTER YIG MGO TRUNCATED A..TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA
+ {0x0F04, 0x0F04, prBB, gcPo}, // TIBETAN MARK INITIAL YIG MGO MDUN MA
+ {0x0F05, 0x0F05, prAL, gcPo}, // TIBETAN MARK CLOSING YIG MGO SGAB MA
+ {0x0F06, 0x0F07, prBB, gcPo}, // [2] TIBETAN MARK CARET YIG MGO PHUR SHAD MA..TIBETAN MARK YIG MGO TSHEG SHAD MA
+ {0x0F08, 0x0F08, prGL, gcPo}, // TIBETAN MARK SBRUL SHAD
+ {0x0F09, 0x0F0A, prBB, gcPo}, // [2] TIBETAN MARK BSKUR YIG MGO..TIBETAN MARK BKA- SHOG YIG MGO
+ {0x0F0B, 0x0F0B, prBA, gcPo}, // TIBETAN MARK INTERSYLLABIC TSHEG
+ {0x0F0C, 0x0F0C, prGL, gcPo}, // TIBETAN MARK DELIMITER TSHEG BSTAR
+ {0x0F0D, 0x0F11, prEX, gcPo}, // [5] TIBETAN MARK SHAD..TIBETAN MARK RIN CHEN SPUNGS SHAD
+ {0x0F12, 0x0F12, prGL, gcPo}, // TIBETAN MARK RGYA GRAM SHAD
+ {0x0F13, 0x0F13, prAL, gcSo}, // TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN
+ {0x0F14, 0x0F14, prEX, gcPo}, // TIBETAN MARK GTER TSHEG
+ {0x0F15, 0x0F17, prAL, gcSo}, // [3] TIBETAN LOGOTYPE SIGN CHAD RTAGS..TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS
+ {0x0F18, 0x0F19, prCM, gcMn}, // [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS
+ {0x0F1A, 0x0F1F, prAL, gcSo}, // [6] TIBETAN SIGN RDEL DKAR GCIG..TIBETAN SIGN RDEL DKAR RDEL NAG
+ {0x0F20, 0x0F29, prNU, gcNd}, // [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
+ {0x0F2A, 0x0F33, prAL, gcNo}, // [10] TIBETAN DIGIT HALF ONE..TIBETAN DIGIT HALF ZERO
+ {0x0F34, 0x0F34, prBA, gcSo}, // TIBETAN MARK BSDUS RTAGS
+ {0x0F35, 0x0F35, prCM, gcMn}, // TIBETAN MARK NGAS BZUNG NYI ZLA
+ {0x0F36, 0x0F36, prAL, gcSo}, // TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN
+ {0x0F37, 0x0F37, prCM, gcMn}, // TIBETAN MARK NGAS BZUNG SGOR RTAGS
+ {0x0F38, 0x0F38, prAL, gcSo}, // TIBETAN MARK CHE MGO
+ {0x0F39, 0x0F39, prCM, gcMn}, // TIBETAN MARK TSA -PHRU
+ {0x0F3A, 0x0F3A, prOP, gcPs}, // TIBETAN MARK GUG RTAGS GYON
+ {0x0F3B, 0x0F3B, prCL, gcPe}, // TIBETAN MARK GUG RTAGS GYAS
+ {0x0F3C, 0x0F3C, prOP, gcPs}, // TIBETAN MARK ANG KHANG GYON
+ {0x0F3D, 0x0F3D, prCL, gcPe}, // TIBETAN MARK ANG KHANG GYAS
+ {0x0F3E, 0x0F3F, prCM, gcMc}, // [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES
+ {0x0F40, 0x0F47, prAL, gcLo}, // [8] TIBETAN LETTER KA..TIBETAN LETTER JA
+ {0x0F49, 0x0F6C, prAL, gcLo}, // [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA
+ {0x0F71, 0x0F7E, prCM, gcMn}, // [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO
+ {0x0F7F, 0x0F7F, prBA, gcMc}, // TIBETAN SIGN RNAM BCAD
+ {0x0F80, 0x0F84, prCM, gcMn}, // [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA
+ {0x0F85, 0x0F85, prBA, gcPo}, // TIBETAN MARK PALUTA
+ {0x0F86, 0x0F87, prCM, gcMn}, // [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS
+ {0x0F88, 0x0F8C, prAL, gcLo}, // [5] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN INVERTED MCHU CAN
+ {0x0F8D, 0x0F97, prCM, gcMn}, // [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA
+ {0x0F99, 0x0FBC, prCM, gcMn}, // [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA
+ {0x0FBE, 0x0FBF, prBA, gcSo}, // [2] TIBETAN KU RU KHA..TIBETAN KU RU KHA BZHI MIG CAN
+ {0x0FC0, 0x0FC5, prAL, gcSo}, // [6] TIBETAN CANTILLATION SIGN HEAVY BEAT..TIBETAN SYMBOL RDO RJE
+ {0x0FC6, 0x0FC6, prCM, gcMn}, // TIBETAN SYMBOL PADMA GDAN
+ {0x0FC7, 0x0FCC, prAL, gcSo}, // [6] TIBETAN SYMBOL RDO RJE RGYA GRAM..TIBETAN SYMBOL NOR BU BZHI -KHYIL
+ {0x0FCE, 0x0FCF, prAL, gcSo}, // [2] TIBETAN SIGN RDEL NAG RDEL DKAR..TIBETAN SIGN RDEL NAG GSUM
+ {0x0FD0, 0x0FD1, prBB, gcPo}, // [2] TIBETAN MARK BSKA- SHOG GI MGO RGYAN..TIBETAN MARK MNYAM YIG GI MGO RGYAN
+ {0x0FD2, 0x0FD2, prBA, gcPo}, // TIBETAN MARK NYIS TSHEG
+ {0x0FD3, 0x0FD3, prBB, gcPo}, // TIBETAN MARK INITIAL BRDA RNYING YIG MGO MDUN MA
+ {0x0FD4, 0x0FD4, prAL, gcPo}, // TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA
+ {0x0FD5, 0x0FD8, prAL, gcSo}, // [4] RIGHT-FACING SVASTI SIGN..LEFT-FACING SVASTI SIGN WITH DOTS
+ {0x0FD9, 0x0FDA, prGL, gcPo}, // [2] TIBETAN MARK LEADING MCHAN RTAGS..TIBETAN MARK TRAILING MCHAN RTAGS
+ {0x1000, 0x102A, prSA, gcLo}, // [43] MYANMAR LETTER KA..MYANMAR LETTER AU
+ {0x102B, 0x102C, prSA, gcMc}, // [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA
+ {0x102D, 0x1030, prSA, gcMn}, // [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU
+ {0x1031, 0x1031, prSA, gcMc}, // MYANMAR VOWEL SIGN E
+ {0x1032, 0x1037, prSA, gcMn}, // [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW
+ {0x1038, 0x1038, prSA, gcMc}, // MYANMAR SIGN VISARGA
+ {0x1039, 0x103A, prSA, gcMn}, // [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT
+ {0x103B, 0x103C, prSA, gcMc}, // [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA
+ {0x103D, 0x103E, prSA, gcMn}, // [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA
+ {0x103F, 0x103F, prSA, gcLo}, // MYANMAR LETTER GREAT SA
+ {0x1040, 0x1049, prNU, gcNd}, // [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
+ {0x104A, 0x104B, prBA, gcPo}, // [2] MYANMAR SIGN LITTLE SECTION..MYANMAR SIGN SECTION
+ {0x104C, 0x104F, prAL, gcPo}, // [4] MYANMAR SYMBOL LOCATIVE..MYANMAR SYMBOL GENITIVE
+ {0x1050, 0x1055, prSA, gcLo}, // [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL
+ {0x1056, 0x1057, prSA, gcMc}, // [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR
+ {0x1058, 0x1059, prSA, gcMn}, // [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL
+ {0x105A, 0x105D, prSA, gcLo}, // [4] MYANMAR LETTER MON NGA..MYANMAR LETTER MON BBE
+ {0x105E, 0x1060, prSA, gcMn}, // [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA
+ {0x1061, 0x1061, prSA, gcLo}, // MYANMAR LETTER SGAW KAREN SHA
+ {0x1062, 0x1064, prSA, gcMc}, // [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO
+ {0x1065, 0x1066, prSA, gcLo}, // [2] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR LETTER WESTERN PWO KAREN PWA
+ {0x1067, 0x106D, prSA, gcMc}, // [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5
+ {0x106E, 0x1070, prSA, gcLo}, // [3] MYANMAR LETTER EASTERN PWO KAREN NNA..MYANMAR LETTER EASTERN PWO KAREN GHWA
+ {0x1071, 0x1074, prSA, gcMn}, // [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE
+ {0x1075, 0x1081, prSA, gcLo}, // [13] MYANMAR LETTER SHAN KA..MYANMAR LETTER SHAN HA
+ {0x1082, 0x1082, prSA, gcMn}, // MYANMAR CONSONANT SIGN SHAN MEDIAL WA
+ {0x1083, 0x1084, prSA, gcMc}, // [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E
+ {0x1085, 0x1086, prSA, gcMn}, // [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y
+ {0x1087, 0x108C, prSA, gcMc}, // [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3
+ {0x108D, 0x108D, prSA, gcMn}, // MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE
+ {0x108E, 0x108E, prSA, gcLo}, // MYANMAR LETTER RUMAI PALAUNG FA
+ {0x108F, 0x108F, prSA, gcMc}, // MYANMAR SIGN RUMAI PALAUNG TONE-5
+ {0x1090, 0x1099, prNU, gcNd}, // [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
+ {0x109A, 0x109C, prSA, gcMc}, // [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A
+ {0x109D, 0x109D, prSA, gcMn}, // MYANMAR VOWEL SIGN AITON AI
+ {0x109E, 0x109F, prSA, gcSo}, // [2] MYANMAR SYMBOL SHAN ONE..MYANMAR SYMBOL SHAN EXCLAMATION
+ {0x10A0, 0x10C5, prAL, gcLu}, // [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+ {0x10C7, 0x10C7, prAL, gcLu}, // GEORGIAN CAPITAL LETTER YN
+ {0x10CD, 0x10CD, prAL, gcLu}, // GEORGIAN CAPITAL LETTER AEN
+ {0x10D0, 0x10FA, prAL, gcLl}, // [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN
+ {0x10FB, 0x10FB, prAL, gcPo}, // GEORGIAN PARAGRAPH SEPARATOR
+ {0x10FC, 0x10FC, prAL, gcLm}, // MODIFIER LETTER GEORGIAN NAR
+ {0x10FD, 0x10FF, prAL, gcLl}, // [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN
+ {0x1100, 0x115F, prJL, gcLo}, // [96] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG FILLER
+ {0x1160, 0x11A7, prJV, gcLo}, // [72] HANGUL JUNGSEONG FILLER..HANGUL JUNGSEONG O-YAE
+ {0x11A8, 0x11FF, prJT, gcLo}, // [88] HANGUL JONGSEONG KIYEOK..HANGUL JONGSEONG SSANGNIEUN
+ {0x1200, 0x1248, prAL, gcLo}, // [73] ETHIOPIC SYLLABLE HA..ETHIOPIC SYLLABLE QWA
+ {0x124A, 0x124D, prAL, gcLo}, // [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE
+ {0x1250, 0x1256, prAL, gcLo}, // [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO
+ {0x1258, 0x1258, prAL, gcLo}, // ETHIOPIC SYLLABLE QHWA
+ {0x125A, 0x125D, prAL, gcLo}, // [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE
+ {0x1260, 0x1288, prAL, gcLo}, // [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA
+ {0x128A, 0x128D, prAL, gcLo}, // [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE
+ {0x1290, 0x12B0, prAL, gcLo}, // [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA
+ {0x12B2, 0x12B5, prAL, gcLo}, // [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE
+ {0x12B8, 0x12BE, prAL, gcLo}, // [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO
+ {0x12C0, 0x12C0, prAL, gcLo}, // ETHIOPIC SYLLABLE KXWA
+ {0x12C2, 0x12C5, prAL, gcLo}, // [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE
+ {0x12C8, 0x12D6, prAL, gcLo}, // [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O
+ {0x12D8, 0x1310, prAL, gcLo}, // [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA
+ {0x1312, 0x1315, prAL, gcLo}, // [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE
+ {0x1318, 0x135A, prAL, gcLo}, // [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA
+ {0x135D, 0x135F, prCM, gcMn}, // [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK
+ {0x1360, 0x1360, prAL, gcPo}, // ETHIOPIC SECTION MARK
+ {0x1361, 0x1361, prBA, gcPo}, // ETHIOPIC WORDSPACE
+ {0x1362, 0x1368, prAL, gcPo}, // [7] ETHIOPIC FULL STOP..ETHIOPIC PARAGRAPH SEPARATOR
+ {0x1369, 0x137C, prAL, gcNo}, // [20] ETHIOPIC DIGIT ONE..ETHIOPIC NUMBER TEN THOUSAND
+ {0x1380, 0x138F, prAL, gcLo}, // [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE
+ {0x1390, 0x1399, prAL, gcSo}, // [10] ETHIOPIC TONAL MARK YIZET..ETHIOPIC TONAL MARK KURT
+ {0x13A0, 0x13F5, prAL, gcLu}, // [86] CHEROKEE LETTER A..CHEROKEE LETTER MV
+ {0x13F8, 0x13FD, prAL, gcLl}, // [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV
+ {0x1400, 0x1400, prBA, gcPd}, // CANADIAN SYLLABICS HYPHEN
+ {0x1401, 0x166C, prAL, gcLo}, // [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA
+ {0x166D, 0x166D, prAL, gcSo}, // CANADIAN SYLLABICS CHI SIGN
+ {0x166E, 0x166E, prAL, gcPo}, // CANADIAN SYLLABICS FULL STOP
+ {0x166F, 0x167F, prAL, gcLo}, // [17] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS BLACKFOOT W
+ {0x1680, 0x1680, prBA, gcZs}, // OGHAM SPACE MARK
+ {0x1681, 0x169A, prAL, gcLo}, // [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH
+ {0x169B, 0x169B, prOP, gcPs}, // OGHAM FEATHER MARK
+ {0x169C, 0x169C, prCL, gcPe}, // OGHAM REVERSED FEATHER MARK
+ {0x16A0, 0x16EA, prAL, gcLo}, // [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X
+ {0x16EB, 0x16ED, prBA, gcPo}, // [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION
+ {0x16EE, 0x16F0, prAL, gcNl}, // [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL
+ {0x16F1, 0x16F8, prAL, gcLo}, // [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC
+ {0x1700, 0x1711, prAL, gcLo}, // [18] TAGALOG LETTER A..TAGALOG LETTER HA
+ {0x1712, 0x1714, prCM, gcMn}, // [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA
+ {0x1715, 0x1715, prCM, gcMc}, // TAGALOG SIGN PAMUDPOD
+ {0x171F, 0x171F, prAL, gcLo}, // TAGALOG LETTER ARCHAIC RA
+ {0x1720, 0x1731, prAL, gcLo}, // [18] HANUNOO LETTER A..HANUNOO LETTER HA
+ {0x1732, 0x1733, prCM, gcMn}, // [2] HANUNOO VOWEL SIGN I..HANUNOO VOWEL SIGN U
+ {0x1734, 0x1734, prCM, gcMc}, // HANUNOO SIGN PAMUDPOD
+ {0x1735, 0x1736, prBA, gcPo}, // [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION
+ {0x1740, 0x1751, prAL, gcLo}, // [18] BUHID LETTER A..BUHID LETTER HA
+ {0x1752, 0x1753, prCM, gcMn}, // [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U
+ {0x1760, 0x176C, prAL, gcLo}, // [13] TAGBANWA LETTER A..TAGBANWA LETTER YA
+ {0x176E, 0x1770, prAL, gcLo}, // [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA
+ {0x1772, 0x1773, prCM, gcMn}, // [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U
+ {0x1780, 0x17B3, prSA, gcLo}, // [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU
+ {0x17B4, 0x17B5, prSA, gcMn}, // [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+ {0x17B6, 0x17B6, prSA, gcMc}, // KHMER VOWEL SIGN AA
+ {0x17B7, 0x17BD, prSA, gcMn}, // [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA
+ {0x17BE, 0x17C5, prSA, gcMc}, // [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU
+ {0x17C6, 0x17C6, prSA, gcMn}, // KHMER SIGN NIKAHIT
+ {0x17C7, 0x17C8, prSA, gcMc}, // [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU
+ {0x17C9, 0x17D3, prSA, gcMn}, // [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT
+ {0x17D4, 0x17D5, prBA, gcPo}, // [2] KHMER SIGN KHAN..KHMER SIGN BARIYOOSAN
+ {0x17D6, 0x17D6, prNS, gcPo}, // KHMER SIGN CAMNUC PII KUUH
+ {0x17D7, 0x17D7, prSA, gcLm}, // KHMER SIGN LEK TOO
+ {0x17D8, 0x17D8, prBA, gcPo}, // KHMER SIGN BEYYAL
+ {0x17D9, 0x17D9, prAL, gcPo}, // KHMER SIGN PHNAEK MUAN
+ {0x17DA, 0x17DA, prBA, gcPo}, // KHMER SIGN KOOMUUT
+ {0x17DB, 0x17DB, prPR, gcSc}, // KHMER CURRENCY SYMBOL RIEL
+ {0x17DC, 0x17DC, prSA, gcLo}, // KHMER SIGN AVAKRAHASANYA
+ {0x17DD, 0x17DD, prSA, gcMn}, // KHMER SIGN ATTHACAN
+ {0x17E0, 0x17E9, prNU, gcNd}, // [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
+ {0x17F0, 0x17F9, prAL, gcNo}, // [10] KHMER SYMBOL LEK ATTAK SON..KHMER SYMBOL LEK ATTAK PRAM-BUON
+ {0x1800, 0x1801, prAL, gcPo}, // [2] MONGOLIAN BIRGA..MONGOLIAN ELLIPSIS
+ {0x1802, 0x1803, prEX, gcPo}, // [2] MONGOLIAN COMMA..MONGOLIAN FULL STOP
+ {0x1804, 0x1805, prBA, gcPo}, // [2] MONGOLIAN COLON..MONGOLIAN FOUR DOTS
+ {0x1806, 0x1806, prBB, gcPd}, // MONGOLIAN TODO SOFT HYPHEN
+ {0x1807, 0x1807, prAL, gcPo}, // MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER
+ {0x1808, 0x1809, prEX, gcPo}, // [2] MONGOLIAN MANCHU COMMA..MONGOLIAN MANCHU FULL STOP
+ {0x180A, 0x180A, prAL, gcPo}, // MONGOLIAN NIRUGU
+ {0x180B, 0x180D, prCM, gcMn}, // [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+ {0x180E, 0x180E, prGL, gcCf}, // MONGOLIAN VOWEL SEPARATOR
+ {0x180F, 0x180F, prCM, gcMn}, // MONGOLIAN FREE VARIATION SELECTOR FOUR
+ {0x1810, 0x1819, prNU, gcNd}, // [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
+ {0x1820, 0x1842, prAL, gcLo}, // [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI
+ {0x1843, 0x1843, prAL, gcLm}, // MONGOLIAN LETTER TODO LONG VOWEL SIGN
+ {0x1844, 0x1878, prAL, gcLo}, // [53] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER CHA WITH TWO DOTS
+ {0x1880, 0x1884, prAL, gcLo}, // [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA
+ {0x1885, 0x1886, prCM, gcMn}, // [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
+ {0x1887, 0x18A8, prAL, gcLo}, // [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA
+ {0x18A9, 0x18A9, prCM, gcMn}, // MONGOLIAN LETTER ALI GALI DAGALGA
+ {0x18AA, 0x18AA, prAL, gcLo}, // MONGOLIAN LETTER MANCHU ALI GALI LHA
+ {0x18B0, 0x18F5, prAL, gcLo}, // [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S
+ {0x1900, 0x191E, prAL, gcLo}, // [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA
+ {0x1920, 0x1922, prCM, gcMn}, // [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U
+ {0x1923, 0x1926, prCM, gcMc}, // [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU
+ {0x1927, 0x1928, prCM, gcMn}, // [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O
+ {0x1929, 0x192B, prCM, gcMc}, // [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA
+ {0x1930, 0x1931, prCM, gcMc}, // [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA
+ {0x1932, 0x1932, prCM, gcMn}, // LIMBU SMALL LETTER ANUSVARA
+ {0x1933, 0x1938, prCM, gcMc}, // [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA
+ {0x1939, 0x193B, prCM, gcMn}, // [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I
+ {0x1940, 0x1940, prAL, gcSo}, // LIMBU SIGN LOO
+ {0x1944, 0x1945, prEX, gcPo}, // [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK
+ {0x1946, 0x194F, prNU, gcNd}, // [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
+ {0x1950, 0x196D, prSA, gcLo}, // [30] TAI LE LETTER KA..TAI LE LETTER AI
+ {0x1970, 0x1974, prSA, gcLo}, // [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6
+ {0x1980, 0x19AB, prSA, gcLo}, // [44] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW SUA
+ {0x19B0, 0x19C9, prSA, gcLo}, // [26] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE TONE MARK-2
+ {0x19D0, 0x19D9, prNU, gcNd}, // [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
+ {0x19DA, 0x19DA, prSA, gcNo}, // NEW TAI LUE THAM DIGIT ONE
+ {0x19DE, 0x19DF, prSA, gcSo}, // [2] NEW TAI LUE SIGN LAE..NEW TAI LUE SIGN LAEV
+ {0x19E0, 0x19FF, prAL, gcSo}, // [32] KHMER SYMBOL PATHAMASAT..KHMER SYMBOL DAP-PRAM ROC
+ {0x1A00, 0x1A16, prAL, gcLo}, // [23] BUGINESE LETTER KA..BUGINESE LETTER HA
+ {0x1A17, 0x1A18, prCM, gcMn}, // [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U
+ {0x1A19, 0x1A1A, prCM, gcMc}, // [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O
+ {0x1A1B, 0x1A1B, prCM, gcMn}, // BUGINESE VOWEL SIGN AE
+ {0x1A1E, 0x1A1F, prAL, gcPo}, // [2] BUGINESE PALLAWA..BUGINESE END OF SECTION
+ {0x1A20, 0x1A54, prSA, gcLo}, // [53] TAI THAM LETTER HIGH KA..TAI THAM LETTER GREAT SA
+ {0x1A55, 0x1A55, prSA, gcMc}, // TAI THAM CONSONANT SIGN MEDIAL RA
+ {0x1A56, 0x1A56, prSA, gcMn}, // TAI THAM CONSONANT SIGN MEDIAL LA
+ {0x1A57, 0x1A57, prSA, gcMc}, // TAI THAM CONSONANT SIGN LA TANG LAI
+ {0x1A58, 0x1A5E, prSA, gcMn}, // [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA
+ {0x1A60, 0x1A60, prSA, gcMn}, // TAI THAM SIGN SAKOT
+ {0x1A61, 0x1A61, prSA, gcMc}, // TAI THAM VOWEL SIGN A
+ {0x1A62, 0x1A62, prSA, gcMn}, // TAI THAM VOWEL SIGN MAI SAT
+ {0x1A63, 0x1A64, prSA, gcMc}, // [2] TAI THAM VOWEL SIGN AA..TAI THAM VOWEL SIGN TALL AA
+ {0x1A65, 0x1A6C, prSA, gcMn}, // [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW
+ {0x1A6D, 0x1A72, prSA, gcMc}, // [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI
+ {0x1A73, 0x1A7C, prSA, gcMn}, // [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN
+ {0x1A7F, 0x1A7F, prCM, gcMn}, // TAI THAM COMBINING CRYPTOGRAMMIC DOT
+ {0x1A80, 0x1A89, prNU, gcNd}, // [10] TAI THAM HORA DIGIT ZERO..TAI THAM HORA DIGIT NINE
+ {0x1A90, 0x1A99, prNU, gcNd}, // [10] TAI THAM THAM DIGIT ZERO..TAI THAM THAM DIGIT NINE
+ {0x1AA0, 0x1AA6, prSA, gcPo}, // [7] TAI THAM SIGN WIANG..TAI THAM SIGN REVERSED ROTATED RANA
+ {0x1AA7, 0x1AA7, prSA, gcLm}, // TAI THAM SIGN MAI YAMOK
+ {0x1AA8, 0x1AAD, prSA, gcPo}, // [6] TAI THAM SIGN KAAN..TAI THAM SIGN CAANG
+ {0x1AB0, 0x1ABD, prCM, gcMn}, // [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW
+ {0x1ABE, 0x1ABE, prCM, gcMe}, // COMBINING PARENTHESES OVERLAY
+ {0x1ABF, 0x1ACE, prCM, gcMn}, // [16] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER INSULAR T
+ {0x1B00, 0x1B03, prCM, gcMn}, // [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
+ {0x1B04, 0x1B04, prCM, gcMc}, // BALINESE SIGN BISAH
+ {0x1B05, 0x1B33, prAL, gcLo}, // [47] BALINESE LETTER AKARA..BALINESE LETTER HA
+ {0x1B34, 0x1B34, prCM, gcMn}, // BALINESE SIGN REREKAN
+ {0x1B35, 0x1B35, prCM, gcMc}, // BALINESE VOWEL SIGN TEDUNG
+ {0x1B36, 0x1B3A, prCM, gcMn}, // [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA
+ {0x1B3B, 0x1B3B, prCM, gcMc}, // BALINESE VOWEL SIGN RA REPA TEDUNG
+ {0x1B3C, 0x1B3C, prCM, gcMn}, // BALINESE VOWEL SIGN LA LENGA
+ {0x1B3D, 0x1B41, prCM, gcMc}, // [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG
+ {0x1B42, 0x1B42, prCM, gcMn}, // BALINESE VOWEL SIGN PEPET
+ {0x1B43, 0x1B44, prCM, gcMc}, // [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG
+ {0x1B45, 0x1B4C, prAL, gcLo}, // [8] BALINESE LETTER KAF SASAK..BALINESE LETTER ARCHAIC JNYA
+ {0x1B50, 0x1B59, prNU, gcNd}, // [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
+ {0x1B5A, 0x1B5B, prBA, gcPo}, // [2] BALINESE PANTI..BALINESE PAMADA
+ {0x1B5C, 0x1B5C, prAL, gcPo}, // BALINESE WINDU
+ {0x1B5D, 0x1B60, prBA, gcPo}, // [4] BALINESE CARIK PAMUNGKAH..BALINESE PAMENENG
+ {0x1B61, 0x1B6A, prAL, gcSo}, // [10] BALINESE MUSICAL SYMBOL DONG..BALINESE MUSICAL SYMBOL DANG GEDE
+ {0x1B6B, 0x1B73, prCM, gcMn}, // [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
+ {0x1B74, 0x1B7C, prAL, gcSo}, // [9] BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG..BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING
+ {0x1B7D, 0x1B7E, prBA, gcPo}, // [2] BALINESE PANTI LANTANG..BALINESE PAMADA LANTANG
+ {0x1B80, 0x1B81, prCM, gcMn}, // [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR
+ {0x1B82, 0x1B82, prCM, gcMc}, // SUNDANESE SIGN PANGWISAD
+ {0x1B83, 0x1BA0, prAL, gcLo}, // [30] SUNDANESE LETTER A..SUNDANESE LETTER HA
+ {0x1BA1, 0x1BA1, prCM, gcMc}, // SUNDANESE CONSONANT SIGN PAMINGKAL
+ {0x1BA2, 0x1BA5, prCM, gcMn}, // [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU
+ {0x1BA6, 0x1BA7, prCM, gcMc}, // [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG
+ {0x1BA8, 0x1BA9, prCM, gcMn}, // [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
+ {0x1BAA, 0x1BAA, prCM, gcMc}, // SUNDANESE SIGN PAMAAEH
+ {0x1BAB, 0x1BAD, prCM, gcMn}, // [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA
+ {0x1BAE, 0x1BAF, prAL, gcLo}, // [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA
+ {0x1BB0, 0x1BB9, prNU, gcNd}, // [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
+ {0x1BBA, 0x1BBF, prAL, gcLo}, // [6] SUNDANESE AVAGRAHA..SUNDANESE LETTER FINAL M
+ {0x1BC0, 0x1BE5, prAL, gcLo}, // [38] BATAK LETTER A..BATAK LETTER U
+ {0x1BE6, 0x1BE6, prCM, gcMn}, // BATAK SIGN TOMPI
+ {0x1BE7, 0x1BE7, prCM, gcMc}, // BATAK VOWEL SIGN E
+ {0x1BE8, 0x1BE9, prCM, gcMn}, // [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE
+ {0x1BEA, 0x1BEC, prCM, gcMc}, // [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O
+ {0x1BED, 0x1BED, prCM, gcMn}, // BATAK VOWEL SIGN KARO O
+ {0x1BEE, 0x1BEE, prCM, gcMc}, // BATAK VOWEL SIGN U
+ {0x1BEF, 0x1BF1, prCM, gcMn}, // [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H
+ {0x1BF2, 0x1BF3, prCM, gcMc}, // [2] BATAK PANGOLAT..BATAK PANONGONAN
+ {0x1BFC, 0x1BFF, prAL, gcPo}, // [4] BATAK SYMBOL BINDU NA METEK..BATAK SYMBOL BINDU PANGOLAT
+ {0x1C00, 0x1C23, prAL, gcLo}, // [36] LEPCHA LETTER KA..LEPCHA LETTER A
+ {0x1C24, 0x1C2B, prCM, gcMc}, // [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU
+ {0x1C2C, 0x1C33, prCM, gcMn}, // [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T
+ {0x1C34, 0x1C35, prCM, gcMc}, // [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG
+ {0x1C36, 0x1C37, prCM, gcMn}, // [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA
+ {0x1C3B, 0x1C3F, prBA, gcPo}, // [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK
+ {0x1C40, 0x1C49, prNU, gcNd}, // [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
+ {0x1C4D, 0x1C4F, prAL, gcLo}, // [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA
+ {0x1C50, 0x1C59, prNU, gcNd}, // [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
+ {0x1C5A, 0x1C77, prAL, gcLo}, // [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH
+ {0x1C78, 0x1C7D, prAL, gcLm}, // [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD
+ {0x1C7E, 0x1C7F, prBA, gcPo}, // [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD
+ {0x1C80, 0x1C88, prAL, gcLl}, // [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK
+ {0x1C90, 0x1CBA, prAL, gcLu}, // [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN
+ {0x1CBD, 0x1CBF, prAL, gcLu}, // [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN
+ {0x1CC0, 0x1CC7, prAL, gcPo}, // [8] SUNDANESE PUNCTUATION BINDU SURYA..SUNDANESE PUNCTUATION BINDU BA SATANGA
+ {0x1CD0, 0x1CD2, prCM, gcMn}, // [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA
+ {0x1CD3, 0x1CD3, prAL, gcPo}, // VEDIC SIGN NIHSHVASA
+ {0x1CD4, 0x1CE0, prCM, gcMn}, // [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA
+ {0x1CE1, 0x1CE1, prCM, gcMc}, // VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA
+ {0x1CE2, 0x1CE8, prCM, gcMn}, // [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL
+ {0x1CE9, 0x1CEC, prAL, gcLo}, // [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL
+ {0x1CED, 0x1CED, prCM, gcMn}, // VEDIC SIGN TIRYAK
+ {0x1CEE, 0x1CF3, prAL, gcLo}, // [6] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ROTATED ARDHAVISARGA
+ {0x1CF4, 0x1CF4, prCM, gcMn}, // VEDIC TONE CANDRA ABOVE
+ {0x1CF5, 0x1CF6, prAL, gcLo}, // [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA
+ {0x1CF7, 0x1CF7, prCM, gcMc}, // VEDIC SIGN ATIKRAMA
+ {0x1CF8, 0x1CF9, prCM, gcMn}, // [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
+ {0x1CFA, 0x1CFA, prAL, gcLo}, // VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA
+ {0x1D00, 0x1D2B, prAL, gcLl}, // [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL
+ {0x1D2C, 0x1D6A, prAL, gcLm}, // [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI
+ {0x1D6B, 0x1D77, prAL, gcLl}, // [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G
+ {0x1D78, 0x1D78, prAL, gcLm}, // MODIFIER LETTER CYRILLIC EN
+ {0x1D79, 0x1D7F, prAL, gcLl}, // [7] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER UPSILON WITH STROKE
+ {0x1D80, 0x1D9A, prAL, gcLl}, // [27] LATIN SMALL LETTER B WITH PALATAL HOOK..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
+ {0x1D9B, 0x1DBF, prAL, gcLm}, // [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA
+ {0x1DC0, 0x1DCC, prCM, gcMn}, // [13] COMBINING DOTTED GRAVE ACCENT..COMBINING MACRON-BREVE
+ {0x1DCD, 0x1DCD, prGL, gcMn}, // COMBINING DOUBLE CIRCUMFLEX ABOVE
+ {0x1DCE, 0x1DFB, prCM, gcMn}, // [46] COMBINING OGONEK ABOVE..COMBINING DELETION MARK
+ {0x1DFC, 0x1DFC, prGL, gcMn}, // COMBINING DOUBLE INVERTED BREVE BELOW
+ {0x1DFD, 0x1DFF, prCM, gcMn}, // [3] COMBINING ALMOST EQUAL TO BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
+ {0x1E00, 0x1EFF, prAL, gcLC}, // [256] LATIN CAPITAL LETTER A WITH RING BELOW..LATIN SMALL LETTER Y WITH LOOP
+ {0x1F00, 0x1F15, prAL, gcLC}, // [22] GREEK SMALL LETTER ALPHA WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+ {0x1F18, 0x1F1D, prAL, gcLu}, // [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+ {0x1F20, 0x1F45, prAL, gcLC}, // [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+ {0x1F48, 0x1F4D, prAL, gcLu}, // [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+ {0x1F50, 0x1F57, prAL, gcLl}, // [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+ {0x1F59, 0x1F59, prAL, gcLu}, // GREEK CAPITAL LETTER UPSILON WITH DASIA
+ {0x1F5B, 0x1F5B, prAL, gcLu}, // GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+ {0x1F5D, 0x1F5D, prAL, gcLu}, // GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+ {0x1F5F, 0x1F7D, prAL, gcLC}, // [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA
+ {0x1F80, 0x1FB4, prAL, gcLC}, // [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+ {0x1FB6, 0x1FBC, prAL, gcLC}, // [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+ {0x1FBD, 0x1FBD, prAL, gcSk}, // GREEK KORONIS
+ {0x1FBE, 0x1FBE, prAL, gcLl}, // GREEK PROSGEGRAMMENI
+ {0x1FBF, 0x1FC1, prAL, gcSk}, // [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI
+ {0x1FC2, 0x1FC4, prAL, gcLl}, // [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+ {0x1FC6, 0x1FCC, prAL, gcLC}, // [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+ {0x1FCD, 0x1FCF, prAL, gcSk}, // [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI
+ {0x1FD0, 0x1FD3, prAL, gcLl}, // [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+ {0x1FD6, 0x1FDB, prAL, gcLC}, // [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA
+ {0x1FDD, 0x1FDF, prAL, gcSk}, // [3] GREEK DASIA AND VARIA..GREEK DASIA AND PERISPOMENI
+ {0x1FE0, 0x1FEC, prAL, gcLC}, // [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+ {0x1FED, 0x1FEF, prAL, gcSk}, // [3] GREEK DIALYTIKA AND VARIA..GREEK VARIA
+ {0x1FF2, 0x1FF4, prAL, gcLl}, // [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+ {0x1FF6, 0x1FFC, prAL, gcLC}, // [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+ {0x1FFD, 0x1FFD, prBB, gcSk}, // GREEK OXIA
+ {0x1FFE, 0x1FFE, prAL, gcSk}, // GREEK DASIA
+ {0x2000, 0x2006, prBA, gcZs}, // [7] EN QUAD..SIX-PER-EM SPACE
+ {0x2007, 0x2007, prGL, gcZs}, // FIGURE SPACE
+ {0x2008, 0x200A, prBA, gcZs}, // [3] PUNCTUATION SPACE..HAIR SPACE
+ {0x200B, 0x200B, prZW, gcCf}, // ZERO WIDTH SPACE
+ {0x200C, 0x200C, prCM, gcCf}, // ZERO WIDTH NON-JOINER
+ {0x200D, 0x200D, prZWJ, gcCf}, // ZERO WIDTH JOINER
+ {0x200E, 0x200F, prCM, gcCf}, // [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK
+ {0x2010, 0x2010, prBA, gcPd}, // HYPHEN
+ {0x2011, 0x2011, prGL, gcPd}, // NON-BREAKING HYPHEN
+ {0x2012, 0x2013, prBA, gcPd}, // [2] FIGURE DASH..EN DASH
+ {0x2014, 0x2014, prB2, gcPd}, // EM DASH
+ {0x2015, 0x2015, prAI, gcPd}, // HORIZONTAL BAR
+ {0x2016, 0x2016, prAI, gcPo}, // DOUBLE VERTICAL LINE
+ {0x2017, 0x2017, prAL, gcPo}, // DOUBLE LOW LINE
+ {0x2018, 0x2018, prQU, gcPi}, // LEFT SINGLE QUOTATION MARK
+ {0x2019, 0x2019, prQU, gcPf}, // RIGHT SINGLE QUOTATION MARK
+ {0x201A, 0x201A, prOP, gcPs}, // SINGLE LOW-9 QUOTATION MARK
+ {0x201B, 0x201C, prQU, gcPi}, // [2] SINGLE HIGH-REVERSED-9 QUOTATION MARK..LEFT DOUBLE QUOTATION MARK
+ {0x201D, 0x201D, prQU, gcPf}, // RIGHT DOUBLE QUOTATION MARK
+ {0x201E, 0x201E, prOP, gcPs}, // DOUBLE LOW-9 QUOTATION MARK
+ {0x201F, 0x201F, prQU, gcPi}, // DOUBLE HIGH-REVERSED-9 QUOTATION MARK
+ {0x2020, 0x2021, prAI, gcPo}, // [2] DAGGER..DOUBLE DAGGER
+ {0x2022, 0x2023, prAL, gcPo}, // [2] BULLET..TRIANGULAR BULLET
+ {0x2024, 0x2026, prIN, gcPo}, // [3] ONE DOT LEADER..HORIZONTAL ELLIPSIS
+ {0x2027, 0x2027, prBA, gcPo}, // HYPHENATION POINT
+ {0x2028, 0x2028, prBK, gcZl}, // LINE SEPARATOR
+ {0x2029, 0x2029, prBK, gcZp}, // PARAGRAPH SEPARATOR
+ {0x202A, 0x202E, prCM, gcCf}, // [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
+ {0x202F, 0x202F, prGL, gcZs}, // NARROW NO-BREAK SPACE
+ {0x2030, 0x2037, prPO, gcPo}, // [8] PER MILLE SIGN..REVERSED TRIPLE PRIME
+ {0x2038, 0x2038, prAL, gcPo}, // CARET
+ {0x2039, 0x2039, prQU, gcPi}, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ {0x203A, 0x203A, prQU, gcPf}, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ {0x203B, 0x203B, prAI, gcPo}, // REFERENCE MARK
+ {0x203C, 0x203D, prNS, gcPo}, // [2] DOUBLE EXCLAMATION MARK..INTERROBANG
+ {0x203E, 0x203E, prAL, gcPo}, // OVERLINE
+ {0x203F, 0x2040, prAL, gcPc}, // [2] UNDERTIE..CHARACTER TIE
+ {0x2041, 0x2043, prAL, gcPo}, // [3] CARET INSERTION POINT..HYPHEN BULLET
+ {0x2044, 0x2044, prIS, gcSm}, // FRACTION SLASH
+ {0x2045, 0x2045, prOP, gcPs}, // LEFT SQUARE BRACKET WITH QUILL
+ {0x2046, 0x2046, prCL, gcPe}, // RIGHT SQUARE BRACKET WITH QUILL
+ {0x2047, 0x2049, prNS, gcPo}, // [3] DOUBLE QUESTION MARK..EXCLAMATION QUESTION MARK
+ {0x204A, 0x2051, prAL, gcPo}, // [8] TIRONIAN SIGN ET..TWO ASTERISKS ALIGNED VERTICALLY
+ {0x2052, 0x2052, prAL, gcSm}, // COMMERCIAL MINUS SIGN
+ {0x2053, 0x2053, prAL, gcPo}, // SWUNG DASH
+ {0x2054, 0x2054, prAL, gcPc}, // INVERTED UNDERTIE
+ {0x2055, 0x2055, prAL, gcPo}, // FLOWER PUNCTUATION MARK
+ {0x2056, 0x2056, prBA, gcPo}, // THREE DOT PUNCTUATION
+ {0x2057, 0x2057, prPO, gcPo}, // QUADRUPLE PRIME
+ {0x2058, 0x205B, prBA, gcPo}, // [4] FOUR DOT PUNCTUATION..FOUR DOT MARK
+ {0x205C, 0x205C, prAL, gcPo}, // DOTTED CROSS
+ {0x205D, 0x205E, prBA, gcPo}, // [2] TRICOLON..VERTICAL FOUR DOTS
+ {0x205F, 0x205F, prBA, gcZs}, // MEDIUM MATHEMATICAL SPACE
+ {0x2060, 0x2060, prWJ, gcCf}, // WORD JOINER
+ {0x2061, 0x2064, prAL, gcCf}, // [4] FUNCTION APPLICATION..INVISIBLE PLUS
+ {0x2066, 0x206F, prCM, gcCf}, // [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES
+ {0x2070, 0x2070, prAL, gcNo}, // SUPERSCRIPT ZERO
+ {0x2071, 0x2071, prAL, gcLm}, // SUPERSCRIPT LATIN SMALL LETTER I
+ {0x2074, 0x2074, prAI, gcNo}, // SUPERSCRIPT FOUR
+ {0x2075, 0x2079, prAL, gcNo}, // [5] SUPERSCRIPT FIVE..SUPERSCRIPT NINE
+ {0x207A, 0x207C, prAL, gcSm}, // [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN
+ {0x207D, 0x207D, prOP, gcPs}, // SUPERSCRIPT LEFT PARENTHESIS
+ {0x207E, 0x207E, prCL, gcPe}, // SUPERSCRIPT RIGHT PARENTHESIS
+ {0x207F, 0x207F, prAI, gcLm}, // SUPERSCRIPT LATIN SMALL LETTER N
+ {0x2080, 0x2080, prAL, gcNo}, // SUBSCRIPT ZERO
+ {0x2081, 0x2084, prAI, gcNo}, // [4] SUBSCRIPT ONE..SUBSCRIPT FOUR
+ {0x2085, 0x2089, prAL, gcNo}, // [5] SUBSCRIPT FIVE..SUBSCRIPT NINE
+ {0x208A, 0x208C, prAL, gcSm}, // [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN
+ {0x208D, 0x208D, prOP, gcPs}, // SUBSCRIPT LEFT PARENTHESIS
+ {0x208E, 0x208E, prCL, gcPe}, // SUBSCRIPT RIGHT PARENTHESIS
+ {0x2090, 0x209C, prAL, gcLm}, // [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T
+ {0x20A0, 0x20A6, prPR, gcSc}, // [7] EURO-CURRENCY SIGN..NAIRA SIGN
+ {0x20A7, 0x20A7, prPO, gcSc}, // PESETA SIGN
+ {0x20A8, 0x20B5, prPR, gcSc}, // [14] RUPEE SIGN..CEDI SIGN
+ {0x20B6, 0x20B6, prPO, gcSc}, // LIVRE TOURNOIS SIGN
+ {0x20B7, 0x20BA, prPR, gcSc}, // [4] SPESMILO SIGN..TURKISH LIRA SIGN
+ {0x20BB, 0x20BB, prPO, gcSc}, // NORDIC MARK SIGN
+ {0x20BC, 0x20BD, prPR, gcSc}, // [2] MANAT SIGN..RUBLE SIGN
+ {0x20BE, 0x20BE, prPO, gcSc}, // LARI SIGN
+ {0x20BF, 0x20BF, prPR, gcSc}, // BITCOIN SIGN
+ {0x20C0, 0x20C0, prPO, gcSc}, // SOM SIGN
+ {0x20C1, 0x20CF, prPR, gcCn}, // [15] ..
+ {0x20D0, 0x20DC, prCM, gcMn}, // [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE
+ {0x20DD, 0x20E0, prCM, gcMe}, // [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH
+ {0x20E1, 0x20E1, prCM, gcMn}, // COMBINING LEFT RIGHT ARROW ABOVE
+ {0x20E2, 0x20E4, prCM, gcMe}, // [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE
+ {0x20E5, 0x20F0, prCM, gcMn}, // [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE
+ {0x2100, 0x2101, prAL, gcSo}, // [2] ACCOUNT OF..ADDRESSED TO THE SUBJECT
+ {0x2102, 0x2102, prAL, gcLu}, // DOUBLE-STRUCK CAPITAL C
+ {0x2103, 0x2103, prPO, gcSo}, // DEGREE CELSIUS
+ {0x2104, 0x2104, prAL, gcSo}, // CENTRE LINE SYMBOL
+ {0x2105, 0x2105, prAI, gcSo}, // CARE OF
+ {0x2106, 0x2106, prAL, gcSo}, // CADA UNA
+ {0x2107, 0x2107, prAL, gcLu}, // EULER CONSTANT
+ {0x2108, 0x2108, prAL, gcSo}, // SCRUPLE
+ {0x2109, 0x2109, prPO, gcSo}, // DEGREE FAHRENHEIT
+ {0x210A, 0x2112, prAL, gcLC}, // [9] SCRIPT SMALL G..SCRIPT CAPITAL L
+ {0x2113, 0x2113, prAI, gcLl}, // SCRIPT SMALL L
+ {0x2114, 0x2114, prAL, gcSo}, // L B BAR SYMBOL
+ {0x2115, 0x2115, prAL, gcLu}, // DOUBLE-STRUCK CAPITAL N
+ {0x2116, 0x2116, prPR, gcSo}, // NUMERO SIGN
+ {0x2117, 0x2117, prAL, gcSo}, // SOUND RECORDING COPYRIGHT
+ {0x2118, 0x2118, prAL, gcSm}, // SCRIPT CAPITAL P
+ {0x2119, 0x211D, prAL, gcLu}, // [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R
+ {0x211E, 0x2120, prAL, gcSo}, // [3] PRESCRIPTION TAKE..SERVICE MARK
+ {0x2121, 0x2122, prAI, gcSo}, // [2] TELEPHONE SIGN..TRADE MARK SIGN
+ {0x2123, 0x2123, prAL, gcSo}, // VERSICLE
+ {0x2124, 0x2124, prAL, gcLu}, // DOUBLE-STRUCK CAPITAL Z
+ {0x2125, 0x2125, prAL, gcSo}, // OUNCE SIGN
+ {0x2126, 0x2126, prAL, gcLu}, // OHM SIGN
+ {0x2127, 0x2127, prAL, gcSo}, // INVERTED OHM SIGN
+ {0x2128, 0x2128, prAL, gcLu}, // BLACK-LETTER CAPITAL Z
+ {0x2129, 0x2129, prAL, gcSo}, // TURNED GREEK SMALL LETTER IOTA
+ {0x212A, 0x212A, prAL, gcLu}, // KELVIN SIGN
+ {0x212B, 0x212B, prAI, gcLu}, // ANGSTROM SIGN
+ {0x212C, 0x212D, prAL, gcLu}, // [2] SCRIPT CAPITAL B..BLACK-LETTER CAPITAL C
+ {0x212E, 0x212E, prAL, gcSo}, // ESTIMATED SYMBOL
+ {0x212F, 0x2134, prAL, gcLC}, // [6] SCRIPT SMALL E..SCRIPT SMALL O
+ {0x2135, 0x2138, prAL, gcLo}, // [4] ALEF SYMBOL..DALET SYMBOL
+ {0x2139, 0x2139, prAL, gcLl}, // INFORMATION SOURCE
+ {0x213A, 0x213B, prAL, gcSo}, // [2] ROTATED CAPITAL Q..FACSIMILE SIGN
+ {0x213C, 0x213F, prAL, gcLC}, // [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI
+ {0x2140, 0x2144, prAL, gcSm}, // [5] DOUBLE-STRUCK N-ARY SUMMATION..TURNED SANS-SERIF CAPITAL Y
+ {0x2145, 0x2149, prAL, gcLC}, // [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J
+ {0x214A, 0x214A, prAL, gcSo}, // PROPERTY LINE
+ {0x214B, 0x214B, prAL, gcSm}, // TURNED AMPERSAND
+ {0x214C, 0x214D, prAL, gcSo}, // [2] PER SIGN..AKTIESELSKAB
+ {0x214E, 0x214E, prAL, gcLl}, // TURNED SMALL F
+ {0x214F, 0x214F, prAL, gcSo}, // SYMBOL FOR SAMARITAN SOURCE
+ {0x2150, 0x2153, prAL, gcNo}, // [4] VULGAR FRACTION ONE SEVENTH..VULGAR FRACTION ONE THIRD
+ {0x2154, 0x2155, prAI, gcNo}, // [2] VULGAR FRACTION TWO THIRDS..VULGAR FRACTION ONE FIFTH
+ {0x2156, 0x215A, prAL, gcNo}, // [5] VULGAR FRACTION TWO FIFTHS..VULGAR FRACTION FIVE SIXTHS
+ {0x215B, 0x215B, prAI, gcNo}, // VULGAR FRACTION ONE EIGHTH
+ {0x215C, 0x215D, prAL, gcNo}, // [2] VULGAR FRACTION THREE EIGHTHS..VULGAR FRACTION FIVE EIGHTHS
+ {0x215E, 0x215E, prAI, gcNo}, // VULGAR FRACTION SEVEN EIGHTHS
+ {0x215F, 0x215F, prAL, gcNo}, // FRACTION NUMERATOR ONE
+ {0x2160, 0x216B, prAI, gcNl}, // [12] ROMAN NUMERAL ONE..ROMAN NUMERAL TWELVE
+ {0x216C, 0x216F, prAL, gcNl}, // [4] ROMAN NUMERAL FIFTY..ROMAN NUMERAL ONE THOUSAND
+ {0x2170, 0x2179, prAI, gcNl}, // [10] SMALL ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL TEN
+ {0x217A, 0x2182, prAL, gcNl}, // [9] SMALL ROMAN NUMERAL ELEVEN..ROMAN NUMERAL TEN THOUSAND
+ {0x2183, 0x2184, prAL, gcLC}, // [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C
+ {0x2185, 0x2188, prAL, gcNl}, // [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND
+ {0x2189, 0x2189, prAI, gcNo}, // VULGAR FRACTION ZERO THIRDS
+ {0x218A, 0x218B, prAL, gcSo}, // [2] TURNED DIGIT TWO..TURNED DIGIT THREE
+ {0x2190, 0x2194, prAI, gcSm}, // [5] LEFTWARDS ARROW..LEFT RIGHT ARROW
+ {0x2195, 0x2199, prAI, gcSo}, // [5] UP DOWN ARROW..SOUTH WEST ARROW
+ {0x219A, 0x219B, prAL, gcSm}, // [2] LEFTWARDS ARROW WITH STROKE..RIGHTWARDS ARROW WITH STROKE
+ {0x219C, 0x219F, prAL, gcSo}, // [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW
+ {0x21A0, 0x21A0, prAL, gcSm}, // RIGHTWARDS TWO HEADED ARROW
+ {0x21A1, 0x21A2, prAL, gcSo}, // [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL
+ {0x21A3, 0x21A3, prAL, gcSm}, // RIGHTWARDS ARROW WITH TAIL
+ {0x21A4, 0x21A5, prAL, gcSo}, // [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR
+ {0x21A6, 0x21A6, prAL, gcSm}, // RIGHTWARDS ARROW FROM BAR
+ {0x21A7, 0x21AD, prAL, gcSo}, // [7] DOWNWARDS ARROW FROM BAR..LEFT RIGHT WAVE ARROW
+ {0x21AE, 0x21AE, prAL, gcSm}, // LEFT RIGHT ARROW WITH STROKE
+ {0x21AF, 0x21CD, prAL, gcSo}, // [31] DOWNWARDS ZIGZAG ARROW..LEFTWARDS DOUBLE ARROW WITH STROKE
+ {0x21CE, 0x21CF, prAL, gcSm}, // [2] LEFT RIGHT DOUBLE ARROW WITH STROKE..RIGHTWARDS DOUBLE ARROW WITH STROKE
+ {0x21D0, 0x21D1, prAL, gcSo}, // [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW
+ {0x21D2, 0x21D2, prAI, gcSm}, // RIGHTWARDS DOUBLE ARROW
+ {0x21D3, 0x21D3, prAL, gcSo}, // DOWNWARDS DOUBLE ARROW
+ {0x21D4, 0x21D4, prAI, gcSm}, // LEFT RIGHT DOUBLE ARROW
+ {0x21D5, 0x21F3, prAL, gcSo}, // [31] UP DOWN DOUBLE ARROW..UP DOWN WHITE ARROW
+ {0x21F4, 0x21FF, prAL, gcSm}, // [12] RIGHT ARROW WITH SMALL CIRCLE..LEFT RIGHT OPEN-HEADED ARROW
+ {0x2200, 0x2200, prAI, gcSm}, // FOR ALL
+ {0x2201, 0x2201, prAL, gcSm}, // COMPLEMENT
+ {0x2202, 0x2203, prAI, gcSm}, // [2] PARTIAL DIFFERENTIAL..THERE EXISTS
+ {0x2204, 0x2206, prAL, gcSm}, // [3] THERE DOES NOT EXIST..INCREMENT
+ {0x2207, 0x2208, prAI, gcSm}, // [2] NABLA..ELEMENT OF
+ {0x2209, 0x220A, prAL, gcSm}, // [2] NOT AN ELEMENT OF..SMALL ELEMENT OF
+ {0x220B, 0x220B, prAI, gcSm}, // CONTAINS AS MEMBER
+ {0x220C, 0x220E, prAL, gcSm}, // [3] DOES NOT CONTAIN AS MEMBER..END OF PROOF
+ {0x220F, 0x220F, prAI, gcSm}, // N-ARY PRODUCT
+ {0x2210, 0x2210, prAL, gcSm}, // N-ARY COPRODUCT
+ {0x2211, 0x2211, prAI, gcSm}, // N-ARY SUMMATION
+ {0x2212, 0x2213, prPR, gcSm}, // [2] MINUS SIGN..MINUS-OR-PLUS SIGN
+ {0x2214, 0x2214, prAL, gcSm}, // DOT PLUS
+ {0x2215, 0x2215, prAI, gcSm}, // DIVISION SLASH
+ {0x2216, 0x2219, prAL, gcSm}, // [4] SET MINUS..BULLET OPERATOR
+ {0x221A, 0x221A, prAI, gcSm}, // SQUARE ROOT
+ {0x221B, 0x221C, prAL, gcSm}, // [2] CUBE ROOT..FOURTH ROOT
+ {0x221D, 0x2220, prAI, gcSm}, // [4] PROPORTIONAL TO..ANGLE
+ {0x2221, 0x2222, prAL, gcSm}, // [2] MEASURED ANGLE..SPHERICAL ANGLE
+ {0x2223, 0x2223, prAI, gcSm}, // DIVIDES
+ {0x2224, 0x2224, prAL, gcSm}, // DOES NOT DIVIDE
+ {0x2225, 0x2225, prAI, gcSm}, // PARALLEL TO
+ {0x2226, 0x2226, prAL, gcSm}, // NOT PARALLEL TO
+ {0x2227, 0x222C, prAI, gcSm}, // [6] LOGICAL AND..DOUBLE INTEGRAL
+ {0x222D, 0x222D, prAL, gcSm}, // TRIPLE INTEGRAL
+ {0x222E, 0x222E, prAI, gcSm}, // CONTOUR INTEGRAL
+ {0x222F, 0x2233, prAL, gcSm}, // [5] SURFACE INTEGRAL..ANTICLOCKWISE CONTOUR INTEGRAL
+ {0x2234, 0x2237, prAI, gcSm}, // [4] THEREFORE..PROPORTION
+ {0x2238, 0x223B, prAL, gcSm}, // [4] DOT MINUS..HOMOTHETIC
+ {0x223C, 0x223D, prAI, gcSm}, // [2] TILDE OPERATOR..REVERSED TILDE
+ {0x223E, 0x2247, prAL, gcSm}, // [10] INVERTED LAZY S..NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO
+ {0x2248, 0x2248, prAI, gcSm}, // ALMOST EQUAL TO
+ {0x2249, 0x224B, prAL, gcSm}, // [3] NOT ALMOST EQUAL TO..TRIPLE TILDE
+ {0x224C, 0x224C, prAI, gcSm}, // ALL EQUAL TO
+ {0x224D, 0x2251, prAL, gcSm}, // [5] EQUIVALENT TO..GEOMETRICALLY EQUAL TO
+ {0x2252, 0x2252, prAI, gcSm}, // APPROXIMATELY EQUAL TO OR THE IMAGE OF
+ {0x2253, 0x225F, prAL, gcSm}, // [13] IMAGE OF OR APPROXIMATELY EQUAL TO..QUESTIONED EQUAL TO
+ {0x2260, 0x2261, prAI, gcSm}, // [2] NOT EQUAL TO..IDENTICAL TO
+ {0x2262, 0x2263, prAL, gcSm}, // [2] NOT IDENTICAL TO..STRICTLY EQUIVALENT TO
+ {0x2264, 0x2267, prAI, gcSm}, // [4] LESS-THAN OR EQUAL TO..GREATER-THAN OVER EQUAL TO
+ {0x2268, 0x2269, prAL, gcSm}, // [2] LESS-THAN BUT NOT EQUAL TO..GREATER-THAN BUT NOT EQUAL TO
+ {0x226A, 0x226B, prAI, gcSm}, // [2] MUCH LESS-THAN..MUCH GREATER-THAN
+ {0x226C, 0x226D, prAL, gcSm}, // [2] BETWEEN..NOT EQUIVALENT TO
+ {0x226E, 0x226F, prAI, gcSm}, // [2] NOT LESS-THAN..NOT GREATER-THAN
+ {0x2270, 0x2281, prAL, gcSm}, // [18] NEITHER LESS-THAN NOR EQUAL TO..DOES NOT SUCCEED
+ {0x2282, 0x2283, prAI, gcSm}, // [2] SUBSET OF..SUPERSET OF
+ {0x2284, 0x2285, prAL, gcSm}, // [2] NOT A SUBSET OF..NOT A SUPERSET OF
+ {0x2286, 0x2287, prAI, gcSm}, // [2] SUBSET OF OR EQUAL TO..SUPERSET OF OR EQUAL TO
+ {0x2288, 0x2294, prAL, gcSm}, // [13] NEITHER A SUBSET OF NOR EQUAL TO..SQUARE CUP
+ {0x2295, 0x2295, prAI, gcSm}, // CIRCLED PLUS
+ {0x2296, 0x2298, prAL, gcSm}, // [3] CIRCLED MINUS..CIRCLED DIVISION SLASH
+ {0x2299, 0x2299, prAI, gcSm}, // CIRCLED DOT OPERATOR
+ {0x229A, 0x22A4, prAL, gcSm}, // [11] CIRCLED RING OPERATOR..DOWN TACK
+ {0x22A5, 0x22A5, prAI, gcSm}, // UP TACK
+ {0x22A6, 0x22BE, prAL, gcSm}, // [25] ASSERTION..RIGHT ANGLE WITH ARC
+ {0x22BF, 0x22BF, prAI, gcSm}, // RIGHT TRIANGLE
+ {0x22C0, 0x22EE, prAL, gcSm}, // [47] N-ARY LOGICAL AND..VERTICAL ELLIPSIS
+ {0x22EF, 0x22EF, prIN, gcSm}, // MIDLINE HORIZONTAL ELLIPSIS
+ {0x22F0, 0x22FF, prAL, gcSm}, // [16] UP RIGHT DIAGONAL ELLIPSIS..Z NOTATION BAG MEMBERSHIP
+ {0x2300, 0x2307, prAL, gcSo}, // [8] DIAMETER SIGN..WAVY LINE
+ {0x2308, 0x2308, prOP, gcPs}, // LEFT CEILING
+ {0x2309, 0x2309, prCL, gcPe}, // RIGHT CEILING
+ {0x230A, 0x230A, prOP, gcPs}, // LEFT FLOOR
+ {0x230B, 0x230B, prCL, gcPe}, // RIGHT FLOOR
+ {0x230C, 0x2311, prAL, gcSo}, // [6] BOTTOM RIGHT CROP..SQUARE LOZENGE
+ {0x2312, 0x2312, prAI, gcSo}, // ARC
+ {0x2313, 0x2319, prAL, gcSo}, // [7] SEGMENT..TURNED NOT SIGN
+ {0x231A, 0x231B, prID, gcSo}, // [2] WATCH..HOURGLASS
+ {0x231C, 0x231F, prAL, gcSo}, // [4] TOP LEFT CORNER..BOTTOM RIGHT CORNER
+ {0x2320, 0x2321, prAL, gcSm}, // [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL
+ {0x2322, 0x2328, prAL, gcSo}, // [7] FROWN..KEYBOARD
+ {0x2329, 0x2329, prOP, gcPs}, // LEFT-POINTING ANGLE BRACKET
+ {0x232A, 0x232A, prCL, gcPe}, // RIGHT-POINTING ANGLE BRACKET
+ {0x232B, 0x237B, prAL, gcSo}, // [81] ERASE TO THE LEFT..NOT CHECK MARK
+ {0x237C, 0x237C, prAL, gcSm}, // RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW
+ {0x237D, 0x239A, prAL, gcSo}, // [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL
+ {0x239B, 0x23B3, prAL, gcSm}, // [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM
+ {0x23B4, 0x23DB, prAL, gcSo}, // [40] TOP SQUARE BRACKET..FUSE
+ {0x23DC, 0x23E1, prAL, gcSm}, // [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET
+ {0x23E2, 0x23EF, prAL, gcSo}, // [14] WHITE TRAPEZIUM..BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR
+ {0x23F0, 0x23F3, prID, gcSo}, // [4] ALARM CLOCK..HOURGLASS WITH FLOWING SAND
+ {0x23F4, 0x23FF, prAL, gcSo}, // [12] BLACK MEDIUM LEFT-POINTING TRIANGLE..OBSERVER EYE SYMBOL
+ {0x2400, 0x2426, prAL, gcSo}, // [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO
+ {0x2440, 0x244A, prAL, gcSo}, // [11] OCR HOOK..OCR DOUBLE BACKSLASH
+ {0x2460, 0x249B, prAI, gcNo}, // [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP
+ {0x249C, 0x24E9, prAI, gcSo}, // [78] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z
+ {0x24EA, 0x24FE, prAI, gcNo}, // [21] CIRCLED DIGIT ZERO..DOUBLE CIRCLED NUMBER TEN
+ {0x24FF, 0x24FF, prAL, gcNo}, // NEGATIVE CIRCLED DIGIT ZERO
+ {0x2500, 0x254B, prAI, gcSo}, // [76] BOX DRAWINGS LIGHT HORIZONTAL..BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL
+ {0x254C, 0x254F, prAL, gcSo}, // [4] BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL..BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL
+ {0x2550, 0x2574, prAI, gcSo}, // [37] BOX DRAWINGS DOUBLE HORIZONTAL..BOX DRAWINGS LIGHT LEFT
+ {0x2575, 0x257F, prAL, gcSo}, // [11] BOX DRAWINGS LIGHT UP..BOX DRAWINGS HEAVY UP AND LIGHT DOWN
+ {0x2580, 0x258F, prAI, gcSo}, // [16] UPPER HALF BLOCK..LEFT ONE EIGHTH BLOCK
+ {0x2590, 0x2591, prAL, gcSo}, // [2] RIGHT HALF BLOCK..LIGHT SHADE
+ {0x2592, 0x2595, prAI, gcSo}, // [4] MEDIUM SHADE..RIGHT ONE EIGHTH BLOCK
+ {0x2596, 0x259F, prAL, gcSo}, // [10] QUADRANT LOWER LEFT..QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT
+ {0x25A0, 0x25A1, prAI, gcSo}, // [2] BLACK SQUARE..WHITE SQUARE
+ {0x25A2, 0x25A2, prAL, gcSo}, // WHITE SQUARE WITH ROUNDED CORNERS
+ {0x25A3, 0x25A9, prAI, gcSo}, // [7] WHITE SQUARE CONTAINING BLACK SMALL SQUARE..SQUARE WITH DIAGONAL CROSSHATCH FILL
+ {0x25AA, 0x25B1, prAL, gcSo}, // [8] BLACK SMALL SQUARE..WHITE PARALLELOGRAM
+ {0x25B2, 0x25B3, prAI, gcSo}, // [2] BLACK UP-POINTING TRIANGLE..WHITE UP-POINTING TRIANGLE
+ {0x25B4, 0x25B5, prAL, gcSo}, // [2] BLACK UP-POINTING SMALL TRIANGLE..WHITE UP-POINTING SMALL TRIANGLE
+ {0x25B6, 0x25B6, prAI, gcSo}, // BLACK RIGHT-POINTING TRIANGLE
+ {0x25B7, 0x25B7, prAI, gcSm}, // WHITE RIGHT-POINTING TRIANGLE
+ {0x25B8, 0x25BB, prAL, gcSo}, // [4] BLACK RIGHT-POINTING SMALL TRIANGLE..WHITE RIGHT-POINTING POINTER
+ {0x25BC, 0x25BD, prAI, gcSo}, // [2] BLACK DOWN-POINTING TRIANGLE..WHITE DOWN-POINTING TRIANGLE
+ {0x25BE, 0x25BF, prAL, gcSo}, // [2] BLACK DOWN-POINTING SMALL TRIANGLE..WHITE DOWN-POINTING SMALL TRIANGLE
+ {0x25C0, 0x25C0, prAI, gcSo}, // BLACK LEFT-POINTING TRIANGLE
+ {0x25C1, 0x25C1, prAI, gcSm}, // WHITE LEFT-POINTING TRIANGLE
+ {0x25C2, 0x25C5, prAL, gcSo}, // [4] BLACK LEFT-POINTING SMALL TRIANGLE..WHITE LEFT-POINTING POINTER
+ {0x25C6, 0x25C8, prAI, gcSo}, // [3] BLACK DIAMOND..WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND
+ {0x25C9, 0x25CA, prAL, gcSo}, // [2] FISHEYE..LOZENGE
+ {0x25CB, 0x25CB, prAI, gcSo}, // WHITE CIRCLE
+ {0x25CC, 0x25CD, prAL, gcSo}, // [2] DOTTED CIRCLE..CIRCLE WITH VERTICAL FILL
+ {0x25CE, 0x25D1, prAI, gcSo}, // [4] BULLSEYE..CIRCLE WITH RIGHT HALF BLACK
+ {0x25D2, 0x25E1, prAL, gcSo}, // [16] CIRCLE WITH LOWER HALF BLACK..LOWER HALF CIRCLE
+ {0x25E2, 0x25E5, prAI, gcSo}, // [4] BLACK LOWER RIGHT TRIANGLE..BLACK UPPER RIGHT TRIANGLE
+ {0x25E6, 0x25EE, prAL, gcSo}, // [9] WHITE BULLET..UP-POINTING TRIANGLE WITH RIGHT HALF BLACK
+ {0x25EF, 0x25EF, prAI, gcSo}, // LARGE CIRCLE
+ {0x25F0, 0x25F7, prAL, gcSo}, // [8] WHITE SQUARE WITH UPPER LEFT QUADRANT..WHITE CIRCLE WITH UPPER RIGHT QUADRANT
+ {0x25F8, 0x25FF, prAL, gcSm}, // [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE
+ {0x2600, 0x2603, prID, gcSo}, // [4] BLACK SUN WITH RAYS..SNOWMAN
+ {0x2604, 0x2604, prAL, gcSo}, // COMET
+ {0x2605, 0x2606, prAI, gcSo}, // [2] BLACK STAR..WHITE STAR
+ {0x2607, 0x2608, prAL, gcSo}, // [2] LIGHTNING..THUNDERSTORM
+ {0x2609, 0x2609, prAI, gcSo}, // SUN
+ {0x260A, 0x260D, prAL, gcSo}, // [4] ASCENDING NODE..OPPOSITION
+ {0x260E, 0x260F, prAI, gcSo}, // [2] BLACK TELEPHONE..WHITE TELEPHONE
+ {0x2610, 0x2613, prAL, gcSo}, // [4] BALLOT BOX..SALTIRE
+ {0x2614, 0x2615, prID, gcSo}, // [2] UMBRELLA WITH RAIN DROPS..HOT BEVERAGE
+ {0x2616, 0x2617, prAI, gcSo}, // [2] WHITE SHOGI PIECE..BLACK SHOGI PIECE
+ {0x2618, 0x2618, prID, gcSo}, // SHAMROCK
+ {0x2619, 0x2619, prAL, gcSo}, // REVERSED ROTATED FLORAL HEART BULLET
+ {0x261A, 0x261C, prID, gcSo}, // [3] BLACK LEFT POINTING INDEX..WHITE LEFT POINTING INDEX
+ {0x261D, 0x261D, prEB, gcSo}, // WHITE UP POINTING INDEX
+ {0x261E, 0x261F, prID, gcSo}, // [2] WHITE RIGHT POINTING INDEX..WHITE DOWN POINTING INDEX
+ {0x2620, 0x2638, prAL, gcSo}, // [25] SKULL AND CROSSBONES..WHEEL OF DHARMA
+ {0x2639, 0x263B, prID, gcSo}, // [3] WHITE FROWNING FACE..BLACK SMILING FACE
+ {0x263C, 0x263F, prAL, gcSo}, // [4] WHITE SUN WITH RAYS..MERCURY
+ {0x2640, 0x2640, prAI, gcSo}, // FEMALE SIGN
+ {0x2641, 0x2641, prAL, gcSo}, // EARTH
+ {0x2642, 0x2642, prAI, gcSo}, // MALE SIGN
+ {0x2643, 0x265F, prAL, gcSo}, // [29] JUPITER..BLACK CHESS PAWN
+ {0x2660, 0x2661, prAI, gcSo}, // [2] BLACK SPADE SUIT..WHITE HEART SUIT
+ {0x2662, 0x2662, prAL, gcSo}, // WHITE DIAMOND SUIT
+ {0x2663, 0x2665, prAI, gcSo}, // [3] BLACK CLUB SUIT..BLACK HEART SUIT
+ {0x2666, 0x2666, prAL, gcSo}, // BLACK DIAMOND SUIT
+ {0x2667, 0x2667, prAI, gcSo}, // WHITE CLUB SUIT
+ {0x2668, 0x2668, prID, gcSo}, // HOT SPRINGS
+ {0x2669, 0x266A, prAI, gcSo}, // [2] QUARTER NOTE..EIGHTH NOTE
+ {0x266B, 0x266B, prAL, gcSo}, // BEAMED EIGHTH NOTES
+ {0x266C, 0x266D, prAI, gcSo}, // [2] BEAMED SIXTEENTH NOTES..MUSIC FLAT SIGN
+ {0x266E, 0x266E, prAL, gcSo}, // MUSIC NATURAL SIGN
+ {0x266F, 0x266F, prAI, gcSm}, // MUSIC SHARP SIGN
+ {0x2670, 0x267E, prAL, gcSo}, // [15] WEST SYRIAC CROSS..PERMANENT PAPER SIGN
+ {0x267F, 0x267F, prID, gcSo}, // WHEELCHAIR SYMBOL
+ {0x2680, 0x269D, prAL, gcSo}, // [30] DIE FACE-1..OUTLINED WHITE STAR
+ {0x269E, 0x269F, prAI, gcSo}, // [2] THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT
+ {0x26A0, 0x26BC, prAL, gcSo}, // [29] WARNING SIGN..SESQUIQUADRATE
+ {0x26BD, 0x26C8, prID, gcSo}, // [12] SOCCER BALL..THUNDER CLOUD AND RAIN
+ {0x26C9, 0x26CC, prAI, gcSo}, // [4] TURNED WHITE SHOGI PIECE..CROSSING LANES
+ {0x26CD, 0x26CD, prID, gcSo}, // DISABLED CAR
+ {0x26CE, 0x26CE, prAL, gcSo}, // OPHIUCHUS
+ {0x26CF, 0x26D1, prID, gcSo}, // [3] PICK..HELMET WITH WHITE CROSS
+ {0x26D2, 0x26D2, prAI, gcSo}, // CIRCLED CROSSING LANES
+ {0x26D3, 0x26D4, prID, gcSo}, // [2] CHAINS..NO ENTRY
+ {0x26D5, 0x26D7, prAI, gcSo}, // [3] ALTERNATE ONE-WAY LEFT WAY TRAFFIC..WHITE TWO-WAY LEFT WAY TRAFFIC
+ {0x26D8, 0x26D9, prID, gcSo}, // [2] BLACK LEFT LANE MERGE..WHITE LEFT LANE MERGE
+ {0x26DA, 0x26DB, prAI, gcSo}, // [2] DRIVE SLOW SIGN..HEAVY WHITE DOWN-POINTING TRIANGLE
+ {0x26DC, 0x26DC, prID, gcSo}, // LEFT CLOSED ENTRY
+ {0x26DD, 0x26DE, prAI, gcSo}, // [2] SQUARED SALTIRE..FALLING DIAGONAL IN WHITE CIRCLE IN BLACK SQUARE
+ {0x26DF, 0x26E1, prID, gcSo}, // [3] BLACK TRUCK..RESTRICTED LEFT ENTRY-2
+ {0x26E2, 0x26E2, prAL, gcSo}, // ASTRONOMICAL SYMBOL FOR URANUS
+ {0x26E3, 0x26E3, prAI, gcSo}, // HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE
+ {0x26E4, 0x26E7, prAL, gcSo}, // [4] PENTAGRAM..INVERTED PENTAGRAM
+ {0x26E8, 0x26E9, prAI, gcSo}, // [2] BLACK CROSS ON SHIELD..SHINTO SHRINE
+ {0x26EA, 0x26EA, prID, gcSo}, // CHURCH
+ {0x26EB, 0x26F0, prAI, gcSo}, // [6] CASTLE..MOUNTAIN
+ {0x26F1, 0x26F5, prID, gcSo}, // [5] UMBRELLA ON GROUND..SAILBOAT
+ {0x26F6, 0x26F6, prAI, gcSo}, // SQUARE FOUR CORNERS
+ {0x26F7, 0x26F8, prID, gcSo}, // [2] SKIER..ICE SKATE
+ {0x26F9, 0x26F9, prEB, gcSo}, // PERSON WITH BALL
+ {0x26FA, 0x26FA, prID, gcSo}, // TENT
+ {0x26FB, 0x26FC, prAI, gcSo}, // [2] JAPANESE BANK SYMBOL..HEADSTONE GRAVEYARD SYMBOL
+ {0x26FD, 0x26FF, prID, gcSo}, // [3] FUEL PUMP..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE
+ {0x2700, 0x2704, prID, gcSo}, // [5] BLACK SAFETY SCISSORS..WHITE SCISSORS
+ {0x2705, 0x2707, prAL, gcSo}, // [3] WHITE HEAVY CHECK MARK..TAPE DRIVE
+ {0x2708, 0x2709, prID, gcSo}, // [2] AIRPLANE..ENVELOPE
+ {0x270A, 0x270D, prEB, gcSo}, // [4] RAISED FIST..WRITING HAND
+ {0x270E, 0x2756, prAL, gcSo}, // [73] LOWER RIGHT PENCIL..BLACK DIAMOND MINUS WHITE X
+ {0x2757, 0x2757, prAI, gcSo}, // HEAVY EXCLAMATION MARK SYMBOL
+ {0x2758, 0x275A, prAL, gcSo}, // [3] LIGHT VERTICAL BAR..HEAVY VERTICAL BAR
+ {0x275B, 0x2760, prQU, gcSo}, // [6] HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT..HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT
+ {0x2761, 0x2761, prAL, gcSo}, // CURVED STEM PARAGRAPH SIGN ORNAMENT
+ {0x2762, 0x2763, prEX, gcSo}, // [2] HEAVY EXCLAMATION MARK ORNAMENT..HEAVY HEART EXCLAMATION MARK ORNAMENT
+ {0x2764, 0x2764, prID, gcSo}, // HEAVY BLACK HEART
+ {0x2765, 0x2767, prAL, gcSo}, // [3] ROTATED HEAVY BLACK HEART BULLET..ROTATED FLORAL HEART BULLET
+ {0x2768, 0x2768, prOP, gcPs}, // MEDIUM LEFT PARENTHESIS ORNAMENT
+ {0x2769, 0x2769, prCL, gcPe}, // MEDIUM RIGHT PARENTHESIS ORNAMENT
+ {0x276A, 0x276A, prOP, gcPs}, // MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT
+ {0x276B, 0x276B, prCL, gcPe}, // MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT
+ {0x276C, 0x276C, prOP, gcPs}, // MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT
+ {0x276D, 0x276D, prCL, gcPe}, // MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT
+ {0x276E, 0x276E, prOP, gcPs}, // HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT
+ {0x276F, 0x276F, prCL, gcPe}, // HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT
+ {0x2770, 0x2770, prOP, gcPs}, // HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT
+ {0x2771, 0x2771, prCL, gcPe}, // HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT
+ {0x2772, 0x2772, prOP, gcPs}, // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT
+ {0x2773, 0x2773, prCL, gcPe}, // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT
+ {0x2774, 0x2774, prOP, gcPs}, // MEDIUM LEFT CURLY BRACKET ORNAMENT
+ {0x2775, 0x2775, prCL, gcPe}, // MEDIUM RIGHT CURLY BRACKET ORNAMENT
+ {0x2776, 0x2793, prAI, gcNo}, // [30] DINGBAT NEGATIVE CIRCLED DIGIT ONE..DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN
+ {0x2794, 0x27BF, prAL, gcSo}, // [44] HEAVY WIDE-HEADED RIGHTWARDS ARROW..DOUBLE CURLY LOOP
+ {0x27C0, 0x27C4, prAL, gcSm}, // [5] THREE DIMENSIONAL ANGLE..OPEN SUPERSET
+ {0x27C5, 0x27C5, prOP, gcPs}, // LEFT S-SHAPED BAG DELIMITER
+ {0x27C6, 0x27C6, prCL, gcPe}, // RIGHT S-SHAPED BAG DELIMITER
+ {0x27C7, 0x27E5, prAL, gcSm}, // [31] OR WITH DOT INSIDE..WHITE SQUARE WITH RIGHTWARDS TICK
+ {0x27E6, 0x27E6, prOP, gcPs}, // MATHEMATICAL LEFT WHITE SQUARE BRACKET
+ {0x27E7, 0x27E7, prCL, gcPe}, // MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+ {0x27E8, 0x27E8, prOP, gcPs}, // MATHEMATICAL LEFT ANGLE BRACKET
+ {0x27E9, 0x27E9, prCL, gcPe}, // MATHEMATICAL RIGHT ANGLE BRACKET
+ {0x27EA, 0x27EA, prOP, gcPs}, // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
+ {0x27EB, 0x27EB, prCL, gcPe}, // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
+ {0x27EC, 0x27EC, prOP, gcPs}, // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET
+ {0x27ED, 0x27ED, prCL, gcPe}, // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET
+ {0x27EE, 0x27EE, prOP, gcPs}, // MATHEMATICAL LEFT FLATTENED PARENTHESIS
+ {0x27EF, 0x27EF, prCL, gcPe}, // MATHEMATICAL RIGHT FLATTENED PARENTHESIS
+ {0x27F0, 0x27FF, prAL, gcSm}, // [16] UPWARDS QUADRUPLE ARROW..LONG RIGHTWARDS SQUIGGLE ARROW
+ {0x2800, 0x28FF, prAL, gcSo}, // [256] BRAILLE PATTERN BLANK..BRAILLE PATTERN DOTS-12345678
+ {0x2900, 0x297F, prAL, gcSm}, // [128] RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE..DOWN FISH TAIL
+ {0x2980, 0x2982, prAL, gcSm}, // [3] TRIPLE VERTICAL BAR DELIMITER..Z NOTATION TYPE COLON
+ {0x2983, 0x2983, prOP, gcPs}, // LEFT WHITE CURLY BRACKET
+ {0x2984, 0x2984, prCL, gcPe}, // RIGHT WHITE CURLY BRACKET
+ {0x2985, 0x2985, prOP, gcPs}, // LEFT WHITE PARENTHESIS
+ {0x2986, 0x2986, prCL, gcPe}, // RIGHT WHITE PARENTHESIS
+ {0x2987, 0x2987, prOP, gcPs}, // Z NOTATION LEFT IMAGE BRACKET
+ {0x2988, 0x2988, prCL, gcPe}, // Z NOTATION RIGHT IMAGE BRACKET
+ {0x2989, 0x2989, prOP, gcPs}, // Z NOTATION LEFT BINDING BRACKET
+ {0x298A, 0x298A, prCL, gcPe}, // Z NOTATION RIGHT BINDING BRACKET
+ {0x298B, 0x298B, prOP, gcPs}, // LEFT SQUARE BRACKET WITH UNDERBAR
+ {0x298C, 0x298C, prCL, gcPe}, // RIGHT SQUARE BRACKET WITH UNDERBAR
+ {0x298D, 0x298D, prOP, gcPs}, // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER
+ {0x298E, 0x298E, prCL, gcPe}, // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+ {0x298F, 0x298F, prOP, gcPs}, // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+ {0x2990, 0x2990, prCL, gcPe}, // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER
+ {0x2991, 0x2991, prOP, gcPs}, // LEFT ANGLE BRACKET WITH DOT
+ {0x2992, 0x2992, prCL, gcPe}, // RIGHT ANGLE BRACKET WITH DOT
+ {0x2993, 0x2993, prOP, gcPs}, // LEFT ARC LESS-THAN BRACKET
+ {0x2994, 0x2994, prCL, gcPe}, // RIGHT ARC GREATER-THAN BRACKET
+ {0x2995, 0x2995, prOP, gcPs}, // DOUBLE LEFT ARC GREATER-THAN BRACKET
+ {0x2996, 0x2996, prCL, gcPe}, // DOUBLE RIGHT ARC LESS-THAN BRACKET
+ {0x2997, 0x2997, prOP, gcPs}, // LEFT BLACK TORTOISE SHELL BRACKET
+ {0x2998, 0x2998, prCL, gcPe}, // RIGHT BLACK TORTOISE SHELL BRACKET
+ {0x2999, 0x29D7, prAL, gcSm}, // [63] DOTTED FENCE..BLACK HOURGLASS
+ {0x29D8, 0x29D8, prOP, gcPs}, // LEFT WIGGLY FENCE
+ {0x29D9, 0x29D9, prCL, gcPe}, // RIGHT WIGGLY FENCE
+ {0x29DA, 0x29DA, prOP, gcPs}, // LEFT DOUBLE WIGGLY FENCE
+ {0x29DB, 0x29DB, prCL, gcPe}, // RIGHT DOUBLE WIGGLY FENCE
+ {0x29DC, 0x29FB, prAL, gcSm}, // [32] INCOMPLETE INFINITY..TRIPLE PLUS
+ {0x29FC, 0x29FC, prOP, gcPs}, // LEFT-POINTING CURVED ANGLE BRACKET
+ {0x29FD, 0x29FD, prCL, gcPe}, // RIGHT-POINTING CURVED ANGLE BRACKET
+ {0x29FE, 0x29FF, prAL, gcSm}, // [2] TINY..MINY
+ {0x2A00, 0x2AFF, prAL, gcSm}, // [256] N-ARY CIRCLED DOT OPERATOR..N-ARY WHITE VERTICAL BAR
+ {0x2B00, 0x2B2F, prAL, gcSo}, // [48] NORTH EAST WHITE ARROW..WHITE VERTICAL ELLIPSE
+ {0x2B30, 0x2B44, prAL, gcSm}, // [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET
+ {0x2B45, 0x2B46, prAL, gcSo}, // [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW
+ {0x2B47, 0x2B4C, prAL, gcSm}, // [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR
+ {0x2B4D, 0x2B54, prAL, gcSo}, // [8] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..WHITE RIGHT-POINTING PENTAGON
+ {0x2B55, 0x2B59, prAI, gcSo}, // [5] HEAVY LARGE CIRCLE..HEAVY CIRCLED SALTIRE
+ {0x2B5A, 0x2B73, prAL, gcSo}, // [26] SLANTED NORTH ARROW WITH HOOKED HEAD..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR
+ {0x2B76, 0x2B95, prAL, gcSo}, // [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW
+ {0x2B97, 0x2BFF, prAL, gcSo}, // [105] SYMBOL FOR TYPE A ELECTRONICS..HELLSCHREIBER PAUSE SYMBOL
+ {0x2C00, 0x2C5F, prAL, gcLC}, // [96] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC SMALL LETTER CAUDATE CHRIVI
+ {0x2C60, 0x2C7B, prAL, gcLC}, // [28] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN LETTER SMALL CAPITAL TURNED E
+ {0x2C7C, 0x2C7D, prAL, gcLm}, // [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V
+ {0x2C7E, 0x2C7F, prAL, gcLu}, // [2] LATIN CAPITAL LETTER S WITH SWASH TAIL..LATIN CAPITAL LETTER Z WITH SWASH TAIL
+ {0x2C80, 0x2CE4, prAL, gcLC}, // [101] COPTIC CAPITAL LETTER ALFA..COPTIC SYMBOL KAI
+ {0x2CE5, 0x2CEA, prAL, gcSo}, // [6] COPTIC SYMBOL MI RO..COPTIC SYMBOL SHIMA SIMA
+ {0x2CEB, 0x2CEE, prAL, gcLC}, // [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA
+ {0x2CEF, 0x2CF1, prCM, gcMn}, // [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS
+ {0x2CF2, 0x2CF3, prAL, gcLC}, // [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI
+ {0x2CF9, 0x2CF9, prEX, gcPo}, // COPTIC OLD NUBIAN FULL STOP
+ {0x2CFA, 0x2CFC, prBA, gcPo}, // [3] COPTIC OLD NUBIAN DIRECT QUESTION MARK..COPTIC OLD NUBIAN VERSE DIVIDER
+ {0x2CFD, 0x2CFD, prAL, gcNo}, // COPTIC FRACTION ONE HALF
+ {0x2CFE, 0x2CFE, prEX, gcPo}, // COPTIC FULL STOP
+ {0x2CFF, 0x2CFF, prBA, gcPo}, // COPTIC MORPHOLOGICAL DIVIDER
+ {0x2D00, 0x2D25, prAL, gcLl}, // [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+ {0x2D27, 0x2D27, prAL, gcLl}, // GEORGIAN SMALL LETTER YN
+ {0x2D2D, 0x2D2D, prAL, gcLl}, // GEORGIAN SMALL LETTER AEN
+ {0x2D30, 0x2D67, prAL, gcLo}, // [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO
+ {0x2D6F, 0x2D6F, prAL, gcLm}, // TIFINAGH MODIFIER LETTER LABIALIZATION MARK
+ {0x2D70, 0x2D70, prBA, gcPo}, // TIFINAGH SEPARATOR MARK
+ {0x2D7F, 0x2D7F, prCM, gcMn}, // TIFINAGH CONSONANT JOINER
+ {0x2D80, 0x2D96, prAL, gcLo}, // [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE
+ {0x2DA0, 0x2DA6, prAL, gcLo}, // [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO
+ {0x2DA8, 0x2DAE, prAL, gcLo}, // [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO
+ {0x2DB0, 0x2DB6, prAL, gcLo}, // [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO
+ {0x2DB8, 0x2DBE, prAL, gcLo}, // [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO
+ {0x2DC0, 0x2DC6, prAL, gcLo}, // [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO
+ {0x2DC8, 0x2DCE, prAL, gcLo}, // [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO
+ {0x2DD0, 0x2DD6, prAL, gcLo}, // [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO
+ {0x2DD8, 0x2DDE, prAL, gcLo}, // [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO
+ {0x2DE0, 0x2DFF, prCM, gcMn}, // [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
+ {0x2E00, 0x2E01, prQU, gcPo}, // [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER
+ {0x2E02, 0x2E02, prQU, gcPi}, // LEFT SUBSTITUTION BRACKET
+ {0x2E03, 0x2E03, prQU, gcPf}, // RIGHT SUBSTITUTION BRACKET
+ {0x2E04, 0x2E04, prQU, gcPi}, // LEFT DOTTED SUBSTITUTION BRACKET
+ {0x2E05, 0x2E05, prQU, gcPf}, // RIGHT DOTTED SUBSTITUTION BRACKET
+ {0x2E06, 0x2E08, prQU, gcPo}, // [3] RAISED INTERPOLATION MARKER..DOTTED TRANSPOSITION MARKER
+ {0x2E09, 0x2E09, prQU, gcPi}, // LEFT TRANSPOSITION BRACKET
+ {0x2E0A, 0x2E0A, prQU, gcPf}, // RIGHT TRANSPOSITION BRACKET
+ {0x2E0B, 0x2E0B, prQU, gcPo}, // RAISED SQUARE
+ {0x2E0C, 0x2E0C, prQU, gcPi}, // LEFT RAISED OMISSION BRACKET
+ {0x2E0D, 0x2E0D, prQU, gcPf}, // RIGHT RAISED OMISSION BRACKET
+ {0x2E0E, 0x2E15, prBA, gcPo}, // [8] EDITORIAL CORONIS..UPWARDS ANCORA
+ {0x2E16, 0x2E16, prAL, gcPo}, // DOTTED RIGHT-POINTING ANGLE
+ {0x2E17, 0x2E17, prBA, gcPd}, // DOUBLE OBLIQUE HYPHEN
+ {0x2E18, 0x2E18, prOP, gcPo}, // INVERTED INTERROBANG
+ {0x2E19, 0x2E19, prBA, gcPo}, // PALM BRANCH
+ {0x2E1A, 0x2E1A, prAL, gcPd}, // HYPHEN WITH DIAERESIS
+ {0x2E1B, 0x2E1B, prAL, gcPo}, // TILDE WITH RING ABOVE
+ {0x2E1C, 0x2E1C, prQU, gcPi}, // LEFT LOW PARAPHRASE BRACKET
+ {0x2E1D, 0x2E1D, prQU, gcPf}, // RIGHT LOW PARAPHRASE BRACKET
+ {0x2E1E, 0x2E1F, prAL, gcPo}, // [2] TILDE WITH DOT ABOVE..TILDE WITH DOT BELOW
+ {0x2E20, 0x2E20, prQU, gcPi}, // LEFT VERTICAL BAR WITH QUILL
+ {0x2E21, 0x2E21, prQU, gcPf}, // RIGHT VERTICAL BAR WITH QUILL
+ {0x2E22, 0x2E22, prOP, gcPs}, // TOP LEFT HALF BRACKET
+ {0x2E23, 0x2E23, prCL, gcPe}, // TOP RIGHT HALF BRACKET
+ {0x2E24, 0x2E24, prOP, gcPs}, // BOTTOM LEFT HALF BRACKET
+ {0x2E25, 0x2E25, prCL, gcPe}, // BOTTOM RIGHT HALF BRACKET
+ {0x2E26, 0x2E26, prOP, gcPs}, // LEFT SIDEWAYS U BRACKET
+ {0x2E27, 0x2E27, prCL, gcPe}, // RIGHT SIDEWAYS U BRACKET
+ {0x2E28, 0x2E28, prOP, gcPs}, // LEFT DOUBLE PARENTHESIS
+ {0x2E29, 0x2E29, prCL, gcPe}, // RIGHT DOUBLE PARENTHESIS
+ {0x2E2A, 0x2E2D, prBA, gcPo}, // [4] TWO DOTS OVER ONE DOT PUNCTUATION..FIVE DOT MARK
+ {0x2E2E, 0x2E2E, prEX, gcPo}, // REVERSED QUESTION MARK
+ {0x2E2F, 0x2E2F, prAL, gcLm}, // VERTICAL TILDE
+ {0x2E30, 0x2E31, prBA, gcPo}, // [2] RING POINT..WORD SEPARATOR MIDDLE DOT
+ {0x2E32, 0x2E32, prAL, gcPo}, // TURNED COMMA
+ {0x2E33, 0x2E34, prBA, gcPo}, // [2] RAISED DOT..RAISED COMMA
+ {0x2E35, 0x2E39, prAL, gcPo}, // [5] TURNED SEMICOLON..TOP HALF SECTION SIGN
+ {0x2E3A, 0x2E3B, prB2, gcPd}, // [2] TWO-EM DASH..THREE-EM DASH
+ {0x2E3C, 0x2E3E, prBA, gcPo}, // [3] STENOGRAPHIC FULL STOP..WIGGLY VERTICAL LINE
+ {0x2E3F, 0x2E3F, prAL, gcPo}, // CAPITULUM
+ {0x2E40, 0x2E40, prBA, gcPd}, // DOUBLE HYPHEN
+ {0x2E41, 0x2E41, prBA, gcPo}, // REVERSED COMMA
+ {0x2E42, 0x2E42, prOP, gcPs}, // DOUBLE LOW-REVERSED-9 QUOTATION MARK
+ {0x2E43, 0x2E4A, prBA, gcPo}, // [8] DASH WITH LEFT UPTURN..DOTTED SOLIDUS
+ {0x2E4B, 0x2E4B, prAL, gcPo}, // TRIPLE DAGGER
+ {0x2E4C, 0x2E4C, prBA, gcPo}, // MEDIEVAL COMMA
+ {0x2E4D, 0x2E4D, prAL, gcPo}, // PARAGRAPHUS MARK
+ {0x2E4E, 0x2E4F, prBA, gcPo}, // [2] PUNCTUS ELEVATUS MARK..CORNISH VERSE DIVIDER
+ {0x2E50, 0x2E51, prAL, gcSo}, // [2] CROSS PATTY WITH RIGHT CROSSBAR..CROSS PATTY WITH LEFT CROSSBAR
+ {0x2E52, 0x2E52, prAL, gcPo}, // TIRONIAN SIGN CAPITAL ET
+ {0x2E53, 0x2E54, prEX, gcPo}, // [2] MEDIEVAL EXCLAMATION MARK..MEDIEVAL QUESTION MARK
+ {0x2E55, 0x2E55, prOP, gcPs}, // LEFT SQUARE BRACKET WITH STROKE
+ {0x2E56, 0x2E56, prCL, gcPe}, // RIGHT SQUARE BRACKET WITH STROKE
+ {0x2E57, 0x2E57, prOP, gcPs}, // LEFT SQUARE BRACKET WITH DOUBLE STROKE
+ {0x2E58, 0x2E58, prCL, gcPe}, // RIGHT SQUARE BRACKET WITH DOUBLE STROKE
+ {0x2E59, 0x2E59, prOP, gcPs}, // TOP HALF LEFT PARENTHESIS
+ {0x2E5A, 0x2E5A, prCL, gcPe}, // TOP HALF RIGHT PARENTHESIS
+ {0x2E5B, 0x2E5B, prOP, gcPs}, // BOTTOM HALF LEFT PARENTHESIS
+ {0x2E5C, 0x2E5C, prCL, gcPe}, // BOTTOM HALF RIGHT PARENTHESIS
+ {0x2E5D, 0x2E5D, prBA, gcPd}, // OBLIQUE HYPHEN
+ {0x2E80, 0x2E99, prID, gcSo}, // [26] CJK RADICAL REPEAT..CJK RADICAL RAP
+ {0x2E9B, 0x2EF3, prID, gcSo}, // [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE
+ {0x2F00, 0x2FD5, prID, gcSo}, // [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE
+ {0x2FF0, 0x2FFB, prID, gcSo}, // [12] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID
+ {0x3000, 0x3000, prBA, gcZs}, // IDEOGRAPHIC SPACE
+ {0x3001, 0x3002, prCL, gcPo}, // [2] IDEOGRAPHIC COMMA..IDEOGRAPHIC FULL STOP
+ {0x3003, 0x3003, prID, gcPo}, // DITTO MARK
+ {0x3004, 0x3004, prID, gcSo}, // JAPANESE INDUSTRIAL STANDARD SYMBOL
+ {0x3005, 0x3005, prNS, gcLm}, // IDEOGRAPHIC ITERATION MARK
+ {0x3006, 0x3006, prID, gcLo}, // IDEOGRAPHIC CLOSING MARK
+ {0x3007, 0x3007, prID, gcNl}, // IDEOGRAPHIC NUMBER ZERO
+ {0x3008, 0x3008, prOP, gcPs}, // LEFT ANGLE BRACKET
+ {0x3009, 0x3009, prCL, gcPe}, // RIGHT ANGLE BRACKET
+ {0x300A, 0x300A, prOP, gcPs}, // LEFT DOUBLE ANGLE BRACKET
+ {0x300B, 0x300B, prCL, gcPe}, // RIGHT DOUBLE ANGLE BRACKET
+ {0x300C, 0x300C, prOP, gcPs}, // LEFT CORNER BRACKET
+ {0x300D, 0x300D, prCL, gcPe}, // RIGHT CORNER BRACKET
+ {0x300E, 0x300E, prOP, gcPs}, // LEFT WHITE CORNER BRACKET
+ {0x300F, 0x300F, prCL, gcPe}, // RIGHT WHITE CORNER BRACKET
+ {0x3010, 0x3010, prOP, gcPs}, // LEFT BLACK LENTICULAR BRACKET
+ {0x3011, 0x3011, prCL, gcPe}, // RIGHT BLACK LENTICULAR BRACKET
+ {0x3012, 0x3013, prID, gcSo}, // [2] POSTAL MARK..GETA MARK
+ {0x3014, 0x3014, prOP, gcPs}, // LEFT TORTOISE SHELL BRACKET
+ {0x3015, 0x3015, prCL, gcPe}, // RIGHT TORTOISE SHELL BRACKET
+ {0x3016, 0x3016, prOP, gcPs}, // LEFT WHITE LENTICULAR BRACKET
+ {0x3017, 0x3017, prCL, gcPe}, // RIGHT WHITE LENTICULAR BRACKET
+ {0x3018, 0x3018, prOP, gcPs}, // LEFT WHITE TORTOISE SHELL BRACKET
+ {0x3019, 0x3019, prCL, gcPe}, // RIGHT WHITE TORTOISE SHELL BRACKET
+ {0x301A, 0x301A, prOP, gcPs}, // LEFT WHITE SQUARE BRACKET
+ {0x301B, 0x301B, prCL, gcPe}, // RIGHT WHITE SQUARE BRACKET
+ {0x301C, 0x301C, prNS, gcPd}, // WAVE DASH
+ {0x301D, 0x301D, prOP, gcPs}, // REVERSED DOUBLE PRIME QUOTATION MARK
+ {0x301E, 0x301F, prCL, gcPe}, // [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK
+ {0x3020, 0x3020, prID, gcSo}, // POSTAL MARK FACE
+ {0x3021, 0x3029, prID, gcNl}, // [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE
+ {0x302A, 0x302D, prCM, gcMn}, // [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK
+ {0x302E, 0x302F, prCM, gcMc}, // [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK
+ {0x3030, 0x3030, prID, gcPd}, // WAVY DASH
+ {0x3031, 0x3034, prID, gcLm}, // [4] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF
+ {0x3035, 0x3035, prCM, gcLm}, // VERTICAL KANA REPEAT MARK LOWER HALF
+ {0x3036, 0x3037, prID, gcSo}, // [2] CIRCLED POSTAL MARK..IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL
+ {0x3038, 0x303A, prID, gcNl}, // [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY
+ {0x303B, 0x303B, prNS, gcLm}, // VERTICAL IDEOGRAPHIC ITERATION MARK
+ {0x303C, 0x303C, prNS, gcLo}, // MASU MARK
+ {0x303D, 0x303D, prID, gcPo}, // PART ALTERNATION MARK
+ {0x303E, 0x303F, prID, gcSo}, // [2] IDEOGRAPHIC VARIATION INDICATOR..IDEOGRAPHIC HALF FILL SPACE
+ {0x3041, 0x3041, prCJ, gcLo}, // HIRAGANA LETTER SMALL A
+ {0x3042, 0x3042, prID, gcLo}, // HIRAGANA LETTER A
+ {0x3043, 0x3043, prCJ, gcLo}, // HIRAGANA LETTER SMALL I
+ {0x3044, 0x3044, prID, gcLo}, // HIRAGANA LETTER I
+ {0x3045, 0x3045, prCJ, gcLo}, // HIRAGANA LETTER SMALL U
+ {0x3046, 0x3046, prID, gcLo}, // HIRAGANA LETTER U
+ {0x3047, 0x3047, prCJ, gcLo}, // HIRAGANA LETTER SMALL E
+ {0x3048, 0x3048, prID, gcLo}, // HIRAGANA LETTER E
+ {0x3049, 0x3049, prCJ, gcLo}, // HIRAGANA LETTER SMALL O
+ {0x304A, 0x3062, prID, gcLo}, // [25] HIRAGANA LETTER O..HIRAGANA LETTER DI
+ {0x3063, 0x3063, prCJ, gcLo}, // HIRAGANA LETTER SMALL TU
+ {0x3064, 0x3082, prID, gcLo}, // [31] HIRAGANA LETTER TU..HIRAGANA LETTER MO
+ {0x3083, 0x3083, prCJ, gcLo}, // HIRAGANA LETTER SMALL YA
+ {0x3084, 0x3084, prID, gcLo}, // HIRAGANA LETTER YA
+ {0x3085, 0x3085, prCJ, gcLo}, // HIRAGANA LETTER SMALL YU
+ {0x3086, 0x3086, prID, gcLo}, // HIRAGANA LETTER YU
+ {0x3087, 0x3087, prCJ, gcLo}, // HIRAGANA LETTER SMALL YO
+ {0x3088, 0x308D, prID, gcLo}, // [6] HIRAGANA LETTER YO..HIRAGANA LETTER RO
+ {0x308E, 0x308E, prCJ, gcLo}, // HIRAGANA LETTER SMALL WA
+ {0x308F, 0x3094, prID, gcLo}, // [6] HIRAGANA LETTER WA..HIRAGANA LETTER VU
+ {0x3095, 0x3096, prCJ, gcLo}, // [2] HIRAGANA LETTER SMALL KA..HIRAGANA LETTER SMALL KE
+ {0x3099, 0x309A, prCM, gcMn}, // [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+ {0x309B, 0x309C, prNS, gcSk}, // [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+ {0x309D, 0x309E, prNS, gcLm}, // [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK
+ {0x309F, 0x309F, prID, gcLo}, // HIRAGANA DIGRAPH YORI
+ {0x30A0, 0x30A0, prNS, gcPd}, // KATAKANA-HIRAGANA DOUBLE HYPHEN
+ {0x30A1, 0x30A1, prCJ, gcLo}, // KATAKANA LETTER SMALL A
+ {0x30A2, 0x30A2, prID, gcLo}, // KATAKANA LETTER A
+ {0x30A3, 0x30A3, prCJ, gcLo}, // KATAKANA LETTER SMALL I
+ {0x30A4, 0x30A4, prID, gcLo}, // KATAKANA LETTER I
+ {0x30A5, 0x30A5, prCJ, gcLo}, // KATAKANA LETTER SMALL U
+ {0x30A6, 0x30A6, prID, gcLo}, // KATAKANA LETTER U
+ {0x30A7, 0x30A7, prCJ, gcLo}, // KATAKANA LETTER SMALL E
+ {0x30A8, 0x30A8, prID, gcLo}, // KATAKANA LETTER E
+ {0x30A9, 0x30A9, prCJ, gcLo}, // KATAKANA LETTER SMALL O
+ {0x30AA, 0x30C2, prID, gcLo}, // [25] KATAKANA LETTER O..KATAKANA LETTER DI
+ {0x30C3, 0x30C3, prCJ, gcLo}, // KATAKANA LETTER SMALL TU
+ {0x30C4, 0x30E2, prID, gcLo}, // [31] KATAKANA LETTER TU..KATAKANA LETTER MO
+ {0x30E3, 0x30E3, prCJ, gcLo}, // KATAKANA LETTER SMALL YA
+ {0x30E4, 0x30E4, prID, gcLo}, // KATAKANA LETTER YA
+ {0x30E5, 0x30E5, prCJ, gcLo}, // KATAKANA LETTER SMALL YU
+ {0x30E6, 0x30E6, prID, gcLo}, // KATAKANA LETTER YU
+ {0x30E7, 0x30E7, prCJ, gcLo}, // KATAKANA LETTER SMALL YO
+ {0x30E8, 0x30ED, prID, gcLo}, // [6] KATAKANA LETTER YO..KATAKANA LETTER RO
+ {0x30EE, 0x30EE, prCJ, gcLo}, // KATAKANA LETTER SMALL WA
+ {0x30EF, 0x30F4, prID, gcLo}, // [6] KATAKANA LETTER WA..KATAKANA LETTER VU
+ {0x30F5, 0x30F6, prCJ, gcLo}, // [2] KATAKANA LETTER SMALL KA..KATAKANA LETTER SMALL KE
+ {0x30F7, 0x30FA, prID, gcLo}, // [4] KATAKANA LETTER VA..KATAKANA LETTER VO
+ {0x30FB, 0x30FB, prNS, gcPo}, // KATAKANA MIDDLE DOT
+ {0x30FC, 0x30FC, prCJ, gcLm}, // KATAKANA-HIRAGANA PROLONGED SOUND MARK
+ {0x30FD, 0x30FE, prNS, gcLm}, // [2] KATAKANA ITERATION MARK..KATAKANA VOICED ITERATION MARK
+ {0x30FF, 0x30FF, prID, gcLo}, // KATAKANA DIGRAPH KOTO
+ {0x3105, 0x312F, prID, gcLo}, // [43] BOPOMOFO LETTER B..BOPOMOFO LETTER NN
+ {0x3131, 0x318E, prID, gcLo}, // [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE
+ {0x3190, 0x3191, prID, gcSo}, // [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK
+ {0x3192, 0x3195, prID, gcNo}, // [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK
+ {0x3196, 0x319F, prID, gcSo}, // [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK
+ {0x31A0, 0x31BF, prID, gcLo}, // [32] BOPOMOFO LETTER BU..BOPOMOFO LETTER AH
+ {0x31C0, 0x31E3, prID, gcSo}, // [36] CJK STROKE T..CJK STROKE Q
+ {0x31F0, 0x31FF, prCJ, gcLo}, // [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO
+ {0x3200, 0x321E, prID, gcSo}, // [31] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED KOREAN CHARACTER O HU
+ {0x3220, 0x3229, prID, gcNo}, // [10] PARENTHESIZED IDEOGRAPH ONE..PARENTHESIZED IDEOGRAPH TEN
+ {0x322A, 0x3247, prID, gcSo}, // [30] PARENTHESIZED IDEOGRAPH MOON..CIRCLED IDEOGRAPH KOTO
+ {0x3248, 0x324F, prAI, gcNo}, // [8] CIRCLED NUMBER TEN ON BLACK SQUARE..CIRCLED NUMBER EIGHTY ON BLACK SQUARE
+ {0x3250, 0x3250, prID, gcSo}, // PARTNERSHIP SIGN
+ {0x3251, 0x325F, prID, gcNo}, // [15] CIRCLED NUMBER TWENTY ONE..CIRCLED NUMBER THIRTY FIVE
+ {0x3260, 0x327F, prID, gcSo}, // [32] CIRCLED HANGUL KIYEOK..KOREAN STANDARD SYMBOL
+ {0x3280, 0x3289, prID, gcNo}, // [10] CIRCLED IDEOGRAPH ONE..CIRCLED IDEOGRAPH TEN
+ {0x328A, 0x32B0, prID, gcSo}, // [39] CIRCLED IDEOGRAPH MOON..CIRCLED IDEOGRAPH NIGHT
+ {0x32B1, 0x32BF, prID, gcNo}, // [15] CIRCLED NUMBER THIRTY SIX..CIRCLED NUMBER FIFTY
+ {0x32C0, 0x32FF, prID, gcSo}, // [64] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..SQUARE ERA NAME REIWA
+ {0x3300, 0x33FF, prID, gcSo}, // [256] SQUARE APAATO..SQUARE GAL
+ {0x3400, 0x4DBF, prID, gcLo}, // [6592] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DBF
+ {0x4DC0, 0x4DFF, prAL, gcSo}, // [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION
+ {0x4E00, 0x9FFF, prID, gcLo}, // [20992] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFF
+ {0xA000, 0xA014, prID, gcLo}, // [21] YI SYLLABLE IT..YI SYLLABLE E
+ {0xA015, 0xA015, prNS, gcLm}, // YI SYLLABLE WU
+ {0xA016, 0xA48C, prID, gcLo}, // [1143] YI SYLLABLE BIT..YI SYLLABLE YYR
+ {0xA490, 0xA4C6, prID, gcSo}, // [55] YI RADICAL QOT..YI RADICAL KE
+ {0xA4D0, 0xA4F7, prAL, gcLo}, // [40] LISU LETTER BA..LISU LETTER OE
+ {0xA4F8, 0xA4FD, prAL, gcLm}, // [6] LISU LETTER TONE MYA TI..LISU LETTER TONE MYA JEU
+ {0xA4FE, 0xA4FF, prBA, gcPo}, // [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP
+ {0xA500, 0xA60B, prAL, gcLo}, // [268] VAI SYLLABLE EE..VAI SYLLABLE NG
+ {0xA60C, 0xA60C, prAL, gcLm}, // VAI SYLLABLE LENGTHENER
+ {0xA60D, 0xA60D, prBA, gcPo}, // VAI COMMA
+ {0xA60E, 0xA60E, prEX, gcPo}, // VAI FULL STOP
+ {0xA60F, 0xA60F, prBA, gcPo}, // VAI QUESTION MARK
+ {0xA610, 0xA61F, prAL, gcLo}, // [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG
+ {0xA620, 0xA629, prNU, gcNd}, // [10] VAI DIGIT ZERO..VAI DIGIT NINE
+ {0xA62A, 0xA62B, prAL, gcLo}, // [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO
+ {0xA640, 0xA66D, prAL, gcLC}, // [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+ {0xA66E, 0xA66E, prAL, gcLo}, // CYRILLIC LETTER MULTIOCULAR O
+ {0xA66F, 0xA66F, prCM, gcMn}, // COMBINING CYRILLIC VZMET
+ {0xA670, 0xA672, prCM, gcMe}, // [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN
+ {0xA673, 0xA673, prAL, gcPo}, // SLAVONIC ASTERISK
+ {0xA674, 0xA67D, prCM, gcMn}, // [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK
+ {0xA67E, 0xA67E, prAL, gcPo}, // CYRILLIC KAVYKA
+ {0xA67F, 0xA67F, prAL, gcLm}, // CYRILLIC PAYEROK
+ {0xA680, 0xA69B, prAL, gcLC}, // [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O
+ {0xA69C, 0xA69D, prAL, gcLm}, // [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN
+ {0xA69E, 0xA69F, prCM, gcMn}, // [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E
+ {0xA6A0, 0xA6E5, prAL, gcLo}, // [70] BAMUM LETTER A..BAMUM LETTER KI
+ {0xA6E6, 0xA6EF, prAL, gcNl}, // [10] BAMUM LETTER MO..BAMUM LETTER KOGHOM
+ {0xA6F0, 0xA6F1, prCM, gcMn}, // [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS
+ {0xA6F2, 0xA6F2, prAL, gcPo}, // BAMUM NJAEMLI
+ {0xA6F3, 0xA6F7, prBA, gcPo}, // [5] BAMUM FULL STOP..BAMUM QUESTION MARK
+ {0xA700, 0xA716, prAL, gcSk}, // [23] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR
+ {0xA717, 0xA71F, prAL, gcLm}, // [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK
+ {0xA720, 0xA721, prAL, gcSk}, // [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE
+ {0xA722, 0xA76F, prAL, gcLC}, // [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON
+ {0xA770, 0xA770, prAL, gcLm}, // MODIFIER LETTER US
+ {0xA771, 0xA787, prAL, gcLC}, // [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T
+ {0xA788, 0xA788, prAL, gcLm}, // MODIFIER LETTER LOW CIRCUMFLEX ACCENT
+ {0xA789, 0xA78A, prAL, gcSk}, // [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN
+ {0xA78B, 0xA78E, prAL, gcLC}, // [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT
+ {0xA78F, 0xA78F, prAL, gcLo}, // LATIN LETTER SINOLOGICAL DOT
+ {0xA790, 0xA7CA, prAL, gcLC}, // [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY
+ {0xA7D0, 0xA7D1, prAL, gcLC}, // [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G
+ {0xA7D3, 0xA7D3, prAL, gcLl}, // LATIN SMALL LETTER DOUBLE THORN
+ {0xA7D5, 0xA7D9, prAL, gcLC}, // [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S
+ {0xA7F2, 0xA7F4, prAL, gcLm}, // [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q
+ {0xA7F5, 0xA7F6, prAL, gcLC}, // [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H
+ {0xA7F7, 0xA7F7, prAL, gcLo}, // LATIN EPIGRAPHIC LETTER SIDEWAYS I
+ {0xA7F8, 0xA7F9, prAL, gcLm}, // [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
+ {0xA7FA, 0xA7FA, prAL, gcLl}, // LATIN LETTER SMALL CAPITAL TURNED M
+ {0xA7FB, 0xA7FF, prAL, gcLo}, // [5] LATIN EPIGRAPHIC LETTER REVERSED F..LATIN EPIGRAPHIC LETTER ARCHAIC M
+ {0xA800, 0xA801, prAL, gcLo}, // [2] SYLOTI NAGRI LETTER A..SYLOTI NAGRI LETTER I
+ {0xA802, 0xA802, prCM, gcMn}, // SYLOTI NAGRI SIGN DVISVARA
+ {0xA803, 0xA805, prAL, gcLo}, // [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O
+ {0xA806, 0xA806, prCM, gcMn}, // SYLOTI NAGRI SIGN HASANTA
+ {0xA807, 0xA80A, prAL, gcLo}, // [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO
+ {0xA80B, 0xA80B, prCM, gcMn}, // SYLOTI NAGRI SIGN ANUSVARA
+ {0xA80C, 0xA822, prAL, gcLo}, // [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO
+ {0xA823, 0xA824, prCM, gcMc}, // [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I
+ {0xA825, 0xA826, prCM, gcMn}, // [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
+ {0xA827, 0xA827, prCM, gcMc}, // SYLOTI NAGRI VOWEL SIGN OO
+ {0xA828, 0xA82B, prAL, gcSo}, // [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI POETRY MARK-4
+ {0xA82C, 0xA82C, prCM, gcMn}, // SYLOTI NAGRI SIGN ALTERNATE HASANTA
+ {0xA830, 0xA835, prAL, gcNo}, // [6] NORTH INDIC FRACTION ONE QUARTER..NORTH INDIC FRACTION THREE SIXTEENTHS
+ {0xA836, 0xA837, prAL, gcSo}, // [2] NORTH INDIC QUARTER MARK..NORTH INDIC PLACEHOLDER MARK
+ {0xA838, 0xA838, prPO, gcSc}, // NORTH INDIC RUPEE MARK
+ {0xA839, 0xA839, prAL, gcSo}, // NORTH INDIC QUANTITY MARK
+ {0xA840, 0xA873, prAL, gcLo}, // [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU
+ {0xA874, 0xA875, prBB, gcPo}, // [2] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA DOUBLE HEAD MARK
+ {0xA876, 0xA877, prEX, gcPo}, // [2] PHAGS-PA MARK SHAD..PHAGS-PA MARK DOUBLE SHAD
+ {0xA880, 0xA881, prCM, gcMc}, // [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA
+ {0xA882, 0xA8B3, prAL, gcLo}, // [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA
+ {0xA8B4, 0xA8C3, prCM, gcMc}, // [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU
+ {0xA8C4, 0xA8C5, prCM, gcMn}, // [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU
+ {0xA8CE, 0xA8CF, prBA, gcPo}, // [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA
+ {0xA8D0, 0xA8D9, prNU, gcNd}, // [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
+ {0xA8E0, 0xA8F1, prCM, gcMn}, // [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA
+ {0xA8F2, 0xA8F7, prAL, gcLo}, // [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA
+ {0xA8F8, 0xA8FA, prAL, gcPo}, // [3] DEVANAGARI SIGN PUSHPIKA..DEVANAGARI CARET
+ {0xA8FB, 0xA8FB, prAL, gcLo}, // DEVANAGARI HEADSTROKE
+ {0xA8FC, 0xA8FC, prBB, gcPo}, // DEVANAGARI SIGN SIDDHAM
+ {0xA8FD, 0xA8FE, prAL, gcLo}, // [2] DEVANAGARI JAIN OM..DEVANAGARI LETTER AY
+ {0xA8FF, 0xA8FF, prCM, gcMn}, // DEVANAGARI VOWEL SIGN AY
+ {0xA900, 0xA909, prNU, gcNd}, // [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
+ {0xA90A, 0xA925, prAL, gcLo}, // [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO
+ {0xA926, 0xA92D, prCM, gcMn}, // [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU
+ {0xA92E, 0xA92F, prBA, gcPo}, // [2] KAYAH LI SIGN CWI..KAYAH LI SIGN SHYA
+ {0xA930, 0xA946, prAL, gcLo}, // [23] REJANG LETTER KA..REJANG LETTER A
+ {0xA947, 0xA951, prCM, gcMn}, // [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
+ {0xA952, 0xA953, prCM, gcMc}, // [2] REJANG CONSONANT SIGN H..REJANG VIRAMA
+ {0xA95F, 0xA95F, prAL, gcPo}, // REJANG SECTION MARK
+ {0xA960, 0xA97C, prJL, gcLo}, // [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH
+ {0xA980, 0xA982, prCM, gcMn}, // [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR
+ {0xA983, 0xA983, prCM, gcMc}, // JAVANESE SIGN WIGNYAN
+ {0xA984, 0xA9B2, prAL, gcLo}, // [47] JAVANESE LETTER A..JAVANESE LETTER HA
+ {0xA9B3, 0xA9B3, prCM, gcMn}, // JAVANESE SIGN CECAK TELU
+ {0xA9B4, 0xA9B5, prCM, gcMc}, // [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG
+ {0xA9B6, 0xA9B9, prCM, gcMn}, // [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT
+ {0xA9BA, 0xA9BB, prCM, gcMc}, // [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE
+ {0xA9BC, 0xA9BD, prCM, gcMn}, // [2] JAVANESE VOWEL SIGN PEPET..JAVANESE CONSONANT SIGN KERET
+ {0xA9BE, 0xA9C0, prCM, gcMc}, // [3] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE PANGKON
+ {0xA9C1, 0xA9C6, prAL, gcPo}, // [6] JAVANESE LEFT RERENGGAN..JAVANESE PADA WINDU
+ {0xA9C7, 0xA9C9, prBA, gcPo}, // [3] JAVANESE PADA PANGKAT..JAVANESE PADA LUNGSI
+ {0xA9CA, 0xA9CD, prAL, gcPo}, // [4] JAVANESE PADA ADEG..JAVANESE TURNED PADA PISELEH
+ {0xA9CF, 0xA9CF, prAL, gcLm}, // JAVANESE PANGRANGKEP
+ {0xA9D0, 0xA9D9, prNU, gcNd}, // [10] JAVANESE DIGIT ZERO..JAVANESE DIGIT NINE
+ {0xA9DE, 0xA9DF, prAL, gcPo}, // [2] JAVANESE PADA TIRTA TUMETES..JAVANESE PADA ISEN-ISEN
+ {0xA9E0, 0xA9E4, prSA, gcLo}, // [5] MYANMAR LETTER SHAN GHA..MYANMAR LETTER SHAN BHA
+ {0xA9E5, 0xA9E5, prSA, gcMn}, // MYANMAR SIGN SHAN SAW
+ {0xA9E6, 0xA9E6, prSA, gcLm}, // MYANMAR MODIFIER LETTER SHAN REDUPLICATION
+ {0xA9E7, 0xA9EF, prSA, gcLo}, // [9] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING NNA
+ {0xA9F0, 0xA9F9, prNU, gcNd}, // [10] MYANMAR TAI LAING DIGIT ZERO..MYANMAR TAI LAING DIGIT NINE
+ {0xA9FA, 0xA9FE, prSA, gcLo}, // [5] MYANMAR LETTER TAI LAING LLA..MYANMAR LETTER TAI LAING BHA
+ {0xAA00, 0xAA28, prAL, gcLo}, // [41] CHAM LETTER A..CHAM LETTER HA
+ {0xAA29, 0xAA2E, prCM, gcMn}, // [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE
+ {0xAA2F, 0xAA30, prCM, gcMc}, // [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI
+ {0xAA31, 0xAA32, prCM, gcMn}, // [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE
+ {0xAA33, 0xAA34, prCM, gcMc}, // [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA
+ {0xAA35, 0xAA36, prCM, gcMn}, // [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA
+ {0xAA40, 0xAA42, prAL, gcLo}, // [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG
+ {0xAA43, 0xAA43, prCM, gcMn}, // CHAM CONSONANT SIGN FINAL NG
+ {0xAA44, 0xAA4B, prAL, gcLo}, // [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS
+ {0xAA4C, 0xAA4C, prCM, gcMn}, // CHAM CONSONANT SIGN FINAL M
+ {0xAA4D, 0xAA4D, prCM, gcMc}, // CHAM CONSONANT SIGN FINAL H
+ {0xAA50, 0xAA59, prNU, gcNd}, // [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
+ {0xAA5C, 0xAA5C, prAL, gcPo}, // CHAM PUNCTUATION SPIRAL
+ {0xAA5D, 0xAA5F, prBA, gcPo}, // [3] CHAM PUNCTUATION DANDA..CHAM PUNCTUATION TRIPLE DANDA
+ {0xAA60, 0xAA6F, prSA, gcLo}, // [16] MYANMAR LETTER KHAMTI GA..MYANMAR LETTER KHAMTI FA
+ {0xAA70, 0xAA70, prSA, gcLm}, // MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION
+ {0xAA71, 0xAA76, prSA, gcLo}, // [6] MYANMAR LETTER KHAMTI XA..MYANMAR LOGOGRAM KHAMTI HM
+ {0xAA77, 0xAA79, prSA, gcSo}, // [3] MYANMAR SYMBOL AITON EXCLAMATION..MYANMAR SYMBOL AITON TWO
+ {0xAA7A, 0xAA7A, prSA, gcLo}, // MYANMAR LETTER AITON RA
+ {0xAA7B, 0xAA7B, prSA, gcMc}, // MYANMAR SIGN PAO KAREN TONE
+ {0xAA7C, 0xAA7C, prSA, gcMn}, // MYANMAR SIGN TAI LAING TONE-2
+ {0xAA7D, 0xAA7D, prSA, gcMc}, // MYANMAR SIGN TAI LAING TONE-5
+ {0xAA7E, 0xAA7F, prSA, gcLo}, // [2] MYANMAR LETTER SHWE PALAUNG CHA..MYANMAR LETTER SHWE PALAUNG SHA
+ {0xAA80, 0xAAAF, prSA, gcLo}, // [48] TAI VIET LETTER LOW KO..TAI VIET LETTER HIGH O
+ {0xAAB0, 0xAAB0, prSA, gcMn}, // TAI VIET MAI KANG
+ {0xAAB1, 0xAAB1, prSA, gcLo}, // TAI VIET VOWEL AA
+ {0xAAB2, 0xAAB4, prSA, gcMn}, // [3] TAI VIET VOWEL I..TAI VIET VOWEL U
+ {0xAAB5, 0xAAB6, prSA, gcLo}, // [2] TAI VIET VOWEL E..TAI VIET VOWEL O
+ {0xAAB7, 0xAAB8, prSA, gcMn}, // [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA
+ {0xAAB9, 0xAABD, prSA, gcLo}, // [5] TAI VIET VOWEL UEA..TAI VIET VOWEL AN
+ {0xAABE, 0xAABF, prSA, gcMn}, // [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK
+ {0xAAC0, 0xAAC0, prSA, gcLo}, // TAI VIET TONE MAI NUENG
+ {0xAAC1, 0xAAC1, prSA, gcMn}, // TAI VIET TONE MAI THO
+ {0xAAC2, 0xAAC2, prSA, gcLo}, // TAI VIET TONE MAI SONG
+ {0xAADB, 0xAADC, prSA, gcLo}, // [2] TAI VIET SYMBOL KON..TAI VIET SYMBOL NUENG
+ {0xAADD, 0xAADD, prSA, gcLm}, // TAI VIET SYMBOL SAM
+ {0xAADE, 0xAADF, prSA, gcPo}, // [2] TAI VIET SYMBOL HO HOI..TAI VIET SYMBOL KOI KOI
+ {0xAAE0, 0xAAEA, prAL, gcLo}, // [11] MEETEI MAYEK LETTER E..MEETEI MAYEK LETTER SSA
+ {0xAAEB, 0xAAEB, prCM, gcMc}, // MEETEI MAYEK VOWEL SIGN II
+ {0xAAEC, 0xAAED, prCM, gcMn}, // [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI
+ {0xAAEE, 0xAAEF, prCM, gcMc}, // [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU
+ {0xAAF0, 0xAAF1, prBA, gcPo}, // [2] MEETEI MAYEK CHEIKHAN..MEETEI MAYEK AHANG KHUDAM
+ {0xAAF2, 0xAAF2, prAL, gcLo}, // MEETEI MAYEK ANJI
+ {0xAAF3, 0xAAF4, prAL, gcLm}, // [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK
+ {0xAAF5, 0xAAF5, prCM, gcMc}, // MEETEI MAYEK VOWEL SIGN VISARGA
+ {0xAAF6, 0xAAF6, prCM, gcMn}, // MEETEI MAYEK VIRAMA
+ {0xAB01, 0xAB06, prAL, gcLo}, // [6] ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO
+ {0xAB09, 0xAB0E, prAL, gcLo}, // [6] ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO
+ {0xAB11, 0xAB16, prAL, gcLo}, // [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO
+ {0xAB20, 0xAB26, prAL, gcLo}, // [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO
+ {0xAB28, 0xAB2E, prAL, gcLo}, // [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO
+ {0xAB30, 0xAB5A, prAL, gcLl}, // [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG
+ {0xAB5B, 0xAB5B, prAL, gcSk}, // MODIFIER BREVE WITH INVERTED BREVE
+ {0xAB5C, 0xAB5F, prAL, gcLm}, // [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
+ {0xAB60, 0xAB68, prAL, gcLl}, // [9] LATIN SMALL LETTER SAKHA YAT..LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE
+ {0xAB69, 0xAB69, prAL, gcLm}, // MODIFIER LETTER SMALL TURNED W
+ {0xAB6A, 0xAB6B, prAL, gcSk}, // [2] MODIFIER LETTER LEFT TACK..MODIFIER LETTER RIGHT TACK
+ {0xAB70, 0xABBF, prAL, gcLl}, // [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
+ {0xABC0, 0xABE2, prAL, gcLo}, // [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM
+ {0xABE3, 0xABE4, prCM, gcMc}, // [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP
+ {0xABE5, 0xABE5, prCM, gcMn}, // MEETEI MAYEK VOWEL SIGN ANAP
+ {0xABE6, 0xABE7, prCM, gcMc}, // [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP
+ {0xABE8, 0xABE8, prCM, gcMn}, // MEETEI MAYEK VOWEL SIGN UNAP
+ {0xABE9, 0xABEA, prCM, gcMc}, // [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG
+ {0xABEB, 0xABEB, prBA, gcPo}, // MEETEI MAYEK CHEIKHEI
+ {0xABEC, 0xABEC, prCM, gcMc}, // MEETEI MAYEK LUM IYEK
+ {0xABED, 0xABED, prCM, gcMn}, // MEETEI MAYEK APUN IYEK
+ {0xABF0, 0xABF9, prNU, gcNd}, // [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT NINE
+ {0xAC00, 0xAC00, prH2, gcLo}, // HANGUL SYLLABLE GA
+ {0xAC01, 0xAC1B, prH3, gcLo}, // [27] HANGUL SYLLABLE GAG..HANGUL SYLLABLE GAH
+ {0xAC1C, 0xAC1C, prH2, gcLo}, // HANGUL SYLLABLE GAE
+ {0xAC1D, 0xAC37, prH3, gcLo}, // [27] HANGUL SYLLABLE GAEG..HANGUL SYLLABLE GAEH
+ {0xAC38, 0xAC38, prH2, gcLo}, // HANGUL SYLLABLE GYA
+ {0xAC39, 0xAC53, prH3, gcLo}, // [27] HANGUL SYLLABLE GYAG..HANGUL SYLLABLE GYAH
+ {0xAC54, 0xAC54, prH2, gcLo}, // HANGUL SYLLABLE GYAE
+ {0xAC55, 0xAC6F, prH3, gcLo}, // [27] HANGUL SYLLABLE GYAEG..HANGUL SYLLABLE GYAEH
+ {0xAC70, 0xAC70, prH2, gcLo}, // HANGUL SYLLABLE GEO
+ {0xAC71, 0xAC8B, prH3, gcLo}, // [27] HANGUL SYLLABLE GEOG..HANGUL SYLLABLE GEOH
+ {0xAC8C, 0xAC8C, prH2, gcLo}, // HANGUL SYLLABLE GE
+ {0xAC8D, 0xACA7, prH3, gcLo}, // [27] HANGUL SYLLABLE GEG..HANGUL SYLLABLE GEH
+ {0xACA8, 0xACA8, prH2, gcLo}, // HANGUL SYLLABLE GYEO
+ {0xACA9, 0xACC3, prH3, gcLo}, // [27] HANGUL SYLLABLE GYEOG..HANGUL SYLLABLE GYEOH
+ {0xACC4, 0xACC4, prH2, gcLo}, // HANGUL SYLLABLE GYE
+ {0xACC5, 0xACDF, prH3, gcLo}, // [27] HANGUL SYLLABLE GYEG..HANGUL SYLLABLE GYEH
+ {0xACE0, 0xACE0, prH2, gcLo}, // HANGUL SYLLABLE GO
+ {0xACE1, 0xACFB, prH3, gcLo}, // [27] HANGUL SYLLABLE GOG..HANGUL SYLLABLE GOH
+ {0xACFC, 0xACFC, prH2, gcLo}, // HANGUL SYLLABLE GWA
+ {0xACFD, 0xAD17, prH3, gcLo}, // [27] HANGUL SYLLABLE GWAG..HANGUL SYLLABLE GWAH
+ {0xAD18, 0xAD18, prH2, gcLo}, // HANGUL SYLLABLE GWAE
+ {0xAD19, 0xAD33, prH3, gcLo}, // [27] HANGUL SYLLABLE GWAEG..HANGUL SYLLABLE GWAEH
+ {0xAD34, 0xAD34, prH2, gcLo}, // HANGUL SYLLABLE GOE
+ {0xAD35, 0xAD4F, prH3, gcLo}, // [27] HANGUL SYLLABLE GOEG..HANGUL SYLLABLE GOEH
+ {0xAD50, 0xAD50, prH2, gcLo}, // HANGUL SYLLABLE GYO
+ {0xAD51, 0xAD6B, prH3, gcLo}, // [27] HANGUL SYLLABLE GYOG..HANGUL SYLLABLE GYOH
+ {0xAD6C, 0xAD6C, prH2, gcLo}, // HANGUL SYLLABLE GU
+ {0xAD6D, 0xAD87, prH3, gcLo}, // [27] HANGUL SYLLABLE GUG..HANGUL SYLLABLE GUH
+ {0xAD88, 0xAD88, prH2, gcLo}, // HANGUL SYLLABLE GWEO
+ {0xAD89, 0xADA3, prH3, gcLo}, // [27] HANGUL SYLLABLE GWEOG..HANGUL SYLLABLE GWEOH
+ {0xADA4, 0xADA4, prH2, gcLo}, // HANGUL SYLLABLE GWE
+ {0xADA5, 0xADBF, prH3, gcLo}, // [27] HANGUL SYLLABLE GWEG..HANGUL SYLLABLE GWEH
+ {0xADC0, 0xADC0, prH2, gcLo}, // HANGUL SYLLABLE GWI
+ {0xADC1, 0xADDB, prH3, gcLo}, // [27] HANGUL SYLLABLE GWIG..HANGUL SYLLABLE GWIH
+ {0xADDC, 0xADDC, prH2, gcLo}, // HANGUL SYLLABLE GYU
+ {0xADDD, 0xADF7, prH3, gcLo}, // [27] HANGUL SYLLABLE GYUG..HANGUL SYLLABLE GYUH
+ {0xADF8, 0xADF8, prH2, gcLo}, // HANGUL SYLLABLE GEU
+ {0xADF9, 0xAE13, prH3, gcLo}, // [27] HANGUL SYLLABLE GEUG..HANGUL SYLLABLE GEUH
+ {0xAE14, 0xAE14, prH2, gcLo}, // HANGUL SYLLABLE GYI
+ {0xAE15, 0xAE2F, prH3, gcLo}, // [27] HANGUL SYLLABLE GYIG..HANGUL SYLLABLE GYIH
+ {0xAE30, 0xAE30, prH2, gcLo}, // HANGUL SYLLABLE GI
+ {0xAE31, 0xAE4B, prH3, gcLo}, // [27] HANGUL SYLLABLE GIG..HANGUL SYLLABLE GIH
+ {0xAE4C, 0xAE4C, prH2, gcLo}, // HANGUL SYLLABLE GGA
+ {0xAE4D, 0xAE67, prH3, gcLo}, // [27] HANGUL SYLLABLE GGAG..HANGUL SYLLABLE GGAH
+ {0xAE68, 0xAE68, prH2, gcLo}, // HANGUL SYLLABLE GGAE
+ {0xAE69, 0xAE83, prH3, gcLo}, // [27] HANGUL SYLLABLE GGAEG..HANGUL SYLLABLE GGAEH
+ {0xAE84, 0xAE84, prH2, gcLo}, // HANGUL SYLLABLE GGYA
+ {0xAE85, 0xAE9F, prH3, gcLo}, // [27] HANGUL SYLLABLE GGYAG..HANGUL SYLLABLE GGYAH
+ {0xAEA0, 0xAEA0, prH2, gcLo}, // HANGUL SYLLABLE GGYAE
+ {0xAEA1, 0xAEBB, prH3, gcLo}, // [27] HANGUL SYLLABLE GGYAEG..HANGUL SYLLABLE GGYAEH
+ {0xAEBC, 0xAEBC, prH2, gcLo}, // HANGUL SYLLABLE GGEO
+ {0xAEBD, 0xAED7, prH3, gcLo}, // [27] HANGUL SYLLABLE GGEOG..HANGUL SYLLABLE GGEOH
+ {0xAED8, 0xAED8, prH2, gcLo}, // HANGUL SYLLABLE GGE
+ {0xAED9, 0xAEF3, prH3, gcLo}, // [27] HANGUL SYLLABLE GGEG..HANGUL SYLLABLE GGEH
+ {0xAEF4, 0xAEF4, prH2, gcLo}, // HANGUL SYLLABLE GGYEO
+ {0xAEF5, 0xAF0F, prH3, gcLo}, // [27] HANGUL SYLLABLE GGYEOG..HANGUL SYLLABLE GGYEOH
+ {0xAF10, 0xAF10, prH2, gcLo}, // HANGUL SYLLABLE GGYE
+ {0xAF11, 0xAF2B, prH3, gcLo}, // [27] HANGUL SYLLABLE GGYEG..HANGUL SYLLABLE GGYEH
+ {0xAF2C, 0xAF2C, prH2, gcLo}, // HANGUL SYLLABLE GGO
+ {0xAF2D, 0xAF47, prH3, gcLo}, // [27] HANGUL SYLLABLE GGOG..HANGUL SYLLABLE GGOH
+ {0xAF48, 0xAF48, prH2, gcLo}, // HANGUL SYLLABLE GGWA
+ {0xAF49, 0xAF63, prH3, gcLo}, // [27] HANGUL SYLLABLE GGWAG..HANGUL SYLLABLE GGWAH
+ {0xAF64, 0xAF64, prH2, gcLo}, // HANGUL SYLLABLE GGWAE
+ {0xAF65, 0xAF7F, prH3, gcLo}, // [27] HANGUL SYLLABLE GGWAEG..HANGUL SYLLABLE GGWAEH
+ {0xAF80, 0xAF80, prH2, gcLo}, // HANGUL SYLLABLE GGOE
+ {0xAF81, 0xAF9B, prH3, gcLo}, // [27] HANGUL SYLLABLE GGOEG..HANGUL SYLLABLE GGOEH
+ {0xAF9C, 0xAF9C, prH2, gcLo}, // HANGUL SYLLABLE GGYO
+ {0xAF9D, 0xAFB7, prH3, gcLo}, // [27] HANGUL SYLLABLE GGYOG..HANGUL SYLLABLE GGYOH
+ {0xAFB8, 0xAFB8, prH2, gcLo}, // HANGUL SYLLABLE GGU
+ {0xAFB9, 0xAFD3, prH3, gcLo}, // [27] HANGUL SYLLABLE GGUG..HANGUL SYLLABLE GGUH
+ {0xAFD4, 0xAFD4, prH2, gcLo}, // HANGUL SYLLABLE GGWEO
+ {0xAFD5, 0xAFEF, prH3, gcLo}, // [27] HANGUL SYLLABLE GGWEOG..HANGUL SYLLABLE GGWEOH
+ {0xAFF0, 0xAFF0, prH2, gcLo}, // HANGUL SYLLABLE GGWE
+ {0xAFF1, 0xB00B, prH3, gcLo}, // [27] HANGUL SYLLABLE GGWEG..HANGUL SYLLABLE GGWEH
+ {0xB00C, 0xB00C, prH2, gcLo}, // HANGUL SYLLABLE GGWI
+ {0xB00D, 0xB027, prH3, gcLo}, // [27] HANGUL SYLLABLE GGWIG..HANGUL SYLLABLE GGWIH
+ {0xB028, 0xB028, prH2, gcLo}, // HANGUL SYLLABLE GGYU
+ {0xB029, 0xB043, prH3, gcLo}, // [27] HANGUL SYLLABLE GGYUG..HANGUL SYLLABLE GGYUH
+ {0xB044, 0xB044, prH2, gcLo}, // HANGUL SYLLABLE GGEU
+ {0xB045, 0xB05F, prH3, gcLo}, // [27] HANGUL SYLLABLE GGEUG..HANGUL SYLLABLE GGEUH
+ {0xB060, 0xB060, prH2, gcLo}, // HANGUL SYLLABLE GGYI
+ {0xB061, 0xB07B, prH3, gcLo}, // [27] HANGUL SYLLABLE GGYIG..HANGUL SYLLABLE GGYIH
+ {0xB07C, 0xB07C, prH2, gcLo}, // HANGUL SYLLABLE GGI
+ {0xB07D, 0xB097, prH3, gcLo}, // [27] HANGUL SYLLABLE GGIG..HANGUL SYLLABLE GGIH
+ {0xB098, 0xB098, prH2, gcLo}, // HANGUL SYLLABLE NA
+ {0xB099, 0xB0B3, prH3, gcLo}, // [27] HANGUL SYLLABLE NAG..HANGUL SYLLABLE NAH
+ {0xB0B4, 0xB0B4, prH2, gcLo}, // HANGUL SYLLABLE NAE
+ {0xB0B5, 0xB0CF, prH3, gcLo}, // [27] HANGUL SYLLABLE NAEG..HANGUL SYLLABLE NAEH
+ {0xB0D0, 0xB0D0, prH2, gcLo}, // HANGUL SYLLABLE NYA
+ {0xB0D1, 0xB0EB, prH3, gcLo}, // [27] HANGUL SYLLABLE NYAG..HANGUL SYLLABLE NYAH
+ {0xB0EC, 0xB0EC, prH2, gcLo}, // HANGUL SYLLABLE NYAE
+ {0xB0ED, 0xB107, prH3, gcLo}, // [27] HANGUL SYLLABLE NYAEG..HANGUL SYLLABLE NYAEH
+ {0xB108, 0xB108, prH2, gcLo}, // HANGUL SYLLABLE NEO
+ {0xB109, 0xB123, prH3, gcLo}, // [27] HANGUL SYLLABLE NEOG..HANGUL SYLLABLE NEOH
+ {0xB124, 0xB124, prH2, gcLo}, // HANGUL SYLLABLE NE
+ {0xB125, 0xB13F, prH3, gcLo}, // [27] HANGUL SYLLABLE NEG..HANGUL SYLLABLE NEH
+ {0xB140, 0xB140, prH2, gcLo}, // HANGUL SYLLABLE NYEO
+ {0xB141, 0xB15B, prH3, gcLo}, // [27] HANGUL SYLLABLE NYEOG..HANGUL SYLLABLE NYEOH
+ {0xB15C, 0xB15C, prH2, gcLo}, // HANGUL SYLLABLE NYE
+ {0xB15D, 0xB177, prH3, gcLo}, // [27] HANGUL SYLLABLE NYEG..HANGUL SYLLABLE NYEH
+ {0xB178, 0xB178, prH2, gcLo}, // HANGUL SYLLABLE NO
+ {0xB179, 0xB193, prH3, gcLo}, // [27] HANGUL SYLLABLE NOG..HANGUL SYLLABLE NOH
+ {0xB194, 0xB194, prH2, gcLo}, // HANGUL SYLLABLE NWA
+ {0xB195, 0xB1AF, prH3, gcLo}, // [27] HANGUL SYLLABLE NWAG..HANGUL SYLLABLE NWAH
+ {0xB1B0, 0xB1B0, prH2, gcLo}, // HANGUL SYLLABLE NWAE
+ {0xB1B1, 0xB1CB, prH3, gcLo}, // [27] HANGUL SYLLABLE NWAEG..HANGUL SYLLABLE NWAEH
+ {0xB1CC, 0xB1CC, prH2, gcLo}, // HANGUL SYLLABLE NOE
+ {0xB1CD, 0xB1E7, prH3, gcLo}, // [27] HANGUL SYLLABLE NOEG..HANGUL SYLLABLE NOEH
+ {0xB1E8, 0xB1E8, prH2, gcLo}, // HANGUL SYLLABLE NYO
+ {0xB1E9, 0xB203, prH3, gcLo}, // [27] HANGUL SYLLABLE NYOG..HANGUL SYLLABLE NYOH
+ {0xB204, 0xB204, prH2, gcLo}, // HANGUL SYLLABLE NU
+ {0xB205, 0xB21F, prH3, gcLo}, // [27] HANGUL SYLLABLE NUG..HANGUL SYLLABLE NUH
+ {0xB220, 0xB220, prH2, gcLo}, // HANGUL SYLLABLE NWEO
+ {0xB221, 0xB23B, prH3, gcLo}, // [27] HANGUL SYLLABLE NWEOG..HANGUL SYLLABLE NWEOH
+ {0xB23C, 0xB23C, prH2, gcLo}, // HANGUL SYLLABLE NWE
+ {0xB23D, 0xB257, prH3, gcLo}, // [27] HANGUL SYLLABLE NWEG..HANGUL SYLLABLE NWEH
+ {0xB258, 0xB258, prH2, gcLo}, // HANGUL SYLLABLE NWI
+ {0xB259, 0xB273, prH3, gcLo}, // [27] HANGUL SYLLABLE NWIG..HANGUL SYLLABLE NWIH
+ {0xB274, 0xB274, prH2, gcLo}, // HANGUL SYLLABLE NYU
+ {0xB275, 0xB28F, prH3, gcLo}, // [27] HANGUL SYLLABLE NYUG..HANGUL SYLLABLE NYUH
+ {0xB290, 0xB290, prH2, gcLo}, // HANGUL SYLLABLE NEU
+ {0xB291, 0xB2AB, prH3, gcLo}, // [27] HANGUL SYLLABLE NEUG..HANGUL SYLLABLE NEUH
+ {0xB2AC, 0xB2AC, prH2, gcLo}, // HANGUL SYLLABLE NYI
+ {0xB2AD, 0xB2C7, prH3, gcLo}, // [27] HANGUL SYLLABLE NYIG..HANGUL SYLLABLE NYIH
+ {0xB2C8, 0xB2C8, prH2, gcLo}, // HANGUL SYLLABLE NI
+ {0xB2C9, 0xB2E3, prH3, gcLo}, // [27] HANGUL SYLLABLE NIG..HANGUL SYLLABLE NIH
+ {0xB2E4, 0xB2E4, prH2, gcLo}, // HANGUL SYLLABLE DA
+ {0xB2E5, 0xB2FF, prH3, gcLo}, // [27] HANGUL SYLLABLE DAG..HANGUL SYLLABLE DAH
+ {0xB300, 0xB300, prH2, gcLo}, // HANGUL SYLLABLE DAE
+ {0xB301, 0xB31B, prH3, gcLo}, // [27] HANGUL SYLLABLE DAEG..HANGUL SYLLABLE DAEH
+ {0xB31C, 0xB31C, prH2, gcLo}, // HANGUL SYLLABLE DYA
+ {0xB31D, 0xB337, prH3, gcLo}, // [27] HANGUL SYLLABLE DYAG..HANGUL SYLLABLE DYAH
+ {0xB338, 0xB338, prH2, gcLo}, // HANGUL SYLLABLE DYAE
+ {0xB339, 0xB353, prH3, gcLo}, // [27] HANGUL SYLLABLE DYAEG..HANGUL SYLLABLE DYAEH
+ {0xB354, 0xB354, prH2, gcLo}, // HANGUL SYLLABLE DEO
+ {0xB355, 0xB36F, prH3, gcLo}, // [27] HANGUL SYLLABLE DEOG..HANGUL SYLLABLE DEOH
+ {0xB370, 0xB370, prH2, gcLo}, // HANGUL SYLLABLE DE
+ {0xB371, 0xB38B, prH3, gcLo}, // [27] HANGUL SYLLABLE DEG..HANGUL SYLLABLE DEH
+ {0xB38C, 0xB38C, prH2, gcLo}, // HANGUL SYLLABLE DYEO
+ {0xB38D, 0xB3A7, prH3, gcLo}, // [27] HANGUL SYLLABLE DYEOG..HANGUL SYLLABLE DYEOH
+ {0xB3A8, 0xB3A8, prH2, gcLo}, // HANGUL SYLLABLE DYE
+ {0xB3A9, 0xB3C3, prH3, gcLo}, // [27] HANGUL SYLLABLE DYEG..HANGUL SYLLABLE DYEH
+ {0xB3C4, 0xB3C4, prH2, gcLo}, // HANGUL SYLLABLE DO
+ {0xB3C5, 0xB3DF, prH3, gcLo}, // [27] HANGUL SYLLABLE DOG..HANGUL SYLLABLE DOH
+ {0xB3E0, 0xB3E0, prH2, gcLo}, // HANGUL SYLLABLE DWA
+ {0xB3E1, 0xB3FB, prH3, gcLo}, // [27] HANGUL SYLLABLE DWAG..HANGUL SYLLABLE DWAH
+ {0xB3FC, 0xB3FC, prH2, gcLo}, // HANGUL SYLLABLE DWAE
+ {0xB3FD, 0xB417, prH3, gcLo}, // [27] HANGUL SYLLABLE DWAEG..HANGUL SYLLABLE DWAEH
+ {0xB418, 0xB418, prH2, gcLo}, // HANGUL SYLLABLE DOE
+ {0xB419, 0xB433, prH3, gcLo}, // [27] HANGUL SYLLABLE DOEG..HANGUL SYLLABLE DOEH
+ {0xB434, 0xB434, prH2, gcLo}, // HANGUL SYLLABLE DYO
+ {0xB435, 0xB44F, prH3, gcLo}, // [27] HANGUL SYLLABLE DYOG..HANGUL SYLLABLE DYOH
+ {0xB450, 0xB450, prH2, gcLo}, // HANGUL SYLLABLE DU
+ {0xB451, 0xB46B, prH3, gcLo}, // [27] HANGUL SYLLABLE DUG..HANGUL SYLLABLE DUH
+ {0xB46C, 0xB46C, prH2, gcLo}, // HANGUL SYLLABLE DWEO
+ {0xB46D, 0xB487, prH3, gcLo}, // [27] HANGUL SYLLABLE DWEOG..HANGUL SYLLABLE DWEOH
+ {0xB488, 0xB488, prH2, gcLo}, // HANGUL SYLLABLE DWE
+ {0xB489, 0xB4A3, prH3, gcLo}, // [27] HANGUL SYLLABLE DWEG..HANGUL SYLLABLE DWEH
+ {0xB4A4, 0xB4A4, prH2, gcLo}, // HANGUL SYLLABLE DWI
+ {0xB4A5, 0xB4BF, prH3, gcLo}, // [27] HANGUL SYLLABLE DWIG..HANGUL SYLLABLE DWIH
+ {0xB4C0, 0xB4C0, prH2, gcLo}, // HANGUL SYLLABLE DYU
+ {0xB4C1, 0xB4DB, prH3, gcLo}, // [27] HANGUL SYLLABLE DYUG..HANGUL SYLLABLE DYUH
+ {0xB4DC, 0xB4DC, prH2, gcLo}, // HANGUL SYLLABLE DEU
+ {0xB4DD, 0xB4F7, prH3, gcLo}, // [27] HANGUL SYLLABLE DEUG..HANGUL SYLLABLE DEUH
+ {0xB4F8, 0xB4F8, prH2, gcLo}, // HANGUL SYLLABLE DYI
+ {0xB4F9, 0xB513, prH3, gcLo}, // [27] HANGUL SYLLABLE DYIG..HANGUL SYLLABLE DYIH
+ {0xB514, 0xB514, prH2, gcLo}, // HANGUL SYLLABLE DI
+ {0xB515, 0xB52F, prH3, gcLo}, // [27] HANGUL SYLLABLE DIG..HANGUL SYLLABLE DIH
+ {0xB530, 0xB530, prH2, gcLo}, // HANGUL SYLLABLE DDA
+ {0xB531, 0xB54B, prH3, gcLo}, // [27] HANGUL SYLLABLE DDAG..HANGUL SYLLABLE DDAH
+ {0xB54C, 0xB54C, prH2, gcLo}, // HANGUL SYLLABLE DDAE
+ {0xB54D, 0xB567, prH3, gcLo}, // [27] HANGUL SYLLABLE DDAEG..HANGUL SYLLABLE DDAEH
+ {0xB568, 0xB568, prH2, gcLo}, // HANGUL SYLLABLE DDYA
+ {0xB569, 0xB583, prH3, gcLo}, // [27] HANGUL SYLLABLE DDYAG..HANGUL SYLLABLE DDYAH
+ {0xB584, 0xB584, prH2, gcLo}, // HANGUL SYLLABLE DDYAE
+ {0xB585, 0xB59F, prH3, gcLo}, // [27] HANGUL SYLLABLE DDYAEG..HANGUL SYLLABLE DDYAEH
+ {0xB5A0, 0xB5A0, prH2, gcLo}, // HANGUL SYLLABLE DDEO
+ {0xB5A1, 0xB5BB, prH3, gcLo}, // [27] HANGUL SYLLABLE DDEOG..HANGUL SYLLABLE DDEOH
+ {0xB5BC, 0xB5BC, prH2, gcLo}, // HANGUL SYLLABLE DDE
+ {0xB5BD, 0xB5D7, prH3, gcLo}, // [27] HANGUL SYLLABLE DDEG..HANGUL SYLLABLE DDEH
+ {0xB5D8, 0xB5D8, prH2, gcLo}, // HANGUL SYLLABLE DDYEO
+ {0xB5D9, 0xB5F3, prH3, gcLo}, // [27] HANGUL SYLLABLE DDYEOG..HANGUL SYLLABLE DDYEOH
+ {0xB5F4, 0xB5F4, prH2, gcLo}, // HANGUL SYLLABLE DDYE
+ {0xB5F5, 0xB60F, prH3, gcLo}, // [27] HANGUL SYLLABLE DDYEG..HANGUL SYLLABLE DDYEH
+ {0xB610, 0xB610, prH2, gcLo}, // HANGUL SYLLABLE DDO
+ {0xB611, 0xB62B, prH3, gcLo}, // [27] HANGUL SYLLABLE DDOG..HANGUL SYLLABLE DDOH
+ {0xB62C, 0xB62C, prH2, gcLo}, // HANGUL SYLLABLE DDWA
+ {0xB62D, 0xB647, prH3, gcLo}, // [27] HANGUL SYLLABLE DDWAG..HANGUL SYLLABLE DDWAH
+ {0xB648, 0xB648, prH2, gcLo}, // HANGUL SYLLABLE DDWAE
+ {0xB649, 0xB663, prH3, gcLo}, // [27] HANGUL SYLLABLE DDWAEG..HANGUL SYLLABLE DDWAEH
+ {0xB664, 0xB664, prH2, gcLo}, // HANGUL SYLLABLE DDOE
+ {0xB665, 0xB67F, prH3, gcLo}, // [27] HANGUL SYLLABLE DDOEG..HANGUL SYLLABLE DDOEH
+ {0xB680, 0xB680, prH2, gcLo}, // HANGUL SYLLABLE DDYO
+ {0xB681, 0xB69B, prH3, gcLo}, // [27] HANGUL SYLLABLE DDYOG..HANGUL SYLLABLE DDYOH
+ {0xB69C, 0xB69C, prH2, gcLo}, // HANGUL SYLLABLE DDU
+ {0xB69D, 0xB6B7, prH3, gcLo}, // [27] HANGUL SYLLABLE DDUG..HANGUL SYLLABLE DDUH
+ {0xB6B8, 0xB6B8, prH2, gcLo}, // HANGUL SYLLABLE DDWEO
+ {0xB6B9, 0xB6D3, prH3, gcLo}, // [27] HANGUL SYLLABLE DDWEOG..HANGUL SYLLABLE DDWEOH
+ {0xB6D4, 0xB6D4, prH2, gcLo}, // HANGUL SYLLABLE DDWE
+ {0xB6D5, 0xB6EF, prH3, gcLo}, // [27] HANGUL SYLLABLE DDWEG..HANGUL SYLLABLE DDWEH
+ {0xB6F0, 0xB6F0, prH2, gcLo}, // HANGUL SYLLABLE DDWI
+ {0xB6F1, 0xB70B, prH3, gcLo}, // [27] HANGUL SYLLABLE DDWIG..HANGUL SYLLABLE DDWIH
+ {0xB70C, 0xB70C, prH2, gcLo}, // HANGUL SYLLABLE DDYU
+ {0xB70D, 0xB727, prH3, gcLo}, // [27] HANGUL SYLLABLE DDYUG..HANGUL SYLLABLE DDYUH
+ {0xB728, 0xB728, prH2, gcLo}, // HANGUL SYLLABLE DDEU
+ {0xB729, 0xB743, prH3, gcLo}, // [27] HANGUL SYLLABLE DDEUG..HANGUL SYLLABLE DDEUH
+ {0xB744, 0xB744, prH2, gcLo}, // HANGUL SYLLABLE DDYI
+ {0xB745, 0xB75F, prH3, gcLo}, // [27] HANGUL SYLLABLE DDYIG..HANGUL SYLLABLE DDYIH
+ {0xB760, 0xB760, prH2, gcLo}, // HANGUL SYLLABLE DDI
+ {0xB761, 0xB77B, prH3, gcLo}, // [27] HANGUL SYLLABLE DDIG..HANGUL SYLLABLE DDIH
+ {0xB77C, 0xB77C, prH2, gcLo}, // HANGUL SYLLABLE RA
+ {0xB77D, 0xB797, prH3, gcLo}, // [27] HANGUL SYLLABLE RAG..HANGUL SYLLABLE RAH
+ {0xB798, 0xB798, prH2, gcLo}, // HANGUL SYLLABLE RAE
+ {0xB799, 0xB7B3, prH3, gcLo}, // [27] HANGUL SYLLABLE RAEG..HANGUL SYLLABLE RAEH
+ {0xB7B4, 0xB7B4, prH2, gcLo}, // HANGUL SYLLABLE RYA
+ {0xB7B5, 0xB7CF, prH3, gcLo}, // [27] HANGUL SYLLABLE RYAG..HANGUL SYLLABLE RYAH
+ {0xB7D0, 0xB7D0, prH2, gcLo}, // HANGUL SYLLABLE RYAE
+ {0xB7D1, 0xB7EB, prH3, gcLo}, // [27] HANGUL SYLLABLE RYAEG..HANGUL SYLLABLE RYAEH
+ {0xB7EC, 0xB7EC, prH2, gcLo}, // HANGUL SYLLABLE REO
+ {0xB7ED, 0xB807, prH3, gcLo}, // [27] HANGUL SYLLABLE REOG..HANGUL SYLLABLE REOH
+ {0xB808, 0xB808, prH2, gcLo}, // HANGUL SYLLABLE RE
+ {0xB809, 0xB823, prH3, gcLo}, // [27] HANGUL SYLLABLE REG..HANGUL SYLLABLE REH
+ {0xB824, 0xB824, prH2, gcLo}, // HANGUL SYLLABLE RYEO
+ {0xB825, 0xB83F, prH3, gcLo}, // [27] HANGUL SYLLABLE RYEOG..HANGUL SYLLABLE RYEOH
+ {0xB840, 0xB840, prH2, gcLo}, // HANGUL SYLLABLE RYE
+ {0xB841, 0xB85B, prH3, gcLo}, // [27] HANGUL SYLLABLE RYEG..HANGUL SYLLABLE RYEH
+ {0xB85C, 0xB85C, prH2, gcLo}, // HANGUL SYLLABLE RO
+ {0xB85D, 0xB877, prH3, gcLo}, // [27] HANGUL SYLLABLE ROG..HANGUL SYLLABLE ROH
+ {0xB878, 0xB878, prH2, gcLo}, // HANGUL SYLLABLE RWA
+ {0xB879, 0xB893, prH3, gcLo}, // [27] HANGUL SYLLABLE RWAG..HANGUL SYLLABLE RWAH
+ {0xB894, 0xB894, prH2, gcLo}, // HANGUL SYLLABLE RWAE
+ {0xB895, 0xB8AF, prH3, gcLo}, // [27] HANGUL SYLLABLE RWAEG..HANGUL SYLLABLE RWAEH
+ {0xB8B0, 0xB8B0, prH2, gcLo}, // HANGUL SYLLABLE ROE
+ {0xB8B1, 0xB8CB, prH3, gcLo}, // [27] HANGUL SYLLABLE ROEG..HANGUL SYLLABLE ROEH
+ {0xB8CC, 0xB8CC, prH2, gcLo}, // HANGUL SYLLABLE RYO
+ {0xB8CD, 0xB8E7, prH3, gcLo}, // [27] HANGUL SYLLABLE RYOG..HANGUL SYLLABLE RYOH
+ {0xB8E8, 0xB8E8, prH2, gcLo}, // HANGUL SYLLABLE RU
+ {0xB8E9, 0xB903, prH3, gcLo}, // [27] HANGUL SYLLABLE RUG..HANGUL SYLLABLE RUH
+ {0xB904, 0xB904, prH2, gcLo}, // HANGUL SYLLABLE RWEO
+ {0xB905, 0xB91F, prH3, gcLo}, // [27] HANGUL SYLLABLE RWEOG..HANGUL SYLLABLE RWEOH
+ {0xB920, 0xB920, prH2, gcLo}, // HANGUL SYLLABLE RWE
+ {0xB921, 0xB93B, prH3, gcLo}, // [27] HANGUL SYLLABLE RWEG..HANGUL SYLLABLE RWEH
+ {0xB93C, 0xB93C, prH2, gcLo}, // HANGUL SYLLABLE RWI
+ {0xB93D, 0xB957, prH3, gcLo}, // [27] HANGUL SYLLABLE RWIG..HANGUL SYLLABLE RWIH
+ {0xB958, 0xB958, prH2, gcLo}, // HANGUL SYLLABLE RYU
+ {0xB959, 0xB973, prH3, gcLo}, // [27] HANGUL SYLLABLE RYUG..HANGUL SYLLABLE RYUH
+ {0xB974, 0xB974, prH2, gcLo}, // HANGUL SYLLABLE REU
+ {0xB975, 0xB98F, prH3, gcLo}, // [27] HANGUL SYLLABLE REUG..HANGUL SYLLABLE REUH
+ {0xB990, 0xB990, prH2, gcLo}, // HANGUL SYLLABLE RYI
+ {0xB991, 0xB9AB, prH3, gcLo}, // [27] HANGUL SYLLABLE RYIG..HANGUL SYLLABLE RYIH
+ {0xB9AC, 0xB9AC, prH2, gcLo}, // HANGUL SYLLABLE RI
+ {0xB9AD, 0xB9C7, prH3, gcLo}, // [27] HANGUL SYLLABLE RIG..HANGUL SYLLABLE RIH
+ {0xB9C8, 0xB9C8, prH2, gcLo}, // HANGUL SYLLABLE MA
+ {0xB9C9, 0xB9E3, prH3, gcLo}, // [27] HANGUL SYLLABLE MAG..HANGUL SYLLABLE MAH
+ {0xB9E4, 0xB9E4, prH2, gcLo}, // HANGUL SYLLABLE MAE
+ {0xB9E5, 0xB9FF, prH3, gcLo}, // [27] HANGUL SYLLABLE MAEG..HANGUL SYLLABLE MAEH
+ {0xBA00, 0xBA00, prH2, gcLo}, // HANGUL SYLLABLE MYA
+ {0xBA01, 0xBA1B, prH3, gcLo}, // [27] HANGUL SYLLABLE MYAG..HANGUL SYLLABLE MYAH
+ {0xBA1C, 0xBA1C, prH2, gcLo}, // HANGUL SYLLABLE MYAE
+ {0xBA1D, 0xBA37, prH3, gcLo}, // [27] HANGUL SYLLABLE MYAEG..HANGUL SYLLABLE MYAEH
+ {0xBA38, 0xBA38, prH2, gcLo}, // HANGUL SYLLABLE MEO
+ {0xBA39, 0xBA53, prH3, gcLo}, // [27] HANGUL SYLLABLE MEOG..HANGUL SYLLABLE MEOH
+ {0xBA54, 0xBA54, prH2, gcLo}, // HANGUL SYLLABLE ME
+ {0xBA55, 0xBA6F, prH3, gcLo}, // [27] HANGUL SYLLABLE MEG..HANGUL SYLLABLE MEH
+ {0xBA70, 0xBA70, prH2, gcLo}, // HANGUL SYLLABLE MYEO
+ {0xBA71, 0xBA8B, prH3, gcLo}, // [27] HANGUL SYLLABLE MYEOG..HANGUL SYLLABLE MYEOH
+ {0xBA8C, 0xBA8C, prH2, gcLo}, // HANGUL SYLLABLE MYE
+ {0xBA8D, 0xBAA7, prH3, gcLo}, // [27] HANGUL SYLLABLE MYEG..HANGUL SYLLABLE MYEH
+ {0xBAA8, 0xBAA8, prH2, gcLo}, // HANGUL SYLLABLE MO
+ {0xBAA9, 0xBAC3, prH3, gcLo}, // [27] HANGUL SYLLABLE MOG..HANGUL SYLLABLE MOH
+ {0xBAC4, 0xBAC4, prH2, gcLo}, // HANGUL SYLLABLE MWA
+ {0xBAC5, 0xBADF, prH3, gcLo}, // [27] HANGUL SYLLABLE MWAG..HANGUL SYLLABLE MWAH
+ {0xBAE0, 0xBAE0, prH2, gcLo}, // HANGUL SYLLABLE MWAE
+ {0xBAE1, 0xBAFB, prH3, gcLo}, // [27] HANGUL SYLLABLE MWAEG..HANGUL SYLLABLE MWAEH
+ {0xBAFC, 0xBAFC, prH2, gcLo}, // HANGUL SYLLABLE MOE
+ {0xBAFD, 0xBB17, prH3, gcLo}, // [27] HANGUL SYLLABLE MOEG..HANGUL SYLLABLE MOEH
+ {0xBB18, 0xBB18, prH2, gcLo}, // HANGUL SYLLABLE MYO
+ {0xBB19, 0xBB33, prH3, gcLo}, // [27] HANGUL SYLLABLE MYOG..HANGUL SYLLABLE MYOH
+ {0xBB34, 0xBB34, prH2, gcLo}, // HANGUL SYLLABLE MU
+ {0xBB35, 0xBB4F, prH3, gcLo}, // [27] HANGUL SYLLABLE MUG..HANGUL SYLLABLE MUH
+ {0xBB50, 0xBB50, prH2, gcLo}, // HANGUL SYLLABLE MWEO
+ {0xBB51, 0xBB6B, prH3, gcLo}, // [27] HANGUL SYLLABLE MWEOG..HANGUL SYLLABLE MWEOH
+ {0xBB6C, 0xBB6C, prH2, gcLo}, // HANGUL SYLLABLE MWE
+ {0xBB6D, 0xBB87, prH3, gcLo}, // [27] HANGUL SYLLABLE MWEG..HANGUL SYLLABLE MWEH
+ {0xBB88, 0xBB88, prH2, gcLo}, // HANGUL SYLLABLE MWI
+ {0xBB89, 0xBBA3, prH3, gcLo}, // [27] HANGUL SYLLABLE MWIG..HANGUL SYLLABLE MWIH
+ {0xBBA4, 0xBBA4, prH2, gcLo}, // HANGUL SYLLABLE MYU
+ {0xBBA5, 0xBBBF, prH3, gcLo}, // [27] HANGUL SYLLABLE MYUG..HANGUL SYLLABLE MYUH
+ {0xBBC0, 0xBBC0, prH2, gcLo}, // HANGUL SYLLABLE MEU
+ {0xBBC1, 0xBBDB, prH3, gcLo}, // [27] HANGUL SYLLABLE MEUG..HANGUL SYLLABLE MEUH
+ {0xBBDC, 0xBBDC, prH2, gcLo}, // HANGUL SYLLABLE MYI
+ {0xBBDD, 0xBBF7, prH3, gcLo}, // [27] HANGUL SYLLABLE MYIG..HANGUL SYLLABLE MYIH
+ {0xBBF8, 0xBBF8, prH2, gcLo}, // HANGUL SYLLABLE MI
+ {0xBBF9, 0xBC13, prH3, gcLo}, // [27] HANGUL SYLLABLE MIG..HANGUL SYLLABLE MIH
+ {0xBC14, 0xBC14, prH2, gcLo}, // HANGUL SYLLABLE BA
+ {0xBC15, 0xBC2F, prH3, gcLo}, // [27] HANGUL SYLLABLE BAG..HANGUL SYLLABLE BAH
+ {0xBC30, 0xBC30, prH2, gcLo}, // HANGUL SYLLABLE BAE
+ {0xBC31, 0xBC4B, prH3, gcLo}, // [27] HANGUL SYLLABLE BAEG..HANGUL SYLLABLE BAEH
+ {0xBC4C, 0xBC4C, prH2, gcLo}, // HANGUL SYLLABLE BYA
+ {0xBC4D, 0xBC67, prH3, gcLo}, // [27] HANGUL SYLLABLE BYAG..HANGUL SYLLABLE BYAH
+ {0xBC68, 0xBC68, prH2, gcLo}, // HANGUL SYLLABLE BYAE
+ {0xBC69, 0xBC83, prH3, gcLo}, // [27] HANGUL SYLLABLE BYAEG..HANGUL SYLLABLE BYAEH
+ {0xBC84, 0xBC84, prH2, gcLo}, // HANGUL SYLLABLE BEO
+ {0xBC85, 0xBC9F, prH3, gcLo}, // [27] HANGUL SYLLABLE BEOG..HANGUL SYLLABLE BEOH
+ {0xBCA0, 0xBCA0, prH2, gcLo}, // HANGUL SYLLABLE BE
+ {0xBCA1, 0xBCBB, prH3, gcLo}, // [27] HANGUL SYLLABLE BEG..HANGUL SYLLABLE BEH
+ {0xBCBC, 0xBCBC, prH2, gcLo}, // HANGUL SYLLABLE BYEO
+ {0xBCBD, 0xBCD7, prH3, gcLo}, // [27] HANGUL SYLLABLE BYEOG..HANGUL SYLLABLE BYEOH
+ {0xBCD8, 0xBCD8, prH2, gcLo}, // HANGUL SYLLABLE BYE
+ {0xBCD9, 0xBCF3, prH3, gcLo}, // [27] HANGUL SYLLABLE BYEG..HANGUL SYLLABLE BYEH
+ {0xBCF4, 0xBCF4, prH2, gcLo}, // HANGUL SYLLABLE BO
+ {0xBCF5, 0xBD0F, prH3, gcLo}, // [27] HANGUL SYLLABLE BOG..HANGUL SYLLABLE BOH
+ {0xBD10, 0xBD10, prH2, gcLo}, // HANGUL SYLLABLE BWA
+ {0xBD11, 0xBD2B, prH3, gcLo}, // [27] HANGUL SYLLABLE BWAG..HANGUL SYLLABLE BWAH
+ {0xBD2C, 0xBD2C, prH2, gcLo}, // HANGUL SYLLABLE BWAE
+ {0xBD2D, 0xBD47, prH3, gcLo}, // [27] HANGUL SYLLABLE BWAEG..HANGUL SYLLABLE BWAEH
+ {0xBD48, 0xBD48, prH2, gcLo}, // HANGUL SYLLABLE BOE
+ {0xBD49, 0xBD63, prH3, gcLo}, // [27] HANGUL SYLLABLE BOEG..HANGUL SYLLABLE BOEH
+ {0xBD64, 0xBD64, prH2, gcLo}, // HANGUL SYLLABLE BYO
+ {0xBD65, 0xBD7F, prH3, gcLo}, // [27] HANGUL SYLLABLE BYOG..HANGUL SYLLABLE BYOH
+ {0xBD80, 0xBD80, prH2, gcLo}, // HANGUL SYLLABLE BU
+ {0xBD81, 0xBD9B, prH3, gcLo}, // [27] HANGUL SYLLABLE BUG..HANGUL SYLLABLE BUH
+ {0xBD9C, 0xBD9C, prH2, gcLo}, // HANGUL SYLLABLE BWEO
+ {0xBD9D, 0xBDB7, prH3, gcLo}, // [27] HANGUL SYLLABLE BWEOG..HANGUL SYLLABLE BWEOH
+ {0xBDB8, 0xBDB8, prH2, gcLo}, // HANGUL SYLLABLE BWE
+ {0xBDB9, 0xBDD3, prH3, gcLo}, // [27] HANGUL SYLLABLE BWEG..HANGUL SYLLABLE BWEH
+ {0xBDD4, 0xBDD4, prH2, gcLo}, // HANGUL SYLLABLE BWI
+ {0xBDD5, 0xBDEF, prH3, gcLo}, // [27] HANGUL SYLLABLE BWIG..HANGUL SYLLABLE BWIH
+ {0xBDF0, 0xBDF0, prH2, gcLo}, // HANGUL SYLLABLE BYU
+ {0xBDF1, 0xBE0B, prH3, gcLo}, // [27] HANGUL SYLLABLE BYUG..HANGUL SYLLABLE BYUH
+ {0xBE0C, 0xBE0C, prH2, gcLo}, // HANGUL SYLLABLE BEU
+ {0xBE0D, 0xBE27, prH3, gcLo}, // [27] HANGUL SYLLABLE BEUG..HANGUL SYLLABLE BEUH
+ {0xBE28, 0xBE28, prH2, gcLo}, // HANGUL SYLLABLE BYI
+ {0xBE29, 0xBE43, prH3, gcLo}, // [27] HANGUL SYLLABLE BYIG..HANGUL SYLLABLE BYIH
+ {0xBE44, 0xBE44, prH2, gcLo}, // HANGUL SYLLABLE BI
+ {0xBE45, 0xBE5F, prH3, gcLo}, // [27] HANGUL SYLLABLE BIG..HANGUL SYLLABLE BIH
+ {0xBE60, 0xBE60, prH2, gcLo}, // HANGUL SYLLABLE BBA
+ {0xBE61, 0xBE7B, prH3, gcLo}, // [27] HANGUL SYLLABLE BBAG..HANGUL SYLLABLE BBAH
+ {0xBE7C, 0xBE7C, prH2, gcLo}, // HANGUL SYLLABLE BBAE
+ {0xBE7D, 0xBE97, prH3, gcLo}, // [27] HANGUL SYLLABLE BBAEG..HANGUL SYLLABLE BBAEH
+ {0xBE98, 0xBE98, prH2, gcLo}, // HANGUL SYLLABLE BBYA
+ {0xBE99, 0xBEB3, prH3, gcLo}, // [27] HANGUL SYLLABLE BBYAG..HANGUL SYLLABLE BBYAH
+ {0xBEB4, 0xBEB4, prH2, gcLo}, // HANGUL SYLLABLE BBYAE
+ {0xBEB5, 0xBECF, prH3, gcLo}, // [27] HANGUL SYLLABLE BBYAEG..HANGUL SYLLABLE BBYAEH
+ {0xBED0, 0xBED0, prH2, gcLo}, // HANGUL SYLLABLE BBEO
+ {0xBED1, 0xBEEB, prH3, gcLo}, // [27] HANGUL SYLLABLE BBEOG..HANGUL SYLLABLE BBEOH
+ {0xBEEC, 0xBEEC, prH2, gcLo}, // HANGUL SYLLABLE BBE
+ {0xBEED, 0xBF07, prH3, gcLo}, // [27] HANGUL SYLLABLE BBEG..HANGUL SYLLABLE BBEH
+ {0xBF08, 0xBF08, prH2, gcLo}, // HANGUL SYLLABLE BBYEO
+ {0xBF09, 0xBF23, prH3, gcLo}, // [27] HANGUL SYLLABLE BBYEOG..HANGUL SYLLABLE BBYEOH
+ {0xBF24, 0xBF24, prH2, gcLo}, // HANGUL SYLLABLE BBYE
+ {0xBF25, 0xBF3F, prH3, gcLo}, // [27] HANGUL SYLLABLE BBYEG..HANGUL SYLLABLE BBYEH
+ {0xBF40, 0xBF40, prH2, gcLo}, // HANGUL SYLLABLE BBO
+ {0xBF41, 0xBF5B, prH3, gcLo}, // [27] HANGUL SYLLABLE BBOG..HANGUL SYLLABLE BBOH
+ {0xBF5C, 0xBF5C, prH2, gcLo}, // HANGUL SYLLABLE BBWA
+ {0xBF5D, 0xBF77, prH3, gcLo}, // [27] HANGUL SYLLABLE BBWAG..HANGUL SYLLABLE BBWAH
+ {0xBF78, 0xBF78, prH2, gcLo}, // HANGUL SYLLABLE BBWAE
+ {0xBF79, 0xBF93, prH3, gcLo}, // [27] HANGUL SYLLABLE BBWAEG..HANGUL SYLLABLE BBWAEH
+ {0xBF94, 0xBF94, prH2, gcLo}, // HANGUL SYLLABLE BBOE
+ {0xBF95, 0xBFAF, prH3, gcLo}, // [27] HANGUL SYLLABLE BBOEG..HANGUL SYLLABLE BBOEH
+ {0xBFB0, 0xBFB0, prH2, gcLo}, // HANGUL SYLLABLE BBYO
+ {0xBFB1, 0xBFCB, prH3, gcLo}, // [27] HANGUL SYLLABLE BBYOG..HANGUL SYLLABLE BBYOH
+ {0xBFCC, 0xBFCC, prH2, gcLo}, // HANGUL SYLLABLE BBU
+ {0xBFCD, 0xBFE7, prH3, gcLo}, // [27] HANGUL SYLLABLE BBUG..HANGUL SYLLABLE BBUH
+ {0xBFE8, 0xBFE8, prH2, gcLo}, // HANGUL SYLLABLE BBWEO
+ {0xBFE9, 0xC003, prH3, gcLo}, // [27] HANGUL SYLLABLE BBWEOG..HANGUL SYLLABLE BBWEOH
+ {0xC004, 0xC004, prH2, gcLo}, // HANGUL SYLLABLE BBWE
+ {0xC005, 0xC01F, prH3, gcLo}, // [27] HANGUL SYLLABLE BBWEG..HANGUL SYLLABLE BBWEH
+ {0xC020, 0xC020, prH2, gcLo}, // HANGUL SYLLABLE BBWI
+ {0xC021, 0xC03B, prH3, gcLo}, // [27] HANGUL SYLLABLE BBWIG..HANGUL SYLLABLE BBWIH
+ {0xC03C, 0xC03C, prH2, gcLo}, // HANGUL SYLLABLE BBYU
+ {0xC03D, 0xC057, prH3, gcLo}, // [27] HANGUL SYLLABLE BBYUG..HANGUL SYLLABLE BBYUH
+ {0xC058, 0xC058, prH2, gcLo}, // HANGUL SYLLABLE BBEU
+ {0xC059, 0xC073, prH3, gcLo}, // [27] HANGUL SYLLABLE BBEUG..HANGUL SYLLABLE BBEUH
+ {0xC074, 0xC074, prH2, gcLo}, // HANGUL SYLLABLE BBYI
+ {0xC075, 0xC08F, prH3, gcLo}, // [27] HANGUL SYLLABLE BBYIG..HANGUL SYLLABLE BBYIH
+ {0xC090, 0xC090, prH2, gcLo}, // HANGUL SYLLABLE BBI
+ {0xC091, 0xC0AB, prH3, gcLo}, // [27] HANGUL SYLLABLE BBIG..HANGUL SYLLABLE BBIH
+ {0xC0AC, 0xC0AC, prH2, gcLo}, // HANGUL SYLLABLE SA
+ {0xC0AD, 0xC0C7, prH3, gcLo}, // [27] HANGUL SYLLABLE SAG..HANGUL SYLLABLE SAH
+ {0xC0C8, 0xC0C8, prH2, gcLo}, // HANGUL SYLLABLE SAE
+ {0xC0C9, 0xC0E3, prH3, gcLo}, // [27] HANGUL SYLLABLE SAEG..HANGUL SYLLABLE SAEH
+ {0xC0E4, 0xC0E4, prH2, gcLo}, // HANGUL SYLLABLE SYA
+ {0xC0E5, 0xC0FF, prH3, gcLo}, // [27] HANGUL SYLLABLE SYAG..HANGUL SYLLABLE SYAH
+ {0xC100, 0xC100, prH2, gcLo}, // HANGUL SYLLABLE SYAE
+ {0xC101, 0xC11B, prH3, gcLo}, // [27] HANGUL SYLLABLE SYAEG..HANGUL SYLLABLE SYAEH
+ {0xC11C, 0xC11C, prH2, gcLo}, // HANGUL SYLLABLE SEO
+ {0xC11D, 0xC137, prH3, gcLo}, // [27] HANGUL SYLLABLE SEOG..HANGUL SYLLABLE SEOH
+ {0xC138, 0xC138, prH2, gcLo}, // HANGUL SYLLABLE SE
+ {0xC139, 0xC153, prH3, gcLo}, // [27] HANGUL SYLLABLE SEG..HANGUL SYLLABLE SEH
+ {0xC154, 0xC154, prH2, gcLo}, // HANGUL SYLLABLE SYEO
+ {0xC155, 0xC16F, prH3, gcLo}, // [27] HANGUL SYLLABLE SYEOG..HANGUL SYLLABLE SYEOH
+ {0xC170, 0xC170, prH2, gcLo}, // HANGUL SYLLABLE SYE
+ {0xC171, 0xC18B, prH3, gcLo}, // [27] HANGUL SYLLABLE SYEG..HANGUL SYLLABLE SYEH
+ {0xC18C, 0xC18C, prH2, gcLo}, // HANGUL SYLLABLE SO
+ {0xC18D, 0xC1A7, prH3, gcLo}, // [27] HANGUL SYLLABLE SOG..HANGUL SYLLABLE SOH
+ {0xC1A8, 0xC1A8, prH2, gcLo}, // HANGUL SYLLABLE SWA
+ {0xC1A9, 0xC1C3, prH3, gcLo}, // [27] HANGUL SYLLABLE SWAG..HANGUL SYLLABLE SWAH
+ {0xC1C4, 0xC1C4, prH2, gcLo}, // HANGUL SYLLABLE SWAE
+ {0xC1C5, 0xC1DF, prH3, gcLo}, // [27] HANGUL SYLLABLE SWAEG..HANGUL SYLLABLE SWAEH
+ {0xC1E0, 0xC1E0, prH2, gcLo}, // HANGUL SYLLABLE SOE
+ {0xC1E1, 0xC1FB, prH3, gcLo}, // [27] HANGUL SYLLABLE SOEG..HANGUL SYLLABLE SOEH
+ {0xC1FC, 0xC1FC, prH2, gcLo}, // HANGUL SYLLABLE SYO
+ {0xC1FD, 0xC217, prH3, gcLo}, // [27] HANGUL SYLLABLE SYOG..HANGUL SYLLABLE SYOH
+ {0xC218, 0xC218, prH2, gcLo}, // HANGUL SYLLABLE SU
+ {0xC219, 0xC233, prH3, gcLo}, // [27] HANGUL SYLLABLE SUG..HANGUL SYLLABLE SUH
+ {0xC234, 0xC234, prH2, gcLo}, // HANGUL SYLLABLE SWEO
+ {0xC235, 0xC24F, prH3, gcLo}, // [27] HANGUL SYLLABLE SWEOG..HANGUL SYLLABLE SWEOH
+ {0xC250, 0xC250, prH2, gcLo}, // HANGUL SYLLABLE SWE
+ {0xC251, 0xC26B, prH3, gcLo}, // [27] HANGUL SYLLABLE SWEG..HANGUL SYLLABLE SWEH
+ {0xC26C, 0xC26C, prH2, gcLo}, // HANGUL SYLLABLE SWI
+ {0xC26D, 0xC287, prH3, gcLo}, // [27] HANGUL SYLLABLE SWIG..HANGUL SYLLABLE SWIH
+ {0xC288, 0xC288, prH2, gcLo}, // HANGUL SYLLABLE SYU
+ {0xC289, 0xC2A3, prH3, gcLo}, // [27] HANGUL SYLLABLE SYUG..HANGUL SYLLABLE SYUH
+ {0xC2A4, 0xC2A4, prH2, gcLo}, // HANGUL SYLLABLE SEU
+ {0xC2A5, 0xC2BF, prH3, gcLo}, // [27] HANGUL SYLLABLE SEUG..HANGUL SYLLABLE SEUH
+ {0xC2C0, 0xC2C0, prH2, gcLo}, // HANGUL SYLLABLE SYI
+ {0xC2C1, 0xC2DB, prH3, gcLo}, // [27] HANGUL SYLLABLE SYIG..HANGUL SYLLABLE SYIH
+ {0xC2DC, 0xC2DC, prH2, gcLo}, // HANGUL SYLLABLE SI
+ {0xC2DD, 0xC2F7, prH3, gcLo}, // [27] HANGUL SYLLABLE SIG..HANGUL SYLLABLE SIH
+ {0xC2F8, 0xC2F8, prH2, gcLo}, // HANGUL SYLLABLE SSA
+ {0xC2F9, 0xC313, prH3, gcLo}, // [27] HANGUL SYLLABLE SSAG..HANGUL SYLLABLE SSAH
+ {0xC314, 0xC314, prH2, gcLo}, // HANGUL SYLLABLE SSAE
+ {0xC315, 0xC32F, prH3, gcLo}, // [27] HANGUL SYLLABLE SSAEG..HANGUL SYLLABLE SSAEH
+ {0xC330, 0xC330, prH2, gcLo}, // HANGUL SYLLABLE SSYA
+ {0xC331, 0xC34B, prH3, gcLo}, // [27] HANGUL SYLLABLE SSYAG..HANGUL SYLLABLE SSYAH
+ {0xC34C, 0xC34C, prH2, gcLo}, // HANGUL SYLLABLE SSYAE
+ {0xC34D, 0xC367, prH3, gcLo}, // [27] HANGUL SYLLABLE SSYAEG..HANGUL SYLLABLE SSYAEH
+ {0xC368, 0xC368, prH2, gcLo}, // HANGUL SYLLABLE SSEO
+ {0xC369, 0xC383, prH3, gcLo}, // [27] HANGUL SYLLABLE SSEOG..HANGUL SYLLABLE SSEOH
+ {0xC384, 0xC384, prH2, gcLo}, // HANGUL SYLLABLE SSE
+ {0xC385, 0xC39F, prH3, gcLo}, // [27] HANGUL SYLLABLE SSEG..HANGUL SYLLABLE SSEH
+ {0xC3A0, 0xC3A0, prH2, gcLo}, // HANGUL SYLLABLE SSYEO
+ {0xC3A1, 0xC3BB, prH3, gcLo}, // [27] HANGUL SYLLABLE SSYEOG..HANGUL SYLLABLE SSYEOH
+ {0xC3BC, 0xC3BC, prH2, gcLo}, // HANGUL SYLLABLE SSYE
+ {0xC3BD, 0xC3D7, prH3, gcLo}, // [27] HANGUL SYLLABLE SSYEG..HANGUL SYLLABLE SSYEH
+ {0xC3D8, 0xC3D8, prH2, gcLo}, // HANGUL SYLLABLE SSO
+ {0xC3D9, 0xC3F3, prH3, gcLo}, // [27] HANGUL SYLLABLE SSOG..HANGUL SYLLABLE SSOH
+ {0xC3F4, 0xC3F4, prH2, gcLo}, // HANGUL SYLLABLE SSWA
+ {0xC3F5, 0xC40F, prH3, gcLo}, // [27] HANGUL SYLLABLE SSWAG..HANGUL SYLLABLE SSWAH
+ {0xC410, 0xC410, prH2, gcLo}, // HANGUL SYLLABLE SSWAE
+ {0xC411, 0xC42B, prH3, gcLo}, // [27] HANGUL SYLLABLE SSWAEG..HANGUL SYLLABLE SSWAEH
+ {0xC42C, 0xC42C, prH2, gcLo}, // HANGUL SYLLABLE SSOE
+ {0xC42D, 0xC447, prH3, gcLo}, // [27] HANGUL SYLLABLE SSOEG..HANGUL SYLLABLE SSOEH
+ {0xC448, 0xC448, prH2, gcLo}, // HANGUL SYLLABLE SSYO
+ {0xC449, 0xC463, prH3, gcLo}, // [27] HANGUL SYLLABLE SSYOG..HANGUL SYLLABLE SSYOH
+ {0xC464, 0xC464, prH2, gcLo}, // HANGUL SYLLABLE SSU
+ {0xC465, 0xC47F, prH3, gcLo}, // [27] HANGUL SYLLABLE SSUG..HANGUL SYLLABLE SSUH
+ {0xC480, 0xC480, prH2, gcLo}, // HANGUL SYLLABLE SSWEO
+ {0xC481, 0xC49B, prH3, gcLo}, // [27] HANGUL SYLLABLE SSWEOG..HANGUL SYLLABLE SSWEOH
+ {0xC49C, 0xC49C, prH2, gcLo}, // HANGUL SYLLABLE SSWE
+ {0xC49D, 0xC4B7, prH3, gcLo}, // [27] HANGUL SYLLABLE SSWEG..HANGUL SYLLABLE SSWEH
+ {0xC4B8, 0xC4B8, prH2, gcLo}, // HANGUL SYLLABLE SSWI
+ {0xC4B9, 0xC4D3, prH3, gcLo}, // [27] HANGUL SYLLABLE SSWIG..HANGUL SYLLABLE SSWIH
+ {0xC4D4, 0xC4D4, prH2, gcLo}, // HANGUL SYLLABLE SSYU
+ {0xC4D5, 0xC4EF, prH3, gcLo}, // [27] HANGUL SYLLABLE SSYUG..HANGUL SYLLABLE SSYUH
+ {0xC4F0, 0xC4F0, prH2, gcLo}, // HANGUL SYLLABLE SSEU
+ {0xC4F1, 0xC50B, prH3, gcLo}, // [27] HANGUL SYLLABLE SSEUG..HANGUL SYLLABLE SSEUH
+ {0xC50C, 0xC50C, prH2, gcLo}, // HANGUL SYLLABLE SSYI
+ {0xC50D, 0xC527, prH3, gcLo}, // [27] HANGUL SYLLABLE SSYIG..HANGUL SYLLABLE SSYIH
+ {0xC528, 0xC528, prH2, gcLo}, // HANGUL SYLLABLE SSI
+ {0xC529, 0xC543, prH3, gcLo}, // [27] HANGUL SYLLABLE SSIG..HANGUL SYLLABLE SSIH
+ {0xC544, 0xC544, prH2, gcLo}, // HANGUL SYLLABLE A
+ {0xC545, 0xC55F, prH3, gcLo}, // [27] HANGUL SYLLABLE AG..HANGUL SYLLABLE AH
+ {0xC560, 0xC560, prH2, gcLo}, // HANGUL SYLLABLE AE
+ {0xC561, 0xC57B, prH3, gcLo}, // [27] HANGUL SYLLABLE AEG..HANGUL SYLLABLE AEH
+ {0xC57C, 0xC57C, prH2, gcLo}, // HANGUL SYLLABLE YA
+ {0xC57D, 0xC597, prH3, gcLo}, // [27] HANGUL SYLLABLE YAG..HANGUL SYLLABLE YAH
+ {0xC598, 0xC598, prH2, gcLo}, // HANGUL SYLLABLE YAE
+ {0xC599, 0xC5B3, prH3, gcLo}, // [27] HANGUL SYLLABLE YAEG..HANGUL SYLLABLE YAEH
+ {0xC5B4, 0xC5B4, prH2, gcLo}, // HANGUL SYLLABLE EO
+ {0xC5B5, 0xC5CF, prH3, gcLo}, // [27] HANGUL SYLLABLE EOG..HANGUL SYLLABLE EOH
+ {0xC5D0, 0xC5D0, prH2, gcLo}, // HANGUL SYLLABLE E
+ {0xC5D1, 0xC5EB, prH3, gcLo}, // [27] HANGUL SYLLABLE EG..HANGUL SYLLABLE EH
+ {0xC5EC, 0xC5EC, prH2, gcLo}, // HANGUL SYLLABLE YEO
+ {0xC5ED, 0xC607, prH3, gcLo}, // [27] HANGUL SYLLABLE YEOG..HANGUL SYLLABLE YEOH
+ {0xC608, 0xC608, prH2, gcLo}, // HANGUL SYLLABLE YE
+ {0xC609, 0xC623, prH3, gcLo}, // [27] HANGUL SYLLABLE YEG..HANGUL SYLLABLE YEH
+ {0xC624, 0xC624, prH2, gcLo}, // HANGUL SYLLABLE O
+ {0xC625, 0xC63F, prH3, gcLo}, // [27] HANGUL SYLLABLE OG..HANGUL SYLLABLE OH
+ {0xC640, 0xC640, prH2, gcLo}, // HANGUL SYLLABLE WA
+ {0xC641, 0xC65B, prH3, gcLo}, // [27] HANGUL SYLLABLE WAG..HANGUL SYLLABLE WAH
+ {0xC65C, 0xC65C, prH2, gcLo}, // HANGUL SYLLABLE WAE
+ {0xC65D, 0xC677, prH3, gcLo}, // [27] HANGUL SYLLABLE WAEG..HANGUL SYLLABLE WAEH
+ {0xC678, 0xC678, prH2, gcLo}, // HANGUL SYLLABLE OE
+ {0xC679, 0xC693, prH3, gcLo}, // [27] HANGUL SYLLABLE OEG..HANGUL SYLLABLE OEH
+ {0xC694, 0xC694, prH2, gcLo}, // HANGUL SYLLABLE YO
+ {0xC695, 0xC6AF, prH3, gcLo}, // [27] HANGUL SYLLABLE YOG..HANGUL SYLLABLE YOH
+ {0xC6B0, 0xC6B0, prH2, gcLo}, // HANGUL SYLLABLE U
+ {0xC6B1, 0xC6CB, prH3, gcLo}, // [27] HANGUL SYLLABLE UG..HANGUL SYLLABLE UH
+ {0xC6CC, 0xC6CC, prH2, gcLo}, // HANGUL SYLLABLE WEO
+ {0xC6CD, 0xC6E7, prH3, gcLo}, // [27] HANGUL SYLLABLE WEOG..HANGUL SYLLABLE WEOH
+ {0xC6E8, 0xC6E8, prH2, gcLo}, // HANGUL SYLLABLE WE
+ {0xC6E9, 0xC703, prH3, gcLo}, // [27] HANGUL SYLLABLE WEG..HANGUL SYLLABLE WEH
+ {0xC704, 0xC704, prH2, gcLo}, // HANGUL SYLLABLE WI
+ {0xC705, 0xC71F, prH3, gcLo}, // [27] HANGUL SYLLABLE WIG..HANGUL SYLLABLE WIH
+ {0xC720, 0xC720, prH2, gcLo}, // HANGUL SYLLABLE YU
+ {0xC721, 0xC73B, prH3, gcLo}, // [27] HANGUL SYLLABLE YUG..HANGUL SYLLABLE YUH
+ {0xC73C, 0xC73C, prH2, gcLo}, // HANGUL SYLLABLE EU
+ {0xC73D, 0xC757, prH3, gcLo}, // [27] HANGUL SYLLABLE EUG..HANGUL SYLLABLE EUH
+ {0xC758, 0xC758, prH2, gcLo}, // HANGUL SYLLABLE YI
+ {0xC759, 0xC773, prH3, gcLo}, // [27] HANGUL SYLLABLE YIG..HANGUL SYLLABLE YIH
+ {0xC774, 0xC774, prH2, gcLo}, // HANGUL SYLLABLE I
+ {0xC775, 0xC78F, prH3, gcLo}, // [27] HANGUL SYLLABLE IG..HANGUL SYLLABLE IH
+ {0xC790, 0xC790, prH2, gcLo}, // HANGUL SYLLABLE JA
+ {0xC791, 0xC7AB, prH3, gcLo}, // [27] HANGUL SYLLABLE JAG..HANGUL SYLLABLE JAH
+ {0xC7AC, 0xC7AC, prH2, gcLo}, // HANGUL SYLLABLE JAE
+ {0xC7AD, 0xC7C7, prH3, gcLo}, // [27] HANGUL SYLLABLE JAEG..HANGUL SYLLABLE JAEH
+ {0xC7C8, 0xC7C8, prH2, gcLo}, // HANGUL SYLLABLE JYA
+ {0xC7C9, 0xC7E3, prH3, gcLo}, // [27] HANGUL SYLLABLE JYAG..HANGUL SYLLABLE JYAH
+ {0xC7E4, 0xC7E4, prH2, gcLo}, // HANGUL SYLLABLE JYAE
+ {0xC7E5, 0xC7FF, prH3, gcLo}, // [27] HANGUL SYLLABLE JYAEG..HANGUL SYLLABLE JYAEH
+ {0xC800, 0xC800, prH2, gcLo}, // HANGUL SYLLABLE JEO
+ {0xC801, 0xC81B, prH3, gcLo}, // [27] HANGUL SYLLABLE JEOG..HANGUL SYLLABLE JEOH
+ {0xC81C, 0xC81C, prH2, gcLo}, // HANGUL SYLLABLE JE
+ {0xC81D, 0xC837, prH3, gcLo}, // [27] HANGUL SYLLABLE JEG..HANGUL SYLLABLE JEH
+ {0xC838, 0xC838, prH2, gcLo}, // HANGUL SYLLABLE JYEO
+ {0xC839, 0xC853, prH3, gcLo}, // [27] HANGUL SYLLABLE JYEOG..HANGUL SYLLABLE JYEOH
+ {0xC854, 0xC854, prH2, gcLo}, // HANGUL SYLLABLE JYE
+ {0xC855, 0xC86F, prH3, gcLo}, // [27] HANGUL SYLLABLE JYEG..HANGUL SYLLABLE JYEH
+ {0xC870, 0xC870, prH2, gcLo}, // HANGUL SYLLABLE JO
+ {0xC871, 0xC88B, prH3, gcLo}, // [27] HANGUL SYLLABLE JOG..HANGUL SYLLABLE JOH
+ {0xC88C, 0xC88C, prH2, gcLo}, // HANGUL SYLLABLE JWA
+ {0xC88D, 0xC8A7, prH3, gcLo}, // [27] HANGUL SYLLABLE JWAG..HANGUL SYLLABLE JWAH
+ {0xC8A8, 0xC8A8, prH2, gcLo}, // HANGUL SYLLABLE JWAE
+ {0xC8A9, 0xC8C3, prH3, gcLo}, // [27] HANGUL SYLLABLE JWAEG..HANGUL SYLLABLE JWAEH
+ {0xC8C4, 0xC8C4, prH2, gcLo}, // HANGUL SYLLABLE JOE
+ {0xC8C5, 0xC8DF, prH3, gcLo}, // [27] HANGUL SYLLABLE JOEG..HANGUL SYLLABLE JOEH
+ {0xC8E0, 0xC8E0, prH2, gcLo}, // HANGUL SYLLABLE JYO
+ {0xC8E1, 0xC8FB, prH3, gcLo}, // [27] HANGUL SYLLABLE JYOG..HANGUL SYLLABLE JYOH
+ {0xC8FC, 0xC8FC, prH2, gcLo}, // HANGUL SYLLABLE JU
+ {0xC8FD, 0xC917, prH3, gcLo}, // [27] HANGUL SYLLABLE JUG..HANGUL SYLLABLE JUH
+ {0xC918, 0xC918, prH2, gcLo}, // HANGUL SYLLABLE JWEO
+ {0xC919, 0xC933, prH3, gcLo}, // [27] HANGUL SYLLABLE JWEOG..HANGUL SYLLABLE JWEOH
+ {0xC934, 0xC934, prH2, gcLo}, // HANGUL SYLLABLE JWE
+ {0xC935, 0xC94F, prH3, gcLo}, // [27] HANGUL SYLLABLE JWEG..HANGUL SYLLABLE JWEH
+ {0xC950, 0xC950, prH2, gcLo}, // HANGUL SYLLABLE JWI
+ {0xC951, 0xC96B, prH3, gcLo}, // [27] HANGUL SYLLABLE JWIG..HANGUL SYLLABLE JWIH
+ {0xC96C, 0xC96C, prH2, gcLo}, // HANGUL SYLLABLE JYU
+ {0xC96D, 0xC987, prH3, gcLo}, // [27] HANGUL SYLLABLE JYUG..HANGUL SYLLABLE JYUH
+ {0xC988, 0xC988, prH2, gcLo}, // HANGUL SYLLABLE JEU
+ {0xC989, 0xC9A3, prH3, gcLo}, // [27] HANGUL SYLLABLE JEUG..HANGUL SYLLABLE JEUH
+ {0xC9A4, 0xC9A4, prH2, gcLo}, // HANGUL SYLLABLE JYI
+ {0xC9A5, 0xC9BF, prH3, gcLo}, // [27] HANGUL SYLLABLE JYIG..HANGUL SYLLABLE JYIH
+ {0xC9C0, 0xC9C0, prH2, gcLo}, // HANGUL SYLLABLE JI
+ {0xC9C1, 0xC9DB, prH3, gcLo}, // [27] HANGUL SYLLABLE JIG..HANGUL SYLLABLE JIH
+ {0xC9DC, 0xC9DC, prH2, gcLo}, // HANGUL SYLLABLE JJA
+ {0xC9DD, 0xC9F7, prH3, gcLo}, // [27] HANGUL SYLLABLE JJAG..HANGUL SYLLABLE JJAH
+ {0xC9F8, 0xC9F8, prH2, gcLo}, // HANGUL SYLLABLE JJAE
+ {0xC9F9, 0xCA13, prH3, gcLo}, // [27] HANGUL SYLLABLE JJAEG..HANGUL SYLLABLE JJAEH
+ {0xCA14, 0xCA14, prH2, gcLo}, // HANGUL SYLLABLE JJYA
+ {0xCA15, 0xCA2F, prH3, gcLo}, // [27] HANGUL SYLLABLE JJYAG..HANGUL SYLLABLE JJYAH
+ {0xCA30, 0xCA30, prH2, gcLo}, // HANGUL SYLLABLE JJYAE
+ {0xCA31, 0xCA4B, prH3, gcLo}, // [27] HANGUL SYLLABLE JJYAEG..HANGUL SYLLABLE JJYAEH
+ {0xCA4C, 0xCA4C, prH2, gcLo}, // HANGUL SYLLABLE JJEO
+ {0xCA4D, 0xCA67, prH3, gcLo}, // [27] HANGUL SYLLABLE JJEOG..HANGUL SYLLABLE JJEOH
+ {0xCA68, 0xCA68, prH2, gcLo}, // HANGUL SYLLABLE JJE
+ {0xCA69, 0xCA83, prH3, gcLo}, // [27] HANGUL SYLLABLE JJEG..HANGUL SYLLABLE JJEH
+ {0xCA84, 0xCA84, prH2, gcLo}, // HANGUL SYLLABLE JJYEO
+ {0xCA85, 0xCA9F, prH3, gcLo}, // [27] HANGUL SYLLABLE JJYEOG..HANGUL SYLLABLE JJYEOH
+ {0xCAA0, 0xCAA0, prH2, gcLo}, // HANGUL SYLLABLE JJYE
+ {0xCAA1, 0xCABB, prH3, gcLo}, // [27] HANGUL SYLLABLE JJYEG..HANGUL SYLLABLE JJYEH
+ {0xCABC, 0xCABC, prH2, gcLo}, // HANGUL SYLLABLE JJO
+ {0xCABD, 0xCAD7, prH3, gcLo}, // [27] HANGUL SYLLABLE JJOG..HANGUL SYLLABLE JJOH
+ {0xCAD8, 0xCAD8, prH2, gcLo}, // HANGUL SYLLABLE JJWA
+ {0xCAD9, 0xCAF3, prH3, gcLo}, // [27] HANGUL SYLLABLE JJWAG..HANGUL SYLLABLE JJWAH
+ {0xCAF4, 0xCAF4, prH2, gcLo}, // HANGUL SYLLABLE JJWAE
+ {0xCAF5, 0xCB0F, prH3, gcLo}, // [27] HANGUL SYLLABLE JJWAEG..HANGUL SYLLABLE JJWAEH
+ {0xCB10, 0xCB10, prH2, gcLo}, // HANGUL SYLLABLE JJOE
+ {0xCB11, 0xCB2B, prH3, gcLo}, // [27] HANGUL SYLLABLE JJOEG..HANGUL SYLLABLE JJOEH
+ {0xCB2C, 0xCB2C, prH2, gcLo}, // HANGUL SYLLABLE JJYO
+ {0xCB2D, 0xCB47, prH3, gcLo}, // [27] HANGUL SYLLABLE JJYOG..HANGUL SYLLABLE JJYOH
+ {0xCB48, 0xCB48, prH2, gcLo}, // HANGUL SYLLABLE JJU
+ {0xCB49, 0xCB63, prH3, gcLo}, // [27] HANGUL SYLLABLE JJUG..HANGUL SYLLABLE JJUH
+ {0xCB64, 0xCB64, prH2, gcLo}, // HANGUL SYLLABLE JJWEO
+ {0xCB65, 0xCB7F, prH3, gcLo}, // [27] HANGUL SYLLABLE JJWEOG..HANGUL SYLLABLE JJWEOH
+ {0xCB80, 0xCB80, prH2, gcLo}, // HANGUL SYLLABLE JJWE
+ {0xCB81, 0xCB9B, prH3, gcLo}, // [27] HANGUL SYLLABLE JJWEG..HANGUL SYLLABLE JJWEH
+ {0xCB9C, 0xCB9C, prH2, gcLo}, // HANGUL SYLLABLE JJWI
+ {0xCB9D, 0xCBB7, prH3, gcLo}, // [27] HANGUL SYLLABLE JJWIG..HANGUL SYLLABLE JJWIH
+ {0xCBB8, 0xCBB8, prH2, gcLo}, // HANGUL SYLLABLE JJYU
+ {0xCBB9, 0xCBD3, prH3, gcLo}, // [27] HANGUL SYLLABLE JJYUG..HANGUL SYLLABLE JJYUH
+ {0xCBD4, 0xCBD4, prH2, gcLo}, // HANGUL SYLLABLE JJEU
+ {0xCBD5, 0xCBEF, prH3, gcLo}, // [27] HANGUL SYLLABLE JJEUG..HANGUL SYLLABLE JJEUH
+ {0xCBF0, 0xCBF0, prH2, gcLo}, // HANGUL SYLLABLE JJYI
+ {0xCBF1, 0xCC0B, prH3, gcLo}, // [27] HANGUL SYLLABLE JJYIG..HANGUL SYLLABLE JJYIH
+ {0xCC0C, 0xCC0C, prH2, gcLo}, // HANGUL SYLLABLE JJI
+ {0xCC0D, 0xCC27, prH3, gcLo}, // [27] HANGUL SYLLABLE JJIG..HANGUL SYLLABLE JJIH
+ {0xCC28, 0xCC28, prH2, gcLo}, // HANGUL SYLLABLE CA
+ {0xCC29, 0xCC43, prH3, gcLo}, // [27] HANGUL SYLLABLE CAG..HANGUL SYLLABLE CAH
+ {0xCC44, 0xCC44, prH2, gcLo}, // HANGUL SYLLABLE CAE
+ {0xCC45, 0xCC5F, prH3, gcLo}, // [27] HANGUL SYLLABLE CAEG..HANGUL SYLLABLE CAEH
+ {0xCC60, 0xCC60, prH2, gcLo}, // HANGUL SYLLABLE CYA
+ {0xCC61, 0xCC7B, prH3, gcLo}, // [27] HANGUL SYLLABLE CYAG..HANGUL SYLLABLE CYAH
+ {0xCC7C, 0xCC7C, prH2, gcLo}, // HANGUL SYLLABLE CYAE
+ {0xCC7D, 0xCC97, prH3, gcLo}, // [27] HANGUL SYLLABLE CYAEG..HANGUL SYLLABLE CYAEH
+ {0xCC98, 0xCC98, prH2, gcLo}, // HANGUL SYLLABLE CEO
+ {0xCC99, 0xCCB3, prH3, gcLo}, // [27] HANGUL SYLLABLE CEOG..HANGUL SYLLABLE CEOH
+ {0xCCB4, 0xCCB4, prH2, gcLo}, // HANGUL SYLLABLE CE
+ {0xCCB5, 0xCCCF, prH3, gcLo}, // [27] HANGUL SYLLABLE CEG..HANGUL SYLLABLE CEH
+ {0xCCD0, 0xCCD0, prH2, gcLo}, // HANGUL SYLLABLE CYEO
+ {0xCCD1, 0xCCEB, prH3, gcLo}, // [27] HANGUL SYLLABLE CYEOG..HANGUL SYLLABLE CYEOH
+ {0xCCEC, 0xCCEC, prH2, gcLo}, // HANGUL SYLLABLE CYE
+ {0xCCED, 0xCD07, prH3, gcLo}, // [27] HANGUL SYLLABLE CYEG..HANGUL SYLLABLE CYEH
+ {0xCD08, 0xCD08, prH2, gcLo}, // HANGUL SYLLABLE CO
+ {0xCD09, 0xCD23, prH3, gcLo}, // [27] HANGUL SYLLABLE COG..HANGUL SYLLABLE COH
+ {0xCD24, 0xCD24, prH2, gcLo}, // HANGUL SYLLABLE CWA
+ {0xCD25, 0xCD3F, prH3, gcLo}, // [27] HANGUL SYLLABLE CWAG..HANGUL SYLLABLE CWAH
+ {0xCD40, 0xCD40, prH2, gcLo}, // HANGUL SYLLABLE CWAE
+ {0xCD41, 0xCD5B, prH3, gcLo}, // [27] HANGUL SYLLABLE CWAEG..HANGUL SYLLABLE CWAEH
+ {0xCD5C, 0xCD5C, prH2, gcLo}, // HANGUL SYLLABLE COE
+ {0xCD5D, 0xCD77, prH3, gcLo}, // [27] HANGUL SYLLABLE COEG..HANGUL SYLLABLE COEH
+ {0xCD78, 0xCD78, prH2, gcLo}, // HANGUL SYLLABLE CYO
+ {0xCD79, 0xCD93, prH3, gcLo}, // [27] HANGUL SYLLABLE CYOG..HANGUL SYLLABLE CYOH
+ {0xCD94, 0xCD94, prH2, gcLo}, // HANGUL SYLLABLE CU
+ {0xCD95, 0xCDAF, prH3, gcLo}, // [27] HANGUL SYLLABLE CUG..HANGUL SYLLABLE CUH
+ {0xCDB0, 0xCDB0, prH2, gcLo}, // HANGUL SYLLABLE CWEO
+ {0xCDB1, 0xCDCB, prH3, gcLo}, // [27] HANGUL SYLLABLE CWEOG..HANGUL SYLLABLE CWEOH
+ {0xCDCC, 0xCDCC, prH2, gcLo}, // HANGUL SYLLABLE CWE
+ {0xCDCD, 0xCDE7, prH3, gcLo}, // [27] HANGUL SYLLABLE CWEG..HANGUL SYLLABLE CWEH
+ {0xCDE8, 0xCDE8, prH2, gcLo}, // HANGUL SYLLABLE CWI
+ {0xCDE9, 0xCE03, prH3, gcLo}, // [27] HANGUL SYLLABLE CWIG..HANGUL SYLLABLE CWIH
+ {0xCE04, 0xCE04, prH2, gcLo}, // HANGUL SYLLABLE CYU
+ {0xCE05, 0xCE1F, prH3, gcLo}, // [27] HANGUL SYLLABLE CYUG..HANGUL SYLLABLE CYUH
+ {0xCE20, 0xCE20, prH2, gcLo}, // HANGUL SYLLABLE CEU
+ {0xCE21, 0xCE3B, prH3, gcLo}, // [27] HANGUL SYLLABLE CEUG..HANGUL SYLLABLE CEUH
+ {0xCE3C, 0xCE3C, prH2, gcLo}, // HANGUL SYLLABLE CYI
+ {0xCE3D, 0xCE57, prH3, gcLo}, // [27] HANGUL SYLLABLE CYIG..HANGUL SYLLABLE CYIH
+ {0xCE58, 0xCE58, prH2, gcLo}, // HANGUL SYLLABLE CI
+ {0xCE59, 0xCE73, prH3, gcLo}, // [27] HANGUL SYLLABLE CIG..HANGUL SYLLABLE CIH
+ {0xCE74, 0xCE74, prH2, gcLo}, // HANGUL SYLLABLE KA
+ {0xCE75, 0xCE8F, prH3, gcLo}, // [27] HANGUL SYLLABLE KAG..HANGUL SYLLABLE KAH
+ {0xCE90, 0xCE90, prH2, gcLo}, // HANGUL SYLLABLE KAE
+ {0xCE91, 0xCEAB, prH3, gcLo}, // [27] HANGUL SYLLABLE KAEG..HANGUL SYLLABLE KAEH
+ {0xCEAC, 0xCEAC, prH2, gcLo}, // HANGUL SYLLABLE KYA
+ {0xCEAD, 0xCEC7, prH3, gcLo}, // [27] HANGUL SYLLABLE KYAG..HANGUL SYLLABLE KYAH
+ {0xCEC8, 0xCEC8, prH2, gcLo}, // HANGUL SYLLABLE KYAE
+ {0xCEC9, 0xCEE3, prH3, gcLo}, // [27] HANGUL SYLLABLE KYAEG..HANGUL SYLLABLE KYAEH
+ {0xCEE4, 0xCEE4, prH2, gcLo}, // HANGUL SYLLABLE KEO
+ {0xCEE5, 0xCEFF, prH3, gcLo}, // [27] HANGUL SYLLABLE KEOG..HANGUL SYLLABLE KEOH
+ {0xCF00, 0xCF00, prH2, gcLo}, // HANGUL SYLLABLE KE
+ {0xCF01, 0xCF1B, prH3, gcLo}, // [27] HANGUL SYLLABLE KEG..HANGUL SYLLABLE KEH
+ {0xCF1C, 0xCF1C, prH2, gcLo}, // HANGUL SYLLABLE KYEO
+ {0xCF1D, 0xCF37, prH3, gcLo}, // [27] HANGUL SYLLABLE KYEOG..HANGUL SYLLABLE KYEOH
+ {0xCF38, 0xCF38, prH2, gcLo}, // HANGUL SYLLABLE KYE
+ {0xCF39, 0xCF53, prH3, gcLo}, // [27] HANGUL SYLLABLE KYEG..HANGUL SYLLABLE KYEH
+ {0xCF54, 0xCF54, prH2, gcLo}, // HANGUL SYLLABLE KO
+ {0xCF55, 0xCF6F, prH3, gcLo}, // [27] HANGUL SYLLABLE KOG..HANGUL SYLLABLE KOH
+ {0xCF70, 0xCF70, prH2, gcLo}, // HANGUL SYLLABLE KWA
+ {0xCF71, 0xCF8B, prH3, gcLo}, // [27] HANGUL SYLLABLE KWAG..HANGUL SYLLABLE KWAH
+ {0xCF8C, 0xCF8C, prH2, gcLo}, // HANGUL SYLLABLE KWAE
+ {0xCF8D, 0xCFA7, prH3, gcLo}, // [27] HANGUL SYLLABLE KWAEG..HANGUL SYLLABLE KWAEH
+ {0xCFA8, 0xCFA8, prH2, gcLo}, // HANGUL SYLLABLE KOE
+ {0xCFA9, 0xCFC3, prH3, gcLo}, // [27] HANGUL SYLLABLE KOEG..HANGUL SYLLABLE KOEH
+ {0xCFC4, 0xCFC4, prH2, gcLo}, // HANGUL SYLLABLE KYO
+ {0xCFC5, 0xCFDF, prH3, gcLo}, // [27] HANGUL SYLLABLE KYOG..HANGUL SYLLABLE KYOH
+ {0xCFE0, 0xCFE0, prH2, gcLo}, // HANGUL SYLLABLE KU
+ {0xCFE1, 0xCFFB, prH3, gcLo}, // [27] HANGUL SYLLABLE KUG..HANGUL SYLLABLE KUH
+ {0xCFFC, 0xCFFC, prH2, gcLo}, // HANGUL SYLLABLE KWEO
+ {0xCFFD, 0xD017, prH3, gcLo}, // [27] HANGUL SYLLABLE KWEOG..HANGUL SYLLABLE KWEOH
+ {0xD018, 0xD018, prH2, gcLo}, // HANGUL SYLLABLE KWE
+ {0xD019, 0xD033, prH3, gcLo}, // [27] HANGUL SYLLABLE KWEG..HANGUL SYLLABLE KWEH
+ {0xD034, 0xD034, prH2, gcLo}, // HANGUL SYLLABLE KWI
+ {0xD035, 0xD04F, prH3, gcLo}, // [27] HANGUL SYLLABLE KWIG..HANGUL SYLLABLE KWIH
+ {0xD050, 0xD050, prH2, gcLo}, // HANGUL SYLLABLE KYU
+ {0xD051, 0xD06B, prH3, gcLo}, // [27] HANGUL SYLLABLE KYUG..HANGUL SYLLABLE KYUH
+ {0xD06C, 0xD06C, prH2, gcLo}, // HANGUL SYLLABLE KEU
+ {0xD06D, 0xD087, prH3, gcLo}, // [27] HANGUL SYLLABLE KEUG..HANGUL SYLLABLE KEUH
+ {0xD088, 0xD088, prH2, gcLo}, // HANGUL SYLLABLE KYI
+ {0xD089, 0xD0A3, prH3, gcLo}, // [27] HANGUL SYLLABLE KYIG..HANGUL SYLLABLE KYIH
+ {0xD0A4, 0xD0A4, prH2, gcLo}, // HANGUL SYLLABLE KI
+ {0xD0A5, 0xD0BF, prH3, gcLo}, // [27] HANGUL SYLLABLE KIG..HANGUL SYLLABLE KIH
+ {0xD0C0, 0xD0C0, prH2, gcLo}, // HANGUL SYLLABLE TA
+ {0xD0C1, 0xD0DB, prH3, gcLo}, // [27] HANGUL SYLLABLE TAG..HANGUL SYLLABLE TAH
+ {0xD0DC, 0xD0DC, prH2, gcLo}, // HANGUL SYLLABLE TAE
+ {0xD0DD, 0xD0F7, prH3, gcLo}, // [27] HANGUL SYLLABLE TAEG..HANGUL SYLLABLE TAEH
+ {0xD0F8, 0xD0F8, prH2, gcLo}, // HANGUL SYLLABLE TYA
+ {0xD0F9, 0xD113, prH3, gcLo}, // [27] HANGUL SYLLABLE TYAG..HANGUL SYLLABLE TYAH
+ {0xD114, 0xD114, prH2, gcLo}, // HANGUL SYLLABLE TYAE
+ {0xD115, 0xD12F, prH3, gcLo}, // [27] HANGUL SYLLABLE TYAEG..HANGUL SYLLABLE TYAEH
+ {0xD130, 0xD130, prH2, gcLo}, // HANGUL SYLLABLE TEO
+ {0xD131, 0xD14B, prH3, gcLo}, // [27] HANGUL SYLLABLE TEOG..HANGUL SYLLABLE TEOH
+ {0xD14C, 0xD14C, prH2, gcLo}, // HANGUL SYLLABLE TE
+ {0xD14D, 0xD167, prH3, gcLo}, // [27] HANGUL SYLLABLE TEG..HANGUL SYLLABLE TEH
+ {0xD168, 0xD168, prH2, gcLo}, // HANGUL SYLLABLE TYEO
+ {0xD169, 0xD183, prH3, gcLo}, // [27] HANGUL SYLLABLE TYEOG..HANGUL SYLLABLE TYEOH
+ {0xD184, 0xD184, prH2, gcLo}, // HANGUL SYLLABLE TYE
+ {0xD185, 0xD19F, prH3, gcLo}, // [27] HANGUL SYLLABLE TYEG..HANGUL SYLLABLE TYEH
+ {0xD1A0, 0xD1A0, prH2, gcLo}, // HANGUL SYLLABLE TO
+ {0xD1A1, 0xD1BB, prH3, gcLo}, // [27] HANGUL SYLLABLE TOG..HANGUL SYLLABLE TOH
+ {0xD1BC, 0xD1BC, prH2, gcLo}, // HANGUL SYLLABLE TWA
+ {0xD1BD, 0xD1D7, prH3, gcLo}, // [27] HANGUL SYLLABLE TWAG..HANGUL SYLLABLE TWAH
+ {0xD1D8, 0xD1D8, prH2, gcLo}, // HANGUL SYLLABLE TWAE
+ {0xD1D9, 0xD1F3, prH3, gcLo}, // [27] HANGUL SYLLABLE TWAEG..HANGUL SYLLABLE TWAEH
+ {0xD1F4, 0xD1F4, prH2, gcLo}, // HANGUL SYLLABLE TOE
+ {0xD1F5, 0xD20F, prH3, gcLo}, // [27] HANGUL SYLLABLE TOEG..HANGUL SYLLABLE TOEH
+ {0xD210, 0xD210, prH2, gcLo}, // HANGUL SYLLABLE TYO
+ {0xD211, 0xD22B, prH3, gcLo}, // [27] HANGUL SYLLABLE TYOG..HANGUL SYLLABLE TYOH
+ {0xD22C, 0xD22C, prH2, gcLo}, // HANGUL SYLLABLE TU
+ {0xD22D, 0xD247, prH3, gcLo}, // [27] HANGUL SYLLABLE TUG..HANGUL SYLLABLE TUH
+ {0xD248, 0xD248, prH2, gcLo}, // HANGUL SYLLABLE TWEO
+ {0xD249, 0xD263, prH3, gcLo}, // [27] HANGUL SYLLABLE TWEOG..HANGUL SYLLABLE TWEOH
+ {0xD264, 0xD264, prH2, gcLo}, // HANGUL SYLLABLE TWE
+ {0xD265, 0xD27F, prH3, gcLo}, // [27] HANGUL SYLLABLE TWEG..HANGUL SYLLABLE TWEH
+ {0xD280, 0xD280, prH2, gcLo}, // HANGUL SYLLABLE TWI
+ {0xD281, 0xD29B, prH3, gcLo}, // [27] HANGUL SYLLABLE TWIG..HANGUL SYLLABLE TWIH
+ {0xD29C, 0xD29C, prH2, gcLo}, // HANGUL SYLLABLE TYU
+ {0xD29D, 0xD2B7, prH3, gcLo}, // [27] HANGUL SYLLABLE TYUG..HANGUL SYLLABLE TYUH
+ {0xD2B8, 0xD2B8, prH2, gcLo}, // HANGUL SYLLABLE TEU
+ {0xD2B9, 0xD2D3, prH3, gcLo}, // [27] HANGUL SYLLABLE TEUG..HANGUL SYLLABLE TEUH
+ {0xD2D4, 0xD2D4, prH2, gcLo}, // HANGUL SYLLABLE TYI
+ {0xD2D5, 0xD2EF, prH3, gcLo}, // [27] HANGUL SYLLABLE TYIG..HANGUL SYLLABLE TYIH
+ {0xD2F0, 0xD2F0, prH2, gcLo}, // HANGUL SYLLABLE TI
+ {0xD2F1, 0xD30B, prH3, gcLo}, // [27] HANGUL SYLLABLE TIG..HANGUL SYLLABLE TIH
+ {0xD30C, 0xD30C, prH2, gcLo}, // HANGUL SYLLABLE PA
+ {0xD30D, 0xD327, prH3, gcLo}, // [27] HANGUL SYLLABLE PAG..HANGUL SYLLABLE PAH
+ {0xD328, 0xD328, prH2, gcLo}, // HANGUL SYLLABLE PAE
+ {0xD329, 0xD343, prH3, gcLo}, // [27] HANGUL SYLLABLE PAEG..HANGUL SYLLABLE PAEH
+ {0xD344, 0xD344, prH2, gcLo}, // HANGUL SYLLABLE PYA
+ {0xD345, 0xD35F, prH3, gcLo}, // [27] HANGUL SYLLABLE PYAG..HANGUL SYLLABLE PYAH
+ {0xD360, 0xD360, prH2, gcLo}, // HANGUL SYLLABLE PYAE
+ {0xD361, 0xD37B, prH3, gcLo}, // [27] HANGUL SYLLABLE PYAEG..HANGUL SYLLABLE PYAEH
+ {0xD37C, 0xD37C, prH2, gcLo}, // HANGUL SYLLABLE PEO
+ {0xD37D, 0xD397, prH3, gcLo}, // [27] HANGUL SYLLABLE PEOG..HANGUL SYLLABLE PEOH
+ {0xD398, 0xD398, prH2, gcLo}, // HANGUL SYLLABLE PE
+ {0xD399, 0xD3B3, prH3, gcLo}, // [27] HANGUL SYLLABLE PEG..HANGUL SYLLABLE PEH
+ {0xD3B4, 0xD3B4, prH2, gcLo}, // HANGUL SYLLABLE PYEO
+ {0xD3B5, 0xD3CF, prH3, gcLo}, // [27] HANGUL SYLLABLE PYEOG..HANGUL SYLLABLE PYEOH
+ {0xD3D0, 0xD3D0, prH2, gcLo}, // HANGUL SYLLABLE PYE
+ {0xD3D1, 0xD3EB, prH3, gcLo}, // [27] HANGUL SYLLABLE PYEG..HANGUL SYLLABLE PYEH
+ {0xD3EC, 0xD3EC, prH2, gcLo}, // HANGUL SYLLABLE PO
+ {0xD3ED, 0xD407, prH3, gcLo}, // [27] HANGUL SYLLABLE POG..HANGUL SYLLABLE POH
+ {0xD408, 0xD408, prH2, gcLo}, // HANGUL SYLLABLE PWA
+ {0xD409, 0xD423, prH3, gcLo}, // [27] HANGUL SYLLABLE PWAG..HANGUL SYLLABLE PWAH
+ {0xD424, 0xD424, prH2, gcLo}, // HANGUL SYLLABLE PWAE
+ {0xD425, 0xD43F, prH3, gcLo}, // [27] HANGUL SYLLABLE PWAEG..HANGUL SYLLABLE PWAEH
+ {0xD440, 0xD440, prH2, gcLo}, // HANGUL SYLLABLE POE
+ {0xD441, 0xD45B, prH3, gcLo}, // [27] HANGUL SYLLABLE POEG..HANGUL SYLLABLE POEH
+ {0xD45C, 0xD45C, prH2, gcLo}, // HANGUL SYLLABLE PYO
+ {0xD45D, 0xD477, prH3, gcLo}, // [27] HANGUL SYLLABLE PYOG..HANGUL SYLLABLE PYOH
+ {0xD478, 0xD478, prH2, gcLo}, // HANGUL SYLLABLE PU
+ {0xD479, 0xD493, prH3, gcLo}, // [27] HANGUL SYLLABLE PUG..HANGUL SYLLABLE PUH
+ {0xD494, 0xD494, prH2, gcLo}, // HANGUL SYLLABLE PWEO
+ {0xD495, 0xD4AF, prH3, gcLo}, // [27] HANGUL SYLLABLE PWEOG..HANGUL SYLLABLE PWEOH
+ {0xD4B0, 0xD4B0, prH2, gcLo}, // HANGUL SYLLABLE PWE
+ {0xD4B1, 0xD4CB, prH3, gcLo}, // [27] HANGUL SYLLABLE PWEG..HANGUL SYLLABLE PWEH
+ {0xD4CC, 0xD4CC, prH2, gcLo}, // HANGUL SYLLABLE PWI
+ {0xD4CD, 0xD4E7, prH3, gcLo}, // [27] HANGUL SYLLABLE PWIG..HANGUL SYLLABLE PWIH
+ {0xD4E8, 0xD4E8, prH2, gcLo}, // HANGUL SYLLABLE PYU
+ {0xD4E9, 0xD503, prH3, gcLo}, // [27] HANGUL SYLLABLE PYUG..HANGUL SYLLABLE PYUH
+ {0xD504, 0xD504, prH2, gcLo}, // HANGUL SYLLABLE PEU
+ {0xD505, 0xD51F, prH3, gcLo}, // [27] HANGUL SYLLABLE PEUG..HANGUL SYLLABLE PEUH
+ {0xD520, 0xD520, prH2, gcLo}, // HANGUL SYLLABLE PYI
+ {0xD521, 0xD53B, prH3, gcLo}, // [27] HANGUL SYLLABLE PYIG..HANGUL SYLLABLE PYIH
+ {0xD53C, 0xD53C, prH2, gcLo}, // HANGUL SYLLABLE PI
+ {0xD53D, 0xD557, prH3, gcLo}, // [27] HANGUL SYLLABLE PIG..HANGUL SYLLABLE PIH
+ {0xD558, 0xD558, prH2, gcLo}, // HANGUL SYLLABLE HA
+ {0xD559, 0xD573, prH3, gcLo}, // [27] HANGUL SYLLABLE HAG..HANGUL SYLLABLE HAH
+ {0xD574, 0xD574, prH2, gcLo}, // HANGUL SYLLABLE HAE
+ {0xD575, 0xD58F, prH3, gcLo}, // [27] HANGUL SYLLABLE HAEG..HANGUL SYLLABLE HAEH
+ {0xD590, 0xD590, prH2, gcLo}, // HANGUL SYLLABLE HYA
+ {0xD591, 0xD5AB, prH3, gcLo}, // [27] HANGUL SYLLABLE HYAG..HANGUL SYLLABLE HYAH
+ {0xD5AC, 0xD5AC, prH2, gcLo}, // HANGUL SYLLABLE HYAE
+ {0xD5AD, 0xD5C7, prH3, gcLo}, // [27] HANGUL SYLLABLE HYAEG..HANGUL SYLLABLE HYAEH
+ {0xD5C8, 0xD5C8, prH2, gcLo}, // HANGUL SYLLABLE HEO
+ {0xD5C9, 0xD5E3, prH3, gcLo}, // [27] HANGUL SYLLABLE HEOG..HANGUL SYLLABLE HEOH
+ {0xD5E4, 0xD5E4, prH2, gcLo}, // HANGUL SYLLABLE HE
+ {0xD5E5, 0xD5FF, prH3, gcLo}, // [27] HANGUL SYLLABLE HEG..HANGUL SYLLABLE HEH
+ {0xD600, 0xD600, prH2, gcLo}, // HANGUL SYLLABLE HYEO
+ {0xD601, 0xD61B, prH3, gcLo}, // [27] HANGUL SYLLABLE HYEOG..HANGUL SYLLABLE HYEOH
+ {0xD61C, 0xD61C, prH2, gcLo}, // HANGUL SYLLABLE HYE
+ {0xD61D, 0xD637, prH3, gcLo}, // [27] HANGUL SYLLABLE HYEG..HANGUL SYLLABLE HYEH
+ {0xD638, 0xD638, prH2, gcLo}, // HANGUL SYLLABLE HO
+ {0xD639, 0xD653, prH3, gcLo}, // [27] HANGUL SYLLABLE HOG..HANGUL SYLLABLE HOH
+ {0xD654, 0xD654, prH2, gcLo}, // HANGUL SYLLABLE HWA
+ {0xD655, 0xD66F, prH3, gcLo}, // [27] HANGUL SYLLABLE HWAG..HANGUL SYLLABLE HWAH
+ {0xD670, 0xD670, prH2, gcLo}, // HANGUL SYLLABLE HWAE
+ {0xD671, 0xD68B, prH3, gcLo}, // [27] HANGUL SYLLABLE HWAEG..HANGUL SYLLABLE HWAEH
+ {0xD68C, 0xD68C, prH2, gcLo}, // HANGUL SYLLABLE HOE
+ {0xD68D, 0xD6A7, prH3, gcLo}, // [27] HANGUL SYLLABLE HOEG..HANGUL SYLLABLE HOEH
+ {0xD6A8, 0xD6A8, prH2, gcLo}, // HANGUL SYLLABLE HYO
+ {0xD6A9, 0xD6C3, prH3, gcLo}, // [27] HANGUL SYLLABLE HYOG..HANGUL SYLLABLE HYOH
+ {0xD6C4, 0xD6C4, prH2, gcLo}, // HANGUL SYLLABLE HU
+ {0xD6C5, 0xD6DF, prH3, gcLo}, // [27] HANGUL SYLLABLE HUG..HANGUL SYLLABLE HUH
+ {0xD6E0, 0xD6E0, prH2, gcLo}, // HANGUL SYLLABLE HWEO
+ {0xD6E1, 0xD6FB, prH3, gcLo}, // [27] HANGUL SYLLABLE HWEOG..HANGUL SYLLABLE HWEOH
+ {0xD6FC, 0xD6FC, prH2, gcLo}, // HANGUL SYLLABLE HWE
+ {0xD6FD, 0xD717, prH3, gcLo}, // [27] HANGUL SYLLABLE HWEG..HANGUL SYLLABLE HWEH
+ {0xD718, 0xD718, prH2, gcLo}, // HANGUL SYLLABLE HWI
+ {0xD719, 0xD733, prH3, gcLo}, // [27] HANGUL SYLLABLE HWIG..HANGUL SYLLABLE HWIH
+ {0xD734, 0xD734, prH2, gcLo}, // HANGUL SYLLABLE HYU
+ {0xD735, 0xD74F, prH3, gcLo}, // [27] HANGUL SYLLABLE HYUG..HANGUL SYLLABLE HYUH
+ {0xD750, 0xD750, prH2, gcLo}, // HANGUL SYLLABLE HEU
+ {0xD751, 0xD76B, prH3, gcLo}, // [27] HANGUL SYLLABLE HEUG..HANGUL SYLLABLE HEUH
+ {0xD76C, 0xD76C, prH2, gcLo}, // HANGUL SYLLABLE HYI
+ {0xD76D, 0xD787, prH3, gcLo}, // [27] HANGUL SYLLABLE HYIG..HANGUL SYLLABLE HYIH
+ {0xD788, 0xD788, prH2, gcLo}, // HANGUL SYLLABLE HI
+ {0xD789, 0xD7A3, prH3, gcLo}, // [27] HANGUL SYLLABLE HIG..HANGUL SYLLABLE HIH
+ {0xD7B0, 0xD7C6, prJV, gcLo}, // [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E
+ {0xD7CB, 0xD7FB, prJT, gcLo}, // [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH
+ {0xD800, 0xDB7F, prSG, gcCs}, // [896] ..
+ {0xDB80, 0xDBFF, prSG, gcCs}, // [128] ..
+ {0xDC00, 0xDFFF, prSG, gcCs}, // [1024] ..
+ {0xE000, 0xF8FF, prXX, gcCo}, // [6400] ..
+ {0xF900, 0xFA6D, prID, gcLo}, // [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D
+ {0xFA6E, 0xFA6F, prID, gcCn}, // [2] ..
+ {0xFA70, 0xFAD9, prID, gcLo}, // [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9
+ {0xFADA, 0xFAFF, prID, gcCn}, // [38] ..
+ {0xFB00, 0xFB06, prAL, gcLl}, // [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+ {0xFB13, 0xFB17, prAL, gcLl}, // [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+ {0xFB1D, 0xFB1D, prHL, gcLo}, // HEBREW LETTER YOD WITH HIRIQ
+ {0xFB1E, 0xFB1E, prCM, gcMn}, // HEBREW POINT JUDEO-SPANISH VARIKA
+ {0xFB1F, 0xFB28, prHL, gcLo}, // [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV
+ {0xFB29, 0xFB29, prAL, gcSm}, // HEBREW LETTER ALTERNATIVE PLUS SIGN
+ {0xFB2A, 0xFB36, prHL, gcLo}, // [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH
+ {0xFB38, 0xFB3C, prHL, gcLo}, // [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH
+ {0xFB3E, 0xFB3E, prHL, gcLo}, // HEBREW LETTER MEM WITH DAGESH
+ {0xFB40, 0xFB41, prHL, gcLo}, // [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH
+ {0xFB43, 0xFB44, prHL, gcLo}, // [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH
+ {0xFB46, 0xFB4F, prHL, gcLo}, // [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATURE ALEF LAMED
+ {0xFB50, 0xFBB1, prAL, gcLo}, // [98] ARABIC LETTER ALEF WASLA ISOLATED FORM..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM
+ {0xFBB2, 0xFBC2, prAL, gcSk}, // [17] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL WASLA ABOVE
+ {0xFBD3, 0xFD3D, prAL, gcLo}, // [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM
+ {0xFD3E, 0xFD3E, prCL, gcPe}, // ORNATE LEFT PARENTHESIS
+ {0xFD3F, 0xFD3F, prOP, gcPs}, // ORNATE RIGHT PARENTHESIS
+ {0xFD40, 0xFD4F, prAL, gcSo}, // [16] ARABIC LIGATURE RAHIMAHU ALLAAH..ARABIC LIGATURE RAHIMAHUM ALLAAH
+ {0xFD50, 0xFD8F, prAL, gcLo}, // [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM
+ {0xFD92, 0xFDC7, prAL, gcLo}, // [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM
+ {0xFDCF, 0xFDCF, prAL, gcSo}, // ARABIC LIGATURE SALAAMUHU ALAYNAA
+ {0xFDF0, 0xFDFB, prAL, gcLo}, // [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU
+ {0xFDFC, 0xFDFC, prPO, gcSc}, // RIAL SIGN
+ {0xFDFD, 0xFDFF, prAL, gcSo}, // [3] ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM..ARABIC LIGATURE AZZA WA JALL
+ {0xFE00, 0xFE0F, prCM, gcMn}, // [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+ {0xFE10, 0xFE10, prIS, gcPo}, // PRESENTATION FORM FOR VERTICAL COMMA
+ {0xFE11, 0xFE12, prCL, gcPo}, // [2] PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA..PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP
+ {0xFE13, 0xFE14, prIS, gcPo}, // [2] PRESENTATION FORM FOR VERTICAL COLON..PRESENTATION FORM FOR VERTICAL SEMICOLON
+ {0xFE15, 0xFE16, prEX, gcPo}, // [2] PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK..PRESENTATION FORM FOR VERTICAL QUESTION MARK
+ {0xFE17, 0xFE17, prOP, gcPs}, // PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET
+ {0xFE18, 0xFE18, prCL, gcPe}, // PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET
+ {0xFE19, 0xFE19, prIN, gcPo}, // PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS
+ {0xFE20, 0xFE2F, prCM, gcMn}, // [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF
+ {0xFE30, 0xFE30, prID, gcPo}, // PRESENTATION FORM FOR VERTICAL TWO DOT LEADER
+ {0xFE31, 0xFE32, prID, gcPd}, // [2] PRESENTATION FORM FOR VERTICAL EM DASH..PRESENTATION FORM FOR VERTICAL EN DASH
+ {0xFE33, 0xFE34, prID, gcPc}, // [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE
+ {0xFE35, 0xFE35, prOP, gcPs}, // PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS
+ {0xFE36, 0xFE36, prCL, gcPe}, // PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS
+ {0xFE37, 0xFE37, prOP, gcPs}, // PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET
+ {0xFE38, 0xFE38, prCL, gcPe}, // PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET
+ {0xFE39, 0xFE39, prOP, gcPs}, // PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET
+ {0xFE3A, 0xFE3A, prCL, gcPe}, // PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET
+ {0xFE3B, 0xFE3B, prOP, gcPs}, // PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET
+ {0xFE3C, 0xFE3C, prCL, gcPe}, // PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET
+ {0xFE3D, 0xFE3D, prOP, gcPs}, // PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET
+ {0xFE3E, 0xFE3E, prCL, gcPe}, // PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET
+ {0xFE3F, 0xFE3F, prOP, gcPs}, // PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET
+ {0xFE40, 0xFE40, prCL, gcPe}, // PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET
+ {0xFE41, 0xFE41, prOP, gcPs}, // PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET
+ {0xFE42, 0xFE42, prCL, gcPe}, // PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET
+ {0xFE43, 0xFE43, prOP, gcPs}, // PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET
+ {0xFE44, 0xFE44, prCL, gcPe}, // PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET
+ {0xFE45, 0xFE46, prID, gcPo}, // [2] SESAME DOT..WHITE SESAME DOT
+ {0xFE47, 0xFE47, prOP, gcPs}, // PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET
+ {0xFE48, 0xFE48, prCL, gcPe}, // PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET
+ {0xFE49, 0xFE4C, prID, gcPo}, // [4] DASHED OVERLINE..DOUBLE WAVY OVERLINE
+ {0xFE4D, 0xFE4F, prID, gcPc}, // [3] DASHED LOW LINE..WAVY LOW LINE
+ {0xFE50, 0xFE50, prCL, gcPo}, // SMALL COMMA
+ {0xFE51, 0xFE51, prID, gcPo}, // SMALL IDEOGRAPHIC COMMA
+ {0xFE52, 0xFE52, prCL, gcPo}, // SMALL FULL STOP
+ {0xFE54, 0xFE55, prNS, gcPo}, // [2] SMALL SEMICOLON..SMALL COLON
+ {0xFE56, 0xFE57, prEX, gcPo}, // [2] SMALL QUESTION MARK..SMALL EXCLAMATION MARK
+ {0xFE58, 0xFE58, prID, gcPd}, // SMALL EM DASH
+ {0xFE59, 0xFE59, prOP, gcPs}, // SMALL LEFT PARENTHESIS
+ {0xFE5A, 0xFE5A, prCL, gcPe}, // SMALL RIGHT PARENTHESIS
+ {0xFE5B, 0xFE5B, prOP, gcPs}, // SMALL LEFT CURLY BRACKET
+ {0xFE5C, 0xFE5C, prCL, gcPe}, // SMALL RIGHT CURLY BRACKET
+ {0xFE5D, 0xFE5D, prOP, gcPs}, // SMALL LEFT TORTOISE SHELL BRACKET
+ {0xFE5E, 0xFE5E, prCL, gcPe}, // SMALL RIGHT TORTOISE SHELL BRACKET
+ {0xFE5F, 0xFE61, prID, gcPo}, // [3] SMALL NUMBER SIGN..SMALL ASTERISK
+ {0xFE62, 0xFE62, prID, gcSm}, // SMALL PLUS SIGN
+ {0xFE63, 0xFE63, prID, gcPd}, // SMALL HYPHEN-MINUS
+ {0xFE64, 0xFE66, prID, gcSm}, // [3] SMALL LESS-THAN SIGN..SMALL EQUALS SIGN
+ {0xFE68, 0xFE68, prID, gcPo}, // SMALL REVERSE SOLIDUS
+ {0xFE69, 0xFE69, prPR, gcSc}, // SMALL DOLLAR SIGN
+ {0xFE6A, 0xFE6A, prPO, gcPo}, // SMALL PERCENT SIGN
+ {0xFE6B, 0xFE6B, prID, gcPo}, // SMALL COMMERCIAL AT
+ {0xFE70, 0xFE74, prAL, gcLo}, // [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM
+ {0xFE76, 0xFEFC, prAL, gcLo}, // [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM
+ {0xFEFF, 0xFEFF, prWJ, gcCf}, // ZERO WIDTH NO-BREAK SPACE
+ {0xFF01, 0xFF01, prEX, gcPo}, // FULLWIDTH EXCLAMATION MARK
+ {0xFF02, 0xFF03, prID, gcPo}, // [2] FULLWIDTH QUOTATION MARK..FULLWIDTH NUMBER SIGN
+ {0xFF04, 0xFF04, prPR, gcSc}, // FULLWIDTH DOLLAR SIGN
+ {0xFF05, 0xFF05, prPO, gcPo}, // FULLWIDTH PERCENT SIGN
+ {0xFF06, 0xFF07, prID, gcPo}, // [2] FULLWIDTH AMPERSAND..FULLWIDTH APOSTROPHE
+ {0xFF08, 0xFF08, prOP, gcPs}, // FULLWIDTH LEFT PARENTHESIS
+ {0xFF09, 0xFF09, prCL, gcPe}, // FULLWIDTH RIGHT PARENTHESIS
+ {0xFF0A, 0xFF0A, prID, gcPo}, // FULLWIDTH ASTERISK
+ {0xFF0B, 0xFF0B, prID, gcSm}, // FULLWIDTH PLUS SIGN
+ {0xFF0C, 0xFF0C, prCL, gcPo}, // FULLWIDTH COMMA
+ {0xFF0D, 0xFF0D, prID, gcPd}, // FULLWIDTH HYPHEN-MINUS
+ {0xFF0E, 0xFF0E, prCL, gcPo}, // FULLWIDTH FULL STOP
+ {0xFF0F, 0xFF0F, prID, gcPo}, // FULLWIDTH SOLIDUS
+ {0xFF10, 0xFF19, prID, gcNd}, // [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
+ {0xFF1A, 0xFF1B, prNS, gcPo}, // [2] FULLWIDTH COLON..FULLWIDTH SEMICOLON
+ {0xFF1C, 0xFF1E, prID, gcSm}, // [3] FULLWIDTH LESS-THAN SIGN..FULLWIDTH GREATER-THAN SIGN
+ {0xFF1F, 0xFF1F, prEX, gcPo}, // FULLWIDTH QUESTION MARK
+ {0xFF20, 0xFF20, prID, gcPo}, // FULLWIDTH COMMERCIAL AT
+ {0xFF21, 0xFF3A, prID, gcLu}, // [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+ {0xFF3B, 0xFF3B, prOP, gcPs}, // FULLWIDTH LEFT SQUARE BRACKET
+ {0xFF3C, 0xFF3C, prID, gcPo}, // FULLWIDTH REVERSE SOLIDUS
+ {0xFF3D, 0xFF3D, prCL, gcPe}, // FULLWIDTH RIGHT SQUARE BRACKET
+ {0xFF3E, 0xFF3E, prID, gcSk}, // FULLWIDTH CIRCUMFLEX ACCENT
+ {0xFF3F, 0xFF3F, prID, gcPc}, // FULLWIDTH LOW LINE
+ {0xFF40, 0xFF40, prID, gcSk}, // FULLWIDTH GRAVE ACCENT
+ {0xFF41, 0xFF5A, prID, gcLl}, // [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+ {0xFF5B, 0xFF5B, prOP, gcPs}, // FULLWIDTH LEFT CURLY BRACKET
+ {0xFF5C, 0xFF5C, prID, gcSm}, // FULLWIDTH VERTICAL LINE
+ {0xFF5D, 0xFF5D, prCL, gcPe}, // FULLWIDTH RIGHT CURLY BRACKET
+ {0xFF5E, 0xFF5E, prID, gcSm}, // FULLWIDTH TILDE
+ {0xFF5F, 0xFF5F, prOP, gcPs}, // FULLWIDTH LEFT WHITE PARENTHESIS
+ {0xFF60, 0xFF60, prCL, gcPe}, // FULLWIDTH RIGHT WHITE PARENTHESIS
+ {0xFF61, 0xFF61, prCL, gcPo}, // HALFWIDTH IDEOGRAPHIC FULL STOP
+ {0xFF62, 0xFF62, prOP, gcPs}, // HALFWIDTH LEFT CORNER BRACKET
+ {0xFF63, 0xFF63, prCL, gcPe}, // HALFWIDTH RIGHT CORNER BRACKET
+ {0xFF64, 0xFF64, prCL, gcPo}, // HALFWIDTH IDEOGRAPHIC COMMA
+ {0xFF65, 0xFF65, prNS, gcPo}, // HALFWIDTH KATAKANA MIDDLE DOT
+ {0xFF66, 0xFF66, prID, gcLo}, // HALFWIDTH KATAKANA LETTER WO
+ {0xFF67, 0xFF6F, prCJ, gcLo}, // [9] HALFWIDTH KATAKANA LETTER SMALL A..HALFWIDTH KATAKANA LETTER SMALL TU
+ {0xFF70, 0xFF70, prCJ, gcLm}, // HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
+ {0xFF71, 0xFF9D, prID, gcLo}, // [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N
+ {0xFF9E, 0xFF9F, prNS, gcLm}, // [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+ {0xFFA0, 0xFFBE, prID, gcLo}, // [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH
+ {0xFFC2, 0xFFC7, prID, gcLo}, // [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E
+ {0xFFCA, 0xFFCF, prID, gcLo}, // [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE
+ {0xFFD2, 0xFFD7, prID, gcLo}, // [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU
+ {0xFFDA, 0xFFDC, prID, gcLo}, // [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I
+ {0xFFE0, 0xFFE0, prPO, gcSc}, // FULLWIDTH CENT SIGN
+ {0xFFE1, 0xFFE1, prPR, gcSc}, // FULLWIDTH POUND SIGN
+ {0xFFE2, 0xFFE2, prID, gcSm}, // FULLWIDTH NOT SIGN
+ {0xFFE3, 0xFFE3, prID, gcSk}, // FULLWIDTH MACRON
+ {0xFFE4, 0xFFE4, prID, gcSo}, // FULLWIDTH BROKEN BAR
+ {0xFFE5, 0xFFE6, prPR, gcSc}, // [2] FULLWIDTH YEN SIGN..FULLWIDTH WON SIGN
+ {0xFFE8, 0xFFE8, prAL, gcSo}, // HALFWIDTH FORMS LIGHT VERTICAL
+ {0xFFE9, 0xFFEC, prAL, gcSm}, // [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW
+ {0xFFED, 0xFFEE, prAL, gcSo}, // [2] HALFWIDTH BLACK SQUARE..HALFWIDTH WHITE CIRCLE
+ {0xFFF9, 0xFFFB, prCM, gcCf}, // [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR
+ {0xFFFC, 0xFFFC, prCB, gcSo}, // OBJECT REPLACEMENT CHARACTER
+ {0xFFFD, 0xFFFD, prAI, gcSo}, // REPLACEMENT CHARACTER
+ {0x10000, 0x1000B, prAL, gcLo}, // [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE
+ {0x1000D, 0x10026, prAL, gcLo}, // [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO
+ {0x10028, 0x1003A, prAL, gcLo}, // [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO
+ {0x1003C, 0x1003D, prAL, gcLo}, // [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE
+ {0x1003F, 0x1004D, prAL, gcLo}, // [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO
+ {0x10050, 0x1005D, prAL, gcLo}, // [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089
+ {0x10080, 0x100FA, prAL, gcLo}, // [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305
+ {0x10100, 0x10102, prBA, gcPo}, // [3] AEGEAN WORD SEPARATOR LINE..AEGEAN CHECK MARK
+ {0x10107, 0x10133, prAL, gcNo}, // [45] AEGEAN NUMBER ONE..AEGEAN NUMBER NINETY THOUSAND
+ {0x10137, 0x1013F, prAL, gcSo}, // [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT
+ {0x10140, 0x10174, prAL, gcNl}, // [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS
+ {0x10175, 0x10178, prAL, gcNo}, // [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN
+ {0x10179, 0x10189, prAL, gcSo}, // [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN
+ {0x1018A, 0x1018B, prAL, gcNo}, // [2] GREEK ZERO SIGN..GREEK ONE QUARTER SIGN
+ {0x1018C, 0x1018E, prAL, gcSo}, // [3] GREEK SINUSOID SIGN..NOMISMA SIGN
+ {0x10190, 0x1019C, prAL, gcSo}, // [13] ROMAN SEXTANS SIGN..ASCIA SYMBOL
+ {0x101A0, 0x101A0, prAL, gcSo}, // GREEK SYMBOL TAU RHO
+ {0x101D0, 0x101FC, prAL, gcSo}, // [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND
+ {0x101FD, 0x101FD, prCM, gcMn}, // PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
+ {0x10280, 0x1029C, prAL, gcLo}, // [29] LYCIAN LETTER A..LYCIAN LETTER X
+ {0x102A0, 0x102D0, prAL, gcLo}, // [49] CARIAN LETTER A..CARIAN LETTER UUU3
+ {0x102E0, 0x102E0, prCM, gcMn}, // COPTIC EPACT THOUSANDS MARK
+ {0x102E1, 0x102FB, prAL, gcNo}, // [27] COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED
+ {0x10300, 0x1031F, prAL, gcLo}, // [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS
+ {0x10320, 0x10323, prAL, gcNo}, // [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY
+ {0x1032D, 0x1032F, prAL, gcLo}, // [3] OLD ITALIC LETTER YE..OLD ITALIC LETTER SOUTHERN TSE
+ {0x10330, 0x10340, prAL, gcLo}, // [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA
+ {0x10341, 0x10341, prAL, gcNl}, // GOTHIC LETTER NINETY
+ {0x10342, 0x10349, prAL, gcLo}, // [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL
+ {0x1034A, 0x1034A, prAL, gcNl}, // GOTHIC LETTER NINE HUNDRED
+ {0x10350, 0x10375, prAL, gcLo}, // [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA
+ {0x10376, 0x1037A, prCM, gcMn}, // [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII
+ {0x10380, 0x1039D, prAL, gcLo}, // [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU
+ {0x1039F, 0x1039F, prBA, gcPo}, // UGARITIC WORD DIVIDER
+ {0x103A0, 0x103C3, prAL, gcLo}, // [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA
+ {0x103C8, 0x103CF, prAL, gcLo}, // [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH
+ {0x103D0, 0x103D0, prBA, gcPo}, // OLD PERSIAN WORD DIVIDER
+ {0x103D1, 0x103D5, prAL, gcNl}, // [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED
+ {0x10400, 0x1044F, prAL, gcLC}, // [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW
+ {0x10450, 0x1047F, prAL, gcLo}, // [48] SHAVIAN LETTER PEEP..SHAVIAN LETTER YEW
+ {0x10480, 0x1049D, prAL, gcLo}, // [30] OSMANYA LETTER ALEF..OSMANYA LETTER OO
+ {0x104A0, 0x104A9, prNU, gcNd}, // [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
+ {0x104B0, 0x104D3, prAL, gcLu}, // [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA
+ {0x104D8, 0x104FB, prAL, gcLl}, // [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA
+ {0x10500, 0x10527, prAL, gcLo}, // [40] ELBASAN LETTER A..ELBASAN LETTER KHE
+ {0x10530, 0x10563, prAL, gcLo}, // [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW
+ {0x1056F, 0x1056F, prAL, gcPo}, // CAUCASIAN ALBANIAN CITATION MARK
+ {0x10570, 0x1057A, prAL, gcLu}, // [11] VITHKUQI CAPITAL LETTER A..VITHKUQI CAPITAL LETTER GA
+ {0x1057C, 0x1058A, prAL, gcLu}, // [15] VITHKUQI CAPITAL LETTER HA..VITHKUQI CAPITAL LETTER RE
+ {0x1058C, 0x10592, prAL, gcLu}, // [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE
+ {0x10594, 0x10595, prAL, gcLu}, // [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE
+ {0x10597, 0x105A1, prAL, gcLl}, // [11] VITHKUQI SMALL LETTER A..VITHKUQI SMALL LETTER GA
+ {0x105A3, 0x105B1, prAL, gcLl}, // [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE
+ {0x105B3, 0x105B9, prAL, gcLl}, // [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE
+ {0x105BB, 0x105BC, prAL, gcLl}, // [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE
+ {0x10600, 0x10736, prAL, gcLo}, // [311] LINEAR A SIGN AB001..LINEAR A SIGN A664
+ {0x10740, 0x10755, prAL, gcLo}, // [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE
+ {0x10760, 0x10767, prAL, gcLo}, // [8] LINEAR A SIGN A800..LINEAR A SIGN A807
+ {0x10780, 0x10785, prAL, gcLm}, // [6] MODIFIER LETTER SMALL CAPITAL AA..MODIFIER LETTER SMALL B WITH HOOK
+ {0x10787, 0x107B0, prAL, gcLm}, // [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK
+ {0x107B2, 0x107BA, prAL, gcLm}, // [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL
+ {0x10800, 0x10805, prAL, gcLo}, // [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA
+ {0x10808, 0x10808, prAL, gcLo}, // CYPRIOT SYLLABLE JO
+ {0x1080A, 0x10835, prAL, gcLo}, // [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO
+ {0x10837, 0x10838, prAL, gcLo}, // [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE
+ {0x1083C, 0x1083C, prAL, gcLo}, // CYPRIOT SYLLABLE ZA
+ {0x1083F, 0x1083F, prAL, gcLo}, // CYPRIOT SYLLABLE ZO
+ {0x10840, 0x10855, prAL, gcLo}, // [22] IMPERIAL ARAMAIC LETTER ALEPH..IMPERIAL ARAMAIC LETTER TAW
+ {0x10857, 0x10857, prBA, gcPo}, // IMPERIAL ARAMAIC SECTION SIGN
+ {0x10858, 0x1085F, prAL, gcNo}, // [8] IMPERIAL ARAMAIC NUMBER ONE..IMPERIAL ARAMAIC NUMBER TEN THOUSAND
+ {0x10860, 0x10876, prAL, gcLo}, // [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW
+ {0x10877, 0x10878, prAL, gcSo}, // [2] PALMYRENE LEFT-POINTING FLEURON..PALMYRENE RIGHT-POINTING FLEURON
+ {0x10879, 0x1087F, prAL, gcNo}, // [7] PALMYRENE NUMBER ONE..PALMYRENE NUMBER TWENTY
+ {0x10880, 0x1089E, prAL, gcLo}, // [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW
+ {0x108A7, 0x108AF, prAL, gcNo}, // [9] NABATAEAN NUMBER ONE..NABATAEAN NUMBER ONE HUNDRED
+ {0x108E0, 0x108F2, prAL, gcLo}, // [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH
+ {0x108F4, 0x108F5, prAL, gcLo}, // [2] HATRAN LETTER SHIN..HATRAN LETTER TAW
+ {0x108FB, 0x108FF, prAL, gcNo}, // [5] HATRAN NUMBER ONE..HATRAN NUMBER ONE HUNDRED
+ {0x10900, 0x10915, prAL, gcLo}, // [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU
+ {0x10916, 0x1091B, prAL, gcNo}, // [6] PHOENICIAN NUMBER ONE..PHOENICIAN NUMBER THREE
+ {0x1091F, 0x1091F, prBA, gcPo}, // PHOENICIAN WORD SEPARATOR
+ {0x10920, 0x10939, prAL, gcLo}, // [26] LYDIAN LETTER A..LYDIAN LETTER C
+ {0x1093F, 0x1093F, prAL, gcPo}, // LYDIAN TRIANGULAR MARK
+ {0x10980, 0x1099F, prAL, gcLo}, // [32] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC HIEROGLYPHIC SYMBOL VIDJ-2
+ {0x109A0, 0x109B7, prAL, gcLo}, // [24] MEROITIC CURSIVE LETTER A..MEROITIC CURSIVE LETTER DA
+ {0x109BC, 0x109BD, prAL, gcNo}, // [2] MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS..MEROITIC CURSIVE FRACTION ONE HALF
+ {0x109BE, 0x109BF, prAL, gcLo}, // [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN
+ {0x109C0, 0x109CF, prAL, gcNo}, // [16] MEROITIC CURSIVE NUMBER ONE..MEROITIC CURSIVE NUMBER SEVENTY
+ {0x109D2, 0x109FF, prAL, gcNo}, // [46] MEROITIC CURSIVE NUMBER ONE HUNDRED..MEROITIC CURSIVE FRACTION TEN TWELFTHS
+ {0x10A00, 0x10A00, prAL, gcLo}, // KHAROSHTHI LETTER A
+ {0x10A01, 0x10A03, prCM, gcMn}, // [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
+ {0x10A05, 0x10A06, prCM, gcMn}, // [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
+ {0x10A0C, 0x10A0F, prCM, gcMn}, // [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
+ {0x10A10, 0x10A13, prAL, gcLo}, // [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA
+ {0x10A15, 0x10A17, prAL, gcLo}, // [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA
+ {0x10A19, 0x10A35, prAL, gcLo}, // [29] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER VHA
+ {0x10A38, 0x10A3A, prCM, gcMn}, // [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
+ {0x10A3F, 0x10A3F, prCM, gcMn}, // KHAROSHTHI VIRAMA
+ {0x10A40, 0x10A48, prAL, gcNo}, // [9] KHAROSHTHI DIGIT ONE..KHAROSHTHI FRACTION ONE HALF
+ {0x10A50, 0x10A57, prBA, gcPo}, // [8] KHAROSHTHI PUNCTUATION DOT..KHAROSHTHI PUNCTUATION DOUBLE DANDA
+ {0x10A58, 0x10A58, prAL, gcPo}, // KHAROSHTHI PUNCTUATION LINES
+ {0x10A60, 0x10A7C, prAL, gcLo}, // [29] OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH
+ {0x10A7D, 0x10A7E, prAL, gcNo}, // [2] OLD SOUTH ARABIAN NUMBER ONE..OLD SOUTH ARABIAN NUMBER FIFTY
+ {0x10A7F, 0x10A7F, prAL, gcPo}, // OLD SOUTH ARABIAN NUMERIC INDICATOR
+ {0x10A80, 0x10A9C, prAL, gcLo}, // [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH
+ {0x10A9D, 0x10A9F, prAL, gcNo}, // [3] OLD NORTH ARABIAN NUMBER ONE..OLD NORTH ARABIAN NUMBER TWENTY
+ {0x10AC0, 0x10AC7, prAL, gcLo}, // [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW
+ {0x10AC8, 0x10AC8, prAL, gcSo}, // MANICHAEAN SIGN UD
+ {0x10AC9, 0x10AE4, prAL, gcLo}, // [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW
+ {0x10AE5, 0x10AE6, prCM, gcMn}, // [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
+ {0x10AEB, 0x10AEF, prAL, gcNo}, // [5] MANICHAEAN NUMBER ONE..MANICHAEAN NUMBER ONE HUNDRED
+ {0x10AF0, 0x10AF5, prBA, gcPo}, // [6] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION TWO DOTS
+ {0x10AF6, 0x10AF6, prIN, gcPo}, // MANICHAEAN PUNCTUATION LINE FILLER
+ {0x10B00, 0x10B35, prAL, gcLo}, // [54] AVESTAN LETTER A..AVESTAN LETTER HE
+ {0x10B39, 0x10B3F, prBA, gcPo}, // [7] AVESTAN ABBREVIATION MARK..LARGE ONE RING OVER TWO RINGS PUNCTUATION
+ {0x10B40, 0x10B55, prAL, gcLo}, // [22] INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW
+ {0x10B58, 0x10B5F, prAL, gcNo}, // [8] INSCRIPTIONAL PARTHIAN NUMBER ONE..INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND
+ {0x10B60, 0x10B72, prAL, gcLo}, // [19] INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW
+ {0x10B78, 0x10B7F, prAL, gcNo}, // [8] INSCRIPTIONAL PAHLAVI NUMBER ONE..INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND
+ {0x10B80, 0x10B91, prAL, gcLo}, // [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW
+ {0x10B99, 0x10B9C, prAL, gcPo}, // [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT
+ {0x10BA9, 0x10BAF, prAL, gcNo}, // [7] PSALTER PAHLAVI NUMBER ONE..PSALTER PAHLAVI NUMBER ONE HUNDRED
+ {0x10C00, 0x10C48, prAL, gcLo}, // [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH
+ {0x10C80, 0x10CB2, prAL, gcLu}, // [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US
+ {0x10CC0, 0x10CF2, prAL, gcLl}, // [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US
+ {0x10CFA, 0x10CFF, prAL, gcNo}, // [6] OLD HUNGARIAN NUMBER ONE..OLD HUNGARIAN NUMBER ONE THOUSAND
+ {0x10D00, 0x10D23, prAL, gcLo}, // [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA
+ {0x10D24, 0x10D27, prCM, gcMn}, // [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
+ {0x10D30, 0x10D39, prNU, gcNd}, // [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE
+ {0x10E60, 0x10E7E, prAL, gcNo}, // [31] RUMI DIGIT ONE..RUMI FRACTION TWO THIRDS
+ {0x10E80, 0x10EA9, prAL, gcLo}, // [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET
+ {0x10EAB, 0x10EAC, prCM, gcMn}, // [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK
+ {0x10EAD, 0x10EAD, prBA, gcPd}, // YEZIDI HYPHENATION MARK
+ {0x10EB0, 0x10EB1, prAL, gcLo}, // [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE
+ {0x10EFD, 0x10EFF, prCM, gcMn}, // [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA
+ {0x10F00, 0x10F1C, prAL, gcLo}, // [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL
+ {0x10F1D, 0x10F26, prAL, gcNo}, // [10] OLD SOGDIAN NUMBER ONE..OLD SOGDIAN FRACTION ONE HALF
+ {0x10F27, 0x10F27, prAL, gcLo}, // OLD SOGDIAN LIGATURE AYIN-DALETH
+ {0x10F30, 0x10F45, prAL, gcLo}, // [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN
+ {0x10F46, 0x10F50, prCM, gcMn}, // [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW
+ {0x10F51, 0x10F54, prAL, gcNo}, // [4] SOGDIAN NUMBER ONE..SOGDIAN NUMBER ONE HUNDRED
+ {0x10F55, 0x10F59, prAL, gcPo}, // [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT
+ {0x10F70, 0x10F81, prAL, gcLo}, // [18] OLD UYGHUR LETTER ALEPH..OLD UYGHUR LETTER LESH
+ {0x10F82, 0x10F85, prCM, gcMn}, // [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW
+ {0x10F86, 0x10F89, prAL, gcPo}, // [4] OLD UYGHUR PUNCTUATION BAR..OLD UYGHUR PUNCTUATION FOUR DOTS
+ {0x10FB0, 0x10FC4, prAL, gcLo}, // [21] CHORASMIAN LETTER ALEPH..CHORASMIAN LETTER TAW
+ {0x10FC5, 0x10FCB, prAL, gcNo}, // [7] CHORASMIAN NUMBER ONE..CHORASMIAN NUMBER ONE HUNDRED
+ {0x10FE0, 0x10FF6, prAL, gcLo}, // [23] ELYMAIC LETTER ALEPH..ELYMAIC LIGATURE ZAYIN-YODH
+ {0x11000, 0x11000, prCM, gcMc}, // BRAHMI SIGN CANDRABINDU
+ {0x11001, 0x11001, prCM, gcMn}, // BRAHMI SIGN ANUSVARA
+ {0x11002, 0x11002, prCM, gcMc}, // BRAHMI SIGN VISARGA
+ {0x11003, 0x11037, prAL, gcLo}, // [53] BRAHMI SIGN JIHVAMULIYA..BRAHMI LETTER OLD TAMIL NNNA
+ {0x11038, 0x11046, prCM, gcMn}, // [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA
+ {0x11047, 0x11048, prBA, gcPo}, // [2] BRAHMI DANDA..BRAHMI DOUBLE DANDA
+ {0x11049, 0x1104D, prAL, gcPo}, // [5] BRAHMI PUNCTUATION DOT..BRAHMI PUNCTUATION LOTUS
+ {0x11052, 0x11065, prAL, gcNo}, // [20] BRAHMI NUMBER ONE..BRAHMI NUMBER ONE THOUSAND
+ {0x11066, 0x1106F, prNU, gcNd}, // [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE
+ {0x11070, 0x11070, prCM, gcMn}, // BRAHMI SIGN OLD TAMIL VIRAMA
+ {0x11071, 0x11072, prAL, gcLo}, // [2] BRAHMI LETTER OLD TAMIL SHORT E..BRAHMI LETTER OLD TAMIL SHORT O
+ {0x11073, 0x11074, prCM, gcMn}, // [2] BRAHMI VOWEL SIGN OLD TAMIL SHORT E..BRAHMI VOWEL SIGN OLD TAMIL SHORT O
+ {0x11075, 0x11075, prAL, gcLo}, // BRAHMI LETTER OLD TAMIL LLA
+ {0x1107F, 0x1107F, prCM, gcMn}, // BRAHMI NUMBER JOINER
+ {0x11080, 0x11081, prCM, gcMn}, // [2] KAITHI SIGN CANDRABINDU..KAITHI SIGN ANUSVARA
+ {0x11082, 0x11082, prCM, gcMc}, // KAITHI SIGN VISARGA
+ {0x11083, 0x110AF, prAL, gcLo}, // [45] KAITHI LETTER A..KAITHI LETTER HA
+ {0x110B0, 0x110B2, prCM, gcMc}, // [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II
+ {0x110B3, 0x110B6, prCM, gcMn}, // [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI
+ {0x110B7, 0x110B8, prCM, gcMc}, // [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU
+ {0x110B9, 0x110BA, prCM, gcMn}, // [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA
+ {0x110BB, 0x110BC, prAL, gcPo}, // [2] KAITHI ABBREVIATION SIGN..KAITHI ENUMERATION SIGN
+ {0x110BD, 0x110BD, prAL, gcCf}, // KAITHI NUMBER SIGN
+ {0x110BE, 0x110C1, prBA, gcPo}, // [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA
+ {0x110C2, 0x110C2, prCM, gcMn}, // KAITHI VOWEL SIGN VOCALIC R
+ {0x110CD, 0x110CD, prAL, gcCf}, // KAITHI NUMBER SIGN ABOVE
+ {0x110D0, 0x110E8, prAL, gcLo}, // [25] SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE
+ {0x110F0, 0x110F9, prNU, gcNd}, // [10] SORA SOMPENG DIGIT ZERO..SORA SOMPENG DIGIT NINE
+ {0x11100, 0x11102, prCM, gcMn}, // [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA
+ {0x11103, 0x11126, prAL, gcLo}, // [36] CHAKMA LETTER AA..CHAKMA LETTER HAA
+ {0x11127, 0x1112B, prCM, gcMn}, // [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU
+ {0x1112C, 0x1112C, prCM, gcMc}, // CHAKMA VOWEL SIGN E
+ {0x1112D, 0x11134, prCM, gcMn}, // [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA
+ {0x11136, 0x1113F, prNU, gcNd}, // [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE
+ {0x11140, 0x11143, prBA, gcPo}, // [4] CHAKMA SECTION MARK..CHAKMA QUESTION MARK
+ {0x11144, 0x11144, prAL, gcLo}, // CHAKMA LETTER LHAA
+ {0x11145, 0x11146, prCM, gcMc}, // [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI
+ {0x11147, 0x11147, prAL, gcLo}, // CHAKMA LETTER VAA
+ {0x11150, 0x11172, prAL, gcLo}, // [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA
+ {0x11173, 0x11173, prCM, gcMn}, // MAHAJANI SIGN NUKTA
+ {0x11174, 0x11174, prAL, gcPo}, // MAHAJANI ABBREVIATION SIGN
+ {0x11175, 0x11175, prBB, gcPo}, // MAHAJANI SECTION MARK
+ {0x11176, 0x11176, prAL, gcLo}, // MAHAJANI LIGATURE SHRI
+ {0x11180, 0x11181, prCM, gcMn}, // [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA
+ {0x11182, 0x11182, prCM, gcMc}, // SHARADA SIGN VISARGA
+ {0x11183, 0x111B2, prAL, gcLo}, // [48] SHARADA LETTER A..SHARADA LETTER HA
+ {0x111B3, 0x111B5, prCM, gcMc}, // [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II
+ {0x111B6, 0x111BE, prCM, gcMn}, // [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O
+ {0x111BF, 0x111C0, prCM, gcMc}, // [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA
+ {0x111C1, 0x111C4, prAL, gcLo}, // [4] SHARADA SIGN AVAGRAHA..SHARADA OM
+ {0x111C5, 0x111C6, prBA, gcPo}, // [2] SHARADA DANDA..SHARADA DOUBLE DANDA
+ {0x111C7, 0x111C7, prAL, gcPo}, // SHARADA ABBREVIATION SIGN
+ {0x111C8, 0x111C8, prBA, gcPo}, // SHARADA SEPARATOR
+ {0x111C9, 0x111CC, prCM, gcMn}, // [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK
+ {0x111CD, 0x111CD, prAL, gcPo}, // SHARADA SUTRA MARK
+ {0x111CE, 0x111CE, prCM, gcMc}, // SHARADA VOWEL SIGN PRISHTHAMATRA E
+ {0x111CF, 0x111CF, prCM, gcMn}, // SHARADA SIGN INVERTED CANDRABINDU
+ {0x111D0, 0x111D9, prNU, gcNd}, // [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE
+ {0x111DA, 0x111DA, prAL, gcLo}, // SHARADA EKAM
+ {0x111DB, 0x111DB, prBB, gcPo}, // SHARADA SIGN SIDDHAM
+ {0x111DC, 0x111DC, prAL, gcLo}, // SHARADA HEADSTROKE
+ {0x111DD, 0x111DF, prBA, gcPo}, // [3] SHARADA CONTINUATION SIGN..SHARADA SECTION MARK-2
+ {0x111E1, 0x111F4, prAL, gcNo}, // [20] SINHALA ARCHAIC DIGIT ONE..SINHALA ARCHAIC NUMBER ONE THOUSAND
+ {0x11200, 0x11211, prAL, gcLo}, // [18] KHOJKI LETTER A..KHOJKI LETTER JJA
+ {0x11213, 0x1122B, prAL, gcLo}, // [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA
+ {0x1122C, 0x1122E, prCM, gcMc}, // [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II
+ {0x1122F, 0x11231, prCM, gcMn}, // [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI
+ {0x11232, 0x11233, prCM, gcMc}, // [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU
+ {0x11234, 0x11234, prCM, gcMn}, // KHOJKI SIGN ANUSVARA
+ {0x11235, 0x11235, prCM, gcMc}, // KHOJKI SIGN VIRAMA
+ {0x11236, 0x11237, prCM, gcMn}, // [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA
+ {0x11238, 0x11239, prBA, gcPo}, // [2] KHOJKI DANDA..KHOJKI DOUBLE DANDA
+ {0x1123A, 0x1123A, prAL, gcPo}, // KHOJKI WORD SEPARATOR
+ {0x1123B, 0x1123C, prBA, gcPo}, // [2] KHOJKI SECTION MARK..KHOJKI DOUBLE SECTION MARK
+ {0x1123D, 0x1123D, prAL, gcPo}, // KHOJKI ABBREVIATION SIGN
+ {0x1123E, 0x1123E, prCM, gcMn}, // KHOJKI SIGN SUKUN
+ {0x1123F, 0x11240, prAL, gcLo}, // [2] KHOJKI LETTER QA..KHOJKI LETTER SHORT I
+ {0x11241, 0x11241, prCM, gcMn}, // KHOJKI VOWEL SIGN VOCALIC R
+ {0x11280, 0x11286, prAL, gcLo}, // [7] MULTANI LETTER A..MULTANI LETTER GA
+ {0x11288, 0x11288, prAL, gcLo}, // MULTANI LETTER GHA
+ {0x1128A, 0x1128D, prAL, gcLo}, // [4] MULTANI LETTER CA..MULTANI LETTER JJA
+ {0x1128F, 0x1129D, prAL, gcLo}, // [15] MULTANI LETTER NYA..MULTANI LETTER BA
+ {0x1129F, 0x112A8, prAL, gcLo}, // [10] MULTANI LETTER BHA..MULTANI LETTER RHA
+ {0x112A9, 0x112A9, prBA, gcPo}, // MULTANI SECTION MARK
+ {0x112B0, 0x112DE, prAL, gcLo}, // [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA
+ {0x112DF, 0x112DF, prCM, gcMn}, // KHUDAWADI SIGN ANUSVARA
+ {0x112E0, 0x112E2, prCM, gcMc}, // [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II
+ {0x112E3, 0x112EA, prCM, gcMn}, // [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA
+ {0x112F0, 0x112F9, prNU, gcNd}, // [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE
+ {0x11300, 0x11301, prCM, gcMn}, // [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU
+ {0x11302, 0x11303, prCM, gcMc}, // [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA
+ {0x11305, 0x1130C, prAL, gcLo}, // [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L
+ {0x1130F, 0x11310, prAL, gcLo}, // [2] GRANTHA LETTER EE..GRANTHA LETTER AI
+ {0x11313, 0x11328, prAL, gcLo}, // [22] GRANTHA LETTER OO..GRANTHA LETTER NA
+ {0x1132A, 0x11330, prAL, gcLo}, // [7] GRANTHA LETTER PA..GRANTHA LETTER RA
+ {0x11332, 0x11333, prAL, gcLo}, // [2] GRANTHA LETTER LA..GRANTHA LETTER LLA
+ {0x11335, 0x11339, prAL, gcLo}, // [5] GRANTHA LETTER VA..GRANTHA LETTER HA
+ {0x1133B, 0x1133C, prCM, gcMn}, // [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA
+ {0x1133D, 0x1133D, prAL, gcLo}, // GRANTHA SIGN AVAGRAHA
+ {0x1133E, 0x1133F, prCM, gcMc}, // [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I
+ {0x11340, 0x11340, prCM, gcMn}, // GRANTHA VOWEL SIGN II
+ {0x11341, 0x11344, prCM, gcMc}, // [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR
+ {0x11347, 0x11348, prCM, gcMc}, // [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI
+ {0x1134B, 0x1134D, prCM, gcMc}, // [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA
+ {0x11350, 0x11350, prAL, gcLo}, // GRANTHA OM
+ {0x11357, 0x11357, prCM, gcMc}, // GRANTHA AU LENGTH MARK
+ {0x1135D, 0x11361, prAL, gcLo}, // [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL
+ {0x11362, 0x11363, prCM, gcMc}, // [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL
+ {0x11366, 0x1136C, prCM, gcMn}, // [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX
+ {0x11370, 0x11374, prCM, gcMn}, // [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA
+ {0x11400, 0x11434, prAL, gcLo}, // [53] NEWA LETTER A..NEWA LETTER HA
+ {0x11435, 0x11437, prCM, gcMc}, // [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II
+ {0x11438, 0x1143F, prCM, gcMn}, // [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI
+ {0x11440, 0x11441, prCM, gcMc}, // [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU
+ {0x11442, 0x11444, prCM, gcMn}, // [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA
+ {0x11445, 0x11445, prCM, gcMc}, // NEWA SIGN VISARGA
+ {0x11446, 0x11446, prCM, gcMn}, // NEWA SIGN NUKTA
+ {0x11447, 0x1144A, prAL, gcLo}, // [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI
+ {0x1144B, 0x1144E, prBA, gcPo}, // [4] NEWA DANDA..NEWA GAP FILLER
+ {0x1144F, 0x1144F, prAL, gcPo}, // NEWA ABBREVIATION SIGN
+ {0x11450, 0x11459, prNU, gcNd}, // [10] NEWA DIGIT ZERO..NEWA DIGIT NINE
+ {0x1145A, 0x1145B, prBA, gcPo}, // [2] NEWA DOUBLE COMMA..NEWA PLACEHOLDER MARK
+ {0x1145D, 0x1145D, prAL, gcPo}, // NEWA INSERTION SIGN
+ {0x1145E, 0x1145E, prCM, gcMn}, // NEWA SANDHI MARK
+ {0x1145F, 0x11461, prAL, gcLo}, // [3] NEWA LETTER VEDIC ANUSVARA..NEWA SIGN UPADHMANIYA
+ {0x11480, 0x114AF, prAL, gcLo}, // [48] TIRHUTA ANJI..TIRHUTA LETTER HA
+ {0x114B0, 0x114B2, prCM, gcMc}, // [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II
+ {0x114B3, 0x114B8, prCM, gcMn}, // [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL
+ {0x114B9, 0x114B9, prCM, gcMc}, // TIRHUTA VOWEL SIGN E
+ {0x114BA, 0x114BA, prCM, gcMn}, // TIRHUTA VOWEL SIGN SHORT E
+ {0x114BB, 0x114BE, prCM, gcMc}, // [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU
+ {0x114BF, 0x114C0, prCM, gcMn}, // [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA
+ {0x114C1, 0x114C1, prCM, gcMc}, // TIRHUTA SIGN VISARGA
+ {0x114C2, 0x114C3, prCM, gcMn}, // [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA
+ {0x114C4, 0x114C5, prAL, gcLo}, // [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG
+ {0x114C6, 0x114C6, prAL, gcPo}, // TIRHUTA ABBREVIATION SIGN
+ {0x114C7, 0x114C7, prAL, gcLo}, // TIRHUTA OM
+ {0x114D0, 0x114D9, prNU, gcNd}, // [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE
+ {0x11580, 0x115AE, prAL, gcLo}, // [47] SIDDHAM LETTER A..SIDDHAM LETTER HA
+ {0x115AF, 0x115B1, prCM, gcMc}, // [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II
+ {0x115B2, 0x115B5, prCM, gcMn}, // [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR
+ {0x115B8, 0x115BB, prCM, gcMc}, // [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU
+ {0x115BC, 0x115BD, prCM, gcMn}, // [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA
+ {0x115BE, 0x115BE, prCM, gcMc}, // SIDDHAM SIGN VISARGA
+ {0x115BF, 0x115C0, prCM, gcMn}, // [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA
+ {0x115C1, 0x115C1, prBB, gcPo}, // SIDDHAM SIGN SIDDHAM
+ {0x115C2, 0x115C3, prBA, gcPo}, // [2] SIDDHAM DANDA..SIDDHAM DOUBLE DANDA
+ {0x115C4, 0x115C5, prEX, gcPo}, // [2] SIDDHAM SEPARATOR DOT..SIDDHAM SEPARATOR BAR
+ {0x115C6, 0x115C8, prAL, gcPo}, // [3] SIDDHAM REPETITION MARK-1..SIDDHAM REPETITION MARK-3
+ {0x115C9, 0x115D7, prBA, gcPo}, // [15] SIDDHAM END OF TEXT MARK..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES
+ {0x115D8, 0x115DB, prAL, gcLo}, // [4] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM LETTER ALTERNATE U
+ {0x115DC, 0x115DD, prCM, gcMn}, // [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU
+ {0x11600, 0x1162F, prAL, gcLo}, // [48] MODI LETTER A..MODI LETTER LLA
+ {0x11630, 0x11632, prCM, gcMc}, // [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II
+ {0x11633, 0x1163A, prCM, gcMn}, // [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI
+ {0x1163B, 0x1163C, prCM, gcMc}, // [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU
+ {0x1163D, 0x1163D, prCM, gcMn}, // MODI SIGN ANUSVARA
+ {0x1163E, 0x1163E, prCM, gcMc}, // MODI SIGN VISARGA
+ {0x1163F, 0x11640, prCM, gcMn}, // [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA
+ {0x11641, 0x11642, prBA, gcPo}, // [2] MODI DANDA..MODI DOUBLE DANDA
+ {0x11643, 0x11643, prAL, gcPo}, // MODI ABBREVIATION SIGN
+ {0x11644, 0x11644, prAL, gcLo}, // MODI SIGN HUVA
+ {0x11650, 0x11659, prNU, gcNd}, // [10] MODI DIGIT ZERO..MODI DIGIT NINE
+ {0x11660, 0x1166C, prBB, gcPo}, // [13] MONGOLIAN BIRGA WITH ORNAMENT..MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT
+ {0x11680, 0x116AA, prAL, gcLo}, // [43] TAKRI LETTER A..TAKRI LETTER RRA
+ {0x116AB, 0x116AB, prCM, gcMn}, // TAKRI SIGN ANUSVARA
+ {0x116AC, 0x116AC, prCM, gcMc}, // TAKRI SIGN VISARGA
+ {0x116AD, 0x116AD, prCM, gcMn}, // TAKRI VOWEL SIGN AA
+ {0x116AE, 0x116AF, prCM, gcMc}, // [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II
+ {0x116B0, 0x116B5, prCM, gcMn}, // [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU
+ {0x116B6, 0x116B6, prCM, gcMc}, // TAKRI SIGN VIRAMA
+ {0x116B7, 0x116B7, prCM, gcMn}, // TAKRI SIGN NUKTA
+ {0x116B8, 0x116B8, prAL, gcLo}, // TAKRI LETTER ARCHAIC KHA
+ {0x116B9, 0x116B9, prAL, gcPo}, // TAKRI ABBREVIATION SIGN
+ {0x116C0, 0x116C9, prNU, gcNd}, // [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE
+ {0x11700, 0x1171A, prSA, gcLo}, // [27] AHOM LETTER KA..AHOM LETTER ALTERNATE BA
+ {0x1171D, 0x1171F, prSA, gcMn}, // [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA
+ {0x11720, 0x11721, prSA, gcMc}, // [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA
+ {0x11722, 0x11725, prSA, gcMn}, // [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU
+ {0x11726, 0x11726, prSA, gcMc}, // AHOM VOWEL SIGN E
+ {0x11727, 0x1172B, prSA, gcMn}, // [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER
+ {0x11730, 0x11739, prNU, gcNd}, // [10] AHOM DIGIT ZERO..AHOM DIGIT NINE
+ {0x1173A, 0x1173B, prSA, gcNo}, // [2] AHOM NUMBER TEN..AHOM NUMBER TWENTY
+ {0x1173C, 0x1173E, prBA, gcPo}, // [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI
+ {0x1173F, 0x1173F, prSA, gcSo}, // AHOM SYMBOL VI
+ {0x11740, 0x11746, prSA, gcLo}, // [7] AHOM LETTER CA..AHOM LETTER LLA
+ {0x11800, 0x1182B, prAL, gcLo}, // [44] DOGRA LETTER A..DOGRA LETTER RRA
+ {0x1182C, 0x1182E, prCM, gcMc}, // [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II
+ {0x1182F, 0x11837, prCM, gcMn}, // [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA
+ {0x11838, 0x11838, prCM, gcMc}, // DOGRA SIGN VISARGA
+ {0x11839, 0x1183A, prCM, gcMn}, // [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA
+ {0x1183B, 0x1183B, prAL, gcPo}, // DOGRA ABBREVIATION SIGN
+ {0x118A0, 0x118DF, prAL, gcLC}, // [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO
+ {0x118E0, 0x118E9, prNU, gcNd}, // [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE
+ {0x118EA, 0x118F2, prAL, gcNo}, // [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY
+ {0x118FF, 0x118FF, prAL, gcLo}, // WARANG CITI OM
+ {0x11900, 0x11906, prAL, gcLo}, // [7] DIVES AKURU LETTER A..DIVES AKURU LETTER E
+ {0x11909, 0x11909, prAL, gcLo}, // DIVES AKURU LETTER O
+ {0x1190C, 0x11913, prAL, gcLo}, // [8] DIVES AKURU LETTER KA..DIVES AKURU LETTER JA
+ {0x11915, 0x11916, prAL, gcLo}, // [2] DIVES AKURU LETTER NYA..DIVES AKURU LETTER TTA
+ {0x11918, 0x1192F, prAL, gcLo}, // [24] DIVES AKURU LETTER DDA..DIVES AKURU LETTER ZA
+ {0x11930, 0x11935, prCM, gcMc}, // [6] DIVES AKURU VOWEL SIGN AA..DIVES AKURU VOWEL SIGN E
+ {0x11937, 0x11938, prCM, gcMc}, // [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O
+ {0x1193B, 0x1193C, prCM, gcMn}, // [2] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN CANDRABINDU
+ {0x1193D, 0x1193D, prCM, gcMc}, // DIVES AKURU SIGN HALANTA
+ {0x1193E, 0x1193E, prCM, gcMn}, // DIVES AKURU VIRAMA
+ {0x1193F, 0x1193F, prAL, gcLo}, // DIVES AKURU PREFIXED NASAL SIGN
+ {0x11940, 0x11940, prCM, gcMc}, // DIVES AKURU MEDIAL YA
+ {0x11941, 0x11941, prAL, gcLo}, // DIVES AKURU INITIAL RA
+ {0x11942, 0x11942, prCM, gcMc}, // DIVES AKURU MEDIAL RA
+ {0x11943, 0x11943, prCM, gcMn}, // DIVES AKURU SIGN NUKTA
+ {0x11944, 0x11946, prBA, gcPo}, // [3] DIVES AKURU DOUBLE DANDA..DIVES AKURU END OF TEXT MARK
+ {0x11950, 0x11959, prNU, gcNd}, // [10] DIVES AKURU DIGIT ZERO..DIVES AKURU DIGIT NINE
+ {0x119A0, 0x119A7, prAL, gcLo}, // [8] NANDINAGARI LETTER A..NANDINAGARI LETTER VOCALIC RR
+ {0x119AA, 0x119D0, prAL, gcLo}, // [39] NANDINAGARI LETTER E..NANDINAGARI LETTER RRA
+ {0x119D1, 0x119D3, prCM, gcMc}, // [3] NANDINAGARI VOWEL SIGN AA..NANDINAGARI VOWEL SIGN II
+ {0x119D4, 0x119D7, prCM, gcMn}, // [4] NANDINAGARI VOWEL SIGN U..NANDINAGARI VOWEL SIGN VOCALIC RR
+ {0x119DA, 0x119DB, prCM, gcMn}, // [2] NANDINAGARI VOWEL SIGN E..NANDINAGARI VOWEL SIGN AI
+ {0x119DC, 0x119DF, prCM, gcMc}, // [4] NANDINAGARI VOWEL SIGN O..NANDINAGARI SIGN VISARGA
+ {0x119E0, 0x119E0, prCM, gcMn}, // NANDINAGARI SIGN VIRAMA
+ {0x119E1, 0x119E1, prAL, gcLo}, // NANDINAGARI SIGN AVAGRAHA
+ {0x119E2, 0x119E2, prBB, gcPo}, // NANDINAGARI SIGN SIDDHAM
+ {0x119E3, 0x119E3, prAL, gcLo}, // NANDINAGARI HEADSTROKE
+ {0x119E4, 0x119E4, prCM, gcMc}, // NANDINAGARI VOWEL SIGN PRISHTHAMATRA E
+ {0x11A00, 0x11A00, prAL, gcLo}, // ZANABAZAR SQUARE LETTER A
+ {0x11A01, 0x11A0A, prCM, gcMn}, // [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK
+ {0x11A0B, 0x11A32, prAL, gcLo}, // [40] ZANABAZAR SQUARE LETTER KA..ZANABAZAR SQUARE LETTER KSSA
+ {0x11A33, 0x11A38, prCM, gcMn}, // [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA
+ {0x11A39, 0x11A39, prCM, gcMc}, // ZANABAZAR SQUARE SIGN VISARGA
+ {0x11A3A, 0x11A3A, prAL, gcLo}, // ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA
+ {0x11A3B, 0x11A3E, prCM, gcMn}, // [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA
+ {0x11A3F, 0x11A3F, prBB, gcPo}, // ZANABAZAR SQUARE INITIAL HEAD MARK
+ {0x11A40, 0x11A40, prAL, gcPo}, // ZANABAZAR SQUARE CLOSING HEAD MARK
+ {0x11A41, 0x11A44, prBA, gcPo}, // [4] ZANABAZAR SQUARE MARK TSHEG..ZANABAZAR SQUARE MARK LONG TSHEG
+ {0x11A45, 0x11A45, prBB, gcPo}, // ZANABAZAR SQUARE INITIAL DOUBLE-LINED HEAD MARK
+ {0x11A46, 0x11A46, prAL, gcPo}, // ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK
+ {0x11A47, 0x11A47, prCM, gcMn}, // ZANABAZAR SQUARE SUBJOINER
+ {0x11A50, 0x11A50, prAL, gcLo}, // SOYOMBO LETTER A
+ {0x11A51, 0x11A56, prCM, gcMn}, // [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE
+ {0x11A57, 0x11A58, prCM, gcMc}, // [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU
+ {0x11A59, 0x11A5B, prCM, gcMn}, // [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK
+ {0x11A5C, 0x11A89, prAL, gcLo}, // [46] SOYOMBO LETTER KA..SOYOMBO CLUSTER-INITIAL LETTER SA
+ {0x11A8A, 0x11A96, prCM, gcMn}, // [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA
+ {0x11A97, 0x11A97, prCM, gcMc}, // SOYOMBO SIGN VISARGA
+ {0x11A98, 0x11A99, prCM, gcMn}, // [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER
+ {0x11A9A, 0x11A9C, prBA, gcPo}, // [3] SOYOMBO MARK TSHEG..SOYOMBO MARK DOUBLE SHAD
+ {0x11A9D, 0x11A9D, prAL, gcLo}, // SOYOMBO MARK PLUTA
+ {0x11A9E, 0x11AA0, prBB, gcPo}, // [3] SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO HEAD MARK WITH MOON AND SUN
+ {0x11AA1, 0x11AA2, prBA, gcPo}, // [2] SOYOMBO TERMINAL MARK-1..SOYOMBO TERMINAL MARK-2
+ {0x11AB0, 0x11ABF, prAL, gcLo}, // [16] CANADIAN SYLLABICS NATTILIK HI..CANADIAN SYLLABICS SPA
+ {0x11AC0, 0x11AF8, prAL, gcLo}, // [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL
+ {0x11B00, 0x11B09, prBB, gcPo}, // [10] DEVANAGARI HEAD MARK..DEVANAGARI SIGN MINDU
+ {0x11C00, 0x11C08, prAL, gcLo}, // [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L
+ {0x11C0A, 0x11C2E, prAL, gcLo}, // [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA
+ {0x11C2F, 0x11C2F, prCM, gcMc}, // BHAIKSUKI VOWEL SIGN AA
+ {0x11C30, 0x11C36, prCM, gcMn}, // [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L
+ {0x11C38, 0x11C3D, prCM, gcMn}, // [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA
+ {0x11C3E, 0x11C3E, prCM, gcMc}, // BHAIKSUKI SIGN VISARGA
+ {0x11C3F, 0x11C3F, prCM, gcMn}, // BHAIKSUKI SIGN VIRAMA
+ {0x11C40, 0x11C40, prAL, gcLo}, // BHAIKSUKI SIGN AVAGRAHA
+ {0x11C41, 0x11C45, prBA, gcPo}, // [5] BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2
+ {0x11C50, 0x11C59, prNU, gcNd}, // [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE
+ {0x11C5A, 0x11C6C, prAL, gcNo}, // [19] BHAIKSUKI NUMBER ONE..BHAIKSUKI HUNDREDS UNIT MARK
+ {0x11C70, 0x11C70, prBB, gcPo}, // MARCHEN HEAD MARK
+ {0x11C71, 0x11C71, prEX, gcPo}, // MARCHEN MARK SHAD
+ {0x11C72, 0x11C8F, prAL, gcLo}, // [30] MARCHEN LETTER KA..MARCHEN LETTER A
+ {0x11C92, 0x11CA7, prCM, gcMn}, // [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA
+ {0x11CA9, 0x11CA9, prCM, gcMc}, // MARCHEN SUBJOINED LETTER YA
+ {0x11CAA, 0x11CB0, prCM, gcMn}, // [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA
+ {0x11CB1, 0x11CB1, prCM, gcMc}, // MARCHEN VOWEL SIGN I
+ {0x11CB2, 0x11CB3, prCM, gcMn}, // [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E
+ {0x11CB4, 0x11CB4, prCM, gcMc}, // MARCHEN VOWEL SIGN O
+ {0x11CB5, 0x11CB6, prCM, gcMn}, // [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU
+ {0x11D00, 0x11D06, prAL, gcLo}, // [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E
+ {0x11D08, 0x11D09, prAL, gcLo}, // [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O
+ {0x11D0B, 0x11D30, prAL, gcLo}, // [38] MASARAM GONDI LETTER AU..MASARAM GONDI LETTER TRA
+ {0x11D31, 0x11D36, prCM, gcMn}, // [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R
+ {0x11D3A, 0x11D3A, prCM, gcMn}, // MASARAM GONDI VOWEL SIGN E
+ {0x11D3C, 0x11D3D, prCM, gcMn}, // [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O
+ {0x11D3F, 0x11D45, prCM, gcMn}, // [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA
+ {0x11D46, 0x11D46, prAL, gcLo}, // MASARAM GONDI REPHA
+ {0x11D47, 0x11D47, prCM, gcMn}, // MASARAM GONDI RA-KARA
+ {0x11D50, 0x11D59, prNU, gcNd}, // [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE
+ {0x11D60, 0x11D65, prAL, gcLo}, // [6] GUNJALA GONDI LETTER A..GUNJALA GONDI LETTER UU
+ {0x11D67, 0x11D68, prAL, gcLo}, // [2] GUNJALA GONDI LETTER EE..GUNJALA GONDI LETTER AI
+ {0x11D6A, 0x11D89, prAL, gcLo}, // [32] GUNJALA GONDI LETTER OO..GUNJALA GONDI LETTER SA
+ {0x11D8A, 0x11D8E, prCM, gcMc}, // [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU
+ {0x11D90, 0x11D91, prCM, gcMn}, // [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI
+ {0x11D93, 0x11D94, prCM, gcMc}, // [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU
+ {0x11D95, 0x11D95, prCM, gcMn}, // GUNJALA GONDI SIGN ANUSVARA
+ {0x11D96, 0x11D96, prCM, gcMc}, // GUNJALA GONDI SIGN VISARGA
+ {0x11D97, 0x11D97, prCM, gcMn}, // GUNJALA GONDI VIRAMA
+ {0x11D98, 0x11D98, prAL, gcLo}, // GUNJALA GONDI OM
+ {0x11DA0, 0x11DA9, prNU, gcNd}, // [10] GUNJALA GONDI DIGIT ZERO..GUNJALA GONDI DIGIT NINE
+ {0x11EE0, 0x11EF2, prAL, gcLo}, // [19] MAKASAR LETTER KA..MAKASAR ANGKA
+ {0x11EF3, 0x11EF4, prCM, gcMn}, // [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U
+ {0x11EF5, 0x11EF6, prCM, gcMc}, // [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O
+ {0x11EF7, 0x11EF8, prAL, gcPo}, // [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION
+ {0x11F00, 0x11F01, prCM, gcMn}, // [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA
+ {0x11F02, 0x11F02, prAL, gcLo}, // KAWI SIGN REPHA
+ {0x11F03, 0x11F03, prCM, gcMc}, // KAWI SIGN VISARGA
+ {0x11F04, 0x11F10, prAL, gcLo}, // [13] KAWI LETTER A..KAWI LETTER O
+ {0x11F12, 0x11F33, prAL, gcLo}, // [34] KAWI LETTER KA..KAWI LETTER JNYA
+ {0x11F34, 0x11F35, prCM, gcMc}, // [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA
+ {0x11F36, 0x11F3A, prCM, gcMn}, // [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R
+ {0x11F3E, 0x11F3F, prCM, gcMc}, // [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI
+ {0x11F40, 0x11F40, prCM, gcMn}, // KAWI VOWEL SIGN EU
+ {0x11F41, 0x11F41, prCM, gcMc}, // KAWI SIGN KILLER
+ {0x11F42, 0x11F42, prCM, gcMn}, // KAWI CONJOINER
+ {0x11F43, 0x11F44, prBA, gcPo}, // [2] KAWI DANDA..KAWI DOUBLE DANDA
+ {0x11F45, 0x11F4F, prID, gcPo}, // [11] KAWI PUNCTUATION SECTION MARKER..KAWI PUNCTUATION CLOSING SPIRAL
+ {0x11F50, 0x11F59, prNU, gcNd}, // [10] KAWI DIGIT ZERO..KAWI DIGIT NINE
+ {0x11FB0, 0x11FB0, prAL, gcLo}, // LISU LETTER YHA
+ {0x11FC0, 0x11FD4, prAL, gcNo}, // [21] TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH..TAMIL FRACTION DOWNSCALING FACTOR KIIZH
+ {0x11FD5, 0x11FDC, prAL, gcSo}, // [8] TAMIL SIGN NEL..TAMIL SIGN MUKKURUNI
+ {0x11FDD, 0x11FE0, prPO, gcSc}, // [4] TAMIL SIGN KAACU..TAMIL SIGN VARAAKAN
+ {0x11FE1, 0x11FF1, prAL, gcSo}, // [17] TAMIL SIGN PAARAM..TAMIL SIGN VAKAIYARAA
+ {0x11FFF, 0x11FFF, prBA, gcPo}, // TAMIL PUNCTUATION END OF TEXT
+ {0x12000, 0x12399, prAL, gcLo}, // [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U
+ {0x12400, 0x1246E, prAL, gcNl}, // [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM
+ {0x12470, 0x12474, prBA, gcPo}, // [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON
+ {0x12480, 0x12543, prAL, gcLo}, // [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU
+ {0x12F90, 0x12FF0, prAL, gcLo}, // [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114
+ {0x12FF1, 0x12FF2, prAL, gcPo}, // [2] CYPRO-MINOAN SIGN CM301..CYPRO-MINOAN SIGN CM302
+ {0x13000, 0x13257, prAL, gcLo}, // [600] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH O006
+ {0x13258, 0x1325A, prOP, gcLo}, // [3] EGYPTIAN HIEROGLYPH O006A..EGYPTIAN HIEROGLYPH O006C
+ {0x1325B, 0x1325D, prCL, gcLo}, // [3] EGYPTIAN HIEROGLYPH O006D..EGYPTIAN HIEROGLYPH O006F
+ {0x1325E, 0x13281, prAL, gcLo}, // [36] EGYPTIAN HIEROGLYPH O007..EGYPTIAN HIEROGLYPH O033
+ {0x13282, 0x13282, prCL, gcLo}, // EGYPTIAN HIEROGLYPH O033A
+ {0x13283, 0x13285, prAL, gcLo}, // [3] EGYPTIAN HIEROGLYPH O034..EGYPTIAN HIEROGLYPH O036
+ {0x13286, 0x13286, prOP, gcLo}, // EGYPTIAN HIEROGLYPH O036A
+ {0x13287, 0x13287, prCL, gcLo}, // EGYPTIAN HIEROGLYPH O036B
+ {0x13288, 0x13288, prOP, gcLo}, // EGYPTIAN HIEROGLYPH O036C
+ {0x13289, 0x13289, prCL, gcLo}, // EGYPTIAN HIEROGLYPH O036D
+ {0x1328A, 0x13378, prAL, gcLo}, // [239] EGYPTIAN HIEROGLYPH O037..EGYPTIAN HIEROGLYPH V011
+ {0x13379, 0x13379, prOP, gcLo}, // EGYPTIAN HIEROGLYPH V011A
+ {0x1337A, 0x1337B, prCL, gcLo}, // [2] EGYPTIAN HIEROGLYPH V011B..EGYPTIAN HIEROGLYPH V011C
+ {0x1337C, 0x1342F, prAL, gcLo}, // [180] EGYPTIAN HIEROGLYPH V012..EGYPTIAN HIEROGLYPH V011D
+ {0x13430, 0x13436, prGL, gcCf}, // [7] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH OVERLAY MIDDLE
+ {0x13437, 0x13437, prOP, gcCf}, // EGYPTIAN HIEROGLYPH BEGIN SEGMENT
+ {0x13438, 0x13438, prCL, gcCf}, // EGYPTIAN HIEROGLYPH END SEGMENT
+ {0x13439, 0x1343B, prGL, gcCf}, // [3] EGYPTIAN HIEROGLYPH INSERT AT MIDDLE..EGYPTIAN HIEROGLYPH INSERT AT BOTTOM
+ {0x1343C, 0x1343C, prOP, gcCf}, // EGYPTIAN HIEROGLYPH BEGIN ENCLOSURE
+ {0x1343D, 0x1343D, prCL, gcCf}, // EGYPTIAN HIEROGLYPH END ENCLOSURE
+ {0x1343E, 0x1343E, prOP, gcCf}, // EGYPTIAN HIEROGLYPH BEGIN WALLED ENCLOSURE
+ {0x1343F, 0x1343F, prCL, gcCf}, // EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE
+ {0x13440, 0x13440, prCM, gcMn}, // EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY
+ {0x13441, 0x13446, prAL, gcLo}, // [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN
+ {0x13447, 0x13455, prCM, gcMn}, // [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED
+ {0x14400, 0x145CD, prAL, gcLo}, // [462] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A409
+ {0x145CE, 0x145CE, prOP, gcLo}, // ANATOLIAN HIEROGLYPH A410 BEGIN LOGOGRAM MARK
+ {0x145CF, 0x145CF, prCL, gcLo}, // ANATOLIAN HIEROGLYPH A410A END LOGOGRAM MARK
+ {0x145D0, 0x14646, prAL, gcLo}, // [119] ANATOLIAN HIEROGLYPH A411..ANATOLIAN HIEROGLYPH A530
+ {0x16800, 0x16A38, prAL, gcLo}, // [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ
+ {0x16A40, 0x16A5E, prAL, gcLo}, // [31] MRO LETTER TA..MRO LETTER TEK
+ {0x16A60, 0x16A69, prNU, gcNd}, // [10] MRO DIGIT ZERO..MRO DIGIT NINE
+ {0x16A6E, 0x16A6F, prBA, gcPo}, // [2] MRO DANDA..MRO DOUBLE DANDA
+ {0x16A70, 0x16ABE, prAL, gcLo}, // [79] TANGSA LETTER OZ..TANGSA LETTER ZA
+ {0x16AC0, 0x16AC9, prNU, gcNd}, // [10] TANGSA DIGIT ZERO..TANGSA DIGIT NINE
+ {0x16AD0, 0x16AED, prAL, gcLo}, // [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I
+ {0x16AF0, 0x16AF4, prCM, gcMn}, // [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
+ {0x16AF5, 0x16AF5, prBA, gcPo}, // BASSA VAH FULL STOP
+ {0x16B00, 0x16B2F, prAL, gcLo}, // [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU
+ {0x16B30, 0x16B36, prCM, gcMn}, // [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
+ {0x16B37, 0x16B39, prBA, gcPo}, // [3] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN CIM CHEEM
+ {0x16B3A, 0x16B3B, prAL, gcPo}, // [2] PAHAWH HMONG SIGN VOS THIAB..PAHAWH HMONG SIGN VOS FEEM
+ {0x16B3C, 0x16B3F, prAL, gcSo}, // [4] PAHAWH HMONG SIGN XYEEM NTXIV..PAHAWH HMONG SIGN XYEEM FAIB
+ {0x16B40, 0x16B43, prAL, gcLm}, // [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM
+ {0x16B44, 0x16B44, prBA, gcPo}, // PAHAWH HMONG SIGN XAUS
+ {0x16B45, 0x16B45, prAL, gcSo}, // PAHAWH HMONG SIGN CIM TSOV ROG
+ {0x16B50, 0x16B59, prNU, gcNd}, // [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE
+ {0x16B5B, 0x16B61, prAL, gcNo}, // [7] PAHAWH HMONG NUMBER TENS..PAHAWH HMONG NUMBER TRILLIONS
+ {0x16B63, 0x16B77, prAL, gcLo}, // [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS
+ {0x16B7D, 0x16B8F, prAL, gcLo}, // [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ
+ {0x16E40, 0x16E7F, prAL, gcLC}, // [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y
+ {0x16E80, 0x16E96, prAL, gcNo}, // [23] MEDEFAIDRIN DIGIT ZERO..MEDEFAIDRIN DIGIT THREE ALTERNATE FORM
+ {0x16E97, 0x16E98, prBA, gcPo}, // [2] MEDEFAIDRIN COMMA..MEDEFAIDRIN FULL STOP
+ {0x16E99, 0x16E9A, prAL, gcPo}, // [2] MEDEFAIDRIN SYMBOL AIVA..MEDEFAIDRIN EXCLAMATION OH
+ {0x16F00, 0x16F4A, prAL, gcLo}, // [75] MIAO LETTER PA..MIAO LETTER RTE
+ {0x16F4F, 0x16F4F, prCM, gcMn}, // MIAO SIGN CONSONANT MODIFIER BAR
+ {0x16F50, 0x16F50, prAL, gcLo}, // MIAO LETTER NASALIZATION
+ {0x16F51, 0x16F87, prCM, gcMc}, // [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI
+ {0x16F8F, 0x16F92, prCM, gcMn}, // [4] MIAO TONE RIGHT..MIAO TONE BELOW
+ {0x16F93, 0x16F9F, prAL, gcLm}, // [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8
+ {0x16FE0, 0x16FE1, prNS, gcLm}, // [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK
+ {0x16FE2, 0x16FE2, prNS, gcPo}, // OLD CHINESE HOOK MARK
+ {0x16FE3, 0x16FE3, prNS, gcLm}, // OLD CHINESE ITERATION MARK
+ {0x16FE4, 0x16FE4, prGL, gcMn}, // KHITAN SMALL SCRIPT FILLER
+ {0x16FF0, 0x16FF1, prCM, gcMc}, // [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY
+ {0x17000, 0x187F7, prID, gcLo}, // [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7
+ {0x18800, 0x18AFF, prID, gcLo}, // [768] TANGUT COMPONENT-001..TANGUT COMPONENT-768
+ {0x18B00, 0x18CD5, prAL, gcLo}, // [470] KHITAN SMALL SCRIPT CHARACTER-18B00..KHITAN SMALL SCRIPT CHARACTER-18CD5
+ {0x18D00, 0x18D08, prID, gcLo}, // [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08
+ {0x1AFF0, 0x1AFF3, prAL, gcLm}, // [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5
+ {0x1AFF5, 0x1AFFB, prAL, gcLm}, // [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5
+ {0x1AFFD, 0x1AFFE, prAL, gcLm}, // [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8
+ {0x1B000, 0x1B0FF, prID, gcLo}, // [256] KATAKANA LETTER ARCHAIC E..HENTAIGANA LETTER RE-2
+ {0x1B100, 0x1B122, prID, gcLo}, // [35] HENTAIGANA LETTER RE-3..KATAKANA LETTER ARCHAIC WU
+ {0x1B132, 0x1B132, prCJ, gcLo}, // HIRAGANA LETTER SMALL KO
+ {0x1B150, 0x1B152, prCJ, gcLo}, // [3] HIRAGANA LETTER SMALL WI..HIRAGANA LETTER SMALL WO
+ {0x1B155, 0x1B155, prCJ, gcLo}, // KATAKANA LETTER SMALL KO
+ {0x1B164, 0x1B167, prCJ, gcLo}, // [4] KATAKANA LETTER SMALL WI..KATAKANA LETTER SMALL N
+ {0x1B170, 0x1B2FB, prID, gcLo}, // [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB
+ {0x1BC00, 0x1BC6A, prAL, gcLo}, // [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M
+ {0x1BC70, 0x1BC7C, prAL, gcLo}, // [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK
+ {0x1BC80, 0x1BC88, prAL, gcLo}, // [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL
+ {0x1BC90, 0x1BC99, prAL, gcLo}, // [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW
+ {0x1BC9C, 0x1BC9C, prAL, gcSo}, // DUPLOYAN SIGN O WITH CROSS
+ {0x1BC9D, 0x1BC9E, prCM, gcMn}, // [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK
+ {0x1BC9F, 0x1BC9F, prBA, gcPo}, // DUPLOYAN PUNCTUATION CHINOOK FULL STOP
+ {0x1BCA0, 0x1BCA3, prCM, gcCf}, // [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
+ {0x1CF00, 0x1CF2D, prCM, gcMn}, // [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT
+ {0x1CF30, 0x1CF46, prCM, gcMn}, // [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG
+ {0x1CF50, 0x1CFC3, prAL, gcSo}, // [116] ZNAMENNY NEUME KRYUK..ZNAMENNY NEUME PAUK
+ {0x1D000, 0x1D0F5, prAL, gcSo}, // [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO
+ {0x1D100, 0x1D126, prAL, gcSo}, // [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2
+ {0x1D129, 0x1D164, prAL, gcSo}, // [60] MUSICAL SYMBOL MULTIPLE MEASURE REST..MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE
+ {0x1D165, 0x1D166, prCM, gcMc}, // [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM
+ {0x1D167, 0x1D169, prCM, gcMn}, // [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3
+ {0x1D16A, 0x1D16C, prAL, gcSo}, // [3] MUSICAL SYMBOL FINGERED TREMOLO-1..MUSICAL SYMBOL FINGERED TREMOLO-3
+ {0x1D16D, 0x1D172, prCM, gcMc}, // [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5
+ {0x1D173, 0x1D17A, prCM, gcCf}, // [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
+ {0x1D17B, 0x1D182, prCM, gcMn}, // [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE
+ {0x1D183, 0x1D184, prAL, gcSo}, // [2] MUSICAL SYMBOL ARPEGGIATO UP..MUSICAL SYMBOL ARPEGGIATO DOWN
+ {0x1D185, 0x1D18B, prCM, gcMn}, // [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
+ {0x1D18C, 0x1D1A9, prAL, gcSo}, // [30] MUSICAL SYMBOL RINFORZANDO..MUSICAL SYMBOL DEGREE SLASH
+ {0x1D1AA, 0x1D1AD, prCM, gcMn}, // [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
+ {0x1D1AE, 0x1D1EA, prAL, gcSo}, // [61] MUSICAL SYMBOL PEDAL MARK..MUSICAL SYMBOL KORON
+ {0x1D200, 0x1D241, prAL, gcSo}, // [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54
+ {0x1D242, 0x1D244, prCM, gcMn}, // [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME
+ {0x1D245, 0x1D245, prAL, gcSo}, // GREEK MUSICAL LEIMMA
+ {0x1D2C0, 0x1D2D3, prAL, gcNo}, // [20] KAKTOVIK NUMERAL ZERO..KAKTOVIK NUMERAL NINETEEN
+ {0x1D2E0, 0x1D2F3, prAL, gcNo}, // [20] MAYAN NUMERAL ZERO..MAYAN NUMERAL NINETEEN
+ {0x1D300, 0x1D356, prAL, gcSo}, // [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING
+ {0x1D360, 0x1D378, prAL, gcNo}, // [25] COUNTING ROD UNIT DIGIT ONE..TALLY MARK FIVE
+ {0x1D400, 0x1D454, prAL, gcLC}, // [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G
+ {0x1D456, 0x1D49C, prAL, gcLC}, // [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A
+ {0x1D49E, 0x1D49F, prAL, gcLu}, // [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D
+ {0x1D4A2, 0x1D4A2, prAL, gcLu}, // MATHEMATICAL SCRIPT CAPITAL G
+ {0x1D4A5, 0x1D4A6, prAL, gcLu}, // [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K
+ {0x1D4A9, 0x1D4AC, prAL, gcLu}, // [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q
+ {0x1D4AE, 0x1D4B9, prAL, gcLC}, // [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D
+ {0x1D4BB, 0x1D4BB, prAL, gcLl}, // MATHEMATICAL SCRIPT SMALL F
+ {0x1D4BD, 0x1D4C3, prAL, gcLl}, // [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N
+ {0x1D4C5, 0x1D505, prAL, gcLC}, // [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B
+ {0x1D507, 0x1D50A, prAL, gcLu}, // [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G
+ {0x1D50D, 0x1D514, prAL, gcLu}, // [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q
+ {0x1D516, 0x1D51C, prAL, gcLu}, // [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y
+ {0x1D51E, 0x1D539, prAL, gcLC}, // [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+ {0x1D53B, 0x1D53E, prAL, gcLu}, // [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+ {0x1D540, 0x1D544, prAL, gcLu}, // [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+ {0x1D546, 0x1D546, prAL, gcLu}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+ {0x1D54A, 0x1D550, prAL, gcLu}, // [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+ {0x1D552, 0x1D6A5, prAL, gcLC}, // [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J
+ {0x1D6A8, 0x1D6C0, prAL, gcLu}, // [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA
+ {0x1D6C1, 0x1D6C1, prAL, gcSm}, // MATHEMATICAL BOLD NABLA
+ {0x1D6C2, 0x1D6DA, prAL, gcLl}, // [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA
+ {0x1D6DB, 0x1D6DB, prAL, gcSm}, // MATHEMATICAL BOLD PARTIAL DIFFERENTIAL
+ {0x1D6DC, 0x1D6FA, prAL, gcLC}, // [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA
+ {0x1D6FB, 0x1D6FB, prAL, gcSm}, // MATHEMATICAL ITALIC NABLA
+ {0x1D6FC, 0x1D714, prAL, gcLl}, // [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA
+ {0x1D715, 0x1D715, prAL, gcSm}, // MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL
+ {0x1D716, 0x1D734, prAL, gcLC}, // [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA
+ {0x1D735, 0x1D735, prAL, gcSm}, // MATHEMATICAL BOLD ITALIC NABLA
+ {0x1D736, 0x1D74E, prAL, gcLl}, // [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA
+ {0x1D74F, 0x1D74F, prAL, gcSm}, // MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL
+ {0x1D750, 0x1D76E, prAL, gcLC}, // [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA
+ {0x1D76F, 0x1D76F, prAL, gcSm}, // MATHEMATICAL SANS-SERIF BOLD NABLA
+ {0x1D770, 0x1D788, prAL, gcLl}, // [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA
+ {0x1D789, 0x1D789, prAL, gcSm}, // MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL
+ {0x1D78A, 0x1D7A8, prAL, gcLC}, // [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA
+ {0x1D7A9, 0x1D7A9, prAL, gcSm}, // MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA
+ {0x1D7AA, 0x1D7C2, prAL, gcLl}, // [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA
+ {0x1D7C3, 0x1D7C3, prAL, gcSm}, // MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL
+ {0x1D7C4, 0x1D7CB, prAL, gcLC}, // [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA
+ {0x1D7CE, 0x1D7FF, prNU, gcNd}, // [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
+ {0x1D800, 0x1D9FF, prAL, gcSo}, // [512] SIGNWRITING HAND-FIST INDEX..SIGNWRITING HEAD
+ {0x1DA00, 0x1DA36, prCM, gcMn}, // [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN
+ {0x1DA37, 0x1DA3A, prAL, gcSo}, // [4] SIGNWRITING AIR BLOW SMALL ROTATIONS..SIGNWRITING BREATH EXHALE
+ {0x1DA3B, 0x1DA6C, prCM, gcMn}, // [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT
+ {0x1DA6D, 0x1DA74, prAL, gcSo}, // [8] SIGNWRITING SHOULDER HIP SPINE..SIGNWRITING TORSO-FLOORPLANE TWISTING
+ {0x1DA75, 0x1DA75, prCM, gcMn}, // SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS
+ {0x1DA76, 0x1DA83, prAL, gcSo}, // [14] SIGNWRITING LIMB COMBINATION..SIGNWRITING LOCATION DEPTH
+ {0x1DA84, 0x1DA84, prCM, gcMn}, // SIGNWRITING LOCATION HEAD NECK
+ {0x1DA85, 0x1DA86, prAL, gcSo}, // [2] SIGNWRITING LOCATION TORSO..SIGNWRITING LOCATION LIMBS DIGITS
+ {0x1DA87, 0x1DA8A, prBA, gcPo}, // [4] SIGNWRITING COMMA..SIGNWRITING COLON
+ {0x1DA8B, 0x1DA8B, prAL, gcPo}, // SIGNWRITING PARENTHESIS
+ {0x1DA9B, 0x1DA9F, prCM, gcMn}, // [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6
+ {0x1DAA1, 0x1DAAF, prCM, gcMn}, // [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16
+ {0x1DF00, 0x1DF09, prAL, gcLl}, // [10] LATIN SMALL LETTER FENG DIGRAPH WITH TRILL..LATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOOK
+ {0x1DF0A, 0x1DF0A, prAL, gcLo}, // LATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOK
+ {0x1DF0B, 0x1DF1E, prAL, gcLl}, // [20] LATIN SMALL LETTER ESH WITH DOUBLE BAR..LATIN SMALL LETTER S WITH CURL
+ {0x1DF25, 0x1DF2A, prAL, gcLl}, // [6] LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK..LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK
+ {0x1E000, 0x1E006, prCM, gcMn}, // [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE
+ {0x1E008, 0x1E018, prCM, gcMn}, // [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU
+ {0x1E01B, 0x1E021, prCM, gcMn}, // [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI
+ {0x1E023, 0x1E024, prCM, gcMn}, // [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS
+ {0x1E026, 0x1E02A, prCM, gcMn}, // [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA
+ {0x1E030, 0x1E06D, prAL, gcLm}, // [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE
+ {0x1E08F, 0x1E08F, prCM, gcMn}, // COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+ {0x1E100, 0x1E12C, prAL, gcLo}, // [45] NYIAKENG PUACHUE HMONG LETTER MA..NYIAKENG PUACHUE HMONG LETTER W
+ {0x1E130, 0x1E136, prCM, gcMn}, // [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D
+ {0x1E137, 0x1E13D, prAL, gcLm}, // [7] NYIAKENG PUACHUE HMONG SIGN FOR PERSON..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER
+ {0x1E140, 0x1E149, prNU, gcNd}, // [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE
+ {0x1E14E, 0x1E14E, prAL, gcLo}, // NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ
+ {0x1E14F, 0x1E14F, prAL, gcSo}, // NYIAKENG PUACHUE HMONG CIRCLED CA
+ {0x1E290, 0x1E2AD, prAL, gcLo}, // [30] TOTO LETTER PA..TOTO LETTER A
+ {0x1E2AE, 0x1E2AE, prCM, gcMn}, // TOTO SIGN RISING TONE
+ {0x1E2C0, 0x1E2EB, prAL, gcLo}, // [44] WANCHO LETTER AA..WANCHO LETTER YIH
+ {0x1E2EC, 0x1E2EF, prCM, gcMn}, // [4] WANCHO TONE TUP..WANCHO TONE KOINI
+ {0x1E2F0, 0x1E2F9, prNU, gcNd}, // [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE
+ {0x1E2FF, 0x1E2FF, prPR, gcSc}, // WANCHO NGUN SIGN
+ {0x1E4D0, 0x1E4EA, prAL, gcLo}, // [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL
+ {0x1E4EB, 0x1E4EB, prAL, gcLm}, // NAG MUNDARI SIGN OJOD
+ {0x1E4EC, 0x1E4EF, prCM, gcMn}, // [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH
+ {0x1E4F0, 0x1E4F9, prNU, gcNd}, // [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE
+ {0x1E7E0, 0x1E7E6, prAL, gcLo}, // [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO
+ {0x1E7E8, 0x1E7EB, prAL, gcLo}, // [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE
+ {0x1E7ED, 0x1E7EE, prAL, gcLo}, // [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE
+ {0x1E7F0, 0x1E7FE, prAL, gcLo}, // [15] ETHIOPIC SYLLABLE GURAGE QWI..ETHIOPIC SYLLABLE GURAGE PWEE
+ {0x1E800, 0x1E8C4, prAL, gcLo}, // [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON
+ {0x1E8C7, 0x1E8CF, prAL, gcNo}, // [9] MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE
+ {0x1E8D0, 0x1E8D6, prCM, gcMn}, // [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS
+ {0x1E900, 0x1E943, prAL, gcLC}, // [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA
+ {0x1E944, 0x1E94A, prCM, gcMn}, // [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA
+ {0x1E94B, 0x1E94B, prAL, gcLm}, // ADLAM NASALIZATION MARK
+ {0x1E950, 0x1E959, prNU, gcNd}, // [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE
+ {0x1E95E, 0x1E95F, prOP, gcPo}, // [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK
+ {0x1EC71, 0x1ECAB, prAL, gcNo}, // [59] INDIC SIYAQ NUMBER ONE..INDIC SIYAQ NUMBER PREFIXED NINE
+ {0x1ECAC, 0x1ECAC, prPO, gcSo}, // INDIC SIYAQ PLACEHOLDER
+ {0x1ECAD, 0x1ECAF, prAL, gcNo}, // [3] INDIC SIYAQ FRACTION ONE QUARTER..INDIC SIYAQ FRACTION THREE QUARTERS
+ {0x1ECB0, 0x1ECB0, prPO, gcSc}, // INDIC SIYAQ RUPEE MARK
+ {0x1ECB1, 0x1ECB4, prAL, gcNo}, // [4] INDIC SIYAQ NUMBER ALTERNATE ONE..INDIC SIYAQ ALTERNATE LAKH MARK
+ {0x1ED01, 0x1ED2D, prAL, gcNo}, // [45] OTTOMAN SIYAQ NUMBER ONE..OTTOMAN SIYAQ NUMBER NINETY THOUSAND
+ {0x1ED2E, 0x1ED2E, prAL, gcSo}, // OTTOMAN SIYAQ MARRATAN
+ {0x1ED2F, 0x1ED3D, prAL, gcNo}, // [15] OTTOMAN SIYAQ ALTERNATE NUMBER TWO..OTTOMAN SIYAQ FRACTION ONE SIXTH
+ {0x1EE00, 0x1EE03, prAL, gcLo}, // [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL
+ {0x1EE05, 0x1EE1F, prAL, gcLo}, // [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF
+ {0x1EE21, 0x1EE22, prAL, gcLo}, // [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM
+ {0x1EE24, 0x1EE24, prAL, gcLo}, // ARABIC MATHEMATICAL INITIAL HEH
+ {0x1EE27, 0x1EE27, prAL, gcLo}, // ARABIC MATHEMATICAL INITIAL HAH
+ {0x1EE29, 0x1EE32, prAL, gcLo}, // [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF
+ {0x1EE34, 0x1EE37, prAL, gcLo}, // [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH
+ {0x1EE39, 0x1EE39, prAL, gcLo}, // ARABIC MATHEMATICAL INITIAL DAD
+ {0x1EE3B, 0x1EE3B, prAL, gcLo}, // ARABIC MATHEMATICAL INITIAL GHAIN
+ {0x1EE42, 0x1EE42, prAL, gcLo}, // ARABIC MATHEMATICAL TAILED JEEM
+ {0x1EE47, 0x1EE47, prAL, gcLo}, // ARABIC MATHEMATICAL TAILED HAH
+ {0x1EE49, 0x1EE49, prAL, gcLo}, // ARABIC MATHEMATICAL TAILED YEH
+ {0x1EE4B, 0x1EE4B, prAL, gcLo}, // ARABIC MATHEMATICAL TAILED LAM
+ {0x1EE4D, 0x1EE4F, prAL, gcLo}, // [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN
+ {0x1EE51, 0x1EE52, prAL, gcLo}, // [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF
+ {0x1EE54, 0x1EE54, prAL, gcLo}, // ARABIC MATHEMATICAL TAILED SHEEN
+ {0x1EE57, 0x1EE57, prAL, gcLo}, // ARABIC MATHEMATICAL TAILED KHAH
+ {0x1EE59, 0x1EE59, prAL, gcLo}, // ARABIC MATHEMATICAL TAILED DAD
+ {0x1EE5B, 0x1EE5B, prAL, gcLo}, // ARABIC MATHEMATICAL TAILED GHAIN
+ {0x1EE5D, 0x1EE5D, prAL, gcLo}, // ARABIC MATHEMATICAL TAILED DOTLESS NOON
+ {0x1EE5F, 0x1EE5F, prAL, gcLo}, // ARABIC MATHEMATICAL TAILED DOTLESS QAF
+ {0x1EE61, 0x1EE62, prAL, gcLo}, // [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM
+ {0x1EE64, 0x1EE64, prAL, gcLo}, // ARABIC MATHEMATICAL STRETCHED HEH
+ {0x1EE67, 0x1EE6A, prAL, gcLo}, // [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF
+ {0x1EE6C, 0x1EE72, prAL, gcLo}, // [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF
+ {0x1EE74, 0x1EE77, prAL, gcLo}, // [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH
+ {0x1EE79, 0x1EE7C, prAL, gcLo}, // [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH
+ {0x1EE7E, 0x1EE7E, prAL, gcLo}, // ARABIC MATHEMATICAL STRETCHED DOTLESS FEH
+ {0x1EE80, 0x1EE89, prAL, gcLo}, // [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH
+ {0x1EE8B, 0x1EE9B, prAL, gcLo}, // [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN
+ {0x1EEA1, 0x1EEA3, prAL, gcLo}, // [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL
+ {0x1EEA5, 0x1EEA9, prAL, gcLo}, // [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH
+ {0x1EEAB, 0x1EEBB, prAL, gcLo}, // [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN
+ {0x1EEF0, 0x1EEF1, prAL, gcSm}, // [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL
+ {0x1F000, 0x1F02B, prID, gcSo}, // [44] MAHJONG TILE EAST WIND..MAHJONG TILE BACK
+ {0x1F02C, 0x1F02F, prID, gcCn}, // [4] ..
+ {0x1F030, 0x1F093, prID, gcSo}, // [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06
+ {0x1F094, 0x1F09F, prID, gcCn}, // [12] ..
+ {0x1F0A0, 0x1F0AE, prID, gcSo}, // [15] PLAYING CARD BACK..PLAYING CARD KING OF SPADES
+ {0x1F0AF, 0x1F0B0, prID, gcCn}, // [2] ..
+ {0x1F0B1, 0x1F0BF, prID, gcSo}, // [15] PLAYING CARD ACE OF HEARTS..PLAYING CARD RED JOKER
+ {0x1F0C0, 0x1F0C0, prID, gcCn}, //
+ {0x1F0C1, 0x1F0CF, prID, gcSo}, // [15] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD BLACK JOKER
+ {0x1F0D0, 0x1F0D0, prID, gcCn}, //
+ {0x1F0D1, 0x1F0F5, prID, gcSo}, // [37] PLAYING CARD ACE OF CLUBS..PLAYING CARD TRUMP-21
+ {0x1F0F6, 0x1F0FF, prID, gcCn}, // [10] ..
+ {0x1F100, 0x1F10C, prAI, gcNo}, // [13] DIGIT ZERO FULL STOP..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO
+ {0x1F10D, 0x1F10F, prID, gcSo}, // [3] CIRCLED ZERO WITH SLASH..CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH
+ {0x1F110, 0x1F12D, prAI, gcSo}, // [30] PARENTHESIZED LATIN CAPITAL LETTER A..CIRCLED CD
+ {0x1F12E, 0x1F12F, prAL, gcSo}, // [2] CIRCLED WZ..COPYLEFT SYMBOL
+ {0x1F130, 0x1F169, prAI, gcSo}, // [58] SQUARED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z
+ {0x1F16A, 0x1F16C, prAL, gcSo}, // [3] RAISED MC SIGN..RAISED MR SIGN
+ {0x1F16D, 0x1F16F, prID, gcSo}, // [3] CIRCLED CC..CIRCLED HUMAN FIGURE
+ {0x1F170, 0x1F1AC, prAI, gcSo}, // [61] NEGATIVE SQUARED LATIN CAPITAL LETTER A..SQUARED VOD
+ {0x1F1AD, 0x1F1AD, prID, gcSo}, // MASK WORK SYMBOL
+ {0x1F1AE, 0x1F1E5, prID, gcCn}, // [56] ..
+ {0x1F1E6, 0x1F1FF, prRI, gcSo}, // [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z
+ {0x1F200, 0x1F202, prID, gcSo}, // [3] SQUARE HIRAGANA HOKA..SQUARED KATAKANA SA
+ {0x1F203, 0x1F20F, prID, gcCn}, // [13] ..
+ {0x1F210, 0x1F23B, prID, gcSo}, // [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D
+ {0x1F23C, 0x1F23F, prID, gcCn}, // [4] ..
+ {0x1F240, 0x1F248, prID, gcSo}, // [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557
+ {0x1F249, 0x1F24F, prID, gcCn}, // [7] ..
+ {0x1F250, 0x1F251, prID, gcSo}, // [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT
+ {0x1F252, 0x1F25F, prID, gcCn}, // [14] ..
+ {0x1F260, 0x1F265, prID, gcSo}, // [6] ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI
+ {0x1F266, 0x1F2FF, prID, gcCn}, // [154] ..
+ {0x1F300, 0x1F384, prID, gcSo}, // [133] CYCLONE..CHRISTMAS TREE
+ {0x1F385, 0x1F385, prEB, gcSo}, // FATHER CHRISTMAS
+ {0x1F386, 0x1F39B, prID, gcSo}, // [22] FIREWORKS..CONTROL KNOBS
+ {0x1F39C, 0x1F39D, prAL, gcSo}, // [2] BEAMED ASCENDING MUSICAL NOTES..BEAMED DESCENDING MUSICAL NOTES
+ {0x1F39E, 0x1F3B4, prID, gcSo}, // [23] FILM FRAMES..FLOWER PLAYING CARDS
+ {0x1F3B5, 0x1F3B6, prAL, gcSo}, // [2] MUSICAL NOTE..MULTIPLE MUSICAL NOTES
+ {0x1F3B7, 0x1F3BB, prID, gcSo}, // [5] SAXOPHONE..VIOLIN
+ {0x1F3BC, 0x1F3BC, prAL, gcSo}, // MUSICAL SCORE
+ {0x1F3BD, 0x1F3C1, prID, gcSo}, // [5] RUNNING SHIRT WITH SASH..CHEQUERED FLAG
+ {0x1F3C2, 0x1F3C4, prEB, gcSo}, // [3] SNOWBOARDER..SURFER
+ {0x1F3C5, 0x1F3C6, prID, gcSo}, // [2] SPORTS MEDAL..TROPHY
+ {0x1F3C7, 0x1F3C7, prEB, gcSo}, // HORSE RACING
+ {0x1F3C8, 0x1F3C9, prID, gcSo}, // [2] AMERICAN FOOTBALL..RUGBY FOOTBALL
+ {0x1F3CA, 0x1F3CC, prEB, gcSo}, // [3] SWIMMER..GOLFER
+ {0x1F3CD, 0x1F3FA, prID, gcSo}, // [46] RACING MOTORCYCLE..AMPHORA
+ {0x1F3FB, 0x1F3FF, prEM, gcSk}, // [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6
+ {0x1F400, 0x1F441, prID, gcSo}, // [66] RAT..EYE
+ {0x1F442, 0x1F443, prEB, gcSo}, // [2] EAR..NOSE
+ {0x1F444, 0x1F445, prID, gcSo}, // [2] MOUTH..TONGUE
+ {0x1F446, 0x1F450, prEB, gcSo}, // [11] WHITE UP POINTING BACKHAND INDEX..OPEN HANDS SIGN
+ {0x1F451, 0x1F465, prID, gcSo}, // [21] CROWN..BUSTS IN SILHOUETTE
+ {0x1F466, 0x1F478, prEB, gcSo}, // [19] BOY..PRINCESS
+ {0x1F479, 0x1F47B, prID, gcSo}, // [3] JAPANESE OGRE..GHOST
+ {0x1F47C, 0x1F47C, prEB, gcSo}, // BABY ANGEL
+ {0x1F47D, 0x1F480, prID, gcSo}, // [4] EXTRATERRESTRIAL ALIEN..SKULL
+ {0x1F481, 0x1F483, prEB, gcSo}, // [3] INFORMATION DESK PERSON..DANCER
+ {0x1F484, 0x1F484, prID, gcSo}, // LIPSTICK
+ {0x1F485, 0x1F487, prEB, gcSo}, // [3] NAIL POLISH..HAIRCUT
+ {0x1F488, 0x1F48E, prID, gcSo}, // [7] BARBER POLE..GEM STONE
+ {0x1F48F, 0x1F48F, prEB, gcSo}, // KISS
+ {0x1F490, 0x1F490, prID, gcSo}, // BOUQUET
+ {0x1F491, 0x1F491, prEB, gcSo}, // COUPLE WITH HEART
+ {0x1F492, 0x1F49F, prID, gcSo}, // [14] WEDDING..HEART DECORATION
+ {0x1F4A0, 0x1F4A0, prAL, gcSo}, // DIAMOND SHAPE WITH A DOT INSIDE
+ {0x1F4A1, 0x1F4A1, prID, gcSo}, // ELECTRIC LIGHT BULB
+ {0x1F4A2, 0x1F4A2, prAL, gcSo}, // ANGER SYMBOL
+ {0x1F4A3, 0x1F4A3, prID, gcSo}, // BOMB
+ {0x1F4A4, 0x1F4A4, prAL, gcSo}, // SLEEPING SYMBOL
+ {0x1F4A5, 0x1F4A9, prID, gcSo}, // [5] COLLISION SYMBOL..PILE OF POO
+ {0x1F4AA, 0x1F4AA, prEB, gcSo}, // FLEXED BICEPS
+ {0x1F4AB, 0x1F4AE, prID, gcSo}, // [4] DIZZY SYMBOL..WHITE FLOWER
+ {0x1F4AF, 0x1F4AF, prAL, gcSo}, // HUNDRED POINTS SYMBOL
+ {0x1F4B0, 0x1F4B0, prID, gcSo}, // MONEY BAG
+ {0x1F4B1, 0x1F4B2, prAL, gcSo}, // [2] CURRENCY EXCHANGE..HEAVY DOLLAR SIGN
+ {0x1F4B3, 0x1F4FF, prID, gcSo}, // [77] CREDIT CARD..PRAYER BEADS
+ {0x1F500, 0x1F506, prAL, gcSo}, // [7] TWISTED RIGHTWARDS ARROWS..HIGH BRIGHTNESS SYMBOL
+ {0x1F507, 0x1F516, prID, gcSo}, // [16] SPEAKER WITH CANCELLATION STROKE..BOOKMARK
+ {0x1F517, 0x1F524, prAL, gcSo}, // [14] LINK SYMBOL..INPUT SYMBOL FOR LATIN LETTERS
+ {0x1F525, 0x1F531, prID, gcSo}, // [13] FIRE..TRIDENT EMBLEM
+ {0x1F532, 0x1F549, prAL, gcSo}, // [24] BLACK SQUARE BUTTON..OM SYMBOL
+ {0x1F54A, 0x1F573, prID, gcSo}, // [42] DOVE OF PEACE..HOLE
+ {0x1F574, 0x1F575, prEB, gcSo}, // [2] MAN IN BUSINESS SUIT LEVITATING..SLEUTH OR SPY
+ {0x1F576, 0x1F579, prID, gcSo}, // [4] DARK SUNGLASSES..JOYSTICK
+ {0x1F57A, 0x1F57A, prEB, gcSo}, // MAN DANCING
+ {0x1F57B, 0x1F58F, prID, gcSo}, // [21] LEFT HAND TELEPHONE RECEIVER..TURNED OK HAND SIGN
+ {0x1F590, 0x1F590, prEB, gcSo}, // RAISED HAND WITH FINGERS SPLAYED
+ {0x1F591, 0x1F594, prID, gcSo}, // [4] REVERSED RAISED HAND WITH FINGERS SPLAYED..REVERSED VICTORY HAND
+ {0x1F595, 0x1F596, prEB, gcSo}, // [2] REVERSED HAND WITH MIDDLE FINGER EXTENDED..RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS
+ {0x1F597, 0x1F5D3, prID, gcSo}, // [61] WHITE DOWN POINTING LEFT HAND INDEX..SPIRAL CALENDAR PAD
+ {0x1F5D4, 0x1F5DB, prAL, gcSo}, // [8] DESKTOP WINDOW..DECREASE FONT SIZE SYMBOL
+ {0x1F5DC, 0x1F5F3, prID, gcSo}, // [24] COMPRESSION..BALLOT BOX WITH BALLOT
+ {0x1F5F4, 0x1F5F9, prAL, gcSo}, // [6] BALLOT SCRIPT X..BALLOT BOX WITH BOLD CHECK
+ {0x1F5FA, 0x1F5FF, prID, gcSo}, // [6] WORLD MAP..MOYAI
+ {0x1F600, 0x1F644, prID, gcSo}, // [69] GRINNING FACE..FACE WITH ROLLING EYES
+ {0x1F645, 0x1F647, prEB, gcSo}, // [3] FACE WITH NO GOOD GESTURE..PERSON BOWING DEEPLY
+ {0x1F648, 0x1F64A, prID, gcSo}, // [3] SEE-NO-EVIL MONKEY..SPEAK-NO-EVIL MONKEY
+ {0x1F64B, 0x1F64F, prEB, gcSo}, // [5] HAPPY PERSON RAISING ONE HAND..PERSON WITH FOLDED HANDS
+ {0x1F650, 0x1F675, prAL, gcSo}, // [38] NORTH WEST POINTING LEAF..SWASH AMPERSAND ORNAMENT
+ {0x1F676, 0x1F678, prQU, gcSo}, // [3] SANS-SERIF HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT..SANS-SERIF HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT
+ {0x1F679, 0x1F67B, prNS, gcSo}, // [3] HEAVY INTERROBANG ORNAMENT..HEAVY SANS-SERIF INTERROBANG ORNAMENT
+ {0x1F67C, 0x1F67F, prAL, gcSo}, // [4] VERY HEAVY SOLIDUS..REVERSE CHECKER BOARD
+ {0x1F680, 0x1F6A2, prID, gcSo}, // [35] ROCKET..SHIP
+ {0x1F6A3, 0x1F6A3, prEB, gcSo}, // ROWBOAT
+ {0x1F6A4, 0x1F6B3, prID, gcSo}, // [16] SPEEDBOAT..NO BICYCLES
+ {0x1F6B4, 0x1F6B6, prEB, gcSo}, // [3] BICYCLIST..PEDESTRIAN
+ {0x1F6B7, 0x1F6BF, prID, gcSo}, // [9] NO PEDESTRIANS..SHOWER
+ {0x1F6C0, 0x1F6C0, prEB, gcSo}, // BATH
+ {0x1F6C1, 0x1F6CB, prID, gcSo}, // [11] BATHTUB..COUCH AND LAMP
+ {0x1F6CC, 0x1F6CC, prEB, gcSo}, // SLEEPING ACCOMMODATION
+ {0x1F6CD, 0x1F6D7, prID, gcSo}, // [11] SHOPPING BAGS..ELEVATOR
+ {0x1F6D8, 0x1F6DB, prID, gcCn}, // [4] ..
+ {0x1F6DC, 0x1F6EC, prID, gcSo}, // [17] WIRELESS..AIRPLANE ARRIVING
+ {0x1F6ED, 0x1F6EF, prID, gcCn}, // [3] ..
+ {0x1F6F0, 0x1F6FC, prID, gcSo}, // [13] SATELLITE..ROLLER SKATE
+ {0x1F6FD, 0x1F6FF, prID, gcCn}, // [3] ..
+ {0x1F700, 0x1F773, prAL, gcSo}, // [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE
+ {0x1F774, 0x1F776, prID, gcSo}, // [3] LOT OF FORTUNE..LUNAR ECLIPSE
+ {0x1F777, 0x1F77A, prID, gcCn}, // [4] ..
+ {0x1F77B, 0x1F77F, prID, gcSo}, // [5] HAUMEA..ORCUS
+ {0x1F780, 0x1F7D4, prAL, gcSo}, // [85] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..HEAVY TWELVE POINTED PINWHEEL STAR
+ {0x1F7D5, 0x1F7D9, prID, gcSo}, // [5] CIRCLED TRIANGLE..NINE POINTED WHITE STAR
+ {0x1F7DA, 0x1F7DF, prID, gcCn}, // [6] ..
+ {0x1F7E0, 0x1F7EB, prID, gcSo}, // [12] LARGE ORANGE CIRCLE..LARGE BROWN SQUARE
+ {0x1F7EC, 0x1F7EF, prID, gcCn}, // [4] ..
+ {0x1F7F0, 0x1F7F0, prID, gcSo}, // HEAVY EQUALS SIGN
+ {0x1F7F1, 0x1F7FF, prID, gcCn}, // [15] ..
+ {0x1F800, 0x1F80B, prAL, gcSo}, // [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD
+ {0x1F80C, 0x1F80F, prID, gcCn}, // [4] ..
+ {0x1F810, 0x1F847, prAL, gcSo}, // [56] LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD..DOWNWARDS HEAVY ARROW
+ {0x1F848, 0x1F84F, prID, gcCn}, // [8] ..
+ {0x1F850, 0x1F859, prAL, gcSo}, // [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW
+ {0x1F85A, 0x1F85F, prID, gcCn}, // [6] ..
+ {0x1F860, 0x1F887, prAL, gcSo}, // [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW
+ {0x1F888, 0x1F88F, prID, gcCn}, // [8] ..
+ {0x1F890, 0x1F8AD, prAL, gcSo}, // [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS
+ {0x1F8AE, 0x1F8AF, prID, gcCn}, // [2] ..
+ {0x1F8B0, 0x1F8B1, prID, gcSo}, // [2] ARROW POINTING UPWARDS THEN NORTH WEST..ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST
+ {0x1F8B2, 0x1F8FF, prID, gcCn}, // [78] ..
+ {0x1F900, 0x1F90B, prAL, gcSo}, // [12] CIRCLED CROSS FORMEE WITH FOUR DOTS..DOWNWARD FACING NOTCHED HOOK WITH DOT
+ {0x1F90C, 0x1F90C, prEB, gcSo}, // PINCHED FINGERS
+ {0x1F90D, 0x1F90E, prID, gcSo}, // [2] WHITE HEART..BROWN HEART
+ {0x1F90F, 0x1F90F, prEB, gcSo}, // PINCHING HAND
+ {0x1F910, 0x1F917, prID, gcSo}, // [8] ZIPPER-MOUTH FACE..HUGGING FACE
+ {0x1F918, 0x1F91F, prEB, gcSo}, // [8] SIGN OF THE HORNS..I LOVE YOU HAND SIGN
+ {0x1F920, 0x1F925, prID, gcSo}, // [6] FACE WITH COWBOY HAT..LYING FACE
+ {0x1F926, 0x1F926, prEB, gcSo}, // FACE PALM
+ {0x1F927, 0x1F92F, prID, gcSo}, // [9] SNEEZING FACE..SHOCKED FACE WITH EXPLODING HEAD
+ {0x1F930, 0x1F939, prEB, gcSo}, // [10] PREGNANT WOMAN..JUGGLING
+ {0x1F93A, 0x1F93B, prID, gcSo}, // [2] FENCER..MODERN PENTATHLON
+ {0x1F93C, 0x1F93E, prEB, gcSo}, // [3] WRESTLERS..HANDBALL
+ {0x1F93F, 0x1F976, prID, gcSo}, // [56] DIVING MASK..FREEZING FACE
+ {0x1F977, 0x1F977, prEB, gcSo}, // NINJA
+ {0x1F978, 0x1F9B4, prID, gcSo}, // [61] DISGUISED FACE..BONE
+ {0x1F9B5, 0x1F9B6, prEB, gcSo}, // [2] LEG..FOOT
+ {0x1F9B7, 0x1F9B7, prID, gcSo}, // TOOTH
+ {0x1F9B8, 0x1F9B9, prEB, gcSo}, // [2] SUPERHERO..SUPERVILLAIN
+ {0x1F9BA, 0x1F9BA, prID, gcSo}, // SAFETY VEST
+ {0x1F9BB, 0x1F9BB, prEB, gcSo}, // EAR WITH HEARING AID
+ {0x1F9BC, 0x1F9CC, prID, gcSo}, // [17] MOTORIZED WHEELCHAIR..TROLL
+ {0x1F9CD, 0x1F9CF, prEB, gcSo}, // [3] STANDING PERSON..DEAF PERSON
+ {0x1F9D0, 0x1F9D0, prID, gcSo}, // FACE WITH MONOCLE
+ {0x1F9D1, 0x1F9DD, prEB, gcSo}, // [13] ADULT..ELF
+ {0x1F9DE, 0x1F9FF, prID, gcSo}, // [34] GENIE..NAZAR AMULET
+ {0x1FA00, 0x1FA53, prAL, gcSo}, // [84] NEUTRAL CHESS KING..BLACK CHESS KNIGHT-BISHOP
+ {0x1FA54, 0x1FA5F, prID, gcCn}, // [12] ..
+ {0x1FA60, 0x1FA6D, prID, gcSo}, // [14] XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER
+ {0x1FA6E, 0x1FA6F, prID, gcCn}, // [2] ..
+ {0x1FA70, 0x1FA7C, prID, gcSo}, // [13] BALLET SHOES..CRUTCH
+ {0x1FA7D, 0x1FA7F, prID, gcCn}, // [3] ..
+ {0x1FA80, 0x1FA88, prID, gcSo}, // [9] YO-YO..FLUTE
+ {0x1FA89, 0x1FA8F, prID, gcCn}, // [7] ..
+ {0x1FA90, 0x1FABD, prID, gcSo}, // [46] RINGED PLANET..WING
+ {0x1FABE, 0x1FABE, prID, gcCn}, //
+ {0x1FABF, 0x1FAC2, prID, gcSo}, // [4] GOOSE..PEOPLE HUGGING
+ {0x1FAC3, 0x1FAC5, prEB, gcSo}, // [3] PREGNANT MAN..PERSON WITH CROWN
+ {0x1FAC6, 0x1FACD, prID, gcCn}, // [8] ..
+ {0x1FACE, 0x1FADB, prID, gcSo}, // [14] MOOSE..PEA POD
+ {0x1FADC, 0x1FADF, prID, gcCn}, // [4] ..
+ {0x1FAE0, 0x1FAE8, prID, gcSo}, // [9] MELTING FACE..SHAKING FACE
+ {0x1FAE9, 0x1FAEF, prID, gcCn}, // [7] ..
+ {0x1FAF0, 0x1FAF8, prEB, gcSo}, // [9] HAND WITH INDEX FINGER AND THUMB CROSSED..RIGHTWARDS PUSHING HAND
+ {0x1FAF9, 0x1FAFF, prID, gcCn}, // [7] ..
+ {0x1FB00, 0x1FB92, prAL, gcSo}, // [147] BLOCK SEXTANT-1..UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK
+ {0x1FB94, 0x1FBCA, prAL, gcSo}, // [55] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..WHITE UP-POINTING CHEVRON
+ {0x1FBF0, 0x1FBF9, prNU, gcNd}, // [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE
+ {0x1FC00, 0x1FFFD, prID, gcCn}, // [1022] ..
+ {0x20000, 0x2A6DF, prID, gcLo}, // [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF
+ {0x2A6E0, 0x2A6FF, prID, gcCn}, // [32] ..
+ {0x2A700, 0x2B739, prID, gcLo}, // [4154] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B739
+ {0x2B73A, 0x2B73F, prID, gcCn}, // [6] ..
+ {0x2B740, 0x2B81D, prID, gcLo}, // [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D
+ {0x2B81E, 0x2B81F, prID, gcCn}, // [2] ..
+ {0x2B820, 0x2CEA1, prID, gcLo}, // [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1
+ {0x2CEA2, 0x2CEAF, prID, gcCn}, // [14] ..
+ {0x2CEB0, 0x2EBE0, prID, gcLo}, // [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0
+ {0x2EBE1, 0x2F7FF, prID, gcCn}, // [3103] ..
+ {0x2F800, 0x2FA1D, prID, gcLo}, // [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
+ {0x2FA1E, 0x2FA1F, prID, gcCn}, // [2] ..
+ {0x2FA20, 0x2FFFD, prID, gcCn}, // [1502] ..
+ {0x30000, 0x3134A, prID, gcLo}, // [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A
+ {0x3134B, 0x3134F, prID, gcCn}, // [5] ..
+ {0x31350, 0x323AF, prID, gcLo}, // [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF
+ {0x323B0, 0x3FFFD, prID, gcCn}, // [56398]