refactor(chat): migrate guilds tree to tview tree package
This commit is contained in:
parent
ecaf28b7e5
commit
3089000935
4 changed files with 42 additions and 40 deletions
2
go.mod
2
go.mod
|
|
@ -11,7 +11,7 @@ require (
|
|||
github.com/alecthomas/chroma/v2 v2.26.1
|
||||
github.com/andybalholm/brotli v1.2.1
|
||||
github.com/ayn2op/clipboard v0.0.0-20260308203959-c5ad7df3fc97
|
||||
github.com/ayn2op/tview v0.0.0-20260530015500-a747daebb9d7
|
||||
github.com/ayn2op/tview v0.0.0-20260603033754-03ce043930ff
|
||||
github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb
|
||||
github.com/diamondburned/arikawa/v3 v3.6.1-0.20260518050745-b430932b3ee1
|
||||
github.com/diamondburned/ningen/v3 v3.0.1-0.20260306213430-5a08d3a709b4
|
||||
|
|
|
|||
4
go.sum
4
go.sum
|
|
@ -14,8 +14,8 @@ github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eT
|
|||
github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
||||
github.com/ayn2op/clipboard v0.0.0-20260308203959-c5ad7df3fc97 h1:WujETUV+v0DEJyZgjeLzQvihWyL80c0Tg4qf0dDo+Io=
|
||||
github.com/ayn2op/clipboard v0.0.0-20260308203959-c5ad7df3fc97/go.mod h1:3kFnpNCa3dF6WryzOMCDao7PfZ7DTCh+pievlfuwV80=
|
||||
github.com/ayn2op/tview v0.0.0-20260530015500-a747daebb9d7 h1:LgNpUAoVkSwZXIf1wlrq/UO+TPEi3LqcGyn3nDlGw8k=
|
||||
github.com/ayn2op/tview v0.0.0-20260530015500-a747daebb9d7/go.mod h1:W0lZFznN+hDXma+CT27czLM8/zbNOda6vsfVgHI1Sew=
|
||||
github.com/ayn2op/tview v0.0.0-20260603033754-03ce043930ff h1:847J26ULcb5dimVXU3ymJXdlmWUY/I/hLpQ5FMiGJOY=
|
||||
github.com/ayn2op/tview v0.0.0-20260603033754-03ce043930ff/go.mod h1:W0lZFznN+hDXma+CT27czLM8/zbNOda6vsfVgHI1Sew=
|
||||
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=
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/ayn2op/tview"
|
||||
"github.com/ayn2op/tview/help"
|
||||
"github.com/ayn2op/tview/keybind"
|
||||
"github.com/ayn2op/tview/tree"
|
||||
"github.com/diamondburned/arikawa/v3/discord"
|
||||
"github.com/diamondburned/arikawa/v3/gateway"
|
||||
"github.com/diamondburned/ningen/v3"
|
||||
|
|
@ -19,7 +20,7 @@ import (
|
|||
type dmNode struct{}
|
||||
|
||||
type guildsTree struct {
|
||||
*tview.TreeView
|
||||
*tree.Model
|
||||
chat *Model
|
||||
|
||||
cfg *config.Config
|
||||
|
|
@ -27,26 +28,26 @@ type guildsTree struct {
|
|||
// Fast-path indexes for frequent event handlers (read updates, picker
|
||||
// navigation). They mirror the current rendered tree and are rebuilt on
|
||||
// READY before nodes are added.
|
||||
guildNodeByID map[discord.GuildID]*tview.TreeNode
|
||||
channelNodeByID map[discord.ChannelID]*tview.TreeNode
|
||||
dmRootNode *tview.TreeNode
|
||||
guildNodeByID map[discord.GuildID]*tree.Node
|
||||
channelNodeByID map[discord.ChannelID]*tree.Node
|
||||
dmRootNode *tree.Node
|
||||
}
|
||||
|
||||
func newGuildsTree(cfg *config.Config, chat *Model) *guildsTree {
|
||||
gt := &guildsTree{
|
||||
TreeView: tview.NewTreeView(),
|
||||
cfg: cfg,
|
||||
chat: chat,
|
||||
Model: tree.NewModel(),
|
||||
cfg: cfg,
|
||||
chat: chat,
|
||||
|
||||
guildNodeByID: make(map[discord.GuildID]*tview.TreeNode),
|
||||
channelNodeByID: make(map[discord.ChannelID]*tview.TreeNode),
|
||||
guildNodeByID: make(map[discord.GuildID]*tree.Node),
|
||||
channelNodeByID: make(map[discord.ChannelID]*tree.Node),
|
||||
}
|
||||
|
||||
gt.Box = ui.ConfigureBox(gt.Box, &cfg.Theme)
|
||||
gt.
|
||||
SetRoot(tview.NewTreeNode("")).
|
||||
SetRoot(tree.NewNode("")).
|
||||
SetTopLevel(1).
|
||||
SetMarkers(tview.TreeMarkers{
|
||||
SetMarkers(tree.Markers{
|
||||
Expanded: cfg.Sidebar.Markers.Expanded,
|
||||
Collapsed: cfg.Sidebar.Markers.Collapsed,
|
||||
Leaf: cfg.Sidebar.Markers.Leaf,
|
||||
|
|
@ -71,7 +72,7 @@ func (gt *guildsTree) createFolderNode(folder gateway.GuildFolder, guildsByID ma
|
|||
name = folder.Name
|
||||
}
|
||||
|
||||
folderNode := tview.NewTreeNode(name).SetExpanded(gt.cfg.Theme.GuildsTree.AutoExpandFolders)
|
||||
folderNode := tree.NewNode(name).SetExpanded(gt.cfg.Theme.GuildsTree.AutoExpandFolders)
|
||||
if folder.Color != 0 {
|
||||
folderStyle := tcell.StyleDefault.Foreground(tcell.NewHexColor(int32(folder.Color)))
|
||||
gt.setNodeLineStyle(folderNode, folderStyle)
|
||||
|
|
@ -133,24 +134,24 @@ func (gt *guildsTree) dmStatusStyle(status discord.Status) tcell.Style {
|
|||
}
|
||||
}
|
||||
|
||||
func (gt *guildsTree) createGuildNode(n *tview.TreeNode, guild discord.Guild) {
|
||||
guildNode := tview.NewTreeNode(guild.Name).
|
||||
func (gt *guildsTree) createGuildNode(parent *tree.Node, guild discord.Guild) {
|
||||
guildNode := tree.NewNode(guild.Name).
|
||||
SetReference(guild.ID).
|
||||
SetExpandable(true).
|
||||
SetExpanded(false).
|
||||
SetIndent(gt.cfg.Sidebar.Indents.Guild)
|
||||
gt.setNodeLineStyle(guildNode, gt.guildNodeStyle(guild.ID))
|
||||
n.AddChild(guildNode)
|
||||
parent.AddChild(guildNode)
|
||||
gt.guildNodeByID[guild.ID] = guildNode
|
||||
}
|
||||
|
||||
func (gt *guildsTree) createChannelNode(node *tview.TreeNode, channel discord.Channel) {
|
||||
func (gt *guildsTree) createChannelNode(parent *tree.Node, channel discord.Channel) {
|
||||
if channel.Type != discord.DirectMessage && channel.Type != discord.GroupDM && channel.Type != discord.GuildCategory && !gt.chat.state.HasPermissions(channel.ID, discord.PermissionViewChannel) {
|
||||
return
|
||||
}
|
||||
|
||||
indents := gt.cfg.Sidebar.Indents
|
||||
channelNode := tview.NewTreeNode(ui.ChannelToString(channel, gt.cfg.Icons, gt.chat.state)).SetReference(channel.ID)
|
||||
channelNode := tree.NewNode(ui.ChannelToString(channel, gt.cfg.Icons, gt.chat.state)).SetReference(channel.ID)
|
||||
gt.setNodeLineStyle(channelNode, gt.channelNodeStyle(channel))
|
||||
switch channel.Type {
|
||||
case discord.DirectMessage:
|
||||
|
|
@ -166,11 +167,11 @@ func (gt *guildsTree) createChannelNode(node *tview.TreeNode, channel discord.Ch
|
|||
default:
|
||||
channelNode.SetIndent(indents.Channel)
|
||||
}
|
||||
node.AddChild(channelNode)
|
||||
parent.AddChild(channelNode)
|
||||
gt.channelNodeByID[channel.ID] = channelNode
|
||||
}
|
||||
|
||||
func (gt *guildsTree) setNodeLineStyle(node *tview.TreeNode, style tcell.Style) {
|
||||
func (gt *guildsTree) setNodeLineStyle(node *tree.Node, style tcell.Style) {
|
||||
line := node.GetLine()
|
||||
for i := range line {
|
||||
line[i].Style = style
|
||||
|
|
@ -178,7 +179,7 @@ func (gt *guildsTree) setNodeLineStyle(node *tview.TreeNode, style tcell.Style)
|
|||
node.SetLine(line)
|
||||
}
|
||||
|
||||
func (gt *guildsTree) createChannelNodes(node *tview.TreeNode, channels []discord.Channel) {
|
||||
func (gt *guildsTree) createChannelNodes(node *tree.Node, channels []discord.Channel) {
|
||||
// Preserve exact ordering semantics:
|
||||
// 1) top-level non-categories (in input order),
|
||||
// 2) categories that have at least one child in the source slice (in input order),
|
||||
|
|
@ -227,7 +228,7 @@ func isThread(t discord.ChannelType) bool {
|
|||
}
|
||||
}
|
||||
|
||||
func (gt *guildsTree) onSelected(node *tview.TreeNode) tview.Cmd {
|
||||
func (gt *guildsTree) onSelected(node *tree.Node) tview.Cmd {
|
||||
if len(node.GetChildren()) != 0 {
|
||||
node.SetExpanded(!node.IsExpanded())
|
||||
return nil
|
||||
|
|
@ -307,10 +308,10 @@ func (gt *guildsTree) loadChannel(channel discord.Channel) tview.Cmd {
|
|||
}
|
||||
}
|
||||
|
||||
func (gt *guildsTree) collapseParentNode(node *tview.TreeNode) {
|
||||
func (gt *guildsTree) collapseParentNode(node *tree.Node) {
|
||||
gt.
|
||||
GetRoot().
|
||||
Walk(func(n, parent *tview.TreeNode) bool {
|
||||
Walk(func(n, parent *tree.Node) bool {
|
||||
if n == node && parent.GetLevel() != 0 {
|
||||
parent.Collapse()
|
||||
gt.SetCurrentNode(parent)
|
||||
|
|
@ -323,10 +324,10 @@ func (gt *guildsTree) collapseParentNode(node *tview.TreeNode) {
|
|||
|
||||
func (gt *guildsTree) Update(msg tview.Msg) tview.Cmd {
|
||||
switch msg := msg.(type) {
|
||||
case tview.TreeViewSelectedMsg:
|
||||
case tree.SelectedMsg:
|
||||
return gt.onSelected(msg.Node)
|
||||
case tview.KeyMsg:
|
||||
handler := gt.TreeView.Update
|
||||
handler := gt.Model.Update
|
||||
switch {
|
||||
case keybind.Matches(msg, gt.cfg.Keybinds.GuildsTree.CollapseAll.Keybind):
|
||||
for _, node := range gt.GetRoot().GetChildren() {
|
||||
|
|
@ -353,10 +354,10 @@ func (gt *guildsTree) Update(msg tview.Msg) tview.Cmd {
|
|||
case keybind.Matches(msg, gt.cfg.Keybinds.GuildsTree.YankID.Keybind):
|
||||
return gt.yankID()
|
||||
}
|
||||
// Do not fall through to TreeView defaults for unmatched keys.
|
||||
// Do not fall through to defaults for unmatched keys.
|
||||
return nil
|
||||
}
|
||||
return gt.TreeView.Update(msg)
|
||||
return gt.Model.Update(msg)
|
||||
}
|
||||
|
||||
func (gt *guildsTree) yankID() tview.Cmd {
|
||||
|
|
@ -378,7 +379,7 @@ func (gt *guildsTree) yankID() tview.Cmd {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (gt *guildsTree) findNodeByReference(reference any) *tview.TreeNode {
|
||||
func (gt *guildsTree) findNodeByReference(reference any) *tree.Node {
|
||||
switch ref := reference.(type) {
|
||||
case discord.GuildID:
|
||||
return gt.guildNodeByID[ref]
|
||||
|
|
@ -388,8 +389,8 @@ func (gt *guildsTree) findNodeByReference(reference any) *tview.TreeNode {
|
|||
return gt.dmRootNode
|
||||
default:
|
||||
// Fallback keeps this helper safe for non-indexed custom references.
|
||||
var found *tview.TreeNode
|
||||
gt.GetRoot().Walk(func(node, _ *tview.TreeNode) bool {
|
||||
var found *tree.Node
|
||||
gt.GetRoot().Walk(func(node, _ *tree.Node) bool {
|
||||
if node.GetReference() == reference {
|
||||
found = node
|
||||
return false
|
||||
|
|
@ -400,7 +401,7 @@ func (gt *guildsTree) findNodeByReference(reference any) *tview.TreeNode {
|
|||
}
|
||||
}
|
||||
|
||||
func (gt *guildsTree) findNodeByChannelID(channelID discord.ChannelID) *tview.TreeNode {
|
||||
func (gt *guildsTree) findNodeByChannelID(channelID discord.ChannelID) *tree.Node {
|
||||
channel, err := gt.chat.state.Cabinet.Channel(channelID)
|
||||
if err != nil {
|
||||
slog.Error("failed to get channel", "channel_id", channelID, "err", err)
|
||||
|
|
@ -413,9 +414,9 @@ func (gt *guildsTree) findNodeByChannelID(channelID discord.ChannelID) *tview.Tr
|
|||
} else {
|
||||
reference = dmNode{}
|
||||
}
|
||||
if parentNode := gt.findNodeByReference(reference); parentNode != nil {
|
||||
if len(parentNode.GetChildren()) == 0 {
|
||||
gt.onSelected(parentNode)
|
||||
if parent := gt.findNodeByReference(reference); parent != nil {
|
||||
if len(parent.GetChildren()) == 0 {
|
||||
gt.onSelected(parent)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -423,7 +424,7 @@ func (gt *guildsTree) findNodeByChannelID(channelID discord.ChannelID) *tview.Tr
|
|||
return node
|
||||
}
|
||||
|
||||
func (gt *guildsTree) expandPathToNode(node *tview.TreeNode) {
|
||||
func (gt *guildsTree) expandPathToNode(node *tree.Node) {
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -490,7 +491,7 @@ func (gt *guildsTree) collapseKeybinds() []keybind.Keybind {
|
|||
return keybinds
|
||||
}
|
||||
|
||||
func (gt *guildsTree) canCollapseParent(node *tview.TreeNode) bool {
|
||||
func (gt *guildsTree) canCollapseParent(node *tree.Node) bool {
|
||||
if node == nil {
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/ayn2op/discordo/internal/notifications"
|
||||
"github.com/ayn2op/tview"
|
||||
"github.com/ayn2op/tview/tree"
|
||||
"github.com/diamondburned/arikawa/v3/discord"
|
||||
"github.com/diamondburned/arikawa/v3/gateway"
|
||||
"github.com/diamondburned/arikawa/v3/utils/httputil/httpdriver"
|
||||
|
|
@ -35,7 +36,7 @@ func (m *Model) onReady(event *gateway.ReadyEvent) tview.Cmd {
|
|||
// retain pointers to detached tree nodes.
|
||||
m.guildsTree.resetNodeIndex()
|
||||
|
||||
dmNode := tview.NewTreeNode("Direct Messages").SetReference(dmNode{}).SetExpandable(true).SetExpanded(false)
|
||||
dmNode := tree.NewNode("Direct Messages").SetReference(dmNode{}).SetExpandable(true).SetExpanded(false)
|
||||
m.guildsTree.dmRootNode = dmNode
|
||||
|
||||
root := m.guildsTree.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue