1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-10-26 16:31:18 +03:00

Bump gocui

The main change here is https://github.com/jesseduffield/gocui/pull/85, which
avoids breaking lines after footnote symbols in commit messages (e.g. [1]).

[1]: https://www.example.com/this-is-a-really-long-url-that-lazy-git-automatically-wraps-and-is-an-issue
This commit is contained in:
Stefan Haller
2025-10-02 17:25:46 +02:00
parent cb2b5c3738
commit ef92e30315
119 changed files with 3883 additions and 17382 deletions

18
go.mod
View File

@@ -9,20 +9,20 @@ require (
github.com/aybabtme/humanlog v0.4.1 github.com/aybabtme/humanlog v0.4.1
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
github.com/creack/pty v1.1.11 github.com/creack/pty v1.1.11
github.com/gdamore/tcell/v2 v2.8.1 github.com/gdamore/tcell/v2 v2.9.0
github.com/go-errors/errors v1.5.1 github.com/go-errors/errors v1.5.1
github.com/gookit/color v1.4.2 github.com/gookit/color v1.4.2
github.com/integrii/flaggy v1.4.0 github.com/integrii/flaggy v1.4.0
github.com/jesseduffield/generics v0.0.0-20250517122708-b0b4a53a6f5c github.com/jesseduffield/generics v0.0.0-20250517122708-b0b4a53a6f5c
github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd
github.com/jesseduffield/gocui v0.3.1-0.20250711082438-4aa4fd0b4d22 github.com/jesseduffield/gocui v0.3.1-0.20251002151855-67e0e55ff42a
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
github.com/karimkhaleel/jsonschema v0.0.0-20231001195015-d933f0d94ea3 github.com/karimkhaleel/jsonschema v0.0.0-20231001195015-d933f0d94ea3
github.com/kyokomi/emoji/v2 v2.2.8 github.com/kyokomi/emoji/v2 v2.2.8
github.com/lucasb-eyer/go-colorful v1.2.0 github.com/lucasb-eyer/go-colorful v1.3.0
github.com/mattn/go-runewidth v0.0.16 github.com/mattn/go-runewidth v0.0.19
github.com/mgutz/str v1.2.0 github.com/mgutz/str v1.2.0
github.com/mitchellh/go-ps v1.0.0 github.com/mitchellh/go-ps v1.0.0
github.com/sahilm/fuzzy v0.1.0 github.com/sahilm/fuzzy v0.1.0
@@ -36,8 +36,8 @@ require (
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.10.0
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
golang.org/x/sync v0.16.0 golang.org/x/sync v0.17.0
golang.org/x/sys v0.34.0 golang.org/x/sys v0.36.0
gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0 gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
@@ -47,6 +47,7 @@ require (
github.com/ProtonMail/go-crypto v1.1.6 // indirect github.com/ProtonMail/go-crypto v1.1.6 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect github.com/buger/jsonparser v1.1.1 // indirect
github.com/clipperhouse/uax29/v2 v2.2.0 // indirect
github.com/cloudflare/circl v1.6.1 // indirect github.com/cloudflare/circl v1.6.1 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
@@ -71,15 +72,14 @@ require (
github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe // indirect github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe // indirect
github.com/pjbgf/sha1cd v0.3.2 // indirect github.com/pjbgf/sha1cd v0.3.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect github.com/skeema/knownhosts v1.3.1 // indirect
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect
golang.org/x/crypto v0.37.0 // indirect golang.org/x/crypto v0.37.0 // indirect
golang.org/x/net v0.39.0 // indirect golang.org/x/net v0.39.0 // indirect
golang.org/x/term v0.33.0 // indirect golang.org/x/term v0.35.0 // indirect
golang.org/x/text v0.27.0 // indirect golang.org/x/text v0.29.0 // indirect
gopkg.in/fsnotify.v1 v1.4.7 // indirect gopkg.in/fsnotify.v1 v1.4.7 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect

33
go.sum
View File

@@ -65,6 +65,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/clipperhouse/uax29/v2 v2.2.0 h1:ChwIKnQN3kcZteTXMgb1wztSgaU+ZemkgWdohwgs8tY=
github.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do= github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do=
@@ -96,8 +98,8 @@ github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL
github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw= github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw=
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo= github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
github.com/gdamore/tcell/v2 v2.8.0/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw= github.com/gdamore/tcell/v2 v2.8.0/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw=
github.com/gdamore/tcell/v2 v2.8.1 h1:KPNxyqclpWpWQlPLx6Xui1pMk8S+7+R37h3g07997NU= github.com/gdamore/tcell/v2 v2.9.0 h1:N6t+eqK7/xwtRPwxzs1PXeRWnm0H9l02CrgJ7DLn1ys=
github.com/gdamore/tcell/v2 v2.8.1/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw= github.com/gdamore/tcell/v2 v2.9.0/go.mod h1:8/ZoqM9rxzYphT9tH/9LnunhV9oPBqwS8WHGYm5nrmo=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
@@ -194,8 +196,8 @@ github.com/jesseduffield/generics v0.0.0-20250517122708-b0b4a53a6f5c h1:tC2Paiis
github.com/jesseduffield/generics v0.0.0-20250517122708-b0b4a53a6f5c/go.mod h1:F2fEBk0ddf6ixrBrJjY7phfQ3hL9rXG0uSjvwYe50bE= github.com/jesseduffield/generics v0.0.0-20250517122708-b0b4a53a6f5c/go.mod h1:F2fEBk0ddf6ixrBrJjY7phfQ3hL9rXG0uSjvwYe50bE=
github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd h1:ViKj6qth8FgcIWizn9KiACWwPemWSymx62OPN0tHT+Q= github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd h1:ViKj6qth8FgcIWizn9KiACWwPemWSymx62OPN0tHT+Q=
github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd/go.mod h1:lRhCiBr6XjQrvcQVa+UYsy/99d3wMXn/a0nSQlhnhlA= github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd/go.mod h1:lRhCiBr6XjQrvcQVa+UYsy/99d3wMXn/a0nSQlhnhlA=
github.com/jesseduffield/gocui v0.3.1-0.20250711082438-4aa4fd0b4d22 h1:vhMwEsLlMtuKKo9/z3Qcggycgad8oV7+siwOZEnJDOs= github.com/jesseduffield/gocui v0.3.1-0.20251002151855-67e0e55ff42a h1:z3NQvFXAWGT4B/MwQBZc+1ej8WJ/Nv35xngQRvwzPuI=
github.com/jesseduffield/gocui v0.3.1-0.20250711082438-4aa4fd0b4d22/go.mod h1:sLIyZ2J42R6idGdtemZzsiR3xY5EF0KsvYEGh3dQv3s= github.com/jesseduffield/gocui v0.3.1-0.20251002151855-67e0e55ff42a/go.mod h1:sLIyZ2J42R6idGdtemZzsiR3xY5EF0KsvYEGh3dQv3s=
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY= github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5/go.mod h1:qxN4mHOAyeIDLP7IK7defgPClM/z1Kze8VVQiaEjzsQ= github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5/go.mod h1:qxN4mHOAyeIDLP7IK7defgPClM/z1Kze8VVQiaEjzsQ=
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e h1:uw/oo+kg7t/oeMs6sqlAwr85ND/9cpO3up3VxphxY0U= github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e h1:uw/oo+kg7t/oeMs6sqlAwr85ND/9cpO3up3VxphxY0U=
@@ -224,8 +226,9 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/kyokomi/emoji/v2 v2.2.8 h1:jcofPxjHWEkJtkIbcLHvZhxKgCPl6C7MyjTrD4KDqUE= github.com/kyokomi/emoji/v2 v2.2.8 h1:jcofPxjHWEkJtkIbcLHvZhxKgCPl6C7MyjTrD4KDqUE=
github.com/kyokomi/emoji/v2 v2.2.8/go.mod h1:JUcn42DTdsXJo1SWanHh4HKDEyPaR5CqkmoirZZP9qE= github.com/kyokomi/emoji/v2 v2.2.8/go.mod h1:JUcn42DTdsXJo1SWanHh4HKDEyPaR5CqkmoirZZP9qE=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -237,8 +240,9 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
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-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/mgutz/str v1.2.0 h1:4IzWSdIz9qPQWLfKZ0rJcV0jcUDpxvP4JVZ4GXQyvSw= github.com/mgutz/str v1.2.0 h1:4IzWSdIz9qPQWLfKZ0rJcV0jcUDpxvP4JVZ4GXQyvSw=
github.com/mgutz/str v1.2.0/go.mod h1:w1v0ofgLaJdoD0HpQ3fycxKD1WtxpjSo151pK/31q6w= github.com/mgutz/str v1.2.0/go.mod h1:w1v0ofgLaJdoD0HpQ3fycxKD1WtxpjSo151pK/31q6w=
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
@@ -260,7 +264,6 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
@@ -434,8 +437,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20170407050850-f3918c30c5c2/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20170407050850-f3918c30c5c2/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-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -488,8 +491,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -499,8 +502,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -515,8 +518,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2019 Oliver Kuederle Copyright (c) 2020 Matt Sherman
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -0,0 +1,82 @@
An implementation of grapheme cluster boundaries from [Unicode text segmentation](https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) (UAX 29), for Unicode version 15.0.0.
## Quick start
```
go get "github.com/clipperhouse/uax29/v2/graphemes"
```
```go
import "github.com/clipperhouse/uax29/v2/graphemes"
text := "Hello, 世界. Nice dog! 👍🐶"
tokens := graphemes.FromString(text)
for tokens.Next() { // Next() returns true until end of data
fmt.Println(tokens.Value()) // Do something with the current grapheme
}
```
[![Documentation](https://pkg.go.dev/badge/github.com/clipperhouse/uax29/v2/graphemes.svg)](https://pkg.go.dev/github.com/clipperhouse/uax29/v2/graphemes)
_A grapheme is a “single visible character”, which might be a simple as a single letter, or a complex emoji that consists of several Unicode code points._
## Conformance
We use the Unicode [test suite](https://unicode.org/reports/tr41/tr41-26.html#Tests29). Status:
![Go](https://github.com/clipperhouse/uax29/actions/workflows/gotest.yml/badge.svg)
## APIs
### If you have a `string`
```go
text := "Hello, 世界. Nice dog! 👍🐶"
tokens := graphemes.FromString(text)
for tokens.Next() { // Next() returns true until end of data
fmt.Println(tokens.Value()) // Do something with the current grapheme
}
```
### If you have an `io.Reader`
`FromReader` embeds a [`bufio.Scanner`](https://pkg.go.dev/bufio#Scanner), so just use those methods.
```go
r := getYourReader() // from a file or network maybe
tokens := graphemes.FromReader(r)
for tokens.Scan() { // Scan() returns true until error or EOF
fmt.Println(tokens.Text()) // Do something with the current grapheme
}
if tokens.Err() != nil { // Check the error
log.Fatal(tokens.Err())
}
```
### If you have a `[]byte`
```go
b := []byte("Hello, 世界. Nice dog! 👍🐶")
tokens := graphemes.FromBytes(b)
for tokens.Next() { // Next() returns true until end of data
fmt.Println(tokens.Value()) // Do something with the current grapheme
}
```
### Performance
On a Mac M2 laptop, we see around 200MB/s, or around 100 million graphemes per second. You should see ~constant memory, and no allocations.
### Invalid inputs
Invalid UTF-8 input is considered undefined behavior. We test to ensure that bad inputs will not cause pathological outcomes, such as a panic or infinite loop. Callers should expect “garbage-in, garbage-out”.
Your pipeline should probably include a call to [`utf8.Valid()`](https://pkg.go.dev/unicode/utf8#Valid).

View File

@@ -0,0 +1,28 @@
package graphemes
import "github.com/clipperhouse/uax29/v2/internal/iterators"
type Iterator[T iterators.Stringish] struct {
*iterators.Iterator[T]
}
var (
splitFuncString = splitFunc[string]
splitFuncBytes = splitFunc[[]byte]
)
// FromString returns an iterator for the grapheme clusters in the input string.
// Iterate while Next() is true, and access the grapheme via Value().
func FromString(s string) Iterator[string] {
return Iterator[string]{
iterators.New(splitFuncString, s),
}
}
// FromBytes returns an iterator for the grapheme clusters in the input bytes.
// Iterate while Next() is true, and access the grapheme via Value().
func FromBytes(b []byte) Iterator[[]byte] {
return Iterator[[]byte]{
iterators.New(splitFuncBytes, b),
}
}

View File

@@ -0,0 +1,25 @@
// Package graphemes implements Unicode grapheme cluster boundaries: https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries
package graphemes
import (
"bufio"
"io"
)
type Scanner struct {
*bufio.Scanner
}
// FromReader returns a Scanner, to split graphemes per
// https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries.
//
// It embeds a [bufio.Scanner], so you can use its methods.
//
// Iterate through graphemes by calling Scan() until false, then check Err().
func FromReader(r io.Reader) *Scanner {
sc := bufio.NewScanner(r)
sc.Split(SplitFunc)
return &Scanner{
Scanner: sc,
}
}

View File

@@ -0,0 +1,174 @@
package graphemes
import (
"bufio"
"github.com/clipperhouse/uax29/v2/internal/iterators"
)
// is determines if lookup intersects propert(ies)
func (lookup property) is(properties property) bool {
return (lookup & properties) != 0
}
const _Ignore = _Extend
// SplitFunc is a bufio.SplitFunc implementation of Unicode grapheme cluster segmentation, for use with bufio.Scanner.
//
// See https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries.
var SplitFunc bufio.SplitFunc = splitFunc[[]byte]
func splitFunc[T iterators.Stringish](data T, atEOF bool) (advance int, token T, err error) {
var empty T
if len(data) == 0 {
return 0, empty, nil
}
// These vars are stateful across loop iterations
var pos int
var lastExIgnore property = 0 // "last excluding ignored categories"
var lastLastExIgnore property = 0 // "last one before that"
var regionalIndicatorCount int
// Rules are usually of the form Cat1 × Cat2; "current" refers to the first property
// to the right of the ×, from which we look back or forward
current, w := lookup(data[pos:])
if w == 0 {
if !atEOF {
// Rune extends past current data, request more
return 0, empty, nil
}
pos = len(data)
return pos, data[:pos], nil
}
// https://unicode.org/reports/tr29/#GB1
// Start of text always advances
pos += w
for {
eot := pos == len(data) // "end of text"
if eot {
if !atEOF {
// Token extends past current data, request more
return 0, empty, nil
}
// https://unicode.org/reports/tr29/#GB2
break
}
/*
We've switched the evaluation order of GB1↓ and GB2↑. It's ok:
because we've checked for len(data) at the top of this function,
sot and eot are mutually exclusive, order doesn't matter.
*/
// Rules are usually of the form Cat1 × Cat2; "current" refers to the first property
// to the right of the ×, from which we look back or forward
// Remember previous properties to avoid lookups/lookbacks
last := current
if !last.is(_Ignore) {
lastLastExIgnore = lastExIgnore
lastExIgnore = last
}
current, w = lookup(data[pos:])
if w == 0 {
if atEOF {
// Just return the bytes, we can't do anything with them
pos = len(data)
break
}
// Rune extends past current data, request more
return 0, empty, nil
}
// Optimization: no rule can possibly apply
if current|last == 0 { // i.e. both are zero
break
}
// https://unicode.org/reports/tr29/#GB3
if current.is(_LF) && last.is(_CR) {
pos += w
continue
}
// https://unicode.org/reports/tr29/#GB4
// https://unicode.org/reports/tr29/#GB5
if (current | last).is(_Control | _CR | _LF) {
break
}
// https://unicode.org/reports/tr29/#GB6
if current.is(_L|_V|_LV|_LVT) && last.is(_L) {
pos += w
continue
}
// https://unicode.org/reports/tr29/#GB7
if current.is(_V|_T) && last.is(_LV|_V) {
pos += w
continue
}
// https://unicode.org/reports/tr29/#GB8
if current.is(_T) && last.is(_LVT|_T) {
pos += w
continue
}
// https://unicode.org/reports/tr29/#GB9
if current.is(_Extend | _ZWJ) {
pos += w
continue
}
// https://unicode.org/reports/tr29/#GB9a
if current.is(_SpacingMark) {
pos += w
continue
}
// https://unicode.org/reports/tr29/#GB9b
if last.is(_Prepend) {
pos += w
continue
}
// https://unicode.org/reports/tr29/#GB9c
// TODO(clipperhouse):
// It appears to be added in Unicode 15.1.0:
// https://unicode.org/versions/Unicode15.1.0/#Migration
// This package currently supports Unicode 15.0.0, so
// out of scope for now
// https://unicode.org/reports/tr29/#GB11
if current.is(_ExtendedPictographic) && last.is(_ZWJ) && lastLastExIgnore.is(_ExtendedPictographic) {
pos += w
continue
}
// https://unicode.org/reports/tr29/#GB12
// https://unicode.org/reports/tr29/#GB13
if (current & last).is(_RegionalIndicator) {
regionalIndicatorCount++
odd := regionalIndicatorCount%2 == 1
if odd {
pos += w
continue
}
}
// If we fall through all the above rules, it's a grapheme cluster break
break
}
// Return token
return pos, data[:pos], nil
}

1409
vendor/github.com/clipperhouse/uax29/v2/graphemes/trie.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,85 @@
package iterators
type Stringish interface {
[]byte | string
}
type SplitFunc[T Stringish] func(T, bool) (int, T, error)
// Iterator is a generic iterator for words that are either []byte or string.
// Iterate while Next() is true, and access the word via Value().
type Iterator[T Stringish] struct {
split SplitFunc[T]
data T
start int
pos int
}
// New creates a new Iterator for the given data and SplitFunc.
func New[T Stringish](split SplitFunc[T], data T) *Iterator[T] {
return &Iterator[T]{
split: split,
data: data,
}
}
// SetText sets the text for the iterator to operate on, and resets all state.
func (iter *Iterator[T]) SetText(data T) {
iter.data = data
iter.start = 0
iter.pos = 0
}
// Split sets the SplitFunc for the Iterator.
func (iter *Iterator[T]) Split(split SplitFunc[T]) {
iter.split = split
}
// Next advances the iterator to the next token. It returns false when there
// are no remaining tokens or an error occurred.
func (iter *Iterator[T]) Next() bool {
if iter.pos == len(iter.data) {
return false
}
if iter.pos > len(iter.data) {
panic("SplitFunc advanced beyond the end of the data")
}
iter.start = iter.pos
advance, _, err := iter.split(iter.data[iter.pos:], true)
if err != nil {
panic(err)
}
if advance <= 0 {
panic("SplitFunc returned a zero or negative advance")
}
iter.pos += advance
if iter.pos > len(iter.data) {
panic("SplitFunc advanced beyond the end of the data")
}
return true
}
// Value returns the current token.
func (iter *Iterator[T]) Value() T {
return iter.data[iter.start:iter.pos]
}
// Start returns the byte position of the current token in the original data.
func (iter *Iterator[T]) Start() int {
return iter.start
}
// End returns the byte position after the current token in the original data.
func (iter *Iterator[T]) End() int {
return iter.pos
}
// Reset resets the iterator to the beginning of the data.
func (iter *Iterator[T]) Reset() {
iter.start = 0
iter.pos = 0
}

View File

@@ -1,13 +0,0 @@
version: 1.0.{build}
clone_folder: c:\gopath\src\github.com\gdamore\tcell
environment:
GOPATH: c:\gopath
build_script:
- go version
- go env
- SET PATH=%LOCALAPPDATA%\atom\bin;%GOPATH%\bin;%PATH%
- go get -t ./...
- go build
- go install ./...
test_script:
- go test ./...

View File

@@ -1,18 +0,0 @@
language: go
go:
- 1.15.x
- master
arch:
- amd64
- ppc64le
before_install:
- go get -t -v ./...
script:
- go test -race -coverprofile=coverage.txt -covermode=atomic
after_success:
- bash <(curl -s https://codecov.io/bash)

View File

@@ -7,12 +7,14 @@ It was inspired by _termbox_, but includes many additional improvements.
[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua) [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua)
[![Linux](https://img.shields.io/github/actions/workflow/status/gdamore/tcell/linux.yml?branch=main&logoColor=grey&logo=linux&label=)](https://github.com/gdamore/tcell/actions/workflows/linux.yml) [![Linux](https://img.shields.io/github/actions/workflow/status/gdamore/tcell/linux.yml?branch=main&logoColor=grey&logo=linux&label=)](https://github.com/gdamore/tcell/actions/workflows/linux.yml)
[![Windows](https://img.shields.io/github/actions/workflow/status/gdamore/tcell/windows.yml?branch=main&logoColor=grey&logo=windows&label=)](https://github.com/gdamore/tcell/actions/workflows/windows.yml) [![Windows](https://img.shields.io/github/actions/workflow/status/gdamore/tcell/windows.yml?branch=main&logoColor=grey&label=Windows)](https://github.com/gdamore/tcell/actions/workflows/windows.yml)
[![Web Assembly](https://img.shields.io/github/actions/workflow/status/gdamore/tcell/webasm.yml?branch=main&logoColor=grey&logo=webassembly&label=)](https://github.com/gdamore/tcell/actions/workflows/webasm.yml)
[![Apache License](https://img.shields.io/github/license/gdamore/tcell.svg?logoColor=silver&logo=opensourceinitiative&color=blue&label=)](https://github.com/gdamore/tcell/blob/master/LICENSE) [![Apache License](https://img.shields.io/github/license/gdamore/tcell.svg?logoColor=silver&logo=opensourceinitiative&color=blue&label=)](https://github.com/gdamore/tcell/blob/master/LICENSE)
[![Docs](https://img.shields.io/badge/godoc-reference-blue.svg?label=&logo=go)](https://pkg.go.dev/github.com/gdamore/tcell/v2) [![Docs](https://img.shields.io/badge/godoc-reference-blue.svg?label=&logo=go)](https://pkg.go.dev/github.com/gdamore/tcell/v2)
[![Discord](https://img.shields.io/discord/639503822733180969?label=&logo=discord)](https://discord.gg/urTTxDN) [![Discord](https://img.shields.io/discord/639503822733180969?label=&logo=discord)](https://discord.gg/urTTxDN)
[![Coverage](https://img.shields.io/codecov/c/github/gdamore/tcell?logoColor=grey&logo=codecov&label=)](https://codecov.io/gh/gdamore/tcell) [![Coverage](https://img.shields.io/codecov/c/github/gdamore/tcell?logoColor=grey&logo=codecov&label=)](https://codecov.io/gh/gdamore/tcell)
[![Go Report Card](https://goreportcard.com/badge/github.com/gdamore/tcell/v2)](https://goreportcard.com/report/github.com/gdamore/tcell/v2) [![Go Report Card](https://goreportcard.com/badge/github.com/gdamore/tcell/v2)](https://goreportcard.com/report/github.com/gdamore/tcell/v2)
[![Latest Release](https://img.shields.io/github/v/release/gdamore/tcell.svg?logo=github&label=)](https://github.com/gdamore/tcell/releases)
Please see [here](UKRAINE.md) for an important message for the people of Russia. Please see [here](UKRAINE.md) for an important message for the people of Russia.
@@ -25,50 +27,9 @@ A brief, and still somewhat rough, [tutorial](TUTORIAL.md) is available.
## Examples ## Examples
- [proxima5](https://github.com/gdamore/proxima5) - space shooter ([video](https://youtu.be/jNxKTCmY_bQ)) A number of example are posted up on our [Gallery](https://github.com/gdamore/tcell/wikis/Gallery/).
- [govisor](https://github.com/gdamore/govisor) - service management UI ([screenshot](http://2.bp.blogspot.com/--OsvnfzSNow/Vf7aqMw3zXI/AAAAAAAAARo/uOMtOvw4Sbg/s1600/Screen%2BShot%2B2015-09-20%2Bat%2B9.08.41%2BAM.png))
- mouse demo - included mouse test ([screenshot](http://2.bp.blogspot.com/-fWvW5opT0es/VhIdItdKqJI/AAAAAAAAATE/7Ojc0L1SpB0/s1600/Screen%2BShot%2B2015-10-04%2Bat%2B11.47.13%2BPM.png)) Let us know if you want to add your masterpiece to the list!
- [gomatrix](https://github.com/gdamore/gomatrix) - converted from Termbox
- [micro](https://github.com/zyedidia/micro/) - lightweight text editor with syntax-highlighting and themes
- [godu](https://github.com/viktomas/godu) - utility to discover large files/folders
- [tview](https://github.com/rivo/tview/) - rich interactive widgets
- [cview](https://code.rocketnine.space/tslocum/cview) - user interface toolkit (fork of _tview_)
- [awesome gocui](https://github.com/awesome-gocui/gocui) - Go Console User Interface
- [gomandelbrot](https://github.com/rgm3/gomandelbrot) - Mandelbrot!
- [WTF](https://github.com/senorprogrammer/wtf) - personal information dashboard
- [browsh](https://github.com/browsh-org/browsh) - modern web browser ([video](https://www.youtube.com/watch?v=HZq86XfBoRo))
- [go-life](https://github.com/sachaos/go-life) - Conway's Game of Life
- [gowid](https://github.com/gcla/gowid) - compositional widgets for terminal UIs, inspired by _urwid_
- [termshark](https://termshark.io) - interface for _tshark_, inspired by Wireshark, built on _gowid_
- [go-tetris](https://github.com/MichaelS11/go-tetris) - Go Tetris with AI option
- [fzf](https://github.com/junegunn/fzf) - command-line fuzzy finder
- [ascii-fluid](https://github.com/esimov/ascii-fluid) - fluid simulation controlled by webcam
- [cbind](https://code.rocketnine.space/tslocum/cbind) - key event encoding, decoding and handling
- [tpong](https://github.com/spinzed/tpong) - old-school Pong
- [aerc](https://git.sr.ht/~sircmpwn/aerc) - email client
- [tblogs](https://github.com/ezeoleaf/tblogs) - development blogs reader
- [spinc](https://github.com/lallassu/spinc) - _irssi_ inspired chat application for Cisco Spark/WebEx
- [gorss](https://github.com/lallassu/gorss) - RSS/Atom feed reader
- [memoryalike](https://github.com/Bios-Marcel/memoryalike) - memorization game
- [lf](https://github.com/gokcehan/lf) - file manager
- [goful](https://github.com/anmitsu/goful) - CUI file manager
- [gokeybr](https://github.com/bunyk/gokeybr) - deliberately practice your typing
- [gonano](https://github.com/jbaramidze/gonano) - editor, mimics _nano_
- [uchess](https://github.com/tmountain/uchess) - UCI chess client
- [min](https://github.com/a-h/min) - Gemini browser
- [ov](https://github.com/noborus/ov) - file pager
- [tmux-wormhole](https://github.com/gcla/tmux-wormhole) - _tmux_ plugin to transfer files
- [gruid-tcell](https://github.com/anaseto/gruid-tcell) - driver for the grid based UI and game framework
- [aretext](https://github.com/aretext/aretext) - minimalist text editor with _vim_ key bindings
- [sync](https://github.com/kyprifog/sync) - GitHub repo synchronization tool
- [statusbar](https://github.com/kyprifog/statusbar) - statusbar motivation tool for tracking periodic tasks/goals
- [todo](https://github.com/kyprifog/todo) - simple todo app
- [gosnakego](https://github.com/liweiyi88/gosnakego) - a snake game
- [gbb](https://github.com/sdemingo/gbb) - A classical bulletin board app for tildes or public unix servers
- [lil](https://github.com/andrievsky/lil) - A simple and flexible interface for any service by implementing only list and get operations
- [hero.go](https://github.com/barisbll/hero.go) - 2d monster shooter ([video](https://user-images.githubusercontent.com/40062673/277157369-240d7606-b471-4aa1-8c54-4379a513122b.mp4))
- [go-tetris](https://github.com/aaronriekenberg/go-tetris) - simple tetris game for native terminal and WASM using github actions+pages
- [oddshub](https://github.com/dos-2/oddshub) - A TUI designed for analyzing sports betting odds
## Pure Go Terminfo Database ## Pure Go Terminfo Database
@@ -85,6 +46,11 @@ _Tcell_ is portable to a wide variety of systems, and is pure Go, without
any need for CGO. any need for CGO.
_Tcell_ is believed to work with mainstream systems officially supported by golang. _Tcell_ is believed to work with mainstream systems officially supported by golang.
Following the Go support policy, _Tcell_ officially only supports the current ("stable") version of go,
and the version immediately prior ("oldstable"). This policy is necessary to make sure that we can
update dependencies to pick up security fixes and new features, and it allows us to adopt changes
(such as library and language features) that are only supported in newer versions of Go.
## No Async IO ## No Async IO
_Tcell_ is able to operate without requiring `SIGIO` signals (unlike _termbox_), _Tcell_ is able to operate without requiring `SIGIO` signals (unlike _termbox_),
@@ -117,11 +83,6 @@ _Tcell_ will respect your terminal's color space as specified within your termin
For example attempts to emit color sequences on VT100 terminals For example attempts to emit color sequences on VT100 terminals
won't result in unintended consequences. won't result in unintended consequences.
In legacy Windows mode, _Tcell_ supports 16 colors, bold, dim, and reverse,
instead of just termbox's 8 colors with reverse. (Note that there is some
conflation with bold/dim and colors.)
Modern Windows 10 can benefit from much richer colors however.
_Tcell_ maps 16 colors down to 8, for terminals that need it. _Tcell_ maps 16 colors down to 8, for terminals that need it.
(The upper 8 colors are just brighter versions of the lower 8.) (The upper 8 colors are just brighter versions of the lower 8.)
@@ -130,10 +91,6 @@ _Tcell_ maps 16 colors down to 8, for terminals that need it.
_Tcell_ supports enhanced mouse tracking mode, so your application can receive _Tcell_ supports enhanced mouse tracking mode, so your application can receive
regular mouse motion events, and wheel events, if your terminal supports it. regular mouse motion events, and wheel events, if your terminal supports it.
(Note: The Windows 10 Terminal application suffers from a flaw in this regard,
and does not support mouse interaction. The stock Windows 10 console host
fired up with cmd.exe or PowerShell works fine however.)
## _Termbox_ Compatibility ## _Termbox_ Compatibility
A compatibility layer for _termbox_ is provided in the `compat` directory. A compatibility layer for _termbox_ is provided in the `compat` directory.
@@ -159,9 +116,6 @@ taken in the application to avoid explicitly attempting to set content in the
next cell, otherwise the results are undefined. (Normally the wide character next cell, otherwise the results are undefined. (Normally the wide character
is displayed, and the other character is not; do not depend on that behavior.) is displayed, and the other character is not; do not depend on that behavior.)
Older terminal applications (especially on systems like Windows 8) lack support
for advanced Unicode, and thus may not fare well.
## Colors ## Colors
_Tcell_ assumes the ANSI/XTerm color model, including the 256 color map that _Tcell_ assumes the ANSI/XTerm color model, including the 256 color map that
@@ -265,22 +219,16 @@ platforms (e.g., AIX) may need to be added. Pull requests are welcome!
Windows console mode applications are supported. Windows console mode applications are supported.
Modern console applications like ConEmu and the Windows 10 terminal, Modern console applications like ConEmu and the Windows Terminal,
support all the good features (resize, mouse tracking, etc.) support all the good features (resize, mouse tracking, etc.)
### WASM ### WASM
WASM is supported, but needs additional setup detailed in [README-wasm](README-wasm.md). WASM is supported, but needs additional setup detailed in [README-wasm](README-wasm.md).
### Plan9 and others ### Plan9 and its variants
These platforms won't work, but compilation stubs are supplied Plan 9 is supported on a limited basis. The Plan 9 backend opens `/dev/cons` for I/O, enables raw mode by writing `rawon`/`rawoff` to `/dev/consctl`, watches `/dev/wctl` for resize notifications, and then constructs a **terminfo-backed** `Screen` (so `NewScreen` works as on other platforms). Typical usage is inside `vt(1)` with `TERM=vt100`. Expect **monochrome text** and **no mouse reporting** under stock `vt(1)` (it generally does not emit ANSI color or xterm mouse sequences). If a Plan 9 terminal supplies ANSI color escape sequences and xterm-style mouse reporting, color can be picked up via **terminfo** and mouse support could be added by wiring those sequences into the Plan 9 TTY path; contributions that improve terminal detection and broaden feature support are welcome.
for folks that want to include parts of this in software for those
platforms. The Simulation screen works, but as _Tcell_ doesn't know how to
allocate a real screen object on those platforms, `NewScreen()` will fail.
If anyone has wisdom about how to improve support for these,
please let me know. PRs are especially welcome.
### Commercial Support ### Commercial Support

23
vendor/github.com/gdamore/tcell/v2/charset_plan9.go generated vendored Normal file
View File

@@ -0,0 +1,23 @@
//go:build plan9
// +build plan9
// Copyright 2025 The TCell Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use 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 tcell
// Plan 9 uses UTF-8 system-wide, so we return "UTF-8" unconditionally.
func getCharset() string {
return "UTF-8"
}

View File

@@ -1,5 +1,5 @@
//go:build plan9 || nacl //go:build nacl
// +build plan9 nacl // +build nacl
// Copyright 2015 The TCell Authors // Copyright 2015 The TCell Authors
// //

View File

@@ -655,25 +655,28 @@ var vkKeys = map[uint16]Key{
func getu32(v []byte) uint32 { func getu32(v []byte) uint32 {
return uint32(v[0]) + (uint32(v[1]) << 8) + (uint32(v[2]) << 16) + (uint32(v[3]) << 24) return uint32(v[0]) + (uint32(v[1]) << 8) + (uint32(v[2]) << 16) + (uint32(v[3]) << 24)
} }
func geti32(v []byte) int32 { func geti32(v []byte) int32 {
return int32(getu32(v)) return int32(getu32(v))
} }
func getu16(v []byte) uint16 { func getu16(v []byte) uint16 {
return uint16(v[0]) + (uint16(v[1]) << 8) return uint16(v[0]) + (uint16(v[1]) << 8)
} }
func geti16(v []byte) int16 { func geti16(v []byte) int16 {
return int16(getu16(v)) return int16(getu16(v))
} }
// Convert windows dwControlKeyState to modifier mask // Convert windows dwControlKeyState to modifier mask
func mod2mask(cks uint32) ModMask { func mod2mask(cks uint32, filter_ctrl_alt bool) ModMask {
mm := ModNone mm := ModNone
// Left or right control // Left or right control
ctrl := (cks & (0x0008 | 0x0004)) != 0 ctrl := (cks & (0x0008 | 0x0004)) != 0
// Left or right alt // Left or right alt
alt := (cks & (0x0002 | 0x0001)) != 0 alt := (cks & (0x0002 | 0x0001)) != 0
// Filter out ctrl+alt (it means AltGr) // Filter out ctrl+alt (it means AltGr)
if !(ctrl && alt) { if !filter_ctrl_alt || !(ctrl && alt) {
if ctrl { if ctrl {
mm |= ModCtrl mm |= ModCtrl
} }
@@ -788,10 +791,10 @@ func (s *cScreen) getConsoleInput() error {
// synthesized key code // synthesized key code
for krec.repeat > 0 { for krec.repeat > 0 {
// convert shift+tab to backtab // convert shift+tab to backtab
if mod2mask(krec.mod) == ModShift && krec.ch == vkTab { if mod2mask(krec.mod, false) == ModShift && krec.ch == vkTab {
s.postEvent(NewEventKey(KeyBacktab, 0, ModNone)) s.postEvent(NewEventKey(KeyBacktab, 0, ModNone))
} else { } else {
s.postEvent(NewEventKey(KeyRune, rune(krec.ch), mod2mask(krec.mod))) s.postEvent(NewEventKey(KeyRune, rune(krec.ch), mod2mask(krec.mod, true)))
} }
krec.repeat-- krec.repeat--
} }
@@ -803,7 +806,7 @@ func (s *cScreen) getConsoleInput() error {
return nil return nil
} }
for krec.repeat > 0 { for krec.repeat > 0 {
s.postEvent(NewEventKey(key, rune(krec.ch), mod2mask(krec.mod))) s.postEvent(NewEventKey(key, rune(krec.ch), mod2mask(krec.mod, false)))
krec.repeat-- krec.repeat--
} }
@@ -816,7 +819,7 @@ func (s *cScreen) getConsoleInput() error {
mrec.flags = getu32(rec.data[12:]) mrec.flags = getu32(rec.data[12:])
btns := mrec2btns(mrec.btns, mrec.flags) btns := mrec2btns(mrec.btns, mrec.flags)
// we ignore double click, events are delivered normally // we ignore double click, events are delivered normally
s.postEvent(NewEventMouse(int(mrec.x), int(mrec.y), btns, mod2mask(mrec.mod))) s.postEvent(NewEventMouse(int(mrec.x), int(mrec.y), btns, mod2mask(mrec.mod, false)))
case resizeEvent: case resizeEvent:
var rrec resizeRecord var rrec resizeRecord
@@ -938,7 +941,7 @@ func (s *cScreen) mapStyle(style Style) uint16 {
return attr return attr
} }
func (s *cScreen) sendVtStyle(style Style) { func (s *cScreen) makeVtStyle(style Style) string {
esc := &strings.Builder{} esc := &strings.Builder{}
fg, bg, attrs := style.fg, style.bg, style.attrs fg, bg, attrs := style.fg, style.bg, style.attrs
@@ -998,30 +1001,40 @@ func (s *cScreen) sendVtStyle(style Style) {
esc.WriteString(vtExitUrl) esc.WriteString(vtExitUrl)
} }
s.emitVtString(esc.String()) return esc.String()
} }
func (s *cScreen) writeString(x, y int, style Style, ch []uint16) { func (s *cScreen) sendVtStyle(style Style) {
s.emitVtString(s.makeVtStyle(style))
}
func (s *cScreen) writeString(x, y int, style Style, vtBuf, ch []uint16) {
// we assume the caller has hidden the cursor // we assume the caller has hidden the cursor
if len(ch) == 0 { if len(ch) == 0 {
return return
} }
s.setCursorPos(x, y, s.vten)
if s.vten { if s.vten {
s.sendVtStyle(style) vtBuf = append(vtBuf, utf16.Encode([]rune(fmt.Sprintf(vtCursorPos, y+1, x+1)))...)
styleStr := s.makeVtStyle(style)
vtBuf = append(vtBuf, utf16.Encode([]rune(styleStr))...)
vtBuf = append(vtBuf, ch...)
_ = syscall.WriteConsole(s.out, &vtBuf[0], uint32(len(vtBuf)), nil, nil)
vtBuf = vtBuf[:0]
} else { } else {
s.setCursorPos(x, y, s.vten)
_, _, _ = procSetConsoleTextAttribute.Call( _, _, _ = procSetConsoleTextAttribute.Call(
uintptr(s.out), uintptr(s.out),
uintptr(s.mapStyle(style))) uintptr(s.mapStyle(style)))
_ = syscall.WriteConsole(s.out, &ch[0], uint32(len(ch)), nil, nil)
} }
_ = syscall.WriteConsole(s.out, &ch[0], uint32(len(ch)), nil, nil)
} }
func (s *cScreen) draw() { func (s *cScreen) draw() {
// allocate a scratch line bit enough for no combining chars. // allocate a scratch line bit enough for no combining chars.
// if you have combining characters, you may pay for extra allocations. // if you have combining characters, you may pay for extra allocations.
buf := make([]uint16, 0, s.w) buf := make([]uint16, 0, s.w)
var vtBuf []uint16
wcs := buf[:] wcs := buf[:]
lstyle := styleInvalid lstyle := styleInvalid
@@ -1040,7 +1053,7 @@ func (s *cScreen) draw() {
// write out any data queued thus far // write out any data queued thus far
// because we are going to skip over some // because we are going to skip over some
// cells, or because we need to change styles // cells, or because we need to change styles
s.writeString(lx, ly, lstyle, wcs) s.writeString(lx, ly, lstyle, vtBuf, wcs)
wcs = buf[0:0] wcs = buf[0:0]
lstyle = StyleDefault lstyle = StyleDefault
if !dirty { if !dirty {
@@ -1067,7 +1080,7 @@ func (s *cScreen) draw() {
} }
x += width - 1 x += width - 1
} }
s.writeString(lx, ly, lstyle, wcs) s.writeString(lx, ly, lstyle, vtBuf, wcs)
wcs = buf[0:0] wcs = buf[0:0]
lstyle = styleInvalid lstyle = styleInvalid
} }

View File

@@ -164,6 +164,16 @@ func (s Style) Underline(params ...interface{}) Style {
return s2 return s2
} }
// GetUnderlineStyle returns the underline style for the style.
func (s Style) GetUnderlineStyle() UnderlineStyle {
return s.ulStyle
}
// GetUnderlineColor returns the underline color for the style.
func (s Style) GetUnderlineColor() Color {
return s.ulColor
}
// Attributes returns a new style based on s, with its attributes set as // Attributes returns a new style based on s, with its attributes set as
// specified. // specified.
func (s Style) Attributes(attrs AttrMask) Style { func (s Style) Attributes(attrs AttrMask) Style {

View File

@@ -25,6 +25,7 @@ import (
// The following imports just register themselves -- // The following imports just register themselves --
// these are the terminal types we aggregate in this package. // these are the terminal types we aggregate in this package.
_ "github.com/gdamore/tcell/v2/terminfo/a/ansi" _ "github.com/gdamore/tcell/v2/terminfo/a/ansi"
_ "github.com/gdamore/tcell/v2/terminfo/t/tmux"
_ "github.com/gdamore/tcell/v2/terminfo/v/vt100" _ "github.com/gdamore/tcell/v2/terminfo/v/vt100"
_ "github.com/gdamore/tcell/v2/terminfo/v/vt102" _ "github.com/gdamore/tcell/v2/terminfo/v/vt102"
_ "github.com/gdamore/tcell/v2/terminfo/v/vt220" _ "github.com/gdamore/tcell/v2/terminfo/v/vt220"

View File

@@ -898,7 +898,7 @@ func (t *tScreen) drawCell(x, y int) int {
} }
// URL string can be long, so don't send it unless we really need to // URL string can be long, so don't send it unless we really need to
if t.enterUrl != "" && t.curstyle != style { if t.enterUrl != "" && t.curstyle.url != style.url {
if style.url != "" { if style.url != "" {
t.TPuts(ti.TParm(t.enterUrl, style.url, style.urlId)) t.TPuts(ti.TParm(t.enterUrl, style.url, style.urlId))
} else { } else {
@@ -1339,6 +1339,10 @@ func (t *tScreen) buildMouseEvent(x, y, btn int) *EventMouse {
button = WheelUp button = WheelUp
case 0x41: case 0x41:
button = WheelDown button = WheelDown
case 0x42:
button = WheelLeft
case 0x43:
button = WheelRight
} }
if btn&0x4 != 0 { if btn&0x4 != 0 {

36
vendor/github.com/gdamore/tcell/v2/tscreen_plan9.go generated vendored Normal file
View File

@@ -0,0 +1,36 @@
//go:build plan9
// +build plan9
// Copyright 2025 The TCell Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use 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 tcell
import "os"
// initialize on Plan 9: if no TTY was provided, use the Plan 9 TTY.
func (t *tScreen) initialize() error {
if os.Getenv("TERM") == "" {
// TERM should be "vt100" in a vt(1) window; color/mouse support will be limited.
_ = os.Setenv("TERM", "vt100")
}
if t.tty == nil {
tty, err := NewDevTty()
if err != nil {
return err
}
t.tty = tty
}
return nil
}

View File

@@ -1,5 +1,5 @@
//go:build plan9 || windows //go:build windows
// +build plan9 windows // +build windows
// Copyright 2022 The TCell Authors // Copyright 2022 The TCell Authors
// //

270
vendor/github.com/gdamore/tcell/v2/tty_plan9.go generated vendored Normal file
View File

@@ -0,0 +1,270 @@
//go:build plan9
// +build plan9
// Copyright 2025 The TCell Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use 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 tcell
import (
"bufio"
"errors"
"fmt"
"io"
"os"
"strconv"
"strings"
"sync"
"sync/atomic"
)
// p9Tty implements tcell.Tty using Plan 9's /dev/cons and /dev/consctl.
// Raw mode is enabled by writing "rawon" to /dev/consctl while the fd stays open.
// Resize notifications are read from /dev/wctl: the first read returns geometry,
// subsequent reads block until the window changes (rio(4)).
//
// References:
// - kbdfs(8): cons/consctl rawon|rawoff semantics
// - rio(4): wctl geometry and blocking-on-change behavior
// - vt(1): VT100 emulator typically used for TUI programs on Plan 9
//
// Limitations:
// - We assume VT100-level capabilities (often no colors, no mouse).
// - Window size is conservative: we return 80x24 unless overridden.
// Set LINES/COLUMNS (or TCELL_LINES/TCELL_COLS) to refine.
// - Mouse and bracketed paste are not wired; terminfo/xterm queries
// are not attempted because vt(1) may not support them.
type p9Tty struct {
cons *os.File // /dev/cons (read+write)
consctl *os.File // /dev/consctl (write "rawon"/"rawoff")
wctl *os.File // /dev/wctl (resize notifications)
// protect close/stop; Read/Write are serialized by os.File
mu sync.Mutex
closed atomic.Bool
// resize callback
onResize atomic.Value // func()
wg sync.WaitGroup
stopCh chan struct{}
}
func NewDevTty() (Tty, error) { // tcell signature
return newPlan9TTY()
}
func NewStdIoTty() (Tty, error) { // also required by tcell
// On Plan 9 there is no POSIX tty discipline on stdin/stdout;
// use /dev/cons explicitly for robustness.
return newPlan9TTY()
}
func NewDevTtyFromDev(_ string) (Tty, error) { // required by tcell
// Plan 9 does not have multiple "ttys" in the POSIX sense;
// always bind to /dev/cons and /dev/consctl.
return newPlan9TTY()
}
func newPlan9TTY() (Tty, error) {
cons, err := os.OpenFile("/dev/cons", os.O_RDWR, 0)
if err != nil {
return nil, fmt.Errorf("open /dev/cons: %w", err)
}
consctl, err := os.OpenFile("/dev/consctl", os.O_WRONLY, 0)
if err != nil {
_ = cons.Close()
return nil, fmt.Errorf("open /dev/consctl: %w", err)
}
// /dev/wctl may not exist (console without rio); best-effort.
wctl, _ := os.OpenFile("/dev/wctl", os.O_RDWR, 0)
t := &p9Tty{
cons: cons,
consctl: consctl,
wctl: wctl,
stopCh: make(chan struct{}),
}
return t, nil
}
func (t *p9Tty) Start() error {
t.mu.Lock()
defer t.mu.Unlock()
if t.closed.Load() {
return errors.New("tty closed")
}
// Recreate stop channel if absent or closed (supports resume).
if t.stopCh == nil || isClosed(t.stopCh) {
t.stopCh = make(chan struct{})
}
// Put console into raw mode; remains active while consctl is open.
if _, err := t.consctl.Write([]byte("rawon")); err != nil {
return fmt.Errorf("enable raw mode: %w", err)
}
// Reopen /dev/wctl on resume; best-effort (system console may lack it).
if t.wctl == nil {
if f, err := os.OpenFile("/dev/wctl", os.O_RDWR, 0); err == nil {
t.wctl = f
}
}
if t.wctl != nil {
t.wg.Add(1)
go t.watchResize()
}
return nil
}
func (t *p9Tty) Drain() error {
// Per tcell docs, this may reasonably be a no-op on non-POSIX ttys.
// Read deadlines are not available on plan9 os.File; we rely on Stop().
return nil
}
func (t *p9Tty) Stop() error {
t.mu.Lock()
defer t.mu.Unlock()
// Signal watcher to stop (if not already).
if t.stopCh != nil && !isClosed(t.stopCh) {
close(t.stopCh)
}
// Exit raw mode first.
_, _ = t.consctl.Write([]byte("rawoff"))
// Closing wctl unblocks watchResize; nil it so Start() can reopen later.
if t.wctl != nil {
_ = t.wctl.Close()
t.wctl = nil
}
// Ensure watcher goroutine has exited before returning.
t.wg.Wait()
return nil
}
func (t *p9Tty) Close() error {
t.mu.Lock()
defer t.mu.Unlock()
if t.closed.Swap(true) {
return nil
}
if t.stopCh != nil && !isClosed(t.stopCh) {
close(t.stopCh)
}
_, _ = t.consctl.Write([]byte("rawoff"))
_ = t.cons.Close()
_ = t.consctl.Close()
if t.wctl != nil {
_ = t.wctl.Close()
t.wctl = nil
}
t.wg.Wait()
return nil
}
func (t *p9Tty) Read(p []byte) (int, error) {
return t.cons.Read(p)
}
func (t *p9Tty) Write(p []byte) (int, error) {
return t.cons.Write(p)
}
func (t *p9Tty) NotifyResize(cb func()) {
if cb == nil {
t.onResize.Store((func())(nil))
return
}
t.onResize.Store(cb)
}
func (t *p9Tty) WindowSize() (WindowSize, error) {
// Strategy:
// 1) honor explicit overrides (TCELL_LINES/TCELL_COLS, LINES/COLUMNS),
// 2) otherwise return conservative 80x24.
// Reading /dev/wctl gives pixel geometry, but char cell metrics are
// not generally available to non-draw clients; vt(1) is fixed-cell.
lines, cols := envInt("TCELL_LINES"), envInt("TCELL_COLS")
if lines == 0 {
lines = envInt("LINES")
}
if cols == 0 {
cols = envInt("COLUMNS")
}
if lines <= 0 {
lines = 24
}
if cols <= 0 {
cols = 80
}
return WindowSize{Width: cols, Height: lines}, nil
}
// watchResize blocks on /dev/wctl reads; each read returns when the window
// changes size/position/state, per rio(4). We ignore the parsed geometry and
// just notify tcell to re-query WindowSize().
func (t *p9Tty) watchResize() {
defer t.wg.Done()
r := bufio.NewReader(t.wctl)
for {
select {
case <-t.stopCh:
return
default:
}
// Each read delivers something like:
// " minx miny maxx maxy visible current\n"
// We don't need to parse here; just signal.
_, err := r.ReadString('\n')
if err != nil {
if errors.Is(err, io.EOF) {
return
}
// transient errors: continue
}
if cb, _ := t.onResize.Load().(func()); cb != nil {
cb()
}
}
}
func envInt(name string) int {
if s := strings.TrimSpace(os.Getenv(name)); s != "" {
if v, err := strconv.Atoi(s); err == nil {
return v
}
}
return 0
}
// helper: safe check if a channel is closed
func isClosed(ch <-chan struct{}) bool {
select {
case <-ch:
return true
default:
return false
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2024 The TCell Authors // Copyright 2025 The TCell Authors
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use file except in compliance with the License. // you may not use file except in compliance with the License.
@@ -145,7 +145,7 @@ func (t *wScreen) drawCell(x, y int) int {
s := "" s := ""
if len(combc) > 0 { if len(combc) > 0 {
b := make([]rune, 0, 1 + len(combc)) b := make([]rune, 0, 1+len(combc))
b = append(b, mainc) b = append(b, mainc)
b = append(b, combc...) b = append(b, combc...)
s = string(b) s = string(b)
@@ -277,6 +277,12 @@ func (t *wScreen) DisableFocus() {
t.Unlock() t.Unlock()
} }
func (s *wScreen) GetClipboard() {
}
func (s *wScreen) SetClipboard(_ []byte) {
}
func (t *wScreen) Size() (int, int) { func (t *wScreen) Size() (int, int) {
t.Lock() t.Lock()
w, h := t.w, t.h w, h := t.w, t.h

View File

@@ -1,6 +1,7 @@
package gocui package gocui
import ( import (
"regexp"
"strings" "strings"
"github.com/mattn/go-runewidth" "github.com/mattn/go-runewidth"
@@ -33,14 +34,16 @@ func AutoWrapContent(content []rune, autoWrapWidth int) ([]rune, []CursorMapping
wrappedContent := make([]rune, 0, len(content)+estimatedNumberOfSoftLineBreaks) wrappedContent := make([]rune, 0, len(content)+estimatedNumberOfSoftLineBreaks)
startOfLine := 0 startOfLine := 0
indexOfLastWhitespace := -1 indexOfLastWhitespace := -1
var footNoteMatcher footNoteMatcher
for currentPos, r := range content { for currentPos, r := range content {
if r == '\n' { if r == '\n' {
wrappedContent = append(wrappedContent, content[startOfLine:currentPos+1]...) wrappedContent = append(wrappedContent, content[startOfLine:currentPos+1]...)
startOfLine = currentPos + 1 startOfLine = currentPos + 1
indexOfLastWhitespace = -1 indexOfLastWhitespace = -1
footNoteMatcher.reset()
} else { } else {
if r == ' ' { if r == ' ' && !footNoteMatcher.isFootNote() {
indexOfLastWhitespace = currentPos + 1 indexOfLastWhitespace = currentPos + 1
} else if currentPos-startOfLine >= autoWrapWidth && indexOfLastWhitespace >= 0 { } else if currentPos-startOfLine >= autoWrapWidth && indexOfLastWhitespace >= 0 {
wrapAt := indexOfLastWhitespace wrapAt := indexOfLastWhitespace
@@ -49,7 +52,9 @@ func AutoWrapContent(content []rune, autoWrapWidth int) ([]rune, []CursorMapping
cursorMapping = append(cursorMapping, CursorMapping{wrapAt, len(wrappedContent)}) cursorMapping = append(cursorMapping, CursorMapping{wrapAt, len(wrappedContent)})
startOfLine = wrapAt startOfLine = wrapAt
indexOfLastWhitespace = -1 indexOfLastWhitespace = -1
footNoteMatcher.reset()
} }
footNoteMatcher.addRune(r)
} }
} }
@@ -58,6 +63,50 @@ func AutoWrapContent(content []rune, autoWrapWidth int) ([]rune, []CursorMapping
return wrappedContent, cursorMapping return wrappedContent, cursorMapping
} }
var footNoteRe = regexp.MustCompile(`^\[\d+\]:\s*$`)
type footNoteMatcher struct {
lineStr strings.Builder
didFailToMatch bool
}
func (self *footNoteMatcher) addRune(r rune) {
if self.didFailToMatch {
// don't bother tracking the rune if we know it can't possibly match any more
return
}
if self.lineStr.Len() == 0 && r != '[' {
// fail early if the first rune of a line isn't a '['; this is mainly to avoid a (possibly
// expensive) regex match
self.didFailToMatch = true
return
}
self.lineStr.WriteRune(r)
}
func (self *footNoteMatcher) isFootNote() bool {
if self.didFailToMatch {
return false
}
if footNoteRe.MatchString(self.lineStr.String()) {
// it's a footnote, so treat spaces as non-breaking. It's important not to reset the matcher
// here, because there could be multiple spaces after a footnote.
return true
}
// no need to check again for this line
self.didFailToMatch = true
return false
}
func (self *footNoteMatcher) reset() {
self.lineStr.Reset()
self.didFailToMatch = false
}
func (self *TextArea) autoWrapContent() { func (self *TextArea) autoWrapContent() {
if self.AutoWrap { if self.AutoWrap {
self.wrappedContent, self.cursorMapping = AutoWrapContent(self.content, self.AutoWrapWidth) self.wrappedContent, self.cursorMapping = AutoWrapContent(self.content, self.AutoWrapWidth)

View File

@@ -6,8 +6,32 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
The format of this file is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format of this file is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
but only releases after v1.0.3 properly adhere to it. but only releases after v1.0.3 properly adhere to it.
## [Unreleased]
## [1.3.0] - 2025-09-08
### Added
- `BlendLinearRgb` (#50)
- `DistanceRiemersma` (#52)
- Introduce a function for sorting colors (#57)
- YAML marshal/unmarshal support (#63)
- Add support for OkLab and OkLch (#66)
- Functions that use randomness now support specifying a custom source (#73)
- Functions BlendOkLab and BlendOkLch (#70)
## Changed
- `Hex()` parsing is much faster (#78)
### Fixed
- Fix bug when doing HSV/HCL blending between a gray color and non-gray color (#60)
- Docs for HSV/HSL were updated to note that hue 360 is not allowed (#71)
### Deprecated
- `DistanceLinearRGB` is deprecated for the name `DistanceLinearRgb` which is more in-line with the rest of the library
## [1.2.0] - 2021-01-27 ## [1.2.0] - 2021-01-27
This is the same as the v1.1.0 tag.
### Added ### Added
- HSLuv and HPLuv color spaces (#41, #51) - HSLuv and HPLuv color spaces (#41, #51)
- CIE LCh(uv) color space, called `LuvLCh` in code (#51) - CIE LCh(uv) color space, called `LuvLCh` in code (#51)

View File

@@ -1,6 +1,7 @@
go-colorful go-colorful
=========== ===========
[![Go Reference](https://pkg.go.dev/badge/github.com/lucasb-eyer/go-colorful.svg)](https://pkg.go.dev/github.com/lucasb-eyer/go-colorful)
[![go reportcard](https://goreportcard.com/badge/github.com/lucasb-eyer/go-colorful)](https://goreportcard.com/report/github.com/lucasb-eyer/go-colorful) [![go reportcard](https://goreportcard.com/badge/github.com/lucasb-eyer/go-colorful)](https://goreportcard.com/report/github.com/lucasb-eyer/go-colorful)
A library for playing with colors in Go. Supports Go 1.13 onwards. A library for playing with colors in Go. Supports Go 1.13 onwards.
@@ -29,10 +30,10 @@ Go-Colorful stores colors in RGB and provides methods from converting these to v
- **CIE-xyY:** encodes chromacity in x and y and luminance in Y, all in [0..1] - **CIE-xyY:** encodes chromacity in x and y and luminance in Y, all in [0..1]
- **CIE-L\*a\*b\*:** A *perceptually uniform* color space, i.e. distances are meaningful. L\* in [0..1] and a\*, b\* almost in [-1..1]. - **CIE-L\*a\*b\*:** A *perceptually uniform* color space, i.e. distances are meaningful. L\* in [0..1] and a\*, b\* almost in [-1..1].
- **CIE-L\*u\*v\*:** Very similar to CIE-L\*a\*b\*, there is [no consensus](http://en.wikipedia.org/wiki/CIELUV#Historical_background) on which one is "better". - **CIE-L\*u\*v\*:** Very similar to CIE-L\*a\*b\*, there is [no consensus](http://en.wikipedia.org/wiki/CIELUV#Historical_background) on which one is "better".
- **CIE-L\*C\*h° (HCL):** This is generally the [most useful](http://vis4.net/blog/posts/avoid-equidistant-hsv-colors/) one; CIE-L\*a\*b\* space in polar coordinates, i.e. a *better* HSV. H° is in [0..360], C\* almost in [-1..1] and L\* as in CIE-L\*a\*b\*. - **CIE-L\*C\*h° (HCL):** This is generally the [most useful](http://vis4.net/blog/posts/avoid-equidistant-hsv-colors/) one; CIE-L\*a\*b\* space in polar coordinates, i.e. a *better* HSV. H° is in [0..360], C\* almost in [0..1] and L\* as in CIE-L\*a\*b\*.
- **CIE LCh(uv):** Called `LuvLCh` in code, this is a cylindrical transformation of the CIE-L\*u\*v\* color space. Like HCL above: H° is in [0..360], C\* almost in [-1..1] and L\* as in CIE-L\*u\*v\*. - **CIE LCh(uv):** Called `LuvLCh` in code, this is a cylindrical transformation of the CIE-L\*u\*v\* color space. Like HCL above: H° is in [0..360], C\* almost in [0..1] and L\* as in CIE-L\*u\*v\*.
- **HSLuv:** The better alternative to HSL, see [here](https://www.hsluv.org/) and [here](https://www.kuon.ch/post/2020-03-08-hsluv/). Hue in [0..360], Saturation and Luminance in [0..1]. - **HSLuv:** The better alternative to HSL, see [here](https://www.hsluv.org/) and [here](https://www.kuon.ch/post/2020-03-08-hsluv/). Hue in [0..360], Saturation and Luminance in [0..1].
- **HPLuv:** A variant of HSLuv. The color space is smoother, but only pastel colors can be included. Because the valid colors are limited, it's easy to get invalid Saturation values way above 1.0, indicating the color can't be represented in HPLuv beccause it's not pastel. - **HPLuv:** A variant of HSLuv. The color space is smoother, but only pastel colors can be included. Because the valid colors are limited, it's easy to get invalid Saturation values way above 1.0, indicating the color can't be represented in HPLuv because it's not pastel.
For the colorspaces where it makes sense (XYZ, Lab, Luv, HCl), the For the colorspaces where it makes sense (XYZ, Lab, Luv, HCl), the
[D65](http://en.wikipedia.org/wiki/Illuminant_D65) is used as reference white [D65](http://en.wikipedia.org/wiki/Illuminant_D65) is used as reference white
@@ -52,14 +53,6 @@ Nice, but what's it useful for?
- Generating random colors under some constraints (e.g. colors of the same shade, or shades of one color.) - Generating random colors under some constraints (e.g. colors of the same shade, or shades of one color.)
- Generating gorgeous random palettes with distinct colors of a same temperature. - Generating gorgeous random palettes with distinct colors of a same temperature.
What not (yet)?
===============
There are a few features which are currently missing and might be useful.
I just haven't implemented them yet because I didn't have the need for it.
Pull requests welcome.
- Sorting colors (potentially using above mentioned distances)
So which colorspace should I use? So which colorspace should I use?
================================= =================================
It depends on what you want to do. I think the folks from *I want hue* are It depends on what you want to do. I think the folks from *I want hue* are
@@ -139,7 +132,7 @@ alpha colors, this means the RGB values are lost (set to 0) and it's impossible
to recover them. In such a case `MakeColor` will return `false` as its second value. to recover them. In such a case `MakeColor` will return `false` as its second value.
### Comparing colors ### Comparing colors
In the RGB color space, the Euclidian distance between colors *doesn't* correspond In the RGB color space, the Euclidean distance between colors *doesn't* correspond
to visual/perceptual distance. This means that two pairs of colors which have the to visual/perceptual distance. This means that two pairs of colors which have the
same distance in RGB space can look much further apart. This is fixed by the same distance in RGB space can look much further apart. This is fixed by the
CIE-L\*a\*b\*, CIE-L\*u\*v\* and CIE-L\*C\*h° color spaces. CIE-L\*a\*b\*, CIE-L\*u\*v\* and CIE-L\*C\*h° color spaces.
@@ -208,7 +201,7 @@ What you see is that HSV is really bad: it adds some green, which is not present
in the original colors at all! RGB is much better, but it stays light a little in the original colors at all! RGB is much better, but it stays light a little
too long. LUV and LAB both hit the right lightness but LAB has a little more too long. LUV and LAB both hit the right lightness but LAB has a little more
color. HCL works in the same vein as HSV (both cylindrical interpolations) but color. HCL works in the same vein as HSV (both cylindrical interpolations) but
it does it right in that there is no green appearing and the lighthness changes it does it right in that there is no green appearing and the lightness changes
in a linear manner. in a linear manner.
While this seems all good, you need to know one thing: When interpolating in any While this seems all good, you need to know one thing: When interpolating in any
@@ -316,11 +309,11 @@ generating this picture in `doc/colorgens/colorgens.go`.
### Getting random palettes ### Getting random palettes
As soon as you need to generate more than one random color, you probably want As soon as you need to generate more than one random color, you probably want
them to be distinguishible. Playing against an opponent which has almost the them to be distinguishable. Playing against an opponent which has almost the
same blue as I do is not fun. This is where random palettes can help. same blue as I do is not fun. This is where random palettes can help.
These palettes are generated using an algorithm which ensures that all colors These palettes are generated using an algorithm which ensures that all colors
on the palette are as distinguishible as possible. Again, there is a `Fast` on the palette are as distinguishable as possible. Again, there is a `Fast`
method which works in HSV and is less perceptually uniform and a non-`Fast` method which works in HSV and is less perceptually uniform and a non-`Fast`
method which works in CIE spaces. For more theory on `SoftPalette`, check out method which works in CIE spaces. For more theory on `SoftPalette`, check out
[I want hue](http://tools.medialab.sciences-po.fr/iwanthue/theory.php). Yet [I want hue](http://tools.medialab.sciences-po.fr/iwanthue/theory.php). Yet
@@ -372,10 +365,18 @@ from top to bottom: `Warm`, `FastWarm`, `Happy`, `FastHappy`, `Soft`,
Again, the code used for generating the above image is available as [doc/palettegens/palettegens.go](https://github.com/lucasb-eyer/go-colorful/blob/master/doc/palettegens/palettegens.go). Again, the code used for generating the above image is available as [doc/palettegens/palettegens.go](https://github.com/lucasb-eyer/go-colorful/blob/master/doc/palettegens/palettegens.go).
### Sorting colors ### Sorting colors
TODO: Sort using dist fn.
Sorting colors is not a well-defined operation. For example, {dark blue, dark red, light blue, light red} is already sorted if darker colors should precede lighter colors but would need to be re-sorted as {dark red, light red, dark blue, light blue} if longer-wavelength colors should precede shorter-wavelength colors.
Go-Colorful's `Sorted` function orders a list of colors so as to minimize the average distance between adjacent colors, including between the last and the first. (`Sorted` does not necessarily find the true minimum, only a reasonably close approximation.) The following picture, drawn by [doc/colorsort/colorsort.go](https://github.com/lucasb-eyer/go-colorful/blob/master/doc/colorsort/colorsort.go), illustrates `Sorted`'s behavior:
![Sorting colors](doc/colorsort/colorsort.png)
The first row represents the input: a slice of 512 randomly chosen colors. The second row shows the colors sorted in CIE-L\*C\*h° space, ordered first by lightness (L), then by hue angle (h), and finally by chroma (C). Note that distracting pinstripes permeate the colors. Sorting using *any* color space and *any* ordering of the channels yields a similar pinstriped pattern. The third row of the image was sorted using Go-Colorful's `Sorted` function. Although the colors do not appear to be in any particular order, the sequence at least appears smoother than the one sorted by channel.
### Using linear RGB for computations ### Using linear RGB for computations
There are two methods for transforming RGB<->Linear RGB: a fast and almost precise one, There are two methods for transforming RGBLinear RGB: a fast and almost precise one,
and a slow and precise one. and a slow and precise one.
```go ```go
@@ -472,9 +473,9 @@ Who?
==== ====
This library was developed by Lucas Beyer with contributions from This library was developed by Lucas Beyer with contributions from
Bastien Dejean (@baskerville), Phil Kulak (@pkulak) and Christian Muehlhaeuser (@muesli). Bastien Dejean (@baskerville), Phil Kulak (@pkulak), Christian Muehlhaeuser (@muesli), and Scott Pakin (@spakin).
It is now maintained by makeworld (@makeworld-the-better-one). It is now maintained by makeworld (@makew0rld).
## License ## License

View File

@@ -2,28 +2,32 @@
package colorful package colorful
import (
"math/rand"
)
// Creates a random dark, "warm" color through a restricted HSV space. // Creates a random dark, "warm" color through a restricted HSV space.
func FastWarmColor() Color { func FastWarmColorWithRand(rand RandInterface) Color {
return Hsv( return Hsv(
rand.Float64()*360.0, rand.Float64()*360.0,
0.5+rand.Float64()*0.3, 0.5+rand.Float64()*0.3,
0.3+rand.Float64()*0.3) 0.3+rand.Float64()*0.3)
} }
func FastWarmColor() Color {
return FastWarmColorWithRand(getDefaultGlobalRand())
}
// Creates a random dark, "warm" color through restricted HCL space. // Creates a random dark, "warm" color through restricted HCL space.
// This is slower than FastWarmColor but will likely give you colors which have // This is slower than FastWarmColor but will likely give you colors which have
// the same "warmness" if you run it many times. // the same "warmness" if you run it many times.
func WarmColor() (c Color) { func WarmColorWithRand(rand RandInterface) (c Color) {
for c = randomWarm(); !c.IsValid(); c = randomWarm() { for c = randomWarmWithRand(rand); !c.IsValid(); c = randomWarmWithRand(rand) {
} }
return return
} }
func randomWarm() Color { func WarmColor() (c Color) {
return WarmColorWithRand(getDefaultGlobalRand())
}
func randomWarmWithRand(rand RandInterface) Color {
return Hcl( return Hcl(
rand.Float64()*360.0, rand.Float64()*360.0,
0.1+rand.Float64()*0.3, 0.1+rand.Float64()*0.3,
@@ -31,23 +35,31 @@ func randomWarm() Color {
} }
// Creates a random bright, "pimpy" color through a restricted HSV space. // Creates a random bright, "pimpy" color through a restricted HSV space.
func FastHappyColor() Color { func FastHappyColorWithRand(rand RandInterface) Color {
return Hsv( return Hsv(
rand.Float64()*360.0, rand.Float64()*360.0,
0.7+rand.Float64()*0.3, 0.7+rand.Float64()*0.3,
0.6+rand.Float64()*0.3) 0.6+rand.Float64()*0.3)
} }
func FastHappyColor() Color {
return FastHappyColorWithRand(getDefaultGlobalRand())
}
// Creates a random bright, "pimpy" color through restricted HCL space. // Creates a random bright, "pimpy" color through restricted HCL space.
// This is slower than FastHappyColor but will likely give you colors which // This is slower than FastHappyColor but will likely give you colors which
// have the same "brightness" if you run it many times. // have the same "brightness" if you run it many times.
func HappyColor() (c Color) { func HappyColorWithRand(rand RandInterface) (c Color) {
for c = randomPimp(); !c.IsValid(); c = randomPimp() { for c = randomPimpWithRand(rand); !c.IsValid(); c = randomPimpWithRand(rand) {
} }
return return
} }
func randomPimp() Color { func HappyColor() (c Color) {
return HappyColorWithRand(getDefaultGlobalRand())
}
func randomPimpWithRand(rand RandInterface) Color {
return Hcl( return Hcl(
rand.Float64()*360.0, rand.Float64()*360.0,
0.5+rand.Float64()*0.3, 0.5+rand.Float64()*0.3,

View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"image/color" "image/color"
"math" "math"
"strconv"
) )
// A color is stored internally using sRGB (standard RGB) values in the range 0-1 // A color is stored internally using sRGB (standard RGB) values in the range 0-1
@@ -94,15 +95,39 @@ func (c1 Color) DistanceRgb(c2 Color) float64 {
return math.Sqrt(sq(c1.R-c2.R) + sq(c1.G-c2.G) + sq(c1.B-c2.B)) return math.Sqrt(sq(c1.R-c2.R) + sq(c1.G-c2.G) + sq(c1.B-c2.B))
} }
// DistanceLinearRGB computes the distance between two colors in linear RGB // DistanceLinearRgb computes the distance between two colors in linear RGB
// space. This is not useful for measuring how humans perceive color, but // space. This is not useful for measuring how humans perceive color, but
// might be useful for other things, like dithering. // might be useful for other things, like dithering.
func (c1 Color) DistanceLinearRGB(c2 Color) float64 { func (c1 Color) DistanceLinearRgb(c2 Color) float64 {
r1, g1, b1 := c1.LinearRgb() r1, g1, b1 := c1.LinearRgb()
r2, g2, b2 := c2.LinearRgb() r2, g2, b2 := c2.LinearRgb()
return math.Sqrt(sq(r1-r2) + sq(g1-g2) + sq(b1-b2)) return math.Sqrt(sq(r1-r2) + sq(g1-g2) + sq(b1-b2))
} }
// DistanceLinearRGB is deprecated in favour of DistanceLinearRgb.
// They do the exact same thing.
func (c1 Color) DistanceLinearRGB(c2 Color) float64 {
return c1.DistanceLinearRgb(c2)
}
// DistanceRiemersma is a color distance algorithm developed by Thiadmer Riemersma.
// It uses RGB coordinates, but he claims it has similar results to CIELUV.
// This makes it both fast and accurate.
//
// Sources:
//
// https://www.compuphase.com/cmetric.htm
// https://github.com/lucasb-eyer/go-colorful/issues/52
func (c1 Color) DistanceRiemersma(c2 Color) float64 {
rAvg := (c1.R + c2.R) / 2.0
// Deltas
dR := c1.R - c2.R
dG := c1.G - c2.G
dB := c1.B - c2.B
return math.Sqrt((2+rAvg)*dR*dR + 4*dG*dG + (2+(1-rAvg))*dB*dB)
}
// Check for equality between colors within the tolerance Delta (1/255). // Check for equality between colors within the tolerance Delta (1/255).
func (c1 Color) AlmostEqualRgb(c2 Color) bool { func (c1 Color) AlmostEqualRgb(c2 Color) bool {
return math.Abs(c1.R-c2.R)+ return math.Abs(c1.R-c2.R)+
@@ -112,9 +137,11 @@ func (c1 Color) AlmostEqualRgb(c2 Color) bool {
// You don't really want to use this, do you? Go for BlendLab, BlendLuv or BlendHcl. // You don't really want to use this, do you? Go for BlendLab, BlendLuv or BlendHcl.
func (c1 Color) BlendRgb(c2 Color, t float64) Color { func (c1 Color) BlendRgb(c2 Color, t float64) Color {
return Color{c1.R + t*(c2.R-c1.R), return Color{
c1.R + t*(c2.R-c1.R),
c1.G + t*(c2.G-c1.G), c1.G + t*(c2.G-c1.G),
c1.B + t*(c2.B-c1.B)} c1.B + t*(c2.B-c1.B),
}
} }
// Utility used by Hxx color-spaces for interpolating between two angles in [0,360]. // Utility used by Hxx color-spaces for interpolating between two angles in [0,360].
@@ -128,9 +155,9 @@ func interp_angle(a0, a1, t float64) float64 {
/// HSV /// /// HSV ///
/////////// ///////////
// From http://en.wikipedia.org/wiki/HSL_and_HSV // From http://en.wikipedia.org/wiki/HSL_and_HSV
// Note that h is in [0..360] and s,v in [0..1] // Note that h is in [0..359] and s,v in [0..1]
// Hsv returns the Hue [0..360], Saturation and Value [0..1] of the color. // Hsv returns the Hue [0..359], Saturation and Value [0..1] of the color.
func (col Color) Hsv() (h, s, v float64) { func (col Color) Hsv() (h, s, v float64) {
min := math.Min(math.Min(col.R, col.G), col.B) min := math.Min(math.Min(col.R, col.G), col.B)
v = math.Max(math.Max(col.R, col.G), col.B) v = math.Max(math.Max(col.R, col.G), col.B)
@@ -160,7 +187,7 @@ func (col Color) Hsv() (h, s, v float64) {
return return
} }
// Hsv creates a new Color given a Hue in [0..360], a Saturation and a Value in [0..1] // Hsv creates a new Color given a Hue in [0..359], a Saturation and a Value in [0..1]
func Hsv(H, S, V float64) Color { func Hsv(H, S, V float64) Color {
Hp := H / 60.0 Hp := H / 60.0
C := V * S C := V * S
@@ -198,6 +225,13 @@ func (c1 Color) BlendHsv(c2 Color, t float64) Color {
h1, s1, v1 := c1.Hsv() h1, s1, v1 := c1.Hsv()
h2, s2, v2 := c2.Hsv() h2, s2, v2 := c2.Hsv()
// https://github.com/lucasb-eyer/go-colorful/pull/60
if s1 == 0 && s2 != 0 {
h1 = h2
} else if s2 == 0 && s1 != 0 {
h2 = h1
}
// We know that h are both in [0..360] // We know that h are both in [0..360]
return Hsv(interp_angle(h1, h2, t), s1+t*(s2-s1), v1+t*(v2-v1)) return Hsv(interp_angle(h1, h2, t), s1+t*(s2-s1), v1+t*(v2-v1))
} }
@@ -205,7 +239,7 @@ func (c1 Color) BlendHsv(c2 Color, t float64) Color {
/// HSL /// /// HSL ///
/////////// ///////////
// Hsl returns the Hue [0..360], Saturation [0..1], and Luminance (lightness) [0..1] of the color. // Hsl returns the Hue [0..359], Saturation [0..1], and Luminance (lightness) [0..1] of the color.
func (col Color) Hsl() (h, s, l float64) { func (col Color) Hsl() (h, s, l float64) {
min := math.Min(math.Min(col.R, col.G), col.B) min := math.Min(math.Min(col.R, col.G), col.B)
max := math.Max(math.Max(col.R, col.G), col.B) max := math.Max(math.Max(col.R, col.G), col.B)
@@ -240,7 +274,7 @@ func (col Color) Hsl() (h, s, l float64) {
return return
} }
// Hsl creates a new Color given a Hue in [0..360], a Saturation [0..1], and a Luminance (lightness) in [0..1] // Hsl creates a new Color given a Hue in [0..359], a Saturation [0..1], and a Luminance (lightness) in [0..1]
func Hsl(h, s, l float64) Color { func Hsl(h, s, l float64) Color {
if s == 0 { if s == 0 {
return Color{l, l, l} return Color{l, l, l}
@@ -331,23 +365,46 @@ func (col Color) Hex() string {
// Hex parses a "html" hex color-string, either in the 3 "#f0c" or 6 "#ff1034" digits form. // Hex parses a "html" hex color-string, either in the 3 "#f0c" or 6 "#ff1034" digits form.
func Hex(scol string) (Color, error) { func Hex(scol string) (Color, error) {
format := "#%02x%02x%02x" if scol == "" || scol[0] != '#' {
factor := 1.0 / 255.0
if len(scol) == 4 {
format = "#%1x%1x%1x"
factor = 1.0 / 15.0
}
var r, g, b uint8
n, err := fmt.Sscanf(scol, format, &r, &g, &b)
if err != nil {
return Color{}, err
}
if n != 3 {
return Color{}, fmt.Errorf("color: %v is not a hex-color", scol) return Color{}, fmt.Errorf("color: %v is not a hex-color", scol)
} }
var c Color
var err error
switch len(scol) {
case 4:
c, err = parseHexColor(scol[1:2], scol[2:3], scol[3:4], 4, 1.0/15.0)
case 7:
c, err = parseHexColor(scol[1:3], scol[3:5], scol[5:7], 8, 1.0/255.0)
default:
return Color{}, fmt.Errorf("color: %v is not a hex-color", scol)
}
if err != nil {
return Color{}, fmt.Errorf("color: %v is not a hex-color: %w", scol, err)
}
return c, nil
}
return Color{float64(r) * factor, float64(g) * factor, float64(b) * factor}, nil func parseHexColor(r, g, b string, bits int, factor float64) (Color, error) {
var c Color
var v uint64
var err error
if v, err = strconv.ParseUint(r, 16, bits); err != nil {
return Color{}, err
}
c.R = float64(v) * factor
if v, err = strconv.ParseUint(g, 16, bits); err != nil {
return Color{}, err
}
c.G = float64(v) * factor
if v, err = strconv.ParseUint(b, 16, bits); err != nil {
return Color{}, err
}
c.B = float64(v) * factor
return c, err
} }
/// Linear /// /// Linear ///
@@ -377,7 +434,7 @@ func linearize_fast(v float64) float64 {
v2 := v1 * v1 v2 := v1 * v1
v3 := v2 * v1 v3 := v2 * v1
v4 := v2 * v2 v4 := v2 * v2
//v5 := v3*v2 // v5 := v3*v2
return -0.248750514614486 + 0.925583310193438*v + 1.16740237321695*v2 + 0.280457026598666*v3 - 0.0757991963780179*v4 //+ 0.0437040411548932*v5 return -0.248750514614486 + 0.925583310193438*v + 1.16740237321695*v2 + 0.280457026598666*v3 - 0.0757991963780179*v4 //+ 0.0437040411548932*v5
} }
@@ -450,6 +507,19 @@ func LinearRgbToXyz(r, g, b float64) (x, y, z float64) {
return return
} }
// BlendLinearRgb blends two colors in the Linear RGB color-space.
// Unlike BlendRgb, this will not produce dark color around the center.
// t == 0 results in c1, t == 1 results in c2
func (c1 Color) BlendLinearRgb(c2 Color, t float64) Color {
r1, g1, b1 := c1.LinearRgb()
r2, g2, b2 := c2.LinearRgb()
return LinearRgb(
r1+t*(r2-r1),
g1+t*(g2-g1),
b1+t*(b2-b1),
)
}
/// XYZ /// /// XYZ ///
/////////// ///////////
// http://www.sjbrown.co.uk/2004/05/14/gamma-correct-rendering/ // http://www.sjbrown.co.uk/2004/05/14/gamma-correct-rendering/
@@ -784,7 +854,7 @@ func LuvToXyz(l, u, v float64) (x, y, z float64) {
} }
func LuvToXyzWhiteRef(l, u, v float64, wref [3]float64) (x, y, z float64) { func LuvToXyzWhiteRef(l, u, v float64, wref [3]float64) (x, y, z float64) {
//y = wref[1] * lab_finv((l + 0.16) / 1.16) // y = wref[1] * lab_finv((l + 0.16) / 1.16)
if l <= 0.08 { if l <= 0.08 {
y = wref[1] * l * 100.0 * 3.0 / 29.0 * 3.0 / 29.0 * 3.0 / 29.0 y = wref[1] * l * 100.0 * 3.0 / 29.0 * 3.0 / 29.0 * 3.0 / 29.0
} else { } else {
@@ -913,6 +983,13 @@ func (col1 Color) BlendHcl(col2 Color, t float64) Color {
h1, c1, l1 := col1.Hcl() h1, c1, l1 := col1.Hcl()
h2, c2, l2 := col2.Hcl() h2, c2, l2 := col2.Hcl()
// https://github.com/lucasb-eyer/go-colorful/pull/60
if c1 <= 0.00015 && c2 >= 0.00015 {
h1 = h2
} else if c2 <= 0.00015 && c1 >= 0.00015 {
h2 = h1
}
// We know that h are both in [0..360] // We know that h are both in [0..360]
return Hcl(interp_angle(h1, h2, t), c1+t*(c2-c1), l1+t*(l2-l1)).Clamped() return Hcl(interp_angle(h1, h2, t), c1+t*(c2-c1), l1+t*(l2-l1)).Clamped()
} }
@@ -977,3 +1054,103 @@ func (col1 Color) BlendLuvLCh(col2 Color, t float64) Color {
// We know that h are both in [0..360] // We know that h are both in [0..360]
return LuvLCh(l1+t*(l2-l1), c1+t*(c2-c1), interp_angle(h1, h2, t)) return LuvLCh(l1+t*(l2-l1), c1+t*(c2-c1), interp_angle(h1, h2, t))
} }
/// OkLab ///
///////////
func (col Color) OkLab() (l, a, b float64) {
return XyzToOkLab(col.Xyz())
}
func OkLab(l, a, b float64) Color {
return Xyz(OkLabToXyz(l, a, b))
}
func XyzToOkLab(x, y, z float64) (l, a, b float64) {
l_ := math.Cbrt(0.8189330101*x + 0.3618667424*y - 0.1288597137*z)
m_ := math.Cbrt(0.0329845436*x + 0.9293118715*y + 0.0361456387*z)
s_ := math.Cbrt(0.0482003018*x + 0.2643662691*y + 0.6338517070*z)
l = 0.2104542553*l_ + 0.7936177850*m_ - 0.0040720468*s_
a = 1.9779984951*l_ - 2.4285922050*m_ + 0.4505937099*s_
b = 0.0259040371*l_ + 0.7827717662*m_ - 0.8086757660*s_
return
}
func OkLabToXyz(l, a, b float64) (x, y, z float64) {
l_ := 0.9999999984505196*l + 0.39633779217376774*a + 0.2158037580607588*b
m_ := 1.0000000088817607*l - 0.10556134232365633*a - 0.0638541747717059*b
s_ := 1.0000000546724108*l - 0.08948418209496574*a - 1.2914855378640917*b
ll := math.Pow(l_, 3)
m := math.Pow(m_, 3)
s := math.Pow(s_, 3)
x = 1.2268798733741557*ll - 0.5578149965554813*m + 0.28139105017721594*s
y = -0.04057576262431372*ll + 1.1122868293970594*m - 0.07171106666151696*s
z = -0.07637294974672142*ll - 0.4214933239627916*m + 1.5869240244272422*s
return
}
// BlendOkLab blends two colors in the OkLab color-space, which should result in a better blend (even compared to BlendLab).
func (c1 Color) BlendOkLab(c2 Color, t float64) Color {
l1, a1, b1 := c1.OkLab()
l2, a2, b2 := c2.OkLab()
return OkLab(l1+t*(l2-l1),
a1+t*(a2-a1),
b1+t*(b2-b1))
}
/// OkLch ///
///////////
func (col Color) OkLch() (l, c, h float64) {
return OkLabToOkLch(col.OkLab())
}
func OkLch(l, c, h float64) Color {
return Xyz(OkLchToXyz(l, c, h))
}
func XyzToOkLch(x, y, z float64) (float64, float64, float64) {
l, c, h := OkLabToOkLch(XyzToOkLab(x, y, z))
return l, c, h
}
func OkLchToXyz(l, c, h float64) (float64, float64, float64) {
x, y, z := OkLabToXyz(OkLchToOkLab(l, c, h))
return x, y, z
}
func OkLabToOkLch(l, a, b float64) (float64, float64, float64) {
c := math.Sqrt((a * a) + (b * b))
h := math.Atan2(b, a)
if h < 0 {
h += 2 * math.Pi
}
return l, c, h * 180 / math.Pi
}
func OkLchToOkLab(l, c, h float64) (float64, float64, float64) {
h *= math.Pi / 180
a := c * math.Cos(h)
b := c * math.Sin(h)
return l, a, b
}
// BlendOkLch blends two colors in the OkLch color-space, which should result in a better blend (even compared to BlendHcl).
func (col1 Color) BlendOkLch(col2 Color, t float64) Color {
l1, c1, h1 := col1.OkLch()
l2, c2, h2 := col2.OkLch()
// https://github.com/lucasb-eyer/go-colorful/pull/60
if c1 <= 0.00015 && c2 >= 0.00015 {
h1 = h2
} else if c2 <= 0.00015 && c1 >= 0.00015 {
h2 = h1
}
// We know that h are both in [0..360]
return OkLch(l1+t*(l2-l1), c1+t*(c2-c1), interp_angle(h1, h2, t)).Clamped()
}

View File

@@ -1,13 +1,9 @@
package colorful package colorful
import (
"math/rand"
)
// Uses the HSV color space to generate colors with similar S,V but distributed // Uses the HSV color space to generate colors with similar S,V but distributed
// evenly along their Hue. This is fast but not always pretty. // evenly along their Hue. This is fast but not always pretty.
// If you've got time to spare, use Lab (the non-fast below). // If you've got time to spare, use Lab (the non-fast below).
func FastHappyPalette(colorsCount int) (colors []Color) { func FastHappyPaletteWithRand(colorsCount int, rand RandInterface) (colors []Color) {
colors = make([]Color, colorsCount) colors = make([]Color, colorsCount)
for i := 0; i < colorsCount; i++ { for i := 0; i < colorsCount; i++ {
@@ -16,10 +12,18 @@ func FastHappyPalette(colorsCount int) (colors []Color) {
return return
} }
func HappyPalette(colorsCount int) ([]Color, error) { func FastHappyPalette(colorsCount int) (colors []Color) {
return FastHappyPaletteWithRand(colorsCount, getDefaultGlobalRand())
}
func HappyPaletteWithRand(colorsCount int, rand RandInterface) ([]Color, error) {
pimpy := func(l, a, b float64) bool { pimpy := func(l, a, b float64) bool {
_, c, _ := LabToHcl(l, a, b) _, c, _ := LabToHcl(l, a, b)
return 0.3 <= c && 0.4 <= l && l <= 0.8 return 0.3 <= c && 0.4 <= l && l <= 0.8
} }
return SoftPaletteEx(colorsCount, SoftPaletteSettings{pimpy, 50, true}) return SoftPaletteExWithRand(colorsCount, SoftPaletteSettings{pimpy, 50, true}, rand)
}
func HappyPalette(colorsCount int) ([]Color, error) {
return HappyPaletteWithRand(colorsCount, getDefaultGlobalRand())
} }

View File

@@ -65,3 +65,23 @@ func (hc *HexColor) Decode(hexCode string) error {
*hc = HexColor(col) *hc = HexColor(col)
return nil return nil
} }
func (hc HexColor) MarshalYAML() (interface{}, error) {
return Color(hc).Hex(), nil
}
func (hc *HexColor) UnmarshalYAML(unmarshal func(interface{}) error) error {
var hexCode string
if err := unmarshal(&hexCode); err != nil {
return err
}
var col, err = Hex(hexCode)
if err != nil {
return err
}
*hc = HexColor(col)
return nil
}

View File

@@ -11,7 +11,8 @@ import "math"
// comparing to the test values, this modified white reference is used internally. // comparing to the test values, this modified white reference is used internally.
// //
// See this GitHub thread for details on these values: // See this GitHub thread for details on these values:
// https://github.com/hsluv/hsluv/issues/79 //
// https://github.com/hsluv/hsluv/issues/79
var hSLuvD65 = [3]float64{0.95045592705167, 1.0, 1.089057750759878} var hSLuvD65 = [3]float64{0.95045592705167, 1.0, 1.089057750759878}
func LuvLChToHSLuv(l, c, h float64) (float64, float64, float64) { func LuvLChToHSLuv(l, c, h float64) (float64, float64, float64) {
@@ -115,7 +116,7 @@ func (col Color) HPLuv() (h, s, l float64) {
return LuvLChToHPLuv(col.LuvLChWhiteRef(hSLuvD65)) return LuvLChToHPLuv(col.LuvLChWhiteRef(hSLuvD65))
} }
// DistanceHSLuv calculates Euclidan distance in the HSLuv colorspace. No idea // DistanceHSLuv calculates Euclidean distance in the HSLuv colorspace. No idea
// how useful this is. // how useful this is.
// //
// The Hue value is divided by 100 before the calculation, so that H, S, and L // The Hue value is divided by 100 before the calculation, so that H, S, and L

22
vendor/github.com/lucasb-eyer/go-colorful/rand.go generated vendored Normal file
View File

@@ -0,0 +1,22 @@
package colorful
import "math/rand"
type RandInterface interface {
Float64() float64
Intn(n int) int
}
type defaultGlobalRand struct{}
func (df defaultGlobalRand) Float64() float64 {
return rand.Float64()
}
func (df defaultGlobalRand) Intn(n int) int {
return rand.Intn(n)
}
func getDefaultGlobalRand() RandInterface {
return defaultGlobalRand{}
}

View File

@@ -6,7 +6,6 @@ package colorful
import ( import (
"fmt" "fmt"
"math" "math"
"math/rand"
) )
// The algorithm works in L*a*b* color space and converts to RGB in the end. // The algorithm works in L*a*b* color space and converts to RGB in the end.
@@ -32,7 +31,7 @@ type SoftPaletteSettings struct {
// as a new palette of distinctive colors. Falls back to K-medoid if the mean // as a new palette of distinctive colors. Falls back to K-medoid if the mean
// happens to fall outside of the color-space, which can only happen if you // happens to fall outside of the color-space, which can only happen if you
// specify a CheckColor function. // specify a CheckColor function.
func SoftPaletteEx(colorsCount int, settings SoftPaletteSettings) ([]Color, error) { func SoftPaletteExWithRand(colorsCount int, settings SoftPaletteSettings, rand RandInterface) ([]Color, error) {
// Checks whether it's a valid RGB and also fulfills the potentially provided constraint. // Checks whether it's a valid RGB and also fulfills the potentially provided constraint.
check := func(col lab_t) bool { check := func(col lab_t) bool {
@@ -79,7 +78,7 @@ func SoftPaletteEx(colorsCount int, settings SoftPaletteSettings) ([]Color, erro
// The actual k-means/medoid iterations // The actual k-means/medoid iterations
for i := 0; i < settings.Iterations; i++ { for i := 0; i < settings.Iterations; i++ {
// Reassing the samples to clusters, i.e. to their closest mean. // Reassigning the samples to clusters, i.e. to their closest mean.
// By the way, also check if any sample is used as a medoid and if so, mark that. // By the way, also check if any sample is used as a medoid and if so, mark that.
for isample, sample := range samples { for isample, sample := range samples {
samples_used[isample] = false samples_used[isample] = false
@@ -100,7 +99,7 @@ func SoftPaletteEx(colorsCount int, settings SoftPaletteSettings) ([]Color, erro
// Compute new means according to the samples. // Compute new means according to the samples.
for imean := range means { for imean := range means {
// The new mean is the average of all samples belonging to it.. // The new mean is the average of all samples belonging to it.
nsamples := 0 nsamples := 0
newmean := lab_t{0.0, 0.0, 0.0} newmean := lab_t{0.0, 0.0, 0.0}
for isample, sample := range samples { for isample, sample := range samples {
@@ -148,9 +147,17 @@ func SoftPaletteEx(colorsCount int, settings SoftPaletteSettings) ([]Color, erro
return labs2cols(means), nil return labs2cols(means), nil
} }
func SoftPaletteEx(colorsCount int, settings SoftPaletteSettings) ([]Color, error) {
return SoftPaletteExWithRand(colorsCount, settings, getDefaultGlobalRand())
}
// A wrapper which uses common parameters. // A wrapper which uses common parameters.
func SoftPaletteWithRand(colorsCount int, rand RandInterface) ([]Color, error) {
return SoftPaletteExWithRand(colorsCount, SoftPaletteSettings{nil, 50, false}, rand)
}
func SoftPalette(colorsCount int) ([]Color, error) { func SoftPalette(colorsCount int) ([]Color, error) {
return SoftPaletteEx(colorsCount, SoftPaletteSettings{nil, 50, false}) return SoftPaletteWithRand(colorsCount, getDefaultGlobalRand())
} }
func in(haystack []lab_t, upto int, needle lab_t) bool { func in(haystack []lab_t, upto int, needle lab_t) bool {

191
vendor/github.com/lucasb-eyer/go-colorful/sort.go generated vendored Normal file
View File

@@ -0,0 +1,191 @@
// This file provides functions for sorting colors.
package colorful
import (
"math"
"sort"
)
// An element represents a single element of a set. It is used to
// implement a disjoint-set forest.
type element struct {
parent *element // Parent element
rank int // Rank (approximate depth) of the subtree with this element as root
}
// newElement creates a singleton set and returns its sole element.
func newElement() *element {
s := &element{}
s.parent = s
return s
}
// find returns an arbitrary element of a set when invoked on any element of
// the set, The important feature is that it returns the same value when
// invoked on any element of the set. Consequently, it can be used to test if
// two elements belong to the same set.
func (e *element) find() *element {
for e.parent != e {
e.parent = e.parent.parent
e = e.parent
}
return e
}
// union establishes the union of two sets when given an element from each set.
// Afterwards, the original sets no longer exist as separate entities.
func union(e1, e2 *element) {
// Ensure the two elements aren't already part of the same union.
e1Root := e1.find()
e2Root := e2.find()
if e1Root == e2Root {
return
}
// Create a union by making the shorter tree point to the root of the
// larger tree.
switch {
case e1Root.rank < e2Root.rank:
e1Root.parent = e2Root
case e1Root.rank > e2Root.rank:
e2Root.parent = e1Root
default:
e2Root.parent = e1Root
e1Root.rank++
}
}
// An edgeIdxs describes an edge in a graph or tree. The vertices in the edge
// are indexes into a list of Color values.
type edgeIdxs [2]int
// An edgeDistance is a map from an edge (pair of indices) to a distance
// between the two vertices.
type edgeDistance map[edgeIdxs]float64
// allToAllDistancesCIEDE2000 computes the CIEDE2000 distance between each pair of
// colors. It returns a map from a pair of indices (u, v) with u < v to a
// distance.
func allToAllDistancesCIEDE2000(cs []Color) edgeDistance {
nc := len(cs)
m := make(edgeDistance, nc*nc)
for u := 0; u < nc-1; u++ {
for v := u + 1; v < nc; v++ {
m[edgeIdxs{u, v}] = cs[u].DistanceCIEDE2000(cs[v])
}
}
return m
}
// sortEdges sorts all edges in a distance map by increasing vertex distance.
func sortEdges(m edgeDistance) []edgeIdxs {
es := make([]edgeIdxs, 0, len(m))
for uv := range m {
es = append(es, uv)
}
sort.Slice(es, func(i, j int) bool {
return m[es[i]] < m[es[j]]
})
return es
}
// minSpanTree computes a minimum spanning tree from a vertex count and a
// distance-sorted edge list. It returns the subset of edges that belong to
// the tree, including both (u, v) and (v, u) for each edge.
func minSpanTree(nc int, es []edgeIdxs) map[edgeIdxs]struct{} {
// Start with each vertex in its own set.
elts := make([]*element, nc)
for i := range elts {
elts[i] = newElement()
}
// Run Kruskal's algorithm to construct a minimal spanning tree.
mst := make(map[edgeIdxs]struct{}, nc)
for _, uv := range es {
u, v := uv[0], uv[1]
if elts[u].find() == elts[v].find() {
continue // Same set: edge would introduce a cycle.
}
mst[uv] = struct{}{}
mst[edgeIdxs{v, u}] = struct{}{}
union(elts[u], elts[v])
}
return mst
}
// traverseMST walks a minimum spanning tree in prefix order.
func traverseMST(mst map[edgeIdxs]struct{}, root int) []int {
// Compute a list of neighbors for each vertex.
neighs := make(map[int][]int, len(mst))
for uv := range mst {
u, v := uv[0], uv[1]
neighs[u] = append(neighs[u], v)
}
for u, vs := range neighs {
sort.Ints(vs)
copy(neighs[u], vs)
}
// Walk the tree from a given vertex.
order := make([]int, 0, len(neighs))
visited := make(map[int]bool, len(neighs))
var walkFrom func(int)
walkFrom = func(r int) {
// Visit the starting vertex.
order = append(order, r)
visited[r] = true
// Recursively visit each child in turn.
for _, c := range neighs[r] {
if !visited[c] {
walkFrom(c)
}
}
}
walkFrom(root)
return order
}
// Sorted sorts a list of Color values. Sorting is not a well-defined operation
// for colors so the intention here primarily is to order colors so that the
// transition from one to the next is fairly smooth.
func Sorted(cs []Color) []Color {
// Do nothing in trivial cases.
newCs := make([]Color, len(cs))
if len(cs) < 2 {
copy(newCs, cs)
return newCs
}
// Compute the distance from each color to every other color.
dists := allToAllDistancesCIEDE2000(cs)
// Produce a list of edges in increasing order of the distance between
// their vertices.
edges := sortEdges(dists)
// Construct a minimum spanning tree from the list of edges.
mst := minSpanTree(len(cs), edges)
// Find the darkest color in the list.
var black Color
var dIdx int // Index of darkest color
light := math.MaxFloat64 // Lightness of darkest color (distance from black)
for i, c := range cs {
d := black.DistanceCIEDE2000(c)
if d < light {
dIdx = i
light = d
}
}
// Traverse the tree starting from the darkest color.
idxs := traverseMST(mst, dIdx)
// Convert the index list to a list of colors, overwriting the input.
for i, idx := range idxs {
newCs[i] = cs[idx]
}
return newCs
}

View File

@@ -1,13 +1,9 @@
package colorful package colorful
import (
"math/rand"
)
// Uses the HSV color space to generate colors with similar S,V but distributed // Uses the HSV color space to generate colors with similar S,V but distributed
// evenly along their Hue. This is fast but not always pretty. // evenly along their Hue. This is fast but not always pretty.
// If you've got time to spare, use Lab (the non-fast below). // If you've got time to spare, use Lab (the non-fast below).
func FastWarmPalette(colorsCount int) (colors []Color) { func FastWarmPaletteWithRand(colorsCount int, rand RandInterface) (colors []Color) {
colors = make([]Color, colorsCount) colors = make([]Color, colorsCount)
for i := 0; i < colorsCount; i++ { for i := 0; i < colorsCount; i++ {
@@ -16,10 +12,18 @@ func FastWarmPalette(colorsCount int) (colors []Color) {
return return
} }
func WarmPalette(colorsCount int) ([]Color, error) { func FastWarmPalette(colorsCount int) (colors []Color) {
return FastWarmPaletteWithRand(colorsCount, getDefaultGlobalRand())
}
func WarmPaletteWithRand(colorsCount int, rand RandInterface) ([]Color, error) {
warmy := func(l, a, b float64) bool { warmy := func(l, a, b float64) bool {
_, c, _ := LabToHcl(l, a, b) _, c, _ := LabToHcl(l, a, b)
return 0.1 <= c && c <= 0.4 && 0.2 <= l && l <= 0.5 return 0.1 <= c && c <= 0.4 && 0.2 <= l && l <= 0.5
} }
return SoftPaletteEx(colorsCount, SoftPaletteSettings{warmy, 50, true}) return SoftPaletteExWithRand(colorsCount, SoftPaletteSettings{warmy, 50, true}, rand)
}
func WarmPalette(colorsCount int) ([]Color, error) {
return WarmPaletteWithRand(colorsCount, getDefaultGlobalRand())
} }

43
vendor/github.com/mattn/go-runewidth/benchstat.txt generated vendored Normal file
View File

@@ -0,0 +1,43 @@
goos: darwin
goarch: arm64
pkg: github.com/mattn/go-runewidth
cpu: Apple M2
│ old.txt │ new.txt │
│ sec/op │ sec/op vs base │
String1WidthAll/regular-8 108.92m ± 0% 35.09m ± 3% -67.78% (p=0.002 n=6)
String1WidthAll/lut-8 93.97m ± 0% 18.70m ± 0% -80.10% (p=0.002 n=6)
String1Width768/regular-8 60.62µ ± 1% 11.54µ ± 0% -80.97% (p=0.002 n=6)
String1Width768/lut-8 60.66µ ± 1% 11.43µ ± 0% -81.16% (p=0.002 n=6)
String1WidthAllEastAsian/regular-8 115.13m ± 1% 40.79m ± 8% -64.57% (p=0.002 n=6)
String1WidthAllEastAsian/lut-8 93.65m ± 0% 18.70m ± 2% -80.03% (p=0.002 n=6)
String1Width768EastAsian/regular-8 75.32µ ± 0% 23.49µ ± 0% -68.82% (p=0.002 n=6)
String1Width768EastAsian/lut-8 60.76µ ± 0% 11.50µ ± 0% -81.07% (p=0.002 n=6)
geomean 2.562m 604.5µ -76.41%
│ old.txt │ new.txt │
│ B/op │ B/op vs base │
String1WidthAll/regular-8 106.3Mi ± 0% 0.0Mi ± 0% -100.00% (p=0.002 n=6)
String1WidthAll/lut-8 106.3Mi ± 0% 0.0Mi ± 0% -100.00% (p=0.002 n=6)
String1Width768/regular-8 75.00Ki ± 0% 0.00Ki ± 0% -100.00% (p=0.002 n=6)
String1Width768/lut-8 75.00Ki ± 0% 0.00Ki ± 0% -100.00% (p=0.002 n=6)
String1WidthAllEastAsian/regular-8 106.3Mi ± 0% 0.0Mi ± 0% -100.00% (p=0.002 n=6)
String1WidthAllEastAsian/lut-8 106.3Mi ± 0% 0.0Mi ± 0% -100.00% (p=0.002 n=6)
String1Width768EastAsian/regular-8 75.00Ki ± 0% 0.00Ki ± 0% -100.00% (p=0.002 n=6)
String1Width768EastAsian/lut-8 75.00Ki ± 0% 0.00Ki ± 0% -100.00% (p=0.002 n=6)
geomean 2.790Mi ? ¹ ²
¹ summaries must be >0 to compute geomean
² ratios must be >0 to compute geomean
│ old.txt │ new.txt │
│ allocs/op │ allocs/op vs base │
String1WidthAll/regular-8 3.342M ± 0% 0.000M ± 0% -100.00% (p=0.002 n=6)
String1WidthAll/lut-8 3.342M ± 0% 0.000M ± 0% -100.00% (p=0.002 n=6)
String1Width768/regular-8 2.304k ± 0% 0.000k ± 0% -100.00% (p=0.002 n=6)
String1Width768/lut-8 2.304k ± 0% 0.000k ± 0% -100.00% (p=0.002 n=6)
String1WidthAllEastAsian/regular-8 3.342M ± 0% 0.000M ± 0% -100.00% (p=0.002 n=6)
String1WidthAllEastAsian/lut-8 3.342M ± 0% 0.000M ± 0% -100.00% (p=0.002 n=6)
String1Width768EastAsian/regular-8 2.304k ± 0% 0.000k ± 0% -100.00% (p=0.002 n=6)
String1Width768EastAsian/lut-8 2.304k ± 0% 0.000k ± 0% -100.00% (p=0.002 n=6)
geomean 87.75k ? ¹ ²
¹ summaries must be >0 to compute geomean
² ratios must be >0 to compute geomean

54
vendor/github.com/mattn/go-runewidth/new.txt generated vendored Normal file
View File

@@ -0,0 +1,54 @@
goos: darwin
goarch: arm64
pkg: github.com/mattn/go-runewidth
cpu: Apple M2
BenchmarkString1WidthAll/regular-8 33 35033923 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAll/regular-8 33 34965112 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAll/regular-8 33 36307234 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAll/regular-8 33 35007705 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAll/regular-8 33 35154182 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAll/regular-8 34 35155400 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAll/lut-8 63 18688500 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAll/lut-8 63 18712474 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAll/lut-8 63 18700211 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAll/lut-8 62 18694179 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAll/lut-8 62 18708392 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAll/lut-8 63 18770608 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768/regular-8 104137 11526 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768/regular-8 103986 11540 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768/regular-8 104079 11552 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768/regular-8 103963 11530 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768/regular-8 103714 11538 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768/regular-8 104181 11537 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768/lut-8 105150 11420 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768/lut-8 104778 11423 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768/lut-8 105069 11422 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768/lut-8 105127 11475 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768/lut-8 104742 11433 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768/lut-8 105163 11432 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAllEastAsian/regular-8 28 40723347 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAllEastAsian/regular-8 28 40790299 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAllEastAsian/regular-8 28 40801338 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAllEastAsian/regular-8 28 40798216 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAllEastAsian/regular-8 28 44135253 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAllEastAsian/regular-8 28 40779546 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAllEastAsian/lut-8 62 18694165 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAllEastAsian/lut-8 62 18685047 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAllEastAsian/lut-8 62 18689273 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAllEastAsian/lut-8 62 19150346 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAllEastAsian/lut-8 63 19126154 ns/op 0 B/op 0 allocs/op
BenchmarkString1WidthAllEastAsian/lut-8 62 18712619 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768EastAsian/regular-8 50775 23595 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768EastAsian/regular-8 51061 23563 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768EastAsian/regular-8 51057 23492 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768EastAsian/regular-8 51138 23445 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768EastAsian/regular-8 51195 23469 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768EastAsian/regular-8 51087 23482 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768EastAsian/lut-8 104559 11549 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768EastAsian/lut-8 104508 11483 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768EastAsian/lut-8 104296 11503 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768EastAsian/lut-8 104606 11485 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768EastAsian/lut-8 104588 11495 ns/op 0 B/op 0 allocs/op
BenchmarkString1Width768EastAsian/lut-8 104602 11518 ns/op 0 B/op 0 allocs/op
PASS
ok github.com/mattn/go-runewidth 64.455s

54
vendor/github.com/mattn/go-runewidth/old.txt generated vendored Normal file
View File

@@ -0,0 +1,54 @@
goos: darwin
goarch: arm64
pkg: github.com/mattn/go-runewidth
cpu: Apple M2
BenchmarkString1WidthAll/regular-8 10 108559258 ns/op 111412145 B/op 3342342 allocs/op
BenchmarkString1WidthAll/regular-8 10 108968079 ns/op 111412364 B/op 3342343 allocs/op
BenchmarkString1WidthAll/regular-8 10 108890338 ns/op 111412388 B/op 3342344 allocs/op
BenchmarkString1WidthAll/regular-8 10 108940704 ns/op 111412584 B/op 3342346 allocs/op
BenchmarkString1WidthAll/regular-8 10 108632796 ns/op 111412348 B/op 3342343 allocs/op
BenchmarkString1WidthAll/regular-8 10 109354546 ns/op 111412777 B/op 3342343 allocs/op
BenchmarkString1WidthAll/lut-8 12 93844406 ns/op 111412569 B/op 3342345 allocs/op
BenchmarkString1WidthAll/lut-8 12 93991080 ns/op 111412512 B/op 3342344 allocs/op
BenchmarkString1WidthAll/lut-8 12 93980632 ns/op 111412413 B/op 3342343 allocs/op
BenchmarkString1WidthAll/lut-8 12 94004083 ns/op 111412396 B/op 3342343 allocs/op
BenchmarkString1WidthAll/lut-8 12 93959795 ns/op 111412445 B/op 3342343 allocs/op
BenchmarkString1WidthAll/lut-8 12 93846198 ns/op 111412556 B/op 3342345 allocs/op
BenchmarkString1Width768/regular-8 19785 60696 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768/regular-8 19824 60520 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768/regular-8 19832 60547 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768/regular-8 19778 60543 ns/op 76800 B/op 2304 allocs/op
BenchmarkString1Width768/regular-8 19842 61142 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768/regular-8 19780 60696 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768/lut-8 19598 61161 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768/lut-8 19731 60707 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768/lut-8 19738 60626 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768/lut-8 19764 60670 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768/lut-8 19797 60642 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768/lut-8 19738 60608 ns/op 76800 B/op 2304 allocs/op
BenchmarkString1WidthAllEastAsian/regular-8 9 115080431 ns/op 111412458 B/op 3342345 allocs/op
BenchmarkString1WidthAllEastAsian/regular-8 9 114908880 ns/op 111412476 B/op 3342345 allocs/op
BenchmarkString1WidthAllEastAsian/regular-8 9 115077134 ns/op 111412540 B/op 3342345 allocs/op
BenchmarkString1WidthAllEastAsian/regular-8 9 115175292 ns/op 111412467 B/op 3342345 allocs/op
BenchmarkString1WidthAllEastAsian/regular-8 9 115792653 ns/op 111412362 B/op 3342344 allocs/op
BenchmarkString1WidthAllEastAsian/regular-8 9 115255417 ns/op 111412572 B/op 3342346 allocs/op
BenchmarkString1WidthAllEastAsian/lut-8 12 93761542 ns/op 111412538 B/op 3342345 allocs/op
BenchmarkString1WidthAllEastAsian/lut-8 12 94089990 ns/op 111412440 B/op 3342343 allocs/op
BenchmarkString1WidthAllEastAsian/lut-8 12 93721410 ns/op 111412514 B/op 3342344 allocs/op
BenchmarkString1WidthAllEastAsian/lut-8 12 93572951 ns/op 111412329 B/op 3342342 allocs/op
BenchmarkString1WidthAllEastAsian/lut-8 12 93536052 ns/op 111412206 B/op 3342341 allocs/op
BenchmarkString1WidthAllEastAsian/lut-8 12 93532365 ns/op 111412412 B/op 3342343 allocs/op
BenchmarkString1Width768EastAsian/regular-8 15904 75401 ns/op 76800 B/op 2304 allocs/op
BenchmarkString1Width768EastAsian/regular-8 15932 75449 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768EastAsian/regular-8 15944 75181 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768EastAsian/regular-8 15963 75311 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768EastAsian/regular-8 15879 75292 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768EastAsian/regular-8 15955 75334 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768EastAsian/lut-8 19692 60692 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768EastAsian/lut-8 19712 60699 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768EastAsian/lut-8 19741 60819 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768EastAsian/lut-8 19771 60653 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768EastAsian/lut-8 19737 61027 ns/op 76801 B/op 2304 allocs/op
BenchmarkString1Width768EastAsian/lut-8 19657 60820 ns/op 76801 B/op 2304 allocs/op
PASS
ok github.com/mattn/go-runewidth 76.165s

View File

@@ -4,7 +4,7 @@ import (
"os" "os"
"strings" "strings"
"github.com/rivo/uniseg" "github.com/clipperhouse/uax29/v2/graphemes"
) )
//go:generate go run script/generate.go //go:generate go run script/generate.go
@@ -64,6 +64,9 @@ func inTable(r rune, t table) bool {
if r < t[0].first { if r < t[0].first {
return false return false
} }
if r > t[len(t)-1].last {
return false
}
bot := 0 bot := 0
top := len(t) - 1 top := len(t) - 1
@@ -175,10 +178,10 @@ func (c *Condition) CreateLUT() {
// StringWidth return width as you can see // StringWidth return width as you can see
func (c *Condition) StringWidth(s string) (width int) { func (c *Condition) StringWidth(s string) (width int) {
g := uniseg.NewGraphemes(s) g := graphemes.FromString(s)
for g.Next() { for g.Next() {
var chWidth int var chWidth int
for _, r := range g.Runes() { for _, r := range g.Value() {
chWidth = c.RuneWidth(r) chWidth = c.RuneWidth(r)
if chWidth > 0 { if chWidth > 0 {
break // Our best guess at this point is to use the width of the first non-zero-width rune. break // Our best guess at this point is to use the width of the first non-zero-width rune.
@@ -197,17 +200,17 @@ func (c *Condition) Truncate(s string, w int, tail string) string {
w -= c.StringWidth(tail) w -= c.StringWidth(tail)
var width int var width int
pos := len(s) pos := len(s)
g := uniseg.NewGraphemes(s) g := graphemes.FromString(s)
for g.Next() { for g.Next() {
var chWidth int var chWidth int
for _, r := range g.Runes() { for _, r := range g.Value() {
chWidth = c.RuneWidth(r) chWidth = c.RuneWidth(r)
if chWidth > 0 { if chWidth > 0 {
break // See StringWidth() for details. break // See StringWidth() for details.
} }
} }
if width+chWidth > w { if width+chWidth > w {
pos, _ = g.Positions() pos = g.Start()
break break
} }
width += chWidth width += chWidth
@@ -224,10 +227,10 @@ func (c *Condition) TruncateLeft(s string, w int, prefix string) string {
var width int var width int
pos := len(s) pos := len(s)
g := uniseg.NewGraphemes(s) g := graphemes.FromString(s)
for g.Next() { for g.Next() {
var chWidth int var chWidth int
for _, r := range g.Runes() { for _, r := range g.Value() {
chWidth = c.RuneWidth(r) chWidth = c.RuneWidth(r)
if chWidth > 0 { if chWidth > 0 {
break // See StringWidth() for details. break // See StringWidth() for details.
@@ -236,10 +239,10 @@ func (c *Condition) TruncateLeft(s string, w int, prefix string) string {
if width+chWidth > w { if width+chWidth > w {
if width < w { if width < w {
_, pos = g.Positions() pos = g.End()
prefix += strings.Repeat(" ", width+chWidth-w) prefix += strings.Repeat(" ", width+chWidth-w)
} else { } else {
pos, _ = g.Positions() pos = g.Start()
} }
break break

View File

@@ -4,6 +4,7 @@
package runewidth package runewidth
import ( import (
"os"
"syscall" "syscall"
) )
@@ -14,6 +15,11 @@ var (
// IsEastAsian return true if the current locale is CJK // IsEastAsian return true if the current locale is CJK
func IsEastAsian() bool { func IsEastAsian() bool {
if os.Getenv("WT_SESSION") != "" {
// Windows Terminal always not use East Asian Ambiguous Width(s).
return false
}
r1, _, _ := procGetConsoleOutputCP.Call() r1, _, _ := procGetConsoleOutputCP.Call()
if r1 == 0 { if r1 == 0 {
return false return false

View File

@@ -1,137 +0,0 @@
# Unicode Text Segmentation for Go
[![Go Reference](https://pkg.go.dev/badge/github.com/rivo/uniseg.svg)](https://pkg.go.dev/github.com/rivo/uniseg)
[![Go Report](https://img.shields.io/badge/go%20report-A%2B-brightgreen.svg)](https://goreportcard.com/report/github.com/rivo/uniseg)
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
### 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|
|-|-|-|-|
|Käse|6 bytes: `4b 61 cc 88 73 65`|5 code points: `4b 61 308 73 65`|4 clusters: `[4b],[61 308],[73],[65]`|
|🏳️‍🌈|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 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
```bash
go get github.com/rivo/uniseg
```
## 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
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]
```
### Advanced Examples
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):
```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://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.
## Sponsor this Project
[Become a Sponsor on GitHub](https://github.com/sponsors/rivo?metadata_source=uniseg_readme) to support this project!
## Your Feedback
Add your issue here on GitHub, preferably before submitting any PR's. Feel free to get in touch if you have any questions.

108
vendor/github.com/rivo/uniseg/doc.go generated vendored
View File

@@ -1,108 +0,0 @@
/*
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/).
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

File diff suppressed because it is too large Load Diff

View File

@@ -1,295 +0,0 @@
// 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 oclock..twelve oclock
{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] (🚹..🚾) mens 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
}

View File

@@ -1,215 +0,0 @@
//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
}

View File

@@ -1,261 +0,0 @@
//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=<property>": 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, "_", "")
}

View File

@@ -1,331 +0,0 @@
package uniseg
import "unicode/utf8"
// 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.
//
// 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).
//
// 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 original string.
original string
// The remaining string to be parsed.
remaining string
// The current grapheme cluster.
cluster string
// The byte offset of the current grapheme cluster relative to the original
// string.
offset int
// The current boundary information of the [Step] parser.
boundaries int
// The current state of the [Step] parser.
state int
}
// NewGraphemes returns a new grapheme cluster iterator.
func NewGraphemes(str string) *Graphemes {
return &Graphemes{
original: str,
remaining: str,
state: -1,
}
}
// 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 {
if len(g.remaining) == 0 {
// We're already past the end.
g.state = -2
g.cluster = ""
return false
}
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 [Graphemes.Next]
// has not yet been called, nil is returned.
func (g *Graphemes) Runes() []rune {
if g.state < 0 {
return nil
}
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
// [Graphemes.Next] has not yet been called, an empty string is returned.
func (g *Graphemes) Str() string {
return g.cluster
}
// Bytes returns a byte slice which corresponds to the current grapheme cluster.
// 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.state < 0 {
return nil
}
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 [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) {
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
// [Graphemes.Next] sets it to the first grapheme cluster again.
func (g *Graphemes) Reset() {
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.
func GraphemeClusterCount(s string) (n int) {
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)
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,176 +0,0 @@
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
}

134
vendor/github.com/rivo/uniseg/line.go generated vendored
View File

@@ -1,134 +0,0 @@
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
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,626 +0,0 @@
package uniseg
import "unicode/utf8"
// The states of the line break parser.
const (
lbAny = iota
lbBK
lbCR
lbLF
lbNL
lbSP
lbZW
lbWJ
lbGL
lbBA
lbHY
lbCL
lbCP
lbEX
lbIS
lbSY
lbOP
lbQU
lbQUSP
lbNS
lbCLCPSP
lbB2
lbB2SP
lbCB
lbBB
lbLB21a
lbHL
lbAL
lbNU
lbPR
lbEB
lbIDEM
lbNUNU
lbNUSY
lbNUIS
lbNUCL
lbNUCP
lbPO
lbJL
lbJV
lbJT
lbH2
lbH3
lbOddRI
lbEvenRI
lbExtPicCn
lbZWJBit = 64
lbCPeaFWHBit = 128
)
// These constants define whether a given text may be broken into the next line.
// If the break is optional (LineCanBreak), you may choose to break or not based
// on your own criteria, for example, if the text has reached the available
// width.
const (
LineDontBreak = iota // You may not break the line here.
LineCanBreak // You may or may not break the line here.
LineMustBreak // You must break the line here.
)
// lbTransitions implements the line break parser's state transitions. It's
// anologous to [grTransitions], see comments there for details.
//
// Unicode version 15.0.0.
func lbTransitions(state, prop int) (newState, lineBreak, rule int) {
switch uint64(state) | uint64(prop)<<32 {
// LB4.
case lbBK | prAny<<32:
return lbAny, LineMustBreak, 40
// LB5.
case lbCR | prLF<<32:
return lbLF, LineDontBreak, 50
case lbCR | prAny<<32:
return lbAny, LineMustBreak, 50
case lbLF | prAny<<32:
return lbAny, LineMustBreak, 50
case lbNL | prAny<<32:
return lbAny, LineMustBreak, 50
// LB6.
case lbAny | prBK<<32:
return lbBK, LineDontBreak, 60
case lbAny | prCR<<32:
return lbCR, LineDontBreak, 60
case lbAny | prLF<<32:
return lbLF, LineDontBreak, 60
case lbAny | prNL<<32:
return lbNL, LineDontBreak, 60
// LB7.
case lbAny | prSP<<32:
return lbSP, LineDontBreak, 70
case lbAny | prZW<<32:
return lbZW, LineDontBreak, 70
// LB8.
case lbZW | prSP<<32:
return lbZW, LineDontBreak, 70
case lbZW | prAny<<32:
return lbAny, LineCanBreak, 80
// LB11.
case lbAny | prWJ<<32:
return lbWJ, LineDontBreak, 110
case lbWJ | prAny<<32:
return lbAny, LineDontBreak, 110
// LB12.
case lbAny | prGL<<32:
return lbGL, LineCanBreak, 310
case lbGL | prAny<<32:
return lbAny, LineDontBreak, 120
// LB13 (simple transitions).
case lbAny | prCL<<32:
return lbCL, LineCanBreak, 310
case lbAny | prCP<<32:
return lbCP, LineCanBreak, 310
case lbAny | prEX<<32:
return lbEX, LineDontBreak, 130
case lbAny | prIS<<32:
return lbIS, LineCanBreak, 310
case lbAny | prSY<<32:
return lbSY, LineCanBreak, 310
// LB14.
case lbAny | prOP<<32:
return lbOP, LineCanBreak, 310
case lbOP | prSP<<32:
return lbOP, LineDontBreak, 70
case lbOP | prAny<<32:
return lbAny, LineDontBreak, 140
// LB15.
case lbQU | prSP<<32:
return lbQUSP, LineDontBreak, 70
case lbQU | prOP<<32:
return lbOP, LineDontBreak, 150
case lbQUSP | prOP<<32:
return lbOP, LineDontBreak, 150
// LB16.
case lbCL | prSP<<32:
return lbCLCPSP, LineDontBreak, 70
case lbNUCL | prSP<<32:
return lbCLCPSP, LineDontBreak, 70
case lbCP | prSP<<32:
return lbCLCPSP, LineDontBreak, 70
case lbNUCP | prSP<<32:
return lbCLCPSP, LineDontBreak, 70
case lbCL | prNS<<32:
return lbNS, LineDontBreak, 160
case lbNUCL | prNS<<32:
return lbNS, LineDontBreak, 160
case lbCP | prNS<<32:
return lbNS, LineDontBreak, 160
case lbNUCP | prNS<<32:
return lbNS, LineDontBreak, 160
case lbCLCPSP | prNS<<32:
return lbNS, LineDontBreak, 160
// LB17.
case lbAny | prB2<<32:
return lbB2, LineCanBreak, 310
case lbB2 | prSP<<32:
return lbB2SP, LineDontBreak, 70
case lbB2 | prB2<<32:
return lbB2, LineDontBreak, 170
case lbB2SP | prB2<<32:
return lbB2, LineDontBreak, 170
// LB18.
case lbSP | prAny<<32:
return lbAny, LineCanBreak, 180
case lbQUSP | prAny<<32:
return lbAny, LineCanBreak, 180
case lbCLCPSP | prAny<<32:
return lbAny, LineCanBreak, 180
case lbB2SP | prAny<<32:
return lbAny, LineCanBreak, 180
// LB19.
case lbAny | prQU<<32:
return lbQU, LineDontBreak, 190
case lbQU | prAny<<32:
return lbAny, LineDontBreak, 190
// LB20.
case lbAny | prCB<<32:
return lbCB, LineCanBreak, 200
case lbCB | prAny<<32:
return lbAny, LineCanBreak, 200
// LB21.
case lbAny | prBA<<32:
return lbBA, LineDontBreak, 210
case lbAny | prHY<<32:
return lbHY, LineDontBreak, 210
case lbAny | prNS<<32:
return lbNS, LineDontBreak, 210
case lbAny | prBB<<32:
return lbBB, LineCanBreak, 310
case lbBB | prAny<<32:
return lbAny, LineDontBreak, 210
// LB21a.
case lbAny | prHL<<32:
return lbHL, LineCanBreak, 310
case lbHL | prHY<<32:
return lbLB21a, LineDontBreak, 210
case lbHL | prBA<<32:
return lbLB21a, LineDontBreak, 210
case lbLB21a | prAny<<32:
return lbAny, LineDontBreak, 211
// LB21b.
case lbSY | prHL<<32:
return lbHL, LineDontBreak, 212
case lbNUSY | prHL<<32:
return lbHL, LineDontBreak, 212
// LB22.
case lbAny | prIN<<32:
return lbAny, LineDontBreak, 220
// LB23.
case lbAny | prAL<<32:
return lbAL, LineCanBreak, 310
case lbAny | prNU<<32:
return lbNU, LineCanBreak, 310
case lbAL | prNU<<32:
return lbNU, LineDontBreak, 230
case lbHL | prNU<<32:
return lbNU, LineDontBreak, 230
case lbNU | prAL<<32:
return lbAL, LineDontBreak, 230
case lbNU | prHL<<32:
return lbHL, LineDontBreak, 230
case lbNUNU | prAL<<32:
return lbAL, LineDontBreak, 230
case lbNUNU | prHL<<32:
return lbHL, LineDontBreak, 230
// LB23a.
case lbAny | prPR<<32:
return lbPR, LineCanBreak, 310
case lbAny | prID<<32:
return lbIDEM, LineCanBreak, 310
case lbAny | prEB<<32:
return lbEB, LineCanBreak, 310
case lbAny | prEM<<32:
return lbIDEM, LineCanBreak, 310
case lbPR | prID<<32:
return lbIDEM, LineDontBreak, 231
case lbPR | prEB<<32:
return lbEB, LineDontBreak, 231
case lbPR | prEM<<32:
return lbIDEM, LineDontBreak, 231
case lbIDEM | prPO<<32:
return lbPO, LineDontBreak, 231
case lbEB | prPO<<32:
return lbPO, LineDontBreak, 231
// LB24.
case lbAny | prPO<<32:
return lbPO, LineCanBreak, 310
case lbPR | prAL<<32:
return lbAL, LineDontBreak, 240
case lbPR | prHL<<32:
return lbHL, LineDontBreak, 240
case lbPO | prAL<<32:
return lbAL, LineDontBreak, 240
case lbPO | prHL<<32:
return lbHL, LineDontBreak, 240
case lbAL | prPR<<32:
return lbPR, LineDontBreak, 240
case lbAL | prPO<<32:
return lbPO, LineDontBreak, 240
case lbHL | prPR<<32:
return lbPR, LineDontBreak, 240
case lbHL | prPO<<32:
return lbPO, LineDontBreak, 240
// LB25 (simple transitions).
case lbPR | prNU<<32:
return lbNU, LineDontBreak, 250
case lbPO | prNU<<32:
return lbNU, LineDontBreak, 250
case lbOP | prNU<<32:
return lbNU, LineDontBreak, 250
case lbHY | prNU<<32:
return lbNU, LineDontBreak, 250
case lbNU | prNU<<32:
return lbNUNU, LineDontBreak, 250
case lbNU | prSY<<32:
return lbNUSY, LineDontBreak, 250
case lbNU | prIS<<32:
return lbNUIS, LineDontBreak, 250
case lbNUNU | prNU<<32:
return lbNUNU, LineDontBreak, 250
case lbNUNU | prSY<<32:
return lbNUSY, LineDontBreak, 250
case lbNUNU | prIS<<32:
return lbNUIS, LineDontBreak, 250
case lbNUSY | prNU<<32:
return lbNUNU, LineDontBreak, 250
case lbNUSY | prSY<<32:
return lbNUSY, LineDontBreak, 250
case lbNUSY | prIS<<32:
return lbNUIS, LineDontBreak, 250
case lbNUIS | prNU<<32:
return lbNUNU, LineDontBreak, 250
case lbNUIS | prSY<<32:
return lbNUSY, LineDontBreak, 250
case lbNUIS | prIS<<32:
return lbNUIS, LineDontBreak, 250
case lbNU | prCL<<32:
return lbNUCL, LineDontBreak, 250
case lbNU | prCP<<32:
return lbNUCP, LineDontBreak, 250
case lbNUNU | prCL<<32:
return lbNUCL, LineDontBreak, 250
case lbNUNU | prCP<<32:
return lbNUCP, LineDontBreak, 250
case lbNUSY | prCL<<32:
return lbNUCL, LineDontBreak, 250
case lbNUSY | prCP<<32:
return lbNUCP, LineDontBreak, 250
case lbNUIS | prCL<<32:
return lbNUCL, LineDontBreak, 250
case lbNUIS | prCP<<32:
return lbNUCP, LineDontBreak, 250
case lbNU | prPO<<32:
return lbPO, LineDontBreak, 250
case lbNUNU | prPO<<32:
return lbPO, LineDontBreak, 250
case lbNUSY | prPO<<32:
return lbPO, LineDontBreak, 250
case lbNUIS | prPO<<32:
return lbPO, LineDontBreak, 250
case lbNUCL | prPO<<32:
return lbPO, LineDontBreak, 250
case lbNUCP | prPO<<32:
return lbPO, LineDontBreak, 250
case lbNU | prPR<<32:
return lbPR, LineDontBreak, 250
case lbNUNU | prPR<<32:
return lbPR, LineDontBreak, 250
case lbNUSY | prPR<<32:
return lbPR, LineDontBreak, 250
case lbNUIS | prPR<<32:
return lbPR, LineDontBreak, 250
case lbNUCL | prPR<<32:
return lbPR, LineDontBreak, 250
case lbNUCP | prPR<<32:
return lbPR, LineDontBreak, 250
// LB26.
case lbAny | prJL<<32:
return lbJL, LineCanBreak, 310
case lbAny | prJV<<32:
return lbJV, LineCanBreak, 310
case lbAny | prJT<<32:
return lbJT, LineCanBreak, 310
case lbAny | prH2<<32:
return lbH2, LineCanBreak, 310
case lbAny | prH3<<32:
return lbH3, LineCanBreak, 310
case lbJL | prJL<<32:
return lbJL, LineDontBreak, 260
case lbJL | prJV<<32:
return lbJV, LineDontBreak, 260
case lbJL | prH2<<32:
return lbH2, LineDontBreak, 260
case lbJL | prH3<<32:
return lbH3, LineDontBreak, 260
case lbJV | prJV<<32:
return lbJV, LineDontBreak, 260
case lbJV | prJT<<32:
return lbJT, LineDontBreak, 260
case lbH2 | prJV<<32:
return lbJV, LineDontBreak, 260
case lbH2 | prJT<<32:
return lbJT, LineDontBreak, 260
case lbJT | prJT<<32:
return lbJT, LineDontBreak, 260
case lbH3 | prJT<<32:
return lbJT, LineDontBreak, 260
// LB27.
case lbJL | prPO<<32:
return lbPO, LineDontBreak, 270
case lbJV | prPO<<32:
return lbPO, LineDontBreak, 270
case lbJT | prPO<<32:
return lbPO, LineDontBreak, 270
case lbH2 | prPO<<32:
return lbPO, LineDontBreak, 270
case lbH3 | prPO<<32:
return lbPO, LineDontBreak, 270
case lbPR | prJL<<32:
return lbJL, LineDontBreak, 270
case lbPR | prJV<<32:
return lbJV, LineDontBreak, 270
case lbPR | prJT<<32:
return lbJT, LineDontBreak, 270
case lbPR | prH2<<32:
return lbH2, LineDontBreak, 270
case lbPR | prH3<<32:
return lbH3, LineDontBreak, 270
// LB28.
case lbAL | prAL<<32:
return lbAL, LineDontBreak, 280
case lbAL | prHL<<32:
return lbHL, LineDontBreak, 280
case lbHL | prAL<<32:
return lbAL, LineDontBreak, 280
case lbHL | prHL<<32:
return lbHL, LineDontBreak, 280
// LB29.
case lbIS | prAL<<32:
return lbAL, LineDontBreak, 290
case lbIS | prHL<<32:
return lbHL, LineDontBreak, 290
case lbNUIS | prAL<<32:
return lbAL, LineDontBreak, 290
case lbNUIS | prHL<<32:
return lbHL, LineDontBreak, 290
default:
return -1, -1, -1
}
}
// transitionLineBreakState determines the new state of the line break parser
// given the current state and the next code point. It also returns the type of
// line break: LineDontBreak, LineCanBreak, or LineMustBreak. If more than one
// code point is needed to determine the new state, the byte slice or the string
// starting after rune "r" can be used (whichever is not nil or empty) for
// further lookups.
func transitionLineBreakState(state int, r rune, b []byte, str string) (newState int, lineBreak int) {
// Determine the property of the next character.
nextProperty, generalCategory := propertyLineBreak(r)
// Prepare.
var forceNoBreak, isCPeaFWH bool
if state >= 0 && state&lbCPeaFWHBit != 0 {
isCPeaFWH = true // LB30: CP but ea is not F, W, or H.
state = state &^ lbCPeaFWHBit
}
if state >= 0 && state&lbZWJBit != 0 {
state = state &^ lbZWJBit // Extract zero-width joiner bit.
forceNoBreak = true // LB8a.
}
defer func() {
// Transition into LB30.
if newState == lbCP || newState == lbNUCP {
ea := propertyEastAsianWidth(r)
if ea != prF && ea != prW && ea != prH {
newState |= lbCPeaFWHBit
}
}
// Override break.
if forceNoBreak {
lineBreak = LineDontBreak
}
}()
// LB1.
if nextProperty == prAI || nextProperty == prSG || nextProperty == prXX {
nextProperty = prAL
} else if nextProperty == prSA {
if generalCategory == gcMn || generalCategory == gcMc {
nextProperty = prCM
} else {
nextProperty = prAL
}
} else if nextProperty == prCJ {
nextProperty = prNS
}
// Combining marks.
if nextProperty == prZWJ || nextProperty == prCM {
var bit int
if nextProperty == prZWJ {
bit = lbZWJBit
}
mustBreakState := state < 0 || state == lbBK || state == lbCR || state == lbLF || state == lbNL
if !mustBreakState && state != lbSP && state != lbZW && state != lbQUSP && state != lbCLCPSP && state != lbB2SP {
// LB9.
return state | bit, LineDontBreak
} else {
// LB10.
if mustBreakState {
return lbAL | bit, LineMustBreak
}
return lbAL | bit, LineCanBreak
}
}
// Find the applicable transition in the table.
var rule int
newState, lineBreak, rule = lbTransitions(state, nextProperty)
if newState < 0 {
// No specific transition found. Try the less specific ones.
anyPropProp, anyPropLineBreak, anyPropRule := lbTransitions(state, prAny)
anyStateProp, anyStateLineBreak, anyStateRule := lbTransitions(lbAny, nextProperty)
if anyPropProp >= 0 && anyStateProp >= 0 {
// Both apply. We'll use a mix (see comments for grTransitions).
newState, lineBreak, rule = anyStateProp, anyStateLineBreak, anyStateRule
if anyPropRule < anyStateRule {
lineBreak, rule = anyPropLineBreak, anyPropRule
}
} else if anyPropProp >= 0 {
// We only have a specific state.
newState, lineBreak, rule = anyPropProp, anyPropLineBreak, anyPropRule
// 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 anyStateProp >= 0 {
// We only have a specific property.
newState, lineBreak, rule = anyStateProp, anyStateLineBreak, anyStateRule
} else {
// No known transition. LB31: ALL ÷ ALL.
newState, lineBreak, rule = lbAny, LineCanBreak, 310
}
}
// LB12a.
if rule > 121 &&
nextProperty == prGL &&
(state != lbSP && state != lbBA && state != lbHY && state != lbLB21a && state != lbQUSP && state != lbCLCPSP && state != lbB2SP) {
return lbGL, LineDontBreak
}
// LB13.
if rule > 130 && state != lbNU && state != lbNUNU {
switch nextProperty {
case prCL:
return lbCL, LineDontBreak
case prCP:
return lbCP, LineDontBreak
case prIS:
return lbIS, LineDontBreak
case prSY:
return lbSY, LineDontBreak
}
}
// LB25 (look ahead).
if rule > 250 &&
(state == lbPR || state == lbPO) &&
nextProperty == prOP || nextProperty == prHY {
var r rune
if b != nil { // Byte slice version.
r, _ = utf8.DecodeRune(b)
} else { // String version.
r, _ = utf8.DecodeRuneInString(str)
}
if r != utf8.RuneError {
pr, _ := propertyLineBreak(r)
if pr == prNU {
return lbNU, LineDontBreak
}
}
}
// LB30 (part one).
if rule > 300 {
if (state == lbAL || state == lbHL || state == lbNU || state == lbNUNU) && nextProperty == prOP {
ea := propertyEastAsianWidth(r)
if ea != prF && ea != prW && ea != prH {
return lbOP, LineDontBreak
}
} else if isCPeaFWH {
switch nextProperty {
case prAL:
return lbAL, LineDontBreak
case prHL:
return lbHL, LineDontBreak
case prNU:
return lbNU, LineDontBreak
}
}
}
// LB30a.
if newState == lbAny && nextProperty == prRI {
if state != lbOddRI && state != lbEvenRI { // Includes state == -1.
// Transition into the first RI.
return lbOddRI, lineBreak
}
if state == lbOddRI {
// Don't break pairs of Regional Indicators.
return lbEvenRI, LineDontBreak
}
return lbOddRI, lineBreak
}
// LB30b.
if rule > 302 {
if nextProperty == prEM {
if state == lbEB || state == lbExtPicCn {
return prAny, LineDontBreak
}
}
graphemeProperty := propertyGraphemes(r)
if graphemeProperty == prExtendedPictographic && generalCategory == gcCn {
return lbExtPicCn, LineCanBreak
}
}
return
}

View File

@@ -1,208 +0,0 @@
package uniseg
// The Unicode properties as used in the various parsers. Only the ones needed
// in the context of this package are included.
const (
prXX = 0 // Same as prAny.
prAny = iota // prAny must be 0.
prPrepend // Grapheme properties must come first, to reduce the number of bits stored in the state vector.
prCR
prLF
prControl
prExtend
prRegionalIndicator
prSpacingMark
prL
prV
prT
prLV
prLVT
prZWJ
prExtendedPictographic
prNewline
prWSegSpace
prDoubleQuote
prSingleQuote
prMidNumLet
prNumeric
prMidLetter
prMidNum
prExtendNumLet
prALetter
prFormat
prHebrewLetter
prKatakana
prSp
prSTerm
prClose
prSContinue
prATerm
prUpper
prLower
prSep
prOLetter
prCM
prBA
prBK
prSP
prEX
prQU
prAL
prPR
prPO
prOP
prCP
prIS
prHY
prSY
prNU
prCL
prNL
prGL
prAI
prBB
prHL
prSA
prJL
prJV
prJT
prNS
prZW
prB2
prIN
prWJ
prID
prEB
prCJ
prH2
prH3
prSG
prCB
prRI
prEM
prN
prNa
prA
prW
prH
prF
prEmojiPresentation
)
// Unicode General Categories. Only the ones needed in the context of this
// package are included.
const (
gcNone = iota // gcNone must be 0.
gcCc
gcZs
gcPo
gcSc
gcPs
gcPe
gcSm
gcPd
gcNd
gcLu
gcSk
gcPc
gcLl
gcSo
gcLo
gcPi
gcCf
gcNo
gcPf
gcLC
gcLm
gcMn
gcMe
gcMc
gcNl
gcZl
gcZp
gcCn
gcCs
gcCo
)
// Special code points.
const (
vs15 = 0xfe0e // Variation Selector-15 (text presentation)
vs16 = 0xfe0f // Variation Selector-16 (emoji presentation)
)
// propertySearch performs a binary search on a property slice and returns the
// entry whose range (start = first array element, end = second array element)
// includes r, or an array of 0's if no such entry was found.
func propertySearch[E interface{ [3]int | [4]int }](dictionary []E, r rune) (result E) {
// Run a binary search.
from := 0
to := len(dictionary)
for to > from {
middle := (from + to) / 2
cpRange := dictionary[middle]
if int(r) < cpRange[0] {
to = middle
continue
}
if int(r) > cpRange[1] {
from = middle + 1
continue
}
return cpRange
}
return
}
// property returns the Unicode property value (see constants above) of the
// given code point.
func property(dictionary [][3]int, r rune) int {
return propertySearch(dictionary, r)[2]
}
// propertyLineBreak returns the Unicode property value and General Category
// (see constants above) of the given code point, as listed in the line break
// code points table, while fast tracking ASCII digits and letters.
func propertyLineBreak(r rune) (property, generalCategory int) {
if r >= 'a' && r <= 'z' {
return prAL, gcLl
}
if r >= 'A' && r <= 'Z' {
return prAL, gcLu
}
if r >= '0' && r <= '9' {
return prNU, gcNd
}
entry := propertySearch(lineBreakCodePoints, r)
return entry[2], entry[3]
}
// propertyGraphemes returns the Unicode grapheme cluster property value of the
// given code point while fast tracking ASCII characters.
func propertyGraphemes(r rune) int {
if r >= 0x20 && r <= 0x7e {
return prAny
}
if r == 0x0a {
return prLF
}
if r == 0x0d {
return prCR
}
if r >= 0 && r <= 0x1f || r == 0x7f {
return prControl
}
return property(graphemeCodePoints, r)
}
// propertyEastAsianWidth returns the Unicode East Asian Width property value of
// the given code point while fast tracking ASCII characters.
func propertyEastAsianWidth(r rune) int {
if r >= 0x20 && r <= 0x7e {
return prNa
}
if r >= 0 && r <= 0x1f || r == 0x7f {
return prN
}
return property(eastAsianWidth, r)
}

View File

@@ -1,90 +0,0 @@
package uniseg
import "unicode/utf8"
// FirstSentence returns the first sentence found in the given byte slice
// according to the rules of [Unicode Standard Annex #29, Sentence Boundaries].
// This function can be called continuously to extract all sentences 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 sentence. If the length of the "rest"
// slice is 0, the entire byte slice "b" has been processed. The "sentence" byte
// slice is the sub-slice of the input slice containing the identified sentence.
//
// Given an empty byte slice "b", the function returns nil values.
//
// [Unicode Standard Annex #29, Sentence Boundaries]: http://unicode.org/reports/tr29/#Sentence_Boundaries
func FirstSentence(b []byte, state int) (sentence, rest []byte, 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, sbAny
}
// If we don't know the state, determine it now.
if state < 0 {
state, _ = transitionSentenceBreakState(state, r, b[length:], "")
}
// Transition until we find a boundary.
var boundary bool
for {
r, l := utf8.DecodeRune(b[length:])
state, boundary = transitionSentenceBreakState(state, r, b[length+l:], "")
if boundary {
return b[:length], b[length:], state
}
length += l
if len(b) <= length {
return b, nil, sbAny
}
}
}
// FirstSentenceInString is like [FirstSentence] but its input and outputs are
// strings.
func FirstSentenceInString(str string, state int) (sentence, rest string, 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, "", sbAny
}
// If we don't know the state, determine it now.
if state < 0 {
state, _ = transitionSentenceBreakState(state, r, nil, str[length:])
}
// Transition until we find a boundary.
var boundary bool
for {
r, l := utf8.DecodeRuneInString(str[length:])
state, boundary = transitionSentenceBreakState(state, r, nil, str[length+l:])
if boundary {
return str[:length], str[length:], state
}
length += l
if len(str) <= length {
return str, "", sbAny
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,276 +0,0 @@
package uniseg
import "unicode/utf8"
// The states of the sentence break parser.
const (
sbAny = iota
sbCR
sbParaSep
sbATerm
sbUpper
sbLower
sbSB7
sbSB8Close
sbSB8Sp
sbSTerm
sbSB8aClose
sbSB8aSp
)
// sbTransitions implements the sentence break parser's state transitions. It's
// anologous to [grTransitions], see comments there for details.
//
// Unicode version 15.0.0.
func sbTransitions(state, prop int) (newState int, sentenceBreak bool, rule int) {
switch uint64(state) | uint64(prop)<<32 {
// SB3.
case sbAny | prCR<<32:
return sbCR, false, 9990
case sbCR | prLF<<32:
return sbParaSep, false, 30
// SB4.
case sbAny | prSep<<32:
return sbParaSep, false, 9990
case sbAny | prLF<<32:
return sbParaSep, false, 9990
case sbParaSep | prAny<<32:
return sbAny, true, 40
case sbCR | prAny<<32:
return sbAny, true, 40
// SB6.
case sbAny | prATerm<<32:
return sbATerm, false, 9990
case sbATerm | prNumeric<<32:
return sbAny, false, 60
case sbSB7 | prNumeric<<32:
return sbAny, false, 60 // Because ATerm also appears in SB7.
// SB7.
case sbAny | prUpper<<32:
return sbUpper, false, 9990
case sbAny | prLower<<32:
return sbLower, false, 9990
case sbUpper | prATerm<<32:
return sbSB7, false, 70
case sbLower | prATerm<<32:
return sbSB7, false, 70
case sbSB7 | prUpper<<32:
return sbUpper, false, 70
// SB8a.
case sbAny | prSTerm<<32:
return sbSTerm, false, 9990
case sbATerm | prSContinue<<32:
return sbAny, false, 81
case sbATerm | prATerm<<32:
return sbATerm, false, 81
case sbATerm | prSTerm<<32:
return sbSTerm, false, 81
case sbSB7 | prSContinue<<32:
return sbAny, false, 81
case sbSB7 | prATerm<<32:
return sbATerm, false, 81
case sbSB7 | prSTerm<<32:
return sbSTerm, false, 81
case sbSB8Close | prSContinue<<32:
return sbAny, false, 81
case sbSB8Close | prATerm<<32:
return sbATerm, false, 81
case sbSB8Close | prSTerm<<32:
return sbSTerm, false, 81
case sbSB8Sp | prSContinue<<32:
return sbAny, false, 81
case sbSB8Sp | prATerm<<32:
return sbATerm, false, 81
case sbSB8Sp | prSTerm<<32:
return sbSTerm, false, 81
case sbSTerm | prSContinue<<32:
return sbAny, false, 81
case sbSTerm | prATerm<<32:
return sbATerm, false, 81
case sbSTerm | prSTerm<<32:
return sbSTerm, false, 81
case sbSB8aClose | prSContinue<<32:
return sbAny, false, 81
case sbSB8aClose | prATerm<<32:
return sbATerm, false, 81
case sbSB8aClose | prSTerm<<32:
return sbSTerm, false, 81
case sbSB8aSp | prSContinue<<32:
return sbAny, false, 81
case sbSB8aSp | prATerm<<32:
return sbATerm, false, 81
case sbSB8aSp | prSTerm<<32:
return sbSTerm, false, 81
// SB9.
case sbATerm | prClose<<32:
return sbSB8Close, false, 90
case sbSB7 | prClose<<32:
return sbSB8Close, false, 90
case sbSB8Close | prClose<<32:
return sbSB8Close, false, 90
case sbATerm | prSp<<32:
return sbSB8Sp, false, 90
case sbSB7 | prSp<<32:
return sbSB8Sp, false, 90
case sbSB8Close | prSp<<32:
return sbSB8Sp, false, 90
case sbSTerm | prClose<<32:
return sbSB8aClose, false, 90
case sbSB8aClose | prClose<<32:
return sbSB8aClose, false, 90
case sbSTerm | prSp<<32:
return sbSB8aSp, false, 90
case sbSB8aClose | prSp<<32:
return sbSB8aSp, false, 90
case sbATerm | prSep<<32:
return sbParaSep, false, 90
case sbATerm | prCR<<32:
return sbParaSep, false, 90
case sbATerm | prLF<<32:
return sbParaSep, false, 90
case sbSB7 | prSep<<32:
return sbParaSep, false, 90
case sbSB7 | prCR<<32:
return sbParaSep, false, 90
case sbSB7 | prLF<<32:
return sbParaSep, false, 90
case sbSB8Close | prSep<<32:
return sbParaSep, false, 90
case sbSB8Close | prCR<<32:
return sbParaSep, false, 90
case sbSB8Close | prLF<<32:
return sbParaSep, false, 90
case sbSTerm | prSep<<32:
return sbParaSep, false, 90
case sbSTerm | prCR<<32:
return sbParaSep, false, 90
case sbSTerm | prLF<<32:
return sbParaSep, false, 90
case sbSB8aClose | prSep<<32:
return sbParaSep, false, 90
case sbSB8aClose | prCR<<32:
return sbParaSep, false, 90
case sbSB8aClose | prLF<<32:
return sbParaSep, false, 90
// SB10.
case sbSB8Sp | prSp<<32:
return sbSB8Sp, false, 100
case sbSB8aSp | prSp<<32:
return sbSB8aSp, false, 100
case sbSB8Sp | prSep<<32:
return sbParaSep, false, 100
case sbSB8Sp | prCR<<32:
return sbParaSep, false, 100
case sbSB8Sp | prLF<<32:
return sbParaSep, false, 100
// SB11.
case sbATerm | prAny<<32:
return sbAny, true, 110
case sbSB7 | prAny<<32:
return sbAny, true, 110
case sbSB8Close | prAny<<32:
return sbAny, true, 110
case sbSB8Sp | prAny<<32:
return sbAny, true, 110
case sbSTerm | prAny<<32:
return sbAny, true, 110
case sbSB8aClose | prAny<<32:
return sbAny, true, 110
case sbSB8aSp | prAny<<32:
return sbAny, true, 110
// We'll always break after ParaSep due to SB4.
default:
return -1, false, -1
}
}
// transitionSentenceBreakState determines the new state of the sentence break
// parser given the current state and the next code point. It also returns
// whether a sentence boundary was detected. If more than one code point is
// needed to determine the new state, the byte slice or the string starting
// after rune "r" can be used (whichever is not nil or empty) for further
// lookups.
func transitionSentenceBreakState(state int, r rune, b []byte, str string) (newState int, sentenceBreak bool) {
// Determine the property of the next character.
nextProperty := property(sentenceBreakCodePoints, r)
// SB5 (Replacing Ignore Rules).
if nextProperty == prExtend || nextProperty == prFormat {
if state == sbParaSep || state == sbCR {
return sbAny, true // Make sure we don't apply SB5 to SB3 or SB4.
}
if state < 0 {
return sbAny, true // SB1.
}
return state, false
}
// Find the applicable transition in the table.
var rule int
newState, sentenceBreak, rule = sbTransitions(state, nextProperty)
if newState < 0 {
// No specific transition found. Try the less specific ones.
anyPropState, anyPropProp, anyPropRule := sbTransitions(state, prAny)
anyStateState, anyStateProp, anyStateRule := sbTransitions(sbAny, nextProperty)
if anyPropState >= 0 && anyStateState >= 0 {
// Both apply. We'll use a mix (see comments for grTransitions).
newState, sentenceBreak, rule = anyStateState, anyStateProp, anyStateRule
if anyPropRule < anyStateRule {
sentenceBreak, rule = anyPropProp, anyPropRule
}
} else if anyPropState >= 0 {
// We only have a specific state.
newState, sentenceBreak, rule = anyPropState, anyPropProp, anyPropRule
// 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 anyStateState >= 0 {
// We only have a specific property.
newState, sentenceBreak, rule = anyStateState, anyStateProp, anyStateRule
} else {
// No known transition. SB999: Any × Any.
newState, sentenceBreak, rule = sbAny, false, 9990
}
}
// SB8.
if rule > 80 && (state == sbATerm || state == sbSB8Close || state == sbSB8Sp || state == sbSB7) {
// Check the right side of the rule.
var length int
for nextProperty != prOLetter &&
nextProperty != prUpper &&
nextProperty != prLower &&
nextProperty != prSep &&
nextProperty != prCR &&
nextProperty != prLF &&
nextProperty != prATerm &&
nextProperty != prSTerm {
// Move on to the next rune.
if b != nil { // Byte slice version.
r, length = utf8.DecodeRune(b)
b = b[length:]
} else { // String version.
r, length = utf8.DecodeRuneInString(str)
str = str[length:]
}
if r == utf8.RuneError {
break
}
nextProperty = property(sentenceBreakCodePoints, r)
}
if nextProperty == prLower {
return sbLower, false
}
}
return
}

242
vendor/github.com/rivo/uniseg/step.go generated vendored
View File

@@ -1,242 +0,0 @@
package uniseg
import "unicode/utf8"
// The bit masks used to extract boundary information returned by [Step].
const (
MaskLine = 3
MaskWord = 4
MaskSentence = 8
)
// The number of bits to shift the boundary information returned by [Step] to
// obtain the monospace width of the grapheme cluster.
const ShiftWidth = 4
// The bit positions by which boundary flags are shifted by the [Step] function.
// These must correspond to the Mask constants.
const (
shiftWord = 2
shiftSentence = 3
// shiftwWidth is ShiftWidth above. No mask as these are always the remaining bits.
)
// The bit positions by which states are shifted by the [Step] function. These
// values must ensure state values defined for each of the boundary algorithms
// don't overlap (and that they all still fit in a single int). These must
// correspond to the Mask constants.
const (
shiftWordState = 4
shiftSentenceState = 9
shiftLineState = 13
shiftPropState = 21 // No mask as these are always the remaining bits.
)
// The bit mask used to extract the state returned by the [Step] function, after
// shifting. These values must correspond to the shift constants.
const (
maskGraphemeState = 0xf
maskWordState = 0x1f
maskSentenceState = 0xf
maskLineState = 0xff
)
// Step returns the first grapheme cluster (user-perceived character) found in
// the given byte slice. It also returns information about the boundary between
// that grapheme cluster and the one following it as well as the monospace width
// of the grapheme cluster. There are three types of boundary information: word
// boundaries, sentence boundaries, and line breaks. This function is therefore
// a combination of [FirstGraphemeCluster], [FirstWord], [FirstSentence], and
// [FirstLineSegment].
//
// The "boundaries" return value can be evaluated as follows:
//
// - boundaries&MaskWord != 0: The boundary is a word boundary.
// - boundaries&MaskWord == 0: The boundary is not a word boundary.
// - boundaries&MaskSentence != 0: The boundary is a sentence boundary.
// - boundaries&MaskSentence == 0: The boundary is not a sentence boundary.
// - boundaries&MaskLine == LineDontBreak: You must not break the line at the
// boundary.
// - boundaries&MaskLine == LineMustBreak: You must break the line at the
// boundary.
// - boundaries&MaskLine == LineCanBreak: You may or may not break the line at
// the boundary.
// - boundaries >> ShiftWidth: The width of the grapheme cluster for most
// monospace fonts where a value of 1 represents one character cell.
//
// This function can be called continuously to extract all grapheme clusters
// from a byte slice, as illustrated in the examples below.
//
// If you don't know which state to pass, 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
// first identified grapheme cluster.
//
// 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.
//
// Note that in accordance with [UAX #14 LB3], the final segment will end with
// a mandatory line break (boundaries&MaskLine == LineMustBreak). 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.
//
// [UAX #14 LB3]: https://www.unicode.org/reports/tr14/#Algorithm
func Step(b []byte, state int) (cluster, rest []byte, boundaries int, 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 >> shiftPropState
}
return b, nil, LineMustBreak | (1 << shiftWord) | (1 << shiftSentence) | (runeWidth(r, prop) << ShiftWidth), grAny | (wbAny << shiftWordState) | (sbAny << shiftSentenceState) | (lbAny << shiftLineState) | (prop << shiftPropState)
}
// If we don't know the state, determine it now.
var graphemeState, wordState, sentenceState, lineState, firstProp int
remainder := b[length:]
if state < 0 {
graphemeState, firstProp, _ = transitionGraphemeState(state, r)
wordState, _ = transitionWordBreakState(state, r, remainder, "")
sentenceState, _ = transitionSentenceBreakState(state, r, remainder, "")
lineState, _ = transitionLineBreakState(state, r, remainder, "")
} else {
graphemeState = state & maskGraphemeState
wordState = (state >> shiftWordState) & maskWordState
sentenceState = (state >> shiftSentenceState) & maskSentenceState
lineState = (state >> shiftLineState) & maskLineState
firstProp = state >> shiftPropState
}
// Transition until we find a grapheme cluster boundary.
width := runeWidth(r, firstProp)
for {
var (
graphemeBoundary, wordBoundary, sentenceBoundary bool
lineBreak, prop int
)
r, l := utf8.DecodeRune(remainder)
remainder = b[length+l:]
graphemeState, prop, graphemeBoundary = transitionGraphemeState(graphemeState, r)
wordState, wordBoundary = transitionWordBreakState(wordState, r, remainder, "")
sentenceState, sentenceBoundary = transitionSentenceBreakState(sentenceState, r, remainder, "")
lineState, lineBreak = transitionLineBreakState(lineState, r, remainder, "")
if graphemeBoundary {
boundary := lineBreak | (width << ShiftWidth)
if wordBoundary {
boundary |= 1 << shiftWord
}
if sentenceBoundary {
boundary |= 1 << shiftSentence
}
return b[:length], b[length:], boundary, graphemeState | (wordState << shiftWordState) | (sentenceState << shiftSentenceState) | (lineState << shiftLineState) | (prop << shiftPropState)
}
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, LineMustBreak | (1 << shiftWord) | (1 << shiftSentence) | (width << ShiftWidth), grAny | (wbAny << shiftWordState) | (sbAny << shiftSentenceState) | (lbAny << shiftLineState) | (prop << shiftPropState)
}
}
}
// StepString is like [Step] but its input and outputs are strings.
func StepString(str string, state int) (cluster, rest string, boundaries int, 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.
prop := propertyGraphemes(r)
return str, "", LineMustBreak | (1 << shiftWord) | (1 << shiftSentence) | (runeWidth(r, prop) << ShiftWidth), grAny | (wbAny << shiftWordState) | (sbAny << shiftSentenceState) | (lbAny << shiftLineState)
}
// If we don't know the state, determine it now.
var graphemeState, wordState, sentenceState, lineState, firstProp int
remainder := str[length:]
if state < 0 {
graphemeState, firstProp, _ = transitionGraphemeState(state, r)
wordState, _ = transitionWordBreakState(state, r, nil, remainder)
sentenceState, _ = transitionSentenceBreakState(state, r, nil, remainder)
lineState, _ = transitionLineBreakState(state, r, nil, remainder)
} else {
graphemeState = state & maskGraphemeState
wordState = (state >> shiftWordState) & maskWordState
sentenceState = (state >> shiftSentenceState) & maskSentenceState
lineState = (state >> shiftLineState) & maskLineState
firstProp = state >> shiftPropState
}
// Transition until we find a grapheme cluster boundary.
width := runeWidth(r, firstProp)
for {
var (
graphemeBoundary, wordBoundary, sentenceBoundary bool
lineBreak, prop int
)
r, l := utf8.DecodeRuneInString(remainder)
remainder = str[length+l:]
graphemeState, prop, graphemeBoundary = transitionGraphemeState(graphemeState, r)
wordState, wordBoundary = transitionWordBreakState(wordState, r, nil, remainder)
sentenceState, sentenceBoundary = transitionSentenceBreakState(sentenceState, r, nil, remainder)
lineState, lineBreak = transitionLineBreakState(lineState, r, nil, remainder)
if graphemeBoundary {
boundary := lineBreak | (width << ShiftWidth)
if wordBoundary {
boundary |= 1 << shiftWord
}
if sentenceBoundary {
boundary |= 1 << shiftSentence
}
return str[:length], str[length:], boundary, graphemeState | (wordState << shiftWordState) | (sentenceState << shiftSentenceState) | (lineState << shiftLineState) | (prop << shiftPropState)
}
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, "", LineMustBreak | (1 << shiftWord) | (1 << shiftSentence) | (width << ShiftWidth), grAny | (wbAny << shiftWordState) | (sbAny << shiftSentenceState) | (lbAny << shiftLineState) | (prop << shiftPropState)
}
}
}

View File

@@ -1,61 +0,0 @@
package uniseg
// EastAsianAmbiguousWidth specifies the monospace width for East Asian
// characters classified as Ambiguous. The default is 1 but some rare fonts
// render them with a width of 2.
var EastAsianAmbiguousWidth = 1
// runeWidth returns the monospace width for the given rune. The provided
// grapheme property is a value mapped by the [graphemeCodePoints] table.
//
// Every rune has a width of 1, except for runes with the following properties
// (evaluated in this order):
//
// - Control, CR, LF, Extend, ZWJ: Width of 0
// - \u2e3a, TWO-EM DASH: Width of 3
// - \u2e3b, THREE-EM DASH: Width of 4
// - East-Asian width Fullwidth and Wide: Width of 2 (Ambiguous and Neutral
// have a width of 1)
// - Regional Indicator: Width of 2
// - Extended Pictographic: Width of 2, unless Emoji Presentation is "No".
func runeWidth(r rune, graphemeProperty int) int {
switch graphemeProperty {
case prControl, prCR, prLF, prExtend, prZWJ:
return 0
case prRegionalIndicator:
return 2
case prExtendedPictographic:
if property(emojiPresentation, r) == prEmojiPresentation {
return 2
}
return 1
}
switch r {
case 0x2e3a:
return 3
case 0x2e3b:
return 4
}
switch propertyEastAsianWidth(r) {
case prW, prF:
return 2
case prA:
return EastAsianAmbiguousWidth
}
return 1
}
// StringWidth returns the monospace width for the given string, that is, the
// number of same-size cells to be occupied by the string.
func StringWidth(s string) (width int) {
state := -1
for len(s) > 0 {
var w int
_, s, w, state = FirstGraphemeClusterInString(s, state)
width += w
}
return
}

View File

@@ -1,89 +0,0 @@
package uniseg
import "unicode/utf8"
// FirstWord returns the first word found in the given byte slice according to
// the rules of [Unicode Standard Annex #29, Word Boundaries]. This function can
// be called continuously to extract all words 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 word. If the length of the "rest" slice
// is 0, the entire byte slice "b" has been processed. The "word" byte slice is
// the sub-slice of the input slice containing the identified word.
//
// Given an empty byte slice "b", the function returns nil values.
//
// [Unicode Standard Annex #29, Word Boundaries]: http://unicode.org/reports/tr29/#Word_Boundaries
func FirstWord(b []byte, state int) (word, rest []byte, 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, wbAny
}
// If we don't know the state, determine it now.
if state < 0 {
state, _ = transitionWordBreakState(state, r, b[length:], "")
}
// Transition until we find a boundary.
var boundary bool
for {
r, l := utf8.DecodeRune(b[length:])
state, boundary = transitionWordBreakState(state, r, b[length+l:], "")
if boundary {
return b[:length], b[length:], state
}
length += l
if len(b) <= length {
return b, nil, wbAny
}
}
}
// FirstWordInString is like [FirstWord] but its input and outputs are strings.
func FirstWordInString(str string, state int) (word, rest string, 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, "", wbAny
}
// If we don't know the state, determine it now.
if state < 0 {
state, _ = transitionWordBreakState(state, r, nil, str[length:])
}
// Transition until we find a boundary.
var boundary bool
for {
r, l := utf8.DecodeRuneInString(str[length:])
state, boundary = transitionWordBreakState(state, r, nil, str[length+l:])
if boundary {
return str[:length], str[length:], state
}
length += l
if len(str) <= length {
return str, "", wbAny
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,282 +0,0 @@
package uniseg
import "unicode/utf8"
// The states of the word break parser.
const (
wbAny = iota
wbCR
wbLF
wbNewline
wbWSegSpace
wbHebrewLetter
wbALetter
wbWB7
wbWB7c
wbNumeric
wbWB11
wbKatakana
wbExtendNumLet
wbOddRI
wbEvenRI
wbZWJBit = 16 // This bit is set for any states followed by at least one zero-width joiner (see WB4 and WB3c).
)
// wbTransitions implements the word break parser's state transitions. It's
// anologous to [grTransitions], see comments there for details.
//
// Unicode version 15.0.0.
func wbTransitions(state, prop int) (newState int, wordBreak bool, rule int) {
switch uint64(state) | uint64(prop)<<32 {
// WB3b.
case wbAny | prNewline<<32:
return wbNewline, true, 32
case wbAny | prCR<<32:
return wbCR, true, 32
case wbAny | prLF<<32:
return wbLF, true, 32
// WB3a.
case wbNewline | prAny<<32:
return wbAny, true, 31
case wbCR | prAny<<32:
return wbAny, true, 31
case wbLF | prAny<<32:
return wbAny, true, 31
// WB3.
case wbCR | prLF<<32:
return wbLF, false, 30
// WB3d.
case wbAny | prWSegSpace<<32:
return wbWSegSpace, true, 9990
case wbWSegSpace | prWSegSpace<<32:
return wbWSegSpace, false, 34
// WB5.
case wbAny | prALetter<<32:
return wbALetter, true, 9990
case wbAny | prHebrewLetter<<32:
return wbHebrewLetter, true, 9990
case wbALetter | prALetter<<32:
return wbALetter, false, 50
case wbALetter | prHebrewLetter<<32:
return wbHebrewLetter, false, 50
case wbHebrewLetter | prALetter<<32:
return wbALetter, false, 50
case wbHebrewLetter | prHebrewLetter<<32:
return wbHebrewLetter, false, 50
// WB7. Transitions to wbWB7 handled by transitionWordBreakState().
case wbWB7 | prALetter<<32:
return wbALetter, false, 70
case wbWB7 | prHebrewLetter<<32:
return wbHebrewLetter, false, 70
// WB7a.
case wbHebrewLetter | prSingleQuote<<32:
return wbAny, false, 71
// WB7c. Transitions to wbWB7c handled by transitionWordBreakState().
case wbWB7c | prHebrewLetter<<32:
return wbHebrewLetter, false, 73
// WB8.
case wbAny | prNumeric<<32:
return wbNumeric, true, 9990
case wbNumeric | prNumeric<<32:
return wbNumeric, false, 80
// WB9.
case wbALetter | prNumeric<<32:
return wbNumeric, false, 90
case wbHebrewLetter | prNumeric<<32:
return wbNumeric, false, 90
// WB10.
case wbNumeric | prALetter<<32:
return wbALetter, false, 100
case wbNumeric | prHebrewLetter<<32:
return wbHebrewLetter, false, 100
// WB11. Transitions to wbWB11 handled by transitionWordBreakState().
case wbWB11 | prNumeric<<32:
return wbNumeric, false, 110
// WB13.
case wbAny | prKatakana<<32:
return wbKatakana, true, 9990
case wbKatakana | prKatakana<<32:
return wbKatakana, false, 130
// WB13a.
case wbAny | prExtendNumLet<<32:
return wbExtendNumLet, true, 9990
case wbALetter | prExtendNumLet<<32:
return wbExtendNumLet, false, 131
case wbHebrewLetter | prExtendNumLet<<32:
return wbExtendNumLet, false, 131
case wbNumeric | prExtendNumLet<<32:
return wbExtendNumLet, false, 131
case wbKatakana | prExtendNumLet<<32:
return wbExtendNumLet, false, 131
case wbExtendNumLet | prExtendNumLet<<32:
return wbExtendNumLet, false, 131
// WB13b.
case wbExtendNumLet | prALetter<<32:
return wbALetter, false, 132
case wbExtendNumLet | prHebrewLetter<<32:
return wbHebrewLetter, false, 132
case wbExtendNumLet | prNumeric<<32:
return wbNumeric, false, 132
case wbExtendNumLet | prKatakana<<32:
return wbKatakana, false, 132
default:
return -1, false, -1
}
}
// transitionWordBreakState determines the new state of the word break parser
// given the current state and the next code point. It also returns whether a
// word boundary was detected. If more than one code point is needed to
// determine the new state, the byte slice or the string starting after rune "r"
// can be used (whichever is not nil or empty) for further lookups.
func transitionWordBreakState(state int, r rune, b []byte, str string) (newState int, wordBreak bool) {
// Determine the property of the next character.
nextProperty := property(workBreakCodePoints, r)
// "Replacing Ignore Rules".
if nextProperty == prZWJ {
// WB4 (for zero-width joiners).
if state == wbNewline || state == wbCR || state == wbLF {
return wbAny | wbZWJBit, true // Make sure we don't apply WB4 to WB3a.
}
if state < 0 {
return wbAny | wbZWJBit, false
}
return state | wbZWJBit, false
} else if nextProperty == prExtend || nextProperty == prFormat {
// WB4 (for Extend and Format).
if state == wbNewline || state == wbCR || state == wbLF {
return wbAny, true // Make sure we don't apply WB4 to WB3a.
}
if state == wbWSegSpace || state == wbAny|wbZWJBit {
return wbAny, false // We don't break but this is also not WB3d or WB3c.
}
if state < 0 {
return wbAny, false
}
return state, false
} else if nextProperty == prExtendedPictographic && state >= 0 && state&wbZWJBit != 0 {
// WB3c.
return wbAny, false
}
if state >= 0 {
state = state &^ wbZWJBit
}
// Find the applicable transition in the table.
var rule int
newState, wordBreak, rule = wbTransitions(state, nextProperty)
if newState < 0 {
// No specific transition found. Try the less specific ones.
anyPropState, anyPropWordBreak, anyPropRule := wbTransitions(state, prAny)
anyStateState, anyStateWordBreak, anyStateRule := wbTransitions(wbAny, nextProperty)
if anyPropState >= 0 && anyStateState >= 0 {
// Both apply. We'll use a mix (see comments for grTransitions).
newState, wordBreak, rule = anyStateState, anyStateWordBreak, anyStateRule
if anyPropRule < anyStateRule {
wordBreak, rule = anyPropWordBreak, anyPropRule
}
} else if anyPropState >= 0 {
// We only have a specific state.
newState, wordBreak, rule = anyPropState, anyPropWordBreak, anyPropRule
// 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 anyStateState >= 0 {
// We only have a specific property.
newState, wordBreak, rule = anyStateState, anyStateWordBreak, anyStateRule
} else {
// No known transition. WB999: Any ÷ Any.
newState, wordBreak, rule = wbAny, true, 9990
}
}
// For those rules that need to look up runes further in the string, we
// determine the property after nextProperty, skipping over Format, Extend,
// and ZWJ (according to WB4). It's -1 if not needed, if such a rune cannot
// be determined (because the text ends or the rune is faulty).
farProperty := -1
if rule > 60 &&
(state == wbALetter || state == wbHebrewLetter || state == wbNumeric) &&
(nextProperty == prMidLetter || nextProperty == prMidNumLet || nextProperty == prSingleQuote || // WB6.
nextProperty == prDoubleQuote || // WB7b.
nextProperty == prMidNum) { // WB12.
for {
var (
r rune
length int
)
if b != nil { // Byte slice version.
r, length = utf8.DecodeRune(b)
b = b[length:]
} else { // String version.
r, length = utf8.DecodeRuneInString(str)
str = str[length:]
}
if r == utf8.RuneError {
break
}
prop := property(workBreakCodePoints, r)
if prop == prExtend || prop == prFormat || prop == prZWJ {
continue
}
farProperty = prop
break
}
}
// WB6.
if rule > 60 &&
(state == wbALetter || state == wbHebrewLetter) &&
(nextProperty == prMidLetter || nextProperty == prMidNumLet || nextProperty == prSingleQuote) &&
(farProperty == prALetter || farProperty == prHebrewLetter) {
return wbWB7, false
}
// WB7b.
if rule > 72 &&
state == wbHebrewLetter &&
nextProperty == prDoubleQuote &&
farProperty == prHebrewLetter {
return wbWB7c, false
}
// WB12.
if rule > 120 &&
state == wbNumeric &&
(nextProperty == prMidNum || nextProperty == prMidNumLet || nextProperty == prSingleQuote) &&
farProperty == prNumeric {
return wbWB11, false
}
// WB15 and WB16.
if newState == wbAny && nextProperty == prRegionalIndicator {
if state != wbOddRI && state != wbEvenRI { // Includes state == -1.
// Transition into the first RI.
return wbOddRI, true
}
if state == wbOddRI {
// Don't break pairs of Regional Indicators.
return wbEvenRI, false
}
return wbOddRI, true // We can break after a pair.
}
return
}

View File

@@ -1,21 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.5
package plan9
import "syscall"
func fixwd() {
syscall.Fixwd()
}
func Getwd() (wd string, err error) {
return syscall.Getwd()
}
func Chdir(path string) error {
return syscall.Chdir(path)
}

View File

@@ -2,22 +2,18 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !go1.5
package plan9 package plan9
import "syscall"
func fixwd() { func fixwd() {
syscall.Fixwd()
} }
func Getwd() (wd string, err error) { func Getwd() (wd string, err error) {
fd, err := open(".", O_RDONLY) return syscall.Getwd()
if err != nil {
return "", err
}
defer Close(fd)
return Fd2path(fd)
} }
func Chdir(path string) error { func Chdir(path string) error {
return chdir(path) return syscall.Chdir(path)
} }

View File

@@ -38,9 +38,7 @@ func SchedSetaffinity(pid int, set *CPUSet) error {
// Zero clears the set s, so that it contains no CPUs. // Zero clears the set s, so that it contains no CPUs.
func (s *CPUSet) Zero() { func (s *CPUSet) Zero() {
for i := range s { clear(s[:])
s[i] = 0
}
} }
func cpuBitsIndex(cpu int) int { func cpuBitsIndex(cpu int) int {

View File

@@ -349,6 +349,9 @@ struct ltchars {
#define _HIDIOCGRAWPHYS HIDIOCGRAWPHYS(_HIDIOCGRAWPHYS_LEN) #define _HIDIOCGRAWPHYS HIDIOCGRAWPHYS(_HIDIOCGRAWPHYS_LEN)
#define _HIDIOCGRAWUNIQ HIDIOCGRAWUNIQ(_HIDIOCGRAWUNIQ_LEN) #define _HIDIOCGRAWUNIQ HIDIOCGRAWUNIQ(_HIDIOCGRAWUNIQ_LEN)
// Renamed in v6.16, commit c6d732c38f93 ("net: ethtool: remove duplicate defines for family info")
#define ETHTOOL_FAMILY_NAME ETHTOOL_GENL_NAME
#define ETHTOOL_FAMILY_VERSION ETHTOOL_GENL_VERSION
' '
includes_NetBSD=' includes_NetBSD='

View File

@@ -602,14 +602,9 @@ func Connectx(fd int, srcIf uint32, srcAddr, dstAddr Sockaddr, associd SaeAssocI
return return
} }
// sys connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error)
const minIovec = 8 const minIovec = 8
func Readv(fd int, iovs [][]byte) (n int, err error) { func Readv(fd int, iovs [][]byte) (n int, err error) {
if !darwinKernelVersionMin(11, 0, 0) {
return 0, ENOSYS
}
iovecs := make([]Iovec, 0, minIovec) iovecs := make([]Iovec, 0, minIovec)
iovecs = appendBytes(iovecs, iovs) iovecs = appendBytes(iovecs, iovs)
n, err = readv(fd, iovecs) n, err = readv(fd, iovecs)
@@ -618,9 +613,6 @@ func Readv(fd int, iovs [][]byte) (n int, err error) {
} }
func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) { func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) {
if !darwinKernelVersionMin(11, 0, 0) {
return 0, ENOSYS
}
iovecs := make([]Iovec, 0, minIovec) iovecs := make([]Iovec, 0, minIovec)
iovecs = appendBytes(iovecs, iovs) iovecs = appendBytes(iovecs, iovs)
n, err = preadv(fd, iovecs, offset) n, err = preadv(fd, iovecs, offset)
@@ -629,10 +621,6 @@ func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) {
} }
func Writev(fd int, iovs [][]byte) (n int, err error) { func Writev(fd int, iovs [][]byte) (n int, err error) {
if !darwinKernelVersionMin(11, 0, 0) {
return 0, ENOSYS
}
iovecs := make([]Iovec, 0, minIovec) iovecs := make([]Iovec, 0, minIovec)
iovecs = appendBytes(iovecs, iovs) iovecs = appendBytes(iovecs, iovs)
if raceenabled { if raceenabled {
@@ -644,10 +632,6 @@ func Writev(fd int, iovs [][]byte) (n int, err error) {
} }
func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) { func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) {
if !darwinKernelVersionMin(11, 0, 0) {
return 0, ENOSYS
}
iovecs := make([]Iovec, 0, minIovec) iovecs := make([]Iovec, 0, minIovec)
iovecs = appendBytes(iovecs, iovs) iovecs = appendBytes(iovecs, iovs)
if raceenabled { if raceenabled {
@@ -707,45 +691,7 @@ func readvRacedetect(iovecs []Iovec, n int, err error) {
} }
} }
func darwinMajorMinPatch() (maj, min, patch int, err error) { //sys connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error)
var un Utsname
err = Uname(&un)
if err != nil {
return
}
var mmp [3]int
c := 0
Loop:
for _, b := range un.Release[:] {
switch {
case b >= '0' && b <= '9':
mmp[c] = 10*mmp[c] + int(b-'0')
case b == '.':
c++
if c > 2 {
return 0, 0, 0, ENOTSUP
}
case b == 0:
break Loop
default:
return 0, 0, 0, ENOTSUP
}
}
if c != 2 {
return 0, 0, 0, ENOTSUP
}
return mmp[0], mmp[1], mmp[2], nil
}
func darwinKernelVersionMin(maj, min, patch int) bool {
actualMaj, actualMin, actualPatch, err := darwinMajorMinPatch()
if err != nil {
return false
}
return actualMaj > maj || actualMaj == maj && (actualMin > min || actualMin == min && actualPatch >= patch)
}
//sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) //sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error)
//sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error) //sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error)

View File

@@ -629,7 +629,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
//sys Kill(pid int, signum syscall.Signal) (err error) //sys Kill(pid int, signum syscall.Signal) (err error)
//sys Lchown(path string, uid int, gid int) (err error) //sys Lchown(path string, uid int, gid int) (err error)
//sys Link(path string, link string) (err error) //sys Link(path string, link string) (err error)
//sys Listen(s int, backlog int) (err error) = libsocket.__xnet_llisten //sys Listen(s int, backlog int) (err error) = libsocket.__xnet_listen
//sys Lstat(path string, stat *Stat_t) (err error) //sys Lstat(path string, stat *Stat_t) (err error)
//sys Madvise(b []byte, advice int) (err error) //sys Madvise(b []byte, advice int) (err error)
//sys Mkdir(path string, mode uint32) (err error) //sys Mkdir(path string, mode uint32) (err error)

View File

@@ -328,6 +328,8 @@ const (
AUDIT_KERNEL = 0x7d0 AUDIT_KERNEL = 0x7d0
AUDIT_KERNEL_OTHER = 0x524 AUDIT_KERNEL_OTHER = 0x524
AUDIT_KERN_MODULE = 0x532 AUDIT_KERN_MODULE = 0x532
AUDIT_LANDLOCK_ACCESS = 0x58f
AUDIT_LANDLOCK_DOMAIN = 0x590
AUDIT_LAST_FEATURE = 0x1 AUDIT_LAST_FEATURE = 0x1
AUDIT_LAST_KERN_ANOM_MSG = 0x707 AUDIT_LAST_KERN_ANOM_MSG = 0x707
AUDIT_LAST_USER_MSG = 0x4af AUDIT_LAST_USER_MSG = 0x4af
@@ -492,6 +494,7 @@ const (
BPF_F_BEFORE = 0x8 BPF_F_BEFORE = 0x8
BPF_F_ID = 0x20 BPF_F_ID = 0x20
BPF_F_NETFILTER_IP_DEFRAG = 0x1 BPF_F_NETFILTER_IP_DEFRAG = 0x1
BPF_F_PREORDER = 0x40
BPF_F_QUERY_EFFECTIVE = 0x1 BPF_F_QUERY_EFFECTIVE = 0x1
BPF_F_REDIRECT_FLAGS = 0x19 BPF_F_REDIRECT_FLAGS = 0x19
BPF_F_REPLACE = 0x4 BPF_F_REPLACE = 0x4
@@ -528,6 +531,7 @@ const (
BPF_LDX = 0x1 BPF_LDX = 0x1
BPF_LEN = 0x80 BPF_LEN = 0x80
BPF_LL_OFF = -0x200000 BPF_LL_OFF = -0x200000
BPF_LOAD_ACQ = 0x100
BPF_LSH = 0x60 BPF_LSH = 0x60
BPF_MAJOR_VERSION = 0x1 BPF_MAJOR_VERSION = 0x1
BPF_MAXINSNS = 0x1000 BPF_MAXINSNS = 0x1000
@@ -555,6 +559,7 @@ const (
BPF_RET = 0x6 BPF_RET = 0x6
BPF_RSH = 0x70 BPF_RSH = 0x70
BPF_ST = 0x2 BPF_ST = 0x2
BPF_STORE_REL = 0x110
BPF_STX = 0x3 BPF_STX = 0x3
BPF_SUB = 0x10 BPF_SUB = 0x10
BPF_TAG_SIZE = 0x8 BPF_TAG_SIZE = 0x8
@@ -844,9 +849,9 @@ const (
DM_UUID_FLAG = 0x4000 DM_UUID_FLAG = 0x4000
DM_UUID_LEN = 0x81 DM_UUID_LEN = 0x81
DM_VERSION = 0xc138fd00 DM_VERSION = 0xc138fd00
DM_VERSION_EXTRA = "-ioctl (2025-01-17)" DM_VERSION_EXTRA = "-ioctl (2025-04-28)"
DM_VERSION_MAJOR = 0x4 DM_VERSION_MAJOR = 0x4
DM_VERSION_MINOR = 0x31 DM_VERSION_MINOR = 0x32
DM_VERSION_PATCHLEVEL = 0x0 DM_VERSION_PATCHLEVEL = 0x0
DT_BLK = 0x6 DT_BLK = 0x6
DT_CHR = 0x2 DT_CHR = 0x2
@@ -937,9 +942,6 @@ const (
EPOLL_CTL_MOD = 0x3 EPOLL_CTL_MOD = 0x3
EPOLL_IOC_TYPE = 0x8a EPOLL_IOC_TYPE = 0x8a
EROFS_SUPER_MAGIC_V1 = 0xe0f5e1e2 EROFS_SUPER_MAGIC_V1 = 0xe0f5e1e2
ESP_V4_FLOW = 0xa
ESP_V6_FLOW = 0xc
ETHER_FLOW = 0x12
ETHTOOL_BUSINFO_LEN = 0x20 ETHTOOL_BUSINFO_LEN = 0x20
ETHTOOL_EROMVERS_LEN = 0x20 ETHTOOL_EROMVERS_LEN = 0x20
ETHTOOL_FAMILY_NAME = "ethtool" ETHTOOL_FAMILY_NAME = "ethtool"
@@ -1213,6 +1215,7 @@ const (
FAN_EVENT_INFO_TYPE_DFID_NAME = 0x2 FAN_EVENT_INFO_TYPE_DFID_NAME = 0x2
FAN_EVENT_INFO_TYPE_ERROR = 0x5 FAN_EVENT_INFO_TYPE_ERROR = 0x5
FAN_EVENT_INFO_TYPE_FID = 0x1 FAN_EVENT_INFO_TYPE_FID = 0x1
FAN_EVENT_INFO_TYPE_MNT = 0x7
FAN_EVENT_INFO_TYPE_NEW_DFID_NAME = 0xc FAN_EVENT_INFO_TYPE_NEW_DFID_NAME = 0xc
FAN_EVENT_INFO_TYPE_OLD_DFID_NAME = 0xa FAN_EVENT_INFO_TYPE_OLD_DFID_NAME = 0xa
FAN_EVENT_INFO_TYPE_PIDFD = 0x4 FAN_EVENT_INFO_TYPE_PIDFD = 0x4
@@ -1231,9 +1234,12 @@ const (
FAN_MARK_IGNORED_SURV_MODIFY = 0x40 FAN_MARK_IGNORED_SURV_MODIFY = 0x40
FAN_MARK_IGNORE_SURV = 0x440 FAN_MARK_IGNORE_SURV = 0x440
FAN_MARK_INODE = 0x0 FAN_MARK_INODE = 0x0
FAN_MARK_MNTNS = 0x110
FAN_MARK_MOUNT = 0x10 FAN_MARK_MOUNT = 0x10
FAN_MARK_ONLYDIR = 0x8 FAN_MARK_ONLYDIR = 0x8
FAN_MARK_REMOVE = 0x2 FAN_MARK_REMOVE = 0x2
FAN_MNT_ATTACH = 0x1000000
FAN_MNT_DETACH = 0x2000000
FAN_MODIFY = 0x2 FAN_MODIFY = 0x2
FAN_MOVE = 0xc0 FAN_MOVE = 0xc0
FAN_MOVED_FROM = 0x40 FAN_MOVED_FROM = 0x40
@@ -1255,6 +1261,7 @@ const (
FAN_REPORT_DIR_FID = 0x400 FAN_REPORT_DIR_FID = 0x400
FAN_REPORT_FD_ERROR = 0x2000 FAN_REPORT_FD_ERROR = 0x2000
FAN_REPORT_FID = 0x200 FAN_REPORT_FID = 0x200
FAN_REPORT_MNT = 0x4000
FAN_REPORT_NAME = 0x800 FAN_REPORT_NAME = 0x800
FAN_REPORT_PIDFD = 0x80 FAN_REPORT_PIDFD = 0x80
FAN_REPORT_TARGET_FID = 0x1000 FAN_REPORT_TARGET_FID = 0x1000
@@ -1274,6 +1281,7 @@ const (
FIB_RULE_PERMANENT = 0x1 FIB_RULE_PERMANENT = 0x1
FIB_RULE_UNRESOLVED = 0x4 FIB_RULE_UNRESOLVED = 0x4
FIDEDUPERANGE = 0xc0189436 FIDEDUPERANGE = 0xc0189436
FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED = 0x1
FSCRYPT_KEY_DESCRIPTOR_SIZE = 0x8 FSCRYPT_KEY_DESCRIPTOR_SIZE = 0x8
FSCRYPT_KEY_DESC_PREFIX = "fscrypt:" FSCRYPT_KEY_DESC_PREFIX = "fscrypt:"
FSCRYPT_KEY_DESC_PREFIX_SIZE = 0x8 FSCRYPT_KEY_DESC_PREFIX_SIZE = 0x8
@@ -1582,7 +1590,6 @@ const (
IPV6_DONTFRAG = 0x3e IPV6_DONTFRAG = 0x3e
IPV6_DROP_MEMBERSHIP = 0x15 IPV6_DROP_MEMBERSHIP = 0x15
IPV6_DSTOPTS = 0x3b IPV6_DSTOPTS = 0x3b
IPV6_FLOW = 0x11
IPV6_FREEBIND = 0x4e IPV6_FREEBIND = 0x4e
IPV6_HDRINCL = 0x24 IPV6_HDRINCL = 0x24
IPV6_HOPLIMIT = 0x34 IPV6_HOPLIMIT = 0x34
@@ -1633,7 +1640,6 @@ const (
IPV6_TRANSPARENT = 0x4b IPV6_TRANSPARENT = 0x4b
IPV6_UNICAST_HOPS = 0x10 IPV6_UNICAST_HOPS = 0x10
IPV6_UNICAST_IF = 0x4c IPV6_UNICAST_IF = 0x4c
IPV6_USER_FLOW = 0xe
IPV6_V6ONLY = 0x1a IPV6_V6ONLY = 0x1a
IPV6_VERSION = 0x60 IPV6_VERSION = 0x60
IPV6_VERSION_MASK = 0xf0 IPV6_VERSION_MASK = 0xf0
@@ -1695,7 +1701,6 @@ const (
IP_TTL = 0x2 IP_TTL = 0x2
IP_UNBLOCK_SOURCE = 0x25 IP_UNBLOCK_SOURCE = 0x25
IP_UNICAST_IF = 0x32 IP_UNICAST_IF = 0x32
IP_USER_FLOW = 0xd
IP_XFRM_POLICY = 0x11 IP_XFRM_POLICY = 0x11
ISOFS_SUPER_MAGIC = 0x9660 ISOFS_SUPER_MAGIC = 0x9660
ISTRIP = 0x20 ISTRIP = 0x20
@@ -1817,7 +1822,11 @@ const (
LANDLOCK_ACCESS_FS_WRITE_FILE = 0x2 LANDLOCK_ACCESS_FS_WRITE_FILE = 0x2
LANDLOCK_ACCESS_NET_BIND_TCP = 0x1 LANDLOCK_ACCESS_NET_BIND_TCP = 0x1
LANDLOCK_ACCESS_NET_CONNECT_TCP = 0x2 LANDLOCK_ACCESS_NET_CONNECT_TCP = 0x2
LANDLOCK_CREATE_RULESET_ERRATA = 0x2
LANDLOCK_CREATE_RULESET_VERSION = 0x1 LANDLOCK_CREATE_RULESET_VERSION = 0x1
LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON = 0x2
LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF = 0x1
LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF = 0x4
LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET = 0x1 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET = 0x1
LANDLOCK_SCOPE_SIGNAL = 0x2 LANDLOCK_SCOPE_SIGNAL = 0x2
LINUX_REBOOT_CMD_CAD_OFF = 0x0 LINUX_REBOOT_CMD_CAD_OFF = 0x0
@@ -2493,6 +2502,10 @@ const (
PR_FP_EXC_UND = 0x40000 PR_FP_EXC_UND = 0x40000
PR_FP_MODE_FR = 0x1 PR_FP_MODE_FR = 0x1
PR_FP_MODE_FRE = 0x2 PR_FP_MODE_FRE = 0x2
PR_FUTEX_HASH = 0x4e
PR_FUTEX_HASH_GET_IMMUTABLE = 0x3
PR_FUTEX_HASH_GET_SLOTS = 0x2
PR_FUTEX_HASH_SET_SLOTS = 0x1
PR_GET_AUXV = 0x41555856 PR_GET_AUXV = 0x41555856
PR_GET_CHILD_SUBREAPER = 0x25 PR_GET_CHILD_SUBREAPER = 0x25
PR_GET_DUMPABLE = 0x3 PR_GET_DUMPABLE = 0x3
@@ -2652,6 +2665,10 @@ const (
PR_TAGGED_ADDR_ENABLE = 0x1 PR_TAGGED_ADDR_ENABLE = 0x1
PR_TASK_PERF_EVENTS_DISABLE = 0x1f PR_TASK_PERF_EVENTS_DISABLE = 0x1f
PR_TASK_PERF_EVENTS_ENABLE = 0x20 PR_TASK_PERF_EVENTS_ENABLE = 0x20
PR_TIMER_CREATE_RESTORE_IDS = 0x4d
PR_TIMER_CREATE_RESTORE_IDS_GET = 0x2
PR_TIMER_CREATE_RESTORE_IDS_OFF = 0x0
PR_TIMER_CREATE_RESTORE_IDS_ON = 0x1
PR_TIMING_STATISTICAL = 0x0 PR_TIMING_STATISTICAL = 0x0
PR_TIMING_TIMESTAMP = 0x1 PR_TIMING_TIMESTAMP = 0x1
PR_TSC_ENABLE = 0x1 PR_TSC_ENABLE = 0x1
@@ -2732,6 +2749,7 @@ const (
PTRACE_SETREGSET = 0x4205 PTRACE_SETREGSET = 0x4205
PTRACE_SETSIGINFO = 0x4203 PTRACE_SETSIGINFO = 0x4203
PTRACE_SETSIGMASK = 0x420b PTRACE_SETSIGMASK = 0x420b
PTRACE_SET_SYSCALL_INFO = 0x4212
PTRACE_SET_SYSCALL_USER_DISPATCH_CONFIG = 0x4210 PTRACE_SET_SYSCALL_USER_DISPATCH_CONFIG = 0x4210
PTRACE_SINGLESTEP = 0x9 PTRACE_SINGLESTEP = 0x9
PTRACE_SYSCALL = 0x18 PTRACE_SYSCALL = 0x18
@@ -2982,6 +3000,7 @@ const (
RTPROT_NTK = 0xf RTPROT_NTK = 0xf
RTPROT_OPENR = 0x63 RTPROT_OPENR = 0x63
RTPROT_OSPF = 0xbc RTPROT_OSPF = 0xbc
RTPROT_OVN = 0x54
RTPROT_RA = 0x9 RTPROT_RA = 0x9
RTPROT_REDIRECT = 0x1 RTPROT_REDIRECT = 0x1
RTPROT_RIP = 0xbd RTPROT_RIP = 0xbd
@@ -3336,7 +3355,7 @@ const (
TASKSTATS_GENL_NAME = "TASKSTATS" TASKSTATS_GENL_NAME = "TASKSTATS"
TASKSTATS_GENL_VERSION = 0x1 TASKSTATS_GENL_VERSION = 0x1
TASKSTATS_TYPE_MAX = 0x6 TASKSTATS_TYPE_MAX = 0x6
TASKSTATS_VERSION = 0xf TASKSTATS_VERSION = 0x10
TCIFLUSH = 0x0 TCIFLUSH = 0x0
TCIOFF = 0x2 TCIOFF = 0x2
TCIOFLUSH = 0x2 TCIOFLUSH = 0x2
@@ -3406,8 +3425,6 @@ const (
TCP_TX_DELAY = 0x25 TCP_TX_DELAY = 0x25
TCP_ULP = 0x1f TCP_ULP = 0x1f
TCP_USER_TIMEOUT = 0x12 TCP_USER_TIMEOUT = 0x12
TCP_V4_FLOW = 0x1
TCP_V6_FLOW = 0x5
TCP_WINDOW_CLAMP = 0xa TCP_WINDOW_CLAMP = 0xa
TCP_ZEROCOPY_RECEIVE = 0x23 TCP_ZEROCOPY_RECEIVE = 0x23
TFD_TIMER_ABSTIME = 0x1 TFD_TIMER_ABSTIME = 0x1
@@ -3530,8 +3547,6 @@ const (
UDP_NO_CHECK6_RX = 0x66 UDP_NO_CHECK6_RX = 0x66
UDP_NO_CHECK6_TX = 0x65 UDP_NO_CHECK6_TX = 0x65
UDP_SEGMENT = 0x67 UDP_SEGMENT = 0x67
UDP_V4_FLOW = 0x2
UDP_V6_FLOW = 0x6
UMOUNT_NOFOLLOW = 0x8 UMOUNT_NOFOLLOW = 0x8
USBDEVICE_SUPER_MAGIC = 0x9fa2 USBDEVICE_SUPER_MAGIC = 0x9fa2
UTIME_NOW = 0x3fffffff UTIME_NOW = 0x3fffffff
@@ -3574,7 +3589,7 @@ const (
WDIOS_TEMPPANIC = 0x4 WDIOS_TEMPPANIC = 0x4
WDIOS_UNKNOWN = -0x1 WDIOS_UNKNOWN = -0x1
WEXITED = 0x4 WEXITED = 0x4
WGALLOWEDIP_A_MAX = 0x3 WGALLOWEDIP_A_MAX = 0x4
WGDEVICE_A_MAX = 0x8 WGDEVICE_A_MAX = 0x8
WGPEER_A_MAX = 0xa WGPEER_A_MAX = 0xa
WG_CMD_MAX = 0x1 WG_CMD_MAX = 0x1
@@ -3688,6 +3703,7 @@ const (
XDP_SHARED_UMEM = 0x1 XDP_SHARED_UMEM = 0x1
XDP_STATISTICS = 0x7 XDP_STATISTICS = 0x7
XDP_TXMD_FLAGS_CHECKSUM = 0x2 XDP_TXMD_FLAGS_CHECKSUM = 0x2
XDP_TXMD_FLAGS_LAUNCH_TIME = 0x4
XDP_TXMD_FLAGS_TIMESTAMP = 0x1 XDP_TXMD_FLAGS_TIMESTAMP = 0x1
XDP_TX_METADATA = 0x2 XDP_TX_METADATA = 0x2
XDP_TX_RING = 0x3 XDP_TX_RING = 0x3

View File

@@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0xfd12
ECCGETLAYOUT = 0x81484d11 ECCGETLAYOUT = 0x81484d11
ECCGETSTATS = 0x80104d12 ECCGETSTATS = 0x80104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@@ -360,6 +361,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10 SO_PASSCRED = 0x10
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x11 SO_PEERCRED = 0x11

View File

@@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0xfd12
ECCGETLAYOUT = 0x81484d11 ECCGETLAYOUT = 0x81484d11
ECCGETSTATS = 0x80104d12 ECCGETSTATS = 0x80104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@@ -361,6 +362,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10 SO_PASSCRED = 0x10
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x11 SO_PEERCRED = 0x11

View File

@@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0xfd12
ECCGETLAYOUT = 0x81484d11 ECCGETLAYOUT = 0x81484d11
ECCGETSTATS = 0x80104d12 ECCGETSTATS = 0x80104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@@ -366,6 +367,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10 SO_PASSCRED = 0x10
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x11 SO_PEERCRED = 0x11

View File

@@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0xfd12
ECCGETLAYOUT = 0x81484d11 ECCGETLAYOUT = 0x81484d11
ECCGETSTATS = 0x80104d12 ECCGETSTATS = 0x80104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@@ -359,6 +360,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10 SO_PASSCRED = 0x10
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x11 SO_PEERCRED = 0x11

View File

@@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0xfd12
ECCGETLAYOUT = 0x81484d11 ECCGETLAYOUT = 0x81484d11
ECCGETSTATS = 0x80104d12 ECCGETSTATS = 0x80104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@@ -353,6 +354,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10 SO_PASSCRED = 0x10
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x11 SO_PEERCRED = 0x11

View File

@@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0x2000fd12
ECCGETLAYOUT = 0x41484d11 ECCGETLAYOUT = 0x41484d11
ECCGETSTATS = 0x40104d12 ECCGETSTATS = 0x40104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@@ -359,6 +360,7 @@ const (
SO_OOBINLINE = 0x100 SO_OOBINLINE = 0x100
SO_PASSCRED = 0x11 SO_PASSCRED = 0x11
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x12 SO_PEERCRED = 0x12

View File

@@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0x2000fd12
ECCGETLAYOUT = 0x41484d11 ECCGETLAYOUT = 0x41484d11
ECCGETSTATS = 0x40104d12 ECCGETSTATS = 0x40104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@@ -359,6 +360,7 @@ const (
SO_OOBINLINE = 0x100 SO_OOBINLINE = 0x100
SO_PASSCRED = 0x11 SO_PASSCRED = 0x11
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x12 SO_PEERCRED = 0x12

View File

@@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0x2000fd12
ECCGETLAYOUT = 0x41484d11 ECCGETLAYOUT = 0x41484d11
ECCGETSTATS = 0x40104d12 ECCGETSTATS = 0x40104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@@ -359,6 +360,7 @@ const (
SO_OOBINLINE = 0x100 SO_OOBINLINE = 0x100
SO_PASSCRED = 0x11 SO_PASSCRED = 0x11
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x12 SO_PEERCRED = 0x12

View File

@@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0x2000fd12
ECCGETLAYOUT = 0x41484d11 ECCGETLAYOUT = 0x41484d11
ECCGETSTATS = 0x40104d12 ECCGETSTATS = 0x40104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@@ -359,6 +360,7 @@ const (
SO_OOBINLINE = 0x100 SO_OOBINLINE = 0x100
SO_PASSCRED = 0x11 SO_PASSCRED = 0x11
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x12 SO_PEERCRED = 0x12

View File

@@ -68,6 +68,7 @@ const (
CS8 = 0x300 CS8 = 0x300
CSIZE = 0x300 CSIZE = 0x300
CSTOPB = 0x400 CSTOPB = 0x400
DM_MPATH_PROBE_PATHS = 0x2000fd12
ECCGETLAYOUT = 0x41484d11 ECCGETLAYOUT = 0x41484d11
ECCGETSTATS = 0x40104d12 ECCGETSTATS = 0x40104d12
ECHOCTL = 0x40 ECHOCTL = 0x40
@@ -414,6 +415,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x14 SO_PASSCRED = 0x14
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x15 SO_PEERCRED = 0x15

View File

@@ -68,6 +68,7 @@ const (
CS8 = 0x300 CS8 = 0x300
CSIZE = 0x300 CSIZE = 0x300
CSTOPB = 0x400 CSTOPB = 0x400
DM_MPATH_PROBE_PATHS = 0x2000fd12
ECCGETLAYOUT = 0x41484d11 ECCGETLAYOUT = 0x41484d11
ECCGETSTATS = 0x40104d12 ECCGETSTATS = 0x40104d12
ECHOCTL = 0x40 ECHOCTL = 0x40
@@ -418,6 +419,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x14 SO_PASSCRED = 0x14
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x15 SO_PEERCRED = 0x15

View File

@@ -68,6 +68,7 @@ const (
CS8 = 0x300 CS8 = 0x300
CSIZE = 0x300 CSIZE = 0x300
CSTOPB = 0x400 CSTOPB = 0x400
DM_MPATH_PROBE_PATHS = 0x2000fd12
ECCGETLAYOUT = 0x41484d11 ECCGETLAYOUT = 0x41484d11
ECCGETSTATS = 0x40104d12 ECCGETSTATS = 0x40104d12
ECHOCTL = 0x40 ECHOCTL = 0x40
@@ -418,6 +419,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x14 SO_PASSCRED = 0x14
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x15 SO_PEERCRED = 0x15

View File

@@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0xfd12
ECCGETLAYOUT = 0x81484d11 ECCGETLAYOUT = 0x81484d11
ECCGETSTATS = 0x80104d12 ECCGETSTATS = 0x80104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@@ -350,6 +351,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10 SO_PASSCRED = 0x10
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x11 SO_PEERCRED = 0x11

View File

@@ -68,6 +68,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0xfd12
ECCGETLAYOUT = 0x81484d11 ECCGETLAYOUT = 0x81484d11
ECCGETSTATS = 0x80104d12 ECCGETSTATS = 0x80104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@@ -422,6 +423,7 @@ const (
SO_OOBINLINE = 0xa SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10 SO_PASSCRED = 0x10
SO_PASSPIDFD = 0x4c SO_PASSPIDFD = 0x4c
SO_PASSRIGHTS = 0x53
SO_PASSSEC = 0x22 SO_PASSSEC = 0x22
SO_PEEK_OFF = 0x2a SO_PEEK_OFF = 0x2a
SO_PEERCRED = 0x11 SO_PEERCRED = 0x11

View File

@@ -71,6 +71,7 @@ const (
CS8 = 0x30 CS8 = 0x30
CSIZE = 0x30 CSIZE = 0x30
CSTOPB = 0x40 CSTOPB = 0x40
DM_MPATH_PROBE_PATHS = 0x2000fd12
ECCGETLAYOUT = 0x41484d11 ECCGETLAYOUT = 0x41484d11
ECCGETSTATS = 0x40104d12 ECCGETSTATS = 0x40104d12
ECHOCTL = 0x200 ECHOCTL = 0x200
@@ -461,6 +462,7 @@ const (
SO_OOBINLINE = 0x100 SO_OOBINLINE = 0x100
SO_PASSCRED = 0x2 SO_PASSCRED = 0x2
SO_PASSPIDFD = 0x55 SO_PASSPIDFD = 0x55
SO_PASSRIGHTS = 0x5c
SO_PASSSEC = 0x1f SO_PASSSEC = 0x1f
SO_PEEK_OFF = 0x26 SO_PEEK_OFF = 0x26
SO_PEERCRED = 0x40 SO_PEERCRED = 0x40

View File

@@ -72,7 +72,7 @@ import (
//go:cgo_import_dynamic libc_kill kill "libc.so" //go:cgo_import_dynamic libc_kill kill "libc.so"
//go:cgo_import_dynamic libc_lchown lchown "libc.so" //go:cgo_import_dynamic libc_lchown lchown "libc.so"
//go:cgo_import_dynamic libc_link link "libc.so" //go:cgo_import_dynamic libc_link link "libc.so"
//go:cgo_import_dynamic libc___xnet_llisten __xnet_llisten "libsocket.so" //go:cgo_import_dynamic libc___xnet_listen __xnet_listen "libsocket.so"
//go:cgo_import_dynamic libc_lstat lstat "libc.so" //go:cgo_import_dynamic libc_lstat lstat "libc.so"
//go:cgo_import_dynamic libc_madvise madvise "libc.so" //go:cgo_import_dynamic libc_madvise madvise "libc.so"
//go:cgo_import_dynamic libc_mkdir mkdir "libc.so" //go:cgo_import_dynamic libc_mkdir mkdir "libc.so"
@@ -221,7 +221,7 @@ import (
//go:linkname procKill libc_kill //go:linkname procKill libc_kill
//go:linkname procLchown libc_lchown //go:linkname procLchown libc_lchown
//go:linkname procLink libc_link //go:linkname procLink libc_link
//go:linkname proc__xnet_llisten libc___xnet_llisten //go:linkname proc__xnet_listen libc___xnet_listen
//go:linkname procLstat libc_lstat //go:linkname procLstat libc_lstat
//go:linkname procMadvise libc_madvise //go:linkname procMadvise libc_madvise
//go:linkname procMkdir libc_mkdir //go:linkname procMkdir libc_mkdir
@@ -371,7 +371,7 @@ var (
procKill, procKill,
procLchown, procLchown,
procLink, procLink,
proc__xnet_llisten, proc__xnet_listen,
procLstat, procLstat,
procMadvise, procMadvise,
procMkdir, procMkdir,
@@ -1178,7 +1178,7 @@ func Link(path string, link string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Listen(s int, backlog int) (err error) { func Listen(s int, backlog int) (err error) {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&proc__xnet_llisten)), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0) _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&proc__xnet_listen)), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
if e1 != 0 { if e1 != 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }

View File

@@ -462,4 +462,5 @@ const (
SYS_GETXATTRAT = 464 SYS_GETXATTRAT = 464
SYS_LISTXATTRAT = 465 SYS_LISTXATTRAT = 465
SYS_REMOVEXATTRAT = 466 SYS_REMOVEXATTRAT = 466
SYS_OPEN_TREE_ATTR = 467
) )

View File

@@ -385,4 +385,5 @@ const (
SYS_GETXATTRAT = 464 SYS_GETXATTRAT = 464
SYS_LISTXATTRAT = 465 SYS_LISTXATTRAT = 465
SYS_REMOVEXATTRAT = 466 SYS_REMOVEXATTRAT = 466
SYS_OPEN_TREE_ATTR = 467
) )

View File

@@ -426,4 +426,5 @@ const (
SYS_GETXATTRAT = 464 SYS_GETXATTRAT = 464
SYS_LISTXATTRAT = 465 SYS_LISTXATTRAT = 465
SYS_REMOVEXATTRAT = 466 SYS_REMOVEXATTRAT = 466
SYS_OPEN_TREE_ATTR = 467
) )

View File

@@ -329,4 +329,5 @@ const (
SYS_GETXATTRAT = 464 SYS_GETXATTRAT = 464
SYS_LISTXATTRAT = 465 SYS_LISTXATTRAT = 465
SYS_REMOVEXATTRAT = 466 SYS_REMOVEXATTRAT = 466
SYS_OPEN_TREE_ATTR = 467
) )

View File

@@ -325,4 +325,5 @@ const (
SYS_GETXATTRAT = 464 SYS_GETXATTRAT = 464
SYS_LISTXATTRAT = 465 SYS_LISTXATTRAT = 465
SYS_REMOVEXATTRAT = 466 SYS_REMOVEXATTRAT = 466
SYS_OPEN_TREE_ATTR = 467
) )

View File

@@ -446,4 +446,5 @@ const (
SYS_GETXATTRAT = 4464 SYS_GETXATTRAT = 4464
SYS_LISTXATTRAT = 4465 SYS_LISTXATTRAT = 4465
SYS_REMOVEXATTRAT = 4466 SYS_REMOVEXATTRAT = 4466
SYS_OPEN_TREE_ATTR = 4467
) )

View File

@@ -376,4 +376,5 @@ const (
SYS_GETXATTRAT = 5464 SYS_GETXATTRAT = 5464
SYS_LISTXATTRAT = 5465 SYS_LISTXATTRAT = 5465
SYS_REMOVEXATTRAT = 5466 SYS_REMOVEXATTRAT = 5466
SYS_OPEN_TREE_ATTR = 5467
) )

View File

@@ -376,4 +376,5 @@ const (
SYS_GETXATTRAT = 5464 SYS_GETXATTRAT = 5464
SYS_LISTXATTRAT = 5465 SYS_LISTXATTRAT = 5465
SYS_REMOVEXATTRAT = 5466 SYS_REMOVEXATTRAT = 5466
SYS_OPEN_TREE_ATTR = 5467
) )

View File

@@ -446,4 +446,5 @@ const (
SYS_GETXATTRAT = 4464 SYS_GETXATTRAT = 4464
SYS_LISTXATTRAT = 4465 SYS_LISTXATTRAT = 4465
SYS_REMOVEXATTRAT = 4466 SYS_REMOVEXATTRAT = 4466
SYS_OPEN_TREE_ATTR = 4467
) )

View File

@@ -453,4 +453,5 @@ const (
SYS_GETXATTRAT = 464 SYS_GETXATTRAT = 464
SYS_LISTXATTRAT = 465 SYS_LISTXATTRAT = 465
SYS_REMOVEXATTRAT = 466 SYS_REMOVEXATTRAT = 466
SYS_OPEN_TREE_ATTR = 467
) )

View File

@@ -425,4 +425,5 @@ const (
SYS_GETXATTRAT = 464 SYS_GETXATTRAT = 464
SYS_LISTXATTRAT = 465 SYS_LISTXATTRAT = 465
SYS_REMOVEXATTRAT = 466 SYS_REMOVEXATTRAT = 466
SYS_OPEN_TREE_ATTR = 467
) )

View File

@@ -425,4 +425,5 @@ const (
SYS_GETXATTRAT = 464 SYS_GETXATTRAT = 464
SYS_LISTXATTRAT = 465 SYS_LISTXATTRAT = 465
SYS_REMOVEXATTRAT = 466 SYS_REMOVEXATTRAT = 466
SYS_OPEN_TREE_ATTR = 467
) )

View File

@@ -330,4 +330,5 @@ const (
SYS_GETXATTRAT = 464 SYS_GETXATTRAT = 464
SYS_LISTXATTRAT = 465 SYS_LISTXATTRAT = 465
SYS_REMOVEXATTRAT = 466 SYS_REMOVEXATTRAT = 466
SYS_OPEN_TREE_ATTR = 467
) )

View File

@@ -391,4 +391,5 @@ const (
SYS_GETXATTRAT = 464 SYS_GETXATTRAT = 464
SYS_LISTXATTRAT = 465 SYS_LISTXATTRAT = 465
SYS_REMOVEXATTRAT = 466 SYS_REMOVEXATTRAT = 466
SYS_OPEN_TREE_ATTR = 467
) )

View File

@@ -404,4 +404,5 @@ const (
SYS_GETXATTRAT = 464 SYS_GETXATTRAT = 464
SYS_LISTXATTRAT = 465 SYS_LISTXATTRAT = 465
SYS_REMOVEXATTRAT = 466 SYS_REMOVEXATTRAT = 466
SYS_OPEN_TREE_ATTR = 467
) )

View File

@@ -115,7 +115,9 @@ type Statx_t struct {
Atomic_write_unit_max uint32 Atomic_write_unit_max uint32
Atomic_write_segments_max uint32 Atomic_write_segments_max uint32
Dio_read_offset_align uint32 Dio_read_offset_align uint32
_ [9]uint64 Atomic_write_unit_max_opt uint32
_ [1]uint32
_ [8]uint64
} }
type Fsid struct { type Fsid struct {
@@ -199,7 +201,8 @@ type FscryptAddKeyArg struct {
Key_spec FscryptKeySpecifier Key_spec FscryptKeySpecifier
Raw_size uint32 Raw_size uint32
Key_id uint32 Key_id uint32
_ [8]uint32 Flags uint32
_ [7]uint32
} }
type FscryptRemoveKeyArg struct { type FscryptRemoveKeyArg struct {
@@ -629,6 +632,8 @@ const (
IFA_FLAGS = 0x8 IFA_FLAGS = 0x8
IFA_RT_PRIORITY = 0x9 IFA_RT_PRIORITY = 0x9
IFA_TARGET_NETNSID = 0xa IFA_TARGET_NETNSID = 0xa
IFAL_LABEL = 0x2
IFAL_ADDRESS = 0x1
RT_SCOPE_UNIVERSE = 0x0 RT_SCOPE_UNIVERSE = 0x0
RT_SCOPE_SITE = 0xc8 RT_SCOPE_SITE = 0xc8
RT_SCOPE_LINK = 0xfd RT_SCOPE_LINK = 0xfd
@@ -686,6 +691,7 @@ const (
SizeofRtAttr = 0x4 SizeofRtAttr = 0x4
SizeofIfInfomsg = 0x10 SizeofIfInfomsg = 0x10
SizeofIfAddrmsg = 0x8 SizeofIfAddrmsg = 0x8
SizeofIfAddrlblmsg = 0xc
SizeofIfaCacheinfo = 0x10 SizeofIfaCacheinfo = 0x10
SizeofRtMsg = 0xc SizeofRtMsg = 0xc
SizeofRtNexthop = 0x8 SizeofRtNexthop = 0x8
@@ -737,6 +743,15 @@ type IfAddrmsg struct {
Index uint32 Index uint32
} }
type IfAddrlblmsg struct {
Family uint8
_ uint8
Prefixlen uint8
Flags uint8
Index uint32
Seq uint32
}
type IfaCacheinfo struct { type IfaCacheinfo struct {
Prefered uint32 Prefered uint32
Valid uint32 Valid uint32
@@ -2317,6 +2332,11 @@ const (
NFT_CT_AVGPKT = 0x10 NFT_CT_AVGPKT = 0x10
NFT_CT_ZONE = 0x11 NFT_CT_ZONE = 0x11
NFT_CT_EVENTMASK = 0x12 NFT_CT_EVENTMASK = 0x12
NFT_CT_SRC_IP = 0x13
NFT_CT_DST_IP = 0x14
NFT_CT_SRC_IP6 = 0x15
NFT_CT_DST_IP6 = 0x16
NFT_CT_ID = 0x17
NFTA_CT_UNSPEC = 0x0 NFTA_CT_UNSPEC = 0x0
NFTA_CT_DREG = 0x1 NFTA_CT_DREG = 0x1
NFTA_CT_KEY = 0x2 NFTA_CT_KEY = 0x2
@@ -2597,8 +2617,8 @@ const (
SOF_TIMESTAMPING_BIND_PHC = 0x8000 SOF_TIMESTAMPING_BIND_PHC = 0x8000
SOF_TIMESTAMPING_OPT_ID_TCP = 0x10000 SOF_TIMESTAMPING_OPT_ID_TCP = 0x10000
SOF_TIMESTAMPING_LAST = 0x20000 SOF_TIMESTAMPING_LAST = 0x40000
SOF_TIMESTAMPING_MASK = 0x3ffff SOF_TIMESTAMPING_MASK = 0x7ffff
SCM_TSTAMP_SND = 0x0 SCM_TSTAMP_SND = 0x0
SCM_TSTAMP_SCHED = 0x1 SCM_TSTAMP_SCHED = 0x1
@@ -3044,6 +3064,23 @@ const (
) )
const ( const (
TCA_UNSPEC = 0x0
TCA_KIND = 0x1
TCA_OPTIONS = 0x2
TCA_STATS = 0x3
TCA_XSTATS = 0x4
TCA_RATE = 0x5
TCA_FCNT = 0x6
TCA_STATS2 = 0x7
TCA_STAB = 0x8
TCA_PAD = 0x9
TCA_DUMP_INVISIBLE = 0xa
TCA_CHAIN = 0xb
TCA_HW_OFFLOAD = 0xc
TCA_INGRESS_BLOCK = 0xd
TCA_EGRESS_BLOCK = 0xe
TCA_DUMP_FLAGS = 0xf
TCA_EXT_WARN_MSG = 0x10
RTNLGRP_NONE = 0x0 RTNLGRP_NONE = 0x0
RTNLGRP_LINK = 0x1 RTNLGRP_LINK = 0x1
RTNLGRP_NOTIFY = 0x2 RTNLGRP_NOTIFY = 0x2
@@ -3078,6 +3115,18 @@ const (
RTNLGRP_IPV6_MROUTE_R = 0x1f RTNLGRP_IPV6_MROUTE_R = 0x1f
RTNLGRP_NEXTHOP = 0x20 RTNLGRP_NEXTHOP = 0x20
RTNLGRP_BRVLAN = 0x21 RTNLGRP_BRVLAN = 0x21
RTNLGRP_MCTP_IFADDR = 0x22
RTNLGRP_TUNNEL = 0x23
RTNLGRP_STATS = 0x24
RTNLGRP_IPV4_MCADDR = 0x25
RTNLGRP_IPV6_MCADDR = 0x26
RTNLGRP_IPV6_ACADDR = 0x27
TCA_ROOT_UNSPEC = 0x0
TCA_ROOT_TAB = 0x1
TCA_ROOT_FLAGS = 0x2
TCA_ROOT_COUNT = 0x3
TCA_ROOT_TIME_DELTA = 0x4
TCA_ROOT_EXT_WARN_MSG = 0x5
) )
type CapUserHeader struct { type CapUserHeader struct {
@@ -4044,7 +4093,7 @@ const (
ETHTOOL_A_TSINFO_PHC_INDEX = 0x5 ETHTOOL_A_TSINFO_PHC_INDEX = 0x5
ETHTOOL_A_TSINFO_STATS = 0x6 ETHTOOL_A_TSINFO_STATS = 0x6
ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER = 0x7 ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER = 0x7
ETHTOOL_A_TSINFO_MAX = 0x7 ETHTOOL_A_TSINFO_MAX = 0x9
ETHTOOL_A_CABLE_TEST_UNSPEC = 0x0 ETHTOOL_A_CABLE_TEST_UNSPEC = 0x0
ETHTOOL_A_CABLE_TEST_HEADER = 0x1 ETHTOOL_A_CABLE_TEST_HEADER = 0x1
ETHTOOL_A_CABLE_TEST_MAX = 0x1 ETHTOOL_A_CABLE_TEST_MAX = 0x1
@@ -4130,6 +4179,19 @@ const (
ETHTOOL_A_TUNNEL_INFO_MAX = 0x2 ETHTOOL_A_TUNNEL_INFO_MAX = 0x2
) )
const (
TCP_V4_FLOW = 0x1
UDP_V4_FLOW = 0x2
TCP_V6_FLOW = 0x5
UDP_V6_FLOW = 0x6
ESP_V4_FLOW = 0xa
ESP_V6_FLOW = 0xc
IP_USER_FLOW = 0xd
IPV6_USER_FLOW = 0xe
IPV6_FLOW = 0x11
ETHER_FLOW = 0x12
)
const SPEED_UNKNOWN = -0x1 const SPEED_UNKNOWN = -0x1
type EthtoolDrvinfo struct { type EthtoolDrvinfo struct {
@@ -4780,7 +4842,7 @@ const (
NL80211_ATTR_MAC_HINT = 0xc8 NL80211_ATTR_MAC_HINT = 0xc8
NL80211_ATTR_MAC_MASK = 0xd7 NL80211_ATTR_MAC_MASK = 0xd7
NL80211_ATTR_MAX_AP_ASSOC_STA = 0xca NL80211_ATTR_MAX_AP_ASSOC_STA = 0xca
NL80211_ATTR_MAX = 0x150 NL80211_ATTR_MAX = 0x151
NL80211_ATTR_MAX_CRIT_PROT_DURATION = 0xb4 NL80211_ATTR_MAX_CRIT_PROT_DURATION = 0xb4
NL80211_ATTR_MAX_CSA_COUNTERS = 0xce NL80211_ATTR_MAX_CSA_COUNTERS = 0xce
NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS = 0x143 NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS = 0x143
@@ -5414,7 +5476,7 @@ const (
NL80211_FREQUENCY_ATTR_GO_CONCURRENT = 0xf NL80211_FREQUENCY_ATTR_GO_CONCURRENT = 0xf
NL80211_FREQUENCY_ATTR_INDOOR_ONLY = 0xe NL80211_FREQUENCY_ATTR_INDOOR_ONLY = 0xe
NL80211_FREQUENCY_ATTR_IR_CONCURRENT = 0xf NL80211_FREQUENCY_ATTR_IR_CONCURRENT = 0xf
NL80211_FREQUENCY_ATTR_MAX = 0x21 NL80211_FREQUENCY_ATTR_MAX = 0x22
NL80211_FREQUENCY_ATTR_MAX_TX_POWER = 0x6 NL80211_FREQUENCY_ATTR_MAX_TX_POWER = 0x6
NL80211_FREQUENCY_ATTR_NO_10MHZ = 0x11 NL80211_FREQUENCY_ATTR_NO_10MHZ = 0x11
NL80211_FREQUENCY_ATTR_NO_160MHZ = 0xc NL80211_FREQUENCY_ATTR_NO_160MHZ = 0xc
@@ -5530,7 +5592,7 @@ const (
NL80211_MAX_SUPP_SELECTORS = 0x80 NL80211_MAX_SUPP_SELECTORS = 0x80
NL80211_MBSSID_CONFIG_ATTR_EMA = 0x5 NL80211_MBSSID_CONFIG_ATTR_EMA = 0x5
NL80211_MBSSID_CONFIG_ATTR_INDEX = 0x3 NL80211_MBSSID_CONFIG_ATTR_INDEX = 0x3
NL80211_MBSSID_CONFIG_ATTR_MAX = 0x5 NL80211_MBSSID_CONFIG_ATTR_MAX = 0x6
NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY = 0x2 NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY = 0x2
NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES = 0x1 NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES = 0x1
NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX = 0x4 NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX = 0x4

View File

@@ -282,19 +282,13 @@ type Taskstats struct {
Ac_exitcode uint32 Ac_exitcode uint32
Ac_flag uint8 Ac_flag uint8
Ac_nice uint8 Ac_nice uint8
_ [4]byte _ [6]byte
Cpu_count uint64 Cpu_count uint64
Cpu_delay_total uint64 Cpu_delay_total uint64
Cpu_delay_max uint64
Cpu_delay_min uint64
Blkio_count uint64 Blkio_count uint64
Blkio_delay_total uint64 Blkio_delay_total uint64
Blkio_delay_max uint64
Blkio_delay_min uint64
Swapin_count uint64 Swapin_count uint64
Swapin_delay_total uint64 Swapin_delay_total uint64
Swapin_delay_max uint64
Swapin_delay_min uint64
Cpu_run_real_total uint64 Cpu_run_real_total uint64
Cpu_run_virtual_total uint64 Cpu_run_virtual_total uint64
Ac_comm [32]int8 Ac_comm [32]int8
@@ -330,17 +324,11 @@ type Taskstats struct {
Cpu_scaled_run_real_total uint64 Cpu_scaled_run_real_total uint64
Freepages_count uint64 Freepages_count uint64
Freepages_delay_total uint64 Freepages_delay_total uint64
Freepages_delay_max uint64
Freepages_delay_min uint64
Thrashing_count uint64 Thrashing_count uint64
Thrashing_delay_total uint64 Thrashing_delay_total uint64
Thrashing_delay_max uint64
Thrashing_delay_min uint64
Ac_btime64 uint64 Ac_btime64 uint64
Compact_count uint64 Compact_count uint64
Compact_delay_total uint64 Compact_delay_total uint64
Compact_delay_max uint64
Compact_delay_min uint64
Ac_tgid uint32 Ac_tgid uint32
_ [4]byte _ [4]byte
Ac_tgetime uint64 Ac_tgetime uint64
@@ -348,10 +336,22 @@ type Taskstats struct {
Ac_exe_inode uint64 Ac_exe_inode uint64
Wpcopy_count uint64 Wpcopy_count uint64
Wpcopy_delay_total uint64 Wpcopy_delay_total uint64
Wpcopy_delay_max uint64
Wpcopy_delay_min uint64
Irq_count uint64 Irq_count uint64
Irq_delay_total uint64 Irq_delay_total uint64
Cpu_delay_max uint64
Cpu_delay_min uint64
Blkio_delay_max uint64
Blkio_delay_min uint64
Swapin_delay_max uint64
Swapin_delay_min uint64
Freepages_delay_max uint64
Freepages_delay_min uint64
Thrashing_delay_max uint64
Thrashing_delay_min uint64
Compact_delay_max uint64
Compact_delay_min uint64
Wpcopy_delay_max uint64
Wpcopy_delay_min uint64
Irq_delay_max uint64 Irq_delay_max uint64
Irq_delay_min uint64 Irq_delay_min uint64
} }

Some files were not shown because too many files have changed in this diff Show More