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/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
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/gookit/color v1.4.2
github.com/iancoleman/orderedmap v0.3.0
@ -16,7 +16,7 @@ require (
github.com/integrii/flaggy v1.4.0
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
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/lazycore v0.0.0-20221012050358-03d2e40243c5
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-logfmt/logfmt v0.5.0 // 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/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // 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/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/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/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU=
github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
github.com/gdamore/tcell/v2 v2.8.0 h1:IDclow1j6kKpU/gOhjmc+7Pj5Dxnukb74pfKN4Cxrfg=
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/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
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.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.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
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/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=
@ -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/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/gocui v0.3.1-0.20250107151125-716b1eb82fb4 h1:hSAimLVb4b5ktU3uJRtBsZW0P2dtXECReTcsHYfOy58=
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 h1:GLFWB8rESraTt2eIe2yssy4d4VEkCnmKbPeeZ5vCT2s=
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/go.mod h1:FSWDLKT0NQpntbDd1H3lbz51fhCVlMzy/J0S6nM727Q=
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.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
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/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
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-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.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/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
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.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.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-20180826012351-8a410e7b638d/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-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.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/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
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-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.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/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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-20220722155257-8c9f86f7a55f/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.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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/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-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.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.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/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
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.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.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.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/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
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.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.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-20191011141410-1b5146add898/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
const wasmFilePath = "yourfile.wasm"
```
to the file you outputed to when building.
to the file you outputted to when building.
## 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.
### 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
<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
- [tview](https://github.com/rivo/tview/) - rich interactive widgets
- [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!
- [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))
@ -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
- [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
@ -143,7 +145,7 @@ Most _termbox-go_ programs will probably work without further modification.
Internally _Tcell_ uses UTF-8, just like Go.
However, _Tcell_ understands how to
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
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.

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");
// you may not use file except in compliance with the License.
@ -19,15 +19,16 @@ package tcell
type AttrMask int
// 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 (
AttrBold AttrMask = 1 << iota
AttrBlink
AttrReverse
AttrUnderline
AttrUnderline // Deprecated: Use UnderlineStyle
AttrDim
AttrItalic
AttrStrikeThrough
AttrInvalid // Mark the style or attributes invalid
AttrNone AttrMask = 0 // Just normal text.
AttrInvalid AttrMask = 1 << 31 // Mark the style or attributes invalid
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
// both cells as dirty together. We only need to do this
// 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++ {
cb.SetDirty(x+i, y, true)
}
@ -246,11 +246,4 @@ func init() {
if os.Getenv("RUNEWIDTH_EASTASIAN") == "" {
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
Color254
Color255
ColorAliceBlue
ColorAntiqueWhite
ColorAquaMarine
ColorAzure
ColorBeige
ColorBisque
ColorBlanchedAlmond
ColorBlueViolet
ColorBrown
ColorBurlyWood
ColorCadetBlue
ColorChartreuse
ColorChocolate
ColorCoral
ColorCornflowerBlue
ColorCornsilk
ColorCrimson
ColorDarkBlue
ColorDarkCyan
ColorDarkGoldenrod
ColorDarkGray
ColorDarkGreen
ColorDarkKhaki
ColorDarkMagenta
ColorDarkOliveGreen
ColorDarkOrange
ColorDarkOrchid
ColorDarkRed
ColorDarkSalmon
ColorDarkSeaGreen
ColorDarkSlateBlue
ColorDarkSlateGray
ColorDarkTurquoise
ColorDarkViolet
ColorDeepPink
ColorDeepSkyBlue
ColorDimGray
ColorDodgerBlue
ColorFireBrick
ColorFloralWhite
ColorForestGreen
ColorGainsboro
ColorGhostWhite
ColorGold
ColorGoldenrod
ColorGreenYellow
ColorHoneydew
ColorHotPink
ColorIndianRed
ColorIndigo
ColorIvory
ColorKhaki
ColorLavender
ColorLavenderBlush
ColorLawnGreen
ColorLemonChiffon
ColorLightBlue
ColorLightCoral
ColorLightCyan
ColorLightGoldenrodYellow
ColorLightGray
ColorLightGreen
ColorLightPink
ColorLightSalmon
ColorLightSeaGreen
ColorLightSkyBlue
ColorLightSlateGray
ColorLightSteelBlue
ColorLightYellow
ColorLimeGreen
ColorLinen
ColorMediumAquamarine
ColorMediumBlue
ColorMediumOrchid
ColorMediumPurple
ColorMediumSeaGreen
ColorMediumSlateBlue
ColorMediumSpringGreen
ColorMediumTurquoise
ColorMediumVioletRed
ColorMidnightBlue
ColorMintCream
ColorMistyRose
ColorMoccasin
ColorNavajoWhite
ColorOldLace
ColorOliveDrab
ColorOrange
ColorOrangeRed
ColorOrchid
ColorPaleGoldenrod
ColorPaleGreen
ColorPaleTurquoise
ColorPaleVioletRed
ColorPapayaWhip
ColorPeachPuff
ColorPeru
ColorPink
ColorPlum
ColorPowderBlue
ColorRebeccaPurple
ColorRosyBrown
ColorRoyalBlue
ColorSaddleBrown
ColorSalmon
ColorSandyBrown
ColorSeaGreen
ColorSeashell
ColorSienna
ColorSkyblue
ColorSlateBlue
ColorSlateGray
ColorSnow
ColorSpringGreen
ColorSteelBlue
ColorTan
ColorThistle
ColorTomato
ColorTurquoise
ColorViolet
ColorWheat
ColorWhiteSmoke
ColorYellowGreen
ColorAliceBlue = ColorIsRGB | ColorValid | 0xF0F8FF
ColorAntiqueWhite = ColorIsRGB | ColorValid | 0xFAEBD7
ColorAquaMarine = ColorIsRGB | ColorValid | 0x7FFFD4
ColorAzure = ColorIsRGB | ColorValid | 0xF0FFFF
ColorBeige = ColorIsRGB | ColorValid | 0xF5F5DC
ColorBisque = ColorIsRGB | ColorValid | 0xFFE4C4
ColorBlanchedAlmond = ColorIsRGB | ColorValid | 0xFFEBCD
ColorBlueViolet = ColorIsRGB | ColorValid | 0x8A2BE2
ColorBrown = ColorIsRGB | ColorValid | 0xA52A2A
ColorBurlyWood = ColorIsRGB | ColorValid | 0xDEB887
ColorCadetBlue = ColorIsRGB | ColorValid | 0x5F9EA0
ColorChartreuse = ColorIsRGB | ColorValid | 0x7FFF00
ColorChocolate = ColorIsRGB | ColorValid | 0xD2691E
ColorCoral = ColorIsRGB | ColorValid | 0xFF7F50
ColorCornflowerBlue = ColorIsRGB | ColorValid | 0x6495ED
ColorCornsilk = ColorIsRGB | ColorValid | 0xFFF8DC
ColorCrimson = ColorIsRGB | ColorValid | 0xDC143C
ColorDarkBlue = ColorIsRGB | ColorValid | 0x00008B
ColorDarkCyan = ColorIsRGB | ColorValid | 0x008B8B
ColorDarkGoldenrod = ColorIsRGB | ColorValid | 0xB8860B
ColorDarkGray = ColorIsRGB | ColorValid | 0xA9A9A9
ColorDarkGreen = ColorIsRGB | ColorValid | 0x006400
ColorDarkKhaki = ColorIsRGB | ColorValid | 0xBDB76B
ColorDarkMagenta = ColorIsRGB | ColorValid | 0x8B008B
ColorDarkOliveGreen = ColorIsRGB | ColorValid | 0x556B2F
ColorDarkOrange = ColorIsRGB | ColorValid | 0xFF8C00
ColorDarkOrchid = ColorIsRGB | ColorValid | 0x9932CC
ColorDarkRed = ColorIsRGB | ColorValid | 0x8B0000
ColorDarkSalmon = ColorIsRGB | ColorValid | 0xE9967A
ColorDarkSeaGreen = ColorIsRGB | ColorValid | 0x8FBC8F
ColorDarkSlateBlue = ColorIsRGB | ColorValid | 0x483D8B
ColorDarkSlateGray = ColorIsRGB | ColorValid | 0x2F4F4F
ColorDarkTurquoise = ColorIsRGB | ColorValid | 0x00CED1
ColorDarkViolet = ColorIsRGB | ColorValid | 0x9400D3
ColorDeepPink = ColorIsRGB | ColorValid | 0xFF1493
ColorDeepSkyBlue = ColorIsRGB | ColorValid | 0x00BFFF
ColorDimGray = ColorIsRGB | ColorValid | 0x696969
ColorDodgerBlue = ColorIsRGB | ColorValid | 0x1E90FF
ColorFireBrick = ColorIsRGB | ColorValid | 0xB22222
ColorFloralWhite = ColorIsRGB | ColorValid | 0xFFFAF0
ColorForestGreen = ColorIsRGB | ColorValid | 0x228B22
ColorGainsboro = ColorIsRGB | ColorValid | 0xDCDCDC
ColorGhostWhite = ColorIsRGB | ColorValid | 0xF8F8FF
ColorGold = ColorIsRGB | ColorValid | 0xFFD700
ColorGoldenrod = ColorIsRGB | ColorValid | 0xDAA520
ColorGreenYellow = ColorIsRGB | ColorValid | 0xADFF2F
ColorHoneydew = ColorIsRGB | ColorValid | 0xF0FFF0
ColorHotPink = ColorIsRGB | ColorValid | 0xFF69B4
ColorIndianRed = ColorIsRGB | ColorValid | 0xCD5C5C
ColorIndigo = ColorIsRGB | ColorValid | 0x4B0082
ColorIvory = ColorIsRGB | ColorValid | 0xFFFFF0
ColorKhaki = ColorIsRGB | ColorValid | 0xF0E68C
ColorLavender = ColorIsRGB | ColorValid | 0xE6E6FA
ColorLavenderBlush = ColorIsRGB | ColorValid | 0xFFF0F5
ColorLawnGreen = ColorIsRGB | ColorValid | 0x7CFC00
ColorLemonChiffon = ColorIsRGB | ColorValid | 0xFFFACD
ColorLightBlue = ColorIsRGB | ColorValid | 0xADD8E6
ColorLightCoral = ColorIsRGB | ColorValid | 0xF08080
ColorLightCyan = ColorIsRGB | ColorValid | 0xE0FFFF
ColorLightGoldenrodYellow = ColorIsRGB | ColorValid | 0xFAFAD2
ColorLightGray = ColorIsRGB | ColorValid | 0xD3D3D3
ColorLightGreen = ColorIsRGB | ColorValid | 0x90EE90
ColorLightPink = ColorIsRGB | ColorValid | 0xFFB6C1
ColorLightSalmon = ColorIsRGB | ColorValid | 0xFFA07A
ColorLightSeaGreen = ColorIsRGB | ColorValid | 0x20B2AA
ColorLightSkyBlue = ColorIsRGB | ColorValid | 0x87CEFA
ColorLightSlateGray = ColorIsRGB | ColorValid | 0x778899
ColorLightSteelBlue = ColorIsRGB | ColorValid | 0xB0C4DE
ColorLightYellow = ColorIsRGB | ColorValid | 0xFFFFE0
ColorLimeGreen = ColorIsRGB | ColorValid | 0x32CD32
ColorLinen = ColorIsRGB | ColorValid | 0xFAF0E6
ColorMediumAquamarine = ColorIsRGB | ColorValid | 0x66CDAA
ColorMediumBlue = ColorIsRGB | ColorValid | 0x0000CD
ColorMediumOrchid = ColorIsRGB | ColorValid | 0xBA55D3
ColorMediumPurple = ColorIsRGB | ColorValid | 0x9370DB
ColorMediumSeaGreen = ColorIsRGB | ColorValid | 0x3CB371
ColorMediumSlateBlue = ColorIsRGB | ColorValid | 0x7B68EE
ColorMediumSpringGreen = ColorIsRGB | ColorValid | 0x00FA9A
ColorMediumTurquoise = ColorIsRGB | ColorValid | 0x48D1CC
ColorMediumVioletRed = ColorIsRGB | ColorValid | 0xC71585
ColorMidnightBlue = ColorIsRGB | ColorValid | 0x191970
ColorMintCream = ColorIsRGB | ColorValid | 0xF5FFFA
ColorMistyRose = ColorIsRGB | ColorValid | 0xFFE4E1
ColorMoccasin = ColorIsRGB | ColorValid | 0xFFE4B5
ColorNavajoWhite = ColorIsRGB | ColorValid | 0xFFDEAD
ColorOldLace = ColorIsRGB | ColorValid | 0xFDF5E6
ColorOliveDrab = ColorIsRGB | ColorValid | 0x6B8E23
ColorOrange = ColorIsRGB | ColorValid | 0xFFA500
ColorOrangeRed = ColorIsRGB | ColorValid | 0xFF4500
ColorOrchid = ColorIsRGB | ColorValid | 0xDA70D6
ColorPaleGoldenrod = ColorIsRGB | ColorValid | 0xEEE8AA
ColorPaleGreen = ColorIsRGB | ColorValid | 0x98FB98
ColorPaleTurquoise = ColorIsRGB | ColorValid | 0xAFEEEE
ColorPaleVioletRed = ColorIsRGB | ColorValid | 0xDB7093
ColorPapayaWhip = ColorIsRGB | ColorValid | 0xFFEFD5
ColorPeachPuff = ColorIsRGB | ColorValid | 0xFFDAB9
ColorPeru = ColorIsRGB | ColorValid | 0xCD853F
ColorPink = ColorIsRGB | ColorValid | 0xFFC0CB
ColorPlum = ColorIsRGB | ColorValid | 0xDDA0DD
ColorPowderBlue = ColorIsRGB | ColorValid | 0xB0E0E6
ColorRebeccaPurple = ColorIsRGB | ColorValid | 0x663399
ColorRosyBrown = ColorIsRGB | ColorValid | 0xBC8F8F
ColorRoyalBlue = ColorIsRGB | ColorValid | 0x4169E1
ColorSaddleBrown = ColorIsRGB | ColorValid | 0x8B4513
ColorSalmon = ColorIsRGB | ColorValid | 0xFA8072
ColorSandyBrown = ColorIsRGB | ColorValid | 0xF4A460
ColorSeaGreen = ColorIsRGB | ColorValid | 0x2E8B57
ColorSeashell = ColorIsRGB | ColorValid | 0xFFF5EE
ColorSienna = ColorIsRGB | ColorValid | 0xA0522D
ColorSkyblue = ColorIsRGB | ColorValid | 0x87CEEB
ColorSlateBlue = ColorIsRGB | ColorValid | 0x6A5ACD
ColorSlateGray = ColorIsRGB | ColorValid | 0x708090
ColorSnow = ColorIsRGB | ColorValid | 0xFFFAFA
ColorSpringGreen = ColorIsRGB | ColorValid | 0x00FF7F
ColorSteelBlue = ColorIsRGB | ColorValid | 0x4682B4
ColorTan = ColorIsRGB | ColorValid | 0xD2B48C
ColorThistle = ColorIsRGB | ColorValid | 0xD8BFD8
ColorTomato = ColorIsRGB | ColorValid | 0xFF6347
ColorTurquoise = ColorIsRGB | ColorValid | 0x40E0D0
ColorViolet = ColorIsRGB | ColorValid | 0xEE82EE
ColorWheat = ColorIsRGB | ColorValid | 0xF5DEB3
ColorWhiteSmoke = ColorIsRGB | ColorValid | 0xF5F5F5
ColorYellowGreen = ColorIsRGB | ColorValid | 0x9ACD32
)
// These are aliases for the color gray, because some of us spell

View File

@ -42,6 +42,7 @@ type cScreen struct {
truecolor bool
running bool
disableAlt bool // disable the alternate screen
title string
w int
h int
@ -49,6 +50,7 @@ type cScreen struct {
oscreen consoleInfo
ocursor cursorInfo
cursorStyle CursorStyle
cursorColor Color
oimode uint32
oomode uint32
cells CellBuffer
@ -164,6 +166,20 @@ const (
vtEnableAm = "\x1b[?7h"
vtEnterCA = "\x1b[?1049h\x1b[22;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{
@ -335,8 +351,10 @@ func (s *cScreen) disengage() {
if s.vten {
s.emitVtString(vtCursorStyles[CursorStyleDefault])
s.emitVtString(vtCursorColorReset)
s.emitVtString(vtEnableAm)
if !s.disableAlt {
s.emitVtString(vtRestoreTitle)
s.emitVtString(vtExitCA)
}
} else if !s.disableAlt {
@ -374,9 +392,13 @@ func (s *cScreen) engage() error {
if s.vten {
s.setOutMode(modeVtOutput | modeNoAutoNL | modeCookedOut | modeUnderline)
if !s.disableAlt {
s.emitVtString(vtSaveTitle)
s.emitVtString(vtEnterCA)
}
s.emitVtString(vtDisableAm)
if s.title != "" {
s.emitVtString(fmt.Sprintf(vtSetTitle, s.title))
}
} else {
s.setOutMode(0)
}
@ -426,6 +448,12 @@ func (s *cScreen) showCursor() {
if s.vten {
s.emitVtString(vtShowCursor)
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 {
s.setCursorInfo(&cursorInfo{size: 100, visible: 1})
}
@ -449,11 +477,12 @@ func (s *cScreen) ShowCursor(x, y int) {
s.Unlock()
}
func (s *cScreen) SetCursorStyle(cs CursorStyle) {
func (s *cScreen) SetCursor(cs CursorStyle, cc Color) {
s.Lock()
if !s.fini {
if _, ok := vtCursorStyles[cs]; ok {
s.cursorStyle = cs
s.cursorColor = cc
s.doCursor()
}
}
@ -875,7 +904,7 @@ func mapColor2RGB(c Color) uint16 {
// Map a tcell style to Windows attributes
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
ba := (s.oscreen.attrs) >> 4 & 0xf
if f != ColorDefault && f != ColorReset {
@ -912,19 +941,41 @@ func (s *cScreen) mapStyle(style Style) uint16 {
func (s *cScreen) sendVtStyle(style Style) {
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)
if attrs&(AttrBold|AttrDim) == AttrBold {
esc.WriteString(vtBold)
}
if attrs&AttrBlink != 0 {
esc.WriteString(vtBlink)
}
if attrs&AttrUnderline != 0 {
if us != UnderlineStyleNone {
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 {
esc.WriteString(vtReverse)
}
@ -940,6 +991,13 @@ func (s *cScreen) sendVtStyle(style Style) {
} else if bg.Valid() {
_, _ = 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())
}
@ -1062,7 +1120,6 @@ func (s *cScreen) setCursorInfo(info *cursorInfo) {
_, _, _ = procSetConsoleCursorInfo.Call(
uintptr(s.out),
uintptr(unsafe.Pointer(info)))
}
func (s *cScreen) setCursorPos(x, y int, vtEnable bool) {
@ -1227,6 +1284,15 @@ func (s *cScreen) SetStyle(style Style) {
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!
func (s *cScreen) RegisterRuneFallback(_ rune, _ string) {
@ -1246,6 +1312,12 @@ func (s *cScreen) HasMouse() bool {
return true
}
func (s *cScreen) SetClipboard(_ []byte) {
}
func (s *cScreen) GetClipboard() {
}
func (s *cScreen) Resize(int, int, int, int) {}
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");
// 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.
// 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
// is pasted in. At the end, an event with .Start() false will be sent.
//
// An event with .Start() true will be sent to mark the start of a bracketed paste,
// followed by a number of keys (string data) for the content, ending with the
// an event with .End() true.
type EventPaste struct {
start bool
t time.Time
data []byte
}
// When returns the time when this EventPaste was created.
@ -46,3 +48,25 @@ func (ev *EventPaste) End() bool {
func NewEventPaste(start bool) *EventPaste {
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");
// 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
// is not supported (or cursor styles are not supported at all),
// then this will have no effect.
SetCursorStyle(CursorStyle)
// then this will have no effect. Color will be changed if supplied,
// and the terminal supports doing so.
SetCursorStyle(CursorStyle, ...Color)
// Size returns the screen size as width, height. This changes in
// 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
// returned bool will be false
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
@ -312,7 +330,7 @@ type screenImpl interface {
SetStyle(style Style)
ShowCursor(x int, y int)
HideCursor()
SetCursorStyle(CursorStyle)
SetCursor(CursorStyle, Color)
Size() (width, height int)
EnableMouse(...MouseFlags)
DisableMouse()
@ -334,7 +352,10 @@ type screenImpl interface {
Resume() error
Beep() error
SetSize(int, int)
SetTitle(string)
Tty() (Tty, bool)
SetClipboard([]byte)
GetClipboard()
// Following methods are not part of the Screen api, but are used for interaction with
// the common layer code.
@ -464,3 +485,11 @@ func (b *baseScreen) PostEvent(ev Event) error {
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");
// you may not use file except in compliance with the License.
@ -60,6 +60,12 @@ type SimulationScreen interface {
// GetCursor returns the cursor details.
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
@ -98,6 +104,8 @@ type simscreen struct {
fillchar rune
fillstyle Style
fallback map[rune]string
title string
clipboard []byte
Screen
sync.Mutex
@ -239,7 +247,7 @@ func (s *simscreen) hideCursor() {
s.cursorvis = false
}
func (s *simscreen) SetCursorStyle(CursorStyle) {}
func (s *simscreen) SetCursor(CursorStyle, Color) {}
func (s *simscreen) Show() {
s.Lock()
@ -495,3 +503,26 @@ func (s *simscreen) EventQ() chan Event {
func (s *simscreen) StopQ() <-chan struct{} {
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");
// you may not use file except in compliance with the License.
@ -23,11 +23,13 @@ package tcell
//
// To use Style, just declare a variable of its type.
type Style struct {
fg Color
bg Color
attrs AttrMask
url string
urlId string
fg Color
bg Color
ulStyle UnderlineStyle
ulColor Color
attrs AttrMask
url string
urlId string
}
// StyleDefault represents a default style, based upon the context.
@ -40,50 +42,35 @@ var styleInvalid = Style{attrs: AttrInvalid}
// Foreground returns a new style based on s, with the foreground color set
// as requested. ColorDefault can be used to select the global default.
func (s Style) Foreground(c Color) Style {
return Style{
fg: c,
bg: s.bg,
attrs: s.attrs,
url: s.url,
urlId: s.urlId,
}
s2 := s
s2.fg = c
return s2
}
// Background returns a new style based on s, with the background color set
// as requested. ColorDefault can be used to select the global default.
func (s Style) Background(c Color) Style {
return Style{
fg: s.fg,
bg: c,
attrs: s.attrs,
url: s.url,
urlId: s.urlId,
}
s2 := s
s2.bg = c
return s2
}
// Decompose breaks a style up, returning the foreground, background,
// 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) {
return s.fg, s.bg, s.attrs
}
func (s Style) setAttrs(attrs AttrMask, on bool) Style {
s2 := s
if on {
return Style{
fg: s.fg,
bg: s.bg,
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,
s2.attrs |= attrs
} else {
s2.attrs &^= attrs
}
return s2
}
// Normal returns the style with all attributes disabled.
@ -125,40 +112,73 @@ func (s Style) Reverse(on bool) Style {
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.
func (s Style) StrikeThrough(on bool) Style {
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
// specified.
func (s Style) Attributes(attrs AttrMask) Style {
return Style{
fg: s.fg,
bg: s.bg,
attrs: attrs,
url: s.url,
urlId: s.urlId,
}
s2 := s
s2.attrs = attrs
return s2
}
// 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
// link to that Url. If the Url is empty, then this mode is turned off.
func (s Style) Url(url string) Style {
return Style{
fg: s.fg,
bg: s.bg,
attrs: s.attrs,
url: url,
urlId: s.urlId,
}
s2 := s
s2.url = url
return s2
}
// 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
// were one Url, even if it spans multiple lines.
func (s Style) UrlId(id string) Style {
return Style{
fg: s.fg,
bg: s.bg,
attrs: s.attrs,
url: s.url,
urlId: "id=" + id,
}
s2 := s
s2.urlId = "id=" + id
return s2
}

View File

@ -67,5 +67,10 @@ func init() {
KeyBacktab: "\x1b[Z",
Modifiers: 1,
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 (
// 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/v/vt100"
_ "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/x/xfce"
_ "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"
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,64 +8,135 @@ func init() {
// tmux terminal multiplexer
terminfo.AddTerminfo(&terminfo.Terminfo{
Name: "tmux",
Columns: 80,
Lines: 24,
Colors: 8,
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[3%p1%dm",
SetBg: "\x1b[4%p1%dm",
SetFgBg: "\x1b[3%p1%d;4%p2%dm",
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,
Name: "tmux",
Columns: 80,
Lines: 24,
Colors: 8,
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[3%p1%dm",
SetBg: "\x1b[4%p1%dm",
SetFgBg: "\x1b[3%p1%d;4%p2%dm",
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",
})
// 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
CursorBlinkingBar 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
ExitUrl string
SetWindowSize string
SetWindowTitle string // no terminfo extension
EnableFocusReporting string
DisableFocusReporting string
DisableAutoMargin string // smam
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 (

View File

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

View File

@ -68,6 +68,7 @@ func init() {
KeyBacktab: "\x1b[Z",
Modifiers: 1,
AutoMargin: true,
XTermLike: true,
})
// xterm with 88 colors
@ -131,6 +132,7 @@ func init() {
KeyBacktab: "\x1b[Z",
Modifiers: 1,
AutoMargin: true,
XTermLike: true,
})
// xterm with 256 colors
@ -194,5 +196,6 @@ func init() {
KeyBacktab: "\x1b[Z",
Modifiers: 1,
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,
TrueColor: 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.
"github.com/gdamore/tcell/v2/terminfo"
"github.com/gdamore/tcell/v2/terminfo/dynamic"
"fmt"
)
func loadDynamicTerminfo(term string) (*terminfo.Terminfo, error) {
if term == "" {
return nil, fmt.Errorf("%w: term not set", ErrTermNotFound)
}
ti, _, e := dynamic.LoadTerminfo(term)
if e != nil {
return nil, e

View File

@ -19,6 +19,7 @@ package tcell
import (
"bytes"
"encoding/base64"
"errors"
"io"
"os"
@ -32,9 +33,6 @@ import (
"golang.org/x/text/transform"
"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
@ -154,8 +152,18 @@ type tScreen struct {
setWinSize string
enableFocus string
disableFocus string
doubleUnder string
curlyUnder string
dottedUnder string
dashedUnder string
underColor string
underRGB string
underFg string
cursorStyles map[CursorStyle]string
cursorStyle CursorStyle
cursorColor Color
cursorRGB string
cursorFg string
saved *term.State
stopQ chan struct{}
eventQ chan Event
@ -164,6 +172,11 @@ type tScreen struct {
mouseFlags MouseFlags
pasteEnabled bool
focusEnabled bool
setTitle string
saveTitle string
restoreTitle string
title string
setClipboard string
sync.Mutex
}
@ -338,7 +351,7 @@ func (t *tScreen) prepareBracketedPaste() {
t.disablePaste = t.ti.DisablePaste
t.prepareKey(keyPasteStart, t.ti.PasteStart)
t.prepareKey(keyPasteEnd, t.ti.PasteEnd)
} else if t.ti.Mouse != "" {
} else if t.ti.Mouse != "" || t.ti.XTermLike {
t.enablePaste = "\x1b[?2004h"
t.disablePaste = "\x1b[?2004l"
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() {
// Linux is a special beast - because it has a mouse entry, but does
// not swallow these OSC commands properly.
@ -359,27 +420,43 @@ func (t *tScreen) prepareExtendedOSC() {
if t.ti.EnterUrl != "" {
t.enterUrl = t.ti.EnterUrl
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.exitUrl = "\x1b]8;;\x1b\\"
}
if 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"
}
if 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"
}
if 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"
}
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() {
@ -397,7 +474,7 @@ func (t *tScreen) prepareCursorStyles() {
CursorStyleBlinkingBar: t.ti.CursorBlinkingBar,
CursorStyleSteadyBar: t.ti.CursorSteadyBar,
}
} else if t.ti.Mouse != "" {
} else if t.ti.Mouse != "" || t.ti.XTermLike {
t.cursorStyles = map[CursorStyle]string{
CursorStyleDefault: "\x1b[0 q",
CursorStyleBlinkingBlock: "\x1b[1 q",
@ -408,6 +485,20 @@ func (t *tScreen) prepareCursorStyles() {
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) {
@ -416,6 +507,11 @@ func (t *tScreen) prepareKey(key Key, val string) {
func (t *tScreen) prepareKeys() {
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(KeyF1, ti.KeyF1)
t.prepareKey(KeyF2, ti.KeyF2)
@ -550,6 +646,7 @@ func (t *tScreen) prepareKeys() {
t.prepareXtermModifiers()
t.prepareBracketedPaste()
t.prepareCursorStyles()
t.prepareUnderlines()
t.prepareExtendedOSC()
outer:
@ -742,7 +839,7 @@ func (t *tScreen) drawCell(x, y int) int {
style = t.style
}
if style != t.curstyle {
fg, bg, attrs := style.Decompose()
fg, bg, attrs := style.fg, style.bg, style.attrs
t.TPuts(ti.AttrOff)
@ -750,8 +847,39 @@ func (t *tScreen) drawCell(x, y int) int {
if attrs&AttrBold != 0 {
t.TPuts(ti.Bold)
}
if attrs&AttrUnderline != 0 {
t.TPuts(ti.Underline)
if us, uc := style.ulStyle, style.ulColor; us != UnderlineStyleNone {
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 {
t.TPuts(ti.Reverse)
@ -827,9 +955,10 @@ func (t *tScreen) ShowCursor(x, y int) {
t.Unlock()
}
func (t *tScreen) SetCursorStyle(cs CursorStyle) {
func (t *tScreen) SetCursor(cs CursorStyle, cc Color) {
t.Lock()
t.cursorStyle = cs
t.cursorColor = cc
t.Unlock()
}
@ -852,6 +981,14 @@ func (t *tScreen) showCursor() {
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.cy = y
}
@ -890,8 +1027,7 @@ func (t *tScreen) Show() {
func (t *tScreen) clearScreen() {
t.TPuts(t.ti.AttrOff)
t.TPuts(t.exitUrl)
fg, bg, _ := t.style.Decompose()
_ = t.sendFgBg(fg, bg, AttrNone)
_ = t.sendFgBg(t.style.fg, t.style.bg, AttrNone)
t.TPuts(t.ti.Clear)
t.clear = false
}
@ -1376,6 +1512,61 @@ func (t *tScreen) parseFocus(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
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
// X11 mouse record.
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 b[0] == '\x1b' {
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
// positions without a setup command, but we don't support them.)
t.TPuts(ti.EnterCA)
if t.saveTitle != "" {
t.TPuts(t.saveTitle)
}
}
t.TPuts(ti.EnterKeypad)
t.TPuts(ti.HideCursor)
t.TPuts(ti.EnableAcs)
t.TPuts(ti.DisableAutoMargin)
t.TPuts(ti.Clear)
if t.title != "" && t.setTitle != "" {
t.TPuts(t.ti.TParm(t.setTitle, t.title))
}
t.wg.Add(2)
go t.inputLoop(stopQ)
@ -1870,11 +2075,17 @@ func (t *tScreen) disengage() {
if t.cursorStyles != nil && t.cursorStyle != CursorStyleDefault {
t.TPuts(t.cursorStyles[CursorStyleDefault])
}
if t.cursorFg != "" && t.cursorColor.Valid() {
t.TPuts(t.cursorFg)
}
t.TPuts(ti.ResetFgBg)
t.TPuts(ti.AttrOff)
t.TPuts(ti.ExitKeypad)
t.TPuts(ti.EnableAutoMargin)
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.ExitCA)
}
@ -1909,3 +2120,30 @@ func (t *tScreen) EventQ() chan Event {
func (t *tScreen) GetCells() *CellBuffer {
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");
// you may not use file except in compliance with the License.
@ -17,6 +17,11 @@
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
// including file descriptors used for terminals and saving the initial state
// 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");
// you may not use file except in compliance with the License.
@ -19,11 +19,13 @@ package tcell
import (
"errors"
"github.com/gdamore/tcell/v2/terminfo"
"fmt"
"strings"
"sync"
"syscall/js"
"unicode/utf8"
"github.com/gdamore/tcell/v2/terminfo"
)
func NewTerminfoScreen() (Screen, error) {
@ -66,6 +68,9 @@ func (t *wScreen) Init() error {
t.Unlock()
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
}
@ -133,14 +138,23 @@ func (t *wScreen) drawCell(x, y int) int {
if bg == -1 {
bg = 0x000000
}
us, uc := style.ulStyle, paletteColor(style.ulColor)
if uc == -1 {
uc = 0x000000
}
var combcarr []interface{} = make([]interface{}, len(combc))
for i, c := range combc {
combcarr[i] = c
s := ""
if len(combc) > 0 {
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)
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
}
@ -151,9 +165,12 @@ func (t *wScreen) ShowCursor(x, y int) {
t.Unlock()
}
func (t *wScreen) SetCursorStyle(cs CursorStyle) {
func (t *wScreen) SetCursor(cs CursorStyle, cc Color) {
if !cc.Valid() {
cc = ColorLightGray
}
t.Lock()
js.Global().Call("setCursorStyle", curStyleClasses[cs])
js.Global().Call("setCursorStyle", curStyleClasses[cs], fmt.Sprintf("#%06x", cc.Hex()))
t.Unlock()
}
@ -511,6 +528,10 @@ func (t *wScreen) StopQ() <-chan struct{} {
return t.quit
}
func (t *wScreen) SetTitle(title string) {
js.Global().Call("setTitle", title)
}
// WebKeyNames maps string names reported from HTML
// (KeyboardEvent.key) to tcell accepted keys.
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
## explicit; go 1.9
github.com/gdamore/encoding
# github.com/gdamore/tcell/v2 v2.7.4
# github.com/gdamore/tcell/v2 v2.8.0
## explicit; go 1.12
github.com/gdamore/tcell/v2
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/x/xfce
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/go-errors/errors v1.5.1
## explicit; go 1.14
@ -105,8 +106,6 @@ github.com/gobwas/glob/syntax/ast
github.com/gobwas/glob/syntax/lexer
github.com/gobwas/glob/util/runes
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
## explicit; go 1.12
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/internal/frame
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
github.com/jesseduffield/gocui
# github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a