mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
Update to tcell v3 (#5562)
Refactor code to introduce a Key type in gocui that bundles the keyName and a rune, so that we don't have to pass these around separately everywhere. This, and updating tcell to v3 lays the ground for supporting more keybindings in terminals that support the CSIu keyboard protocol.
This commit is contained in:
commit
69635f379c
6
go.mod
6
go.mod
|
|
@ -13,7 +13,7 @@ require (
|
|||
github.com/cli/go-gh/v2 v2.13.0
|
||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
|
||||
github.com/creack/pty v1.1.24
|
||||
github.com/gdamore/tcell/v2 v2.13.8
|
||||
github.com/gdamore/tcell/v3 v3.3.0
|
||||
github.com/go-errors/errors v1.5.1
|
||||
github.com/gookit/color v1.6.0
|
||||
github.com/integrii/flaggy v1.8.0
|
||||
|
|
@ -47,6 +47,8 @@ require (
|
|||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
github.com/buger/jsonparser v1.1.2 // indirect
|
||||
github.com/cli/safeexec v1.0.1 // indirect
|
||||
github.com/clipperhouse/displaywidth v0.11.0 // indirect
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fatih/color v1.9.0 // indirect
|
||||
github.com/gdamore/encoding v1.0.1 // indirect
|
||||
|
|
@ -67,7 +69,7 @@ require (
|
|||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/term v0.41.0 // indirect
|
||||
golang.org/x/term v0.42.0 // indirect
|
||||
golang.org/x/text v0.36.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/fsnotify.v1 v1.4.7 // indirect
|
||||
|
|
|
|||
12
go.sum
12
go.sum
|
|
@ -15,6 +15,10 @@ github.com/cli/go-gh/v2 v2.13.0 h1:jEHZu/VPVoIJkciK3pzZd3rbT8J90swsK5Ui4ewH1ys=
|
|||
github.com/cli/go-gh/v2 v2.13.0/go.mod h1:Us/NbQ8VNM0fdaILgoXSz6PKkV5PWaEzkJdc9vR2geM=
|
||||
github.com/cli/safeexec v1.0.1 h1:e/C79PbXF4yYTN/wauC4tviMxEV13BwljGj0N9j+N00=
|
||||
github.com/cli/safeexec v1.0.1/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q=
|
||||
github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8=
|
||||
github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
|
||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do=
|
||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
|
|
@ -29,8 +33,8 @@ 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/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.13.8 h1:Mys/Kl5wfC/GcC5Cx4C2BIQH9dbnhnkPgS9/wF3RlfU=
|
||||
github.com/gdamore/tcell/v2 v2.13.8/go.mod h1:+Wfe208WDdB7INEtCsNrAN6O2m+wsTPk1RAovjaILlo=
|
||||
github.com/gdamore/tcell/v3 v3.3.0 h1:lGo3VwiV8iYMH4TdwBDwEOoDctnOLns6QfrXvZkKNe8=
|
||||
github.com/gdamore/tcell/v3 v3.3.0/go.mod h1:8CJpEjUiAlFIrs7jUhzobiZsSLBAtXo8Dq9mCTrVnqo=
|
||||
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
|
||||
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
|
|
@ -163,8 +167,8 @@ golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
|||
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.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
|
||||
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
|
||||
golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
|
||||
golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ func getBindingSections(bindings []*types.Binding, tr *i18n.TranslationSet) []*b
|
|||
return false
|
||||
}
|
||||
|
||||
return (binding.Description != "" || binding.Alternative != "") && binding.Key != nil
|
||||
return (binding.Description != "" || binding.Alternative != "") && binding.Key.IsSet()
|
||||
})
|
||||
|
||||
bindingsByHeader := lo.GroupBy(bindingsToDisplay, func(binding *types.Binding) header {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package cheatsheet
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -27,7 +28,7 @@ func TestGetBindingSections(t *testing.T) {
|
|||
{
|
||||
ViewName: "files",
|
||||
Description: "stage file",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
},
|
||||
expected: []*bindingSection{
|
||||
|
|
@ -37,7 +38,7 @@ func TestGetBindingSections(t *testing.T) {
|
|||
{
|
||||
ViewName: "files",
|
||||
Description: "stage file",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -49,7 +50,7 @@ func TestGetBindingSections(t *testing.T) {
|
|||
{
|
||||
ViewName: "",
|
||||
Description: "quit",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
},
|
||||
expected: []*bindingSection{
|
||||
|
|
@ -59,7 +60,7 @@ func TestGetBindingSections(t *testing.T) {
|
|||
{
|
||||
ViewName: "",
|
||||
Description: "quit",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -71,17 +72,17 @@ func TestGetBindingSections(t *testing.T) {
|
|||
{
|
||||
ViewName: "files",
|
||||
Description: "stage file",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
{
|
||||
ViewName: "files",
|
||||
Description: "unstage file",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
{
|
||||
ViewName: "submodules",
|
||||
Description: "drop submodule",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
},
|
||||
expected: []*bindingSection{
|
||||
|
|
@ -91,12 +92,12 @@ func TestGetBindingSections(t *testing.T) {
|
|||
{
|
||||
ViewName: "files",
|
||||
Description: "stage file",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
{
|
||||
ViewName: "files",
|
||||
Description: "unstage file",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -106,7 +107,7 @@ func TestGetBindingSections(t *testing.T) {
|
|||
{
|
||||
ViewName: "submodules",
|
||||
Description: "drop submodule",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -118,23 +119,23 @@ func TestGetBindingSections(t *testing.T) {
|
|||
{
|
||||
ViewName: "files",
|
||||
Description: "stage file",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
{
|
||||
ViewName: "files",
|
||||
Description: "unstage file",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
{
|
||||
ViewName: "files",
|
||||
Description: "scroll",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
Tag: "navigation",
|
||||
},
|
||||
{
|
||||
ViewName: "commits",
|
||||
Description: "revert commit",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
},
|
||||
expected: []*bindingSection{
|
||||
|
|
@ -144,7 +145,7 @@ func TestGetBindingSections(t *testing.T) {
|
|||
{
|
||||
ViewName: "files",
|
||||
Description: "scroll",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
Tag: "navigation",
|
||||
},
|
||||
},
|
||||
|
|
@ -155,7 +156,7 @@ func TestGetBindingSections(t *testing.T) {
|
|||
{
|
||||
ViewName: "commits",
|
||||
Description: "revert commit",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -165,12 +166,12 @@ func TestGetBindingSections(t *testing.T) {
|
|||
{
|
||||
ViewName: "files",
|
||||
Description: "stage file",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
{
|
||||
ViewName: "files",
|
||||
Description: "unstage file",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -182,34 +183,34 @@ func TestGetBindingSections(t *testing.T) {
|
|||
{
|
||||
ViewName: "files",
|
||||
Description: "stage file",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
{
|
||||
ViewName: "files",
|
||||
Description: "unstage file",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
{
|
||||
ViewName: "files",
|
||||
Description: "scroll",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
Tag: "navigation",
|
||||
},
|
||||
{
|
||||
ViewName: "commits",
|
||||
Description: "revert commit",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
{
|
||||
ViewName: "commits",
|
||||
Description: "scroll",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
Tag: "navigation",
|
||||
},
|
||||
{
|
||||
ViewName: "commits",
|
||||
Description: "page up",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
Tag: "navigation",
|
||||
},
|
||||
},
|
||||
|
|
@ -220,13 +221,13 @@ func TestGetBindingSections(t *testing.T) {
|
|||
{
|
||||
ViewName: "files",
|
||||
Description: "scroll",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
Tag: "navigation",
|
||||
},
|
||||
{
|
||||
ViewName: "commits",
|
||||
Description: "page up",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
Tag: "navigation",
|
||||
},
|
||||
},
|
||||
|
|
@ -237,7 +238,7 @@ func TestGetBindingSections(t *testing.T) {
|
|||
{
|
||||
ViewName: "commits",
|
||||
Description: "revert commit",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -247,12 +248,12 @@ func TestGetBindingSections(t *testing.T) {
|
|||
{
|
||||
ViewName: "files",
|
||||
Description: "stage file",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
{
|
||||
ViewName: "files",
|
||||
Description: "unstage file",
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import (
|
|||
// NOTE: if you make changes to this table, be sure to update
|
||||
// docs/keybindings/Custom_Keybindings.md as well
|
||||
|
||||
var LabelByKey = map[gocui.Key]string{
|
||||
var LabelByKey = map[gocui.KeyName]string{
|
||||
gocui.KeyF1: "<f1>",
|
||||
gocui.KeyF2: "<f2>",
|
||||
gocui.KeyF3: "<f3>",
|
||||
|
|
@ -42,8 +42,6 @@ var LabelByKey = map[gocui.Key]string{
|
|||
gocui.KeyAltEnter: "<a-enter>",
|
||||
gocui.KeyEsc: "<esc>", // <c-[>, <c-3>
|
||||
gocui.KeyBackspace: "<backspace>", // <c-h>
|
||||
gocui.KeyCtrlSpace: "<c-space>", // <c-~>, <c-2>
|
||||
gocui.KeyCtrlSlash: "<c-/>", // <c-_>
|
||||
gocui.KeySpace: "<space>",
|
||||
gocui.KeyCtrlA: "<c-a>",
|
||||
gocui.KeyCtrlB: "<c-b>",
|
||||
|
|
@ -68,9 +66,6 @@ var LabelByKey = map[gocui.Key]string{
|
|||
gocui.KeyCtrlX: "<c-x>",
|
||||
gocui.KeyCtrlY: "<c-y>",
|
||||
gocui.KeyCtrlZ: "<c-z>",
|
||||
gocui.KeyCtrl4: "<c-4>", // <c-\>
|
||||
gocui.KeyCtrl5: "<c-5>", // <c-]>
|
||||
gocui.KeyCtrl6: "<c-6>",
|
||||
gocui.KeyCtrl8: "<c-8>",
|
||||
gocui.MouseWheelUp: "mouse wheel up",
|
||||
gocui.MouseWheelDown: "mouse wheel down",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package gocui
|
||||
|
||||
import "github.com/gdamore/tcell/v2"
|
||||
import "github.com/gdamore/tcell/v3"
|
||||
|
||||
// Attribute affects the presentation of characters, such as color, boldness, etc.
|
||||
type Attribute uint64
|
||||
|
|
|
|||
|
|
@ -6,64 +6,64 @@ package gocui
|
|||
|
||||
// Editor interface must be satisfied by gocui editors.
|
||||
type Editor interface {
|
||||
Edit(v *View, key Key, ch rune, mod Modifier) bool
|
||||
Edit(v *View, key Key, mod Modifier) bool
|
||||
}
|
||||
|
||||
// The EditorFunc type is an adapter to allow the use of ordinary functions as
|
||||
// Editors. If f is a function with the appropriate signature, EditorFunc(f)
|
||||
// is an Editor object that calls f.
|
||||
type EditorFunc func(v *View, key Key, ch rune, mod Modifier) bool
|
||||
type EditorFunc func(v *View, key Key, mod Modifier) bool
|
||||
|
||||
// Edit calls f(v, key, ch, mod)
|
||||
func (f EditorFunc) Edit(v *View, key Key, ch rune, mod Modifier) bool {
|
||||
return f(v, key, ch, mod)
|
||||
// Edit calls f(v, key, mod)
|
||||
func (f EditorFunc) Edit(v *View, key Key, mod Modifier) bool {
|
||||
return f(v, key, mod)
|
||||
}
|
||||
|
||||
// DefaultEditor is the default editor.
|
||||
var DefaultEditor Editor = EditorFunc(SimpleEditor)
|
||||
|
||||
// SimpleEditor is used as the default gocui editor.
|
||||
func SimpleEditor(v *View, key Key, ch rune, mod Modifier) bool {
|
||||
func SimpleEditor(v *View, key Key, mod Modifier) bool {
|
||||
switch {
|
||||
case (key == KeyBackspace || key == KeyBackspace2) && (mod&ModAlt) != 0,
|
||||
key == KeyCtrlW:
|
||||
case (key.KeyName() == KeyBackspace || key.KeyName() == KeyBackspace2) && (mod&ModAlt) != 0,
|
||||
key.KeyName() == KeyCtrlW:
|
||||
v.TextArea.BackSpaceWord()
|
||||
case key == KeyBackspace || key == KeyBackspace2 || key == KeyCtrlH:
|
||||
case key.KeyName() == KeyBackspace || key.KeyName() == KeyBackspace2 || key.KeyName() == KeyCtrlH:
|
||||
v.TextArea.BackSpaceChar()
|
||||
case key == KeyCtrlD || key == KeyDelete:
|
||||
case key.KeyName() == KeyCtrlD || key.KeyName() == KeyDelete:
|
||||
v.TextArea.DeleteChar()
|
||||
case key == KeyArrowDown:
|
||||
case key.KeyName() == KeyArrowDown:
|
||||
v.TextArea.MoveCursorDown()
|
||||
case key == KeyArrowUp:
|
||||
case key.KeyName() == KeyArrowUp:
|
||||
v.TextArea.MoveCursorUp()
|
||||
case (key == KeyArrowLeft || ch == 'b') && (mod&ModAlt) != 0:
|
||||
case (key.KeyName() == KeyArrowLeft || key.Equals(NewKeyRune('b'))) && (mod&ModAlt) != 0:
|
||||
v.TextArea.MoveLeftWord()
|
||||
case key == KeyArrowLeft || key == KeyCtrlB:
|
||||
case key.KeyName() == KeyArrowLeft || key.KeyName() == KeyCtrlB:
|
||||
v.TextArea.MoveCursorLeft()
|
||||
case (key == KeyArrowRight || ch == 'f') && (mod&ModAlt) != 0:
|
||||
case (key.KeyName() == KeyArrowRight || key.Equals(NewKeyRune('f'))) && (mod&ModAlt) != 0:
|
||||
v.TextArea.MoveRightWord()
|
||||
case key == KeyArrowRight || key == KeyCtrlF:
|
||||
case key.KeyName() == KeyArrowRight || key.KeyName() == KeyCtrlF:
|
||||
v.TextArea.MoveCursorRight()
|
||||
case key == KeyEnter:
|
||||
case key.KeyName() == KeyEnter:
|
||||
v.TextArea.TypeCharacter("\n")
|
||||
case key == KeySpace:
|
||||
case key.KeyName() == KeySpace:
|
||||
v.TextArea.TypeCharacter(" ")
|
||||
case key == KeyInsert:
|
||||
case key.KeyName() == KeyInsert:
|
||||
v.TextArea.ToggleOverwrite()
|
||||
case key == KeyCtrlU:
|
||||
case key.KeyName() == KeyCtrlU:
|
||||
v.TextArea.DeleteToStartOfLine()
|
||||
case key == KeyCtrlK:
|
||||
case key.KeyName() == KeyCtrlK:
|
||||
v.TextArea.DeleteToEndOfLine()
|
||||
case key == KeyCtrlA || key == KeyHome:
|
||||
case key.KeyName() == KeyCtrlA || key.KeyName() == KeyHome:
|
||||
v.TextArea.GoToStartOfLine()
|
||||
case key == KeyCtrlE || key == KeyEnd:
|
||||
case key.KeyName() == KeyCtrlE || key.KeyName() == KeyEnd:
|
||||
v.TextArea.GoToEndOfLine()
|
||||
case key == KeyCtrlW:
|
||||
case key.KeyName() == KeyCtrlW:
|
||||
v.TextArea.BackSpaceWord()
|
||||
case key == KeyCtrlY:
|
||||
case key.KeyName() == KeyCtrlY:
|
||||
v.TextArea.Yank()
|
||||
case ch != 0:
|
||||
v.TextArea.TypeCharacter(string(ch))
|
||||
case key.Str() != "":
|
||||
v.TextArea.TypeCharacter(key.Str())
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/gdamore/tcell/v3"
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/rivo/uniseg"
|
||||
)
|
||||
|
|
@ -81,14 +81,14 @@ type ViewMouseBinding struct {
|
|||
Modifier Modifier
|
||||
|
||||
// must be a mouse key
|
||||
Key Key
|
||||
Key KeyName
|
||||
}
|
||||
|
||||
type ViewMouseBindingOpts struct {
|
||||
X int // i.e. origin x + cursor x
|
||||
Y int // i.e. origin y + cursor y
|
||||
|
||||
Key Key // which button was clicked (will be one of the Mouse* constants)
|
||||
Key KeyName // which button was clicked (will be one of the Mouse* constants)
|
||||
|
||||
IsDoubleClick bool // true if this is a double click
|
||||
}
|
||||
|
|
@ -111,7 +111,7 @@ type RecordingConfig struct {
|
|||
type clickInfo struct {
|
||||
x int
|
||||
y int
|
||||
key Key
|
||||
key KeyName
|
||||
viewName string
|
||||
time time.Time
|
||||
}
|
||||
|
|
@ -175,14 +175,14 @@ type Gui struct {
|
|||
Mutexes GuiMutexes
|
||||
|
||||
OnSearchEscape func() error
|
||||
// these keys must either be of type Key of rune
|
||||
SearchEscapeKey any
|
||||
NextSearchMatchKey any
|
||||
PrevSearchMatchKey any
|
||||
|
||||
SearchEscapeKey Key
|
||||
NextSearchMatchKey Key
|
||||
PrevSearchMatchKey Key
|
||||
|
||||
ErrorHandler func(error) error
|
||||
|
||||
ShouldHandleMouseEvent func(view *View, key Key) bool
|
||||
ShouldHandleMouseEvent func(view *View, key KeyName) bool
|
||||
|
||||
screen tcell.Screen
|
||||
suspendedMutex sync.Mutex
|
||||
|
|
@ -254,9 +254,9 @@ func NewGui(opts NewGuiOpts) (*Gui, error) {
|
|||
g.SupportOverlaps = opts.SupportOverlaps
|
||||
|
||||
// default keys for when searching strings in a view
|
||||
g.SearchEscapeKey = KeyEsc
|
||||
g.NextSearchMatchKey = 'n'
|
||||
g.PrevSearchMatchKey = 'N'
|
||||
g.SearchEscapeKey = NewKeyName(KeyEsc)
|
||||
g.NextSearchMatchKey = NewKeyRune('n')
|
||||
g.PrevSearchMatchKey = NewKeyRune('N')
|
||||
|
||||
g.playRecording = opts.PlayRecording
|
||||
|
||||
|
|
@ -549,28 +549,16 @@ func (g *Gui) CurrentView() *View {
|
|||
// It behaves differently on different platforms. Somewhere it doesn't register Alt key press,
|
||||
// on others it might report Ctrl as Alt. It's not consistent and therefore it's not recommended
|
||||
// to use with mouse keys.
|
||||
func (g *Gui) SetKeybinding(viewname string, key any, mod Modifier, handler func(*Gui, *View) error) error {
|
||||
var kb *keybinding
|
||||
|
||||
k, ch, err := getKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kb = newKeybinding(viewname, k, ch, mod, handler)
|
||||
func (g *Gui) SetKeybinding(viewname string, key Key, mod Modifier, handler func(*Gui, *View) error) error {
|
||||
kb := newKeybinding(viewname, key, mod, handler)
|
||||
g.keybindings = append(g.keybindings, kb)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteKeybinding deletes a keybinding.
|
||||
func (g *Gui) DeleteKeybinding(viewname string, key any, mod Modifier) error {
|
||||
k, ch, err := getKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *Gui) DeleteKeybinding(viewname string, key Key, mod Modifier) error {
|
||||
for i, kb := range g.keybindings {
|
||||
if kb.viewName == viewname && kb.ch == ch && kb.key == k && kb.mod == mod {
|
||||
if kb.viewName == viewname && kb.key.keyName == key.KeyName() && kb.key.str == key.str && kb.mod == mod {
|
||||
g.keybindings = append(g.keybindings[:i], g.keybindings[i+1:]...)
|
||||
return nil
|
||||
}
|
||||
|
|
@ -628,21 +616,6 @@ func (g *Gui) SetRenderSearchStatusFunc(renderSearchStatusFunc func(*View, int,
|
|||
g.renderSearchStatusFunc = renderSearchStatusFunc
|
||||
}
|
||||
|
||||
// getKey takes an empty interface with a key and returns the corresponding
|
||||
// typed Key or rune.
|
||||
func getKey(key any) (Key, rune, error) {
|
||||
switch t := key.(type) {
|
||||
case nil: // Ignore keybinding if `nil`
|
||||
return 0, 0, nil
|
||||
case Key:
|
||||
return t, 0, nil
|
||||
case rune:
|
||||
return 0, t, nil
|
||||
default:
|
||||
return 0, 0, errors.New("unknown type")
|
||||
}
|
||||
}
|
||||
|
||||
// userEvent represents an event triggered by the user.
|
||||
type userEvent struct {
|
||||
f func(*Gui) error
|
||||
|
|
@ -1301,8 +1274,8 @@ func (g *Gui) onKey(ev *GocuiEvent) error {
|
|||
// seem harmful for other terminal emulators.
|
||||
//
|
||||
// KeyCtrlJ (int value 10) is '\r'.
|
||||
if g.IsPasting && ev.Key == KeyCtrlJ {
|
||||
ev.Key = KeyEnter
|
||||
if g.IsPasting && ev.Key.KeyName() == KeyCtrlJ {
|
||||
ev.Key = NewKeyName(KeyEnter)
|
||||
}
|
||||
|
||||
err := g.execKeybindings(g.currentView, ev)
|
||||
|
|
@ -1343,7 +1316,7 @@ func (g *Gui) onKey(ev *GocuiEvent) error {
|
|||
}
|
||||
}
|
||||
|
||||
if ev.Key == MouseLeft && (ev.Mod&ModMotion) == 0 && !v.Editable && g.openHyperlink != nil {
|
||||
if ev.Key.KeyName() == MouseLeft && (ev.Mod&ModMotion) == 0 && !v.Editable && g.openHyperlink != nil {
|
||||
if newY >= 0 && newY <= len(v.viewLines)-1 && newX >= 0 && newX <= len(v.viewLines[newY].line)-1 {
|
||||
if link := v.viewLines[newY].line[newX].hyperlink; link != "" {
|
||||
return g.openHyperlink(link, v.name)
|
||||
|
|
@ -1352,14 +1325,14 @@ func (g *Gui) onKey(ev *GocuiEvent) error {
|
|||
}
|
||||
|
||||
if g.ShouldHandleMouseEvent != nil {
|
||||
if !g.ShouldHandleMouseEvent(v, ev.Key) {
|
||||
if !g.ShouldHandleMouseEvent(v, ev.Key.KeyName()) {
|
||||
// Give clients a chance to reject clicks, for example clicks in inactive views
|
||||
// when a modal panel is open.
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !IsMouseScrollKey(ev.Key) {
|
||||
if !IsMouseScrollKey(ev.Key.KeyName()) {
|
||||
v.SetCursor(newCx, newCy)
|
||||
if v.Editable {
|
||||
v.TextArea.SetCursor2D(newX, newY)
|
||||
|
|
@ -1387,8 +1360,8 @@ func (g *Gui) onKey(ev *GocuiEvent) error {
|
|||
}
|
||||
|
||||
if IsMouseKey(ev.Key) {
|
||||
isDoubleClick := g.recordClickInfo(newX, newY, ev.Key, v)
|
||||
opts := ViewMouseBindingOpts{X: newX, Y: newY, Key: ev.Key, IsDoubleClick: isDoubleClick}
|
||||
isDoubleClick := g.recordClickInfo(newX, newY, ev.Key.KeyName(), v)
|
||||
opts := ViewMouseBindingOpts{X: newX, Y: newY, Key: ev.Key.KeyName(), IsDoubleClick: isDoubleClick}
|
||||
matched, err := g.execMouseKeybindings(v, ev, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -1422,7 +1395,7 @@ func (g *Gui) onKey(ev *GocuiEvent) error {
|
|||
}
|
||||
|
||||
// remember the information for this click, and return true if it was a double click
|
||||
func (g *Gui) recordClickInfo(x, y int, key Key, v *View) bool {
|
||||
func (g *Gui) recordClickInfo(x, y int, key KeyName, v *View) bool {
|
||||
if IsMouseScrollKey(key) {
|
||||
g.lastClick = nil
|
||||
return false
|
||||
|
|
@ -1450,7 +1423,7 @@ func (g *Gui) recordClickInfo(x, y int, key Key, v *View) bool {
|
|||
func (g *Gui) execMouseKeybindings(view *View, ev *GocuiEvent, opts ViewMouseBindingOpts) (bool, error) {
|
||||
isMatch := func(binding *ViewMouseBinding) bool {
|
||||
return binding.ViewName == view.Name() &&
|
||||
ev.Key == binding.Key &&
|
||||
ev.Key.KeyName() == binding.Key &&
|
||||
ev.Mod == binding.Modifier
|
||||
}
|
||||
|
||||
|
|
@ -1472,8 +1445,8 @@ func (g *Gui) execMouseKeybindings(view *View, ev *GocuiEvent, opts ViewMouseBin
|
|||
return false, nil
|
||||
}
|
||||
|
||||
func IsMouseKey(key any) bool {
|
||||
switch key {
|
||||
func IsMouseKey(key Key) bool {
|
||||
switch key.KeyName() {
|
||||
case
|
||||
MouseLeft,
|
||||
MouseRight,
|
||||
|
|
@ -1489,8 +1462,8 @@ func IsMouseKey(key any) bool {
|
|||
}
|
||||
}
|
||||
|
||||
func IsMouseScrollKey(key any) bool {
|
||||
switch key {
|
||||
func IsMouseScrollKey(keyName KeyName) bool {
|
||||
switch keyName {
|
||||
case
|
||||
MouseWheelUp,
|
||||
MouseWheelDown,
|
||||
|
|
@ -1514,11 +1487,11 @@ func (g *Gui) execKeybindings(v *View, ev *GocuiEvent) error {
|
|||
|
||||
// if we're searching, and we've hit n/N/Esc, we ignore the default keybinding
|
||||
if v != nil && v.IsSearching() && ev.Mod == ModNone {
|
||||
if eventMatchesKey(ev, g.NextSearchMatchKey) {
|
||||
if ev.Key.Equals(g.NextSearchMatchKey) {
|
||||
return v.gotoNextMatch()
|
||||
} else if eventMatchesKey(ev, g.PrevSearchMatchKey) {
|
||||
} else if ev.Key.Equals(g.PrevSearchMatchKey) {
|
||||
return v.gotoPreviousMatch()
|
||||
} else if eventMatchesKey(ev, g.SearchEscapeKey) {
|
||||
} else if ev.Key.Equals(g.SearchEscapeKey) {
|
||||
v.searcher.clearSearch()
|
||||
if g.OnSearchEscape != nil {
|
||||
if err := g.OnSearchEscape(); err != nil {
|
||||
|
|
@ -1535,7 +1508,7 @@ func (g *Gui) execKeybindings(v *View, ev *GocuiEvent) error {
|
|||
if kb.handler == nil {
|
||||
continue
|
||||
}
|
||||
if !kb.matchKeypress(ev.Key, ev.Ch, ev.Mod) {
|
||||
if !kb.matchKeypress(ev.Key, ev.Mod) {
|
||||
continue
|
||||
}
|
||||
if g.matchView(v, kb) {
|
||||
|
|
@ -1550,7 +1523,7 @@ func (g *Gui) execKeybindings(v *View, ev *GocuiEvent) error {
|
|||
if v != nil && g.matchView(v.ParentView, kb) {
|
||||
matchingParentViewKb = kb
|
||||
}
|
||||
if globalKb == nil && kb.viewName == "" && ((v != nil && !v.Editable) || (kb.ch == 0 && kb.key != KeyCtrlU && kb.key != KeyCtrlA && kb.key != KeyCtrlE)) {
|
||||
if globalKb == nil && kb.viewName == "" && ((v != nil && !v.Editable) || (kb.key.keyName != KeyCtrlU && kb.key.keyName != KeyCtrlA && kb.key.keyName != KeyCtrlE)) {
|
||||
globalKb = kb
|
||||
}
|
||||
}
|
||||
|
|
@ -1562,7 +1535,7 @@ func (g *Gui) execKeybindings(v *View, ev *GocuiEvent) error {
|
|||
}
|
||||
|
||||
if g.currentView != nil && g.currentView.Editable && g.currentView.Editor != nil {
|
||||
matched := g.currentView.Editor.Edit(g.currentView, ev.Key, ev.Ch, ev.Mod)
|
||||
matched := g.currentView.Editor.Edit(g.currentView, ev.Key, ev.Mod)
|
||||
if matched {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1622,7 +1595,7 @@ func (g *Gui) matchView(v *View, kb *keybinding) bool {
|
|||
if v == nil {
|
||||
return false
|
||||
}
|
||||
if v.Editable && kb.ch != 0 {
|
||||
if v.Editable && kb.key.Str() != "" {
|
||||
return false
|
||||
}
|
||||
if kb.viewName != v.name {
|
||||
|
|
|
|||
49
pkg/gocui/key.go
Normal file
49
pkg/gocui/key.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2026 The gocui Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gocui
|
||||
|
||||
import "github.com/gdamore/tcell/v3"
|
||||
|
||||
type Key struct {
|
||||
keyName KeyName
|
||||
str string
|
||||
}
|
||||
|
||||
func NewKey(keyName KeyName, str string) Key {
|
||||
return Key{
|
||||
keyName: keyName,
|
||||
str: str,
|
||||
}
|
||||
}
|
||||
|
||||
func NewKeyName(keyName KeyName) Key {
|
||||
return Key{
|
||||
keyName: keyName,
|
||||
str: "",
|
||||
}
|
||||
}
|
||||
|
||||
func NewKeyRune(ch rune) Key {
|
||||
return Key{
|
||||
keyName: KeyName(tcell.KeyRune),
|
||||
str: string(ch),
|
||||
}
|
||||
}
|
||||
|
||||
func (k Key) KeyName() KeyName {
|
||||
return k.keyName
|
||||
}
|
||||
|
||||
func (k Key) Str() string {
|
||||
return k.str
|
||||
}
|
||||
|
||||
func (k Key) IsSet() bool {
|
||||
return k.keyName != 0
|
||||
}
|
||||
|
||||
func (k Key) Equals(otherKey Key) bool {
|
||||
return k.keyName == otherKey.keyName && k.str == otherKey.str
|
||||
}
|
||||
|
|
@ -5,147 +5,119 @@
|
|||
package gocui
|
||||
|
||||
import (
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/gdamore/tcell/v3"
|
||||
)
|
||||
|
||||
// Key represents special keys or keys combinations.
|
||||
type Key tcell.Key
|
||||
// KeyName represents special keys or keys combinations.
|
||||
type KeyName tcell.Key
|
||||
|
||||
// Modifier allows to define special keys combinations. They can be used
|
||||
// in combination with Keys or Runes when a new keybinding is defined.
|
||||
type Modifier tcell.ModMask
|
||||
|
||||
// Keybidings are used to link a given key-press event with a handler.
|
||||
// Keybindings are used to link a given key-press event with a handler.
|
||||
type keybinding struct {
|
||||
viewName string
|
||||
key Key
|
||||
ch rune
|
||||
mod Modifier
|
||||
handler func(*Gui, *View) error
|
||||
}
|
||||
|
||||
// newKeybinding returns a new Keybinding object.
|
||||
func newKeybinding(viewname string, key Key, ch rune, mod Modifier, handler func(*Gui, *View) error) (kb *keybinding) {
|
||||
func newKeybinding(viewname string, key Key, mod Modifier, handler func(*Gui, *View) error) (kb *keybinding) {
|
||||
kb = &keybinding{
|
||||
viewName: viewname,
|
||||
key: key,
|
||||
ch: ch,
|
||||
mod: mod,
|
||||
handler: handler,
|
||||
}
|
||||
return kb
|
||||
}
|
||||
|
||||
func eventMatchesKey(ev *GocuiEvent, key any) bool {
|
||||
// assuming ModNone for now
|
||||
if ev.Mod != ModNone {
|
||||
return false
|
||||
}
|
||||
|
||||
k, ch, err := getKey(key)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return k == ev.Key && ch == ev.Ch
|
||||
}
|
||||
|
||||
// matchKeypress returns if the keybinding matches the keypress.
|
||||
func (kb *keybinding) matchKeypress(key Key, ch rune, mod Modifier) bool {
|
||||
return kb.key == key && kb.ch == ch && kb.mod == mod
|
||||
func (kb *keybinding) matchKeypress(key Key, mod Modifier) bool {
|
||||
return kb.key.Equals(key) && kb.mod == mod
|
||||
}
|
||||
|
||||
// Special keys.
|
||||
const (
|
||||
KeyF1 Key = Key(tcell.KeyF1)
|
||||
KeyF2 = Key(tcell.KeyF2)
|
||||
KeyF3 = Key(tcell.KeyF3)
|
||||
KeyF4 = Key(tcell.KeyF4)
|
||||
KeyF5 = Key(tcell.KeyF5)
|
||||
KeyF6 = Key(tcell.KeyF6)
|
||||
KeyF7 = Key(tcell.KeyF7)
|
||||
KeyF8 = Key(tcell.KeyF8)
|
||||
KeyF9 = Key(tcell.KeyF9)
|
||||
KeyF10 = Key(tcell.KeyF10)
|
||||
KeyF11 = Key(tcell.KeyF11)
|
||||
KeyF12 = Key(tcell.KeyF12)
|
||||
KeyInsert = Key(tcell.KeyInsert)
|
||||
KeyDelete = Key(tcell.KeyDelete)
|
||||
KeyHome = Key(tcell.KeyHome)
|
||||
KeyEnd = Key(tcell.KeyEnd)
|
||||
KeyPgdn = Key(tcell.KeyPgDn)
|
||||
KeyPgup = Key(tcell.KeyPgUp)
|
||||
KeyArrowUp = Key(tcell.KeyUp)
|
||||
KeyShiftArrowUp = Key(tcell.KeyF62)
|
||||
KeyArrowDown = Key(tcell.KeyDown)
|
||||
KeyShiftArrowDown = Key(tcell.KeyF63)
|
||||
KeyArrowLeft = Key(tcell.KeyLeft)
|
||||
KeyArrowRight = Key(tcell.KeyRight)
|
||||
KeyF1 KeyName = KeyName(tcell.KeyF1)
|
||||
KeyF2 = KeyName(tcell.KeyF2)
|
||||
KeyF3 = KeyName(tcell.KeyF3)
|
||||
KeyF4 = KeyName(tcell.KeyF4)
|
||||
KeyF5 = KeyName(tcell.KeyF5)
|
||||
KeyF6 = KeyName(tcell.KeyF6)
|
||||
KeyF7 = KeyName(tcell.KeyF7)
|
||||
KeyF8 = KeyName(tcell.KeyF8)
|
||||
KeyF9 = KeyName(tcell.KeyF9)
|
||||
KeyF10 = KeyName(tcell.KeyF10)
|
||||
KeyF11 = KeyName(tcell.KeyF11)
|
||||
KeyF12 = KeyName(tcell.KeyF12)
|
||||
KeyInsert = KeyName(tcell.KeyInsert)
|
||||
KeyDelete = KeyName(tcell.KeyDelete)
|
||||
KeyHome = KeyName(tcell.KeyHome)
|
||||
KeyEnd = KeyName(tcell.KeyEnd)
|
||||
KeyPgdn = KeyName(tcell.KeyPgDn)
|
||||
KeyPgup = KeyName(tcell.KeyPgUp)
|
||||
KeyArrowUp = KeyName(tcell.KeyUp)
|
||||
KeyShiftArrowUp = KeyName(tcell.KeyF62)
|
||||
KeyArrowDown = KeyName(tcell.KeyDown)
|
||||
KeyShiftArrowDown = KeyName(tcell.KeyF63)
|
||||
KeyArrowLeft = KeyName(tcell.KeyLeft)
|
||||
KeyArrowRight = KeyName(tcell.KeyRight)
|
||||
)
|
||||
|
||||
// Keys combinations.
|
||||
const (
|
||||
KeyCtrlTilde = Key(tcell.KeyF64) // arbitrary assignment
|
||||
KeyCtrlSpace = Key(tcell.KeyCtrlSpace)
|
||||
KeyCtrlA = Key(tcell.KeyCtrlA)
|
||||
KeyCtrlB = Key(tcell.KeyCtrlB)
|
||||
KeyCtrlC = Key(tcell.KeyCtrlC)
|
||||
KeyCtrlD = Key(tcell.KeyCtrlD)
|
||||
KeyCtrlE = Key(tcell.KeyCtrlE)
|
||||
KeyCtrlF = Key(tcell.KeyCtrlF)
|
||||
KeyCtrlG = Key(tcell.KeyCtrlG)
|
||||
KeyBackspace = Key(tcell.KeyBackspace)
|
||||
KeyCtrlH = Key(tcell.KeyCtrlH)
|
||||
KeyTab = Key(tcell.KeyTab)
|
||||
KeyBacktab = Key(tcell.KeyBacktab)
|
||||
KeyCtrlI = Key(tcell.KeyCtrlI)
|
||||
KeyCtrlJ = Key(tcell.KeyCtrlJ)
|
||||
KeyCtrlK = Key(tcell.KeyCtrlK)
|
||||
KeyCtrlL = Key(tcell.KeyCtrlL)
|
||||
KeyEnter = Key(tcell.KeyEnter)
|
||||
KeyCtrlM = Key(tcell.KeyCtrlM)
|
||||
KeyCtrlN = Key(tcell.KeyCtrlN)
|
||||
KeyCtrlO = Key(tcell.KeyCtrlO)
|
||||
KeyCtrlP = Key(tcell.KeyCtrlP)
|
||||
KeyCtrlQ = Key(tcell.KeyCtrlQ)
|
||||
KeyCtrlR = Key(tcell.KeyCtrlR)
|
||||
KeyCtrlS = Key(tcell.KeyCtrlS)
|
||||
KeyCtrlT = Key(tcell.KeyCtrlT)
|
||||
KeyCtrlU = Key(tcell.KeyCtrlU)
|
||||
KeyCtrlV = Key(tcell.KeyCtrlV)
|
||||
KeyCtrlW = Key(tcell.KeyCtrlW)
|
||||
KeyCtrlX = Key(tcell.KeyCtrlX)
|
||||
KeyCtrlY = Key(tcell.KeyCtrlY)
|
||||
KeyCtrlZ = Key(tcell.KeyCtrlZ)
|
||||
KeyEsc = Key(tcell.KeyEscape)
|
||||
KeyCtrlUnderscore = Key(tcell.KeyCtrlUnderscore)
|
||||
KeySpace = Key(32)
|
||||
KeyBackspace2 = Key(tcell.KeyBackspace2)
|
||||
KeyCtrl8 = Key(tcell.KeyBackspace2) // same key as in termbox-go
|
||||
KeyCtrlTilde = KeyName(tcell.KeyF64) // arbitrary assignment
|
||||
KeyCtrlA = KeyName(tcell.KeyCtrlA)
|
||||
KeyCtrlB = KeyName(tcell.KeyCtrlB)
|
||||
KeyCtrlC = KeyName(tcell.KeyCtrlC)
|
||||
KeyCtrlD = KeyName(tcell.KeyCtrlD)
|
||||
KeyCtrlE = KeyName(tcell.KeyCtrlE)
|
||||
KeyCtrlF = KeyName(tcell.KeyCtrlF)
|
||||
KeyCtrlG = KeyName(tcell.KeyCtrlG)
|
||||
KeyBackspace = KeyName(tcell.KeyBackspace)
|
||||
KeyCtrlH = KeyName(tcell.KeyCtrlH)
|
||||
KeyTab = KeyName(tcell.KeyTab)
|
||||
KeyBacktab = KeyName(tcell.KeyBacktab)
|
||||
KeyCtrlI = KeyName(tcell.KeyCtrlI)
|
||||
KeyCtrlJ = KeyName(tcell.KeyCtrlJ)
|
||||
KeyCtrlK = KeyName(tcell.KeyCtrlK)
|
||||
KeyCtrlL = KeyName(tcell.KeyCtrlL)
|
||||
KeyEnter = KeyName(tcell.KeyEnter)
|
||||
KeyCtrlM = KeyName(tcell.KeyCtrlM)
|
||||
KeyCtrlN = KeyName(tcell.KeyCtrlN)
|
||||
KeyCtrlO = KeyName(tcell.KeyCtrlO)
|
||||
KeyCtrlP = KeyName(tcell.KeyCtrlP)
|
||||
KeyCtrlQ = KeyName(tcell.KeyCtrlQ)
|
||||
KeyCtrlR = KeyName(tcell.KeyCtrlR)
|
||||
KeyCtrlS = KeyName(tcell.KeyCtrlS)
|
||||
KeyCtrlT = KeyName(tcell.KeyCtrlT)
|
||||
KeyCtrlU = KeyName(tcell.KeyCtrlU)
|
||||
KeyCtrlV = KeyName(tcell.KeyCtrlV)
|
||||
KeyCtrlW = KeyName(tcell.KeyCtrlW)
|
||||
KeyCtrlX = KeyName(tcell.KeyCtrlX)
|
||||
KeyCtrlY = KeyName(tcell.KeyCtrlY)
|
||||
KeyCtrlZ = KeyName(tcell.KeyCtrlZ)
|
||||
KeyEsc = KeyName(tcell.KeyEscape)
|
||||
KeySpace = KeyName(32)
|
||||
KeyBackspace2 = KeyName(tcell.KeyBackspace2)
|
||||
KeyCtrl8 = KeyName(tcell.KeyBackspace2) // same key as in termbox-go
|
||||
|
||||
// The following assignments were used in termbox implementation.
|
||||
// In tcell, these are not keys per se. But in gocui we have them
|
||||
// mapped to the keys so we have to use placeholder keys.
|
||||
|
||||
KeyAltEnter = Key(tcell.KeyF64) // arbitrary assignments
|
||||
MouseLeft = Key(tcell.KeyF63)
|
||||
MouseRight = Key(tcell.KeyF62)
|
||||
MouseMiddle = Key(tcell.KeyF61)
|
||||
MouseRelease = Key(tcell.KeyF60)
|
||||
MouseWheelUp = Key(tcell.KeyF59)
|
||||
MouseWheelDown = Key(tcell.KeyF58)
|
||||
MouseWheelLeft = Key(tcell.KeyF57)
|
||||
MouseWheelRight = Key(tcell.KeyF56)
|
||||
KeyCtrl2 = Key(tcell.KeyNUL) // termbox defines theses
|
||||
KeyCtrl3 = Key(tcell.KeyEscape)
|
||||
KeyCtrl4 = Key(tcell.KeyCtrlBackslash)
|
||||
KeyCtrl5 = Key(tcell.KeyCtrlRightSq)
|
||||
KeyCtrl6 = Key(tcell.KeyCtrlCarat)
|
||||
KeyCtrl7 = Key(tcell.KeyCtrlUnderscore)
|
||||
KeyCtrlSlash = Key(tcell.KeyCtrlUnderscore)
|
||||
KeyCtrlRsqBracket = Key(tcell.KeyCtrlRightSq)
|
||||
KeyCtrlBackslash = Key(tcell.KeyCtrlBackslash)
|
||||
KeyCtrlLsqBracket = Key(tcell.KeyCtrlLeftSq)
|
||||
KeyAltEnter = KeyName(tcell.KeyF64) // arbitrary assignments
|
||||
MouseLeft = KeyName(tcell.KeyF63)
|
||||
MouseRight = KeyName(tcell.KeyF62)
|
||||
MouseMiddle = KeyName(tcell.KeyF61)
|
||||
MouseRelease = KeyName(tcell.KeyF60)
|
||||
MouseWheelUp = KeyName(tcell.KeyF59)
|
||||
MouseWheelDown = KeyName(tcell.KeyF58)
|
||||
MouseWheelLeft = KeyName(tcell.KeyF57)
|
||||
MouseWheelRight = KeyName(tcell.KeyF56)
|
||||
)
|
||||
|
||||
// Modifiers.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
package gocui
|
||||
|
||||
import (
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/gdamore/tcell/v3"
|
||||
"github.com/gdamore/tcell/v3/vt"
|
||||
)
|
||||
|
||||
// We probably don't want this being a global variable for YOLO for now
|
||||
|
|
@ -83,16 +84,17 @@ func registerRuneFallbacks(s tcell.Screen, additional map[rune]string) {
|
|||
|
||||
// tcellInitSimulation initializes tcell screen for use.
|
||||
func (g *Gui) tcellInitSimulation(width int, height int) error {
|
||||
s := tcell.NewSimulationScreen("")
|
||||
if e := s.Init(); e != nil {
|
||||
mt := vt.NewMockTerm(vt.MockOptSize{X: vt.Col(width), Y: vt.Row(height)})
|
||||
s, e := tcell.NewTerminfoScreenFromTty(mt)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
if e = s.Init(); e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
g.screen = s
|
||||
Screen = s
|
||||
// setting to a larger value than the typical terminal size
|
||||
// so that during a test we're more likely to see an item to select in a view.
|
||||
s.SetSize(width, height)
|
||||
s.Sync()
|
||||
return nil
|
||||
}
|
||||
|
|
@ -163,7 +165,6 @@ type GocuiEvent struct {
|
|||
Type gocuiEventType
|
||||
Mod Modifier
|
||||
Key Key
|
||||
Ch rune
|
||||
Width int
|
||||
Height int
|
||||
Err error
|
||||
|
|
@ -207,7 +208,7 @@ type TcellKeyEventWrapper struct {
|
|||
Timestamp int64
|
||||
Mod tcell.ModMask
|
||||
Key tcell.Key
|
||||
Ch rune
|
||||
Ch string
|
||||
}
|
||||
|
||||
func NewTcellKeyEventWrapper(event *tcell.EventKey, timestamp int64) *TcellKeyEventWrapper {
|
||||
|
|
@ -215,7 +216,7 @@ func NewTcellKeyEventWrapper(event *tcell.EventKey, timestamp int64) *TcellKeyEv
|
|||
Timestamp: timestamp,
|
||||
Mod: event.Modifiers(),
|
||||
Key: event.Key(),
|
||||
Ch: event.Rune(),
|
||||
Ch: event.Str(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -279,7 +280,7 @@ func (g *Gui) pollEvent() GocuiEvent {
|
|||
tev = (ev).toTcellEvent()
|
||||
}
|
||||
} else {
|
||||
tev = Screen.PollEvent()
|
||||
tev = <-Screen.EventQ()
|
||||
}
|
||||
|
||||
switch tev := tev.(type) {
|
||||
|
|
@ -290,29 +291,27 @@ func (g *Gui) pollEvent() GocuiEvent {
|
|||
return GocuiEvent{Type: eventResize, Width: w, Height: h}
|
||||
case *tcell.EventKey:
|
||||
k := tev.Key()
|
||||
ch := rune(0)
|
||||
ch := ""
|
||||
if k == tcell.KeyRune {
|
||||
k = 0 // if rune remove key (so it can match rune instead of key)
|
||||
ch = tev.Rune()
|
||||
if ch == ' ' {
|
||||
ch = tev.Str()
|
||||
if ch == " " {
|
||||
// special handling for spacebar
|
||||
k = 32 // tcell keys ends at 31 or starts at 256
|
||||
ch = rune(0)
|
||||
k = tcell.Key(KeySpace)
|
||||
ch = ""
|
||||
}
|
||||
}
|
||||
mod := tev.Modifiers()
|
||||
// remove control modifier and setup special handling of ctrl+spacebar, etc.
|
||||
if mod == tcell.ModCtrl && k == 32 {
|
||||
mod = 0
|
||||
ch = rune(0)
|
||||
k = tcell.KeyCtrlSpace
|
||||
ch = " "
|
||||
k = tcell.KeyRune
|
||||
} else if mod == tcell.ModShift && k == tcell.KeyUp {
|
||||
mod = 0
|
||||
ch = rune(0)
|
||||
ch = ""
|
||||
k = tcell.KeyF62
|
||||
} else if mod == tcell.ModShift && k == tcell.KeyDown {
|
||||
mod = 0
|
||||
ch = rune(0)
|
||||
ch = ""
|
||||
k = tcell.KeyF63
|
||||
} else if mod == tcell.ModCtrl || mod == tcell.ModShift {
|
||||
// remove Ctrl or Shift if specified
|
||||
|
|
@ -329,8 +328,7 @@ func (g *Gui) pollEvent() GocuiEvent {
|
|||
|
||||
return GocuiEvent{
|
||||
Type: eventKey,
|
||||
Key: Key(k),
|
||||
Ch: ch,
|
||||
Key: NewKey(KeyName(k), ch),
|
||||
Mod: Modifier(mod),
|
||||
}
|
||||
case *tcell.EventMouse:
|
||||
|
|
@ -413,8 +411,7 @@ func (g *Gui) pollEvent() GocuiEvent {
|
|||
Type: eventMouse,
|
||||
MouseX: x,
|
||||
MouseY: y,
|
||||
Key: mouseKey,
|
||||
Ch: 0,
|
||||
Key: NewKeyName(mouseKey),
|
||||
Mod: mouseMod,
|
||||
}
|
||||
case *tcell.EventFocus:
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/gdamore/tcell/v3"
|
||||
"github.com/rivo/uniseg"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/constants"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
)
|
||||
|
|
@ -55,7 +54,7 @@ func (gui *Gui) LogCommand(cmdStr string, commandLine bool) {
|
|||
func (gui *Gui) printCommandLogHeader() {
|
||||
introStr := fmt.Sprintf(
|
||||
gui.c.Tr.CommandLogHeader,
|
||||
keybindings.Label(gui.c.UserConfig().Keybinding.Universal.ExtrasMenu),
|
||||
gui.c.UserConfig().Keybinding.Universal.ExtrasMenu,
|
||||
)
|
||||
fmt.Fprintln(gui.Views.Extras, style.FgCyan.Sprint(introStr))
|
||||
|
||||
|
|
@ -72,95 +71,91 @@ func (gui *Gui) printCommandLogHeader() {
|
|||
func (gui *Gui) getRandomTip() string {
|
||||
config := gui.c.UserConfig().Keybinding
|
||||
|
||||
formattedKey := func(key string) string {
|
||||
return keybindings.Label(key)
|
||||
}
|
||||
|
||||
tips := []string{
|
||||
// keybindings and lazygit-specific advice
|
||||
fmt.Sprintf(
|
||||
"To force push, press '%s' and then if the push is rejected you will be asked if you want to force push",
|
||||
formattedKey(config.Universal.Push),
|
||||
config.Universal.Push,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"To filter commits by path, press '%s'",
|
||||
formattedKey(config.Universal.FilteringMenu),
|
||||
config.Universal.FilteringMenu,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"To start an interactive rebase, press '%s' on a commit. You can always abort the rebase by pressing '%s' and selecting 'abort'",
|
||||
formattedKey(config.Universal.Edit),
|
||||
formattedKey(config.Universal.CreateRebaseOptionsMenu),
|
||||
config.Universal.Edit,
|
||||
config.Universal.CreateRebaseOptionsMenu,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"In flat file view, merge conflicts are sorted to the top. To switch to flat file view press '%s'",
|
||||
formattedKey(config.Files.ToggleTreeView),
|
||||
config.Files.ToggleTreeView,
|
||||
),
|
||||
"If you want to learn Go and can think of ways to improve lazygit, join the team! Click 'Ask Question' and express your interest",
|
||||
fmt.Sprintf(
|
||||
"If you press '%s'/'%s' you can undo/redo your changes. Be wary though, this only applies to branches/commits, so only do this if your worktree is clear.\nDocs: %s",
|
||||
formattedKey(config.Universal.Undo),
|
||||
formattedKey(config.Universal.Redo),
|
||||
config.Universal.Undo,
|
||||
config.Universal.Redo,
|
||||
constants.Links.Docs.Undoing,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"to hard reset onto your current upstream branch, press '%s' in the files panel",
|
||||
formattedKey(config.Commits.ViewResetOptions),
|
||||
config.Commits.ViewResetOptions,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"To push a tag, navigate to the tag in the tags tab and press '%s'",
|
||||
formattedKey(config.Branches.PushTag),
|
||||
config.Branches.PushTag,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"You can view the individual files of a stash entry by pressing '%s'",
|
||||
formattedKey(config.Universal.GoInto),
|
||||
config.Universal.GoInto,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"You can diff two commits by pressing '%s' on one commit and then navigating to the other. You can then press '%s' to view the files of the diff",
|
||||
formattedKey(config.Universal.DiffingMenu),
|
||||
formattedKey(config.Universal.GoInto),
|
||||
config.Universal.DiffingMenu,
|
||||
config.Universal.GoInto,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"press '%s' on a commit to drop it (delete it)",
|
||||
formattedKey(config.Universal.Remove),
|
||||
config.Universal.Remove,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"If you need to pull out the big guns to resolve merge conflicts, you can press '%s' in the files panel to open merge options",
|
||||
formattedKey(config.Files.OpenMergeOptions),
|
||||
config.Files.OpenMergeOptions,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"To revert a commit, press '%s' on that commit",
|
||||
formattedKey(config.Commits.RevertCommit),
|
||||
config.Commits.RevertCommit,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"To escape a mode, for example cherry-picking, patch-building, diffing, or filtering mode, you can just spam the '%s' button. Unless of course you have `quitOnTopLevelReturn` enabled in your config",
|
||||
formattedKey(config.Universal.Return),
|
||||
config.Universal.Return,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"You can page through the items of a panel using '%s' and '%s'",
|
||||
formattedKey(config.Universal.PrevPage),
|
||||
formattedKey(config.Universal.NextPage),
|
||||
config.Universal.PrevPage,
|
||||
config.Universal.NextPage,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"You can jump to the top/bottom of a panel using '%s (or %s)' and '%s (or %s)'",
|
||||
formattedKey(config.Universal.GotoTop), formattedKey(config.Universal.GotoTopAlt),
|
||||
formattedKey(config.Universal.GotoBottom), formattedKey(config.Universal.GotoBottomAlt),
|
||||
config.Universal.GotoTop, config.Universal.GotoTopAlt,
|
||||
config.Universal.GotoBottom, config.Universal.GotoBottomAlt,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"To collapse/expand a directory, press '%s'",
|
||||
formattedKey(config.Universal.GoInto),
|
||||
config.Universal.GoInto,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"You can append your staged changes to an older commit by pressing '%s' on that commit",
|
||||
formattedKey(config.Commits.AmendToCommit),
|
||||
config.Commits.AmendToCommit,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"You can amend the last commit with your new file changes by pressing '%s' in the files panel",
|
||||
formattedKey(config.Files.AmendLastCommit),
|
||||
config.Files.AmendLastCommit,
|
||||
),
|
||||
fmt.Sprintf(
|
||||
"You can now navigate the side panels with '%s' and '%s'",
|
||||
formattedKey(config.Universal.NextBlockAlt2),
|
||||
formattedKey(config.Universal.PrevBlockAlt2),
|
||||
config.Universal.NextBlockAlt2,
|
||||
config.Universal.PrevBlockAlt2,
|
||||
),
|
||||
|
||||
"You can use lazygit with a bare repo by passing the --git-dir and --work-tree arguments as you would for the git CLI",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/spf13/afero"
|
||||
|
|
@ -167,8 +166,8 @@ func (self *CommitMessageContext) SetPanelState(
|
|||
|
||||
self.c.Views().CommitDescription.Subtitle = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionSubTitle,
|
||||
map[string]string{
|
||||
"togglePanelKeyBinding": keybindings.Label(self.c.UserConfig().Keybinding.Universal.TogglePanel),
|
||||
"commitMenuKeybinding": keybindings.Label(self.c.UserConfig().Keybinding.CommitMessage.CommitMenu),
|
||||
"togglePanelKeyBinding": self.c.UserConfig().Keybinding.Universal.TogglePanel,
|
||||
"commitMenuKeybinding": self.c.UserConfig().Keybinding.CommitMessage.CommitMenu,
|
||||
})
|
||||
|
||||
self.c.Views().CommitDescription.Visible = true
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ func (self *MenuViewModel) GetDisplayStrings(_ int, _ int) [][]string {
|
|||
}
|
||||
|
||||
keyLabel := ""
|
||||
if item.Key != nil {
|
||||
if item.Key.IsSet() {
|
||||
keyLabel = style.FgCyan.Sprint(keybindings.LabelFromKey(item.Key))
|
||||
}
|
||||
|
||||
|
|
@ -205,7 +205,7 @@ func (self *MenuViewModel) GetNonModelItems() []*NonModelItem {
|
|||
func (self *MenuContext) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
basicBindings := self.ListContextTrait.GetKeybindings(opts)
|
||||
menuItemsWithKeys := lo.Filter(self.menuItems, func(item *types.MenuItem, _ int) bool {
|
||||
return item.Key != nil
|
||||
return item.Key.IsSet()
|
||||
})
|
||||
|
||||
menuItemBindings := lo.Map(menuItemsWithKeys, func(item *types.MenuItem, _ int) *types.Binding {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package context
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
)
|
||||
|
||||
|
|
@ -45,7 +44,7 @@ func (self *SearchTrait) RenderSearchStatus(index int, total int) {
|
|||
fmt.Sprintf(
|
||||
self.c.Tr.NoMatchesFor,
|
||||
self.searchString,
|
||||
theme.OptionsFgColor.Sprintf(self.c.Tr.ExitSearchMode, keybindings.Label(keybindingConfig.Universal.Return)),
|
||||
theme.OptionsFgColor.Sprintf(self.c.Tr.ExitSearchMode, keybindingConfig.Universal.Return),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
|
|
@ -58,9 +57,9 @@ func (self *SearchTrait) RenderSearchStatus(index int, total int) {
|
|||
total,
|
||||
theme.OptionsFgColor.Sprintf(
|
||||
self.c.Tr.SearchKeybindings,
|
||||
keybindings.Label(keybindingConfig.Universal.NextMatch),
|
||||
keybindings.Label(keybindingConfig.Universal.PrevMatch),
|
||||
keybindings.Label(keybindingConfig.Universal.Return),
|
||||
keybindingConfig.Universal.NextMatch,
|
||||
keybindingConfig.Universal.PrevMatch,
|
||||
keybindingConfig.Universal.Return,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import (
|
|||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context/traits"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/samber/lo"
|
||||
|
|
@ -106,8 +106,8 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
|||
Description: self.c.Tr.CherryPickCopy,
|
||||
Tooltip: utils.ResolvePlaceholderString(self.c.Tr.CherryPickCopyTooltip,
|
||||
map[string]string{
|
||||
"paste": keybindings.Label(opts.Config.Commits.PasteCommits),
|
||||
"escape": keybindings.Label(opts.Config.Universal.Return),
|
||||
"paste": opts.Config.Commits.PasteCommits,
|
||||
"escape": opts.Config.Universal.Return,
|
||||
},
|
||||
),
|
||||
DisplayOnScreen: true,
|
||||
|
|
@ -164,14 +164,14 @@ func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) e
|
|||
OnPress: func() error {
|
||||
return self.copyCommitSubjectToClipboard(commit)
|
||||
},
|
||||
Key: 's',
|
||||
Key: gocui.NewKeyRune('s'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.CommitMessage,
|
||||
OnPress: func() error {
|
||||
return self.copyCommitMessageToClipboard(commit)
|
||||
},
|
||||
Key: 'm',
|
||||
Key: gocui.NewKeyRune('m'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.CommitMessageBody,
|
||||
|
|
@ -179,28 +179,28 @@ func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) e
|
|||
OnPress: func() error {
|
||||
return self.copyCommitMessageBodyToClipboard(commitMessageBody)
|
||||
},
|
||||
Key: 'b',
|
||||
Key: gocui.NewKeyRune('b'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.CommitURL,
|
||||
OnPress: func() error {
|
||||
return self.copyCommitURLToClipboard(commit)
|
||||
},
|
||||
Key: 'u',
|
||||
Key: gocui.NewKeyRune('u'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.CommitDiff,
|
||||
OnPress: func() error {
|
||||
return self.copyCommitDiffToClipboard(commit)
|
||||
},
|
||||
Key: 'd',
|
||||
Key: gocui.NewKeyRune('d'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.CommitAuthor,
|
||||
OnPress: func() error {
|
||||
return self.copyAuthorToClipboard(commit)
|
||||
},
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -209,7 +209,7 @@ func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) e
|
|||
OnPress: func() error {
|
||||
return self.copyCommitTagsToClipboard(commit)
|
||||
},
|
||||
Key: 't',
|
||||
Key: gocui.NewKeyRune('t'),
|
||||
}
|
||||
|
||||
if len(commit.Tags) == 0 {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
|
|
@ -101,7 +102,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
|
|||
return self.afterMark(selectCurrentAfter, waitToReselect)
|
||||
},
|
||||
DisabledReason: singleItemIfNotBisecting,
|
||||
Key: 'b',
|
||||
Key: gocui.NewKeyRune('b'),
|
||||
},
|
||||
{
|
||||
Label: fmt.Sprintf(self.c.Tr.Bisect.Mark, shortHashToMark, info.OldTerm()),
|
||||
|
|
@ -114,7 +115,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
|
|||
return self.afterMark(selectCurrentAfter, waitToReselect)
|
||||
},
|
||||
DisabledReason: singleItemIfNotBisecting,
|
||||
Key: 'g',
|
||||
Key: gocui.NewKeyRune('g'),
|
||||
},
|
||||
{
|
||||
Label: fmt.Sprintf(self.c.Tr.Bisect.SkipCurrent, shortHashToMark),
|
||||
|
|
@ -127,7 +128,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
|
|||
return self.afterMark(selectCurrentAfter, waitToReselect)
|
||||
},
|
||||
DisabledReason: singleItemIfNotBisecting,
|
||||
Key: 's',
|
||||
Key: gocui.NewKeyRune('s'),
|
||||
},
|
||||
}
|
||||
if info.GetCurrentHash() != "" && info.GetCurrentHash() != commit.Hash() {
|
||||
|
|
@ -142,7 +143,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
|
|||
return self.afterMark(selectCurrentAfter, waitToReselect)
|
||||
},
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 'S',
|
||||
Key: gocui.NewKeyRune('S'),
|
||||
}))
|
||||
}
|
||||
menuItems = append(menuItems, lo.ToPtr(types.MenuItem{
|
||||
|
|
@ -150,7 +151,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
|
|||
OnPress: func() error {
|
||||
return self.c.Helpers().Bisect.Reset()
|
||||
},
|
||||
Key: 'r',
|
||||
Key: gocui.NewKeyRune('r'),
|
||||
}))
|
||||
|
||||
return self.c.Menu(types.CreateMenuOptions{
|
||||
|
|
@ -179,7 +180,7 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo,
|
|||
return nil
|
||||
},
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 'b',
|
||||
Key: gocui.NewKeyRune('b'),
|
||||
},
|
||||
{
|
||||
Label: fmt.Sprintf(self.c.Tr.Bisect.MarkStart, commit.ShortHash(), info.OldTerm()),
|
||||
|
|
@ -197,7 +198,7 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo,
|
|||
return nil
|
||||
},
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 'g',
|
||||
Key: gocui.NewKeyRune('g'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.Bisect.ChooseTerms,
|
||||
|
|
@ -222,7 +223,7 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo,
|
|||
})
|
||||
return nil
|
||||
},
|
||||
Key: 't',
|
||||
Key: gocui.NewKeyRune('t'),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
|
|||
)
|
||||
viewDivergenceFromBaseBranchItem := &types.MenuItem{
|
||||
LabelColumns: []string{label},
|
||||
Key: 'b',
|
||||
Key: gocui.NewKeyRune('b'),
|
||||
OnPress: func() error {
|
||||
branch := self.context().GetSelected()
|
||||
if branch == nil {
|
||||
|
|
@ -333,7 +333,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
|
|||
})
|
||||
return nil
|
||||
},
|
||||
Key: 'u',
|
||||
Key: gocui.NewKeyRune('u'),
|
||||
}
|
||||
|
||||
setUpstreamItem := &types.MenuItem{
|
||||
|
|
@ -358,7 +358,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
|
|||
return nil
|
||||
})
|
||||
},
|
||||
Key: 's',
|
||||
Key: gocui.NewKeyRune('s'),
|
||||
}
|
||||
|
||||
upstreamResetOptions := utils.ResolvePlaceholderString(
|
||||
|
|
@ -391,7 +391,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
|
|||
return nil
|
||||
},
|
||||
Tooltip: upstreamResetTooltip,
|
||||
Key: 'g',
|
||||
Key: gocui.NewKeyRune('g'),
|
||||
}
|
||||
|
||||
upstreamRebaseItem := &types.MenuItem{
|
||||
|
|
@ -404,7 +404,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
|
|||
return nil
|
||||
},
|
||||
Tooltip: upstreamRebaseTooltip,
|
||||
Key: 'r',
|
||||
Key: gocui.NewKeyRune('r'),
|
||||
}
|
||||
|
||||
if !selectedBranch.IsTrackingRemote() {
|
||||
|
|
@ -624,7 +624,7 @@ func (self *BranchesController) delete(branches []*models.Branch) error {
|
|||
|
||||
localDeleteItem := &types.MenuItem{
|
||||
Label: lo.Ternary(len(branches) > 1, self.c.Tr.DeleteLocalBranches, self.c.Tr.DeleteLocalBranch),
|
||||
Key: 'c',
|
||||
Key: gocui.NewKeyRune('c'),
|
||||
OnPress: func() error {
|
||||
return self.localDelete(branches)
|
||||
},
|
||||
|
|
@ -635,7 +635,7 @@ func (self *BranchesController) delete(branches []*models.Branch) error {
|
|||
|
||||
remoteDeleteItem := &types.MenuItem{
|
||||
Label: lo.Ternary(len(branches) > 1, self.c.Tr.DeleteRemoteBranches, self.c.Tr.DeleteRemoteBranch),
|
||||
Key: 'r',
|
||||
Key: gocui.NewKeyRune('r'),
|
||||
OnPress: func() error {
|
||||
return self.remoteDelete(branches)
|
||||
},
|
||||
|
|
@ -648,7 +648,7 @@ func (self *BranchesController) delete(branches []*models.Branch) error {
|
|||
|
||||
deleteBothItem := &types.MenuItem{
|
||||
Label: lo.Ternary(len(branches) > 1, self.c.Tr.DeleteLocalAndRemoteBranches, self.c.Tr.DeleteLocalAndRemoteBranch),
|
||||
Key: 'b',
|
||||
Key: gocui.NewKeyRune('b'),
|
||||
OnPress: func() error {
|
||||
return self.localAndRemoteDelete(branches)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package controllers
|
|||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
|
@ -72,18 +71,18 @@ func (self *CommitDescriptionController) GetOnFocus() func(types.OnFocusOpts) {
|
|||
if self.c.UserConfig().Keybinding.Universal.ConfirmInEditor == "<disabled>" {
|
||||
footer = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionFooter,
|
||||
map[string]string{
|
||||
"confirmInEditorKeybinding": keybindings.Label(self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt),
|
||||
"confirmInEditorKeybinding": self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt,
|
||||
})
|
||||
} else if self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt == "<disabled>" {
|
||||
footer = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionFooter,
|
||||
map[string]string{
|
||||
"confirmInEditorKeybinding": keybindings.Label(self.c.UserConfig().Keybinding.Universal.ConfirmInEditor),
|
||||
"confirmInEditorKeybinding": self.c.UserConfig().Keybinding.Universal.ConfirmInEditor,
|
||||
})
|
||||
} else {
|
||||
footer = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionFooterTwoBindings,
|
||||
map[string]string{
|
||||
"confirmInEditorKeybinding1": keybindings.Label(self.c.UserConfig().Keybinding.Universal.ConfirmInEditor),
|
||||
"confirmInEditorKeybinding2": keybindings.Label(self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt),
|
||||
"confirmInEditorKeybinding1": self.c.UserConfig().Keybinding.Universal.ConfirmInEditor,
|
||||
"confirmInEditorKeybinding2": self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -120,7 +119,7 @@ func (self *CommitDescriptionController) handleTogglePanel() error {
|
|||
// which is common in pasted code snippets.
|
||||
view := self.Context().GetView()
|
||||
for range 4 {
|
||||
view.Editor.Edit(view, gocui.KeySpace, ' ', 0)
|
||||
view.Editor.Edit(view, gocui.NewKeyRune(' '), 0)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ func (self *CommitMessageController) handleTogglePanel() error {
|
|||
// switch to the description panel.
|
||||
view := self.context().GetView()
|
||||
for range 4 {
|
||||
view.Editor.Edit(view, gocui.KeySpace, ' ', 0)
|
||||
view.Editor.Edit(view, gocui.NewKeyRune(' '), 0)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import (
|
|||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/samber/lo"
|
||||
|
|
@ -231,7 +230,7 @@ func (self *CommitFilesController) openCopyMenu() error {
|
|||
return nil
|
||||
},
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 'n',
|
||||
Key: gocui.NewKeyRune('n'),
|
||||
}
|
||||
copyRelativePathItem := &types.MenuItem{
|
||||
Label: self.c.Tr.CopyRelativeFilePath,
|
||||
|
|
@ -243,7 +242,7 @@ func (self *CommitFilesController) openCopyMenu() error {
|
|||
return nil
|
||||
},
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 'p',
|
||||
Key: gocui.NewKeyRune('p'),
|
||||
}
|
||||
copyAbsolutePathItem := &types.MenuItem{
|
||||
Label: self.c.Tr.CopyAbsoluteFilePath,
|
||||
|
|
@ -259,7 +258,7 @@ func (self *CommitFilesController) openCopyMenu() error {
|
|||
return nil
|
||||
},
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 'P',
|
||||
Key: gocui.NewKeyRune('P'),
|
||||
}
|
||||
copyFileDiffItem := &types.MenuItem{
|
||||
Label: self.c.Tr.CopySelectedDiff,
|
||||
|
|
@ -267,7 +266,7 @@ func (self *CommitFilesController) openCopyMenu() error {
|
|||
return self.copyDiffToClipboard(node.GetPath(), self.c.Tr.FileDiffCopiedToast)
|
||||
},
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 's',
|
||||
Key: gocui.NewKeyRune('s'),
|
||||
}
|
||||
copyAllDiff := &types.MenuItem{
|
||||
Label: self.c.Tr.CopyAllFilesDiff,
|
||||
|
|
@ -275,7 +274,7 @@ func (self *CommitFilesController) openCopyMenu() error {
|
|||
return self.copyDiffToClipboard(".", self.c.Tr.AllFilesDiffCopiedToast)
|
||||
},
|
||||
DisabledReason: self.require(self.itemsSelected())(),
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
}
|
||||
copyFileContentItem := &types.MenuItem{
|
||||
Label: self.c.Tr.CopyFileContent,
|
||||
|
|
@ -296,7 +295,7 @@ func (self *CommitFilesController) openCopyMenu() error {
|
|||
}
|
||||
return nil
|
||||
}))(),
|
||||
Key: 'c',
|
||||
Key: gocui.NewKeyRune('c'),
|
||||
}
|
||||
|
||||
return self.c.Menu(types.CreateMenuOptions{
|
||||
|
|
@ -437,7 +436,7 @@ func (self *CommitFilesController) openDiffTool(node *filetree.CommitFileNode) e
|
|||
func (self *CommitFilesController) toggleForPatch(selectedNodes []*filetree.CommitFileNode) error {
|
||||
if self.c.UserConfig().Git.DiffContextSize == 0 {
|
||||
return fmt.Errorf(self.c.Tr.Actions.NotEnoughContextForCustomPatch,
|
||||
keybindings.Label(self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView))
|
||||
self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView)
|
||||
}
|
||||
|
||||
toggle := func() error {
|
||||
|
|
@ -531,7 +530,7 @@ func (self *CommitFilesController) enterCommitFile(node *filetree.CommitFileNode
|
|||
|
||||
if self.c.UserConfig().Git.DiffContextSize == 0 {
|
||||
return fmt.Errorf(self.c.Tr.Actions.NotEnoughContextForCustomPatch,
|
||||
keybindings.Label(self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView))
|
||||
self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView)
|
||||
}
|
||||
|
||||
from, to, reverse := self.currentFromToReverseForPatchBuilding()
|
||||
|
|
|
|||
|
|
@ -31,19 +31,19 @@ func (self *CustomPatchOptionsMenuAction) Call() error {
|
|||
Label: self.c.Tr.ResetPatch,
|
||||
Tooltip: self.c.Tr.ResetPatchTooltip,
|
||||
OnPress: self.c.Helpers().PatchBuilding.Reset,
|
||||
Key: 'c',
|
||||
Key: gocui.NewKeyRune('c'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.ApplyPatch,
|
||||
Tooltip: self.c.Tr.ApplyPatchTooltip,
|
||||
OnPress: func() error { return self.handleApplyPatch(false) },
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.ApplyPatchInReverse,
|
||||
Tooltip: self.c.Tr.ApplyPatchInReverseTooltip,
|
||||
OnPress: func() error { return self.handleApplyPatch(true) },
|
||||
Key: 'r',
|
||||
Key: gocui.NewKeyRune('r'),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -53,25 +53,25 @@ func (self *CustomPatchOptionsMenuAction) Call() error {
|
|||
Label: fmt.Sprintf(self.c.Tr.RemovePatchFromOriginalCommit, utils.ShortHash(self.c.Git().Patch.PatchBuilder.To)),
|
||||
Tooltip: self.c.Tr.RemovePatchFromOriginalCommitTooltip,
|
||||
OnPress: self.handleDeletePatchFromCommit,
|
||||
Key: 'd',
|
||||
Key: gocui.NewKeyRune('d'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.MovePatchOutIntoIndex,
|
||||
Tooltip: self.c.Tr.MovePatchOutIntoIndexTooltip,
|
||||
OnPress: self.handleMovePatchIntoWorkingTree,
|
||||
Key: 'i',
|
||||
Key: gocui.NewKeyRune('i'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.MovePatchIntoNewCommit,
|
||||
Tooltip: self.c.Tr.MovePatchIntoNewCommitTooltip,
|
||||
OnPress: self.handlePullPatchIntoNewCommit,
|
||||
Key: 'n',
|
||||
Key: gocui.NewKeyRune('n'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.MovePatchIntoNewCommitBefore,
|
||||
Tooltip: self.c.Tr.MovePatchIntoNewCommitBeforeTooltip,
|
||||
OnPress: self.handlePullPatchIntoNewCommitBefore,
|
||||
Key: 'N',
|
||||
Key: gocui.NewKeyRune('N'),
|
||||
},
|
||||
}...)
|
||||
|
||||
|
|
@ -93,7 +93,7 @@ func (self *CustomPatchOptionsMenuAction) Call() error {
|
|||
Label: fmt.Sprintf(self.c.Tr.MovePatchToSelectedCommit, selectedCommit.Hash()),
|
||||
Tooltip: self.c.Tr.MovePatchToSelectedCommitTooltip,
|
||||
OnPress: self.handleMovePatchToSelectedCommit,
|
||||
Key: 'm',
|
||||
Key: gocui.NewKeyRune('m'),
|
||||
DisabledReason: disabledReason,
|
||||
},
|
||||
}, menuItems[1:]...,
|
||||
|
|
@ -107,7 +107,7 @@ func (self *CustomPatchOptionsMenuAction) Call() error {
|
|||
{
|
||||
Label: self.c.Tr.CopyPatchToClipboard,
|
||||
OnPress: func() error { return self.copyPatchToClipboard() },
|
||||
Key: 'y',
|
||||
Key: gocui.NewKeyRune('y'),
|
||||
},
|
||||
}...)
|
||||
|
||||
|
|
|
|||
|
|
@ -671,14 +671,14 @@ func (self *FilesController) handleNonInlineConflict(file *models.File) error {
|
|||
OnPress: func() error {
|
||||
return handle(self.c.Git().WorkingTree.StageFile, self.c.Tr.Actions.ResolveConflictByKeepingFile)
|
||||
},
|
||||
Key: 'k',
|
||||
Key: gocui.NewKeyRune('k'),
|
||||
}
|
||||
deleteItem := &types.MenuItem{
|
||||
Label: self.c.Tr.MergeConflictDeleteFile,
|
||||
OnPress: func() error {
|
||||
return handle(self.c.Git().WorkingTree.RemoveConflictedFile, self.c.Tr.Actions.ResolveConflictByDeletingFile)
|
||||
},
|
||||
Key: 'd',
|
||||
Key: gocui.NewKeyRune('d'),
|
||||
}
|
||||
items := []*types.MenuItem{}
|
||||
switch file.ShortStatus {
|
||||
|
|
@ -856,7 +856,7 @@ func (self *FilesController) ignoreOrExcludeMenu(node *filetree.FileNode) error
|
|||
}
|
||||
return nil
|
||||
},
|
||||
Key: 'i',
|
||||
Key: gocui.NewKeyRune('i'),
|
||||
},
|
||||
{
|
||||
LabelColumns: []string{self.c.Tr.ExcludeFile},
|
||||
|
|
@ -866,7 +866,7 @@ func (self *FilesController) ignoreOrExcludeMenu(node *filetree.FileNode) error
|
|||
}
|
||||
return nil
|
||||
},
|
||||
Key: 'e',
|
||||
Key: gocui.NewKeyRune('e'),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
@ -950,7 +950,7 @@ func (self *FilesController) handleStatusFilterPressed() error {
|
|||
OnPress: func() error {
|
||||
return self.setStatusFiltering(filetree.DisplayStaged)
|
||||
},
|
||||
Key: 's',
|
||||
Key: gocui.NewKeyRune('s'),
|
||||
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayStaged),
|
||||
},
|
||||
{
|
||||
|
|
@ -958,7 +958,7 @@ func (self *FilesController) handleStatusFilterPressed() error {
|
|||
OnPress: func() error {
|
||||
return self.setStatusFiltering(filetree.DisplayUnstaged)
|
||||
},
|
||||
Key: 'u',
|
||||
Key: gocui.NewKeyRune('u'),
|
||||
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayUnstaged),
|
||||
},
|
||||
{
|
||||
|
|
@ -966,7 +966,7 @@ func (self *FilesController) handleStatusFilterPressed() error {
|
|||
OnPress: func() error {
|
||||
return self.setStatusFiltering(filetree.DisplayTracked)
|
||||
},
|
||||
Key: 't',
|
||||
Key: gocui.NewKeyRune('t'),
|
||||
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayTracked),
|
||||
},
|
||||
{
|
||||
|
|
@ -974,7 +974,7 @@ func (self *FilesController) handleStatusFilterPressed() error {
|
|||
OnPress: func() error {
|
||||
return self.setStatusFiltering(filetree.DisplayUntracked)
|
||||
},
|
||||
Key: 'T',
|
||||
Key: gocui.NewKeyRune('T'),
|
||||
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayUntracked),
|
||||
},
|
||||
{
|
||||
|
|
@ -982,7 +982,7 @@ func (self *FilesController) handleStatusFilterPressed() error {
|
|||
OnPress: func() error {
|
||||
return self.setStatusFiltering(filetree.DisplayAll)
|
||||
},
|
||||
Key: 'r',
|
||||
Key: gocui.NewKeyRune('r'),
|
||||
Widget: types.MakeMenuRadioButton(currentFilter == filetree.DisplayAll),
|
||||
},
|
||||
},
|
||||
|
|
@ -1092,7 +1092,7 @@ func (self *FilesController) createStashMenu() error {
|
|||
}
|
||||
return self.handleStashSave(self.c.Git().Stash.Push, self.c.Tr.Actions.StashAllChanges)
|
||||
},
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.StashAllChangesKeepIndex,
|
||||
|
|
@ -1103,14 +1103,14 @@ func (self *FilesController) createStashMenu() error {
|
|||
// if there are no staged files it behaves the same as Stash.Save
|
||||
return self.handleStashSave(self.c.Git().Stash.StashAndKeepIndex, self.c.Tr.Actions.StashAllChangesKeepIndex)
|
||||
},
|
||||
Key: 'i',
|
||||
Key: gocui.NewKeyRune('i'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.StashIncludeUntrackedChanges,
|
||||
OnPress: func() error {
|
||||
return self.handleStashSave(self.c.Git().Stash.StashIncludeUntrackedChanges, self.c.Tr.Actions.StashIncludeUntrackedChanges)
|
||||
},
|
||||
Key: 'U',
|
||||
Key: gocui.NewKeyRune('U'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.StashStagedChanges,
|
||||
|
|
@ -1121,7 +1121,7 @@ func (self *FilesController) createStashMenu() error {
|
|||
}
|
||||
return self.handleStashSave(self.c.Git().Stash.SaveStagedChanges, self.c.Tr.Actions.StashStagedChanges)
|
||||
},
|
||||
Key: 's',
|
||||
Key: gocui.NewKeyRune('s'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.StashUnstagedChanges,
|
||||
|
|
@ -1135,7 +1135,7 @@ func (self *FilesController) createStashMenu() error {
|
|||
// ordinary stash
|
||||
return self.handleStashSave(self.c.Git().Stash.Push, self.c.Tr.Actions.StashUnstagedChanges)
|
||||
},
|
||||
Key: 'u',
|
||||
Key: gocui.NewKeyRune('u'),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
@ -1182,7 +1182,7 @@ func (self *FilesController) openCopyMenu() error {
|
|||
return nil
|
||||
},
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 'n',
|
||||
Key: gocui.NewKeyRune('n'),
|
||||
}
|
||||
copyRelativePathItem := &types.MenuItem{
|
||||
Label: self.c.Tr.CopyRelativeFilePath,
|
||||
|
|
@ -1194,7 +1194,7 @@ func (self *FilesController) openCopyMenu() error {
|
|||
return nil
|
||||
},
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 'p',
|
||||
Key: gocui.NewKeyRune('p'),
|
||||
}
|
||||
copyAbsolutePathItem := &types.MenuItem{
|
||||
Label: self.c.Tr.CopyAbsoluteFilePath,
|
||||
|
|
@ -1210,7 +1210,7 @@ func (self *FilesController) openCopyMenu() error {
|
|||
return nil
|
||||
},
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 'P',
|
||||
Key: gocui.NewKeyRune('P'),
|
||||
}
|
||||
copyFileDiffItem := &types.MenuItem{
|
||||
Label: self.c.Tr.CopySelectedDiff,
|
||||
|
|
@ -1236,7 +1236,7 @@ func (self *FilesController) openCopyMenu() error {
|
|||
return nil
|
||||
},
|
||||
))(),
|
||||
Key: 's',
|
||||
Key: gocui.NewKeyRune('s'),
|
||||
}
|
||||
copyAllDiff := &types.MenuItem{
|
||||
Label: self.c.Tr.CopyAllFilesDiff,
|
||||
|
|
@ -1261,7 +1261,7 @@ func (self *FilesController) openCopyMenu() error {
|
|||
return nil
|
||||
},
|
||||
)(),
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
}
|
||||
|
||||
return self.c.Menu(types.CreateMenuOptions{
|
||||
|
|
@ -1534,7 +1534,7 @@ func (self *FilesController) remove(selectedNodes []*filetree.FileNode) error {
|
|||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.WORKTREES}})
|
||||
return nil
|
||||
},
|
||||
Key: 'u',
|
||||
Key: gocui.NewKeyRune('u'),
|
||||
Tooltip: utils.ResolvePlaceholderString(
|
||||
self.c.Tr.DiscardUnstagedTooltip,
|
||||
map[string]string{
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
|
@ -82,22 +83,22 @@ func (self *GitFlowController) handleCreateGitFlowMenu(branch *models.Branch) er
|
|||
{
|
||||
Label: "start feature",
|
||||
OnPress: startHandler("feature"),
|
||||
Key: 'f',
|
||||
Key: gocui.NewKeyRune('f'),
|
||||
},
|
||||
{
|
||||
Label: "start hotfix",
|
||||
OnPress: startHandler("hotfix"),
|
||||
Key: 'h',
|
||||
Key: gocui.NewKeyRune('h'),
|
||||
},
|
||||
{
|
||||
Label: "start bugfix",
|
||||
OnPress: startHandler("bugfix"),
|
||||
Key: 'b',
|
||||
Key: gocui.NewKeyRune('b'),
|
||||
},
|
||||
{
|
||||
Label: "start release",
|
||||
OnPress: startHandler("release"),
|
||||
Key: 'r',
|
||||
Key: gocui.NewKeyRune('r'),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ func (self *CommitsHelper) OpenCommitMenu(suggestionFunc func(string) []*types.S
|
|||
OnPress: func() error {
|
||||
return self.SwitchToEditor()
|
||||
},
|
||||
Key: 'e',
|
||||
Key: gocui.NewKeyRune('e'),
|
||||
DisabledReason: disabledReasonForOpenInEditor,
|
||||
},
|
||||
{
|
||||
|
|
@ -236,14 +236,14 @@ func (self *CommitsHelper) OpenCommitMenu(suggestionFunc func(string) []*types.S
|
|||
OnPress: func() error {
|
||||
return self.addCoAuthor(suggestionFunc)
|
||||
},
|
||||
Key: 'c',
|
||||
Key: gocui.NewKeyRune('c'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.PasteCommitMessageFromClipboard,
|
||||
OnPress: func() error {
|
||||
return self.pasteCommitMessageFromClipboard()
|
||||
},
|
||||
Key: 'p',
|
||||
Key: gocui.NewKeyRune('p'),
|
||||
},
|
||||
}
|
||||
return self.c.Menu(types.CreateMenuOptions{
|
||||
|
|
|
|||
|
|
@ -39,17 +39,17 @@ const (
|
|||
func (self *MergeAndRebaseHelper) CreateRebaseOptionsMenu() error {
|
||||
type optionAndKey struct {
|
||||
option string
|
||||
key types.Key
|
||||
key gocui.Key
|
||||
}
|
||||
|
||||
options := []optionAndKey{
|
||||
{option: REBASE_OPTION_CONTINUE, key: 'c'},
|
||||
{option: REBASE_OPTION_ABORT, key: 'a'},
|
||||
{option: REBASE_OPTION_CONTINUE, key: gocui.NewKeyRune('c')},
|
||||
{option: REBASE_OPTION_ABORT, key: gocui.NewKeyRune('a')},
|
||||
}
|
||||
|
||||
if self.c.Git().Status.WorkingTreeState().CanSkip() {
|
||||
options = append(options, optionAndKey{
|
||||
option: REBASE_OPTION_SKIP, key: 's',
|
||||
option: REBASE_OPTION_SKIP, key: gocui.NewKeyRune('s'),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -198,7 +198,7 @@ func (self *MergeAndRebaseHelper) PromptForConflictHandling() error {
|
|||
OnPress: func() error {
|
||||
return self.genericMergeCommand(REBASE_OPTION_ABORT)
|
||||
},
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
},
|
||||
},
|
||||
HideCancel: true,
|
||||
|
|
@ -284,7 +284,7 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error {
|
|||
Label: utils.ResolvePlaceholderString(self.c.Tr.SimpleRebase,
|
||||
map[string]string{"ref": ref},
|
||||
),
|
||||
Key: 's',
|
||||
Key: gocui.NewKeyRune('s'),
|
||||
DisabledReason: disabledReason,
|
||||
OnPress: func() error {
|
||||
self.c.LogAction(self.c.Tr.Actions.RebaseBranch)
|
||||
|
|
@ -308,7 +308,7 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error {
|
|||
Label: utils.ResolvePlaceholderString(self.c.Tr.InteractiveRebase,
|
||||
map[string]string{"ref": ref},
|
||||
),
|
||||
Key: 'i',
|
||||
Key: gocui.NewKeyRune('i'),
|
||||
DisabledReason: disabledReason,
|
||||
Tooltip: self.c.Tr.InteractiveRebaseTooltip,
|
||||
OnPress: func() error {
|
||||
|
|
@ -334,7 +334,7 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error {
|
|||
Label: utils.ResolvePlaceholderString(self.c.Tr.RebaseOntoBaseBranch,
|
||||
map[string]string{"baseBranch": ShortBranchName(baseBranch)},
|
||||
),
|
||||
Key: 'b',
|
||||
Key: gocui.NewKeyRune('b'),
|
||||
DisabledReason: baseBranchDisabledReason,
|
||||
Tooltip: self.c.Tr.RebaseOntoBaseBranchTooltip,
|
||||
OnPress: func() error {
|
||||
|
|
@ -392,7 +392,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e
|
|||
firstRegularMergeItem = &types.MenuItem{
|
||||
Label: self.c.Tr.RegularMergeFastForward,
|
||||
OnPress: self.RegularMerge(refName, git_commands.MERGE_VARIANT_REGULAR),
|
||||
Key: 'm',
|
||||
Key: gocui.NewKeyRune('m'),
|
||||
Tooltip: utils.ResolvePlaceholderString(
|
||||
self.c.Tr.RegularMergeFastForwardTooltip,
|
||||
map[string]string{
|
||||
|
|
@ -406,7 +406,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e
|
|||
secondRegularMergeItem = &types.MenuItem{
|
||||
Label: self.c.Tr.RegularMergeNonFastForward,
|
||||
OnPress: self.RegularMerge(refName, git_commands.MERGE_VARIANT_NON_FAST_FORWARD),
|
||||
Key: 'n',
|
||||
Key: gocui.NewKeyRune('n'),
|
||||
Tooltip: utils.ResolvePlaceholderString(
|
||||
self.c.Tr.RegularMergeNonFastForwardTooltip,
|
||||
map[string]string{
|
||||
|
|
@ -419,7 +419,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e
|
|||
firstRegularMergeItem = &types.MenuItem{
|
||||
Label: self.c.Tr.RegularMergeNonFastForward,
|
||||
OnPress: self.RegularMerge(refName, git_commands.MERGE_VARIANT_REGULAR),
|
||||
Key: 'm',
|
||||
Key: gocui.NewKeyRune('m'),
|
||||
Tooltip: utils.ResolvePlaceholderString(
|
||||
self.c.Tr.RegularMergeNonFastForwardTooltip,
|
||||
map[string]string{
|
||||
|
|
@ -432,7 +432,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e
|
|||
secondRegularMergeItem = &types.MenuItem{
|
||||
Label: self.c.Tr.RegularMergeFastForward,
|
||||
OnPress: self.RegularMerge(refName, git_commands.MERGE_VARIANT_FAST_FORWARD),
|
||||
Key: 'f',
|
||||
Key: gocui.NewKeyRune('f'),
|
||||
Tooltip: utils.ResolvePlaceholderString(
|
||||
self.c.Tr.RegularMergeFastForwardTooltip,
|
||||
map[string]string{
|
||||
|
|
@ -464,7 +464,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e
|
|||
{
|
||||
Label: self.c.Tr.SquashMergeUncommitted,
|
||||
OnPress: self.SquashMergeUncommitted(refName),
|
||||
Key: 's',
|
||||
Key: gocui.NewKeyRune('s'),
|
||||
Tooltip: utils.ResolvePlaceholderString(
|
||||
self.c.Tr.SquashMergeUncommittedTooltip,
|
||||
map[string]string{
|
||||
|
|
@ -475,7 +475,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e
|
|||
{
|
||||
Label: self.c.Tr.SquashMergeCommitted,
|
||||
OnPress: self.SquashMergeCommitted(refName, checkedOutBranchName),
|
||||
Key: 'S',
|
||||
Key: gocui.NewKeyRune('S'),
|
||||
Tooltip: utils.ResolvePlaceholderString(
|
||||
self.c.Tr.SquashMergeCommittedTooltip,
|
||||
map[string]string{
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/patch"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/patch_exploring"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
)
|
||||
|
|
@ -26,8 +25,7 @@ func (self *PatchBuildingHelper) ShowHunkStagingHint() {
|
|||
self.c.AppState.DidShowHunkStagingHint = true
|
||||
self.c.SaveAppStateAndLogError()
|
||||
|
||||
message := fmt.Sprintf(self.c.Tr.HunkStagingHint,
|
||||
keybindings.Label(self.c.UserConfig().Keybinding.Main.ToggleSelectHunk))
|
||||
message := fmt.Sprintf(self.c.Tr.HunkStagingHint, self.c.UserConfig().Keybinding.Main.ToggleSelectHunk)
|
||||
self.c.Confirm(types.ConfirmOpts{
|
||||
Prompt: message,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -216,15 +216,15 @@ func (self *RefsHelper) ResetToRef(ref string, strength string, envVars []string
|
|||
|
||||
func (self *RefsHelper) CreateSortOrderMenu(sortOptionsOrder []string, menuPrompt string, onSelected func(sortOrder string) error, currentValue string) error {
|
||||
type sortMenuOption struct {
|
||||
key types.Key
|
||||
key gocui.Key
|
||||
label string
|
||||
description string
|
||||
sortOrder string
|
||||
}
|
||||
availableSortOptions := map[string]sortMenuOption{
|
||||
"recency": {label: self.c.Tr.SortByRecency, description: self.c.Tr.SortBasedOnReflog, key: 'r'},
|
||||
"alphabetical": {label: self.c.Tr.SortAlphabetical, description: "--sort=refname", key: 'a'},
|
||||
"date": {label: self.c.Tr.SortByDate, description: "--sort=-committerdate", key: 'd'},
|
||||
"recency": {label: self.c.Tr.SortByRecency, description: self.c.Tr.SortBasedOnReflog, key: gocui.NewKeyRune('r')},
|
||||
"alphabetical": {label: self.c.Tr.SortAlphabetical, description: "--sort=refname", key: gocui.NewKeyRune('a')},
|
||||
"date": {label: self.c.Tr.SortByDate, description: "--sort=-committerdate", key: gocui.NewKeyRune('d')},
|
||||
}
|
||||
sortOptions := make([]sortMenuOption, 0, len(sortOptionsOrder))
|
||||
for _, key := range sortOptionsOrder {
|
||||
|
|
@ -260,14 +260,14 @@ func (self *RefsHelper) CreateGitResetMenu(name string, ref string) error {
|
|||
type strengthWithKey struct {
|
||||
strength string
|
||||
label string
|
||||
key types.Key
|
||||
key gocui.Key
|
||||
tooltip string
|
||||
}
|
||||
strengths := []strengthWithKey{
|
||||
// not i18'ing because it's git terminology
|
||||
{strength: "mixed", label: "Mixed reset", key: 'm', tooltip: self.c.Tr.ResetMixedTooltip},
|
||||
{strength: "soft", label: "Soft reset", key: 's', tooltip: self.c.Tr.ResetSoftTooltip},
|
||||
{strength: "hard", label: "Hard reset", key: 'h', tooltip: self.c.Tr.ResetHardTooltip},
|
||||
{strength: "mixed", label: "Mixed reset", key: gocui.NewKeyRune('m'), tooltip: self.c.Tr.ResetMixedTooltip},
|
||||
{strength: "soft", label: "Soft reset", key: gocui.NewKeyRune('s'), tooltip: self.c.Tr.ResetSoftTooltip},
|
||||
{strength: "hard", label: "Hard reset", key: gocui.NewKeyRune('h'), tooltip: self.c.Tr.ResetHardTooltip},
|
||||
}
|
||||
|
||||
menuItems := lo.Map(strengths, func(row strengthWithKey, _ int) *types.MenuItem {
|
||||
|
|
@ -312,15 +312,15 @@ func (self *RefsHelper) CreateCheckoutMenu(commit *models.Commit) error {
|
|||
self.c.LogAction(self.c.Tr.Actions.CheckoutCommit)
|
||||
return self.CheckoutRef(hash, types.CheckoutRefOptions{})
|
||||
},
|
||||
Key: 'd',
|
||||
Key: gocui.NewKeyRune('d'),
|
||||
},
|
||||
}
|
||||
|
||||
if len(branches) > 0 {
|
||||
menuItems = append(menuItems, lo.Map(branches, func(branch *models.Branch, index int) *types.MenuItem {
|
||||
var key types.Key
|
||||
var key gocui.Key
|
||||
if index < 9 {
|
||||
key = rune(index + 1 + '0') // Convert 1-based index to key
|
||||
key = gocui.NewKeyRune(rune(index + 1 + '0')) // Convert 1-based index to key
|
||||
}
|
||||
return &types.MenuItem{
|
||||
LabelColumns: []string{fmt.Sprintf(self.c.Tr.Actions.CheckoutBranchAtCommit, branch.Name)},
|
||||
|
|
@ -336,7 +336,7 @@ func (self *RefsHelper) CreateCheckoutMenu(commit *models.Commit) error {
|
|||
LabelColumns: []string{self.c.Tr.Actions.CheckoutBranch},
|
||||
OnPress: func() error { return nil },
|
||||
DisabledReason: &types.DisabledReason{Text: self.c.Tr.NoBranchesFoundAtCommitTooltip},
|
||||
Key: '1',
|
||||
Key: gocui.NewKeyRune('1'),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
|
|
@ -75,7 +74,7 @@ func (self *SearchHelper) DisplayFilterStatus(context types.IFilterableContext)
|
|||
|
||||
promptView := self.promptView()
|
||||
keybindingConfig := self.c.UserConfig().Keybinding
|
||||
promptView.SetContent(fmt.Sprintf("matches for '%s' ", searchString) + theme.OptionsFgColor.Sprintf(self.c.Tr.ExitTextFilterMode, keybindings.Label(keybindingConfig.Universal.Return)))
|
||||
promptView.SetContent(fmt.Sprintf("matches for '%s' ", searchString) + theme.OptionsFgColor.Sprintf(self.c.Tr.ExitTextFilterMode, keybindingConfig.Universal.Return))
|
||||
}
|
||||
|
||||
func (self *SearchHelper) DisplaySearchStatus(context types.ISearchableContext) {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
|
|
@ -382,7 +383,7 @@ func (self *WorkingTreeHelper) CreateMergeConflictMenu(selectedFilepaths []strin
|
|||
OnPress: func() error {
|
||||
return onMergeStrategySelected("--ours")
|
||||
},
|
||||
Key: 'c',
|
||||
Key: gocui.NewKeyRune('c'),
|
||||
},
|
||||
{
|
||||
LabelColumns: []string{
|
||||
|
|
@ -392,7 +393,7 @@ func (self *WorkingTreeHelper) CreateMergeConflictMenu(selectedFilepaths []strin
|
|||
OnPress: func() error {
|
||||
return onMergeStrategySelected("--theirs")
|
||||
},
|
||||
Key: 'i',
|
||||
Key: gocui.NewKeyRune('i'),
|
||||
},
|
||||
{
|
||||
LabelColumns: []string{
|
||||
|
|
@ -402,7 +403,7 @@ func (self *WorkingTreeHelper) CreateMergeConflictMenu(selectedFilepaths []strin
|
|||
OnPress: func() error {
|
||||
return onMergeStrategySelected("--union")
|
||||
},
|
||||
Key: 'b',
|
||||
Key: gocui.NewKeyRune('b'),
|
||||
},
|
||||
{
|
||||
LabelColumns: []string{
|
||||
|
|
@ -410,7 +411,7 @@ func (self *WorkingTreeHelper) CreateMergeConflictMenu(selectedFilepaths []strin
|
|||
cmdColor.Sprint("git mergetool"),
|
||||
},
|
||||
OnPress: self.OpenMergeTool,
|
||||
Key: 'm',
|
||||
Key: gocui.NewKeyRune('m'),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context/traits"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
|
|
@ -142,7 +141,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
|||
GetDisabledReason: self.require(self.notMidRebase(self.c.Tr.AlreadyRebasing), self.canFindCommitForQuickStart),
|
||||
Description: self.c.Tr.QuickStartInteractiveRebase,
|
||||
Tooltip: utils.ResolvePlaceholderString(self.c.Tr.QuickStartInteractiveRebaseTooltip, map[string]string{
|
||||
"editKey": keybindings.Label(editCommitKey),
|
||||
"editKey": editCommitKey,
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
|
@ -162,7 +161,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
|||
Tooltip: utils.ResolvePlaceholderString(
|
||||
self.c.Tr.CreateFixupCommitTooltip,
|
||||
map[string]string{
|
||||
"squashAbove": keybindings.Label(opts.Config.Commits.SquashAboveCommits),
|
||||
"squashAbove": opts.Config.Commits.SquashAboveCommits,
|
||||
},
|
||||
),
|
||||
},
|
||||
|
|
@ -362,7 +361,7 @@ func (self *LocalCommitsController) fixup(selectedCommits []*models.Commit, star
|
|||
Items: []*types.MenuItem{
|
||||
{
|
||||
Label: self.c.Tr.Fixup,
|
||||
Key: 'f',
|
||||
Key: gocui.NewKeyRune('f'),
|
||||
OnPress: func() error {
|
||||
return self.c.WithWaitingStatus(self.c.Tr.FixingStatus, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.FixupCommit)
|
||||
|
|
@ -373,7 +372,7 @@ func (self *LocalCommitsController) fixup(selectedCommits []*models.Commit, star
|
|||
},
|
||||
{
|
||||
Label: self.c.Tr.FixupKeepMessage,
|
||||
Key: 'c',
|
||||
Key: gocui.NewKeyRune('c'),
|
||||
OnPress: func() error {
|
||||
return self.c.WithWaitingStatus(self.c.Tr.FixingStatus, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.FixupCommitKeepMessage)
|
||||
|
|
@ -404,7 +403,7 @@ func (self *LocalCommitsController) setFixupMessage(commit *models.Commit) error
|
|||
Items: []*types.MenuItem{
|
||||
{
|
||||
Label: self.c.Tr.FixupDiscardMessage,
|
||||
Key: 'f',
|
||||
Key: gocui.NewKeyRune('f'),
|
||||
OnPress: func() error {
|
||||
return self.updateTodosWithFlag(todo.Fixup, []*models.Commit{commit}, "")
|
||||
},
|
||||
|
|
@ -412,7 +411,7 @@ func (self *LocalCommitsController) setFixupMessage(commit *models.Commit) error
|
|||
},
|
||||
{
|
||||
Label: self.c.Tr.FixupKeepMessage,
|
||||
Key: 'c',
|
||||
Key: gocui.NewKeyRune('c'),
|
||||
OnPress: func() error {
|
||||
return self.updateTodosWithFlag(todo.Fixup, []*models.Commit{commit}, "-C")
|
||||
},
|
||||
|
|
@ -680,7 +679,7 @@ func (self *LocalCommitsController) findCommitForQuickStartInteractiveRebase() (
|
|||
|
||||
if !ok || index == 0 {
|
||||
errorMsg := utils.ResolvePlaceholderString(self.c.Tr.CannotQuickStartInteractiveRebase, map[string]string{
|
||||
"editKey": keybindings.Label(self.c.UserConfig().Keybinding.Universal.Edit),
|
||||
"editKey": self.c.UserConfig().Keybinding.Universal.Edit,
|
||||
})
|
||||
|
||||
return nil, errors.New(errorMsg)
|
||||
|
|
@ -1001,7 +1000,7 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err
|
|||
Items: []*types.MenuItem{
|
||||
{
|
||||
Label: self.c.Tr.FixupMenu_Fixup,
|
||||
Key: 'f',
|
||||
Key: gocui.NewKeyRune('f'),
|
||||
OnPress: func() error {
|
||||
return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error {
|
||||
self.c.LogAction(self.c.Tr.Actions.CreateFixupCommit)
|
||||
|
|
@ -1025,7 +1024,7 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err
|
|||
},
|
||||
{
|
||||
Label: self.c.Tr.FixupMenu_AmendWithChanges,
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
OnPress: func() error {
|
||||
return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error {
|
||||
return self.createAmendCommit(commit, true)
|
||||
|
|
@ -1036,7 +1035,7 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err
|
|||
},
|
||||
{
|
||||
Label: self.c.Tr.FixupMenu_AmendWithoutChanges,
|
||||
Key: 'r',
|
||||
Key: gocui.NewKeyRune('r'),
|
||||
OnPress: func() error { return self.createAmendCommit(commit, false) },
|
||||
Tooltip: self.c.Tr.FixupMenu_AmendWithoutChangesTooltip,
|
||||
},
|
||||
|
|
@ -1135,14 +1134,14 @@ func (self *LocalCommitsController) squashFixupCommits() error {
|
|||
Label: self.c.Tr.SquashCommitsInCurrentBranch,
|
||||
OnPress: self.squashAllFixupsInCurrentBranch,
|
||||
DisabledReason: self.canFindCommitForSquashFixupsInCurrentBranch(),
|
||||
Key: 'b',
|
||||
Key: gocui.NewKeyRune('b'),
|
||||
Tooltip: self.c.Tr.SquashCommitsInCurrentBranchTooltip,
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.SquashCommitsAboveSelectedCommit,
|
||||
OnPress: self.withItem(self.squashAllFixupsAboveSelectedCommit),
|
||||
DisabledReason: self.singleItemSelected()(),
|
||||
Key: 'a',
|
||||
Key: gocui.NewKeyRune('a'),
|
||||
Tooltip: self.c.Tr.SquashCommitsAboveSelectedTooltip,
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
|
@ -188,7 +187,7 @@ func (self *PatchBuildingController) getDisabledReasonForDiscard() *types.Disabl
|
|||
}
|
||||
if self.c.UserConfig().Git.DiffContextSize == 0 {
|
||||
text := fmt.Sprintf(self.c.Tr.Actions.NotEnoughContextToRemoveLines,
|
||||
keybindings.Label(self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView))
|
||||
self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView)
|
||||
return &types.DisabledReason{Text: text, ShowErrorInPanel: true}
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ func NewPromptController(
|
|||
func (self *PromptController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: gocui.KeyEnter,
|
||||
Key: gocui.NewKeyName(gocui.KeyEnter),
|
||||
Handler: func() error { return self.context().State.OnConfirm() },
|
||||
Description: self.c.Tr.Confirm,
|
||||
DisplayOnScreen: true,
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ func NewSearchPromptController(
|
|||
func (self *SearchPromptController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
return []*types.Binding{
|
||||
{
|
||||
Key: gocui.KeyEnter,
|
||||
Key: gocui.NewKeyName(gocui.KeyEnter),
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: self.confirm,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/patch"
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
)
|
||||
|
||||
|
|
@ -205,7 +204,7 @@ func (self *StagingController) TogglePanel() error {
|
|||
func (self *StagingController) ToggleStaged() error {
|
||||
if self.c.UserConfig().Git.DiffContextSize == 0 {
|
||||
return fmt.Errorf(self.c.Tr.Actions.NotEnoughContextToStage,
|
||||
keybindings.Label(self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView))
|
||||
self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView)
|
||||
}
|
||||
|
||||
return self.applySelectionAndRefresh(self.staged)
|
||||
|
|
@ -214,7 +213,7 @@ func (self *StagingController) ToggleStaged() error {
|
|||
func (self *StagingController) DiscardSelection() error {
|
||||
if self.c.UserConfig().Git.DiffContextSize == 0 {
|
||||
return fmt.Errorf(self.c.Tr.Actions.NotEnoughContextToDiscard,
|
||||
keybindings.Label(self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView))
|
||||
self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView)
|
||||
}
|
||||
|
||||
return self.c.ConfirmIf(!self.staged && !self.c.UserConfig().Gui.SkipDiscardChangeWarning,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import (
|
|||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
|
|
@ -45,7 +44,7 @@ func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []*
|
|||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Enter,
|
||||
Tooltip: utils.ResolvePlaceholderString(self.c.Tr.EnterSubmoduleTooltip,
|
||||
map[string]string{"escape": keybindings.Label(opts.Config.Universal.Return)}),
|
||||
map[string]string{"escape": opts.Config.Universal.Return}),
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
|
|
@ -95,7 +94,6 @@ func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []*
|
|||
OpensMenu: true,
|
||||
},
|
||||
{
|
||||
Key: nil,
|
||||
Handler: self.easterEgg,
|
||||
Description: self.c.Tr.EasterEgg,
|
||||
},
|
||||
|
|
@ -235,7 +233,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error {
|
|||
return nil
|
||||
})
|
||||
},
|
||||
Key: 'i',
|
||||
Key: gocui.NewKeyRune('i'),
|
||||
},
|
||||
{
|
||||
LabelColumns: []string{self.c.Tr.BulkUpdateSubmodules, style.FgYellow.Sprint(self.c.Git().Submodule.BulkUpdateCmdObj().ToString())},
|
||||
|
|
@ -250,7 +248,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error {
|
|||
return nil
|
||||
})
|
||||
},
|
||||
Key: 'u',
|
||||
Key: gocui.NewKeyRune('u'),
|
||||
},
|
||||
{
|
||||
LabelColumns: []string{self.c.Tr.BulkUpdateRecursiveSubmodules, style.FgYellow.Sprint(self.c.Git().Submodule.BulkUpdateRecursivelyCmdObj().ToString())},
|
||||
|
|
@ -265,7 +263,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error {
|
|||
return nil
|
||||
})
|
||||
},
|
||||
Key: 'r',
|
||||
Key: gocui.NewKeyRune('r'),
|
||||
},
|
||||
{
|
||||
LabelColumns: []string{self.c.Tr.BulkDeinitSubmodules, style.FgRed.Sprint(self.c.Git().Submodule.BulkDeinitCmdObj().ToString())},
|
||||
|
|
@ -280,7 +278,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error {
|
|||
return nil
|
||||
})
|
||||
},
|
||||
Key: 'd',
|
||||
Key: gocui.NewKeyRune('d'),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -282,14 +282,14 @@ func (self *TagsController) delete(tag *models.Tag) error {
|
|||
menuItems := []*types.MenuItem{
|
||||
{
|
||||
Label: self.c.Tr.DeleteLocalTag,
|
||||
Key: 'c',
|
||||
Key: gocui.NewKeyRune('c'),
|
||||
OnPress: func() error {
|
||||
return self.localDelete(tag)
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.DeleteRemoteTag,
|
||||
Key: 'r',
|
||||
Key: gocui.NewKeyRune('r'),
|
||||
OpensMenu: true,
|
||||
OnPress: func() error {
|
||||
return self.remoteDelete(tag)
|
||||
|
|
@ -297,7 +297,7 @@ func (self *TagsController) delete(tag *models.Tag) error {
|
|||
},
|
||||
{
|
||||
Label: self.c.Tr.DeleteLocalAndRemoteTag,
|
||||
Key: 'b',
|
||||
Key: gocui.NewKeyRune('b'),
|
||||
OpensMenu: true,
|
||||
OnPress: func() error {
|
||||
return self.localAndRemoteDelete(tag)
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ func (self *FilesController) createResetMenu() error {
|
|||
})
|
||||
return nil
|
||||
},
|
||||
Key: 'x',
|
||||
Key: gocui.NewKeyRune('x'),
|
||||
Tooltip: self.c.Tr.NukeDescription,
|
||||
},
|
||||
{
|
||||
|
|
@ -72,7 +72,7 @@ func (self *FilesController) createResetMenu() error {
|
|||
)
|
||||
return nil
|
||||
},
|
||||
Key: 'u',
|
||||
Key: gocui.NewKeyRune('u'),
|
||||
},
|
||||
{
|
||||
LabelColumns: []string{
|
||||
|
|
@ -90,7 +90,7 @@ func (self *FilesController) createResetMenu() error {
|
|||
)
|
||||
return nil
|
||||
},
|
||||
Key: 'c',
|
||||
Key: gocui.NewKeyRune('c'),
|
||||
},
|
||||
{
|
||||
LabelColumns: []string{
|
||||
|
|
@ -115,7 +115,7 @@ func (self *FilesController) createResetMenu() error {
|
|||
)
|
||||
return nil
|
||||
},
|
||||
Key: 'S',
|
||||
Key: gocui.NewKeyRune('S'),
|
||||
},
|
||||
{
|
||||
LabelColumns: []string{
|
||||
|
|
@ -133,7 +133,7 @@ func (self *FilesController) createResetMenu() error {
|
|||
)
|
||||
return nil
|
||||
},
|
||||
Key: 's',
|
||||
Key: gocui.NewKeyRune('s'),
|
||||
},
|
||||
{
|
||||
LabelColumns: []string{
|
||||
|
|
@ -151,7 +151,7 @@ func (self *FilesController) createResetMenu() error {
|
|||
)
|
||||
return nil
|
||||
},
|
||||
Key: 'm',
|
||||
Key: gocui.NewKeyRune('m'),
|
||||
},
|
||||
{
|
||||
LabelColumns: []string{
|
||||
|
|
@ -176,7 +176,7 @@ func (self *FilesController) createResetMenu() error {
|
|||
},
|
||||
})
|
||||
},
|
||||
Key: 'h',
|
||||
Key: gocui.NewKeyRune('h'),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,33 +4,33 @@ import (
|
|||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
)
|
||||
|
||||
func (gui *Gui) handleEditorKeypress(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier, allowMultiline bool) bool {
|
||||
if key == gocui.KeyEnter && allowMultiline {
|
||||
func (gui *Gui) handleEditorKeypress(v *gocui.View, key gocui.Key, mod gocui.Modifier, allowMultiline bool) bool {
|
||||
if key.KeyName() == gocui.KeyEnter && allowMultiline {
|
||||
v.TextArea.TypeCharacter("\n")
|
||||
v.RenderTextArea()
|
||||
return true
|
||||
}
|
||||
|
||||
return gocui.DefaultEditor.Edit(v, key, ch, mod)
|
||||
return gocui.DefaultEditor.Edit(v, key, mod)
|
||||
}
|
||||
|
||||
// we've just copy+pasted the editor from gocui to here so that we can also re-
|
||||
// render the commit message length on each keypress
|
||||
func (gui *Gui) commitMessageEditor(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool {
|
||||
matched := gui.handleEditorKeypress(v, key, ch, mod, false)
|
||||
func (gui *Gui) commitMessageEditor(v *gocui.View, key gocui.Key, mod gocui.Modifier) bool {
|
||||
matched := gui.handleEditorKeypress(v, key, mod, false)
|
||||
v.RenderTextArea()
|
||||
gui.c.Contexts().CommitMessage.RenderSubtitle()
|
||||
return matched
|
||||
}
|
||||
|
||||
func (gui *Gui) commitDescriptionEditor(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool {
|
||||
matched := gui.handleEditorKeypress(v, key, ch, mod, true)
|
||||
func (gui *Gui) commitDescriptionEditor(v *gocui.View, key gocui.Key, mod gocui.Modifier) bool {
|
||||
matched := gui.handleEditorKeypress(v, key, mod, true)
|
||||
v.RenderTextArea()
|
||||
return matched
|
||||
}
|
||||
|
||||
func (gui *Gui) promptEditor(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool {
|
||||
matched := gui.handleEditorKeypress(v, key, ch, mod, false)
|
||||
func (gui *Gui) promptEditor(v *gocui.View, key gocui.Key, mod gocui.Modifier) bool {
|
||||
matched := gui.handleEditorKeypress(v, key, mod, false)
|
||||
|
||||
v.RenderTextArea()
|
||||
|
||||
|
|
@ -46,8 +46,8 @@ func (gui *Gui) promptEditor(v *gocui.View, key gocui.Key, ch rune, mod gocui.Mo
|
|||
return matched
|
||||
}
|
||||
|
||||
func (gui *Gui) searchEditor(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool {
|
||||
matched := gui.handleEditorKeypress(v, key, ch, mod, false)
|
||||
func (gui *Gui) searchEditor(v *gocui.View, key gocui.Key, mod gocui.Modifier) bool {
|
||||
matched := gui.handleEditorKeypress(v, key, mod, false)
|
||||
v.RenderTextArea()
|
||||
|
||||
searchString := v.TextArea.GetContent()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package gui
|
|||
import (
|
||||
"io"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
|
|
@ -14,7 +15,7 @@ func (gui *Gui) handleCreateExtrasMenuPanel() error {
|
|||
Items: []*types.MenuItem{
|
||||
{
|
||||
Label: gui.c.Tr.ToggleShowCommandLog,
|
||||
Key: 't',
|
||||
Key: gocui.NewKeyRune('t'),
|
||||
OnPress: func() error {
|
||||
currentContext := gui.c.Context().CurrentStatic()
|
||||
if gui.c.State().GetShowExtrasWindow() && currentContext.GetKey() == context.COMMAND_LOG_CONTEXT_KEY {
|
||||
|
|
@ -29,7 +30,7 @@ func (gui *Gui) handleCreateExtrasMenuPanel() error {
|
|||
},
|
||||
{
|
||||
Label: gui.c.Tr.FocusCommandLog,
|
||||
Key: 'f',
|
||||
Key: gocui.NewKeyRune('f'),
|
||||
OnPress: gui.handleFocusCommandLog,
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -882,7 +882,7 @@ func (gui *Gui) Run(startArgs appTypes.StartArgs) error {
|
|||
|
||||
g.ErrorHandler = gui.PopupHandler.ErrorHandler
|
||||
|
||||
gui.g.ShouldHandleMouseEvent = func(view *gocui.View, key gocui.Key) bool {
|
||||
gui.g.ShouldHandleMouseEvent = func(view *gocui.View, key gocui.KeyName) bool {
|
||||
if gui.helpers.Confirmation.IsPopupPanelFocused() && gui.currentViewName() != view.Name() &&
|
||||
!gocui.IsMouseScrollKey(key) {
|
||||
// we ignore click events on views that aren't popup panels, when a popup panel is focused.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/gdamore/tcell/v3"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
|
|
@ -31,18 +31,8 @@ func (self *GuiDriver) PressKey(keyStr string) {
|
|||
|
||||
key := keybindings.GetKey(keyStr)
|
||||
|
||||
var r rune
|
||||
var tcellKey tcell.Key
|
||||
switch v := key.(type) {
|
||||
case rune:
|
||||
r = v
|
||||
tcellKey = tcell.KeyRune
|
||||
case gocui.Key:
|
||||
tcellKey = tcell.Key(v)
|
||||
}
|
||||
|
||||
self.gui.g.ReplayedEvents.Keys <- gocui.NewTcellKeyEventWrapper(
|
||||
tcell.NewEventKey(tcellKey, r, tcell.ModNone),
|
||||
tcell.NewEventKey(tcell.Key(key.KeyName()), key.Str(), tcell.ModNone),
|
||||
0,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin
|
|||
},
|
||||
{
|
||||
ViewName: "information",
|
||||
Key: gocui.MouseLeft,
|
||||
Key: gocui.NewKeyName(gocui.MouseLeft),
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleInfoClick,
|
||||
},
|
||||
|
|
@ -201,27 +201,27 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin
|
|||
},
|
||||
{
|
||||
ViewName: "main",
|
||||
Key: gocui.MouseWheelDown,
|
||||
Key: gocui.NewKeyName(gocui.MouseWheelDown),
|
||||
Handler: gui.scrollDownMain,
|
||||
Description: gui.c.Tr.ScrollDown,
|
||||
Alternative: "fn+up",
|
||||
},
|
||||
{
|
||||
ViewName: "main",
|
||||
Key: gocui.MouseWheelUp,
|
||||
Key: gocui.NewKeyName(gocui.MouseWheelUp),
|
||||
Handler: gui.scrollUpMain,
|
||||
Description: gui.c.Tr.ScrollUp,
|
||||
Alternative: "fn+down",
|
||||
},
|
||||
{
|
||||
ViewName: "secondary",
|
||||
Key: gocui.MouseWheelDown,
|
||||
Key: gocui.NewKeyName(gocui.MouseWheelDown),
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.scrollDownSecondary,
|
||||
},
|
||||
{
|
||||
ViewName: "secondary",
|
||||
Key: gocui.MouseWheelUp,
|
||||
Key: gocui.NewKeyName(gocui.MouseWheelUp),
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.scrollUpSecondary,
|
||||
},
|
||||
|
|
@ -251,12 +251,12 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin
|
|||
},
|
||||
{
|
||||
ViewName: "confirmation",
|
||||
Key: gocui.MouseWheelUp,
|
||||
Key: gocui.NewKeyName(gocui.MouseWheelUp),
|
||||
Handler: gui.scrollUpConfirmationPanel,
|
||||
},
|
||||
{
|
||||
ViewName: "confirmation",
|
||||
Key: gocui.MouseWheelDown,
|
||||
Key: gocui.NewKeyName(gocui.MouseWheelDown),
|
||||
Handler: gui.scrollDownConfirmationPanel,
|
||||
},
|
||||
{
|
||||
|
|
@ -304,12 +304,12 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin
|
|||
},
|
||||
{
|
||||
ViewName: "extras",
|
||||
Key: gocui.MouseWheelUp,
|
||||
Key: gocui.NewKeyName(gocui.MouseWheelUp),
|
||||
Handler: gui.scrollUpExtra,
|
||||
},
|
||||
{
|
||||
ViewName: "extras",
|
||||
Key: gocui.MouseWheelDown,
|
||||
Key: gocui.NewKeyName(gocui.MouseWheelDown),
|
||||
Handler: gui.scrollDownExtra,
|
||||
},
|
||||
{
|
||||
|
|
@ -379,7 +379,7 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin
|
|||
{
|
||||
ViewName: "extras",
|
||||
Tag: "navigation",
|
||||
Key: gocui.MouseLeft,
|
||||
Key: gocui.NewKeyName(gocui.MouseLeft),
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleFocusCommandLog,
|
||||
},
|
||||
|
|
@ -473,30 +473,12 @@ func (gui *Gui) resetKeybindings() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) wrappedHandler(f func() error) func(g *gocui.Gui, v *gocui.View) error {
|
||||
return func(g *gocui.Gui, v *gocui.View) error {
|
||||
return f()
|
||||
}
|
||||
}
|
||||
|
||||
func (gui *Gui) SetKeybinding(binding *types.Binding) error {
|
||||
handler := func() error {
|
||||
handler := func(g *gocui.Gui, v *gocui.View) error {
|
||||
return gui.callKeybindingHandler(binding)
|
||||
}
|
||||
|
||||
// TODO: move all mouse-ey stuff into new mouse approach
|
||||
if gocui.IsMouseKey(binding.Key) {
|
||||
handler = func() error {
|
||||
// we ignore click events on views that aren't popup panels, when a popup panel is focused
|
||||
if gui.helpers.Confirmation.IsPopupPanelFocused() && gui.currentViewName() != binding.ViewName {
|
||||
return nil
|
||||
}
|
||||
|
||||
return binding.Handler()
|
||||
}
|
||||
}
|
||||
|
||||
return gui.g.SetKeybinding(binding.ViewName, binding.Key, binding.Modifier, gui.wrappedHandler(handler))
|
||||
return gui.g.SetKeybinding(binding.ViewName, binding.Key, binding.Modifier, handler)
|
||||
}
|
||||
|
||||
func (gui *Gui) SetMouseKeybinding(binding *gocui.ViewMouseBinding) error {
|
||||
|
|
|
|||
|
|
@ -1,54 +1,50 @@
|
|||
package keybindings
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/gdamore/tcell/v3"
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/constants"
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
)
|
||||
|
||||
func Label(name string) string {
|
||||
return LabelFromKey(GetKey(name))
|
||||
}
|
||||
|
||||
func LabelFromKey(key types.Key) string {
|
||||
if key == nil {
|
||||
func LabelFromKey(key gocui.Key) string {
|
||||
if !key.IsSet() {
|
||||
return ""
|
||||
}
|
||||
|
||||
keyInt := 0
|
||||
|
||||
switch key := key.(type) {
|
||||
case rune:
|
||||
keyInt = int(key)
|
||||
case gocui.Key:
|
||||
value, ok := config.LabelByKey[key]
|
||||
if ok {
|
||||
return value
|
||||
}
|
||||
keyInt = int(key)
|
||||
if key.KeyName() == gocui.KeyName(tcell.KeyRune) {
|
||||
return key.Str()
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%c", keyInt)
|
||||
value, ok := config.LabelByKey[key.KeyName()]
|
||||
if ok {
|
||||
return value
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
func GetKey(key string) types.Key {
|
||||
runeCount := utf8.RuneCountInString(key)
|
||||
func GetKey(key string) gocui.Key {
|
||||
if key == "<disabled>" {
|
||||
return nil
|
||||
} else if runeCount > 1 {
|
||||
binding, ok := config.KeyByLabel[strings.ToLower(key)]
|
||||
return gocui.Key{}
|
||||
}
|
||||
|
||||
runeCount := utf8.RuneCountInString(key)
|
||||
if runeCount > 1 {
|
||||
keyName, ok := config.KeyByLabel[strings.ToLower(key)]
|
||||
if !ok {
|
||||
log.Fatalf("Unrecognized key %s for keybinding. For permitted values see %s", strings.ToLower(key), constants.Links.Docs.CustomKeybindings)
|
||||
}
|
||||
return binding
|
||||
} else if runeCount == 1 {
|
||||
return []rune(key)[0]
|
||||
return gocui.NewKeyName(keyName)
|
||||
}
|
||||
return nil
|
||||
|
||||
if runeCount == 1 {
|
||||
return gocui.NewKeyRune([]rune(key)[0])
|
||||
}
|
||||
|
||||
return gocui.Key{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package gui
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
|
|
@ -26,7 +27,7 @@ func (gui *Gui) createMenu(opts types.CreateMenuOptions) error {
|
|||
|
||||
maxColumnSize := 1
|
||||
|
||||
essentialKeys := []types.Key{
|
||||
essentialKeys := []gocui.Key{
|
||||
keybindings.GetKey(gui.c.UserConfig().Keybinding.Universal.ConfirmMenu),
|
||||
keybindings.GetKey(gui.c.UserConfig().Keybinding.Universal.Return),
|
||||
keybindings.GetKey(gui.c.UserConfig().Keybinding.Universal.PrevItem),
|
||||
|
|
@ -46,7 +47,7 @@ func (gui *Gui) createMenu(opts types.CreateMenuOptions) error {
|
|||
|
||||
// Remove all item keybindings that are the same as one of the essential bindings
|
||||
if !opts.KeepConflictingKeybindings && lo.Contains(essentialKeys, item.Key) {
|
||||
item.Key = nil
|
||||
item.Key = gocui.Key{}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/jesseduffield/generics/set"
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||
|
|
@ -40,7 +41,7 @@ func (self *OptionsMapMgr) renderContextOptionsMap() {
|
|||
globalBindings := self.c.Contexts().Global.GetKeybindings(self.c.KeybindingsOpts())
|
||||
|
||||
currentContextKeys := set.NewFromSlice(
|
||||
lo.Map(currentContextBindings, func(binding *types.Binding, _ int) types.Key {
|
||||
lo.Map(currentContextBindings, func(binding *types.Binding, _ int) gocui.Key {
|
||||
return binding.Key
|
||||
}))
|
||||
|
||||
|
|
@ -69,7 +70,7 @@ func (self *OptionsMapMgr) renderContextOptionsMap() {
|
|||
if currentContext.GetKey() == context.LOCAL_COMMITS_CONTEXT_KEY {
|
||||
if self.c.Modes().CherryPicking.Active() {
|
||||
optionsMap = utils.Prepend(optionsMap, bindingInfo{
|
||||
key: keybindings.Label(self.c.KeybindingsOpts().Config.Commits.PasteCommits),
|
||||
key: self.c.KeybindingsOpts().Config.Commits.PasteCommits,
|
||||
description: self.c.Tr.PasteCommits,
|
||||
style: style.FgCyan,
|
||||
})
|
||||
|
|
@ -77,7 +78,7 @@ func (self *OptionsMapMgr) renderContextOptionsMap() {
|
|||
|
||||
if self.c.Model().BisectInfo.Started() {
|
||||
optionsMap = utils.Prepend(optionsMap, bindingInfo{
|
||||
key: keybindings.Label(self.c.KeybindingsOpts().Config.Commits.ViewBisectOptions),
|
||||
key: self.c.KeybindingsOpts().Config.Commits.ViewBisectOptions,
|
||||
description: self.c.Tr.ViewBisectOptions,
|
||||
style: style.FgGreen,
|
||||
})
|
||||
|
|
@ -87,7 +88,7 @@ func (self *OptionsMapMgr) renderContextOptionsMap() {
|
|||
// Mode-specific global keybindings
|
||||
if state := self.c.Model().WorkingTreeStateAtLastCommitRefresh; state.Any() {
|
||||
optionsMap = utils.Prepend(optionsMap, bindingInfo{
|
||||
key: keybindings.Label(self.c.KeybindingsOpts().Config.Universal.CreateRebaseOptionsMenu),
|
||||
key: self.c.KeybindingsOpts().Config.Universal.CreateRebaseOptionsMenu,
|
||||
description: state.OptionsMapTitle(self.c.Tr),
|
||||
style: style.FgYellow,
|
||||
})
|
||||
|
|
@ -95,7 +96,7 @@ func (self *OptionsMapMgr) renderContextOptionsMap() {
|
|||
|
||||
if self.c.Git().Patch.PatchBuilder.Active() {
|
||||
optionsMap = utils.Prepend(optionsMap, bindingInfo{
|
||||
key: keybindings.Label(self.c.KeybindingsOpts().Config.Universal.CreatePatchOptionsMenu),
|
||||
key: self.c.KeybindingsOpts().Config.Universal.CreatePatchOptionsMenu,
|
||||
description: self.c.Tr.ViewPatchOptions,
|
||||
style: style.FgYellow,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ type MenuItem struct {
|
|||
|
||||
// If Key is defined it allows the user to press the key to invoke the menu
|
||||
// item, as opposed to having to navigate to it
|
||||
Key Key
|
||||
Key gocui.Key
|
||||
|
||||
// A widget to show in front of the menu item. Supported widget types are
|
||||
// checkboxes and radio buttons,
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ type OnFocusLostOpts struct {
|
|||
type ContextKey string
|
||||
|
||||
type KeybindingsOpts struct {
|
||||
GetKey func(key string) Key
|
||||
GetKey func(key string) gocui.Key
|
||||
Config config.KeybindingConfig
|
||||
Guards KeybindingGuards
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,13 @@ import (
|
|||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
)
|
||||
|
||||
type Key any // FIXME: find out how to get `gocui.Key | rune`
|
||||
|
||||
// Binding - a keybinding mapping a key and modifier to a handler. The keypress
|
||||
// is only handled if the given view has focus, or handled globally if the view
|
||||
// is ""
|
||||
type Binding struct {
|
||||
ViewName string
|
||||
Handler func() error
|
||||
Key Key
|
||||
Key gocui.Key
|
||||
Modifier gocui.Modifier
|
||||
Description string
|
||||
// DescriptionFunc is used instead of Description if non-nil, and is useful for dynamic
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ func RunTUI(raceDetector bool) {
|
|||
|
||||
g.SetManagerFunc(app.layout)
|
||||
|
||||
if err := g.SetKeybinding("list", gocui.KeyArrowUp, gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
if err := g.SetKeybinding("list", gocui.NewKeyName(gocui.KeyArrowUp), gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
if app.itemIdx > 0 {
|
||||
app.itemIdx--
|
||||
}
|
||||
|
|
@ -57,7 +57,7 @@ func RunTUI(raceDetector bool) {
|
|||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", gocui.KeyArrowDown, gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
if err := g.SetKeybinding("list", gocui.NewKeyName(gocui.KeyArrowDown), gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
if app.itemIdx < len(app.filteredTests)-1 {
|
||||
app.itemIdx++
|
||||
}
|
||||
|
|
@ -72,15 +72,15 @@ func RunTUI(raceDetector bool) {
|
|||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
|
||||
if err := g.SetKeybinding("list", gocui.NewKeyName(gocui.KeyCtrlC), gocui.ModNone, quit); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", 'q', gocui.ModNone, quit); err != nil {
|
||||
if err := g.SetKeybinding("list", gocui.NewKeyRune('q'), gocui.ModNone, quit); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", 's', gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
if err := g.SetKeybinding("list", gocui.NewKeyRune('s'), gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
|
|
@ -93,7 +93,7 @@ func RunTUI(raceDetector bool) {
|
|||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", gocui.KeyEnter, gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
if err := g.SetKeybinding("list", gocui.NewKeyName(gocui.KeyEnter), gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
|
|
@ -106,7 +106,7 @@ func RunTUI(raceDetector bool) {
|
|||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", 't', gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
if err := g.SetKeybinding("list", gocui.NewKeyRune('t'), gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
|
|
@ -119,7 +119,7 @@ func RunTUI(raceDetector bool) {
|
|||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", 'd', gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
if err := g.SetKeybinding("list", gocui.NewKeyRune('d'), gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
|
|
@ -132,7 +132,7 @@ func RunTUI(raceDetector bool) {
|
|||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", 'o', gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
if err := g.SetKeybinding("list", gocui.NewKeyRune('o'), gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
|
|
@ -148,7 +148,7 @@ func RunTUI(raceDetector bool) {
|
|||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", 'O', gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
if err := g.SetKeybinding("list", gocui.NewKeyRune('O'), gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
|
|
@ -164,7 +164,7 @@ func RunTUI(raceDetector bool) {
|
|||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", '/', gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
if err := g.SetKeybinding("list", gocui.NewKeyRune('/'), gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
app.filtering = true
|
||||
if _, err := g.SetCurrentView("editor"); err != nil {
|
||||
return err
|
||||
|
|
@ -181,7 +181,7 @@ func RunTUI(raceDetector bool) {
|
|||
}
|
||||
|
||||
// not using the editor yet, but will use it to help filter the list
|
||||
if err := g.SetKeybinding("editor", gocui.KeyEsc, gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
if err := g.SetKeybinding("editor", gocui.NewKeyName(gocui.KeyEsc), gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
app.filtering = false
|
||||
if _, err := g.SetCurrentView("list"); err != nil {
|
||||
return err
|
||||
|
|
@ -198,7 +198,7 @@ func RunTUI(raceDetector bool) {
|
|||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("editor", gocui.KeyEnter, gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
if err := g.SetKeybinding("editor", gocui.NewKeyName(gocui.KeyEnter), gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
app.filtering = false
|
||||
|
||||
if _, err := g.SetCurrentView("list"); err != nil {
|
||||
|
|
@ -273,9 +273,9 @@ func (self *app) renderTests() {
|
|||
}
|
||||
}
|
||||
|
||||
func (self *app) wrapEditor(f func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool) func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool {
|
||||
return func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool {
|
||||
matched := f(v, key, ch, mod)
|
||||
func (self *app) wrapEditor(f func(v *gocui.View, key gocui.Key, mod gocui.Modifier) bool) func(v *gocui.View, key gocui.Key, mod gocui.Modifier) bool {
|
||||
return func(v *gocui.View, key gocui.Key, mod gocui.Modifier) bool {
|
||||
matched := f(v, key, mod)
|
||||
if matched {
|
||||
self.filterWithString(v.TextArea.GetContent())
|
||||
}
|
||||
|
|
|
|||
3
vendor/github.com/clipperhouse/displaywidth/.gitignore
generated
vendored
Normal file
3
vendor/github.com/clipperhouse/displaywidth/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
.DS_Store
|
||||
*.out
|
||||
*.test
|
||||
51
vendor/github.com/clipperhouse/displaywidth/AGENTS.md
generated
vendored
Normal file
51
vendor/github.com/clipperhouse/displaywidth/AGENTS.md
generated
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
The goals and overview of this package can be found in the README.md file,
|
||||
start by reading that.
|
||||
|
||||
The goal of this package is to determine the display (column) width of a
|
||||
string, UTF-8 bytes, or runes, as would happen in a monospace font, especially
|
||||
in a terminal.
|
||||
|
||||
When troubleshooting, write Go unit tests instead of executing debug scripts.
|
||||
The tests can return whatever logs or output you need. If those tests are
|
||||
only for temporary troubleshooting, clean up the tests after the debugging is
|
||||
done.
|
||||
|
||||
(Separate executable debugging scripts are messy, tend to have conflicting
|
||||
dependencies and are hard to cleanup.)
|
||||
|
||||
If you make changes to the trie generation in internal/gen, it can be invoked
|
||||
by running `go generate` from the top package directory.
|
||||
|
||||
## Pull Requests and branches
|
||||
|
||||
For PRs (pull requests), you can use the gh CLI tool. Compare the current branch with main. Reviewing a PR and reviewing a branch are about the same, but the PR may add context.
|
||||
|
||||
Understand the goals of the PR. Note any API changes, especially breaking changes.
|
||||
|
||||
Look for thoroughness of tests, as well as GoDoc comments.
|
||||
|
||||
Retrieve and consider the comments on the PR, which may have come from GitHub Copilot or Cursor BugBot. Think like GitHub Copilot or Cursor BugBot.
|
||||
|
||||
Offer to optionally post a brief summary of the review to the PR, via the gh CLI tool.
|
||||
|
||||
## Tagged Go releases
|
||||
|
||||
If I ask you whether we are ready to release, this means a tagged Go release on the main branch. Go releases are git tagged with a version number.
|
||||
|
||||
Review the changes since the last release, i.e. the previous git tag. Ensure that the changes are complete and correct. Identify new features, bug fixes, and performance improvements.
|
||||
|
||||
Identify breaking changes, especially API changes.
|
||||
|
||||
Ensure good test coverage. Look for performance changes, especially performance regressions, by running benchmarks against the previous release.
|
||||
|
||||
Ensure that the documentation in READMEs and GoDocs are complete, correct and consistent.
|
||||
|
||||
## Comparisons to go-runewidth
|
||||
|
||||
We originally attempted to make this package compatible with go-runewidth.
|
||||
However, we found that there were too many differences in the handling of
|
||||
certain characters and properties.
|
||||
|
||||
We believe, preliminarily, that our choices are more correct and complete,
|
||||
by using more complete categories such as Unicode Cf (format) for zero-width
|
||||
and Mn (Nonspacing_Mark) for combining marks.
|
||||
129
vendor/github.com/clipperhouse/displaywidth/CHANGELOG.md
generated
vendored
Normal file
129
vendor/github.com/clipperhouse/displaywidth/CHANGELOG.md
generated
vendored
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
# Changelog
|
||||
|
||||
## [0.11.0]
|
||||
|
||||
[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.10.0...v0.11.0)
|
||||
|
||||
### Added
|
||||
- New `ControlSequences8Bit` option to treat 8-bit ECMA-48 (C1) escape sequences as zero-width. (#22)
|
||||
|
||||
### Changed
|
||||
- Upgraded uax29 dependency to v2.7.0 for 8-bit escape sequence support in the grapheme iterator.
|
||||
- Truncation now validates that preserved trailing escape sequences are zero-width, preventing edge cases where non-zero-width sequences could leak into output.
|
||||
|
||||
### Note
|
||||
- `ControlSequences8Bit` is deliberately ignored by `TruncateString` and `TruncateBytes`, because C1 byte values (0x80–0x9F) overlap with UTF-8 multi-byte encoding.
|
||||
|
||||
## [0.10.0]
|
||||
|
||||
[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.9.0...v0.10.0)
|
||||
|
||||
### Added
|
||||
- New `ControlSequences` option to treat ECMA-48/ANSI escape sequences as zero-width. (#20)
|
||||
- `TruncateString` and `TruncateBytes` now preserve trailing ANSI escape sequences (such as SGR resets) when `ControlSequences` is true, preventing color bleed in terminal output.
|
||||
|
||||
### Changed
|
||||
- Removed `stringish` dependency; generic type constraints are now inline `~string | []byte`.
|
||||
- Upgraded uax29 dependency to v2.6.0 for ANSI escape sequence support in the grapheme iterator.
|
||||
|
||||
## [0.9.0]
|
||||
|
||||
[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.8.0...v0.9.0)
|
||||
|
||||
### Changed
|
||||
- Unicode 17 support: East Asian Width and emoji data updated to Unicode 17.0.0. (#18)
|
||||
- Upgraded uax29 dependency to v2.5.0 (Unicode 17 grapheme segmentation).
|
||||
|
||||
## [0.8.0]
|
||||
|
||||
[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.7.0...v0.8.0)
|
||||
|
||||
### Changed
|
||||
- Performance: ASCII fast path that applies to any run of printable
|
||||
ASCII. 2x-10x faster for ASCII text vs v0.7.0. (#16)
|
||||
- Upgraded uax29 dependency to v2.4.0 for Unicode 16 support. Text that includes
|
||||
Indic_Conjunct_Break may segment differently (and more correctly). (#15)
|
||||
|
||||
## [0.7.0]
|
||||
|
||||
[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.6.2...v0.7.0)
|
||||
|
||||
### Added
|
||||
- New `TruncateString` and `TruncateBytes` methods to truncate strings to a
|
||||
maximum display width, with optional tail (like an ellipsis). (#13)
|
||||
|
||||
## [0.6.2]
|
||||
|
||||
[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.6.1...v0.6.2)
|
||||
|
||||
### Changed
|
||||
- Internal: reduced property categories for simpler trie.
|
||||
|
||||
## [0.6.1]
|
||||
|
||||
[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.6.0...v0.6.1)
|
||||
|
||||
### Changed
|
||||
- Perf improvements: replaced the ASCII lookup table with a simple
|
||||
function. A bit more cache-friendly. More inlining.
|
||||
- Bug fix: single regional indicators are now treated as width 2, since that
|
||||
is what actual terminals do.
|
||||
|
||||
## [0.6.0]
|
||||
|
||||
[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.5.0...v0.6.0)
|
||||
|
||||
### Added
|
||||
- New `StringGraphemes` and `BytesGraphemes` methods, for iterating over the
|
||||
widths of grapheme clusters.
|
||||
|
||||
### Changed
|
||||
- Fast ASCII lookups
|
||||
|
||||
## [0.5.0]
|
||||
|
||||
[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.4.1...v0.5.0)
|
||||
|
||||
### Added
|
||||
- Unicode 16 support
|
||||
- Improved emoji presentation handling per Unicode TR51
|
||||
|
||||
### Changed
|
||||
- Corrected VS15 (U+FE0E) handling: now preserves base character width (no-op) per Unicode TR51
|
||||
- Performance optimizations: reduced property lookups
|
||||
|
||||
### Fixed
|
||||
- VS15 variation selector now correctly preserves base character width instead of forcing width 1
|
||||
|
||||
## [0.4.1]
|
||||
|
||||
[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.4.0...v0.4.1)
|
||||
|
||||
### Changed
|
||||
- Updated uax29 dependency
|
||||
- Improved flag handling
|
||||
|
||||
## [0.4.0]
|
||||
|
||||
[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.3.1...v0.4.0)
|
||||
|
||||
### Added
|
||||
- Support for variation selectors (VS15, VS16) and regional indicator pairs (flags)
|
||||
|
||||
## [0.3.1]
|
||||
|
||||
[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.3.0...v0.3.1)
|
||||
|
||||
### Added
|
||||
- Fuzz testing support
|
||||
|
||||
### Changed
|
||||
- Updated stringish dependency
|
||||
|
||||
## [0.3.0]
|
||||
|
||||
[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.2.0...v0.3.0)
|
||||
|
||||
### Changed
|
||||
- Dropped compatibility with go-runewidth
|
||||
- Trie implementation cleanup
|
||||
21
vendor/github.com/clipperhouse/displaywidth/LICENSE
generated
vendored
Normal file
21
vendor/github.com/clipperhouse/displaywidth/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2025 Matt Sherman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
190
vendor/github.com/clipperhouse/displaywidth/README.md
generated
vendored
Normal file
190
vendor/github.com/clipperhouse/displaywidth/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
# displaywidth
|
||||
|
||||
A high-performance Go package for measuring the monospace display width of strings, UTF-8 bytes, and runes.
|
||||
|
||||
[](https://pkg.go.dev/github.com/clipperhouse/displaywidth)
|
||||
[](https://github.com/clipperhouse/displaywidth/actions/workflows/gotest.yml)
|
||||
[](https://github.com/clipperhouse/displaywidth/actions/workflows/gofuzz.yml)
|
||||
|
||||
## Install
|
||||
```bash
|
||||
go get github.com/clipperhouse/displaywidth
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/clipperhouse/displaywidth"
|
||||
)
|
||||
|
||||
func main() {
|
||||
width := displaywidth.String("Hello, 世界!")
|
||||
fmt.Println(width)
|
||||
|
||||
width = displaywidth.Bytes([]byte("🌍"))
|
||||
fmt.Println(width)
|
||||
|
||||
width = displaywidth.Rune('🌍')
|
||||
fmt.Println(width)
|
||||
}
|
||||
```
|
||||
|
||||
For most purposes, you should use the `String` or `Bytes` methods. They sum
|
||||
the widths of grapheme clusters in the string or byte slice.
|
||||
|
||||
> Note: in your application, iterating over runes to measure width is likely incorrect;
|
||||
the smallest unit of display is a grapheme, not a rune.
|
||||
|
||||
### Iterating over graphemes
|
||||
|
||||
If you need the individual graphemes:
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/clipperhouse/displaywidth"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g := displaywidth.StringGraphemes("Hello, 世界!")
|
||||
for g.Next() {
|
||||
width := g.Width()
|
||||
value := g.Value()
|
||||
// do something with the width or value
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
Create the options you need, and then use methods on the options struct.
|
||||
|
||||
```go
|
||||
var myOptions = displaywidth.Options{
|
||||
EastAsianWidth: true,
|
||||
ControlSequences: true,
|
||||
}
|
||||
|
||||
width := myOptions.String("Hello, 世界!")
|
||||
```
|
||||
|
||||
#### ControlSequences
|
||||
|
||||
`ControlSequences` specifies whether to ignore ECMA-48 escape sequences
|
||||
when calculating the display width. When `false` (default), ANSI escape
|
||||
sequences are treated as just a series of characters. When `true`, they are
|
||||
treated as a single zero-width unit.
|
||||
|
||||
#### ControlSequences8Bit
|
||||
|
||||
`ControlSequences8Bit` specifies whether to ignore 8-bit ECMA-48 escape sequences
|
||||
when calculating the display width. When `false` (default), these are treated
|
||||
as just a series of characters. When `true`, they are treated as a single
|
||||
zero-width unit.
|
||||
|
||||
Note: this option is ignored by the `Truncate` methods, as the concatenation
|
||||
can lead to unintended UTF-8 semantics.
|
||||
|
||||
#### EastAsianWidth
|
||||
|
||||
`EastAsianWidth` defines how
|
||||
[East Asian Ambiguous characters](https://www.unicode.org/reports/tr11/#Ambiguous)
|
||||
are treated.
|
||||
|
||||
When `false` (default), East Asian Ambiguous characters are treated as width 1.
|
||||
When `true`, they are treated as width 2.
|
||||
|
||||
You may wish to configure this based on environment variables or locale.
|
||||
`go-runewidth`, for example, does so
|
||||
[during package initialization](https://github.com/mattn/go-runewidth/blob/master/runewidth.go#L26C1-L45C2). `displaywidth` does not do this automatically, we prefer to leave it to you.
|
||||
|
||||
|
||||
## Technical standards and compatibility
|
||||
|
||||
This package implements the Unicode East Asian Width standard
|
||||
([UAX #11](https://www.unicode.org/reports/tr11/tr11-43.html)), and handles
|
||||
[version selectors](https://en.wikipedia.org/wiki/Variation_Selectors_(Unicode_block)),
|
||||
and [regional indicator pairs](https://en.wikipedia.org/wiki/Regional_indicator_symbol)
|
||||
(flags). We implement [Unicode TR51](https://www.unicode.org/reports/tr51/tr51-27.html)
|
||||
for emojis. We are keeping an eye on
|
||||
[emerging standards](https://www.jeffquast.com/post/state-of-terminal-emulation-2025/).
|
||||
|
||||
For control sequences, we implement the [ECMA-48](https://ecma-international.org/publications-and-standards/standards/ecma-48/) standard for 7-bit and 8-bit control sequences.
|
||||
|
||||
`clipperhouse/displaywidth`, `mattn/go-runewidth`, and `rivo/uniseg` will
|
||||
give the same outputs for most real-world text. Extensive details are in the
|
||||
[compatibility analysis](comparison/COMPATIBILITY_ANALYSIS.md).
|
||||
|
||||
## Invalid UTF-8
|
||||
|
||||
This package does not validate UTF-8. If you pass invalid UTF-8, the results
|
||||
are undefined. We fuzz against invalid UTF-8 to ensure we don't panic or
|
||||
loop indefinitely.
|
||||
|
||||
The `ControlSequences8Bit` option means that we will segment valid 8-bit
|
||||
control sequences, which are typically _not_ valid UTF-8. 8-bit control bytes
|
||||
happen to also be UTF-8 continuation bytes. Use with caution.
|
||||
|
||||
## Prior Art
|
||||
|
||||
[mattn/go-runewidth](https://github.com/mattn/go-runewidth)
|
||||
|
||||
[rivo/uniseg](https://github.com/rivo/uniseg)
|
||||
|
||||
[x/text/width](https://pkg.go.dev/golang.org/x/text/width)
|
||||
|
||||
[x/text/internal/triegen](https://pkg.go.dev/golang.org/x/text/internal/triegen)
|
||||
|
||||
## Benchmarks
|
||||
|
||||
```bash
|
||||
cd comparison
|
||||
go test -bench=. -benchmem
|
||||
```
|
||||
|
||||
```
|
||||
goos: darwin
|
||||
goarch: arm64
|
||||
pkg: github.com/clipperhouse/displaywidth/comparison
|
||||
cpu: Apple M2
|
||||
|
||||
BenchmarkString_Mixed/clipperhouse/displaywidth-8 5784 ns/op 291.69 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkString_Mixed/mattn/go-runewidth-8 14751 ns/op 114.36 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkString_Mixed/rivo/uniseg-8 19360 ns/op 87.14 MB/s 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkString_ASCII/clipperhouse/displaywidth-8 54.60 ns/op 2344.32 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkString_ASCII/mattn/go-runewidth-8 1195 ns/op 107.08 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkString_ASCII/rivo/uniseg-8 1578 ns/op 81.13 MB/s 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkString_EastAsian/clipperhouse/displaywidth-8 5837 ns/op 289.01 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkString_EastAsian/mattn/go-runewidth-8 24418 ns/op 69.09 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkString_EastAsian/rivo/uniseg-8 19339 ns/op 87.23 MB/s 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkString_Emoji/clipperhouse/displaywidth-8 3225 ns/op 224.51 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkString_Emoji/mattn/go-runewidth-8 4851 ns/op 149.25 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkString_Emoji/rivo/uniseg-8 6591 ns/op 109.85 MB/s 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkRune_Mixed/clipperhouse/displaywidth-8 3385 ns/op 498.34 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkRune_Mixed/mattn/go-runewidth-8 5354 ns/op 315.07 MB/s 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkRune_EastAsian/clipperhouse/displaywidth-8 3397 ns/op 496.56 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkRune_EastAsian/mattn/go-runewidth-8 15673 ns/op 107.64 MB/s 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkRune_ASCII/clipperhouse/displaywidth-8 255.7 ns/op 500.53 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkRune_ASCII/mattn/go-runewidth-8 261.5 ns/op 489.55 MB/s 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkRune_Emoji/clipperhouse/displaywidth-8 1371 ns/op 528.22 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkRune_Emoji/mattn/go-runewidth-8 2267 ns/op 319.43 MB/s 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkTruncateWithTail/clipperhouse/displaywidth-8 3229 ns/op 54.82 MB/s 192 B/op 14 allocs/op
|
||||
BenchmarkTruncateWithTail/mattn/go-runewidth-8 8408 ns/op 21.05 MB/s 192 B/op 14 allocs/op
|
||||
|
||||
BenchmarkTruncateWithoutTail/clipperhouse/displaywidth-8 3554 ns/op 64.43 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkTruncateWithoutTail/mattn/go-runewidth-8 11189 ns/op 20.47 MB/s 0 B/op 0 allocs/op
|
||||
```
|
||||
|
||||
Here are some notes on [how to make Unicode things fast](https://clipperhouse.com/go-unicode/).
|
||||
3
vendor/github.com/clipperhouse/displaywidth/gen.go
generated
vendored
Normal file
3
vendor/github.com/clipperhouse/displaywidth/gen.go
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
package displaywidth
|
||||
|
||||
//go:generate go run -C internal/gen .
|
||||
73
vendor/github.com/clipperhouse/displaywidth/graphemes.go
generated
vendored
Normal file
73
vendor/github.com/clipperhouse/displaywidth/graphemes.go
generated
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
package displaywidth
|
||||
|
||||
import (
|
||||
"github.com/clipperhouse/uax29/v2/graphemes"
|
||||
)
|
||||
|
||||
// Graphemes is an iterator over grapheme clusters.
|
||||
//
|
||||
// Iterate using the Next method, and get the width of the current grapheme
|
||||
// using the Width method.
|
||||
type Graphemes[T ~string | []byte] struct {
|
||||
iter *graphemes.Iterator[T]
|
||||
options Options
|
||||
}
|
||||
|
||||
// Next advances the iterator to the next grapheme cluster.
|
||||
func (g *Graphemes[T]) Next() bool {
|
||||
return g.iter.Next()
|
||||
}
|
||||
|
||||
// Value returns the current grapheme cluster.
|
||||
func (g *Graphemes[T]) Value() T {
|
||||
return g.iter.Value()
|
||||
}
|
||||
|
||||
// Width returns the display width of the current grapheme cluster.
|
||||
func (g *Graphemes[T]) Width() int {
|
||||
return graphemeWidth(g.Value(), g.options)
|
||||
}
|
||||
|
||||
// StringGraphemes returns an iterator over grapheme clusters for the given
|
||||
// string.
|
||||
//
|
||||
// Iterate using the Next method, and get the width of the current grapheme
|
||||
// using the Width method.
|
||||
func StringGraphemes(s string) Graphemes[string] {
|
||||
return DefaultOptions.StringGraphemes(s)
|
||||
}
|
||||
|
||||
// StringGraphemes returns an iterator over grapheme clusters for the given
|
||||
// string, with the given options.
|
||||
//
|
||||
// Iterate using the Next method, and get the width of the current grapheme
|
||||
// using the Width method.
|
||||
func (options Options) StringGraphemes(s string) Graphemes[string] {
|
||||
g := graphemes.FromString(s)
|
||||
g.AnsiEscapeSequences = options.ControlSequences
|
||||
g.AnsiEscapeSequences8Bit = options.ControlSequences8Bit
|
||||
|
||||
return Graphemes[string]{iter: g, options: options}
|
||||
}
|
||||
|
||||
// BytesGraphemes returns an iterator over grapheme clusters for the given
|
||||
// []byte.
|
||||
//
|
||||
// Iterate using the Next method, and get the width of the current grapheme
|
||||
// using the Width method.
|
||||
func BytesGraphemes(s []byte) Graphemes[[]byte] {
|
||||
return DefaultOptions.BytesGraphemes(s)
|
||||
}
|
||||
|
||||
// BytesGraphemes returns an iterator over grapheme clusters for the given
|
||||
// []byte, with the given options.
|
||||
//
|
||||
// Iterate using the Next method, and get the width of the current grapheme
|
||||
// using the Width method.
|
||||
func (options Options) BytesGraphemes(s []byte) Graphemes[[]byte] {
|
||||
g := graphemes.FromBytes(s)
|
||||
g.AnsiEscapeSequences = options.ControlSequences
|
||||
g.AnsiEscapeSequences8Bit = options.ControlSequences8Bit
|
||||
|
||||
return Graphemes[[]byte]{iter: g, options: options}
|
||||
}
|
||||
30
vendor/github.com/clipperhouse/displaywidth/options.go
generated
vendored
Normal file
30
vendor/github.com/clipperhouse/displaywidth/options.go
generated
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
package displaywidth
|
||||
|
||||
// Options allows you to specify the treatment of ambiguous East Asian
|
||||
// characters and ANSI escape sequences.
|
||||
type Options struct {
|
||||
// EastAsianWidth specifies whether to treat ambiguous East Asian characters
|
||||
// as width 1 or 2. When false (default), ambiguous East Asian characters
|
||||
// are treated as width 1. When true, they are width 2.
|
||||
EastAsianWidth bool
|
||||
|
||||
// ControlSequences specifies whether to ignore 7-bit ECMA-48 escape sequences
|
||||
// when calculating the display width. When false (default), ANSI escape
|
||||
// sequences are treated as just a series of characters. When true, they are
|
||||
// treated as a single zero-width unit.
|
||||
ControlSequences bool
|
||||
// ControlSequences8Bit specifies whether to ignore 8-bit ECMA-48 escape sequences
|
||||
// when calculating the display width. When false (default), these are treated
|
||||
// as just a series of characters. When true, they are treated as a single
|
||||
// zero-width unit.
|
||||
ControlSequences8Bit bool
|
||||
}
|
||||
|
||||
// DefaultOptions is the default options for the display width
|
||||
// calculation, which is EastAsianWidth false, ControlSequences false, and
|
||||
// ControlSequences8Bit false.
|
||||
var DefaultOptions = Options{
|
||||
EastAsianWidth: false,
|
||||
ControlSequences: false,
|
||||
ControlSequences8Bit: false,
|
||||
}
|
||||
1699
vendor/github.com/clipperhouse/displaywidth/trie.go
generated
vendored
Normal file
1699
vendor/github.com/clipperhouse/displaywidth/trie.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
149
vendor/github.com/clipperhouse/displaywidth/truncate.go
generated
vendored
Normal file
149
vendor/github.com/clipperhouse/displaywidth/truncate.go
generated
vendored
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
package displaywidth
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/clipperhouse/uax29/v2/graphemes"
|
||||
)
|
||||
|
||||
// TruncateString truncates a string to the given maxWidth, and appends the
|
||||
// given tail if the string is truncated.
|
||||
//
|
||||
// It ensures the visible width, including the width of the tail, is less than or
|
||||
// equal to maxWidth.
|
||||
//
|
||||
// When [Options.ControlSequences] is true, 7-bit ANSI escape sequences that
|
||||
// appear after the truncation point are preserved in the output. This ensures
|
||||
// that escape sequences such as SGR resets are not lost, preventing color
|
||||
// bleed in terminal output.
|
||||
//
|
||||
// [Options.ControlSequences8Bit] is ignored by truncation. 8-bit C1 byte values
|
||||
// (0x80-0x9F) overlap with UTF-8 multi-byte encoding, so manipulating them
|
||||
// during truncation can shift byte boundaries and form unintended visible
|
||||
// characters. Use [Options.String] or [Options.Bytes] for 8-bit-aware width
|
||||
// measurement.
|
||||
func (options Options) TruncateString(s string, maxWidth int, tail string) string {
|
||||
// We deliberately ignore ControlSequences8Bit for truncation, see above.
|
||||
options.ControlSequences8Bit = false
|
||||
|
||||
maxWidthWithoutTail := maxWidth - options.String(tail)
|
||||
|
||||
var pos, total int
|
||||
g := graphemes.FromString(s)
|
||||
g.AnsiEscapeSequences = options.ControlSequences
|
||||
|
||||
for g.Next() {
|
||||
gw := graphemeWidth(g.Value(), options)
|
||||
if total+gw <= maxWidthWithoutTail {
|
||||
pos = g.End()
|
||||
}
|
||||
total += gw
|
||||
if total > maxWidth {
|
||||
if options.ControlSequences {
|
||||
// Build result with trailing 7-bit ANSI escape sequences preserved
|
||||
var b strings.Builder
|
||||
b.Grow(len(s) + len(tail)) // at most original + tail
|
||||
b.WriteString(s[:pos])
|
||||
b.WriteString(tail)
|
||||
|
||||
rem := graphemes.FromString(s[pos:])
|
||||
rem.AnsiEscapeSequences = options.ControlSequences
|
||||
|
||||
for rem.Next() {
|
||||
v := rem.Value()
|
||||
// Only preserve 7-bit escapes (ESC = 0x1B) that measure
|
||||
// as zero-width on their own; some sequences (e.g. SOS)
|
||||
// are only valid in their original context.
|
||||
if len(v) > 0 && v[0] == 0x1B && options.String(v) == 0 {
|
||||
b.WriteString(v)
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
return s[:pos] + tail
|
||||
}
|
||||
}
|
||||
// No truncation
|
||||
return s
|
||||
}
|
||||
|
||||
// TruncateString truncates a string to the given maxWidth, and appends the
|
||||
// given tail if the string is truncated.
|
||||
//
|
||||
// It ensures the total width, including the width of the tail, is less than or
|
||||
// equal to maxWidth.
|
||||
func TruncateString(s string, maxWidth int, tail string) string {
|
||||
return DefaultOptions.TruncateString(s, maxWidth, tail)
|
||||
}
|
||||
|
||||
// TruncateBytes truncates a []byte to the given maxWidth, and appends the
|
||||
// given tail if the []byte is truncated.
|
||||
//
|
||||
// It ensures the visible width, including the width of the tail, is less than or
|
||||
// equal to maxWidth.
|
||||
//
|
||||
// When [Options.ControlSequences] is true, 7-bit ANSI escape sequences that
|
||||
// appear after the truncation point are preserved in the output. This ensures
|
||||
// that escape sequences such as SGR resets are not lost, preventing color
|
||||
// bleed in terminal output.
|
||||
//
|
||||
// [Options.ControlSequences8Bit] is ignored by truncation. 8-bit C1 byte values
|
||||
// (0x80-0x9F) overlap with UTF-8 multi-byte encoding, so manipulating them
|
||||
// during truncation can shift byte boundaries and form unintended visible
|
||||
// characters. Use [Options.String] or [Options.Bytes] for 8-bit-aware width
|
||||
// measurement.
|
||||
func (options Options) TruncateBytes(s []byte, maxWidth int, tail []byte) []byte {
|
||||
// We deliberately ignore ControlSequences8Bit for truncation, see above.
|
||||
options.ControlSequences8Bit = false
|
||||
|
||||
maxWidthWithoutTail := maxWidth - options.Bytes(tail)
|
||||
|
||||
var pos, total int
|
||||
g := graphemes.FromBytes(s)
|
||||
g.AnsiEscapeSequences = options.ControlSequences
|
||||
|
||||
for g.Next() {
|
||||
gw := graphemeWidth(g.Value(), options)
|
||||
if total+gw <= maxWidthWithoutTail {
|
||||
pos = g.End()
|
||||
}
|
||||
total += gw
|
||||
if total > maxWidth {
|
||||
if options.ControlSequences {
|
||||
// Build result with trailing 7-bit ANSI escape sequences preserved
|
||||
result := make([]byte, 0, len(s)+len(tail)) // at most original + tail
|
||||
result = append(result, s[:pos]...)
|
||||
result = append(result, tail...)
|
||||
|
||||
rem := graphemes.FromBytes(s[pos:])
|
||||
rem.AnsiEscapeSequences = options.ControlSequences
|
||||
|
||||
for rem.Next() {
|
||||
v := rem.Value()
|
||||
// Only preserve 7-bit escapes (ESC = 0x1B) that measure
|
||||
// as zero-width on their own; some sequences (e.g. SOS)
|
||||
// are only valid in their original context.
|
||||
if len(v) > 0 && v[0] == 0x1B && options.Bytes(v) == 0 {
|
||||
result = append(result, v...)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
result := make([]byte, 0, pos+len(tail))
|
||||
result = append(result, s[:pos]...)
|
||||
result = append(result, tail...)
|
||||
return result
|
||||
}
|
||||
}
|
||||
// No truncation
|
||||
return s
|
||||
}
|
||||
|
||||
// TruncateBytes truncates a []byte to the given maxWidth, and appends the
|
||||
// given tail if the []byte is truncated.
|
||||
//
|
||||
// It ensures the total width, including the width of the tail, is less than or
|
||||
// equal to maxWidth.
|
||||
func TruncateBytes(s []byte, maxWidth int, tail []byte) []byte {
|
||||
return DefaultOptions.TruncateBytes(s, maxWidth, tail)
|
||||
}
|
||||
239
vendor/github.com/clipperhouse/displaywidth/width.go
generated
vendored
Normal file
239
vendor/github.com/clipperhouse/displaywidth/width.go
generated
vendored
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
package displaywidth
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/clipperhouse/uax29/v2/graphemes"
|
||||
)
|
||||
|
||||
// String calculates the display width of a string,
|
||||
// by iterating over grapheme clusters in the string
|
||||
// and summing their widths.
|
||||
func String(s string) int {
|
||||
return DefaultOptions.String(s)
|
||||
}
|
||||
|
||||
// String calculates the display width of a string, for the given options, by
|
||||
// iterating over grapheme clusters in the string and summing their widths.
|
||||
func (options Options) String(s string) int {
|
||||
width := 0
|
||||
pos := 0
|
||||
|
||||
for pos < len(s) {
|
||||
// Try ASCII optimization
|
||||
asciiLen := printableASCIILength(s[pos:])
|
||||
if asciiLen > 0 {
|
||||
width += asciiLen
|
||||
pos += asciiLen
|
||||
continue
|
||||
}
|
||||
|
||||
// Not ASCII, use grapheme parsing
|
||||
g := graphemes.FromString(s[pos:])
|
||||
g.AnsiEscapeSequences = options.ControlSequences
|
||||
g.AnsiEscapeSequences8Bit = options.ControlSequences8Bit
|
||||
|
||||
start := pos
|
||||
|
||||
for g.Next() {
|
||||
v := g.Value()
|
||||
width += graphemeWidth(v, options)
|
||||
pos += len(v)
|
||||
|
||||
// Quick check: if remaining might have printable ASCII, break to outer loop
|
||||
if pos < len(s) && s[pos] >= 0x20 && s[pos] <= 0x7E {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Defensive, should not happen: if no progress was made,
|
||||
// skip a byte to prevent infinite loop. Only applies if
|
||||
// the grapheme parser misbehaves.
|
||||
if pos == start {
|
||||
pos++
|
||||
}
|
||||
}
|
||||
|
||||
return width
|
||||
}
|
||||
|
||||
// Bytes calculates the display width of a []byte,
|
||||
// by iterating over grapheme clusters in the byte slice
|
||||
// and summing their widths.
|
||||
func Bytes(s []byte) int {
|
||||
return DefaultOptions.Bytes(s)
|
||||
}
|
||||
|
||||
// Bytes calculates the display width of a []byte, for the given options, by
|
||||
// iterating over grapheme clusters in the slice and summing their widths.
|
||||
func (options Options) Bytes(s []byte) int {
|
||||
width := 0
|
||||
pos := 0
|
||||
|
||||
for pos < len(s) {
|
||||
// Try ASCII optimization
|
||||
asciiLen := printableASCIILength(s[pos:])
|
||||
if asciiLen > 0 {
|
||||
width += asciiLen
|
||||
pos += asciiLen
|
||||
continue
|
||||
}
|
||||
|
||||
// Not ASCII, use grapheme parsing
|
||||
g := graphemes.FromBytes(s[pos:])
|
||||
g.AnsiEscapeSequences = options.ControlSequences
|
||||
g.AnsiEscapeSequences8Bit = options.ControlSequences8Bit
|
||||
|
||||
start := pos
|
||||
|
||||
for g.Next() {
|
||||
v := g.Value()
|
||||
width += graphemeWidth(v, options)
|
||||
pos += len(v)
|
||||
|
||||
// Quick check: if remaining might have printable ASCII, break to outer loop
|
||||
if pos < len(s) && s[pos] >= 0x20 && s[pos] <= 0x7E {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Defensive, should not happen: if no progress was made,
|
||||
// skip a byte to prevent infinite loop. Only applies if
|
||||
// the grapheme parser misbehaves.
|
||||
if pos == start {
|
||||
pos++
|
||||
}
|
||||
}
|
||||
|
||||
return width
|
||||
}
|
||||
|
||||
// Rune calculates the display width of a rune. You
|
||||
// should almost certainly use [String] or [Bytes] for
|
||||
// most purposes.
|
||||
//
|
||||
// The smallest unit of display width is a grapheme
|
||||
// cluster, not a rune. Iterating over runes to measure
|
||||
// width is incorrect in many cases.
|
||||
func Rune(r rune) int {
|
||||
return DefaultOptions.Rune(r)
|
||||
}
|
||||
|
||||
// Rune calculates the display width of a rune, for the given options.
|
||||
//
|
||||
// You should almost certainly use [String] or [Bytes] for most purposes.
|
||||
//
|
||||
// The smallest unit of display width is a grapheme cluster, not a rune.
|
||||
// Iterating over runes to measure width is incorrect in many cases.
|
||||
func (options Options) Rune(r rune) int {
|
||||
if r < utf8.RuneSelf {
|
||||
return asciiWidth(byte(r))
|
||||
}
|
||||
|
||||
// Surrogates (U+D800-U+DFFF) are invalid UTF-8.
|
||||
if r >= 0xD800 && r <= 0xDFFF {
|
||||
return 0
|
||||
}
|
||||
|
||||
var buf [4]byte
|
||||
n := utf8.EncodeRune(buf[:], r)
|
||||
|
||||
// Skip the grapheme iterator
|
||||
return graphemeWidth(buf[:n], options)
|
||||
}
|
||||
|
||||
const _Default property = 0
|
||||
|
||||
// graphemeWidth returns the display width of a grapheme cluster.
|
||||
// The passed string must be a single grapheme cluster.
|
||||
func graphemeWidth[T ~string | []byte](s T, options Options) int {
|
||||
if len(s) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// C1 controls (0x80-0x9F) are zero-width when 8-bit control sequences
|
||||
// are enabled. This must be checked before the single-byte optimization
|
||||
// below, which would otherwise return width 1 for these bytes.
|
||||
if options.ControlSequences8Bit && s[0] >= 0x80 && s[0] <= 0x9F {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Optimization: single-byte graphemes need no property lookup
|
||||
if len(s) == 1 {
|
||||
return asciiWidth(s[0])
|
||||
}
|
||||
|
||||
// Multi-byte grapheme clusters led by a C0 control (0x00-0x1F)
|
||||
if s[0] <= 0x1F {
|
||||
return 0
|
||||
}
|
||||
|
||||
p, sz := lookup(s)
|
||||
prop := property(p)
|
||||
|
||||
// Variation Selector 16 (VS16) requests emoji presentation
|
||||
if prop != _Wide && sz > 0 && len(s) >= sz+3 {
|
||||
vs := s[sz : sz+3]
|
||||
if isVS16(vs) {
|
||||
prop = _Wide
|
||||
}
|
||||
// VS15 (0x8E) requests text presentation but does not affect width,
|
||||
// in my reading of Unicode TR51. Falls through to return the base
|
||||
// character's property.
|
||||
}
|
||||
|
||||
if options.EastAsianWidth && prop == _East_Asian_Ambiguous {
|
||||
prop = _Wide
|
||||
}
|
||||
|
||||
if prop > upperBound {
|
||||
prop = _Default
|
||||
}
|
||||
|
||||
return propertyWidths[prop]
|
||||
}
|
||||
|
||||
func asciiWidth(b byte) int {
|
||||
if b <= 0x1F || b == 0x7F {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
// printableASCIILength returns the length of consecutive printable ASCII bytes
|
||||
// starting at the beginning of s.
|
||||
func printableASCIILength[T string | []byte](s T) int {
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
b := s[i]
|
||||
// Printable ASCII is 0x20-0x7E (space through tilde)
|
||||
if b < 0x20 || b > 0x7E {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If the next byte is non-ASCII (>= 0x80), back off by 1. The grapheme
|
||||
// parser may group the last ASCII byte with subsequent non-ASCII bytes,
|
||||
// such as combining marks.
|
||||
if i > 0 && i < len(s) && s[i] >= 0x80 {
|
||||
i--
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
// isVS16 checks if the slice matches VS16 (U+FE0F) UTF-8 encoding
|
||||
// (EF B8 8F). It assumes len(s) >= 3.
|
||||
func isVS16[T ~string | []byte](s T) bool {
|
||||
return s[0] == 0xEF && s[1] == 0xB8 && s[2] == 0x8F
|
||||
}
|
||||
|
||||
// propertyWidths is a jump table of sorts, instead of a switch
|
||||
var propertyWidths = [4]int{
|
||||
_Default: 1,
|
||||
_Zero_Width: 0,
|
||||
_Wide: 2,
|
||||
_East_Asian_Ambiguous: 1,
|
||||
}
|
||||
|
||||
const upperBound = property(len(propertyWidths) - 1)
|
||||
21
vendor/github.com/clipperhouse/uax29/v2/LICENSE
generated
vendored
Normal file
21
vendor/github.com/clipperhouse/uax29/v2/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 Matt Sherman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
120
vendor/github.com/clipperhouse/uax29/v2/graphemes/README.md
generated
vendored
Normal file
120
vendor/github.com/clipperhouse/uax29/v2/graphemes/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
An implementation of grapheme cluster boundaries from [Unicode text segmentation](https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) (UAX 29), for Unicode 17.
|
||||
|
||||
[](https://pkg.go.dev/github.com/clipperhouse/uax29/v2/graphemes)
|
||||

|
||||

|
||||
|
||||
## Quick start
|
||||
|
||||
```
|
||||
go get github.com/clipperhouse/uax29/v2/graphemes
|
||||
```
|
||||
|
||||
```go
|
||||
import "github.com/clipperhouse/uax29/v2/graphemes"
|
||||
|
||||
text := "Hello, 世界. Nice dog! 👍🐶"
|
||||
g := graphemes.FromString(text)
|
||||
|
||||
for g.Next() { // Next() returns true until end of data
|
||||
fmt.Println(g.Value()) // Do something with the current grapheme
|
||||
}
|
||||
```
|
||||
|
||||
_A grapheme is a “single visible character”, which might be a simple as a single letter, or a complex emoji that consists of several Unicode code points._
|
||||
|
||||
## Conformance
|
||||
|
||||
We use the Unicode [test suite](https://unicode.org/reports/tr41/tr41-36.html#Tests29).
|
||||
|
||||

|
||||

|
||||
|
||||
## APIs
|
||||
|
||||
### If you have a `string`
|
||||
|
||||
```go
|
||||
text := "Hello, 世界. Nice dog! 👍🐶"
|
||||
g := graphemes.FromString(text)
|
||||
|
||||
for g.Next() { // Next() returns true until end of data
|
||||
fmt.Println(g.Value()) // Do something with the current grapheme
|
||||
}
|
||||
```
|
||||
|
||||
### If you have an `io.Reader`
|
||||
|
||||
`FromReader` embeds a [`bufio.Scanner`](https://pkg.go.dev/bufio#Scanner), so just use those methods.
|
||||
|
||||
```go
|
||||
r := getYourReader() // from a file or network maybe
|
||||
g := graphemes.FromReader(r)
|
||||
|
||||
for g.Scan() { // Scan() returns true until error or EOF
|
||||
fmt.Println(g.Text()) // Do something with the current grapheme
|
||||
}
|
||||
|
||||
if g.Err() != nil { // Check the error
|
||||
log.Fatal(g.Err())
|
||||
}
|
||||
```
|
||||
|
||||
### If you have a `[]byte`
|
||||
|
||||
```go
|
||||
b := []byte("Hello, 世界. Nice dog! 👍🐶")
|
||||
|
||||
g := graphemes.FromBytes(b)
|
||||
|
||||
for g.Next() { // Next() returns true until end of data
|
||||
fmt.Println(g.Value()) // Do something with the current grapheme
|
||||
}
|
||||
```
|
||||
|
||||
### ANSI escape sequences
|
||||
|
||||
By the UAX 29 specification, ANSI escape sequences are not grapheme clusters. To treat 7-bit ANSI escape sequences as a single cluster, set `AnsiEscapeSequences` to true.
|
||||
|
||||
```go
|
||||
text := "Hello, \x1b[31mworld\x1b[0m!"
|
||||
g := graphemes.FromString(text)
|
||||
g.AnsiEscapeSequences = true
|
||||
|
||||
for g.Next() {
|
||||
fmt.Println(g.Value())
|
||||
}
|
||||
```
|
||||
|
||||
To also parse 8-bit C1 controls (non-UTF-8 bytes), set `AnsiEscapeSequences8Bit` to true.
|
||||
|
||||
```go
|
||||
g.AnsiEscapeSequences = true // 7-bit forms (ESC ...)
|
||||
g.AnsiEscapeSequences8Bit = true // 8-bit C1 forms (0x80-0x9F), not valid UTF-8
|
||||
```
|
||||
|
||||
For ESC-initiated (7-bit) control strings, only 7-bit terminators are recognized.
|
||||
For C1-initiated (8-bit) control strings, only C1 ST (`0x9C`) is recognized as ST.
|
||||
|
||||
We implement [ECMA-48](https://ecma-international.org/publications-and-standards/standards/ecma-48/) control codes in both 7-bit and 8-bit representations. 8-bit control codes are not UTF-8 encoded and are not valid UTF-8, caveat emptor.
|
||||
|
||||
### Benchmarks
|
||||
|
||||
```
|
||||
goos: darwin
|
||||
goarch: arm64
|
||||
pkg: github.com/clipperhouse/uax29/graphemes/comparative
|
||||
cpu: Apple M2
|
||||
|
||||
BenchmarkGraphemesMixed/clipperhouse/uax29-8 142635 ns/op 245.12 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkGraphemesMixed/rivo/uniseg-8 2018284 ns/op 17.32 MB/s 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkGraphemesASCII/clipperhouse/uax29-8 8846 ns/op 508.73 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkGraphemesASCII/rivo/uniseg-8 366760 ns/op 12.27 MB/s 0 B/op 0 allocs/op
|
||||
```
|
||||
|
||||
### Invalid inputs
|
||||
|
||||
Invalid UTF-8 input is considered undefined behavior. We test to ensure that bad inputs will not cause pathological outcomes, such as a panic or infinite loop. Callers should expect “garbage-in, garbage-out”.
|
||||
|
||||
Your pipeline should probably include a call to [`utf8.Valid()`](https://pkg.go.dev/unicode/utf8#Valid).
|
||||
138
vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi.go
generated
vendored
Normal file
138
vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi.go
generated
vendored
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
package graphemes
|
||||
|
||||
// ansiEscapeLength returns the byte length of a valid 7-bit ANSI escape
|
||||
// sequence at the start of data, or 0 if none.
|
||||
//
|
||||
// Recognized forms (ECMA-48 / ISO 6429):
|
||||
// - CSI: ESC [ then parameter bytes (0x30-0x3F), intermediate (0x20-0x2F), final (0x40-0x7E)
|
||||
// - OSC: ESC ] then payload until BEL (0x07), 7-bit ST (ESC \), CAN (0x18), or SUB (0x1A)
|
||||
// - DCS, SOS, PM, APC: ESC P/X/^/_ then payload until 7-bit ST (ESC \), CAN, or SUB
|
||||
// - Two-byte: ESC + Fe/Fs (0x40-0x7E excluding above), or Fp (0x30-0x3F), or nF (0x20-0x2F then final)
|
||||
func ansiEscapeLength[T ~string | ~[]byte](data T) int {
|
||||
n := len(data)
|
||||
if n < 2 || data[0] != esc {
|
||||
return 0
|
||||
}
|
||||
|
||||
b1 := data[1]
|
||||
switch b1 {
|
||||
case '[': // CSI
|
||||
body := csiBodyLength(data[2:])
|
||||
if body == 0 {
|
||||
return 0
|
||||
}
|
||||
return 2 + body
|
||||
case ']': // OSC - allows BEL or 7-bit ST terminator
|
||||
body := oscLength(data[2:])
|
||||
if body < 0 {
|
||||
return 0
|
||||
}
|
||||
return 2 + body
|
||||
case 'P', 'X', '^', '_': // DCS, SOS, PM, APC
|
||||
body := stSequenceLength(data[2:])
|
||||
if body < 0 {
|
||||
return 0
|
||||
}
|
||||
return 2 + body
|
||||
}
|
||||
|
||||
if b1 >= 0x40 && b1 <= 0x7E {
|
||||
// Fe/Fs two-byte; [ ] P X ^ _ handled above
|
||||
return 2
|
||||
}
|
||||
if b1 >= 0x30 && b1 <= 0x3F {
|
||||
// Fp (private) two-byte
|
||||
return 2
|
||||
}
|
||||
if b1 >= 0x20 && b1 <= 0x2F {
|
||||
// nF: intermediates then one final (0x30-0x7E)
|
||||
i := 2
|
||||
for i < n && data[i] >= 0x20 && data[i] <= 0x2F {
|
||||
i++
|
||||
}
|
||||
if i < n && data[i] >= 0x30 && data[i] <= 0x7E {
|
||||
return i + 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// csiBodyLength returns the length of the CSI body (param/intermediate/final bytes).
|
||||
// data is the slice after "ESC [".
|
||||
// Per ECMA-48, the CSI body has the form:
|
||||
//
|
||||
// parameters (0x30–0x3F)*, intermediates (0x20–0x2F)*, final (0x40–0x7E)
|
||||
//
|
||||
// Once an intermediate byte is seen, subsequent parameter bytes are invalid.
|
||||
func csiBodyLength[T ~string | ~[]byte](data T) int {
|
||||
seenIntermediate := false
|
||||
for i := 0; i < len(data); i++ {
|
||||
b := data[i]
|
||||
if b >= 0x30 && b <= 0x3F {
|
||||
if seenIntermediate {
|
||||
return 0
|
||||
}
|
||||
continue
|
||||
}
|
||||
if b >= 0x20 && b <= 0x2F {
|
||||
seenIntermediate = true
|
||||
continue
|
||||
}
|
||||
if b >= 0x40 && b <= 0x7E {
|
||||
return i + 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// oscLength returns the length of the OSC body.
|
||||
// data is the slice after "ESC ]".
|
||||
//
|
||||
// Returns:
|
||||
// - n >= 0: consumed body length (includes BEL/ST terminator when present)
|
||||
// - -1: not terminated in the provided data
|
||||
//
|
||||
// OSC accepts BEL (0x07) or 7-bit ST (ESC \) as terminators by widespread convention.
|
||||
// Per ECMA-48, CAN (0x18) and SUB (0x1A) cancel the control string; in that
|
||||
// case they are not part of the OSC sequence length.
|
||||
func oscLength[T ~string | ~[]byte](data T) int {
|
||||
for i := 0; i < len(data); i++ {
|
||||
b := data[i]
|
||||
if b == bel {
|
||||
return i + 1
|
||||
}
|
||||
if b == can || b == sub {
|
||||
return i
|
||||
}
|
||||
if b == esc && i+1 < len(data) && data[i+1] == '\\' {
|
||||
return i + 2
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// stSequenceLength returns the length of a control-string body.
|
||||
// data is the slice after "ESC x".
|
||||
//
|
||||
// Returns:
|
||||
// - n >= 0: consumed body length (includes ST terminator when present)
|
||||
// - -1: not terminated in the provided data
|
||||
//
|
||||
// Used for DCS, SOS, PM, and APC, which per ECMA-48 terminate with ST.
|
||||
// ST here is the 7-bit form (ESC \).
|
||||
// CAN (0x18) and SUB (0x1A) cancel the control string; in that case they are
|
||||
// not part of the sequence length.
|
||||
func stSequenceLength[T ~string | ~[]byte](data T) int {
|
||||
for i := 0; i < len(data); i++ {
|
||||
if data[i] == can || data[i] == sub {
|
||||
return i
|
||||
}
|
||||
if data[i] == esc && i+1 < len(data) && data[i+1] == '\\' {
|
||||
return i + 2
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
79
vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi8.go
generated
vendored
Normal file
79
vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi8.go
generated
vendored
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
package graphemes
|
||||
|
||||
// ansiEscapeLength8Bit returns the byte length of a valid 8-bit C1 ANSI
|
||||
// sequence at the start of data, or 0 if none.
|
||||
//
|
||||
// Recognized forms (ECMA-48 / ISO 6429):
|
||||
// - C1 CSI (0x9B) body as parameter/intermediate/final bytes
|
||||
// - C1 OSC (0x9D) body terminated by BEL, C1 ST, CAN, or SUB
|
||||
// - C1 DCS/SOS/PM/APC (0x90/0x98/0x9E/0x9F) body terminated by C1 ST, CAN, or SUB
|
||||
// - Standalone C1 controls (0x80..0x9F not listed above): single byte
|
||||
func ansiEscapeLength8Bit[T ~string | ~[]byte](data T) int {
|
||||
if len(data) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
switch data[0] {
|
||||
case 0x9B: // C1 CSI
|
||||
body := csiBodyLength(data[1:])
|
||||
if body == 0 {
|
||||
return 0
|
||||
}
|
||||
return 1 + body
|
||||
case 0x9D: // C1 OSC
|
||||
body := oscLengthC1(data[1:])
|
||||
if body < 0 {
|
||||
return 0
|
||||
}
|
||||
return 1 + body
|
||||
case 0x90, 0x98, 0x9E, 0x9F: // C1 DCS, SOS, PM, APC
|
||||
body := stSequenceLengthC1(data[1:])
|
||||
if body < 0 {
|
||||
return 0
|
||||
}
|
||||
return 1 + body
|
||||
default:
|
||||
if data[0] >= 0x80 && data[0] <= 0x9F {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// oscLengthC1 returns the length of a C1 OSC body.
|
||||
// data is the slice after the C1 OSC initiator (0x9D).
|
||||
//
|
||||
// Returns:
|
||||
// - n >= 0: consumed body length (includes BEL/ST terminator when present)
|
||||
// - -1: not terminated in the provided data
|
||||
//
|
||||
// Terminators: BEL (0x07) or C1 ST (0x9C).
|
||||
// CAN (0x18) and SUB (0x1A) cancel the control string.
|
||||
func oscLengthC1[T ~string | ~[]byte](data T) int {
|
||||
for i := 0; i < len(data); i++ {
|
||||
b := data[i]
|
||||
if b == bel || b == st {
|
||||
return i + 1
|
||||
}
|
||||
if b == can || b == sub {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// stSequenceLengthC1 parses DCS/SOS/PM/APC bodies that terminate with C1 ST
|
||||
// (0x9C), or are canceled by CAN/SUB.
|
||||
func stSequenceLengthC1[T ~string | ~[]byte](data T) int {
|
||||
for i := 0; i < len(data); i++ {
|
||||
b := data[i]
|
||||
if b == can || b == sub {
|
||||
return i
|
||||
}
|
||||
if b == st {
|
||||
return i + 1
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
144
vendor/github.com/clipperhouse/uax29/v2/graphemes/iterator.go
generated
vendored
Normal file
144
vendor/github.com/clipperhouse/uax29/v2/graphemes/iterator.go
generated
vendored
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
package graphemes
|
||||
|
||||
import "unicode/utf8"
|
||||
|
||||
// FromString returns an iterator for the grapheme clusters in the input string.
|
||||
// Iterate while Next() is true, and access the grapheme via Value().
|
||||
func FromString(s string) *Iterator[string] {
|
||||
return &Iterator[string]{
|
||||
split: splitFuncString,
|
||||
data: s,
|
||||
}
|
||||
}
|
||||
|
||||
// FromBytes returns an iterator for the grapheme clusters in the input bytes.
|
||||
// Iterate while Next() is true, and access the grapheme via Value().
|
||||
func FromBytes(b []byte) *Iterator[[]byte] {
|
||||
return &Iterator[[]byte]{
|
||||
split: splitFuncBytes,
|
||||
data: b,
|
||||
}
|
||||
}
|
||||
|
||||
// Iterator is a generic iterator for grapheme clusters in strings or byte slices,
|
||||
// with an ASCII hot path optimization.
|
||||
type Iterator[T ~string | ~[]byte] struct {
|
||||
split func(T, bool) (int, T, error)
|
||||
data T
|
||||
pos int
|
||||
start int
|
||||
// AnsiEscapeSequences treats 7-bit ANSI escape sequences (ECMA-48) as
|
||||
// single grapheme clusters when true. The default is false.
|
||||
//
|
||||
// 8-bit controls are not enabled by this option. See [AnsiEscapeSequences8Bit].
|
||||
AnsiEscapeSequences bool
|
||||
// AnsiEscapeSequences8Bit treats 8-bit C1 ANSI escape sequences (ECMA-48) as single
|
||||
// grapheme clusters when true. The default is false.
|
||||
//
|
||||
// 8-bit control bytes are not UTF-8 encoded, i.e. not valid UTF-8. If you
|
||||
// choose this option, you are choosing to interpret non-UTF-8 data, caveat
|
||||
// emptor.
|
||||
AnsiEscapeSequences8Bit bool
|
||||
}
|
||||
|
||||
var (
|
||||
splitFuncString = splitFunc[string]
|
||||
splitFuncBytes = splitFunc[[]byte]
|
||||
)
|
||||
|
||||
const (
|
||||
esc = 0x1B
|
||||
cr = 0x0D
|
||||
bel = 0x07
|
||||
can = 0x18
|
||||
sub = 0x1A
|
||||
st = 0x9C
|
||||
)
|
||||
|
||||
// Next advances the iterator to the next grapheme cluster.
|
||||
// Returns false when there are no more grapheme clusters.
|
||||
func (iter *Iterator[T]) Next() bool {
|
||||
if iter.pos >= len(iter.data) {
|
||||
return false
|
||||
}
|
||||
iter.start = iter.pos
|
||||
|
||||
b := iter.data[iter.pos]
|
||||
if iter.AnsiEscapeSequences && b == esc {
|
||||
if a := ansiEscapeLength(iter.data[iter.pos:]); a > 0 {
|
||||
iter.pos += a
|
||||
return true
|
||||
}
|
||||
}
|
||||
if iter.AnsiEscapeSequences8Bit && b >= 0x80 && b <= 0x9F {
|
||||
if a := ansiEscapeLength8Bit(iter.data[iter.pos:]); a > 0 {
|
||||
iter.pos += a
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// ASCII hot path: any ASCII is one grapheme when next byte is ASCII or end.
|
||||
if b < utf8.RuneSelf && b != cr {
|
||||
if iter.pos+1 >= len(iter.data) || iter.data[iter.pos+1] < utf8.RuneSelf {
|
||||
iter.pos++
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to UAX29 grapheme parsing
|
||||
remaining := iter.data[iter.pos:]
|
||||
advance, _, err := iter.split(remaining, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if advance <= 0 {
|
||||
panic("splitFunc returned a zero or negative advance")
|
||||
}
|
||||
iter.pos += advance
|
||||
if iter.pos > len(iter.data) {
|
||||
panic("splitFunc advanced beyond end of data")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Value returns the current grapheme cluster.
|
||||
func (iter *Iterator[T]) Value() T {
|
||||
return iter.data[iter.start:iter.pos]
|
||||
}
|
||||
|
||||
// Start returns the byte position of the current grapheme in the original data.
|
||||
func (iter *Iterator[T]) Start() int {
|
||||
return iter.start
|
||||
}
|
||||
|
||||
// End returns the byte position after the current grapheme in the original data.
|
||||
func (iter *Iterator[T]) End() int {
|
||||
return iter.pos
|
||||
}
|
||||
|
||||
// Reset resets the iterator to the beginning of the data.
|
||||
func (iter *Iterator[T]) Reset() {
|
||||
iter.start = 0
|
||||
iter.pos = 0
|
||||
}
|
||||
|
||||
// SetText sets the data for the iterator to operate on, and resets all state.
|
||||
func (iter *Iterator[T]) SetText(data T) {
|
||||
iter.data = data
|
||||
iter.start = 0
|
||||
iter.pos = 0
|
||||
}
|
||||
|
||||
// First returns the first grapheme cluster without advancing the iterator.
|
||||
func (iter *Iterator[T]) First() T {
|
||||
if len(iter.data) == 0 {
|
||||
return iter.data
|
||||
}
|
||||
|
||||
// Use a copy to leverage Next()'s ASCII optimization
|
||||
cp := *iter
|
||||
cp.pos = 0
|
||||
cp.start = 0
|
||||
cp.Next()
|
||||
return cp.Value()
|
||||
}
|
||||
25
vendor/github.com/clipperhouse/uax29/v2/graphemes/reader.go
generated
vendored
Normal file
25
vendor/github.com/clipperhouse/uax29/v2/graphemes/reader.go
generated
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// Package graphemes implements Unicode grapheme cluster boundaries: https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries
|
||||
package graphemes
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
)
|
||||
|
||||
type Scanner struct {
|
||||
*bufio.Scanner
|
||||
}
|
||||
|
||||
// FromReader returns a Scanner, to split graphemes per
|
||||
// https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries.
|
||||
//
|
||||
// It embeds a [bufio.Scanner], so you can use its methods.
|
||||
//
|
||||
// Iterate through graphemes by calling Scan() until false, then check Err().
|
||||
func FromReader(r io.Reader) *Scanner {
|
||||
sc := bufio.NewScanner(r)
|
||||
sc.Split(SplitFunc)
|
||||
return &Scanner{
|
||||
Scanner: sc,
|
||||
}
|
||||
}
|
||||
205
vendor/github.com/clipperhouse/uax29/v2/graphemes/splitfunc.go
generated
vendored
Normal file
205
vendor/github.com/clipperhouse/uax29/v2/graphemes/splitfunc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
package graphemes
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
)
|
||||
|
||||
// is determines if lookup intersects propert(ies)
|
||||
func (lookup property) is(properties property) bool {
|
||||
return (lookup & properties) != 0
|
||||
}
|
||||
|
||||
const _Ignore = _Extend
|
||||
|
||||
// incbState tracks state for GB9c rule (Indic conjunct clusters)
|
||||
// Pattern: Consonant (Extend|Linker)* Linker (Extend|Linker)* × Consonant
|
||||
type incbState int
|
||||
|
||||
const (
|
||||
incbNone incbState = iota // initial/reset
|
||||
incbConsonant // seen Consonant, awaiting Linker
|
||||
incbLinker // seen Consonant and Linker (conjunct ready)
|
||||
)
|
||||
|
||||
// SplitFunc is a bufio.SplitFunc implementation of Unicode grapheme cluster segmentation, for use with bufio.Scanner.
|
||||
//
|
||||
// See https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries.
|
||||
var SplitFunc bufio.SplitFunc = splitFunc[[]byte]
|
||||
|
||||
func splitFunc[T ~string | ~[]byte](data T, atEOF bool) (advance int, token T, err error) {
|
||||
var empty T
|
||||
if len(data) == 0 {
|
||||
return 0, empty, nil
|
||||
}
|
||||
|
||||
// These vars are stateful across loop iterations
|
||||
var pos int
|
||||
var lastExIgnore property = 0 // "last excluding ignored categories"
|
||||
var lastLastExIgnore property = 0 // "last one before that"
|
||||
var regionalIndicatorCount int
|
||||
|
||||
// GB9c state: tracking Indic conjunct clusters
|
||||
var incb incbState
|
||||
|
||||
// Rules are usually of the form Cat1 × Cat2; "current" refers to the first property
|
||||
// to the right of the ×, from which we look back or forward
|
||||
|
||||
current, w := lookup(data[pos:])
|
||||
if w == 0 {
|
||||
if !atEOF {
|
||||
// Rune extends past current data, request more
|
||||
return 0, empty, nil
|
||||
}
|
||||
pos = len(data)
|
||||
return pos, data[:pos], nil
|
||||
}
|
||||
|
||||
// https://unicode.org/reports/tr29/#GB1
|
||||
// Start of text always advances
|
||||
pos += w
|
||||
|
||||
for {
|
||||
eot := pos == len(data) // "end of text"
|
||||
|
||||
if eot {
|
||||
if !atEOF {
|
||||
// Token extends past current data, request more
|
||||
return 0, empty, nil
|
||||
}
|
||||
|
||||
// https://unicode.org/reports/tr29/#GB2
|
||||
break
|
||||
}
|
||||
|
||||
/*
|
||||
We've switched the evaluation order of GB1↓ and GB2↑. It's ok:
|
||||
because we've checked for len(data) at the top of this function,
|
||||
sot and eot are mutually exclusive, order doesn't matter.
|
||||
*/
|
||||
|
||||
// Rules are usually of the form Cat1 × Cat2; "current" refers to the first property
|
||||
// to the right of the ×, from which we look back or forward
|
||||
|
||||
// Remember previous properties to avoid lookups/lookbacks
|
||||
last := current
|
||||
if !last.is(_Ignore) {
|
||||
lastLastExIgnore = lastExIgnore
|
||||
lastExIgnore = last
|
||||
}
|
||||
|
||||
// Update GB9c state based on what we just advanced past
|
||||
if last.is(_InCBConsonant | _InCBLinker | _InCBExtend) {
|
||||
switch {
|
||||
case last.is(_InCBConsonant):
|
||||
if incb != incbLinker {
|
||||
incb = incbConsonant
|
||||
}
|
||||
case last.is(_InCBLinker):
|
||||
if incb >= incbConsonant {
|
||||
incb = incbLinker
|
||||
}
|
||||
// case last.is(_InCBExtend): stay in current state
|
||||
}
|
||||
} else {
|
||||
incb = incbNone
|
||||
}
|
||||
|
||||
current, w = lookup(data[pos:])
|
||||
if w == 0 {
|
||||
if atEOF {
|
||||
// Just return the bytes, we can't do anything with them
|
||||
pos = len(data)
|
||||
break
|
||||
}
|
||||
// Rune extends past current data, request more
|
||||
return 0, empty, nil
|
||||
}
|
||||
|
||||
// Optimization: no rule can possibly apply
|
||||
if current|last == 0 { // i.e. both are zero
|
||||
break
|
||||
}
|
||||
|
||||
// https://unicode.org/reports/tr29/#GB3
|
||||
if current.is(_LF) && last.is(_CR) {
|
||||
pos += w
|
||||
continue
|
||||
}
|
||||
|
||||
// https://unicode.org/reports/tr29/#GB4
|
||||
// https://unicode.org/reports/tr29/#GB5
|
||||
if (current | last).is(_Control | _CR | _LF) {
|
||||
break
|
||||
}
|
||||
|
||||
// https://unicode.org/reports/tr29/#GB6
|
||||
if current.is(_L|_V|_LV|_LVT) && last.is(_L) {
|
||||
pos += w
|
||||
continue
|
||||
}
|
||||
|
||||
// https://unicode.org/reports/tr29/#GB7
|
||||
if current.is(_V|_T) && last.is(_LV|_V) {
|
||||
pos += w
|
||||
continue
|
||||
}
|
||||
|
||||
// https://unicode.org/reports/tr29/#GB8
|
||||
if current.is(_T) && last.is(_LVT|_T) {
|
||||
pos += w
|
||||
continue
|
||||
}
|
||||
|
||||
// https://unicode.org/reports/tr29/#GB9
|
||||
if current.is(_Extend | _ZWJ) {
|
||||
pos += w
|
||||
continue
|
||||
}
|
||||
|
||||
// https://unicode.org/reports/tr29/#GB9a
|
||||
if current.is(_SpacingMark) {
|
||||
pos += w
|
||||
continue
|
||||
}
|
||||
|
||||
// https://unicode.org/reports/tr29/#GB9b
|
||||
if last.is(_Prepend) {
|
||||
pos += w
|
||||
continue
|
||||
}
|
||||
|
||||
// https://unicode.org/reports/tr29/#GB9c
|
||||
// Do not break within certain combinations with Indic_Conjunct_Break (InCB)=Linker.
|
||||
if incb == incbLinker && current.is(_InCBConsonant) {
|
||||
// After matching the pattern, reset state to start tracking a new pattern
|
||||
// The current Consonant becomes the start of the new pattern
|
||||
incb = incbConsonant
|
||||
pos += w
|
||||
continue
|
||||
}
|
||||
|
||||
// https://unicode.org/reports/tr29/#GB11
|
||||
if current.is(_ExtendedPictographic) && last.is(_ZWJ) && lastLastExIgnore.is(_ExtendedPictographic) {
|
||||
pos += w
|
||||
continue
|
||||
}
|
||||
|
||||
// https://unicode.org/reports/tr29/#GB12
|
||||
// https://unicode.org/reports/tr29/#GB13
|
||||
if (current & last).is(_RegionalIndicator) {
|
||||
regionalIndicatorCount++
|
||||
|
||||
odd := regionalIndicatorCount%2 == 1
|
||||
if odd {
|
||||
pos += w
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// If we fall through all the above rules, it's a grapheme cluster break
|
||||
break
|
||||
}
|
||||
|
||||
// Return token
|
||||
return pos, data[:pos], nil
|
||||
}
|
||||
1717
vendor/github.com/clipperhouse/uax29/v2/graphemes/trie.go
generated
vendored
Normal file
1717
vendor/github.com/clipperhouse/uax29/v2/graphemes/trie.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1128
vendor/github.com/gdamore/tcell/v2/color.go
generated
vendored
1128
vendor/github.com/gdamore/tcell/v2/color.go
generated
vendored
File diff suppressed because it is too large
Load diff
24
vendor/github.com/gdamore/tcell/v2/console_stub.go
generated
vendored
24
vendor/github.com/gdamore/tcell/v2/console_stub.go
generated
vendored
|
|
@ -1,24 +0,0 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
// Copyright 2015 The TCell Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use file except in compliance with the License.
|
||||
// You may obtain a copy of the license at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tcell
|
||||
|
||||
// NewConsoleScreen returns a console based screen. This platform
|
||||
// doesn't have support for any, so it returns nil and a suitable error.
|
||||
func NewConsoleScreen() (Screen, error) {
|
||||
return nil, ErrNoScreen
|
||||
}
|
||||
1275
vendor/github.com/gdamore/tcell/v2/console_win.go
generated
vendored
1275
vendor/github.com/gdamore/tcell/v2/console_win.go
generated
vendored
File diff suppressed because it is too large
Load diff
47
vendor/github.com/gdamore/tcell/v2/doc.go
generated
vendored
47
vendor/github.com/gdamore/tcell/v2/doc.go
generated
vendored
|
|
@ -1,47 +0,0 @@
|
|||
// Copyright 2018 The TCell Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use file except in compliance with the License.
|
||||
// You may obtain a copy of the license at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package tcell provides a lower-level, portable API for building
|
||||
// programs that interact with terminals or consoles. It works with
|
||||
// both common (and many uncommon!) terminals or terminal emulators,
|
||||
// and Windows console implementations.
|
||||
//
|
||||
// It provides support for up to 256 colors, text attributes, and box drawing
|
||||
// elements. A database of terminals built from a real terminfo database
|
||||
// is provided, along with code to generate new database entries.
|
||||
//
|
||||
// Tcell offers very rich support for mice, dependent upon the terminal
|
||||
// of course. (Windows, XTerm, and iTerm 2 are known to work very well.)
|
||||
//
|
||||
// If the environment is not Unicode by default, such as an ISO8859 based
|
||||
// locale or GB18030, Tcell can convert input and output, so that your
|
||||
// terminal can operate in whatever locale is most convenient, while the
|
||||
// application program can just assume "everything is UTF-8". Reasonable
|
||||
// defaults are used for updating characters to something suitable for
|
||||
// display. Unicode box drawing characters will be converted to use the
|
||||
// alternate character set of your terminal, if native conversions are
|
||||
// not available. If no ACS is available, then some ASCII fallbacks will
|
||||
// be used.
|
||||
//
|
||||
// Note that support for non-UTF-8 locales (other than C) must be enabled
|
||||
// by the application using RegisterEncoding() -- we don't have them all
|
||||
// enabled by default to avoid bloating the application unnecessarily.
|
||||
// (These days UTF-8 is good enough for almost everyone, and nobody should
|
||||
// be using legacy locales anymore.) Also, actual glyphs for various code
|
||||
// point will only be displayed if your terminal or emulator (or the font
|
||||
// the emulator is using) supports them.
|
||||
//
|
||||
// A rich set of key codes is supported, with support for up to 65 function
|
||||
// keys, and various other special keys.
|
||||
package tcell
|
||||
535
vendor/github.com/gdamore/tcell/v2/simulation.go
generated
vendored
535
vendor/github.com/gdamore/tcell/v2/simulation.go
generated
vendored
|
|
@ -1,535 +0,0 @@
|
|||
// 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.
|
||||
// You may obtain a copy of the license at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tcell
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// NewSimulationScreen returns a SimulationScreen. Note that
|
||||
// SimulationScreen is also a Screen.
|
||||
func NewSimulationScreen(charset string) SimulationScreen {
|
||||
if charset == "" {
|
||||
charset = "UTF-8"
|
||||
}
|
||||
ss := &simscreen{charset: charset}
|
||||
ss.Screen = &baseScreen{screenImpl: ss}
|
||||
return ss
|
||||
}
|
||||
|
||||
// SimulationScreen represents a screen simulation. This is intended to
|
||||
// be a superset of normal Screens, but also adds some important interfaces
|
||||
// for testing.
|
||||
type SimulationScreen interface {
|
||||
Screen
|
||||
|
||||
// InjectKeyBytes injects a stream of bytes corresponding to
|
||||
// the native encoding (see charset). It turns true if the entire
|
||||
// set of bytes were processed and delivered as KeyEvents, false
|
||||
// if any bytes were not fully understood. Any bytes that are not
|
||||
// fully converted are discarded.
|
||||
InjectKeyBytes(buf []byte) bool
|
||||
|
||||
// InjectKey injects a key event. The rune is a UTF-8 rune, post
|
||||
// any translation.
|
||||
InjectKey(key Key, r rune, mod ModMask)
|
||||
|
||||
// InjectMouse injects a mouse event.
|
||||
InjectMouse(x, y int, buttons ButtonMask, mod ModMask)
|
||||
|
||||
// GetContents returns screen contents as an array of
|
||||
// cells, along with the physical width & height. Note that the
|
||||
// physical contents will be used until the next time SetSize()
|
||||
// is called.
|
||||
GetContents() (cells []SimCell, width int, height int)
|
||||
|
||||
// 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
|
||||
// is to track on screen content.
|
||||
type SimCell struct {
|
||||
// Bytes is the actual character bytes. Normally this is
|
||||
// rune data, but it could be be data in another encoding system.
|
||||
Bytes []byte
|
||||
|
||||
// Style is the style used to display the data.
|
||||
Style Style
|
||||
|
||||
// Runes is the list of runes, unadulterated, in UTF-8.
|
||||
Runes []rune
|
||||
}
|
||||
|
||||
type simscreen struct {
|
||||
physw int
|
||||
physh int
|
||||
fini bool
|
||||
style Style
|
||||
evch chan Event
|
||||
quit chan struct{}
|
||||
|
||||
front []SimCell
|
||||
back CellBuffer
|
||||
clear bool
|
||||
cursorx int
|
||||
cursory int
|
||||
cursorvis bool
|
||||
mouse bool
|
||||
paste bool
|
||||
charset string
|
||||
encoder transform.Transformer
|
||||
decoder transform.Transformer
|
||||
fillchar rune
|
||||
fillstyle Style
|
||||
fallback map[rune]string
|
||||
title string
|
||||
clipboard []byte
|
||||
|
||||
Screen
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func (s *simscreen) Init() error {
|
||||
s.evch = make(chan Event, 10)
|
||||
s.quit = make(chan struct{})
|
||||
s.fillchar = 'X'
|
||||
s.fillstyle = StyleDefault
|
||||
s.mouse = false
|
||||
s.physw = 80
|
||||
s.physh = 25
|
||||
s.cursorx = -1
|
||||
s.cursory = -1
|
||||
s.style = StyleDefault
|
||||
|
||||
if enc := GetEncoding(s.charset); enc != nil {
|
||||
s.encoder = enc.NewEncoder()
|
||||
s.decoder = enc.NewDecoder()
|
||||
} else {
|
||||
return ErrNoCharset
|
||||
}
|
||||
|
||||
s.front = make([]SimCell, s.physw*s.physh)
|
||||
s.back.Resize(80, 25)
|
||||
|
||||
// default fallbacks
|
||||
s.fallback = make(map[rune]string)
|
||||
for k, v := range RuneFallbacks {
|
||||
s.fallback[k] = v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *simscreen) Fini() {
|
||||
s.Lock()
|
||||
s.fini = true
|
||||
s.back.Resize(0, 0)
|
||||
s.Unlock()
|
||||
if s.quit != nil {
|
||||
close(s.quit)
|
||||
}
|
||||
s.physw = 0
|
||||
s.physh = 0
|
||||
s.front = nil
|
||||
}
|
||||
|
||||
func (s *simscreen) SetStyle(style Style) {
|
||||
s.Lock()
|
||||
s.style = style
|
||||
s.Unlock()
|
||||
}
|
||||
|
||||
func (s *simscreen) drawCell(x, y int) int {
|
||||
|
||||
mainc, combc, style, width := s.back.GetContent(x, y)
|
||||
if !s.back.Dirty(x, y) {
|
||||
return width
|
||||
}
|
||||
if x >= s.physw || y >= s.physh || x < 0 || y < 0 {
|
||||
return width
|
||||
}
|
||||
simc := &s.front[(y*s.physw)+x]
|
||||
|
||||
if style == StyleDefault {
|
||||
style = s.style
|
||||
}
|
||||
simc.Style = style
|
||||
simc.Runes = append([]rune{mainc}, combc...)
|
||||
|
||||
// now emit runes - taking care to not overrun width with a
|
||||
// wide character, and to ensure that we emit exactly one regular
|
||||
// character followed up by any residual combing characters
|
||||
|
||||
simc.Bytes = nil
|
||||
|
||||
if x > s.physw-width {
|
||||
simc.Runes = []rune{' '}
|
||||
simc.Bytes = []byte{' '}
|
||||
return width
|
||||
}
|
||||
|
||||
lbuf := make([]byte, 12)
|
||||
ubuf := make([]byte, 12)
|
||||
nout := 0
|
||||
|
||||
for _, r := range simc.Runes {
|
||||
|
||||
l := utf8.EncodeRune(ubuf, r)
|
||||
|
||||
nout, _, _ = s.encoder.Transform(lbuf, ubuf[:l], true)
|
||||
|
||||
if nout == 0 || lbuf[0] == '\x1a' {
|
||||
|
||||
// skip combining
|
||||
|
||||
if subst, ok := s.fallback[r]; ok {
|
||||
simc.Bytes = append(simc.Bytes,
|
||||
[]byte(subst)...)
|
||||
|
||||
} else if r >= ' ' && r <= '~' {
|
||||
simc.Bytes = append(simc.Bytes, byte(r))
|
||||
|
||||
} else if simc.Bytes == nil {
|
||||
simc.Bytes = append(simc.Bytes, '?')
|
||||
}
|
||||
} else {
|
||||
simc.Bytes = append(simc.Bytes, lbuf[:nout]...)
|
||||
}
|
||||
}
|
||||
s.back.SetDirty(x, y, false)
|
||||
return width
|
||||
}
|
||||
|
||||
func (s *simscreen) ShowCursor(x, y int) {
|
||||
s.Lock()
|
||||
s.cursorx, s.cursory = x, y
|
||||
s.showCursor()
|
||||
s.Unlock()
|
||||
}
|
||||
|
||||
func (s *simscreen) HideCursor() {
|
||||
s.ShowCursor(-1, -1)
|
||||
}
|
||||
|
||||
func (s *simscreen) showCursor() {
|
||||
|
||||
x, y := s.cursorx, s.cursory
|
||||
if x < 0 || y < 0 || x >= s.physw || y >= s.physh {
|
||||
s.cursorvis = false
|
||||
} else {
|
||||
s.cursorvis = true
|
||||
}
|
||||
}
|
||||
|
||||
func (s *simscreen) hideCursor() {
|
||||
// does not update cursor position
|
||||
s.cursorvis = false
|
||||
}
|
||||
|
||||
func (s *simscreen) SetCursor(CursorStyle, Color) {}
|
||||
|
||||
func (s *simscreen) Show() {
|
||||
s.Lock()
|
||||
s.resize()
|
||||
s.draw()
|
||||
s.Unlock()
|
||||
}
|
||||
|
||||
func (s *simscreen) clearScreen() {
|
||||
// We emulate a hardware clear by filling with a specific pattern
|
||||
for i := range s.front {
|
||||
s.front[i].Style = s.fillstyle
|
||||
s.front[i].Runes = []rune{s.fillchar}
|
||||
s.front[i].Bytes = []byte{byte(s.fillchar)}
|
||||
}
|
||||
s.clear = false
|
||||
}
|
||||
|
||||
func (s *simscreen) draw() {
|
||||
s.hideCursor()
|
||||
if s.clear {
|
||||
s.clearScreen()
|
||||
}
|
||||
|
||||
w, h := s.back.Size()
|
||||
for y := 0; y < h; y++ {
|
||||
for x := 0; x < w; x++ {
|
||||
width := s.drawCell(x, y)
|
||||
x += width - 1
|
||||
}
|
||||
}
|
||||
s.showCursor()
|
||||
}
|
||||
|
||||
func (s *simscreen) EnableMouse(...MouseFlags) {
|
||||
s.mouse = true
|
||||
}
|
||||
|
||||
func (s *simscreen) DisableMouse() {
|
||||
s.mouse = false
|
||||
}
|
||||
|
||||
func (s *simscreen) EnablePaste() {
|
||||
s.paste = true
|
||||
}
|
||||
|
||||
func (s *simscreen) DisablePaste() {
|
||||
s.paste = false
|
||||
}
|
||||
|
||||
func (s *simscreen) EnableFocus() {
|
||||
}
|
||||
|
||||
func (s *simscreen) DisableFocus() {
|
||||
}
|
||||
|
||||
func (s *simscreen) Size() (int, int) {
|
||||
s.Lock()
|
||||
w, h := s.back.Size()
|
||||
s.Unlock()
|
||||
return w, h
|
||||
}
|
||||
|
||||
func (s *simscreen) resize() {
|
||||
w, h := s.physw, s.physh
|
||||
ow, oh := s.back.Size()
|
||||
if w != ow || h != oh {
|
||||
s.back.Resize(w, h)
|
||||
ev := NewEventResize(w, h)
|
||||
s.postEvent(ev)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *simscreen) Colors() int {
|
||||
return 256
|
||||
}
|
||||
|
||||
func (s *simscreen) postEvent(ev Event) {
|
||||
select {
|
||||
case s.evch <- ev:
|
||||
case <-s.quit:
|
||||
}
|
||||
}
|
||||
|
||||
func (s *simscreen) InjectMouse(x, y int, buttons ButtonMask, mod ModMask) {
|
||||
ev := NewEventMouse(x, y, buttons, mod)
|
||||
s.postEvent(ev)
|
||||
}
|
||||
|
||||
func (s *simscreen) InjectKey(key Key, r rune, mod ModMask) {
|
||||
ev := NewEventKey(key, r, mod)
|
||||
s.postEvent(ev)
|
||||
}
|
||||
|
||||
func (s *simscreen) InjectKeyBytes(b []byte) bool {
|
||||
failed := false
|
||||
|
||||
outer:
|
||||
for len(b) > 0 {
|
||||
if b[0] >= ' ' && b[0] <= 0x7F {
|
||||
// printable ASCII easy to deal with -- no encodings
|
||||
ev := NewEventKey(KeyRune, rune(b[0]), ModNone)
|
||||
s.postEvent(ev)
|
||||
b = b[1:]
|
||||
continue
|
||||
}
|
||||
|
||||
if b[0] < 0x80 {
|
||||
// No encodings start with low numbered values
|
||||
if b[0] > 0 && b[0] < ' ' { // control keys
|
||||
switch Key(b[0]) {
|
||||
case KeyESC, KeyEnter, KeyTAB:
|
||||
s.postEvent(NewEventKey(Key(b[0]), 0, 0))
|
||||
continue;
|
||||
default:
|
||||
s.postEvent(NewEventKey(Key(b[0]), rune(b[0])+'\x60', ModCtrl))
|
||||
continue
|
||||
}
|
||||
}
|
||||
mod := ModNone
|
||||
ev := NewEventKey(Key(b[0]), 0, mod)
|
||||
s.postEvent(ev)
|
||||
b = b[1:]
|
||||
continue
|
||||
}
|
||||
|
||||
utfb := make([]byte, len(b)*4) // worst case
|
||||
for l := 1; l < len(b); l++ {
|
||||
s.decoder.Reset()
|
||||
nout, nin, _ := s.decoder.Transform(utfb, b[:l], true)
|
||||
|
||||
if nout != 0 {
|
||||
r, _ := utf8.DecodeRune(utfb[:nout])
|
||||
if r != utf8.RuneError {
|
||||
ev := NewEventKey(KeyRune, r, ModNone)
|
||||
s.postEvent(ev)
|
||||
}
|
||||
b = b[nin:]
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
failed = true
|
||||
b = b[1:]
|
||||
continue
|
||||
}
|
||||
|
||||
return !failed
|
||||
}
|
||||
|
||||
func (s *simscreen) Sync() {
|
||||
s.Lock()
|
||||
s.clear = true
|
||||
s.resize()
|
||||
s.back.Invalidate()
|
||||
s.draw()
|
||||
s.Unlock()
|
||||
}
|
||||
|
||||
func (s *simscreen) CharacterSet() string {
|
||||
return s.charset
|
||||
}
|
||||
|
||||
func (s *simscreen) SetSize(w, h int) {
|
||||
s.Lock()
|
||||
newc := make([]SimCell, w*h)
|
||||
for row := 0; row < h && row < s.physh; row++ {
|
||||
for col := 0; col < w && col < s.physw; col++ {
|
||||
newc[(row*w)+col] = s.front[(row*s.physw)+col]
|
||||
}
|
||||
}
|
||||
s.cursorx, s.cursory = -1, -1
|
||||
s.physw, s.physh = w, h
|
||||
s.front = newc
|
||||
s.back.Resize(w, h)
|
||||
s.Unlock()
|
||||
}
|
||||
|
||||
func (s *simscreen) GetContents() ([]SimCell, int, int) {
|
||||
s.Lock()
|
||||
cells, w, h := s.front, s.physw, s.physh
|
||||
s.Unlock()
|
||||
return cells, w, h
|
||||
}
|
||||
|
||||
func (s *simscreen) GetCursor() (int, int, bool) {
|
||||
s.Lock()
|
||||
x, y, vis := s.cursorx, s.cursory, s.cursorvis
|
||||
s.Unlock()
|
||||
return x, y, vis
|
||||
}
|
||||
|
||||
func (s *simscreen) RegisterRuneFallback(r rune, subst string) {
|
||||
s.Lock()
|
||||
s.fallback[r] = subst
|
||||
s.Unlock()
|
||||
}
|
||||
|
||||
func (s *simscreen) UnregisterRuneFallback(r rune) {
|
||||
s.Lock()
|
||||
delete(s.fallback, r)
|
||||
s.Unlock()
|
||||
}
|
||||
|
||||
func (s *simscreen) CanDisplay(r rune, checkFallbacks bool) bool {
|
||||
|
||||
if enc := s.encoder; enc != nil {
|
||||
nb := make([]byte, 6)
|
||||
ob := make([]byte, 6)
|
||||
num := utf8.EncodeRune(ob, r)
|
||||
|
||||
enc.Reset()
|
||||
dst, _, err := enc.Transform(nb, ob[:num], true)
|
||||
if dst != 0 && err == nil && nb[0] != '\x1A' {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if !checkFallbacks {
|
||||
return false
|
||||
}
|
||||
if _, ok := s.fallback[r]; ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *simscreen) HasMouse() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *simscreen) Resize(int, int, int, int) {}
|
||||
|
||||
func (s *simscreen) HasKey(Key) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *simscreen) Beep() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *simscreen) Suspend() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *simscreen) Resume() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *simscreen) Tty() (Tty, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (s *simscreen) GetCells() *CellBuffer {
|
||||
return &s.back
|
||||
}
|
||||
|
||||
func (s *simscreen) EventQ() chan Event {
|
||||
return s.evch
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
1
vendor/github.com/gdamore/tcell/v2/terminfo/.gitignore
generated
vendored
1
vendor/github.com/gdamore/tcell/v2/terminfo/.gitignore
generated
vendored
|
|
@ -1 +0,0 @@
|
|||
mkinfo
|
||||
25
vendor/github.com/gdamore/tcell/v2/terminfo/README.md
generated
vendored
25
vendor/github.com/gdamore/tcell/v2/terminfo/README.md
generated
vendored
|
|
@ -1,25 +0,0 @@
|
|||
This package represents the parent for all terminals.
|
||||
|
||||
In older versions of tcell we had (a couple of) different
|
||||
external file formats for the terminal database. Those are
|
||||
now removed. All terminal definitions are supplied by
|
||||
one of two methods:
|
||||
|
||||
1. Compiled Go code
|
||||
|
||||
2. For systems with terminfo and infocmp, dynamically
|
||||
generated at runtime.
|
||||
|
||||
The Go code can be generated using the mkinfo utility in
|
||||
this directory. The database entry should be generated
|
||||
into a package in a directory named as the first character
|
||||
of the package name. (This permits us to group them all
|
||||
without having a huge directory of little packages.)
|
||||
|
||||
It may be desirable to add new packages to the extended
|
||||
package, or -- rarely -- the base package.
|
||||
|
||||
Applications which want to have the large set of terminal
|
||||
descriptions built into the binary can simply import the
|
||||
extended package. Otherwise a smaller reasonable default
|
||||
set (the base package) will be included instead.
|
||||
7
vendor/github.com/gdamore/tcell/v2/terminfo/TERMINALS.md
generated
vendored
7
vendor/github.com/gdamore/tcell/v2/terminfo/TERMINALS.md
generated
vendored
|
|
@ -1,7 +0,0 @@
|
|||
TERMINALS
|
||||
=========
|
||||
|
||||
The best way to populate terminals on Debian is to install ncurses,
|
||||
ncurses-term, screen, tmux, rxvt-unicode, and dvtm. This populates the
|
||||
the terminfo database so that we can have a reasonable set of starting
|
||||
terminals.
|
||||
31
vendor/github.com/gdamore/tcell/v2/terminfo/a/aixterm/term.go
generated
vendored
31
vendor/github.com/gdamore/tcell/v2/terminfo/a/aixterm/term.go
generated
vendored
|
|
@ -1,31 +0,0 @@
|
|||
// Generated automatically. DO NOT HAND-EDIT.
|
||||
|
||||
package aixterm
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// IBM Aixterm Terminal Emulator
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "aixterm",
|
||||
Columns: 80,
|
||||
Lines: 25,
|
||||
Colors: 8,
|
||||
Clear: "\x1b[H\x1b[J",
|
||||
AttrOff: "\x1b[0;10m\x1b(B",
|
||||
Underline: "\x1b[4m",
|
||||
Bold: "\x1b[1m",
|
||||
Reverse: "\x1b[7m",
|
||||
SetFg: "\x1b[3%p1%dm",
|
||||
SetBg: "\x1b[4%p1%dm",
|
||||
SetFgBg: "\x1b[3%p1%d;4%p2%dm",
|
||||
ResetFgBg: "\x1b[32m\x1b[40m",
|
||||
PadChar: "\x00",
|
||||
AltChars: "jjkkllmmnnqqttuuvvwwxx",
|
||||
EnterAcs: "\x1b(0",
|
||||
ExitAcs: "\x1b(B",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
})
|
||||
}
|
||||
41
vendor/github.com/gdamore/tcell/v2/terminfo/a/alacritty/direct.go
generated
vendored
41
vendor/github.com/gdamore/tcell/v2/terminfo/a/alacritty/direct.go
generated
vendored
|
|
@ -1,41 +0,0 @@
|
|||
// Generated automatically. DO NOT HAND-EDIT.
|
||||
|
||||
package alacritty
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// alacritty with direct color indexing
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "alacritty-direct",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 16777216,
|
||||
Clear: "\x1b[H\x1b[2J",
|
||||
EnterCA: "\x1b[?1049h\x1b[22;0;0t",
|
||||
ExitCA: "\x1b[?1049l\x1b[23;0;0t",
|
||||
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",
|
||||
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: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||
EnterAcs: "\x1b(0",
|
||||
ExitAcs: "\x1b(B",
|
||||
StrikeThrough: "\x1b[9m",
|
||||
Mouse: "\x1b[M",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
TrueColor: true,
|
||||
AutoMargin: true,
|
||||
})
|
||||
}
|
||||
44
vendor/github.com/gdamore/tcell/v2/terminfo/a/alacritty/term.go
generated
vendored
44
vendor/github.com/gdamore/tcell/v2/terminfo/a/alacritty/term.go
generated
vendored
|
|
@ -1,44 +0,0 @@
|
|||
// Generated automatically. DO NOT HAND-EDIT.
|
||||
|
||||
package alacritty
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// alacritty terminal emulator
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "alacritty",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 256,
|
||||
Clear: "\x1b[H\x1b[2J",
|
||||
EnterCA: "\x1b[?1049h\x1b[22;0;0t",
|
||||
ExitCA: "\x1b[?1049l\x1b[23;0;0t",
|
||||
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: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||
EnterAcs: "\x1b(0",
|
||||
ExitAcs: "\x1b(B",
|
||||
EnableAutoMargin: "\x1b[?7h",
|
||||
DisableAutoMargin: "\x1b[?7l",
|
||||
StrikeThrough: "\x1b[9m",
|
||||
Mouse: "\x1b[<",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
XTermLike: true,
|
||||
})
|
||||
}
|
||||
32
vendor/github.com/gdamore/tcell/v2/terminfo/a/ansi/term.go
generated
vendored
32
vendor/github.com/gdamore/tcell/v2/terminfo/a/ansi/term.go
generated
vendored
|
|
@ -1,32 +0,0 @@
|
|||
// Generated automatically. DO NOT HAND-EDIT.
|
||||
|
||||
package ansi
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// ansi/pc-term compatible with color
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "ansi",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 8,
|
||||
Clear: "\x1b[H\x1b[J",
|
||||
AttrOff: "\x1b[0;10m",
|
||||
Underline: "\x1b[4m",
|
||||
Bold: "\x1b[1m",
|
||||
Blink: "\x1b[5m",
|
||||
Reverse: "\x1b[7m",
|
||||
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: "+\x10,\x11-\x18.\x190\xdb`\x04a\xb1f\xf8g\xf1h\xb0j\xd9k\xbfl\xdam\xc0n\xc5o~p\xc4q\xc4r\xc4s_t\xc3u\xb4v\xc1w\xc2x\xb3y\xf3z\xf2{\xe3|\xd8}\x9c~\xfe",
|
||||
EnterAcs: "\x1b[11m",
|
||||
ExitAcs: "\x1b[10m",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
})
|
||||
}
|
||||
33
vendor/github.com/gdamore/tcell/v2/terminfo/base/base.go
generated
vendored
33
vendor/github.com/gdamore/tcell/v2/terminfo/base/base.go
generated
vendored
|
|
@ -1,33 +0,0 @@
|
|||
// Copyright 2020 The TCell Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use file except in compliance with the License.
|
||||
// You may obtain a copy of the license at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// This is just a "minimalist" set of the base terminal descriptions.
|
||||
// It should be sufficient for most applications.
|
||||
|
||||
// Package base contains the base terminal descriptions that are likely
|
||||
// to be needed by any stock application. It is imported by default in the
|
||||
// terminfo package, so terminal types listed here will be available to any
|
||||
// tcell application.
|
||||
package base
|
||||
|
||||
import (
|
||||
// The following imports just register themselves --
|
||||
// these are the terminal types we aggregate in this package.
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/a/ansi"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/t/tmux"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/v/vt100"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/v/vt102"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/v/vt220"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/x/xterm"
|
||||
)
|
||||
32
vendor/github.com/gdamore/tcell/v2/terminfo/c/cygwin/term.go
generated
vendored
32
vendor/github.com/gdamore/tcell/v2/terminfo/c/cygwin/term.go
generated
vendored
|
|
@ -1,32 +0,0 @@
|
|||
// Generated automatically. DO NOT HAND-EDIT.
|
||||
|
||||
package cygwin
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// ANSI emulation for Cygwin
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "cygwin",
|
||||
Colors: 8,
|
||||
Clear: "\x1b[H\x1b[J",
|
||||
EnterCA: "\x1b7\x1b[?47h",
|
||||
ExitCA: "\x1b[2J\x1b[?47l\x1b8",
|
||||
AttrOff: "\x1b[0;10m",
|
||||
Underline: "\x1b[4m",
|
||||
Bold: "\x1b[1m",
|
||||
Reverse: "\x1b[7m",
|
||||
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: "+\x10,\x11-\x18.\x190\xdb`\x04a\xb1f\xf8g\xf1h\xb0j\xd9k\xbfl\xdam\xc0n\xc5o~p\xc4q\xc4r\xc4s_t\xc3u\xb4v\xc1w\xc2x\xb3y\xf3z\xf2{\xe3|\xd8}\x9c~\xfe",
|
||||
EnterAcs: "\x1b[11m",
|
||||
ExitAcs: "\x1b[10m",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
InsertChar: "\x1b[@",
|
||||
})
|
||||
}
|
||||
38
vendor/github.com/gdamore/tcell/v2/terminfo/d/dtterm/term.go
generated
vendored
38
vendor/github.com/gdamore/tcell/v2/terminfo/d/dtterm/term.go
generated
vendored
|
|
@ -1,38 +0,0 @@
|
|||
// Generated automatically. DO NOT HAND-EDIT.
|
||||
|
||||
package dtterm
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// CDE desktop terminal
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "dtterm",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 8,
|
||||
Clear: "\x1b[H\x1b[J",
|
||||
ShowCursor: "\x1b[?25h",
|
||||
HideCursor: "\x1b[?25l",
|
||||
AttrOff: "\x1b[m\x0f",
|
||||
Underline: "\x1b[4m",
|
||||
Bold: "\x1b[1m",
|
||||
Dim: "\x1b[2m",
|
||||
Blink: "\x1b[5m",
|
||||
Reverse: "\x1b[7m",
|
||||
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: "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||
EnterAcs: "\x0e",
|
||||
ExitAcs: "\x0f",
|
||||
EnableAcs: "\x1b(B\x1b)0",
|
||||
EnableAutoMargin: "\x1b[?7h",
|
||||
DisableAutoMargin: "\x1b[?7l",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
})
|
||||
}
|
||||
266
vendor/github.com/gdamore/tcell/v2/terminfo/dynamic/dynamic.go
generated
vendored
266
vendor/github.com/gdamore/tcell/v2/terminfo/dynamic/dynamic.go
generated
vendored
|
|
@ -1,266 +0,0 @@
|
|||
// Copyright 2021 The TCell Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use file except in compliance with the License.
|
||||
// You may obtain a copy of the license at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// The dynamic package is used to generate a terminal description dynamically,
|
||||
// using infocmp. This is really a method of last resort, as the performance
|
||||
// will be slow, and it requires a working infocmp. But, the hope is that it
|
||||
// will assist folks who have to deal with a terminal description that isn't
|
||||
// already built in. This requires infocmp to be in the user's path, and to
|
||||
// support reasonably the -1 option.
|
||||
|
||||
package dynamic
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gdamore/tcell/v2/terminfo"
|
||||
)
|
||||
|
||||
type termcap struct {
|
||||
name string
|
||||
desc string
|
||||
aliases []string
|
||||
bools map[string]bool
|
||||
nums map[string]int
|
||||
strs map[string]string
|
||||
}
|
||||
|
||||
func (tc *termcap) getnum(s string) int {
|
||||
return (tc.nums[s])
|
||||
}
|
||||
|
||||
func (tc *termcap) getflag(s string) bool {
|
||||
return (tc.bools[s])
|
||||
}
|
||||
|
||||
func (tc *termcap) getstr(s string) string {
|
||||
return (tc.strs[s])
|
||||
}
|
||||
|
||||
const (
|
||||
none = iota
|
||||
control
|
||||
escaped
|
||||
)
|
||||
|
||||
var errNotAddressable = errors.New("terminal not cursor addressable")
|
||||
|
||||
func unescape(s string) string {
|
||||
// Various escapes are in \x format. Control codes are
|
||||
// encoded as ^M (carat followed by ASCII equivalent).
|
||||
// escapes are: \e, \E - escape
|
||||
// \0 NULL, \n \l \r \t \b \f \s for equivalent C escape.
|
||||
buf := &bytes.Buffer{}
|
||||
esc := none
|
||||
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
switch esc {
|
||||
case none:
|
||||
switch c {
|
||||
case '\\':
|
||||
esc = escaped
|
||||
case '^':
|
||||
esc = control
|
||||
default:
|
||||
buf.WriteByte(c)
|
||||
}
|
||||
case control:
|
||||
buf.WriteByte(c ^ 1<<6)
|
||||
esc = none
|
||||
case escaped:
|
||||
switch c {
|
||||
case 'E', 'e':
|
||||
buf.WriteByte(0x1b)
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7':
|
||||
if i+2 < len(s) && s[i+1] >= '0' && s[i+1] <= '7' && s[i+2] >= '0' && s[i+2] <= '7' {
|
||||
buf.WriteByte(((c - '0') * 64) + ((s[i+1] - '0') * 8) + (s[i+2] - '0'))
|
||||
i = i + 2
|
||||
} else if c == '0' {
|
||||
buf.WriteByte(0)
|
||||
}
|
||||
case 'n':
|
||||
buf.WriteByte('\n')
|
||||
case 'r':
|
||||
buf.WriteByte('\r')
|
||||
case 't':
|
||||
buf.WriteByte('\t')
|
||||
case 'b':
|
||||
buf.WriteByte('\b')
|
||||
case 'f':
|
||||
buf.WriteByte('\f')
|
||||
case 's':
|
||||
buf.WriteByte(' ')
|
||||
default:
|
||||
buf.WriteByte(c)
|
||||
}
|
||||
esc = none
|
||||
}
|
||||
}
|
||||
return (buf.String())
|
||||
}
|
||||
|
||||
func (tc *termcap) setupterm(name string) error {
|
||||
cmd := exec.Command("infocmp", "-1", name)
|
||||
output := &bytes.Buffer{}
|
||||
cmd.Stdout = output
|
||||
|
||||
tc.strs = make(map[string]string)
|
||||
tc.bools = make(map[string]bool)
|
||||
tc.nums = make(map[string]int)
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("couldn't open terminfo ($TERM) file for %s: %w", name, err)
|
||||
}
|
||||
|
||||
// Now parse the output.
|
||||
// We get comment lines (starting with "#"), followed by
|
||||
// a header line that looks like "<name>|<alias>|...|<desc>"
|
||||
// then capabilities, one per line, starting with a tab and ending
|
||||
// with a comma and newline.
|
||||
lines := strings.Split(output.String(), "\n")
|
||||
for len(lines) > 0 && strings.HasPrefix(lines[0], "#") {
|
||||
lines = lines[1:]
|
||||
}
|
||||
|
||||
// Ditch trailing empty last line
|
||||
if lines[len(lines)-1] == "" {
|
||||
lines = lines[:len(lines)-1]
|
||||
}
|
||||
header := lines[0]
|
||||
header = strings.TrimSuffix(header, ",")
|
||||
names := strings.Split(header, "|")
|
||||
tc.name = names[0]
|
||||
names = names[1:]
|
||||
if len(names) > 0 {
|
||||
tc.desc = names[len(names)-1]
|
||||
names = names[:len(names)-1]
|
||||
}
|
||||
tc.aliases = names
|
||||
for _, val := range lines[1:] {
|
||||
if (!strings.HasPrefix(val, "\t")) ||
|
||||
(!strings.HasSuffix(val, ",")) {
|
||||
return (errors.New("malformed infocmp: " + val))
|
||||
}
|
||||
|
||||
val = val[1:]
|
||||
val = val[:len(val)-1]
|
||||
|
||||
if k := strings.SplitN(val, "=", 2); len(k) == 2 {
|
||||
tc.strs[k[0]] = unescape(k[1])
|
||||
} else if k := strings.SplitN(val, "#", 2); len(k) == 2 {
|
||||
u, err := strconv.ParseUint(k[1], 0, 0)
|
||||
if err != nil {
|
||||
return (err)
|
||||
}
|
||||
tc.nums[k[0]] = int(u)
|
||||
} else {
|
||||
tc.bools[val] = true
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadTerminfo creates a Terminfo by for named terminal by attempting to parse
|
||||
// the output from infocmp. This returns the terminfo entry, a description of
|
||||
// the terminal, and either nil or an error.
|
||||
func LoadTerminfo(name string) (*terminfo.Terminfo, string, error) {
|
||||
var tc termcap
|
||||
if err := tc.setupterm(name); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
t := &terminfo.Terminfo{}
|
||||
t.Name = tc.name
|
||||
t.Aliases = tc.aliases
|
||||
t.Colors = tc.getnum("colors")
|
||||
t.Columns = tc.getnum("cols")
|
||||
t.Lines = tc.getnum("lines")
|
||||
t.Clear = tc.getstr("clear")
|
||||
t.EnterCA = tc.getstr("smcup")
|
||||
t.ExitCA = tc.getstr("rmcup")
|
||||
t.ShowCursor = tc.getstr("cnorm")
|
||||
t.HideCursor = tc.getstr("civis")
|
||||
t.AttrOff = tc.getstr("sgr0")
|
||||
t.Underline = tc.getstr("smul")
|
||||
t.Bold = tc.getstr("bold")
|
||||
t.Blink = tc.getstr("blink")
|
||||
t.Dim = tc.getstr("dim")
|
||||
t.Italic = tc.getstr("sitm")
|
||||
t.Reverse = tc.getstr("rev")
|
||||
t.EnterKeypad = tc.getstr("smkx")
|
||||
t.ExitKeypad = tc.getstr("rmkx")
|
||||
t.SetFg = tc.getstr("setaf")
|
||||
t.SetBg = tc.getstr("setab")
|
||||
t.SetCursor = tc.getstr("cup")
|
||||
t.AltChars = tc.getstr("acsc")
|
||||
t.EnterAcs = tc.getstr("smacs")
|
||||
t.ExitAcs = tc.getstr("rmacs")
|
||||
t.EnableAcs = tc.getstr("enacs")
|
||||
t.Mouse = tc.getstr("kmous")
|
||||
|
||||
// Technically the RGB flag that is provided for xterm-direct is not
|
||||
// quite right. The problem is that the -direct flag that was introduced
|
||||
// with ncurses 6.1 requires a parsing for the parameters that we lack.
|
||||
// For this case we'll just assume it's XTerm compatible. Someday this
|
||||
// may be incorrect, but right now it is correct, and nobody uses it
|
||||
// anyway.
|
||||
if tc.getflag("Tc") {
|
||||
// This presumes XTerm 24-bit true color.
|
||||
t.TrueColor = true
|
||||
} else if tc.getflag("RGB") {
|
||||
// This is for xterm-direct, which uses a different scheme entirely.
|
||||
// (ncurses went a very different direction from everyone else, and
|
||||
// so it's unlikely anything is using this definition.)
|
||||
t.TrueColor = true
|
||||
t.SetBg = "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m"
|
||||
t.SetFg = "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m"
|
||||
}
|
||||
|
||||
// We only support colors in ANSI 8 or 256 color mode.
|
||||
if t.Colors < 8 || t.SetFg == "" {
|
||||
t.Colors = 0
|
||||
}
|
||||
if t.SetCursor == "" {
|
||||
return nil, "", errNotAddressable
|
||||
}
|
||||
|
||||
// For padding, we lookup the pad char. If that isn't present,
|
||||
// and npc is *not* set, then we assume a null byte.
|
||||
t.PadChar = tc.getstr("pad")
|
||||
if t.PadChar == "" {
|
||||
if !tc.getflag("npc") {
|
||||
t.PadChar = "\u0000"
|
||||
}
|
||||
}
|
||||
|
||||
// For terminals that use "standard" SGR sequences, lets combine the
|
||||
// foreground and background together.
|
||||
if strings.HasPrefix(t.SetFg, "\x1b[") &&
|
||||
strings.HasPrefix(t.SetBg, "\x1b[") &&
|
||||
strings.HasSuffix(t.SetFg, "m") &&
|
||||
strings.HasSuffix(t.SetBg, "m") {
|
||||
fg := t.SetFg[:len(t.SetFg)-1]
|
||||
r := regexp.MustCompile("%p1")
|
||||
bg := r.ReplaceAllString(t.SetBg[2:], "%p2")
|
||||
t.SetFgBg = fg + ";" + bg
|
||||
}
|
||||
|
||||
return t, tc.desc, nil
|
||||
}
|
||||
48
vendor/github.com/gdamore/tcell/v2/terminfo/e/emacs/term.go
generated
vendored
48
vendor/github.com/gdamore/tcell/v2/terminfo/e/emacs/term.go
generated
vendored
|
|
@ -1,48 +0,0 @@
|
|||
// Generated automatically. DO NOT HAND-EDIT.
|
||||
|
||||
package emacs
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// GNU Emacs term.el terminal emulation
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "eterm",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Clear: "\x1b[H\x1b[J",
|
||||
EnterCA: "\x1b7\x1b[?47h",
|
||||
ExitCA: "\x1b[2J\x1b[?47l\x1b8",
|
||||
AttrOff: "\x1b[m",
|
||||
Underline: "\x1b[4m",
|
||||
Bold: "\x1b[1m",
|
||||
Reverse: "\x1b[7m",
|
||||
PadChar: "\x00",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
})
|
||||
|
||||
// Emacs term.el terminal emulator term-protocol-version 0.96
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "eterm-color",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 8,
|
||||
Clear: "\x1b[H\x1b[J",
|
||||
EnterCA: "\x1b7\x1b[?47h",
|
||||
ExitCA: "\x1b[2J\x1b[?47l\x1b8",
|
||||
AttrOff: "\x1b[m",
|
||||
Underline: "\x1b[4m",
|
||||
Bold: "\x1b[1m",
|
||||
Blink: "\x1b[5m",
|
||||
Reverse: "\x1b[7m",
|
||||
SetFg: "\x1b[%p1%{30}%+%dm",
|
||||
SetBg: "\x1b[%p1%'('%+%dm",
|
||||
SetFgBg: "\x1b[%p1%{30}%+%d;%p2%'('%+%dm",
|
||||
ResetFgBg: "\x1b[39;49m",
|
||||
PadChar: "\x00",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
})
|
||||
}
|
||||
51
vendor/github.com/gdamore/tcell/v2/terminfo/extended/extended.go
generated
vendored
51
vendor/github.com/gdamore/tcell/v2/terminfo/extended/extended.go
generated
vendored
|
|
@ -1,51 +0,0 @@
|
|||
// 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.
|
||||
// You may obtain a copy of the license at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package extended contains an extended set of terminal descriptions.
|
||||
// Applications desiring to have a better chance of Just Working by
|
||||
// default should include this package. This will significantly increase
|
||||
// the size of the program.
|
||||
package extended
|
||||
|
||||
import (
|
||||
// The following imports just register themselves --
|
||||
// these are the terminal types we aggregate in this package.
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/a/aixterm"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/a/alacritty"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/a/ansi"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/c/cygwin"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/d/dtterm"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/e/emacs"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/f/foot"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/g/gnome"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/k/konsole"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/k/kterm"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/l/linux"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/p/pcansi"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/r/rxvt"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/s/screen"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/s/simpleterm"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/s/sun"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/t/tmux"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/v/vt100"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/v/vt102"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/v/vt220"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/v/vt320"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/v/vt400"
|
||||
_ "github.com/gdamore/tcell/v2/terminfo/v/vt420"
|
||||
_ "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"
|
||||
)
|
||||
42
vendor/github.com/gdamore/tcell/v2/terminfo/f/foot/foot.go
generated
vendored
42
vendor/github.com/gdamore/tcell/v2/terminfo/f/foot/foot.go
generated
vendored
|
|
@ -1,42 +0,0 @@
|
|||
// Generated automatically. DO NOT HAND-EDIT.
|
||||
|
||||
package foot
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// foot terminal emulator
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "foot",
|
||||
Aliases: []string{"foot-extra"},
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 256,
|
||||
Clear: "\x1b[H\x1b[2J",
|
||||
EnterCA: "\x1b[?1049h\x1b[22;0;0t",
|
||||
ExitCA: "\x1b[?1049l\x1b[23;0;0t",
|
||||
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: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||
EnterAcs: "\x1b(0",
|
||||
ExitAcs: "\x1b(B",
|
||||
StrikeThrough: "\x1b[9m",
|
||||
Mouse: "\x1b[M",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
})
|
||||
}
|
||||
80
vendor/github.com/gdamore/tcell/v2/terminfo/g/gnome/term.go
generated
vendored
80
vendor/github.com/gdamore/tcell/v2/terminfo/g/gnome/term.go
generated
vendored
|
|
@ -1,80 +0,0 @@
|
|||
// Generated automatically. DO NOT HAND-EDIT.
|
||||
|
||||
package gnome
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// GNOME Terminal
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "gnome",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 8,
|
||||
Clear: "\x1b[H\x1b[2J",
|
||||
EnterCA: "\x1b7\x1b[?47h",
|
||||
ExitCA: "\x1b[2J\x1b[?47l\x1b8",
|
||||
ShowCursor: "\x1b[?25h",
|
||||
HideCursor: "\x1b[?25l",
|
||||
AttrOff: "\x1b[0m\x0f",
|
||||
Underline: "\x1b[4m",
|
||||
Bold: "\x1b[1m",
|
||||
Dim: "\x1b[2m",
|
||||
Italic: "\x1b[3m",
|
||||
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: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||
EnterAcs: "\x0e",
|
||||
ExitAcs: "\x0f",
|
||||
EnableAcs: "\x1b)0",
|
||||
EnableAutoMargin: "\x1b[?7h",
|
||||
DisableAutoMargin: "\x1b[?7l",
|
||||
Mouse: "\x1b[M",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
XTermLike: true,
|
||||
})
|
||||
|
||||
// GNOME Terminal with xterm 256-colors
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "gnome-256color",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 256,
|
||||
Clear: "\x1b[H\x1b[2J",
|
||||
EnterCA: "\x1b7\x1b[?47h",
|
||||
ExitCA: "\x1b[2J\x1b[?47l\x1b8",
|
||||
ShowCursor: "\x1b[?25h",
|
||||
HideCursor: "\x1b[?25l",
|
||||
AttrOff: "\x1b[0m\x0f",
|
||||
Underline: "\x1b[4m",
|
||||
Bold: "\x1b[1m",
|
||||
Dim: "\x1b[2m",
|
||||
Italic: "\x1b[3m",
|
||||
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: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||
EnterAcs: "\x0e",
|
||||
ExitAcs: "\x0f",
|
||||
EnableAcs: "\x1b)0",
|
||||
EnableAutoMargin: "\x1b[?7h",
|
||||
DisableAutoMargin: "\x1b[?7l",
|
||||
Mouse: "\x1b[M",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
XTermLike: true,
|
||||
})
|
||||
}
|
||||
19
vendor/github.com/gdamore/tcell/v2/terminfo/gen.sh
generated
vendored
19
vendor/github.com/gdamore/tcell/v2/terminfo/gen.sh
generated
vendored
|
|
@ -1,19 +0,0 @@
|
|||
#!/bin/bash
|
||||
while read line
|
||||
do
|
||||
case "$line" in
|
||||
*'|'*)
|
||||
alias=${line#*|}
|
||||
line=${line%|*}
|
||||
;;
|
||||
*)
|
||||
alias=${line%%,*}
|
||||
;;
|
||||
esac
|
||||
|
||||
alias=${alias//-/_}
|
||||
direc=${alias:0:1}
|
||||
|
||||
mkdir -p ${direc}/${alias}
|
||||
go run mkinfo.go -P ${alias} -go ${direc}/${alias}/term.go ${line//,/ }
|
||||
done < models.txt
|
||||
82
vendor/github.com/gdamore/tcell/v2/terminfo/k/konsole/term.go
generated
vendored
82
vendor/github.com/gdamore/tcell/v2/terminfo/k/konsole/term.go
generated
vendored
|
|
@ -1,82 +0,0 @@
|
|||
// Generated automatically. DO NOT HAND-EDIT.
|
||||
|
||||
package konsole
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// KDE console window
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "konsole",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 8,
|
||||
Clear: "\x1b[H\x1b[2J",
|
||||
EnterCA: "\x1b7\x1b[?47h",
|
||||
ExitCA: "\x1b[2J\x1b[?47l\x1b8",
|
||||
ShowCursor: "\x1b[?25h",
|
||||
HideCursor: "\x1b[?25l",
|
||||
AttrOff: "\x1b[0m\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",
|
||||
AltChars: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||
EnterAcs: "\x0e",
|
||||
ExitAcs: "\x0f",
|
||||
EnableAcs: "\x1b)0",
|
||||
EnableAutoMargin: "\x1b[?7h",
|
||||
DisableAutoMargin: "\x1b[?7l",
|
||||
StrikeThrough: "\x1b[9m",
|
||||
Mouse: "\x1b[<",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
XTermLike: true,
|
||||
})
|
||||
|
||||
// KDE console window with xterm 256-colors
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "konsole-256color",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 256,
|
||||
Clear: "\x1b[H\x1b[2J",
|
||||
EnterCA: "\x1b7\x1b[?47h",
|
||||
ExitCA: "\x1b[2J\x1b[?47l\x1b8",
|
||||
ShowCursor: "\x1b[?25h",
|
||||
HideCursor: "\x1b[?25l",
|
||||
AttrOff: "\x1b[0m\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",
|
||||
AltChars: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||
EnterAcs: "\x0e",
|
||||
ExitAcs: "\x0f",
|
||||
EnableAcs: "\x1b)0",
|
||||
EnableAutoMargin: "\x1b[?7h",
|
||||
DisableAutoMargin: "\x1b[?7l",
|
||||
StrikeThrough: "\x1b[9m",
|
||||
Mouse: "\x1b[<",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
XTermLike: true,
|
||||
})
|
||||
}
|
||||
39
vendor/github.com/gdamore/tcell/v2/terminfo/k/kterm/term.go
generated
vendored
39
vendor/github.com/gdamore/tcell/v2/terminfo/k/kterm/term.go
generated
vendored
|
|
@ -1,39 +0,0 @@
|
|||
// Generated automatically. DO NOT HAND-EDIT.
|
||||
|
||||
package kterm
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// kterm kanji terminal emulator (X window system)
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "kterm",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 8,
|
||||
Clear: "\x1b[H\x1b[2J",
|
||||
EnterCA: "\x1b7\x1b[?47h",
|
||||
ExitCA: "\x1b[2J\x1b[?47l\x1b8",
|
||||
AttrOff: "\x1b[m\x1b(B",
|
||||
Underline: "\x1b[4m",
|
||||
Bold: "\x1b[1m",
|
||||
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: "``aajjkkllmmnnooppqqrrssttuuvvwwxx~~",
|
||||
EnterAcs: "\x1b(0",
|
||||
ExitAcs: "\x1b(B",
|
||||
EnableAutoMargin: "\x1b[?7h",
|
||||
DisableAutoMargin: "\x1b[?7l",
|
||||
Mouse: "\x1b[M",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
XTermLike: true,
|
||||
})
|
||||
}
|
||||
38
vendor/github.com/gdamore/tcell/v2/terminfo/l/linux/term.go
generated
vendored
38
vendor/github.com/gdamore/tcell/v2/terminfo/l/linux/term.go
generated
vendored
|
|
@ -1,38 +0,0 @@
|
|||
// Generated automatically. DO NOT HAND-EDIT.
|
||||
|
||||
package linux
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// Linux console
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "linux",
|
||||
Colors: 8,
|
||||
Clear: "\x1b[H\x1b[J",
|
||||
ShowCursor: "\x1b[?25h\x1b[?0c",
|
||||
HideCursor: "\x1b[?25l\x1b[?1c",
|
||||
AttrOff: "\x1b[m\x0f",
|
||||
Underline: "\x1b[4m",
|
||||
Bold: "\x1b[1m",
|
||||
Dim: "\x1b[2m",
|
||||
Blink: "\x1b[5m",
|
||||
Reverse: "\x1b[7m",
|
||||
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)0",
|
||||
EnableAutoMargin: "\x1b[?7h",
|
||||
DisableAutoMargin: "\x1b[?7l",
|
||||
Mouse: "\x1b[M",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
InsertChar: "\x1b[@",
|
||||
})
|
||||
}
|
||||
29
vendor/github.com/gdamore/tcell/v2/terminfo/models.txt
generated
vendored
29
vendor/github.com/gdamore/tcell/v2/terminfo/models.txt
generated
vendored
|
|
@ -1,29 +0,0 @@
|
|||
aixterm
|
||||
alacritty
|
||||
ansi
|
||||
cygwin
|
||||
dtterm
|
||||
eterm,eterm-color|emacs
|
||||
gnome,gnome-256color
|
||||
hpterm
|
||||
konsole,konsole-256color
|
||||
kterm
|
||||
linux
|
||||
pcansi
|
||||
rxvt,rxvt-256color,rxvt-88color,rxvt-unicode,rxvt-unicode-256color
|
||||
screen,screen-256color
|
||||
st,st-256color|simpleterm
|
||||
tmux,tmux-256color
|
||||
vt100
|
||||
vt102
|
||||
vt220
|
||||
vt320
|
||||
vt400
|
||||
vt420
|
||||
wy50
|
||||
wy60
|
||||
wy99-ansi,wy99a-ansi
|
||||
xfce
|
||||
xterm,xterm-88color,xterm-256color
|
||||
xterm-ghostty
|
||||
xterm-kitty
|
||||
32
vendor/github.com/gdamore/tcell/v2/terminfo/p/pcansi/term.go
generated
vendored
32
vendor/github.com/gdamore/tcell/v2/terminfo/p/pcansi/term.go
generated
vendored
|
|
@ -1,32 +0,0 @@
|
|||
// Generated automatically. DO NOT HAND-EDIT.
|
||||
|
||||
package pcansi
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// ibm-pc terminal programs claiming to be ANSI
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "pcansi",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 8,
|
||||
Clear: "\x1b[H\x1b[J",
|
||||
AttrOff: "\x1b[0;10m",
|
||||
Underline: "\x1b[4m",
|
||||
Bold: "\x1b[1m",
|
||||
Blink: "\x1b[5m",
|
||||
Reverse: "\x1b[7m",
|
||||
SetFg: "\x1b[3%p1%dm",
|
||||
SetBg: "\x1b[4%p1%dm",
|
||||
SetFgBg: "\x1b[3%p1%d;4%p2%dm",
|
||||
ResetFgBg: "\x1b[37;40m",
|
||||
PadChar: "\x00",
|
||||
AltChars: "+\x10,\x11-\x18.\x190\xdb`\x04a\xb1f\xf8g\xf1h\xb0j\xd9k\xbfl\xdam\xc0n\xc5o~p\xc4q\xc4r\xc4s_t\xc3u\xb4v\xc1w\xc2x\xb3y\xf3z\xf2{\xe3|\xd8}\x9c~\xfe",
|
||||
EnterAcs: "\x1b[12m",
|
||||
ExitAcs: "\x1b[10m",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
})
|
||||
}
|
||||
176
vendor/github.com/gdamore/tcell/v2/terminfo/r/rxvt/term.go
generated
vendored
176
vendor/github.com/gdamore/tcell/v2/terminfo/r/rxvt/term.go
generated
vendored
|
|
@ -1,176 +0,0 @@
|
|||
// Generated automatically. DO NOT HAND-EDIT.
|
||||
|
||||
package rxvt
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// rxvt terminal emulator (X Window System)
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "rxvt",
|
||||
Aliases: []string{"rxvt-color"},
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 8,
|
||||
Clear: "\x1b[H\x1b[2J",
|
||||
EnterCA: "\x1b7\x1b[?47h",
|
||||
ExitCA: "\x1b[2J\x1b[?47l\x1b8",
|
||||
ShowCursor: "\x1b[?25h",
|
||||
HideCursor: "\x1b[?25l",
|
||||
AttrOff: "\x1b[m\x0f",
|
||||
Underline: "\x1b[4m",
|
||||
Bold: "\x1b[1m",
|
||||
Blink: "\x1b[5m",
|
||||
Reverse: "\x1b[7m",
|
||||
EnterKeypad: "\x1b=",
|
||||
ExitKeypad: "\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: "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||
EnterAcs: "\x0e",
|
||||
ExitAcs: "\x0f",
|
||||
EnableAcs: "\x1b(B\x1b)0",
|
||||
Mouse: "\x1b[M",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
XTermLike: true,
|
||||
})
|
||||
|
||||
// rxvt 2.7.9 with xterm 256-colors
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "rxvt-256color",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 256,
|
||||
Clear: "\x1b[H\x1b[2J",
|
||||
EnterCA: "\x1b7\x1b[?47h",
|
||||
ExitCA: "\x1b[2J\x1b[?47l\x1b8",
|
||||
ShowCursor: "\x1b[?25h",
|
||||
HideCursor: "\x1b[?25l",
|
||||
AttrOff: "\x1b[m\x0f",
|
||||
Underline: "\x1b[4m",
|
||||
Bold: "\x1b[1m",
|
||||
Blink: "\x1b[5m",
|
||||
Reverse: "\x1b[7m",
|
||||
EnterKeypad: "\x1b=",
|
||||
ExitKeypad: "\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: "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||
EnterAcs: "\x0e",
|
||||
ExitAcs: "\x0f",
|
||||
EnableAcs: "\x1b(B\x1b)0",
|
||||
Mouse: "\x1b[M",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
XTermLike: true,
|
||||
})
|
||||
|
||||
// rxvt 2.7.9 with xterm 88-colors
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "rxvt-88color",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 88,
|
||||
Clear: "\x1b[H\x1b[2J",
|
||||
EnterCA: "\x1b7\x1b[?47h",
|
||||
ExitCA: "\x1b[2J\x1b[?47l\x1b8",
|
||||
ShowCursor: "\x1b[?25h",
|
||||
HideCursor: "\x1b[?25l",
|
||||
AttrOff: "\x1b[m\x0f",
|
||||
Underline: "\x1b[4m",
|
||||
Bold: "\x1b[1m",
|
||||
Blink: "\x1b[5m",
|
||||
Reverse: "\x1b[7m",
|
||||
EnterKeypad: "\x1b=",
|
||||
ExitKeypad: "\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: "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||
EnterAcs: "\x0e",
|
||||
ExitAcs: "\x0f",
|
||||
EnableAcs: "\x1b(B\x1b)0",
|
||||
Mouse: "\x1b[M",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
XTermLike: true,
|
||||
})
|
||||
|
||||
// rxvt-unicode terminal (X Window System)
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "rxvt-unicode",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 88,
|
||||
Clear: "\x1b[H\x1b[2J",
|
||||
EnterCA: "\x1b[?1049h",
|
||||
ExitCA: "\x1b[r\x1b[?1049l",
|
||||
ShowCursor: "\x1b[?12l\x1b[?25h",
|
||||
HideCursor: "\x1b[?25l",
|
||||
AttrOff: "\x1b[m\x1b(B",
|
||||
Underline: "\x1b[4m",
|
||||
Bold: "\x1b[1m",
|
||||
Italic: "\x1b[3m",
|
||||
Blink: "\x1b[5m",
|
||||
Reverse: "\x1b[7m",
|
||||
EnterKeypad: "\x1b=",
|
||||
ExitKeypad: "\x1b>",
|
||||
SetFg: "\x1b[38;5;%p1%dm",
|
||||
SetBg: "\x1b[48;5;%p1%dm",
|
||||
SetFgBg: "\x1b[38;5;%p1%d;48;5;%p2%dm",
|
||||
ResetFgBg: "\x1b[39;49m",
|
||||
AltChars: "+C,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||
EnterAcs: "\x1b(0",
|
||||
ExitAcs: "\x1b(B",
|
||||
EnableAutoMargin: "\x1b[?7h",
|
||||
DisableAutoMargin: "\x1b[?7l",
|
||||
Mouse: "\x1b[M",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
InsertChar: "\x1b[@",
|
||||
})
|
||||
|
||||
// rxvt-unicode terminal with 256 colors (X Window System)
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "rxvt-unicode-256color",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 256,
|
||||
Clear: "\x1b[H\x1b[2J",
|
||||
EnterCA: "\x1b[?1049h",
|
||||
ExitCA: "\x1b[r\x1b[?1049l",
|
||||
ShowCursor: "\x1b[?12l\x1b[?25h",
|
||||
HideCursor: "\x1b[?25l",
|
||||
AttrOff: "\x1b[m\x1b(B",
|
||||
Underline: "\x1b[4m",
|
||||
Bold: "\x1b[1m",
|
||||
Italic: "\x1b[3m",
|
||||
Blink: "\x1b[5m",
|
||||
Reverse: "\x1b[7m",
|
||||
EnterKeypad: "\x1b=",
|
||||
ExitKeypad: "\x1b>",
|
||||
SetFg: "\x1b[38;5;%p1%dm",
|
||||
SetBg: "\x1b[48;5;%p1%dm",
|
||||
SetFgBg: "\x1b[38;5;%p1%d;48;5;%p2%dm",
|
||||
ResetFgBg: "\x1b[39;49m",
|
||||
AltChars: "+C,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||
EnterAcs: "\x1b(0",
|
||||
ExitAcs: "\x1b(B",
|
||||
EnableAutoMargin: "\x1b[?7h",
|
||||
DisableAutoMargin: "\x1b[?7l",
|
||||
Mouse: "\x1b[M",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
InsertChar: "\x1b[@",
|
||||
})
|
||||
}
|
||||
74
vendor/github.com/gdamore/tcell/v2/terminfo/s/screen/term.go
generated
vendored
74
vendor/github.com/gdamore/tcell/v2/terminfo/s/screen/term.go
generated
vendored
|
|
@ -1,74 +0,0 @@
|
|||
// Generated automatically. DO NOT HAND-EDIT.
|
||||
|
||||
package screen
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// VT 100/ANSI X3.64 virtual terminal
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "screen",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 8,
|
||||
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",
|
||||
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",
|
||||
Mouse: "\x1b[M",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
})
|
||||
|
||||
// GNU Screen with 256 colors
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "screen-256color",
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 256,
|
||||
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",
|
||||
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",
|
||||
Mouse: "\x1b[M",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
})
|
||||
}
|
||||
80
vendor/github.com/gdamore/tcell/v2/terminfo/s/simpleterm/term.go
generated
vendored
80
vendor/github.com/gdamore/tcell/v2/terminfo/s/simpleterm/term.go
generated
vendored
|
|
@ -1,80 +0,0 @@
|
|||
// Generated automatically. DO NOT HAND-EDIT.
|
||||
|
||||
package simpleterm
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// aka simpleterm
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "st",
|
||||
Aliases: []string{"stterm"},
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 8,
|
||||
Clear: "\x1b[H\x1b[2J",
|
||||
EnterCA: "\x1b[?1049h",
|
||||
ExitCA: "\x1b[?1049l",
|
||||
ShowCursor: "\x1b[?25h",
|
||||
HideCursor: "\x1b[?25l",
|
||||
AttrOff: "\x1b[0m",
|
||||
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",
|
||||
AltChars: "+C,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||
EnterAcs: "\x1b(0",
|
||||
ExitAcs: "\x1b(B",
|
||||
EnableAcs: "\x1b)0",
|
||||
StrikeThrough: "\x1b[9m",
|
||||
Mouse: "\x1b[M",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
XTermLike: true,
|
||||
})
|
||||
|
||||
// simpleterm with 256 colors
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "st-256color",
|
||||
Aliases: []string{"stterm-256color"},
|
||||
Columns: 80,
|
||||
Lines: 24,
|
||||
Colors: 256,
|
||||
Clear: "\x1b[H\x1b[2J",
|
||||
EnterCA: "\x1b[?1049h",
|
||||
ExitCA: "\x1b[?1049l",
|
||||
ShowCursor: "\x1b[?25h",
|
||||
HideCursor: "\x1b[?25l",
|
||||
AttrOff: "\x1b[0m",
|
||||
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: "+C,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
|
||||
EnterAcs: "\x1b(0",
|
||||
ExitAcs: "\x1b(B",
|
||||
EnableAcs: "\x1b)0",
|
||||
StrikeThrough: "\x1b[9m",
|
||||
Mouse: "\x1b[M",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
XTermLike: true,
|
||||
})
|
||||
}
|
||||
60
vendor/github.com/gdamore/tcell/v2/terminfo/s/sun/term.go
generated
vendored
60
vendor/github.com/gdamore/tcell/v2/terminfo/s/sun/term.go
generated
vendored
|
|
@ -1,60 +0,0 @@
|
|||
// Copyright 2021 The TCell Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use file except in compliance with the License.
|
||||
// You may obtain a copy of the license at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// This terminal definition is hand-coded, as the default terminfo for
|
||||
// this terminal is busted with respect to color. Unlike pretty much every
|
||||
// other ANSI compliant terminal, this terminal cannot combine foreground and
|
||||
// background escapes. The default terminfo also only provides escapes for
|
||||
// 16-bit color.
|
||||
|
||||
package sun
|
||||
|
||||
import "github.com/gdamore/tcell/v2/terminfo"
|
||||
|
||||
func init() {
|
||||
|
||||
// Sun Microsystems Inc. workstation console
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "sun",
|
||||
Aliases: []string{"sun1", "sun2"},
|
||||
Columns: 80,
|
||||
Lines: 34,
|
||||
Clear: "\f",
|
||||
AttrOff: "\x1b[m",
|
||||
Reverse: "\x1b[7m",
|
||||
PadChar: "\x00",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
InsertChar: "\x1b[@",
|
||||
})
|
||||
|
||||
// Sun Microsystems Workstation console with color support (IA systems)
|
||||
terminfo.AddTerminfo(&terminfo.Terminfo{
|
||||
Name: "sun-color",
|
||||
Columns: 80,
|
||||
Lines: 34,
|
||||
Colors: 256,
|
||||
Clear: "\f",
|
||||
AttrOff: "\x1b[m",
|
||||
Bold: "\x1b[1m",
|
||||
Reverse: "\x1b[7m",
|
||||
SetFg: "\x1b[38;5;%p1%dm",
|
||||
SetBg: "\x1b[48;5;%p1%dm",
|
||||
ResetFgBg: "\x1b[0m",
|
||||
PadChar: "\x00",
|
||||
SetCursor: "\x1b[%i%p1%d;%p2%dH",
|
||||
AutoMargin: true,
|
||||
InsertChar: "\x1b[@",
|
||||
})
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue