1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-04-21 12:16:54 +02:00

Bump gocui (and tcell)

This updates our tcell dependency to v2.8.0, adding support for ghostty and
tmux-256color.
This commit is contained in:
Stefan Haller 2025-01-11 21:54:30 +01:00
parent a1a8cd114d
commit 274e24d75e
32 changed files with 963 additions and 318 deletions

5
go.mod
View File

@ -8,7 +8,7 @@ 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.7.4 github.com/gdamore/tcell/v2 v2.8.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/iancoleman/orderedmap v0.3.0 github.com/iancoleman/orderedmap v0.3.0
@ -16,7 +16,7 @@ require (
github.com/integrii/flaggy v1.4.0 github.com/integrii/flaggy v1.4.0
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
github.com/jesseduffield/gocui v0.3.1-0.20250107151125-716b1eb82fb4 github.com/jesseduffield/gocui v0.3.1-0.20250111205211-82d518436b5a
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a
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
@ -54,7 +54,6 @@ require (
github.com/go-git/go-billy/v5 v5.0.0 // indirect github.com/go-git/go-billy/v5 v5.0.0 // indirect
github.com/go-logfmt/logfmt v0.5.0 // indirect github.com/go-logfmt/logfmt v0.5.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect github.com/gobwas/glob v0.2.3 // indirect
github.com/google/go-cmp v0.5.6 // indirect
github.com/invopop/jsonschema v0.10.0 // indirect github.com/invopop/jsonschema v0.10.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect

39
go.sum
View File

@ -85,11 +85,10 @@ github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
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.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU= github.com/gdamore/tcell/v2 v2.8.0 h1:IDclow1j6kKpU/gOhjmc+7Pj5Dxnukb74pfKN4Cxrfg=
github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg= github.com/gdamore/tcell/v2 v2.8.0/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
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=
@ -145,8 +144,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@ -188,8 +187,8 @@ github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8T
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE= github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE=
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o= github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
github.com/jesseduffield/gocui v0.3.1-0.20250107151125-716b1eb82fb4 h1:hSAimLVb4b5ktU3uJRtBsZW0P2dtXECReTcsHYfOy58= github.com/jesseduffield/gocui v0.3.1-0.20250111205211-82d518436b5a h1:GLFWB8rESraTt2eIe2yssy4d4VEkCnmKbPeeZ5vCT2s=
github.com/jesseduffield/gocui v0.3.1-0.20250107151125-716b1eb82fb4/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8= github.com/jesseduffield/gocui v0.3.1-0.20250111205211-82d518436b5a/go.mod h1:sLIyZ2J42R6idGdtemZzsiR3xY5EF0KsvYEGh3dQv3s=
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a h1:UDeJ3EBk04bXDLOPvuqM3on8HvyJfISw0+UMqW+0a4g= github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a h1:UDeJ3EBk04bXDLOPvuqM3on8HvyJfISw0+UMqW+0a4g=
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a/go.mod h1:FSWDLKT0NQpntbDd1H3lbz51fhCVlMzy/J0S6nM727Q= github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a/go.mod h1:FSWDLKT0NQpntbDd1H3lbz51fhCVlMzy/J0S6nM727Q=
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY= github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
@ -235,7 +234,6 @@ 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.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= 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/mgutz/str v1.2.0 h1:4IzWSdIz9qPQWLfKZ0rJcV0jcUDpxvP4JVZ4GXQyvSw= github.com/mgutz/str v1.2.0 h1:4IzWSdIz9qPQWLfKZ0rJcV0jcUDpxvP4JVZ4GXQyvSw=
@ -328,6 +326,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -367,6 +368,9 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -402,6 +406,10 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -425,6 +433,9 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
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/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=
@ -475,13 +486,20 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
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/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=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
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.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
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/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=
@ -493,7 +511,10 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
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.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
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/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=
@ -548,6 +569,8 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -20,7 +20,7 @@ In `tcell.js`, you also need to change the constant
```js ```js
const wasmFilePath = "yourfile.wasm" const wasmFilePath = "yourfile.wasm"
``` ```
to the file you outputed to when building. to the file you outputted to when building.
## Displaying your project ## Displaying your project
@ -49,7 +49,7 @@ func main() {
To see the webpage with this example, you can type in `localhost:8080/tcell.html` into your browser while `server.go` is running. To see the webpage with this example, you can type in `localhost:8080/tcell.html` into your browser while `server.go` is running.
### Embedding ### Embedding
It is recomended to use an iframe if you want to embed the app into a webpage: It is recommended to use an iframe if you want to embed the app into a webpage:
```html ```html
<iframe src="tcell.html" title="Tcell app"></iframe> <iframe src="tcell.html" title="Tcell app"></iframe>
``` ```

View File

@ -33,7 +33,7 @@ A brief, and still somewhat rough, [tutorial](TUTORIAL.md) is available.
- [godu](https://github.com/viktomas/godu) - utility to discover large files/folders - [godu](https://github.com/viktomas/godu) - utility to discover large files/folders
- [tview](https://github.com/rivo/tview/) - rich interactive widgets - [tview](https://github.com/rivo/tview/) - rich interactive widgets
- [cview](https://code.rocketnine.space/tslocum/cview) - user interface toolkit (fork of _tview_) - [cview](https://code.rocketnine.space/tslocum/cview) - user interface toolkit (fork of _tview_)
- [awsome gocui](https://github.com/awesome-gocui/gocui) - Go Console User Interface - [awesome gocui](https://github.com/awesome-gocui/gocui) - Go Console User Interface
- [gomandelbrot](https://github.com/rgm3/gomandelbrot) - Mandelbrot! - [gomandelbrot](https://github.com/rgm3/gomandelbrot) - Mandelbrot!
- [WTF](https://github.com/senorprogrammer/wtf) - personal information dashboard - [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)) - [browsh](https://github.com/browsh-org/browsh) - modern web browser ([video](https://www.youtube.com/watch?v=HZq86XfBoRo))
@ -67,6 +67,8 @@ A brief, and still somewhat rough, [tutorial](TUTORIAL.md) is available.
- [gbb](https://github.com/sdemingo/gbb) - A classical bulletin board app for tildes or public unix servers - [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 - [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)) - [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
@ -143,7 +145,7 @@ Most _termbox-go_ programs will probably work without further modification.
Internally _Tcell_ uses UTF-8, just like Go. Internally _Tcell_ uses UTF-8, just like Go.
However, _Tcell_ understands how to However, _Tcell_ understands how to
convert to and from other character sets, using the capabilities of convert to and from other character sets, using the capabilities of
the `golang.org/x/text/encoding packages`. the `golang.org/x/text/encoding` packages.
Your application must supply Your application must supply
them, as the full set of the most common ones bloats the program by about 2 MB. them, as the full set of the most common ones bloats the program by about 2 MB.
If you're lazy, and want them all anyway, see the `encoding` sub-directory. If you're lazy, and want them all anyway, see the `encoding` sub-directory.

View File

@ -1,4 +1,4 @@
// Copyright 2020 The TCell Authors // Copyright 2024 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.
@ -19,15 +19,16 @@ package tcell
type AttrMask int type AttrMask int
// Attributes are not colors, but affect the display of text. They can // Attributes are not colors, but affect the display of text. They can
// be combined. // be combined, in some cases, but not others. (E.g. you can have Dim Italic,
// but only CurlyUnderline cannot be mixed with DottedUnderline.)
const ( const (
AttrBold AttrMask = 1 << iota AttrBold AttrMask = 1 << iota
AttrBlink AttrBlink
AttrReverse AttrReverse
AttrUnderline AttrUnderline // Deprecated: Use UnderlineStyle
AttrDim AttrDim
AttrItalic AttrItalic
AttrStrikeThrough AttrStrikeThrough
AttrInvalid // Mark the style or attributes invalid AttrInvalid AttrMask = 1 << 31 // Mark the style or attributes invalid
AttrNone AttrMask = 0 // Just normal text. AttrNone AttrMask = 0 // Just normal text.
) )

View File

@ -58,7 +58,7 @@ func (cb *CellBuffer) SetContent(x int, y int,
// dirty as well as the base cell, to make sure we consider // dirty as well as the base cell, to make sure we consider
// both cells as dirty together. We only need to do this // both cells as dirty together. We only need to do this
// if we're changing content // if we're changing content
if (c.width > 0) && (mainc != c.currMain || !reflect.DeepEqual(combc, c.currComb)) { if (c.width > 0) && (mainc != c.currMain || len(combc) != len(c.currComb) || (len(combc) > 0 && !reflect.DeepEqual(combc, c.currComb))) {
for i := 0; i < c.width; i++ { for i := 0; i < c.width; i++ {
cb.SetDirty(x+i, y, true) cb.SetDirty(x+i, y, true)
} }
@ -246,11 +246,4 @@ func init() {
if os.Getenv("RUNEWIDTH_EASTASIAN") == "" { if os.Getenv("RUNEWIDTH_EASTASIAN") == "" {
runewidth.DefaultCondition.EastAsianWidth = false runewidth.DefaultCondition.EastAsianWidth = false
} }
// For performance reasons, we create a lookup table. However, some users
// might be more memory conscious. If that's you, set the TCELL_MINIMIZE
// environment variable.
if os.Getenv("TCELL_MINIMIZE") == "" {
runewidth.CreateLUT()
}
} }

View File

@ -314,129 +314,129 @@ const (
Color253 Color253
Color254 Color254
Color255 Color255
ColorAliceBlue ColorAliceBlue = ColorIsRGB | ColorValid | 0xF0F8FF
ColorAntiqueWhite ColorAntiqueWhite = ColorIsRGB | ColorValid | 0xFAEBD7
ColorAquaMarine ColorAquaMarine = ColorIsRGB | ColorValid | 0x7FFFD4
ColorAzure ColorAzure = ColorIsRGB | ColorValid | 0xF0FFFF
ColorBeige ColorBeige = ColorIsRGB | ColorValid | 0xF5F5DC
ColorBisque ColorBisque = ColorIsRGB | ColorValid | 0xFFE4C4
ColorBlanchedAlmond ColorBlanchedAlmond = ColorIsRGB | ColorValid | 0xFFEBCD
ColorBlueViolet ColorBlueViolet = ColorIsRGB | ColorValid | 0x8A2BE2
ColorBrown ColorBrown = ColorIsRGB | ColorValid | 0xA52A2A
ColorBurlyWood ColorBurlyWood = ColorIsRGB | ColorValid | 0xDEB887
ColorCadetBlue ColorCadetBlue = ColorIsRGB | ColorValid | 0x5F9EA0
ColorChartreuse ColorChartreuse = ColorIsRGB | ColorValid | 0x7FFF00
ColorChocolate ColorChocolate = ColorIsRGB | ColorValid | 0xD2691E
ColorCoral ColorCoral = ColorIsRGB | ColorValid | 0xFF7F50
ColorCornflowerBlue ColorCornflowerBlue = ColorIsRGB | ColorValid | 0x6495ED
ColorCornsilk ColorCornsilk = ColorIsRGB | ColorValid | 0xFFF8DC
ColorCrimson ColorCrimson = ColorIsRGB | ColorValid | 0xDC143C
ColorDarkBlue ColorDarkBlue = ColorIsRGB | ColorValid | 0x00008B
ColorDarkCyan ColorDarkCyan = ColorIsRGB | ColorValid | 0x008B8B
ColorDarkGoldenrod ColorDarkGoldenrod = ColorIsRGB | ColorValid | 0xB8860B
ColorDarkGray ColorDarkGray = ColorIsRGB | ColorValid | 0xA9A9A9
ColorDarkGreen ColorDarkGreen = ColorIsRGB | ColorValid | 0x006400
ColorDarkKhaki ColorDarkKhaki = ColorIsRGB | ColorValid | 0xBDB76B
ColorDarkMagenta ColorDarkMagenta = ColorIsRGB | ColorValid | 0x8B008B
ColorDarkOliveGreen ColorDarkOliveGreen = ColorIsRGB | ColorValid | 0x556B2F
ColorDarkOrange ColorDarkOrange = ColorIsRGB | ColorValid | 0xFF8C00
ColorDarkOrchid ColorDarkOrchid = ColorIsRGB | ColorValid | 0x9932CC
ColorDarkRed ColorDarkRed = ColorIsRGB | ColorValid | 0x8B0000
ColorDarkSalmon ColorDarkSalmon = ColorIsRGB | ColorValid | 0xE9967A
ColorDarkSeaGreen ColorDarkSeaGreen = ColorIsRGB | ColorValid | 0x8FBC8F
ColorDarkSlateBlue ColorDarkSlateBlue = ColorIsRGB | ColorValid | 0x483D8B
ColorDarkSlateGray ColorDarkSlateGray = ColorIsRGB | ColorValid | 0x2F4F4F
ColorDarkTurquoise ColorDarkTurquoise = ColorIsRGB | ColorValid | 0x00CED1
ColorDarkViolet ColorDarkViolet = ColorIsRGB | ColorValid | 0x9400D3
ColorDeepPink ColorDeepPink = ColorIsRGB | ColorValid | 0xFF1493
ColorDeepSkyBlue ColorDeepSkyBlue = ColorIsRGB | ColorValid | 0x00BFFF
ColorDimGray ColorDimGray = ColorIsRGB | ColorValid | 0x696969
ColorDodgerBlue ColorDodgerBlue = ColorIsRGB | ColorValid | 0x1E90FF
ColorFireBrick ColorFireBrick = ColorIsRGB | ColorValid | 0xB22222
ColorFloralWhite ColorFloralWhite = ColorIsRGB | ColorValid | 0xFFFAF0
ColorForestGreen ColorForestGreen = ColorIsRGB | ColorValid | 0x228B22
ColorGainsboro ColorGainsboro = ColorIsRGB | ColorValid | 0xDCDCDC
ColorGhostWhite ColorGhostWhite = ColorIsRGB | ColorValid | 0xF8F8FF
ColorGold ColorGold = ColorIsRGB | ColorValid | 0xFFD700
ColorGoldenrod ColorGoldenrod = ColorIsRGB | ColorValid | 0xDAA520
ColorGreenYellow ColorGreenYellow = ColorIsRGB | ColorValid | 0xADFF2F
ColorHoneydew ColorHoneydew = ColorIsRGB | ColorValid | 0xF0FFF0
ColorHotPink ColorHotPink = ColorIsRGB | ColorValid | 0xFF69B4
ColorIndianRed ColorIndianRed = ColorIsRGB | ColorValid | 0xCD5C5C
ColorIndigo ColorIndigo = ColorIsRGB | ColorValid | 0x4B0082
ColorIvory ColorIvory = ColorIsRGB | ColorValid | 0xFFFFF0
ColorKhaki ColorKhaki = ColorIsRGB | ColorValid | 0xF0E68C
ColorLavender ColorLavender = ColorIsRGB | ColorValid | 0xE6E6FA
ColorLavenderBlush ColorLavenderBlush = ColorIsRGB | ColorValid | 0xFFF0F5
ColorLawnGreen ColorLawnGreen = ColorIsRGB | ColorValid | 0x7CFC00
ColorLemonChiffon ColorLemonChiffon = ColorIsRGB | ColorValid | 0xFFFACD
ColorLightBlue ColorLightBlue = ColorIsRGB | ColorValid | 0xADD8E6
ColorLightCoral ColorLightCoral = ColorIsRGB | ColorValid | 0xF08080
ColorLightCyan ColorLightCyan = ColorIsRGB | ColorValid | 0xE0FFFF
ColorLightGoldenrodYellow ColorLightGoldenrodYellow = ColorIsRGB | ColorValid | 0xFAFAD2
ColorLightGray ColorLightGray = ColorIsRGB | ColorValid | 0xD3D3D3
ColorLightGreen ColorLightGreen = ColorIsRGB | ColorValid | 0x90EE90
ColorLightPink ColorLightPink = ColorIsRGB | ColorValid | 0xFFB6C1
ColorLightSalmon ColorLightSalmon = ColorIsRGB | ColorValid | 0xFFA07A
ColorLightSeaGreen ColorLightSeaGreen = ColorIsRGB | ColorValid | 0x20B2AA
ColorLightSkyBlue ColorLightSkyBlue = ColorIsRGB | ColorValid | 0x87CEFA
ColorLightSlateGray ColorLightSlateGray = ColorIsRGB | ColorValid | 0x778899
ColorLightSteelBlue ColorLightSteelBlue = ColorIsRGB | ColorValid | 0xB0C4DE
ColorLightYellow ColorLightYellow = ColorIsRGB | ColorValid | 0xFFFFE0
ColorLimeGreen ColorLimeGreen = ColorIsRGB | ColorValid | 0x32CD32
ColorLinen ColorLinen = ColorIsRGB | ColorValid | 0xFAF0E6
ColorMediumAquamarine ColorMediumAquamarine = ColorIsRGB | ColorValid | 0x66CDAA
ColorMediumBlue ColorMediumBlue = ColorIsRGB | ColorValid | 0x0000CD
ColorMediumOrchid ColorMediumOrchid = ColorIsRGB | ColorValid | 0xBA55D3
ColorMediumPurple ColorMediumPurple = ColorIsRGB | ColorValid | 0x9370DB
ColorMediumSeaGreen ColorMediumSeaGreen = ColorIsRGB | ColorValid | 0x3CB371
ColorMediumSlateBlue ColorMediumSlateBlue = ColorIsRGB | ColorValid | 0x7B68EE
ColorMediumSpringGreen ColorMediumSpringGreen = ColorIsRGB | ColorValid | 0x00FA9A
ColorMediumTurquoise ColorMediumTurquoise = ColorIsRGB | ColorValid | 0x48D1CC
ColorMediumVioletRed ColorMediumVioletRed = ColorIsRGB | ColorValid | 0xC71585
ColorMidnightBlue ColorMidnightBlue = ColorIsRGB | ColorValid | 0x191970
ColorMintCream ColorMintCream = ColorIsRGB | ColorValid | 0xF5FFFA
ColorMistyRose ColorMistyRose = ColorIsRGB | ColorValid | 0xFFE4E1
ColorMoccasin ColorMoccasin = ColorIsRGB | ColorValid | 0xFFE4B5
ColorNavajoWhite ColorNavajoWhite = ColorIsRGB | ColorValid | 0xFFDEAD
ColorOldLace ColorOldLace = ColorIsRGB | ColorValid | 0xFDF5E6
ColorOliveDrab ColorOliveDrab = ColorIsRGB | ColorValid | 0x6B8E23
ColorOrange ColorOrange = ColorIsRGB | ColorValid | 0xFFA500
ColorOrangeRed ColorOrangeRed = ColorIsRGB | ColorValid | 0xFF4500
ColorOrchid ColorOrchid = ColorIsRGB | ColorValid | 0xDA70D6
ColorPaleGoldenrod ColorPaleGoldenrod = ColorIsRGB | ColorValid | 0xEEE8AA
ColorPaleGreen ColorPaleGreen = ColorIsRGB | ColorValid | 0x98FB98
ColorPaleTurquoise ColorPaleTurquoise = ColorIsRGB | ColorValid | 0xAFEEEE
ColorPaleVioletRed ColorPaleVioletRed = ColorIsRGB | ColorValid | 0xDB7093
ColorPapayaWhip ColorPapayaWhip = ColorIsRGB | ColorValid | 0xFFEFD5
ColorPeachPuff ColorPeachPuff = ColorIsRGB | ColorValid | 0xFFDAB9
ColorPeru ColorPeru = ColorIsRGB | ColorValid | 0xCD853F
ColorPink ColorPink = ColorIsRGB | ColorValid | 0xFFC0CB
ColorPlum ColorPlum = ColorIsRGB | ColorValid | 0xDDA0DD
ColorPowderBlue ColorPowderBlue = ColorIsRGB | ColorValid | 0xB0E0E6
ColorRebeccaPurple ColorRebeccaPurple = ColorIsRGB | ColorValid | 0x663399
ColorRosyBrown ColorRosyBrown = ColorIsRGB | ColorValid | 0xBC8F8F
ColorRoyalBlue ColorRoyalBlue = ColorIsRGB | ColorValid | 0x4169E1
ColorSaddleBrown ColorSaddleBrown = ColorIsRGB | ColorValid | 0x8B4513
ColorSalmon ColorSalmon = ColorIsRGB | ColorValid | 0xFA8072
ColorSandyBrown ColorSandyBrown = ColorIsRGB | ColorValid | 0xF4A460
ColorSeaGreen ColorSeaGreen = ColorIsRGB | ColorValid | 0x2E8B57
ColorSeashell ColorSeashell = ColorIsRGB | ColorValid | 0xFFF5EE
ColorSienna ColorSienna = ColorIsRGB | ColorValid | 0xA0522D
ColorSkyblue ColorSkyblue = ColorIsRGB | ColorValid | 0x87CEEB
ColorSlateBlue ColorSlateBlue = ColorIsRGB | ColorValid | 0x6A5ACD
ColorSlateGray ColorSlateGray = ColorIsRGB | ColorValid | 0x708090
ColorSnow ColorSnow = ColorIsRGB | ColorValid | 0xFFFAFA
ColorSpringGreen ColorSpringGreen = ColorIsRGB | ColorValid | 0x00FF7F
ColorSteelBlue ColorSteelBlue = ColorIsRGB | ColorValid | 0x4682B4
ColorTan ColorTan = ColorIsRGB | ColorValid | 0xD2B48C
ColorThistle ColorThistle = ColorIsRGB | ColorValid | 0xD8BFD8
ColorTomato ColorTomato = ColorIsRGB | ColorValid | 0xFF6347
ColorTurquoise ColorTurquoise = ColorIsRGB | ColorValid | 0x40E0D0
ColorViolet ColorViolet = ColorIsRGB | ColorValid | 0xEE82EE
ColorWheat ColorWheat = ColorIsRGB | ColorValid | 0xF5DEB3
ColorWhiteSmoke ColorWhiteSmoke = ColorIsRGB | ColorValid | 0xF5F5F5
ColorYellowGreen ColorYellowGreen = ColorIsRGB | ColorValid | 0x9ACD32
) )
// These are aliases for the color gray, because some of us spell // These are aliases for the color gray, because some of us spell

View File

@ -42,6 +42,7 @@ type cScreen struct {
truecolor bool truecolor bool
running bool running bool
disableAlt bool // disable the alternate screen disableAlt bool // disable the alternate screen
title string
w int w int
h int h int
@ -49,6 +50,7 @@ type cScreen struct {
oscreen consoleInfo oscreen consoleInfo
ocursor cursorInfo ocursor cursorInfo
cursorStyle CursorStyle cursorStyle CursorStyle
cursorColor Color
oimode uint32 oimode uint32
oomode uint32 oomode uint32
cells CellBuffer cells CellBuffer
@ -164,6 +166,20 @@ const (
vtEnableAm = "\x1b[?7h" vtEnableAm = "\x1b[?7h"
vtEnterCA = "\x1b[?1049h\x1b[22;0;0t" vtEnterCA = "\x1b[?1049h\x1b[22;0;0t"
vtExitCA = "\x1b[?1049l\x1b[23;0;0t" vtExitCA = "\x1b[?1049l\x1b[23;0;0t"
vtDoubleUnderline = "\x1b[4:2m"
vtCurlyUnderline = "\x1b[4:3m"
vtDottedUnderline = "\x1b[4:4m"
vtDashedUnderline = "\x1b[4:5m"
vtUnderColor = "\x1b[58:5:%dm"
vtUnderColorRGB = "\x1b[58:2::%d:%d:%dm"
vtUnderColorReset = "\x1b[59m"
vtEnterUrl = "\x1b]8;%s;%s\x1b\\" // NB arg 1 is id, arg 2 is url
vtExitUrl = "\x1b]8;;\x1b\\"
vtCursorColorRGB = "\x1b]12;#%02x%02x%02x\007"
vtCursorColorReset = "\x1b]112\007"
vtSaveTitle = "\x1b[22;2t"
vtRestoreTitle = "\x1b[23;2t"
vtSetTitle = "\x1b]2;%s\x1b\\"
) )
var vtCursorStyles = map[CursorStyle]string{ var vtCursorStyles = map[CursorStyle]string{
@ -335,8 +351,10 @@ func (s *cScreen) disengage() {
if s.vten { if s.vten {
s.emitVtString(vtCursorStyles[CursorStyleDefault]) s.emitVtString(vtCursorStyles[CursorStyleDefault])
s.emitVtString(vtCursorColorReset)
s.emitVtString(vtEnableAm) s.emitVtString(vtEnableAm)
if !s.disableAlt { if !s.disableAlt {
s.emitVtString(vtRestoreTitle)
s.emitVtString(vtExitCA) s.emitVtString(vtExitCA)
} }
} else if !s.disableAlt { } else if !s.disableAlt {
@ -374,9 +392,13 @@ func (s *cScreen) engage() error {
if s.vten { if s.vten {
s.setOutMode(modeVtOutput | modeNoAutoNL | modeCookedOut | modeUnderline) s.setOutMode(modeVtOutput | modeNoAutoNL | modeCookedOut | modeUnderline)
if !s.disableAlt { if !s.disableAlt {
s.emitVtString(vtSaveTitle)
s.emitVtString(vtEnterCA) s.emitVtString(vtEnterCA)
} }
s.emitVtString(vtDisableAm) s.emitVtString(vtDisableAm)
if s.title != "" {
s.emitVtString(fmt.Sprintf(vtSetTitle, s.title))
}
} else { } else {
s.setOutMode(0) s.setOutMode(0)
} }
@ -426,6 +448,12 @@ func (s *cScreen) showCursor() {
if s.vten { if s.vten {
s.emitVtString(vtShowCursor) s.emitVtString(vtShowCursor)
s.emitVtString(vtCursorStyles[s.cursorStyle]) s.emitVtString(vtCursorStyles[s.cursorStyle])
if s.cursorColor == ColorReset {
s.emitVtString(vtCursorColorReset)
} else if s.cursorColor.Valid() {
r, g, b := s.cursorColor.RGB()
s.emitVtString(fmt.Sprintf(vtCursorColorRGB, r, g, b))
}
} else { } else {
s.setCursorInfo(&cursorInfo{size: 100, visible: 1}) s.setCursorInfo(&cursorInfo{size: 100, visible: 1})
} }
@ -449,11 +477,12 @@ func (s *cScreen) ShowCursor(x, y int) {
s.Unlock() s.Unlock()
} }
func (s *cScreen) SetCursorStyle(cs CursorStyle) { func (s *cScreen) SetCursor(cs CursorStyle, cc Color) {
s.Lock() s.Lock()
if !s.fini { if !s.fini {
if _, ok := vtCursorStyles[cs]; ok { if _, ok := vtCursorStyles[cs]; ok {
s.cursorStyle = cs s.cursorStyle = cs
s.cursorColor = cc
s.doCursor() s.doCursor()
} }
} }
@ -875,7 +904,7 @@ func mapColor2RGB(c Color) uint16 {
// Map a tcell style to Windows attributes // Map a tcell style to Windows attributes
func (s *cScreen) mapStyle(style Style) uint16 { func (s *cScreen) mapStyle(style Style) uint16 {
f, b, a := style.Decompose() f, b, a := style.fg, style.bg, style.attrs
fa := s.oscreen.attrs & 0xf fa := s.oscreen.attrs & 0xf
ba := (s.oscreen.attrs) >> 4 & 0xf ba := (s.oscreen.attrs) >> 4 & 0xf
if f != ColorDefault && f != ColorReset { if f != ColorDefault && f != ColorReset {
@ -912,19 +941,41 @@ func (s *cScreen) mapStyle(style Style) uint16 {
func (s *cScreen) sendVtStyle(style Style) { func (s *cScreen) sendVtStyle(style Style) {
esc := &strings.Builder{} esc := &strings.Builder{}
fg, bg, attrs := style.Decompose() fg, bg, attrs := style.fg, style.bg, style.attrs
us, uc := style.ulStyle, style.ulColor
esc.WriteString(vtSgr0) esc.WriteString(vtSgr0)
if attrs&(AttrBold|AttrDim) == AttrBold { if attrs&(AttrBold|AttrDim) == AttrBold {
esc.WriteString(vtBold) esc.WriteString(vtBold)
} }
if attrs&AttrBlink != 0 { if attrs&AttrBlink != 0 {
esc.WriteString(vtBlink) esc.WriteString(vtBlink)
} }
if attrs&AttrUnderline != 0 { if us != UnderlineStyleNone {
esc.WriteString(vtUnderline) if uc == ColorReset {
esc.WriteString(vtUnderColorReset)
} else if uc.IsRGB() {
r, g, b := uc.RGB()
_, _ = fmt.Fprintf(esc, vtUnderColorRGB, int(r), int(g), int(b))
} else if uc.Valid() {
_, _ = fmt.Fprintf(esc, vtUnderColor, uc&0xff)
} }
esc.WriteString(vtUnderline)
// legacy ConHost does not understand these but Terminal does
switch us {
case UnderlineStyleSolid:
case UnderlineStyleDouble:
esc.WriteString(vtDoubleUnderline)
case UnderlineStyleCurly:
esc.WriteString(vtCurlyUnderline)
case UnderlineStyleDotted:
esc.WriteString(vtDottedUnderline)
case UnderlineStyleDashed:
esc.WriteString(vtDashedUnderline)
}
}
if attrs&AttrReverse != 0 { if attrs&AttrReverse != 0 {
esc.WriteString(vtReverse) esc.WriteString(vtReverse)
} }
@ -940,6 +991,13 @@ func (s *cScreen) sendVtStyle(style Style) {
} else if bg.Valid() { } else if bg.Valid() {
_, _ = fmt.Fprintf(esc, vtSetBg, bg&0xff) _, _ = fmt.Fprintf(esc, vtSetBg, bg&0xff)
} }
// URL string can be long, so don't send it unless we really need to
if style.url != "" {
_, _ = fmt.Fprintf(esc, vtEnterUrl, style.urlId, style.url)
} else {
esc.WriteString(vtExitUrl)
}
s.emitVtString(esc.String()) s.emitVtString(esc.String())
} }
@ -1062,7 +1120,6 @@ func (s *cScreen) setCursorInfo(info *cursorInfo) {
_, _, _ = procSetConsoleCursorInfo.Call( _, _, _ = procSetConsoleCursorInfo.Call(
uintptr(s.out), uintptr(s.out),
uintptr(unsafe.Pointer(info))) uintptr(unsafe.Pointer(info)))
} }
func (s *cScreen) setCursorPos(x, y int, vtEnable bool) { func (s *cScreen) setCursorPos(x, y int, vtEnable bool) {
@ -1227,6 +1284,15 @@ func (s *cScreen) SetStyle(style Style) {
s.Unlock() s.Unlock()
} }
func (s *cScreen) SetTitle(title string) {
s.Lock()
s.title = title
if s.vten {
s.emitVtString(fmt.Sprintf(vtSetTitle, title))
}
s.Unlock()
}
// No fallback rune support, since we have Unicode. Yay! // No fallback rune support, since we have Unicode. Yay!
func (s *cScreen) RegisterRuneFallback(_ rune, _ string) { func (s *cScreen) RegisterRuneFallback(_ rune, _ string) {
@ -1246,6 +1312,12 @@ func (s *cScreen) HasMouse() bool {
return true return true
} }
func (s *cScreen) SetClipboard(_ []byte) {
}
func (s *cScreen) GetClipboard() {
}
func (s *cScreen) Resize(int, int, int, int) {} func (s *cScreen) Resize(int, int, int, int) {}
func (s *cScreen) HasKey(k Key) bool { func (s *cScreen) HasKey(k Key) bool {

View File

@ -1,4 +1,4 @@
// Copyright 2020 The TCell Authors // Copyright 2024 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.
@ -19,12 +19,14 @@ import (
) )
// EventPaste is used to mark the start and end of a bracketed paste. // EventPaste is used to mark the start and end of a bracketed paste.
// An event with .Start() true will be sent to mark the start. //
// Then a number of keys will be sent to indicate that the content // An event with .Start() true will be sent to mark the start of a bracketed paste,
// is pasted in. At the end, an event with .Start() false will be sent. // followed by a number of keys (string data) for the content, ending with the
// an event with .End() true.
type EventPaste struct { type EventPaste struct {
start bool start bool
t time.Time t time.Time
data []byte
} }
// When returns the time when this EventPaste was created. // When returns the time when this EventPaste was created.
@ -46,3 +48,25 @@ func (ev *EventPaste) End() bool {
func NewEventPaste(start bool) *EventPaste { func NewEventPaste(start bool) *EventPaste {
return &EventPaste{t: time.Now(), start: start} return &EventPaste{t: time.Now(), start: start}
} }
// NewEventClipboard returns a new NewEventClipboard with a data payload
func NewEventClipboard(data []byte) *EventClipboard {
return &EventClipboard{t: time.Now(), data: data}
}
// EventClipboard represents data from the clipboard,
// in response to a GetClipboard request.
type EventClipboard struct {
t time.Time
data []byte
}
// Data returns the attached binary data.
func (ev *EventClipboard) Data() []byte {
return ev.data
}
// When returns the time when this event was created.
func (ev *EventClipboard) When() time.Time {
return ev.t
}

View File

@ -1,4 +1,4 @@
// Copyright 2023 The TCell Authors // Copyright 2024 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.
@ -79,8 +79,9 @@ type Screen interface {
// SetCursorStyle is used to set the cursor style. If the style // SetCursorStyle is used to set the cursor style. If the style
// is not supported (or cursor styles are not supported at all), // is not supported (or cursor styles are not supported at all),
// then this will have no effect. // then this will have no effect. Color will be changed if supplied,
SetCursorStyle(CursorStyle) // and the terminal supports doing so.
SetCursorStyle(CursorStyle, ...Color)
// Size returns the screen size as width, height. This changes in // Size returns the screen size as width, height. This changes in
// response to a call to Clear or Flush. // response to a call to Clear or Flush.
@ -265,6 +266,23 @@ type Screen interface {
// Tty returns the underlying Tty. If the screen is not a terminal, the // Tty returns the underlying Tty. If the screen is not a terminal, the
// returned bool will be false // returned bool will be false
Tty() (Tty, bool) Tty() (Tty, bool)
// SetTitle sets a window title on the screen.
// Terminals may be configured to ignore this, or unable to.
// Tcell may attempt to save and restore the window title on entry and exit, but
// the results may vary. Use of unicode characters may not be supported.
SetTitle(string)
// SetClipboard is used to post arbitrary data to the system clipboard.
// This need not be UTF-8 string data. It's up to the recipient to decode the
// data meaningfully. Terminals may prevent this for security reasons.
SetClipboard([]byte)
// GetClipboard is used to request the clipboard contents. It may be ignored.
// If the terminal is willing, it will be post the clipboard contents using an
// EventPaste with the clipboard content as the Data() field. Terminals may
// prevent this for security reasons.
GetClipboard()
} }
// NewScreen returns a default Screen suitable for the user's terminal // NewScreen returns a default Screen suitable for the user's terminal
@ -312,7 +330,7 @@ type screenImpl interface {
SetStyle(style Style) SetStyle(style Style)
ShowCursor(x int, y int) ShowCursor(x int, y int)
HideCursor() HideCursor()
SetCursorStyle(CursorStyle) SetCursor(CursorStyle, Color)
Size() (width, height int) Size() (width, height int)
EnableMouse(...MouseFlags) EnableMouse(...MouseFlags)
DisableMouse() DisableMouse()
@ -334,7 +352,10 @@ type screenImpl interface {
Resume() error Resume() error
Beep() error Beep() error
SetSize(int, int) SetSize(int, int)
SetTitle(string)
Tty() (Tty, bool) Tty() (Tty, bool)
SetClipboard([]byte)
GetClipboard()
// Following methods are not part of the Screen api, but are used for interaction with // Following methods are not part of the Screen api, but are used for interaction with
// the common layer code. // the common layer code.
@ -464,3 +485,11 @@ func (b *baseScreen) PostEvent(ev Event) error {
return ErrEventQFull return ErrEventQFull
} }
} }
func (b *baseScreen) SetCursorStyle(cs CursorStyle, ccs ...Color) {
if len(ccs) > 0 {
b.SetCursor(cs, ccs[0])
} else {
b.SetCursor(cs, ColorNone)
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2023 The TCell Authors // Copyright 2024 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.
@ -60,6 +60,12 @@ type SimulationScreen interface {
// GetCursor returns the cursor details. // GetCursor returns the cursor details.
GetCursor() (x int, y int, visible bool) GetCursor() (x int, y int, visible bool)
// GetTitle gets the previously set title.
GetTitle() string
// GetClipboardData gets the actual data for the clipboard.
GetClipboardData() []byte
} }
// SimCell represents a simulated screen cell. The purpose of this // SimCell represents a simulated screen cell. The purpose of this
@ -98,6 +104,8 @@ type simscreen struct {
fillchar rune fillchar rune
fillstyle Style fillstyle Style
fallback map[rune]string fallback map[rune]string
title string
clipboard []byte
Screen Screen
sync.Mutex sync.Mutex
@ -239,7 +247,7 @@ func (s *simscreen) hideCursor() {
s.cursorvis = false s.cursorvis = false
} }
func (s *simscreen) SetCursorStyle(CursorStyle) {} func (s *simscreen) SetCursor(CursorStyle, Color) {}
func (s *simscreen) Show() { func (s *simscreen) Show() {
s.Lock() s.Lock()
@ -495,3 +503,26 @@ func (s *simscreen) EventQ() chan Event {
func (s *simscreen) StopQ() <-chan struct{} { func (s *simscreen) StopQ() <-chan struct{} {
return s.quit return s.quit
} }
func (s *simscreen) SetTitle(title string) {
s.title = title
}
func (s *simscreen) GetTitle() string {
return s.title
}
func (s *simscreen) SetClipboard(data []byte) {
s.clipboard = data
}
func (s *simscreen) GetClipboard() {
if s.clipboard != nil {
ev := NewEventClipboard(s.clipboard)
s.postEvent(ev)
}
}
func (s *simscreen) GetClipboardData() []byte {
return s.clipboard
}

View File

@ -1,4 +1,4 @@
// Copyright 2022 The TCell Authors // Copyright 2024 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.
@ -25,6 +25,8 @@ package tcell
type Style struct { type Style struct {
fg Color fg Color
bg Color bg Color
ulStyle UnderlineStyle
ulColor Color
attrs AttrMask attrs AttrMask
url string url string
urlId string urlId string
@ -40,50 +42,35 @@ var styleInvalid = Style{attrs: AttrInvalid}
// Foreground returns a new style based on s, with the foreground color set // Foreground returns a new style based on s, with the foreground color set
// as requested. ColorDefault can be used to select the global default. // as requested. ColorDefault can be used to select the global default.
func (s Style) Foreground(c Color) Style { func (s Style) Foreground(c Color) Style {
return Style{ s2 := s
fg: c, s2.fg = c
bg: s.bg, return s2
attrs: s.attrs,
url: s.url,
urlId: s.urlId,
}
} }
// Background returns a new style based on s, with the background color set // Background returns a new style based on s, with the background color set
// as requested. ColorDefault can be used to select the global default. // as requested. ColorDefault can be used to select the global default.
func (s Style) Background(c Color) Style { func (s Style) Background(c Color) Style {
return Style{ s2 := s
fg: s.fg, s2.bg = c
bg: c, return s2
attrs: s.attrs,
url: s.url,
urlId: s.urlId,
}
} }
// Decompose breaks a style up, returning the foreground, background, // Decompose breaks a style up, returning the foreground, background,
// and other attributes. The URL if set is not included. // and other attributes. The URL if set is not included.
// Deprecated: Applications should not attempt to decompose style,
// as this content is not sufficient to describe the actual style.
func (s Style) Decompose() (fg Color, bg Color, attr AttrMask) { func (s Style) Decompose() (fg Color, bg Color, attr AttrMask) {
return s.fg, s.bg, s.attrs return s.fg, s.bg, s.attrs
} }
func (s Style) setAttrs(attrs AttrMask, on bool) Style { func (s Style) setAttrs(attrs AttrMask, on bool) Style {
s2 := s
if on { if on {
return Style{ s2.attrs |= attrs
fg: s.fg, } else {
bg: s.bg, s2.attrs &^= attrs
attrs: s.attrs | attrs,
url: s.url,
urlId: s.urlId,
}
}
return Style{
fg: s.fg,
bg: s.bg,
attrs: s.attrs &^ attrs,
url: s.url,
urlId: s.urlId,
} }
return s2
} }
// Normal returns the style with all attributes disabled. // Normal returns the style with all attributes disabled.
@ -125,40 +112,73 @@ func (s Style) Reverse(on bool) Style {
return s.setAttrs(AttrReverse, on) return s.setAttrs(AttrReverse, on)
} }
// Underline returns a new style based on s, with the underline attribute set
// as requested.
func (s Style) Underline(on bool) Style {
return s.setAttrs(AttrUnderline, on)
}
// StrikeThrough sets strikethrough mode. // StrikeThrough sets strikethrough mode.
func (s Style) StrikeThrough(on bool) Style { func (s Style) StrikeThrough(on bool) Style {
return s.setAttrs(AttrStrikeThrough, on) return s.setAttrs(AttrStrikeThrough, on)
} }
// Underline style. Modern terminals have the option of rendering the
// underline using different styles, and even different colors.
type UnderlineStyle int
const (
UnderlineStyleNone = UnderlineStyle(iota)
UnderlineStyleSolid
UnderlineStyleDouble
UnderlineStyleCurly
UnderlineStyleDotted
UnderlineStyleDashed
)
// Underline returns a new style based on s, with the underline attribute set
// as requested. The parameters can be:
//
// bool: on / off - enables just a simple underline
// UnderlineStyle: sets a specific style (should not coexist with the bool)
// Color: the color to use
func (s Style) Underline(params ...interface{}) Style {
s2 := s
for _, param := range params {
switch v := param.(type) {
case bool:
if v {
s2.ulStyle = UnderlineStyleSolid
s2.attrs |= AttrUnderline
} else {
s2.ulStyle = UnderlineStyleNone
s2.attrs &^= AttrUnderline
}
case UnderlineStyle:
if v == UnderlineStyleNone {
s2.attrs &^= AttrUnderline
} else {
s2.attrs |= AttrUnderline
}
s2.ulStyle = v
case Color:
s2.ulColor = v
default:
panic("Bad type for underline")
}
}
return s2
}
// 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 {
return Style{ s2 := s
fg: s.fg, s2.attrs = attrs
bg: s.bg, return s2
attrs: attrs,
url: s.url,
urlId: s.urlId,
}
} }
// Url returns a style with the Url set. If the provided Url is not empty, // Url returns a style with the Url set. If the provided Url is not empty,
// and the terminal supports it, text will typically be marked up as a clickable // and the terminal supports it, text will typically be marked up as a clickable
// link to that Url. If the Url is empty, then this mode is turned off. // link to that Url. If the Url is empty, then this mode is turned off.
func (s Style) Url(url string) Style { func (s Style) Url(url string) Style {
return Style{ s2 := s
fg: s.fg, s2.url = url
bg: s.bg, return s2
attrs: s.attrs,
url: url,
urlId: s.urlId,
}
} }
// UrlId returns a style with the UrlId set. If the provided UrlId is not empty, // UrlId returns a style with the UrlId set. If the provided UrlId is not empty,
@ -166,11 +186,7 @@ func (s Style) Url(url string) Style {
// terminal supports it, any text with the same UrlId will be grouped as if it // terminal supports it, any text with the same UrlId will be grouped as if it
// were one Url, even if it spans multiple lines. // were one Url, even if it spans multiple lines.
func (s Style) UrlId(id string) Style { func (s Style) UrlId(id string) Style {
return Style{ s2 := s
fg: s.fg, s2.urlId = "id=" + id
bg: s.bg, return s2
attrs: s.attrs,
url: s.url,
urlId: "id=" + id,
}
} }

View File

@ -67,5 +67,10 @@ func init() {
KeyBacktab: "\x1b[Z", KeyBacktab: "\x1b[Z",
Modifiers: 1, Modifiers: 1,
AutoMargin: true, AutoMargin: true,
DoubleUnderline: "\x1b[4:2m",
CurlyUnderline: "\x1b[4:3m",
DottedUnderline: "\x1b[4:4m",
DashedUnderline: "\x1b[4:5m",
XTermLike: true,
}) })
} }

View File

@ -23,7 +23,7 @@ package base
import ( import (
// The following imports just register themselves -- // The following imports just register themselves --
// thse 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/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"

View File

@ -52,5 +52,6 @@ import (
_ "github.com/gdamore/tcell/v2/terminfo/w/wy99_ansi" _ "github.com/gdamore/tcell/v2/terminfo/w/wy99_ansi"
_ "github.com/gdamore/tcell/v2/terminfo/x/xfce" _ "github.com/gdamore/tcell/v2/terminfo/x/xfce"
_ "github.com/gdamore/tcell/v2/terminfo/x/xterm" _ "github.com/gdamore/tcell/v2/terminfo/x/xterm"
_ "github.com/gdamore/tcell/v2/terminfo/x/xterm_ghostty"
_ "github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty" _ "github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty"
) )

View File

@ -67,6 +67,7 @@ func init() {
KeyBacktab: "\x1b[Z", KeyBacktab: "\x1b[Z",
Modifiers: 1, Modifiers: 1,
AutoMargin: true, AutoMargin: true,
XTermLike: true,
}) })
// GNOME Terminal with xterm 256-colors // GNOME Terminal with xterm 256-colors
@ -130,5 +131,6 @@ func init() {
KeyBacktab: "\x1b[Z", KeyBacktab: "\x1b[Z",
Modifiers: 1, Modifiers: 1,
AutoMargin: true, AutoMargin: true,
XTermLike: true,
}) })
} }

View File

@ -68,6 +68,7 @@ func init() {
KeyBacktab: "\x1b[Z", KeyBacktab: "\x1b[Z",
Modifiers: 1, Modifiers: 1,
AutoMargin: true, AutoMargin: true,
XTermLike: true,
}) })
// KDE console window with xterm 256-colors // KDE console window with xterm 256-colors
@ -132,5 +133,6 @@ func init() {
KeyBacktab: "\x1b[Z", KeyBacktab: "\x1b[Z",
Modifiers: 1, Modifiers: 1,
AutoMargin: true, AutoMargin: true,
XTermLike: true,
}) })
} }

View File

@ -66,5 +66,6 @@ func init() {
KeyF19: "\x1b[33~", KeyF19: "\x1b[33~",
KeyF20: "\x1b[34~", KeyF20: "\x1b[34~",
AutoMargin: true, AutoMargin: true,
XTermLike: true,
}) })
} }

View File

@ -14,7 +14,7 @@ pcansi
rxvt,rxvt-256color,rxvt-88color,rxvt-unicode,rxvt-unicode-256color rxvt,rxvt-256color,rxvt-88color,rxvt-unicode,rxvt-unicode-256color
screen,screen-256color screen,screen-256color
st,st-256color|simpleterm st,st-256color|simpleterm
tmux tmux,tmux-256color
vt52 vt52
vt100 vt100
vt102 vt102
@ -27,4 +27,5 @@ wy60
wy99-ansi,wy99a-ansi wy99-ansi,wy99a-ansi
xfce xfce
xterm,xterm-88color,xterm-256color xterm,xterm-88color,xterm-256color
xterm-ghostty
xterm-kitty xterm-kitty

View File

@ -110,6 +110,7 @@ func init() {
KeyCtrlHome: "\x1b[7^", KeyCtrlHome: "\x1b[7^",
KeyCtrlEnd: "\x1b[8^", KeyCtrlEnd: "\x1b[8^",
AutoMargin: true, AutoMargin: true,
XTermLike: true,
}) })
// rxvt 2.7.9 with xterm 256-colors // rxvt 2.7.9 with xterm 256-colors
@ -215,6 +216,7 @@ func init() {
KeyCtrlHome: "\x1b[7^", KeyCtrlHome: "\x1b[7^",
KeyCtrlEnd: "\x1b[8^", KeyCtrlEnd: "\x1b[8^",
AutoMargin: true, AutoMargin: true,
XTermLike: true,
}) })
// rxvt 2.7.9 with xterm 88-colors // rxvt 2.7.9 with xterm 88-colors
@ -320,6 +322,7 @@ func init() {
KeyCtrlHome: "\x1b[7^", KeyCtrlHome: "\x1b[7^",
KeyCtrlEnd: "\x1b[8^", KeyCtrlEnd: "\x1b[8^",
AutoMargin: true, AutoMargin: true,
XTermLike: true,
}) })
// rxvt-unicode terminal (X Window System) // rxvt-unicode terminal (X Window System)

View File

@ -67,6 +67,7 @@ func init() {
KeyClear: "\x1b[3;5~", KeyClear: "\x1b[3;5~",
Modifiers: 1, Modifiers: 1,
AutoMargin: true, AutoMargin: true,
XTermLike: true,
}) })
// simpleterm with 256 colors // simpleterm with 256 colors
@ -130,5 +131,6 @@ func init() {
KeyClear: "\x1b[3;5~", KeyClear: "\x1b[3;5~",
Modifiers: 1, Modifiers: 1,
AutoMargin: true, AutoMargin: true,
XTermLike: true,
}) })
} }

View File

@ -67,5 +67,76 @@ func init() {
KeyBacktab: "\x1b[Z", KeyBacktab: "\x1b[Z",
Modifiers: 1, Modifiers: 1,
AutoMargin: true, AutoMargin: true,
DoubleUnderline: "\x1b[4:2m",
CurlyUnderline: "\x1b[4:3m",
DottedUnderline: "\x1b[4:4m",
DashedUnderline: "\x1b[4:5m",
})
// tmux with 256 colors
terminfo.AddTerminfo(&terminfo.Terminfo{
Name: "tmux-256color",
Columns: 80,
Lines: 24,
Colors: 256,
Bell: "\a",
Clear: "\x1b[H\x1b[J",
EnterCA: "\x1b[?1049h",
ExitCA: "\x1b[?1049l",
ShowCursor: "\x1b[34h\x1b[?25h",
HideCursor: "\x1b[?25l",
AttrOff: "\x1b[m\x0f",
Underline: "\x1b[4m",
Bold: "\x1b[1m",
Dim: "\x1b[2m",
Italic: "\x1b[3m",
Blink: "\x1b[5m",
Reverse: "\x1b[7m",
EnterKeypad: "\x1b[?1h\x1b=",
ExitKeypad: "\x1b[?1l\x1b>",
SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
SetFgBg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;;%?%p2%{8}%<%t4%p2%d%e%p2%{16}%<%t10%p2%{8}%-%d%e48;5;%p2%d%;m",
ResetFgBg: "\x1b[39;49m",
PadChar: "\x00",
AltChars: "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
EnterAcs: "\x0e",
ExitAcs: "\x0f",
EnableAcs: "\x1b(B\x1b)0",
StrikeThrough: "\x1b[9m",
Mouse: "\x1b[M",
SetCursor: "\x1b[%i%p1%d;%p2%dH",
CursorBack1: "\b",
CursorUp1: "\x1bM",
KeyUp: "\x1bOA",
KeyDown: "\x1bOB",
KeyRight: "\x1bOC",
KeyLeft: "\x1bOD",
KeyInsert: "\x1b[2~",
KeyDelete: "\x1b[3~",
KeyBackspace: "\x7f",
KeyHome: "\x1b[1~",
KeyEnd: "\x1b[4~",
KeyPgUp: "\x1b[5~",
KeyPgDn: "\x1b[6~",
KeyF1: "\x1bOP",
KeyF2: "\x1bOQ",
KeyF3: "\x1bOR",
KeyF4: "\x1bOS",
KeyF5: "\x1b[15~",
KeyF6: "\x1b[17~",
KeyF7: "\x1b[18~",
KeyF8: "\x1b[19~",
KeyF9: "\x1b[20~",
KeyF10: "\x1b[21~",
KeyF11: "\x1b[23~",
KeyF12: "\x1b[24~",
KeyBacktab: "\x1b[Z",
Modifiers: 1,
AutoMargin: true,
DoubleUnderline: "\x1b[4:2m",
CurlyUnderline: "\x1b[4:3m",
DottedUnderline: "\x1b[4:4m",
DashedUnderline: "\x1b[4:5m",
}) })
} }

View File

@ -227,13 +227,25 @@ type Terminfo struct {
CursorSteadyUnderline string CursorSteadyUnderline string
CursorBlinkingBar string CursorBlinkingBar string
CursorSteadyBar string CursorSteadyBar string
CursorColor string // nothing uses it yet
CursorColorRGB string // Cs (but not really because Cs uses X11 color string)
CursorColorReset string // Cr
EnterUrl string EnterUrl string
ExitUrl string ExitUrl string
SetWindowSize string SetWindowSize string
SetWindowTitle string // no terminfo extension
EnableFocusReporting string EnableFocusReporting string
DisableFocusReporting string DisableFocusReporting string
DisableAutoMargin string // smam DisableAutoMargin string // smam
EnableAutoMargin string // rmam EnableAutoMargin string // rmam
DoubleUnderline string // Smulx with param 2
CurlyUnderline string // Smulx with param 3
DottedUnderline string // Smulx with param 4
DashedUnderline string // Smulx with param 5
UnderlineColor string // Setuc1
UnderlineColorRGB string // Setulc
UnderlineColorReset string // ol
XTermLike bool // (XT) has XTerm extensions
} }
const ( const (

View File

@ -65,5 +65,6 @@ func init() {
KeyBacktab: "\x1b[Z", KeyBacktab: "\x1b[Z",
Modifiers: 1, Modifiers: 1,
AutoMargin: true, AutoMargin: true,
XTermLike: true,
}) })
} }

View File

@ -68,6 +68,7 @@ func init() {
KeyBacktab: "\x1b[Z", KeyBacktab: "\x1b[Z",
Modifiers: 1, Modifiers: 1,
AutoMargin: true, AutoMargin: true,
XTermLike: true,
}) })
// xterm with 88 colors // xterm with 88 colors
@ -131,6 +132,7 @@ func init() {
KeyBacktab: "\x1b[Z", KeyBacktab: "\x1b[Z",
Modifiers: 1, Modifiers: 1,
AutoMargin: true, AutoMargin: true,
XTermLike: true,
}) })
// xterm with 256 colors // xterm with 256 colors
@ -194,5 +196,6 @@ func init() {
KeyBacktab: "\x1b[Z", KeyBacktab: "\x1b[Z",
Modifiers: 1, Modifiers: 1,
AutoMargin: true, AutoMargin: true,
XTermLike: true,
}) })
} }

View File

@ -0,0 +1,79 @@
// Generated automatically. DO NOT HAND-EDIT.
package xterm_ghostty
import "github.com/gdamore/tcell/v2/terminfo"
func init() {
// Ghostty
terminfo.AddTerminfo(&terminfo.Terminfo{
Name: "xterm-ghostty",
Aliases: []string{"ghostty"},
Columns: 80,
Lines: 24,
Colors: 256,
Bell: "\a",
Clear: "\x1b[H\x1b[2J",
EnterCA: "\x1b[?1049h",
ExitCA: "\x1b[?1049l",
ShowCursor: "\x1b[?12l\x1b[?25h",
HideCursor: "\x1b[?25l",
AttrOff: "\x1b(B\x1b[m",
Underline: "\x1b[4m",
Bold: "\x1b[1m",
Dim: "\x1b[2m",
Italic: "\x1b[3m",
Blink: "\x1b[5m",
Reverse: "\x1b[7m",
EnterKeypad: "\x1b[?1h\x1b=",
ExitKeypad: "\x1b[?1l\x1b>",
SetFg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
SetBg: "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
SetFgBg: "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;;%?%p2%{8}%<%t4%p2%d%e%p2%{16}%<%t10%p2%{8}%-%d%e48;5;%p2%d%;m",
ResetFgBg: "\x1b[39;49m",
AltChars: "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
EnterAcs: "\x1b(0",
ExitAcs: "\x1b(B",
EnableAutoMargin: "\x1b[?7h",
DisableAutoMargin: "\x1b[?7l",
StrikeThrough: "\x1b[9m",
Mouse: "\x1b[<",
SetCursor: "\x1b[%i%p1%d;%p2%dH",
CursorBack1: "\b",
CursorUp1: "\x1b[A",
KeyUp: "\x1bOA",
KeyDown: "\x1bOB",
KeyRight: "\x1bOC",
KeyLeft: "\x1bOD",
KeyInsert: "\x1b[2~",
KeyDelete: "\x1b[3~",
KeyBackspace: "\x7f",
KeyHome: "\x1bOH",
KeyEnd: "\x1bOF",
KeyPgUp: "\x1b[5~",
KeyPgDn: "\x1b[6~",
KeyF1: "\x1bOP",
KeyF2: "\x1bOQ",
KeyF3: "\x1bOR",
KeyF4: "\x1bOS",
KeyF5: "\x1b[15~",
KeyF6: "\x1b[17~",
KeyF7: "\x1b[18~",
KeyF8: "\x1b[19~",
KeyF9: "\x1b[20~",
KeyF10: "\x1b[21~",
KeyF11: "\x1b[23~",
KeyF12: "\x1b[24~",
KeyBacktab: "\x1b[Z",
Modifiers: 1,
TrueColor: true,
AutoMargin: true,
InsertChar: "\x1b[@",
DoubleUnderline: "\x1b[4:2m",
CurlyUnderline: "\x1b[4:3m",
DottedUnderline: "\x1b[4:4m",
DashedUnderline: "\x1b[4:5m",
XTermLike: true,
})
}

View File

@ -67,5 +67,9 @@ func init() {
Modifiers: 1, Modifiers: 1,
TrueColor: true, TrueColor: true,
AutoMargin: true, AutoMargin: true,
DoubleUnderline: "\x1b[4:2m",
CurlyUnderline: "\x1b[4:3m",
DottedUnderline: "\x1b[4:4m",
DashedUnderline: "\x1b[4:5m",
}) })
} }

View File

@ -27,9 +27,14 @@ import (
// will be automatically included anyway. // will be automatically included anyway.
"github.com/gdamore/tcell/v2/terminfo" "github.com/gdamore/tcell/v2/terminfo"
"github.com/gdamore/tcell/v2/terminfo/dynamic" "github.com/gdamore/tcell/v2/terminfo/dynamic"
"fmt"
) )
func loadDynamicTerminfo(term string) (*terminfo.Terminfo, error) { func loadDynamicTerminfo(term string) (*terminfo.Terminfo, error) {
if term == "" {
return nil, fmt.Errorf("%w: term not set", ErrTermNotFound)
}
ti, _, e := dynamic.LoadTerminfo(term) ti, _, e := dynamic.LoadTerminfo(term)
if e != nil { if e != nil {
return nil, e return nil, e

View File

@ -19,6 +19,7 @@ package tcell
import ( import (
"bytes" "bytes"
"encoding/base64"
"errors" "errors"
"io" "io"
"os" "os"
@ -32,9 +33,6 @@ import (
"golang.org/x/text/transform" "golang.org/x/text/transform"
"github.com/gdamore/tcell/v2/terminfo" "github.com/gdamore/tcell/v2/terminfo"
// import the stock terminals
_ "github.com/gdamore/tcell/v2/terminfo/base"
) )
// NewTerminfoScreen returns a Screen that uses the stock TTY interface // NewTerminfoScreen returns a Screen that uses the stock TTY interface
@ -154,8 +152,18 @@ type tScreen struct {
setWinSize string setWinSize string
enableFocus string enableFocus string
disableFocus string disableFocus string
doubleUnder string
curlyUnder string
dottedUnder string
dashedUnder string
underColor string
underRGB string
underFg string
cursorStyles map[CursorStyle]string cursorStyles map[CursorStyle]string
cursorStyle CursorStyle cursorStyle CursorStyle
cursorColor Color
cursorRGB string
cursorFg string
saved *term.State saved *term.State
stopQ chan struct{} stopQ chan struct{}
eventQ chan Event eventQ chan Event
@ -164,6 +172,11 @@ type tScreen struct {
mouseFlags MouseFlags mouseFlags MouseFlags
pasteEnabled bool pasteEnabled bool
focusEnabled bool focusEnabled bool
setTitle string
saveTitle string
restoreTitle string
title string
setClipboard string
sync.Mutex sync.Mutex
} }
@ -338,7 +351,7 @@ func (t *tScreen) prepareBracketedPaste() {
t.disablePaste = t.ti.DisablePaste t.disablePaste = t.ti.DisablePaste
t.prepareKey(keyPasteStart, t.ti.PasteStart) t.prepareKey(keyPasteStart, t.ti.PasteStart)
t.prepareKey(keyPasteEnd, t.ti.PasteEnd) t.prepareKey(keyPasteEnd, t.ti.PasteEnd)
} else if t.ti.Mouse != "" { } else if t.ti.Mouse != "" || t.ti.XTermLike {
t.enablePaste = "\x1b[?2004h" t.enablePaste = "\x1b[?2004h"
t.disablePaste = "\x1b[?2004l" t.disablePaste = "\x1b[?2004l"
t.prepareKey(keyPasteStart, "\x1b[200~") t.prepareKey(keyPasteStart, "\x1b[200~")
@ -346,6 +359,54 @@ func (t *tScreen) prepareBracketedPaste() {
} }
} }
func (t *tScreen) prepareUnderlines() {
if t.ti.DoubleUnderline != "" {
t.doubleUnder = t.ti.DoubleUnderline
} else if t.ti.XTermLike {
t.doubleUnder = "\x1b[4:2m"
}
if t.ti.CurlyUnderline != "" {
t.curlyUnder = t.ti.CurlyUnderline
} else if t.ti.XTermLike {
t.curlyUnder = "\x1b[4:3m"
}
if t.ti.DottedUnderline != "" {
t.dottedUnder = t.ti.DottedUnderline
} else if t.ti.XTermLike {
t.dottedUnder = "\x1b[4:4m"
}
if t.ti.DashedUnderline != "" {
t.dashedUnder = t.ti.DashedUnderline
} else if t.ti.XTermLike {
t.dashedUnder = "\x1b[4:5m"
}
// Underline colors. We're not going to rely upon terminfo for this
// Essentially all terminals that support the curly underlines are
// expected to also support coloring them too - which reflects actual
// practice since these were introduced at about the same time.
if t.ti.UnderlineColor != "" {
t.underColor = t.ti.UnderlineColor
} else if t.ti.CurlyUnderline != "" {
t.underColor = "\x1b[58:5:%p1%dm"
}
if t.ti.UnderlineColorRGB != "" {
// An interesting wart here is that in order to facilitate
// using just a single parameter, the Setulc parameter takes
// the 24-bit color as an integer rather than separate bytes.
// This matches the "new" style direct color approach that
// ncurses took, even though everyone else when another way.
t.underRGB = t.ti.UnderlineColorRGB
} else if t.ti.CurlyUnderline != "" {
t.underRGB = "\x1b[58:2::%p1%d:%p2%d:%p3%dm"
}
if t.ti.UnderlineColorReset != "" {
t.underFg = t.ti.UnderlineColorReset
} else if t.ti.CurlyUnderline != "" {
t.underFg = "\x1b[59m"
}
}
func (t *tScreen) prepareExtendedOSC() { func (t *tScreen) prepareExtendedOSC() {
// Linux is a special beast - because it has a mouse entry, but does // Linux is a special beast - because it has a mouse entry, but does
// not swallow these OSC commands properly. // not swallow these OSC commands properly.
@ -359,27 +420,43 @@ func (t *tScreen) prepareExtendedOSC() {
if t.ti.EnterUrl != "" { if t.ti.EnterUrl != "" {
t.enterUrl = t.ti.EnterUrl t.enterUrl = t.ti.EnterUrl
t.exitUrl = t.ti.ExitUrl t.exitUrl = t.ti.ExitUrl
} else if t.ti.Mouse != "" { } else if t.ti.Mouse != "" || t.ti.XTermLike {
t.enterUrl = "\x1b]8;%p2%s;%p1%s\x1b\\" t.enterUrl = "\x1b]8;%p2%s;%p1%s\x1b\\"
t.exitUrl = "\x1b]8;;\x1b\\" t.exitUrl = "\x1b]8;;\x1b\\"
} }
if t.ti.SetWindowSize != "" { if t.ti.SetWindowSize != "" {
t.setWinSize = t.ti.SetWindowSize t.setWinSize = t.ti.SetWindowSize
} else if t.ti.Mouse != "" { } else if t.ti.Mouse != "" || t.ti.XTermLike {
t.setWinSize = "\x1b[8;%p1%p2%d;%dt" t.setWinSize = "\x1b[8;%p1%p2%d;%dt"
} }
if t.ti.EnableFocusReporting != "" { if t.ti.EnableFocusReporting != "" {
t.enableFocus = t.ti.EnableFocusReporting t.enableFocus = t.ti.EnableFocusReporting
} else if t.ti.Mouse != "" { } else if t.ti.Mouse != "" || t.ti.XTermLike {
t.enableFocus = "\x1b[?1004h" t.enableFocus = "\x1b[?1004h"
} }
if t.ti.DisableFocusReporting != "" { if t.ti.DisableFocusReporting != "" {
t.disableFocus = t.ti.DisableFocusReporting t.disableFocus = t.ti.DisableFocusReporting
} else if t.ti.Mouse != "" { } else if t.ti.Mouse != "" || t.ti.XTermLike {
t.disableFocus = "\x1b[?1004l" t.disableFocus = "\x1b[?1004l"
} }
if t.ti.SetWindowTitle != "" {
t.setTitle = t.ti.SetWindowTitle
} else if t.ti.XTermLike {
t.saveTitle = "\x1b[22;2t"
t.restoreTitle = "\x1b[23;2t"
// this also tries to request that UTF-8 is allowed in the title
t.setTitle = "\x1b[>2t\x1b]2;%p1%s\x1b\\"
}
if t.setClipboard == "" && t.ti.XTermLike {
// this string takes a base64 string and sends it to the clipboard.
// it will also be able to retrieve the clipboard using "?" as the
// sent string, when we support that.
t.setClipboard = "\x1b]52;c;%p1%s\x1b\\"
}
} }
func (t *tScreen) prepareCursorStyles() { func (t *tScreen) prepareCursorStyles() {
@ -397,7 +474,7 @@ func (t *tScreen) prepareCursorStyles() {
CursorStyleBlinkingBar: t.ti.CursorBlinkingBar, CursorStyleBlinkingBar: t.ti.CursorBlinkingBar,
CursorStyleSteadyBar: t.ti.CursorSteadyBar, CursorStyleSteadyBar: t.ti.CursorSteadyBar,
} }
} else if t.ti.Mouse != "" { } else if t.ti.Mouse != "" || t.ti.XTermLike {
t.cursorStyles = map[CursorStyle]string{ t.cursorStyles = map[CursorStyle]string{
CursorStyleDefault: "\x1b[0 q", CursorStyleDefault: "\x1b[0 q",
CursorStyleBlinkingBlock: "\x1b[1 q", CursorStyleBlinkingBlock: "\x1b[1 q",
@ -408,6 +485,20 @@ func (t *tScreen) prepareCursorStyles() {
CursorStyleSteadyBar: "\x1b[6 q", CursorStyleSteadyBar: "\x1b[6 q",
} }
} }
if t.ti.CursorColorRGB != "" {
// if it was X11 style with just a single %p1%s, then convert
t.cursorRGB = t.ti.CursorColorRGB
}
if t.ti.CursorColorReset != "" {
t.cursorFg = t.ti.CursorColorReset
}
if t.cursorRGB == "" {
t.cursorRGB = "\x1b]12;%p1%s\007"
t.cursorFg = "\x1b]112\007"
}
// convert XTERM style color names to RGB color code. We have no way to do palette colors
t.cursorRGB = strings.Replace(t.cursorRGB, "%p1%s", "#%p1%02x%p2%02x%p3%02x", 1)
} }
func (t *tScreen) prepareKey(key Key, val string) { func (t *tScreen) prepareKey(key Key, val string) {
@ -416,6 +507,11 @@ func (t *tScreen) prepareKey(key Key, val string) {
func (t *tScreen) prepareKeys() { func (t *tScreen) prepareKeys() {
ti := t.ti ti := t.ti
if strings.HasPrefix(ti.Name, "xterm") {
// assume its some form of XTerm clone
t.ti.XTermLike = true
ti.XTermLike = true
}
t.prepareKey(KeyBackspace, ti.KeyBackspace) t.prepareKey(KeyBackspace, ti.KeyBackspace)
t.prepareKey(KeyF1, ti.KeyF1) t.prepareKey(KeyF1, ti.KeyF1)
t.prepareKey(KeyF2, ti.KeyF2) t.prepareKey(KeyF2, ti.KeyF2)
@ -550,6 +646,7 @@ func (t *tScreen) prepareKeys() {
t.prepareXtermModifiers() t.prepareXtermModifiers()
t.prepareBracketedPaste() t.prepareBracketedPaste()
t.prepareCursorStyles() t.prepareCursorStyles()
t.prepareUnderlines()
t.prepareExtendedOSC() t.prepareExtendedOSC()
outer: outer:
@ -742,7 +839,7 @@ func (t *tScreen) drawCell(x, y int) int {
style = t.style style = t.style
} }
if style != t.curstyle { if style != t.curstyle {
fg, bg, attrs := style.Decompose() fg, bg, attrs := style.fg, style.bg, style.attrs
t.TPuts(ti.AttrOff) t.TPuts(ti.AttrOff)
@ -750,8 +847,39 @@ func (t *tScreen) drawCell(x, y int) int {
if attrs&AttrBold != 0 { if attrs&AttrBold != 0 {
t.TPuts(ti.Bold) t.TPuts(ti.Bold)
} }
if attrs&AttrUnderline != 0 { if us, uc := style.ulStyle, style.ulColor; us != UnderlineStyleNone {
t.TPuts(ti.Underline) if t.underColor != "" || t.underRGB != "" {
if uc == ColorReset {
t.TPuts(t.underFg)
} else if uc.IsRGB() {
if t.underRGB != "" {
r, g, b := uc.RGB()
t.TPuts(ti.TParm(t.underRGB, int(r), int(g), int(b)))
} else {
if v, ok := t.colors[uc]; ok {
uc = v
} else {
v = FindColor(uc, t.palette)
t.colors[uc] = v
uc = v
}
t.TPuts(ti.TParm(t.underColor, int(uc&0xff)))
}
} else if uc.Valid() {
t.TPuts(ti.TParm(t.underColor, int(uc&0xff)))
}
}
t.TPuts(ti.Underline) // to ensure everyone gets at least a basic underline
switch us {
case UnderlineStyleDouble:
t.TPuts(t.doubleUnder)
case UnderlineStyleCurly:
t.TPuts(t.curlyUnder)
case UnderlineStyleDotted:
t.TPuts(t.dottedUnder)
case UnderlineStyleDashed:
t.TPuts(t.dashedUnder)
}
} }
if attrs&AttrReverse != 0 { if attrs&AttrReverse != 0 {
t.TPuts(ti.Reverse) t.TPuts(ti.Reverse)
@ -827,9 +955,10 @@ func (t *tScreen) ShowCursor(x, y int) {
t.Unlock() t.Unlock()
} }
func (t *tScreen) SetCursorStyle(cs CursorStyle) { func (t *tScreen) SetCursor(cs CursorStyle, cc Color) {
t.Lock() t.Lock()
t.cursorStyle = cs t.cursorStyle = cs
t.cursorColor = cc
t.Unlock() t.Unlock()
} }
@ -852,6 +981,14 @@ func (t *tScreen) showCursor() {
t.TPuts(esc) t.TPuts(esc)
} }
} }
if t.cursorRGB != "" {
if t.cursorColor == ColorReset {
t.TPuts(t.cursorFg)
} else if t.cursorColor.Valid() {
r, g, b := t.cursorColor.RGB()
t.TPuts(t.ti.TParm(t.cursorRGB, int(r), int(g), int(b)))
}
}
t.cx = x t.cx = x
t.cy = y t.cy = y
} }
@ -890,8 +1027,7 @@ func (t *tScreen) Show() {
func (t *tScreen) clearScreen() { func (t *tScreen) clearScreen() {
t.TPuts(t.ti.AttrOff) t.TPuts(t.ti.AttrOff)
t.TPuts(t.exitUrl) t.TPuts(t.exitUrl)
fg, bg, _ := t.style.Decompose() _ = t.sendFgBg(t.style.fg, t.style.bg, AttrNone)
_ = t.sendFgBg(fg, bg, AttrNone)
t.TPuts(t.ti.Clear) t.TPuts(t.ti.Clear)
t.clear = false t.clear = false
} }
@ -1376,6 +1512,61 @@ func (t *tScreen) parseFocus(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
return true, false return true, false
} }
func (t *tScreen) parseClipboard(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
b := buf.Bytes()
state := 0
prefix := []byte("\x1b]52;c;")
if len(prefix) >= len(b) {
if bytes.HasPrefix(prefix, b) {
// inconclusive so far
return true, false
}
// definitely not a match
return false, false
}
b = b[len(prefix):]
for _, c := range b {
// valid base64 digits
if (state == 0) {
if (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '+') || (c == '/') || (c == '=') {
continue
}
if (c == '\x1b') {
state = 1
continue
}
if (c == '\a') {
// matched with BEL instead of ST
b = b[:len(b)-1] // drop the trailing BEL
decoded := make([]byte, base64.StdEncoding.DecodedLen(len(b)))
if num, err := base64.StdEncoding.Decode(decoded, b); err == nil {
*evs = append(*evs, NewEventClipboard(decoded[:num]))
}
_, _ = buf.ReadBytes('\a')
return true, true
}
return false, false
}
if (state == 1) {
if (c == '\\') {
b = b[:len(b)-2] // drop the trailing ST (\x1b\\)
// now decode the data
decoded := make([]byte, base64.StdEncoding.DecodedLen(len(b)))
if num, err := base64.StdEncoding.Decode(decoded, b); err == nil {
*evs = append(*evs, NewEventClipboard(decoded[:num]))
}
_, _ = buf.ReadBytes('\\')
return true, true
}
return false, false
}
}
// not enough data yet (not terminated)
return true, false
}
// parseXtermMouse is like parseSgrMouse, but it parses a legacy // parseXtermMouse is like parseSgrMouse, but it parses a legacy
// X11 mouse record. // X11 mouse record.
func (t *tScreen) parseXtermMouse(buf *bytes.Buffer, evs *[]Event) (bool, bool) { func (t *tScreen) parseXtermMouse(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
@ -1579,6 +1770,14 @@ func (t *tScreen) collectEventsFromInput(buf *bytes.Buffer, expire bool) []Event
} }
} }
if t.setClipboard != "" {
if part, comp := t.parseClipboard(buf, &res); comp {
continue
} else if part {
partials++
}
}
if partials == 0 || expire { if partials == 0 || expire {
if b[0] == '\x1b' { if b[0] == '\x1b' {
if len(b) == 1 { if len(b) == 1 {
@ -1829,12 +2028,18 @@ func (t *tScreen) engage() error {
// (In theory there could be terminals that don't support X,Y cursor // (In theory there could be terminals that don't support X,Y cursor
// positions without a setup command, but we don't support them.) // positions without a setup command, but we don't support them.)
t.TPuts(ti.EnterCA) t.TPuts(ti.EnterCA)
if t.saveTitle != "" {
t.TPuts(t.saveTitle)
}
} }
t.TPuts(ti.EnterKeypad) t.TPuts(ti.EnterKeypad)
t.TPuts(ti.HideCursor) t.TPuts(ti.HideCursor)
t.TPuts(ti.EnableAcs) t.TPuts(ti.EnableAcs)
t.TPuts(ti.DisableAutoMargin) t.TPuts(ti.DisableAutoMargin)
t.TPuts(ti.Clear) t.TPuts(ti.Clear)
if t.title != "" && t.setTitle != "" {
t.TPuts(t.ti.TParm(t.setTitle, t.title))
}
t.wg.Add(2) t.wg.Add(2)
go t.inputLoop(stopQ) go t.inputLoop(stopQ)
@ -1870,11 +2075,17 @@ func (t *tScreen) disengage() {
if t.cursorStyles != nil && t.cursorStyle != CursorStyleDefault { if t.cursorStyles != nil && t.cursorStyle != CursorStyleDefault {
t.TPuts(t.cursorStyles[CursorStyleDefault]) t.TPuts(t.cursorStyles[CursorStyleDefault])
} }
if t.cursorFg != "" && t.cursorColor.Valid() {
t.TPuts(t.cursorFg)
}
t.TPuts(ti.ResetFgBg) t.TPuts(ti.ResetFgBg)
t.TPuts(ti.AttrOff) t.TPuts(ti.AttrOff)
t.TPuts(ti.ExitKeypad) t.TPuts(ti.ExitKeypad)
t.TPuts(ti.EnableAutoMargin) t.TPuts(ti.EnableAutoMargin)
if os.Getenv("TCELL_ALTSCREEN") != "disable" { if os.Getenv("TCELL_ALTSCREEN") != "disable" {
if t.restoreTitle != "" {
t.TPuts(t.restoreTitle)
}
t.TPuts(ti.Clear) // only needed if ExitCA is empty t.TPuts(ti.Clear) // only needed if ExitCA is empty
t.TPuts(ti.ExitCA) t.TPuts(ti.ExitCA)
} }
@ -1909,3 +2120,30 @@ func (t *tScreen) EventQ() chan Event {
func (t *tScreen) GetCells() *CellBuffer { func (t *tScreen) GetCells() *CellBuffer {
return &t.cells return &t.cells
} }
func (t *tScreen) SetTitle(title string) {
t.Lock()
t.title = title
if t.setTitle != "" && t.running {
t.TPuts(t.ti.TParm(t.setTitle, title))
}
t.Unlock()
}
func (t *tScreen) SetClipboard(data []byte) {
// Post binary data to the system clipboard. It might be UTF-8, it might not be.
t.Lock()
if t.setClipboard != "" {
encoded := base64.StdEncoding.EncodeToString(data)
t.TPuts(t.ti.TParm(t.setClipboard, encoded))
}
t.Unlock()
}
func (t *tScreen) GetClipboard() {
t.Lock()
if t.setClipboard != "" {
t.TPuts(t.ti.TParm(t.setClipboard, "?"))
}
t.Unlock()
}

View File

@ -1,4 +1,4 @@
// Copyright 2021 The TCell Authors // Copyright 2024 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.
@ -17,6 +17,11 @@
package tcell package tcell
import (
// import the stock terminals
_ "github.com/gdamore/tcell/v2/terminfo/base"
)
// initialize is used at application startup, and sets up the initial values // initialize is used at application startup, and sets up the initial values
// including file descriptors used for terminals and saving the initial state // including file descriptors used for terminals and saving the initial state
// so that it can be restored when the application terminates. // so that it can be restored when the application terminates.

View File

@ -1,4 +1,4 @@
// Copyright 2023 The TCell Authors // Copyright 2024 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.
@ -19,11 +19,13 @@ package tcell
import ( import (
"errors" "errors"
"github.com/gdamore/tcell/v2/terminfo" "fmt"
"strings" "strings"
"sync" "sync"
"syscall/js" "syscall/js"
"unicode/utf8" "unicode/utf8"
"github.com/gdamore/tcell/v2/terminfo"
) )
func NewTerminfoScreen() (Screen, error) { func NewTerminfoScreen() (Screen, error) {
@ -66,6 +68,9 @@ func (t *wScreen) Init() error {
t.Unlock() t.Unlock()
js.Global().Set("onKeyEvent", js.FuncOf(t.onKeyEvent)) js.Global().Set("onKeyEvent", js.FuncOf(t.onKeyEvent))
js.Global().Set("onMouseClick", js.FuncOf(t.unset))
js.Global().Set("onMouseMove", js.FuncOf(t.unset))
js.Global().Set("onFocus", js.FuncOf(t.unset))
return nil return nil
} }
@ -133,14 +138,23 @@ func (t *wScreen) drawCell(x, y int) int {
if bg == -1 { if bg == -1 {
bg = 0x000000 bg = 0x000000
} }
us, uc := style.ulStyle, paletteColor(style.ulColor)
if uc == -1 {
uc = 0x000000
}
var combcarr []interface{} = make([]interface{}, len(combc)) s := ""
for i, c := range combc { if len(combc) > 0 {
combcarr[i] = c b := make([]rune, 0, 1 + len(combc))
b = append(b, mainc)
b = append(b, combc...)
s = string(b)
} else {
s = string(mainc)
} }
t.cells.SetDirty(x, y, false) t.cells.SetDirty(x, y, false)
js.Global().Call("drawCell", x, y, mainc, combcarr, fg, bg, int(style.attrs)) js.Global().Call("drawCell", x, y, s, fg, bg, int(style.attrs), int(us), int(uc))
return width return width
} }
@ -151,9 +165,12 @@ func (t *wScreen) ShowCursor(x, y int) {
t.Unlock() t.Unlock()
} }
func (t *wScreen) SetCursorStyle(cs CursorStyle) { func (t *wScreen) SetCursor(cs CursorStyle, cc Color) {
if !cc.Valid() {
cc = ColorLightGray
}
t.Lock() t.Lock()
js.Global().Call("setCursorStyle", curStyleClasses[cs]) js.Global().Call("setCursorStyle", curStyleClasses[cs], fmt.Sprintf("#%06x", cc.Hex()))
t.Unlock() t.Unlock()
} }
@ -511,6 +528,10 @@ func (t *wScreen) StopQ() <-chan struct{} {
return t.quit return t.quit
} }
func (t *wScreen) SetTitle(title string) {
js.Global().Call("setTitle", title)
}
// WebKeyNames maps string names reported from HTML // WebKeyNames maps string names reported from HTML
// (KeyboardEvent.key) to tcell accepted keys. // (KeyboardEvent.key) to tcell accepted keys.
var WebKeyNames = map[string]Key{ var WebKeyNames = map[string]Key{

7
vendor/modules.txt vendored
View File

@ -37,7 +37,7 @@ github.com/fatih/color
# github.com/gdamore/encoding v1.0.1 # github.com/gdamore/encoding v1.0.1
## explicit; go 1.9 ## explicit; go 1.9
github.com/gdamore/encoding github.com/gdamore/encoding
# github.com/gdamore/tcell/v2 v2.7.4 # github.com/gdamore/tcell/v2 v2.8.0
## explicit; go 1.12 ## explicit; go 1.12
github.com/gdamore/tcell/v2 github.com/gdamore/tcell/v2
github.com/gdamore/tcell/v2/terminfo github.com/gdamore/tcell/v2/terminfo
@ -75,6 +75,7 @@ github.com/gdamore/tcell/v2/terminfo/w/wy60
github.com/gdamore/tcell/v2/terminfo/w/wy99_ansi github.com/gdamore/tcell/v2/terminfo/w/wy99_ansi
github.com/gdamore/tcell/v2/terminfo/x/xfce github.com/gdamore/tcell/v2/terminfo/x/xfce
github.com/gdamore/tcell/v2/terminfo/x/xterm github.com/gdamore/tcell/v2/terminfo/x/xterm
github.com/gdamore/tcell/v2/terminfo/x/xterm_ghostty
github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty
# github.com/go-errors/errors v1.5.1 # github.com/go-errors/errors v1.5.1
## explicit; go 1.14 ## explicit; go 1.14
@ -105,8 +106,6 @@ github.com/gobwas/glob/syntax/ast
github.com/gobwas/glob/syntax/lexer github.com/gobwas/glob/syntax/lexer
github.com/gobwas/glob/util/runes github.com/gobwas/glob/util/runes
github.com/gobwas/glob/util/strings github.com/gobwas/glob/util/strings
# github.com/google/go-cmp v0.5.6
## explicit; go 1.8
# github.com/gookit/color v1.4.2 # github.com/gookit/color v1.4.2
## explicit; go 1.12 ## explicit; go 1.12
github.com/gookit/color github.com/gookit/color
@ -172,7 +171,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/filesystem
github.com/jesseduffield/go-git/v5/utils/merkletrie/index github.com/jesseduffield/go-git/v5/utils/merkletrie/index
github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame
github.com/jesseduffield/go-git/v5/utils/merkletrie/noder github.com/jesseduffield/go-git/v5/utils/merkletrie/noder
# github.com/jesseduffield/gocui v0.3.1-0.20250107151125-716b1eb82fb4 # github.com/jesseduffield/gocui v0.3.1-0.20250111205211-82d518436b5a
## explicit; go 1.12 ## explicit; go 1.12
github.com/jesseduffield/gocui github.com/jesseduffield/gocui
# github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a # github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a