diff --git a/go.mod b/go.mod index 572f660..7a1715a 100644 --- a/go.mod +++ b/go.mod @@ -4,11 +4,11 @@ go 1.16 require ( github.com/BurntSushi/toml v0.3.1 + github.com/awesome-gocui/gocui v1.1.0 github.com/gofrs/uuid v4.0.0+incompatible github.com/gookit/color v1.5.2 - github.com/jroimartin/gocui v0.4.0 github.com/lightningnetwork/lnd v0.15.0-beta - github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d // indirect + github.com/mattn/go-runewidth v0.0.13 github.com/pkg/errors v0.9.1 go.uber.org/zap v1.17.0 golang.org/x/text v0.3.7 diff --git a/go.sum b/go.sum index ab54b7f..d69f845 100644 --- a/go.sum +++ b/go.sum @@ -58,6 +58,8 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/awesome-gocui/gocui v1.1.0 h1:db2j7yFEoHZjpQFeE2xqiatS8bm1lO3THeLwE6MzOII= +github.com/awesome-gocui/gocui v1.1.0/go.mod h1:M2BXkrp7PR97CKnPRT7Rk0+rtswChPtksw/vRAESGpg= github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJyXg= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -190,6 +192,10 @@ github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHs github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= +github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= +github.com/gdamore/tcell/v2 v2.4.0 h1:W6dxJEmaxYvhICFoTY3WrLLEXsQ11SaFnKGVEXW57KM= +github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU= github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -377,8 +383,6 @@ github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUB github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= -github.com/jroimartin/gocui v0.4.0 h1:52jnalstgmc25FmtGcWqa0tcbMEWS6RpFLsOIO+I+E8= -github.com/jroimartin/gocui v0.4.0/go.mod h1:7i7bbj99OgFHzo7kB2zPb8pXLqMBSQegY7azfqXMkyY= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= @@ -498,6 +502,8 @@ github.com/lightningnetwork/lnd/tor v1.0.1/go.mod h1:RDtaAdwfAm+ONuPYwUhNIH1RAvK github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw= github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1sNPI5H8P3NkTFF4LuwMdPl2DodF60qAKqY= github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA= +github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= +github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lunixbochs/vtclean v0.0.0-20160125035106-4fbf7632a2c6/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/masterzen/azure-sdk-for-go v3.2.0-beta.0.20161014135628-ee4f0065d00c+incompatible/go.mod h1:mf8fjOu33zCqxUjuiU3I8S1lJMyEAlH+0F2+M5xl3hE= @@ -513,6 +519,7 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -538,8 +545,6 @@ github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840= -github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nwaples/rardecode v1.1.2 h1:Cj0yZY6T1Zx1R7AhTbyGSALm44/Mmq+BAPc4B/p/d3M= @@ -595,6 +600,7 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -922,8 +928,9 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= +golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/network/models/channel.go b/network/models/channel.go index 1ded328..0542180 100644 --- a/network/models/channel.go +++ b/network/models/channel.go @@ -5,6 +5,7 @@ import ( "time" "github.com/edouardparis/lntop/logging" + "github.com/mattn/go-runewidth" ) const ( @@ -79,12 +80,12 @@ func (m Channel) ShortAlias() (alias string, forced bool) { alias = m.Node.ForcedAlias forced = true } else if m.Node == nil || m.Node.Alias == "" { - alias = m.RemotePubKey[:24] + alias = m.RemotePubKey[:25] } else { alias = strings.ReplaceAll(m.Node.Alias, "\ufe0f", "") } - if len(alias) > 25 { - alias = alias[:24] + if runewidth.StringWidth(alias) > 25 { + alias = runewidth.Truncate(alias, 25, "") } return } diff --git a/ui/controller.go b/ui/controller.go index 96f70a7..4df3b6d 100644 --- a/ui/controller.go +++ b/ui/controller.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/jroimartin/gocui" + "github.com/awesome-gocui/gocui" "github.com/edouardparis/lntop/app" "github.com/edouardparis/lntop/events" @@ -247,7 +247,7 @@ func (c *controller) OnEnter(g *gocui.Gui, v *gocui.View) error { defer cancel() c.models.RefreshCurrentNode(ctx) c.views.Main = c.views.Channel - return ToggleView(g, view, c.views.Channels) + return ToggleView(g, view, c.views.Channel) case views.CHANNEL: c.views.Main = c.views.Channels diff --git a/ui/keybindings.go b/ui/keybindings.go index 22a8d55..9a4c49f 100644 --- a/ui/keybindings.go +++ b/ui/keybindings.go @@ -1,8 +1,8 @@ package ui import ( + "github.com/awesome-gocui/gocui" "github.com/edouardparis/lntop/ui/models" - "github.com/jroimartin/gocui" ) func quit(g *gocui.Gui, v *gocui.View) error { diff --git a/ui/ui.go b/ui/ui.go index e39287f..e3a7d27 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -3,7 +3,7 @@ package ui import ( "context" - "github.com/jroimartin/gocui" + "github.com/awesome-gocui/gocui" "github.com/pkg/errors" "github.com/edouardparis/lntop/app" @@ -11,13 +11,13 @@ import ( ) func Run(ctx context.Context, app *app.App, sub chan *events.Event) error { - g, err := gocui.NewGui(gocui.Output256) + g, err := gocui.NewGui(gocui.Output256, false) if err != nil { return err } defer g.Close() - g.Cursor = true + g.Cursor = false ctrl := newController(app) err = ctrl.SetModels(ctx) if err != nil { diff --git a/ui/views/channel.go b/ui/views/channel.go index f91e948..d2f3153 100644 --- a/ui/views/channel.go +++ b/ui/views/channel.go @@ -3,7 +3,7 @@ package views import ( "fmt" - "github.com/jroimartin/gocui" + "github.com/awesome-gocui/gocui" "golang.org/x/text/language" "golang.org/x/text/message" @@ -63,7 +63,7 @@ func (c *Channel) SetOrigin(x, y int) error { } func (c *Channel) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { - header, err := g.SetView(CHANNEL_HEADER, x0-1, y0, x1+2, y0+2) + header, err := g.SetView(CHANNEL_HEADER, x0-1, y0, x1+2, y0+2, 0) if err != nil { if err != gocui.ErrUnknownView { return err @@ -72,10 +72,10 @@ func (c *Channel) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { header.Frame = false header.BgColor = gocui.ColorGreen header.FgColor = gocui.ColorBlack | gocui.AttrBold - header.Clear() + header.Rewind() fmt.Fprintln(header, "Channel") - v, err := g.SetView(CHANNEL, x0-1, y0+1, x1+2, y1-1) + v, err := g.SetView(CHANNEL, x0-1, y0+1, x1+2, y1-1, 0) if err != nil { if err != gocui.ErrUnknownView { return err @@ -85,7 +85,7 @@ func (c *Channel) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { c.view = v c.display() - footer, err := g.SetView(CHANNEL_FOOTER, x0-1, y1-2, x1, y1) + footer, err := g.SetView(CHANNEL_FOOTER, x0-1, y1-2, x1, y1, 0) if err != nil { if err != gocui.ErrUnknownView { return err @@ -94,7 +94,7 @@ func (c *Channel) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { footer.Frame = false footer.BgColor = gocui.ColorCyan footer.FgColor = gocui.ColorBlack - footer.Clear() + footer.Rewind() blackBg := color.Black(color.Background) fmt.Fprintf(footer, "%s%s %s%s %s%s %s%s\n", blackBg("F2"), "Menu", diff --git a/ui/views/channels.go b/ui/views/channels.go index cf6fc56..a92429c 100644 --- a/ui/views/channels.go +++ b/ui/views/channels.go @@ -4,7 +4,7 @@ import ( "bytes" "fmt" - "github.com/jroimartin/gocui" + "github.com/awesome-gocui/gocui" "golang.org/x/text/language" "golang.org/x/text/message" @@ -41,9 +41,11 @@ type Channels struct { columns []channelsColumn - columnsView *gocui.View - view *gocui.View - channels *models.Channels + columnHeadersView *gocui.View + columnViews []*gocui.View + view *gocui.View + + channels *models.Channels ox, oy int cx, cy int @@ -107,22 +109,30 @@ func (c Channels) Cursor() (int, int) { } func (c *Channels) SetCursor(cx, cy int) error { - err := c.columnsView.SetCursor(cx, 0) - if err != nil { + if err := cursorCompat(c.columnHeadersView, cx, 0); err != nil { return err } - - err = c.view.SetCursor(cx, cy) + err := c.columnHeadersView.SetCursor(cx, 0) if err != nil { return err } + for _, cv := range c.columnViews { + if err := cursorCompat(c.view, cx, cy); err != nil { + return err + } + err = cv.SetCursor(cx, cy) + if err != nil { + return err + } + } + c.cx, c.cy = cx, cy return nil } func (c *Channels) SetOrigin(ox, oy int) error { - err := c.columnsView.SetOrigin(ox, 0) + err := c.columnHeadersView.SetOrigin(ox, 0) if err != nil { return err } @@ -131,6 +141,13 @@ func (c *Channels) SetOrigin(ox, oy int) error { return err } + for _, cv := range c.columnViews { + err = cv.SetOrigin(0, oy) + if err != nil { + return err + } + } + c.ox, c.oy = ox, oy return nil } @@ -168,7 +185,7 @@ func (c Channels) Index() int { return cy + oy } -func (c Channels) Delete(g *gocui.Gui) error { +func (c *Channels) Delete(g *gocui.Gui) error { err := g.DeleteView(CHANNELS_COLUMNS) if err != nil { return err @@ -179,24 +196,31 @@ func (c Channels) Delete(g *gocui.Gui) error { return err } + for _, cv := range c.columnViews { + err = g.DeleteView(cv.Name()) + if err != nil { + return err + } + } + c.columnViews = c.columnViews[:0] return g.DeleteView(CHANNELS_FOOTER) } func (c *Channels) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { var err error setCursor := false - c.columnsView, err = g.SetView(CHANNELS_COLUMNS, x0-1, y0, x1+2, y0+2) + c.columnHeadersView, err = g.SetView(CHANNELS_COLUMNS, x0-1, y0, x1+2, y0+2, 0) if err != nil { if err != gocui.ErrUnknownView { return err } setCursor = true } - c.columnsView.Frame = false - c.columnsView.BgColor = gocui.ColorGreen - c.columnsView.FgColor = gocui.ColorBlack + c.columnHeadersView.Frame = false + c.columnHeadersView.BgColor = gocui.ColorGreen + c.columnHeadersView.FgColor = gocui.ColorBlack - c.view, err = g.SetView(CHANNELS, x0-1, y0+1, x1+2, y1-1) + c.view, err = g.SetView(CHANNELS, x0-1, y0+1, x1+2, y1-1, 0) if err != nil { if err != gocui.ErrUnknownView { return err @@ -207,7 +231,9 @@ func (c *Channels) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { c.view.Autoscroll = false c.view.SelBgColor = gocui.ColorCyan c.view.SelFgColor = gocui.ColorBlack - c.view.Highlight = true + c.view.Highlight = false + c.display(g) + if setCursor { ox, oy := c.Origin() err := c.SetOrigin(ox, oy) @@ -222,9 +248,7 @@ func (c *Channels) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { } } - c.display() - - footer, err := g.SetView(CHANNELS_FOOTER, x0-1, y1-2, x1+2, y1) + footer, err := g.SetView(CHANNELS_FOOTER, x0-1, y1-2, x1+2, y1, 0) if err != nil { if err != gocui.ErrUnknownView { return err @@ -233,7 +257,7 @@ func (c *Channels) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { footer.Frame = false footer.BgColor = gocui.ColorCyan footer.FgColor = gocui.ColorBlack - footer.Clear() + footer.Rewind() blackBg := color.Black(color.Background) fmt.Fprintln(footer, fmt.Sprintf("%s%s %s%s %s%s", blackBg("F2"), "Menu", @@ -243,8 +267,8 @@ func (c *Channels) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { return nil } -func (c *Channels) display() { - c.columnsView.Clear() +func (c *Channels) display(g *gocui.Gui) { + c.columnHeadersView.Rewind() var buffer bytes.Buffer currentColumnIndex := c.currentColumnIndex() for i := range c.columns { @@ -260,20 +284,39 @@ func (c *Channels) display() { buffer.WriteString(c.columns[i].name) buffer.WriteString(" ") } - fmt.Fprintln(c.columnsView, buffer.String()) + fmt.Fprintln(c.columnHeadersView, buffer.String()) - c.view.Clear() - for _, item := range c.channels.List() { - var buffer bytes.Buffer + if len(c.columnViews) == 0 { + c.columnViews = make([]*gocui.View, len(c.columns)) + x0, y0, _, y1 := c.view.Dimensions() + for i := range c.columns { + width := c.columns[i].width + cc, _ := g.SetView("channel_content_"+c.columns[i].name, x0, y0, x0+width+2, y1, 0) + cc.Frame = false + cc.Autoscroll = false + cc.SelBgColor = gocui.ColorCyan + cc.SelFgColor = gocui.ColorBlack + cc.Highlight = true + c.columnViews[i] = cc + } + } + for ci, item := range c.channels.List() { + x0, y0, _, y1 := c.view.Dimensions() + x0 -= c.ox for i := range c.columns { var opt color.Option if currentColumnIndex == i { opt = color.Bold } - buffer.WriteString(c.columns[i].display(item, opt)) - buffer.WriteString(" ") + width := c.columns[i].width + cc, _ := g.SetView("channel_content_"+c.columns[i].name, x0, y0, x0+width+2, y1, 0) + c.columnViews[i] = cc + if ci == 0 { + cc.Rewind() + } + fmt.Fprintln(cc, c.columns[i].display(item, opt), " ") + x0 += width + 1 } - fmt.Fprintln(c.view, buffer.String()) } } @@ -506,7 +549,7 @@ func NewChannels(cfg *config.View, chans *models.Channels) *Channels { if c.ID == 0 { return fmt.Sprintf("%-19s", "") } - return color.White(opts...)(fmt.Sprintf("%d", c.ID)) + return color.White(opts...)(fmt.Sprintf("%-19d", c.ID)) }, } case "SCID": @@ -640,7 +683,7 @@ func NewChannels(cfg *config.View, chans *models.Channels) *Channels { } case "AGE": channels.columns[i] = channelsColumn{ - width: 8, + width: 10, name: fmt.Sprintf("%10s", columns[i]), sort: func(order models.Order) models.ChannelsSort { return func(c1, c2 *netmodels.Channel) bool { diff --git a/ui/views/header.go b/ui/views/header.go index e33d3aa..37c35d7 100644 --- a/ui/views/header.go +++ b/ui/views/header.go @@ -4,9 +4,9 @@ import ( "fmt" "regexp" + "github.com/awesome-gocui/gocui" "github.com/edouardparis/lntop/ui/color" "github.com/edouardparis/lntop/ui/models" - "github.com/jroimartin/gocui" ) const ( @@ -20,7 +20,7 @@ type Header struct { } func (h *Header) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { - v, err := g.SetView(HEADER, x0, y0, x1, y0+2) + v, err := g.SetView(HEADER, x0, y0, x1, y0+2, 0) if err != nil { if err != gocui.ErrUnknownView { return err diff --git a/ui/views/menu.go b/ui/views/menu.go index 309e645..839c626 100644 --- a/ui/views/menu.go +++ b/ui/views/menu.go @@ -3,8 +3,8 @@ package views import ( "fmt" + "github.com/awesome-gocui/gocui" "github.com/edouardparis/lntop/ui/color" - "github.com/jroimartin/gocui" ) const ( @@ -106,7 +106,7 @@ func (c Menu) Delete(g *gocui.Gui) error { func (h Menu) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { setCursor := false - header, err := g.SetView(MENU_HEADER, x0-1, y0, x1, y0+2) + header, err := g.SetView(MENU_HEADER, x0-1, y0, x1, y0+2, 0) if err != nil { if err != gocui.ErrUnknownView { return err @@ -117,10 +117,10 @@ func (h Menu) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { header.BgColor = gocui.ColorGreen header.FgColor = gocui.ColorBlack - header.Clear() + header.Rewind() fmt.Fprintln(header, " MENU") - h.view, err = g.SetView(MENU, x0-1, y0+1, x1, y1-2) + h.view, err = g.SetView(MENU, x0-1, y0+1, x1, y1-2, 0) if err != nil { if err != gocui.ErrUnknownView { return err @@ -132,6 +132,16 @@ func (h Menu) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { h.view.Highlight = true h.view.SelBgColor = gocui.ColorCyan h.view.SelFgColor = gocui.ColorBlack + + h.view.Rewind() + for i := range menu { + fmt.Fprintln(h.view, fmt.Sprintf(" %-9s", menu[i])) + } + _, err = g.SetCurrentView(MENU) + if err != nil { + return err + } + if setCursor { ox, oy := h.Origin() err := h.SetOrigin(ox, oy) @@ -146,16 +156,7 @@ func (h Menu) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { } } - h.view.Clear() - for i := range menu { - fmt.Fprintln(h.view, fmt.Sprintf(" %-9s", menu[i])) - } - _, err = g.SetCurrentView(MENU) - if err != nil { - return err - } - - footer, err := g.SetView(MENU_FOOTER, x0-1, y1-2, x1, y1) + footer, err := g.SetView(MENU_FOOTER, x0-1, y1-2, x1, y1, 0) if err != nil { if err != gocui.ErrUnknownView { return err @@ -164,7 +165,7 @@ func (h Menu) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { footer.Frame = false footer.BgColor = gocui.ColorCyan footer.FgColor = gocui.ColorBlack - footer.Clear() + footer.Rewind() blackBg := color.Black(color.Background) fmt.Fprintln(footer, fmt.Sprintf("%s%s", blackBg("F2"), "Close", diff --git a/ui/views/routing.go b/ui/views/routing.go index 357200f..2d088dc 100644 --- a/ui/views/routing.go +++ b/ui/views/routing.go @@ -4,7 +4,7 @@ import ( "bytes" "fmt" - "github.com/jroimartin/gocui" + "github.com/awesome-gocui/gocui" "golang.org/x/text/language" "golang.org/x/text/message" @@ -38,9 +38,10 @@ type Routing struct { columns []routingColumn - columnsView *gocui.View - view *gocui.View - routingEvents *models.RoutingLog + columnHeadersView *gocui.View + columnViews []*gocui.View + view *gocui.View + routingEvents *models.RoutingLog ox, oy int cx, cy int @@ -84,22 +85,30 @@ func (c Routing) Cursor() (int, int) { } func (c *Routing) SetCursor(cx, cy int) error { - err := c.columnsView.SetCursor(cx, 0) - if err != nil { + if err := cursorCompat(c.columnHeadersView, cx, 0); err != nil { return err } - - err = c.view.SetCursor(cx, cy) + err := c.columnHeadersView.SetCursor(cx, 0) if err != nil { return err } + for _, cv := range c.columnViews { + if err := cursorCompat(c.view, cx, cy); err != nil { + return err + } + err = cv.SetCursor(cx, cy) + if err != nil { + return err + } + } + c.cx, c.cy = cx, cy return nil } func (c *Routing) SetOrigin(ox, oy int) error { - err := c.columnsView.SetOrigin(ox, 0) + err := c.columnHeadersView.SetOrigin(ox, 0) if err != nil { return err } @@ -108,6 +117,13 @@ func (c *Routing) SetOrigin(ox, oy int) error { return err } + for _, cv := range c.columnViews { + err = cv.SetOrigin(0, oy) + if err != nil { + return err + } + } + c.ox, c.oy = ox, oy return nil } @@ -149,7 +165,7 @@ func (c Routing) Index() int { return cy + oy } -func (c Routing) Delete(g *gocui.Gui) error { +func (c *Routing) Delete(g *gocui.Gui) error { err := g.DeleteView(ROUTING_COLUMNS) if err != nil { return err @@ -160,24 +176,31 @@ func (c Routing) Delete(g *gocui.Gui) error { return err } + for _, cv := range c.columnViews { + err = g.DeleteView(cv.Name()) + if err != nil { + return err + } + } + c.columnViews = c.columnViews[:0] return g.DeleteView(ROUTING_FOOTER) } func (c *Routing) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { var err error setCursor := false - c.columnsView, err = g.SetView(ROUTING_COLUMNS, x0-1, y0, x1+2, y0+2) + c.columnHeadersView, err = g.SetView(ROUTING_COLUMNS, x0-1, y0, x1+2, y0+2, 0) if err != nil { if err != gocui.ErrUnknownView { return err } setCursor = true } - c.columnsView.Frame = false - c.columnsView.BgColor = gocui.ColorGreen - c.columnsView.FgColor = gocui.ColorBlack + c.columnHeadersView.Frame = false + c.columnHeadersView.BgColor = gocui.ColorGreen + c.columnHeadersView.FgColor = gocui.ColorBlack - c.view, err = g.SetView(ROUTING, x0-1, y0+1, x1+2, y1-1) + c.view, err = g.SetView(ROUTING, x0-1, y0+1, x1+2, y1-1, 0) if err != nil { if err != gocui.ErrUnknownView { return err @@ -189,6 +212,8 @@ func (c *Routing) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { c.view.SelBgColor = gocui.ColorCyan c.view.SelFgColor = gocui.ColorBlack c.view.Highlight = true + c.display(g) + if setCursor { ox, oy := c.Origin() err := c.SetOrigin(ox, oy) @@ -203,9 +228,7 @@ func (c *Routing) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { } } - c.display() - - footer, err := g.SetView(ROUTING_FOOTER, x0-1, y1-2, x1+2, y1) + footer, err := g.SetView(ROUTING_FOOTER, x0-1, y1-2, x1+2, y1, 0) if err != nil { if err != gocui.ErrUnknownView { return err @@ -214,7 +237,7 @@ func (c *Routing) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { footer.Frame = false footer.BgColor = gocui.ColorCyan footer.FgColor = gocui.ColorBlack - footer.Clear() + footer.Rewind() blackBg := color.Black(color.Background) fmt.Fprintln(footer, fmt.Sprintf("%s%s %s%s", blackBg("F2"), "Menu", @@ -223,8 +246,8 @@ func (c *Routing) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { return nil } -func (c *Routing) display() { - c.columnsView.Clear() +func (c *Routing) display(g *gocui.Gui) { + c.columnHeadersView.Rewind() var buffer bytes.Buffer currentColumnIndex := c.currentColumnIndex() for i := range c.columns { @@ -236,9 +259,7 @@ func (c *Routing) display() { buffer.WriteString(c.columns[i].name) buffer.WriteString(" ") } - fmt.Fprintln(c.columnsView, buffer.String()) - - c.view.Clear() + fmt.Fprintln(c.columnHeadersView, buffer.String()) _, height := c.view.Size() numEvents := len(c.routingEvents.Log) @@ -247,18 +268,40 @@ func (c *Routing) display() { if height < numEvents { j = numEvents - height } + if len(c.columnViews) == 0 { + c.columnViews = make([]*gocui.View, len(c.columns)) + x0, y0, _, y1 := c.view.Dimensions() + for i := range c.columns { + width := c.columns[i].width + cc, _ := g.SetView("routing_content_"+c.columns[i].name, x0, y0, x0+width+2, y1, 0) + cc.Frame = false + cc.Autoscroll = false + cc.SelBgColor = gocui.ColorCyan + cc.SelFgColor = gocui.ColorBlack + cc.Highlight = true + c.columnViews[i] = cc + } + } + rewind := true for ; j < numEvents; j++ { var item = c.routingEvents.Log[j] - var buffer bytes.Buffer + x0, y0, _, y1 := c.view.Dimensions() + x0 -= c.ox for i := range c.columns { var opt color.Option if currentColumnIndex == i { opt = color.Bold } - buffer.WriteString(c.columns[i].display(item, opt)) - buffer.WriteString(" ") + width := c.columns[i].width + cc, _ := g.SetView("routing_content_"+c.columns[i].name, x0, y0, x0+width+2, y1, 0) + c.columnViews[i] = cc + if rewind { + cc.Rewind() + } + fmt.Fprintln(cc, c.columns[i].display(item, opt), " ") + x0 += width + 1 } - fmt.Fprintln(c.view, buffer.String()) + rewind = false } } diff --git a/ui/views/summary.go b/ui/views/summary.go index 11ae96a..e9d2ae5 100644 --- a/ui/views/summary.go +++ b/ui/views/summary.go @@ -4,7 +4,7 @@ import ( "bytes" "fmt" - "github.com/jroimartin/gocui" + "github.com/awesome-gocui/gocui" "golang.org/x/text/language" "golang.org/x/text/message" @@ -29,7 +29,7 @@ type Summary struct { func (s *Summary) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { var err error - s.left, err = g.SetView(SUMMARY_LEFT, x0, y0, x1/2, y1) + s.left, err = g.SetView(SUMMARY_LEFT, x0, y0, x1/2, y1, 0) if err != nil { if err != gocui.ErrUnknownView { return err @@ -38,7 +38,7 @@ func (s *Summary) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { s.left.Frame = false s.left.Wrap = true - s.right, err = g.SetView(SUMMARY_RIGHT, x1/2, y0, x1, y1) + s.right, err = g.SetView(SUMMARY_RIGHT, x1/2, y0, x1, y1, 0) if err != nil { if err != gocui.ErrUnknownView { return err diff --git a/ui/views/transaction.go b/ui/views/transaction.go index e33a2a2..de85387 100644 --- a/ui/views/transaction.go +++ b/ui/views/transaction.go @@ -3,7 +3,7 @@ package views import ( "fmt" - "github.com/jroimartin/gocui" + "github.com/awesome-gocui/gocui" "golang.org/x/text/language" "golang.org/x/text/message" @@ -62,7 +62,7 @@ func (c *Transaction) SetOrigin(x, y int) error { } func (c *Transaction) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { - header, err := g.SetView(TRANSACTION_HEADER, x0-1, y0, x1+2, y0+2) + header, err := g.SetView(TRANSACTION_HEADER, x0-1, y0, x1+2, y0+2, 0) if err != nil { if err != gocui.ErrUnknownView { return err @@ -71,10 +71,10 @@ func (c *Transaction) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { header.Frame = false header.BgColor = gocui.ColorGreen header.FgColor = gocui.ColorBlack | gocui.AttrBold - header.Clear() + header.Rewind() fmt.Fprintln(header, "Transaction") - v, err := g.SetView(TRANSACTION, x0-1, y0+1, x1+2, y1-1) + v, err := g.SetView(TRANSACTION, x0-1, y0+1, x1+2, y1-1, 0) if err != nil { if err != gocui.ErrUnknownView { return err @@ -84,7 +84,7 @@ func (c *Transaction) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { c.view = v c.display() - footer, err := g.SetView(TRANSACTION_FOOTER, x0-1, y1-2, x1, y1) + footer, err := g.SetView(TRANSACTION_FOOTER, x0-1, y1-2, x1, y1, 0) if err != nil { if err != gocui.ErrUnknownView { return err @@ -93,7 +93,7 @@ func (c *Transaction) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { footer.Frame = false footer.BgColor = gocui.ColorCyan footer.FgColor = gocui.ColorBlack - footer.Clear() + footer.Rewind() blackBg := color.Black(color.Background) fmt.Fprintln(footer, fmt.Sprintf("%s%s %s%s %s%s", blackBg("F2"), "Menu", @@ -120,7 +120,7 @@ func (c Transaction) Delete(g *gocui.Gui) error { func (c *Transaction) display() { p := message.NewPrinter(language.English) v := c.view - v.Clear() + v.Rewind() transaction := c.transactions.Current() green := color.Green() cyan := color.Cyan() diff --git a/ui/views/transactions.go b/ui/views/transactions.go index 47083b8..6c88163 100644 --- a/ui/views/transactions.go +++ b/ui/views/transactions.go @@ -4,7 +4,7 @@ import ( "bytes" "fmt" - "github.com/jroimartin/gocui" + "github.com/awesome-gocui/gocui" "golang.org/x/text/language" "golang.org/x/text/message" @@ -32,10 +32,10 @@ var DefaultTransactionsColumns = []string{ type Transactions struct { cfg *config.View - columns []transactionsColumn - columnsView *gocui.View - view *gocui.View - transactions *models.Transactions + columns []transactionsColumn + columnHeadersView *gocui.View + view *gocui.View + transactions *models.Transactions ox, oy int cx, cy int @@ -87,11 +87,17 @@ func (c Transactions) Cursor() (int, int) { } func (c *Transactions) SetCursor(cx, cy int) error { - err := c.columnsView.SetCursor(cx, 0) + if err := cursorCompat(c.columnHeadersView, cx, 0); err != nil { + return err + } + err := c.columnHeadersView.SetCursor(cx, 0) if err != nil { return err } + if err := cursorCompat(c.view, cx, cy); err != nil { + return err + } err = c.view.SetCursor(cx, cy) if err != nil { return err @@ -102,7 +108,7 @@ func (c *Transactions) SetCursor(cx, cy int) error { } func (c *Transactions) SetOrigin(ox, oy int) error { - err := c.columnsView.SetOrigin(ox, 0) + err := c.columnHeadersView.SetOrigin(ox, 0) if err != nil { return err } @@ -177,18 +183,18 @@ func (c Transactions) Delete(g *gocui.Gui) error { func (c *Transactions) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { var err error setCursor := false - c.columnsView, err = g.SetView(TRANSACTIONS_COLUMNS, x0-1, y0, x1+2, y0+2) + c.columnHeadersView, err = g.SetView(TRANSACTIONS_COLUMNS, x0-1, y0, x1+2, y0+2, 0) if err != nil { if err != gocui.ErrUnknownView { return err } setCursor = true } - c.columnsView.Frame = false - c.columnsView.BgColor = gocui.ColorGreen - c.columnsView.FgColor = gocui.ColorBlack + c.columnHeadersView.Frame = false + c.columnHeadersView.BgColor = gocui.ColorGreen + c.columnHeadersView.FgColor = gocui.ColorBlack - c.view, err = g.SetView(TRANSACTIONS, x0-1, y0+1, x1+2, y1-1) + c.view, err = g.SetView(TRANSACTIONS, x0-1, y0+1, x1+2, y1-1, 0) if err != nil { if err != gocui.ErrUnknownView { return err @@ -200,6 +206,8 @@ func (c *Transactions) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { c.view.SelBgColor = gocui.ColorCyan c.view.SelFgColor = gocui.ColorBlack c.view.Highlight = true + c.display() + if setCursor { ox, oy := c.Origin() err := c.SetOrigin(ox, oy) @@ -214,9 +222,7 @@ func (c *Transactions) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { } } - c.display() - - footer, err := g.SetView(TRANSACTIONS_FOOTER, x0-1, y1-2, x1+2, y1) + footer, err := g.SetView(TRANSACTIONS_FOOTER, x0-1, y1-2, x1+2, y1, 0) if err != nil { if err != gocui.ErrUnknownView { return err @@ -225,7 +231,7 @@ func (c *Transactions) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { footer.Frame = false footer.BgColor = gocui.ColorCyan footer.FgColor = gocui.ColorBlack - footer.Clear() + footer.Rewind() blackBg := color.Black(color.Background) fmt.Fprintln(footer, fmt.Sprintf("%s%s %s%s %s%s", blackBg("F2"), "Menu", @@ -236,7 +242,7 @@ func (c *Transactions) Set(g *gocui.Gui, x0, y0, x1, y1 int) error { } func (c *Transactions) display() { - c.columnsView.Clear() + c.columnHeadersView.Rewind() var buffer bytes.Buffer current := c.currentColumnIndex() for i := range c.columns { @@ -252,9 +258,9 @@ func (c *Transactions) display() { buffer.WriteString(c.columns[i].name) buffer.WriteString(" ") } - fmt.Fprintln(c.columnsView, buffer.String()) + fmt.Fprintln(c.columnHeadersView, buffer.String()) - c.view.Clear() + c.view.Rewind() for _, item := range c.transactions.List() { var buffer bytes.Buffer for i := range c.columns { diff --git a/ui/views/views.go b/ui/views/views.go index cccf67e..b1f93a2 100644 --- a/ui/views/views.go +++ b/ui/views/views.go @@ -3,7 +3,7 @@ package views import ( "fmt" - "github.com/jroimartin/gocui" + "github.com/awesome-gocui/gocui" "github.com/pkg/errors" "github.com/edouardparis/lntop/config" @@ -154,3 +154,11 @@ func ColorizeAge(age uint32, text string, opts ...color.Option) string { } return color.HSL256(cur[0]/360, cur[1], cur[2], opts...)(text) } + +func cursorCompat(v *gocui.View, x, y int) error { + maxX, maxY := v.Size() + if x < 0 || x >= maxX || y < 0 || y >= maxY { + return gocui.ErrInvalidPoint + } + return nil +}