package main import ( "encoding/json" "fmt" "io/ioutil" "strings" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) type GuildData map[string]GuildInfo type GuildInfo map[string]CategoryInfo type CategoryInfo struct { Channels map[string]ChannelInfo `json:"channels"` } type ChannelInfo struct { Channelname string `json:"channelname"` Channeltype string `json:"channeltype"` Access bool `json:"access"` } func loadJSONFiles(outputDir string) (map[string]GuildData, error) { allData := make(map[string]GuildData) files, err := ioutil.ReadDir(outputDir) if err != nil { return nil, err } for _, fileInfo := range files { if !fileInfo.IsDir() && strings.HasSuffix(fileInfo.Name(), ".json") { filePath := fmt.Sprintf("%s/%s", outputDir, fileInfo.Name()) data, err := ioutil.ReadFile(filePath) if err != nil { return nil, err } var fileGuildData GuildData if err := json.Unmarshal(data, &fileGuildData); err != nil { return nil, err } allData[fileInfo.Name()] = fileGuildData } } return allData, nil } func main() { outputDir := "output" allData, err := loadJSONFiles(outputDir) if err != nil { fmt.Println("Error loading JSON files:", err) return } app := tview.NewApplication() treeView := tview.NewTreeView().SetRoot(createTreeRoot(allData)).SetCurrentNode(createTreeRoot(allData)) treeView.SetBorder(true).SetTitle("Files, Guilds, Categories and Channels").SetTitleAlign(tview.AlignLeft) treeView.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { node := treeView.GetCurrentNode() if node == nil { return event } switch event.Key() { case tcell.KeyRight: node.SetExpanded(true) case tcell.KeyLeft: node.SetExpanded(false) } return event }) instructions := tview.NewTextView(). SetText("Navigate with Up/Down arrows. Expand with Right arrow, Collapse with Left arrow."). SetDynamicColors(true). SetRegions(true). SetWrap(true) flex := tview.NewFlex(). SetDirection(tview.FlexRow). AddItem(instructions, 1, 1, false). AddItem(treeView, 0, 1, true) if err := app.SetRoot(flex, true).Run(); err != nil { panic(err) } } func createTreeRoot(allData map[string]GuildData) *tview.TreeNode { root := tview.NewTreeNode("Files") for fileName, guildData := range allData { fileNode := tview.NewTreeNode(fileName).SetReference(fileName).SetColor(tview.Styles.SecondaryTextColor) for guildName, categories := range guildData { guildNode := tview.NewTreeNode(guildName).SetReference(guildName).SetColor(tview.Styles.PrimaryTextColor) for categoryName, categoryInfo := range categories { categoryNode := tview.NewTreeNode(categoryName).SetReference(categoryName).SetColor(tview.Styles.TertiaryTextColor) for _, channelInfo := range categoryInfo.Channels { access := "No" if channelInfo.Access { access = "Yes" } channelNode := tview.NewTreeNode(fmt.Sprintf("%s (Type: %s, Access: %s)", channelInfo.Channelname, channelInfo.Channeltype, access)). SetReference(channelInfo.Channelname). SetColor(tview.Styles.ContrastSecondaryTextColor) categoryNode.AddChild(channelNode) } categoryNode.SetExpanded(false) guildNode.AddChild(categoryNode) } guildNode.SetExpanded(false) fileNode.AddChild(guildNode) } fileNode.SetExpanded(false) root.AddChild(fileNode) } return root }