diff --git a/go.mod b/go.mod index d2ead45..e265cdc 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/andybalholm/brotli v1.2.6 github.com/ayn2op/arikawa/v3 v3.0.0-20260929021956-7d0802bf4d7c github.com/ayn2op/ningen/v3 v3.0.1-0.20260929010920-29794d5fa70e - github.com/ayn2op/tview v0.0.0-20261003181757-a9ac55442caa + github.com/ayn2op/tview v0.0.0-20261004032233-8a715f5225e6 github.com/bogdanfinn/fhttp v0.6.9 github.com/bogdanfinn/tls-client v1.16.0 github.com/gdamore/tcell/v3 v3.5.0 diff --git a/go.sum b/go.sum index bb2499f..5d59962 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,8 @@ github.com/ayn2op/arikawa/v3 v3.0.0-20260929021956-7d0802bf4d7c h1:Qkl3W5RXzUQUR github.com/ayn2op/arikawa/v3 v3.0.0-20260929021956-7d0802bf4d7c/go.mod h1:SHqcr+EmZKeNtVKZybHJn4HNz+ufA1XbeKNSTigBCEE= github.com/ayn2op/ningen/v3 v3.0.1-0.20260929010920-29794d5fa70e h1:QAei/IVEyZV7GcpkpcFUh37+QRqwrt57z7OT3ciHrhI= github.com/ayn2op/ningen/v3 v3.0.1-0.20260929010920-29794d5fa70e/go.mod h1:RsvYiMzi4Si1F7vmml5NCL2DaKIZXkNUQC7QlGTMtCw= -github.com/ayn2op/tview v0.0.0-20261003181757-a9ac55442caa h1:oTjG/n566Utl7gNRvrYMI7722fc/FgqnWD9C35avl6Q= -github.com/ayn2op/tview v0.0.0-20261003181757-a9ac55442caa/go.mod h1:oRPTSZgaEJPhv3dmmNvo6grBq/BemrLG3wFQLMTZJkY= +github.com/ayn2op/tview v0.0.0-20261004032233-8a715f5225e6 h1:Ja2H6nUN2NnXcpQ9TAf1HPNkAsurCIhSsVGHIEMrcIw= +github.com/ayn2op/tview v0.0.0-20261004032233-8a715f5225e6/go.mod h1:oRPTSZgaEJPhv3dmmNvo6grBq/BemrLG3wFQLMTZJkY= github.com/bdandy/go-errors v1.2.2 h1:WdFv/oukjTJCLa79UfkGmwX7ZxONAihKu4V0mLIs11Q= github.com/bdandy/go-errors v1.2.2/go.mod h1:NkYHl4Fey9oRRdbB1CoC6e84tuqQHiqrOcZpqFEkBxM= github.com/bdandy/go-socks4 v1.2.3 h1:Q6Y2heY1GRjCtHbmlKfnwrKVU/k81LS8mRGLRlmDlic= diff --git a/internal/config/theme.go b/internal/config/theme.go index fce9517..658fe57 100644 --- a/internal/config/theme.go +++ b/internal/config/theme.go @@ -33,7 +33,7 @@ func (aw *AlignmentWrapper) UnmarshalTOML(v any) error { return nil } -type StyleWrapper struct{ tcell.Style } +type StyleWrapper struct{ tview.Style } func (sw *StyleWrapper) UnmarshalTOML(v any) error { m, ok := v.(map[string]any) @@ -288,7 +288,7 @@ type CommonTreeTheme struct { } // StatusStyle returns the style for a user with status. -func (ctt CommonTreeTheme) StatusStyle(status discord.Status) tcell.Style { +func (ctt CommonTreeTheme) StatusStyle(status discord.Status) tview.Style { switch status { case discord.OnlineStatus: return ctt.OnlineStyle.Style diff --git a/internal/markdown/renderer.go b/internal/markdown/renderer.go index 5e769cb..2d907c3 100644 --- a/internal/markdown/renderer.go +++ b/internal/markdown/renderer.go @@ -28,18 +28,18 @@ func NewRenderer(cfg *config.Config) *Renderer { return &Renderer{cfg: cfg} } -func (r *Renderer) RenderText(source []byte, node ast.Node, base tcell.Style) richtext.Text { +func (r *Renderer) RenderText(source []byte, node ast.Node, base tview.Style) richtext.Text { r.listIx = nil r.listNested = 0 builder := new(richtext.Builder) - styleStack := []tcell.Style{base} + styleStack := []tview.Style{base} linkDepth := 0 - currentStyle := func() tcell.Style { + currentStyle := func() tview.Style { return styleStack[len(styleStack)-1] } - pushStyle := func(style tcell.Style) { + pushStyle := func(style tview.Style) { styleStack = append(styleStack, style) } popStyle := func() { @@ -145,7 +145,7 @@ func (r *Renderer) RenderText(source []byte, node ast.Node, base tcell.Style) ri return builder.Finish() } -func (r *Renderer) renderFencedCodeBlock(builder *richtext.Builder, source []byte, node *ast.FencedCodeBlock, base tcell.Style) { +func (r *Renderer) renderFencedCodeBlock(builder *richtext.Builder, source []byte, node *ast.FencedCodeBlock, base tview.Style) { var code strings.Builder lines := node.Lines() for i := range lines.Len() { @@ -215,7 +215,7 @@ func (r *Renderer) renderFencedCodeBlock(builder *richtext.Builder, source []byt } } -func applyChromaStyle(base tcell.Style, entry chroma.StyleEntry) tcell.Style { +func applyChromaStyle(base tview.Style, entry chroma.StyleEntry) tview.Style { style := base if entry.Colour.IsSet() { style = style.Foreground(tcell.NewRGBColor( @@ -263,7 +263,7 @@ func mentionText(node *md.Mention) string { } } -func applyInlineAttr(style tcell.Style, attr md.Attribute, inLink bool) tcell.Style { +func applyInlineAttr(style tview.Style, attr md.Attribute, inLink bool) tview.Style { if attr&md.AttrBold != 0 { style = style.Bold(true) } diff --git a/internal/ui/chat/attachmentspicker/model.go b/internal/ui/chat/attachmentspicker/model.go index d88ca17..176a67e 100644 --- a/internal/ui/chat/attachmentspicker/model.go +++ b/internal/ui/chat/attachmentspicker/model.go @@ -18,7 +18,7 @@ func NewModel(cfg *config.Config) Model { var _ tview.Model[Model] = Model{} // View shows the picker in a box titled Attachments. -func (m Model) View() tview.Element { +func (m Model) View() tview.Widget { return m.Model.View(func(item picker.Item) tview.Msg { action, ok := item.Reference.(tview.Cmd) if !ok { diff --git a/internal/ui/chat/channelspicker/model.go b/internal/ui/chat/channelspicker/model.go index 5b1a7be..ce11580 100644 --- a/internal/ui/chat/channelspicker/model.go +++ b/internal/ui/chat/channelspicker/model.go @@ -24,7 +24,7 @@ func NewModel(cfg *config.Config) Model { var _ tview.Model[Model] = Model{} // View shows the picker in a box titled Channels. -func (m Model) View() tview.Element { +func (m Model) View() tview.Widget { return m.Model.View(func(item picker.Item) tview.Msg { channelID, ok := item.Reference.(discord.ChannelID) if !ok || !channelID.IsValid() { diff --git a/internal/ui/chat/composer/model.go b/internal/ui/chat/composer/model.go index a6291f1..4a97596 100644 --- a/internal/ui/chat/composer/model.go +++ b/internal/ui/chat/composer/model.go @@ -110,7 +110,7 @@ func (c *Model) Disabled() bool { } // View shows the text area in a box, taking keys if focused. -func (c Model) View(focused bool) tview.Element { return view{&c, focused} } +func (c Model) View(focused bool) tview.Widget { return view{&c, focused} } // view is the composer as shown, with or without the focus. type view struct { @@ -489,7 +489,7 @@ func (c *Model) OnGuildMemberRemove(event *gateway.GuildMemberRemoveEvent) { } // MentionsView places the mentions list just above the composer, near the cursor, or returns nil if it is hidden. -func (c *Model) MentionsView() tview.Element { +func (c *Model) MentionsView() tview.Widget { if !c.mentionsVisible { return nil } diff --git a/internal/ui/chat/guildstree/model.go b/internal/ui/chat/guildstree/model.go index 2096f60..0026f78 100644 --- a/internal/ui/chat/guildstree/model.go +++ b/internal/ui/chat/guildstree/model.go @@ -47,7 +47,7 @@ func (m *Model) CurrentNode() *tree.Node { } // View shows the tree in a box titled Guilds. -func (m Model) View(focused bool) tview.Element { +func (m Model) View(focused bool) tview.Widget { onChange := func(c tree.Change) tview.Msg { return Msg(c) } onSelect := func(n *tree.Node) tview.Msg { return SelectedMsg{Node: n} } return uitree.New( @@ -177,12 +177,12 @@ func (m *Model) createFolderNode(folder gateway.GuildFolder, guildsByID map[disc } } -func (m *Model) guildNodeStyle(guildID discord.GuildID) tcell.Style { +func (m *Model) guildNodeStyle(guildID discord.GuildID) tview.Style { indication := m.state.GuildIsUnread(guildID, ningen.GuildUnreadOpts{IncludeMutedCategories: true}) return unreadStyle(indication) } -func (m *Model) channelNodeStyle(channel discord.Channel) tcell.Style { +func (m *Model) channelNodeStyle(channel discord.Channel) tview.Style { unread := unreadStyle(m.state.ChannelIsUnread(channel.ID, ningen.UnreadOpts{IncludeMutedCategories: true})) if channel.Type != discord.DirectMessage || len(channel.DMRecipients) != 1 { return unread @@ -234,7 +234,7 @@ func (m *Model) createChannelNode(parent *tree.Node, channel discord.Channel) { m.nodes[discord.Snowflake(channel.ID)] = channelNode } -func (m *Model) setNodeLineStyle(node *tree.Node, style tcell.Style) { +func (m *Model) setNodeLineStyle(node *tree.Node, style tview.Style) { line := node.Line() for i := range line { line[i].Style = style @@ -455,8 +455,8 @@ func (m *Model) expandPathToNode(node *tree.Node) { } } -func unreadStyle(indication ningen.UnreadIndication) tcell.Style { - var style tcell.Style +func unreadStyle(indication ningen.UnreadIndication) tview.Style { + var style tview.Style switch indication { case ningen.ChannelRead: style = style.Dim(true) diff --git a/internal/ui/chat/memberstree/model.go b/internal/ui/chat/memberstree/model.go index 88904eb..51d54c8 100644 --- a/internal/ui/chat/memberstree/model.go +++ b/internal/ui/chat/memberstree/model.go @@ -82,7 +82,7 @@ func (m *Model) SetChannel(channel *discord.Channel) tview.Cmd { } // View shows the tree in a box titled Members. -func (m Model) View(focused bool) tview.Element { +func (m Model) View(focused bool) tview.Widget { onChange := func(c tree.Change) tview.Msg { return Msg(c) } onSelect := func(n *tree.Node) tview.Msg { return SelectedMsg{Node: n} } return uitree.New(m.root, m.selectionState, m.cfg, m.cfg.Theme.MembersTree, m.cfg.Keybinds.MembersTree, focused, onChange, onSelect).Title("Members") @@ -207,7 +207,7 @@ func (m *Model) addRecipients(recipients []discord.User) { func (m *Model) addGroup(guildID discord.GuildID, group gateway.GuildMemberListGroup) *tree.Node { name := "Members" - var style tcell.Style + var style tview.Style switch group.ID { case "online": name = "Online" @@ -239,7 +239,7 @@ func (m *Model) addGroup(guildID discord.GuildID, group gateway.GuildMemberListG // addMember adds a member as Discord shows it: a status dot, then the name in the color of their highest colored role, dimmed when offline. func (m *Model) addMember(group *tree.Node, guildID discord.GuildID, member discord.Member, index int) { name := cmp.Or(member.Nick, member.User.DisplayName, member.User.Username) - var nameStyle tcell.Style + var nameStyle tview.Style color, ok := state.MemberColor(&member, func(id discord.RoleID) *discord.Role { r, _ := m.state.Cabinet.Role(guildID, id) return r diff --git a/internal/ui/chat/mentionslist/item.go b/internal/ui/chat/mentionslist/item.go index b74afbf..c67c169 100644 --- a/internal/ui/chat/mentionslist/item.go +++ b/internal/ui/chat/mentionslist/item.go @@ -1,9 +1,9 @@ package mentionslist -import "github.com/gdamore/tcell/v3" +import "github.com/ayn2op/tview" type Item struct { InsertText string DisplayText string - Style tcell.Style + Style tview.Style } diff --git a/internal/ui/chat/mentionslist/model.go b/internal/ui/chat/mentionslist/model.go index 1070eab..b0ef5ea 100644 --- a/internal/ui/chat/mentionslist/model.go +++ b/internal/ui/chat/mentionslist/model.go @@ -6,7 +6,6 @@ import ( "github.com/ayn2op/tview" "github.com/ayn2op/tview/layout" "github.com/ayn2op/tview/list" - "github.com/gdamore/tcell/v3" "github.com/rivo/uniseg" ) @@ -22,7 +21,7 @@ func NewModel(cfg *config.Config) Model { } // View shows the list in a box whose bottom corners join the composer's border below it. -func (m Model) View() tview.Element { +func (m Model) View() tview.Widget { set := m.cfg.Theme.Border.NormalSet.BorderSet set.BottomLeft, set.BottomRight = set.BottomT, set.BottomT return ui.Box(m.listView(), &m.cfg.Theme, false).Title("Mentions").BorderSet(set) @@ -31,7 +30,7 @@ func (m Model) View() tview.Element { func (Model) Init() tview.Cmd { return nil } func (m Model) listView() list.Widget { - return list.New(m.selectionState, len(m.items), func(i int) tview.Element { + return list.New(m.selectionState, len(m.items), func(i int) tview.Widget { item := m.items[i] return row{text: item.DisplayText, style: item.Style} }). @@ -87,7 +86,7 @@ var _ tview.Model[Model] = Model{} // row is a mention on one line in its style. type row struct { text string - style tcell.Style + style tview.Style } // Size returns Fill and a height of one row. diff --git a/internal/ui/chat/messageslist/model.go b/internal/ui/chat/messageslist/model.go index 47188a3..64843eb 100644 --- a/internal/ui/chat/messageslist/model.go +++ b/internal/ui/chat/messageslist/model.go @@ -2,7 +2,6 @@ package messageslist import ( "fmt" - "github.com/ayn2op/tview/layout" "io" "log/slog" "net/http" @@ -14,6 +13,8 @@ import ( "time" "unicode/utf8" + "github.com/ayn2op/tview/layout" + "github.com/ayn2op/arikawa/v3/discord" md "github.com/ayn2op/arikawa/v3/markdown" "github.com/ayn2op/arikawa/v3/state" @@ -37,7 +38,7 @@ import ( type messageItem struct { message discord.Message - view tview.Element + view tview.Widget separator bool timestamp discord.Timestamp @@ -89,7 +90,7 @@ func NewModel(cfg *config.Config, state *ningen.State) Model { } // View shows the messages in a box titled with the channel and footed with footer, such as who is typing. -func (ml Model) View(focused bool, footer string) tview.Element { +func (ml Model) View(focused bool, footer string) tview.Widget { return ui.Box(ml.listView(focused), &ml.cfg.Theme, focused).Title(ml.title()).Footer(footer) } @@ -239,7 +240,7 @@ func (ml *Model) clearSelection() { ml.setCursor(-1) } -func (ml *Model) buildItem(index int) tview.Element { +func (ml *Model) buildItem(index int) tview.Widget { if index < 0 || index >= len(ml.items) { return nil } @@ -315,7 +316,7 @@ func (v *messageView) Handle(msg tview.Msg, area tview.Rectangle) tview.Msg { re // dateSeparator is a line with the date in the middle, filled to the width it is drawn at. type dateSeparator struct { date, fill string - style tcell.Style + style tview.Style } // Size returns Fill and a height of one row. @@ -338,7 +339,7 @@ func (d dateSeparator) Draw(screen tview.Screen, area tview.Rectangle) { func (dateSeparator) Handle(msg tview.Msg, area tview.Rectangle) tview.Msg { return msg } -func (ml *Model) renderMessage(message discord.Message, baseStyle tcell.Style) richtext.Text { +func (ml *Model) renderMessage(message discord.Message, baseStyle tview.Style) richtext.Text { builder := new(richtext.Builder) ml.writeMessage(builder, message, baseStyle) return builder.Finish() @@ -393,7 +394,7 @@ func (ml *Model) onRowCursorChanged(index int) { ml.setCursor(target) } -func (ml *Model) writeMessage(builder *richtext.Builder, message discord.Message, baseStyle tcell.Style) { +func (ml *Model) writeMessage(builder *richtext.Builder, message discord.Message, baseStyle tview.Style) { if ml.cfg.HideBlockedUsers { isBlocked := ml.state.UserIsBlocked(message.Author.ID) if isBlocked { @@ -424,7 +425,7 @@ func (ml *Model) writeMessage(builder *richtext.Builder, message discord.Message ml.drawReactions(builder, message.Reactions, baseStyle) } -func (ml *Model) drawReactions(builder *richtext.Builder, reactions []discord.Reaction, baseStyle tcell.Style) { +func (ml *Model) drawReactions(builder *richtext.Builder, reactions []discord.Reaction, baseStyle tview.Style) { if len(reactions) == 0 { return } @@ -451,12 +452,12 @@ func (ml *Model) formatTimestamp(ts discord.Timestamp) string { return ts.Time().In(time.Local).Format(ml.cfg.Timestamps.Format) } -func (ml *Model) drawTimestamps(builder *richtext.Builder, ts discord.Timestamp, baseStyle tcell.Style) { +func (ml *Model) drawTimestamps(builder *richtext.Builder, ts discord.Timestamp, baseStyle tview.Style) { dimStyle := baseStyle.Dim(true) builder.Write(ml.formatTimestamp(ts)+" ", dimStyle) } -func (ml *Model) drawAuthor(builder *richtext.Builder, message discord.Message, baseStyle tcell.Style) { +func (ml *Model) drawAuthor(builder *richtext.Builder, message discord.Message, baseStyle tview.Style) { name := message.Author.DisplayOrUsername() foreground := tcell.ColorDefault @@ -495,7 +496,7 @@ func (ml *Model) memberForMessage(message discord.Message) *discord.Member { // drawContent renders the message body and returns the parsed markdown AST together with the source bytes it indexes into, so callers can reuse them instead of re-parsing the same content (see drawEmbeds). // root is nil when markdown rendering is disabled. -func (ml *Model) drawContent(builder *richtext.Builder, message discord.Message, baseStyle tcell.Style) (ast.Node, []byte) { +func (ml *Model) drawContent(builder *richtext.Builder, message discord.Message, baseStyle tview.Style) (ast.Node, []byte) { content, root, source := ml.renderContent(message, baseStyle, false) if ml.cfg.Markdown.Enabled && !builder.LineEmpty() { startsWithCodeBlock := false @@ -521,7 +522,7 @@ func (ml *Model) drawContent(builder *richtext.Builder, message discord.Message, return root, source } -func (ml *Model) renderContent(message discord.Message, baseStyle tcell.Style, forceMarkdown bool) (richtext.Text, ast.Node, []byte) { +func (ml *Model) renderContent(message discord.Message, baseStyle tview.Style, forceMarkdown bool) (richtext.Text, ast.Node, []byte) { // Keep one rendering path for both normal messages and embed fragments so we preserve mention/link parsing behavior consistently across both. if forceMarkdown || ml.cfg.Markdown.Enabled { c := []byte(message.Content) @@ -534,7 +535,7 @@ func (ml *Model) renderContent(message discord.Message, baseStyle tcell.Style, f return b.Finish(), nil, nil } -func (ml *Model) drawSnapshotContent(builder *richtext.Builder, parent discord.Message, snapshot discord.MessageSnapshotMessage, baseStyle tcell.Style) { +func (ml *Model) drawSnapshotContent(builder *richtext.Builder, parent discord.Message, snapshot discord.MessageSnapshotMessage, baseStyle tview.Style) { // Convert discord.MessageSnapshotMessage to discord.Message with common fields. message := discord.Message{ Type: snapshot.Type, @@ -554,7 +555,7 @@ func (ml *Model) drawSnapshotContent(builder *richtext.Builder, parent discord.M ml.drawContent(builder, message, baseStyle) } -func (ml *Model) drawDefaultMessage(builder *richtext.Builder, message discord.Message, baseStyle tcell.Style) { +func (ml *Model) drawDefaultMessage(builder *richtext.Builder, message discord.Message, baseStyle tview.Style) { if ml.cfg.Timestamps.Enabled { ml.drawTimestamps(builder, message.Timestamp, baseStyle) } @@ -582,7 +583,7 @@ func (ml *Model) drawDefaultMessage(builder *richtext.Builder, message discord.M } } -func (ml *Model) drawEmbeds(builder *richtext.Builder, message discord.Message, baseStyle tcell.Style, contentRoot ast.Node, contentSource []byte) { +func (ml *Model) drawEmbeds(builder *richtext.Builder, message discord.Message, baseStyle tview.Style, contentRoot ast.Node, contentSource []byte) { if len(message.Embeds) == 0 { return } @@ -675,8 +676,8 @@ const ( embedLineURL ) -func embedLineStyles(baseStyle tcell.Style, theme config.MessagesListEmbedsTheme) [8]tcell.Style { - styles := [8]tcell.Style{} +func embedLineStyles(baseStyle tview.Style, theme config.MessagesListEmbedsTheme) [8]tview.Style { + styles := [8]tview.Style{} styles[embedLineProvider] = tview.MergeStyle(baseStyle, theme.ProviderStyle.Style) styles[embedLineAuthor] = tview.MergeStyle(baseStyle, theme.AuthorStyle.Style) styles[embedLineTitle] = tview.MergeStyle(baseStyle, theme.TitleStyle.Style) @@ -804,7 +805,7 @@ func isMarkdownEscapable(c byte) bool { } } -func (ml *Model) drawForwardedMessage(builder *richtext.Builder, message discord.Message, baseStyle tcell.Style) { +func (ml *Model) drawForwardedMessage(builder *richtext.Builder, message discord.Message, baseStyle tview.Style) { dimStyle := baseStyle.Dim(true) ml.drawTimestamps(builder, message.Timestamp, baseStyle) ml.drawAuthor(builder, message, baseStyle) @@ -813,7 +814,7 @@ func (ml *Model) drawForwardedMessage(builder *richtext.Builder, message discord builder.Write(" ("+ml.formatTimestamp(message.MessageSnapshots[0].Message.Timestamp)+") ", dimStyle) } -func (ml *Model) drawReplyMessage(builder *richtext.Builder, message discord.Message, baseStyle tcell.Style) { +func (ml *Model) drawReplyMessage(builder *richtext.Builder, message discord.Message, baseStyle tview.Style) { dimStyle := baseStyle.Dim(true) builder.Write(ml.cfg.Theme.MessagesList.ReplyIndicator+" ", dimStyle) @@ -829,7 +830,7 @@ func (ml *Model) drawReplyMessage(builder *richtext.Builder, message discord.Mes ml.drawDefaultMessage(builder, message, baseStyle) } -func (ml *Model) drawPinnedMessage(builder *richtext.Builder, message discord.Message, baseStyle tcell.Style) { +func (ml *Model) drawPinnedMessage(builder *richtext.Builder, message discord.Message, baseStyle tview.Style) { builder.Write(message.Author.DisplayOrUsername()+" pinned a message.", baseStyle) } diff --git a/internal/ui/chat/model.go b/internal/ui/chat/model.go index f7b868e..d1e36fd 100644 --- a/internal/ui/chat/model.go +++ b/internal/ui/chat/model.go @@ -132,7 +132,7 @@ const ( ) // pickerView returns the view of the picker shown on top, or nil if none is open. -func (m Model) pickerView() tview.Element { +func (m Model) pickerView() tview.Widget { switch m.overlay { case overlayChannelsPicker: return m.channelsPicker.View() @@ -346,25 +346,25 @@ func (m *Model) updatePane(p pane, msg tview.Msg) tview.Cmd { return cmd } -// paneElement passes input to the element of a pane and marks mouse input within the pane as meant for it. -type paneElement struct { +// paneWidget passes input to the widget of a pane and marks mouse input within the pane as meant for it. +type paneWidget struct { pane pane - child tview.Element + child tview.Widget } -func (p paneElement) Size() (width, height layout.Length) { +func (p paneWidget) Size() (width, height layout.Length) { return p.child.Size() } -func (p paneElement) Layout(limits layout.Limits) layout.Size { +func (p paneWidget) Layout(limits layout.Limits) layout.Size { return p.child.Layout(limits) } -func (p paneElement) Draw(screen tview.Screen, area tview.Rectangle) { +func (p paneWidget) Draw(screen tview.Screen, area tview.Rectangle) { p.child.Draw(screen, area) } -func (p paneElement) Handle(msg tview.Msg, area tview.Rectangle) tview.Msg { +func (p paneWidget) Handle(msg tview.Msg, area tview.Rectangle) tview.Msg { out := p.child.Handle(msg, area) if mouse, ok := msg.(tview.MouseMsg); ok && area.Contains(mouse.Position()) { return paneMsg{pane: p.pane, msg: out, focus: mouse.Action == tview.MouseLeftDown} @@ -385,9 +385,9 @@ const ( ) // paneView returns the view of p, focused if it has the focus and no picker is open, marked so that clicking it focuses it. -func (m Model) paneView(p pane) tview.Element { +func (m Model) paneView(p pane) tview.Widget { focused := m.focused == p && m.overlay == overlayNone - var child tview.Element + var child tview.Widget switch p { case paneGuildsTree: child = m.guildsTree.View(focused) @@ -398,7 +398,7 @@ func (m Model) paneView(p pane) tview.Element { case paneMembersTree: child = m.membersTree.View(focused) } - return paneElement{pane: p, child: child} + return paneWidget{pane: p, child: child} } // setFocus focuses p if it can take the focus. @@ -423,10 +423,10 @@ func (m Model) canFocus(p pane) bool { } // View shows the guilds tree left of the messages above the composer, with the mentions list over the messages and an open picker on top. -func (m Model) View() tview.Element { +func (m Model) View() tview.Widget { picker := m.pickerView() - var right tview.Element = column.New( + var right tview.Widget = column.New( m.paneView(paneMessagesList), column.New(m.paneView(paneComposer)).Height(layout.Fixed(m.composer.Height())), ) diff --git a/internal/ui/chat/msg.go b/internal/ui/chat/msg.go index b0ffec7..1f3b984 100644 --- a/internal/ui/chat/msg.go +++ b/internal/ui/chat/msg.go @@ -67,7 +67,7 @@ func (m *Model) navigateToChannel(channelID discord.ChannelID) tview.Cmd { return cmd } -// paneMsg is what a pane's element made of a mouse message within it. A left mouse button press also focuses the pane. +// paneMsg is what a pane's widget made of a mouse message within it. A left mouse button press also focuses the pane. type paneMsg struct { pane pane msg tview.Msg diff --git a/internal/ui/login/model.go b/internal/ui/login/model.go index 3827668..34e20e3 100644 --- a/internal/ui/login/model.go +++ b/internal/ui/login/model.go @@ -50,8 +50,8 @@ func (m Model) Init() tview.Cmd { } // View shows the tabs in a box. -func (m Model) View() tview.Element { - var content tview.Element +func (m Model) View() tview.Widget { + var content tview.Widget switch m.active { case tabPassword: content = m.password.View() diff --git a/internal/ui/login/password/model.go b/internal/ui/login/password/model.go index ce9fa49..08d04b5 100644 --- a/internal/ui/login/password/model.go +++ b/internal/ui/login/password/model.go @@ -60,7 +60,7 @@ func (m Model) Update(msg tview.Msg) (Model, tview.Cmd) { return m, nil } -func (m Model) View() tview.Element { +func (m Model) View() tview.Widget { labelWidth := layout.Fixed(len("Password") + 1) login := textinput.New(&m.login). Focused(m.focus == focusLogin). diff --git a/internal/ui/login/qr/model.go b/internal/ui/login/qr/model.go index fefad8f..c97cad3 100644 --- a/internal/ui/login/qr/model.go +++ b/internal/ui/login/qr/model.go @@ -135,7 +135,7 @@ func halfBlock(top, bottom bool) rune { } // View centers the code, which scrolls when it is taller than the tab. -func (m Model) View() tview.Element { +func (m Model) View() tview.Widget { return center.New( textview.New(m.code). ScrollState(&m.scrollState). diff --git a/internal/ui/login/token/model.go b/internal/ui/login/token/model.go index a2f03b9..d506ca2 100644 --- a/internal/ui/login/token/model.go +++ b/internal/ui/login/token/model.go @@ -46,7 +46,7 @@ func (m Model) Update(msg tview.Msg) (Model, tview.Cmd) { return m, nil } -func (m Model) View() tview.Element { +func (m Model) View() tview.Widget { input := textinput.New(&m.token). Mask("*"). Focused(!m.buttonFocused). diff --git a/internal/ui/picker/picker.go b/internal/ui/picker/picker.go index 4ffbe9c..352b382 100644 --- a/internal/ui/picker/picker.go +++ b/internal/ui/picker/picker.go @@ -25,7 +25,7 @@ func NewModel(cfg *config.Config, title string) Model { func (Model) Init() tview.Cmd { return nil } // View shows the picker, turning the selected item into the message onSelect returns and canceling with onCancel. -func (m Model) View(onSelect func(picker.Item) tview.Msg, onCancel tview.Msg) tview.Element { +func (m Model) View(onSelect func(picker.Item) tview.Msg, onCancel tview.Msg) tview.Widget { cfg := m.cfg bar := scrollbar.New(). SymbolSet(cfg.Theme.ScrollBar.SymbolSet.SymbolSet). diff --git a/internal/ui/root/model.go b/internal/ui/root/model.go index 7fce5ef..c5a3550 100644 --- a/internal/ui/root/model.go +++ b/internal/ui/root/model.go @@ -151,8 +151,8 @@ func (m Model) helpHeight() int { } // View shows the inner model above help, with the modal dialog on top of both when one is open. -func (m Model) View() tview.Element { - var innerView, helpView tview.Element +func (m Model) View() tview.Widget { + var innerView, helpView tview.Widget switch m.screen { case screenLogin: innerView = m.login.View() @@ -173,13 +173,11 @@ func (m Model) View() tview.Element { // helpView returns the help for the keybinds that currently apply. func (m Model) helpView() help.Widget { cfg := m.cfg - styles := help.DefaultStyles() - styles.ShortKey = cfg.Theme.Help.ShortKeyStyle.Style - styles.ShortDesc = cfg.Theme.Help.ShortDescStyle.Style - styles.FullKey = cfg.Theme.Help.FullKeyStyle.Style - styles.FullDesc = cfg.Theme.Help.FullDescStyle.Style return help.New(m). - Styles(styles). + ShortKeyStyle(cfg.Theme.Help.ShortKeyStyle.Style). + ShortDescStyle(cfg.Theme.Help.ShortDescStyle.Style). + FullKeyStyle(cfg.Theme.Help.FullKeyStyle.Style). + FullDescStyle(cfg.Theme.Help.FullDescStyle.Style). CompactModifiers(cfg.Help.CompactModifiers). ShortSeparator(cfg.Help.Separator). ShowAll(m.helpShowAll) @@ -191,7 +189,7 @@ type ( ) // dialogView returns the dialog for the open modal request. -func (m Model) dialogView() tview.Element { +func (m Model) dialogView() tview.Widget { labels := make([]string, len(m.modal.Buttons)) for i, button := range m.modal.Buttons { labels[i] = button.Label diff --git a/internal/ui/util.go b/internal/ui/util.go index 353c202..e79f7ce 100644 --- a/internal/ui/util.go +++ b/internal/ui/util.go @@ -13,7 +13,7 @@ import ( ) // Box returns child in a box styled by the theme, highlighted while focused. -func Box(child tview.Element, theme *config.Theme, focused bool) box.Widget { +func Box(child tview.Widget, theme *config.Theme, focused bool) box.Widget { padding := theme.Border.Padding b := box.New(child). Padding(padding[0], padding[1], padding[2], padding[3]).