ソースを参照

feat: replace slog with charmbracelet/log

ayn2op 1 年間 前
コミット
a5c5540147
9 ファイル変更86 行追加69 行削除
  1. 8 7
      cmd/guilds_tree.go
  2. 5 5
      cmd/layout.go
  3. 15 16
      cmd/message_input.go
  4. 14 14
      cmd/messages_text.go
  5. 2 2
      cmd/state.go
  6. 8 1
      go.mod
  7. 19 2
      go.sum
  8. 12 19
      internal/logger/logger.go
  9. 3 3
      main.go

+ 8 - 7
cmd/guilds_tree.go

@@ -2,11 +2,11 @@ package cmd
 
 
 import (
 import (
 	"fmt"
 	"fmt"
-	"log/slog"
 	"sort"
 	"sort"
 	"strings"
 	"strings"
 
 
 	"github.com/ayn2op/discordo/internal/config"
 	"github.com/ayn2op/discordo/internal/config"
+	"github.com/charmbracelet/log"
 	"github.com/diamondburned/arikawa/v3/discord"
 	"github.com/diamondburned/arikawa/v3/discord"
 	"github.com/diamondburned/arikawa/v3/gateway"
 	"github.com/diamondburned/arikawa/v3/gateway"
 	"github.com/gdamore/tcell/v2"
 	"github.com/gdamore/tcell/v2"
@@ -64,7 +64,7 @@ func (gt *GuildsTree) createFolderNode(folder gateway.GuildFolder) {
 	for _, gID := range folder.GuildIDs {
 	for _, gID := range folder.GuildIDs {
 		g, err := discordState.Cabinet.Guild(gID)
 		g, err := discordState.Cabinet.Guild(gID)
 		if err != nil {
 		if err != nil {
-			slog.Info("guild not found in state", "err", err, "guild", g)
+			log.Error("failed to get guild from state", "guild_id", gID, "err", err)
 			continue
 			continue
 		}
 		}
 
 
@@ -110,9 +110,10 @@ func (gt *GuildsTree) channelToString(c discord.Channel) string {
 
 
 func (gt *GuildsTree) createChannelNode(n *tview.TreeNode, c discord.Channel) *tview.TreeNode {
 func (gt *GuildsTree) createChannelNode(n *tview.TreeNode, c discord.Channel) *tview.TreeNode {
 	if c.Type != discord.DirectMessage && c.Type != discord.GroupDM {
 	if c.Type != discord.DirectMessage && c.Type != discord.GroupDM {
-		ps, err := discordState.Permissions(c.ID, discordState.Ready().User.ID)
+		userID := discordState.Ready().User.ID
+		ps, err := discordState.Permissions(c.ID, userID)
 		if err != nil {
 		if err != nil {
-			slog.Error("failed to get permissions", "err", err, "channel_id", c.ID)
+			log.Error("failed to get permissions for user in channel", "user_id", userID, "channel_id", c.ID, "err", err)
 			return nil
 			return nil
 		}
 		}
 
 
@@ -186,7 +187,7 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) {
 	case discord.GuildID:
 	case discord.GuildID:
 		cs, err := discordState.Cabinet.Channels(ref)
 		cs, err := discordState.Cabinet.Channels(ref)
 		if err != nil {
 		if err != nil {
-			slog.Error("failed to get channels", "err", err, "guild_id", ref)
+			log.Error("failed to get channels in the guild", "guild_id", ref, "err", err)
 			return
 			return
 		}
 		}
 
 
@@ -201,7 +202,7 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) {
 
 
 		c, err := discordState.Cabinet.Channel(ref)
 		c, err := discordState.Cabinet.Channel(ref)
 		if err != nil {
 		if err != nil {
-			slog.Error("failed to get channel", "channel_id", ref)
+			log.Error("channel not found in state", "channel_id", ref, "err", err)
 			return
 			return
 		}
 		}
 
 
@@ -212,7 +213,7 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) {
 	case nil: // Direct messages
 	case nil: // Direct messages
 		cs, err := discordState.PrivateChannels()
 		cs, err := discordState.PrivateChannels()
 		if err != nil {
 		if err != nil {
-			slog.Error("failed to get private channels", "err", err)
+			log.Error("failed to get private channels", "err", err)
 			return
 			return
 		}
 		}
 
 

+ 5 - 5
cmd/layout.go

@@ -1,9 +1,8 @@
 package cmd
 package cmd
 
 
 import (
 import (
-	"log/slog"
-
 	"github.com/ayn2op/discordo/internal/config"
 	"github.com/ayn2op/discordo/internal/config"
+	"github.com/charmbracelet/log"
 	"github.com/gdamore/tcell/v2"
 	"github.com/gdamore/tcell/v2"
 	"github.com/rivo/tview"
 	"github.com/rivo/tview"
 	"github.com/zalando/go-keyring"
 	"github.com/zalando/go-keyring"
@@ -43,12 +42,13 @@ func (l *Layout) show(token string) error {
 	if token == "" {
 	if token == "" {
 		loginForm := newLoginForm(func(token string, err error) {
 		loginForm := newLoginForm(func(token string, err error) {
 			if err != nil {
 			if err != nil {
-				slog.Error("failed to login", "err", err)
+				log.Error(err)
 				return
 				return
 			}
 			}
 
 
 			if err := l.show(token); err != nil {
 			if err := l.show(token); err != nil {
-				slog.Error("failed to show app", "err", err)
+				log.Error("failed to show app", "err", err)
+				return
 			}
 			}
 		}, l.cfg)
 		}, l.cfg)
 		l.app.SetRoot(loginForm, true)
 		l.app.SetRoot(loginForm, true)
@@ -110,7 +110,7 @@ func (l *Layout) onFlexInputCapture(event *tcell.EventKey) *tcell.EventKey {
 		l.app.Stop()
 		l.app.Stop()
 
 
 		if err := keyring.Delete(config.Name, "token"); err != nil {
 		if err := keyring.Delete(config.Name, "token"); err != nil {
-			slog.Error("failed to delete token from keyring", "err", err)
+			log.Error("failed to delete token from keyring", "err", err)
 			return nil
 			return nil
 		}
 		}
 
 

+ 15 - 16
cmd/message_input.go

@@ -1,13 +1,13 @@
 package cmd
 package cmd
 
 
 import (
 import (
-	"log/slog"
 	"os"
 	"os"
 	"os/exec"
 	"os/exec"
 	"strings"
 	"strings"
 
 
 	"github.com/atotto/clipboard"
 	"github.com/atotto/clipboard"
 	"github.com/ayn2op/discordo/internal/config"
 	"github.com/ayn2op/discordo/internal/config"
+	"github.com/charmbracelet/log"
 	"github.com/diamondburned/arikawa/v3/api"
 	"github.com/diamondburned/arikawa/v3/api"
 	"github.com/diamondburned/arikawa/v3/discord"
 	"github.com/diamondburned/arikawa/v3/discord"
 	"github.com/diamondburned/arikawa/v3/utils/json/option"
 	"github.com/diamondburned/arikawa/v3/utils/json/option"
@@ -85,12 +85,12 @@ func (mi *MessageInput) send() {
 		return
 		return
 	}
 	}
 
 
+	data := api.SendMessageData{
+		Content: text,
+	}
 	if mi.replyMessageID != 0 {
 	if mi.replyMessageID != 0 {
-		data := api.SendMessageData{
-			Content:         text,
-			Reference:       &discord.MessageReference{MessageID: mi.replyMessageID},
-			AllowedMentions: &api.AllowedMentions{RepliedUser: option.False},
-		}
+		data.Reference = &discord.MessageReference{MessageID: mi.replyMessageID}
+		data.AllowedMentions = &api.AllowedMentions{RepliedUser: option.False}
 
 
 		if strings.HasPrefix(mi.GetTitle(), "[@]") {
 		if strings.HasPrefix(mi.GetTitle(), "[@]") {
 			data.AllowedMentions.RepliedUser = option.True
 			data.AllowedMentions.RepliedUser = option.True
@@ -98,17 +98,16 @@ func (mi *MessageInput) send() {
 
 
 		go func() {
 		go func() {
 			if _, err := discordState.SendMessageComplex(layout.guildsTree.selectedChannelID, data); err != nil {
 			if _, err := discordState.SendMessageComplex(layout.guildsTree.selectedChannelID, data); err != nil {
-				slog.Error("failed to send message", "err", err)
-			}
-		}()
-	} else {
-		go func() {
-			if _, err := discordState.SendMessage(layout.guildsTree.selectedChannelID, text); err != nil {
-				slog.Error("failed to send message", "err", err)
 			}
 			}
 		}()
 		}()
 	}
 	}
 
 
+	go func() {
+		if _, err := discordState.SendMessageComplex(layout.guildsTree.selectedChannelID, data); err != nil {
+			log.Error("failed to send message in channel", "channel_id", layout.guildsTree.selectedChannelID, "err", err)
+		}
+	}()
+
 	mi.replyMessageID = 0
 	mi.replyMessageID = 0
 	mi.reset()
 	mi.reset()
 
 
@@ -124,7 +123,7 @@ func (mi *MessageInput) editor() {
 
 
 	f, err := os.CreateTemp("", tmpFilePattern)
 	f, err := os.CreateTemp("", tmpFilePattern)
 	if err != nil {
 	if err != nil {
-		slog.Error("failed to create temporary file", "err", err)
+		log.Error("failed to create temporary file", "err", err)
 		return
 		return
 	}
 	}
 	_, _ = f.WriteString(mi.GetText())
 	_, _ = f.WriteString(mi.GetText())
@@ -140,14 +139,14 @@ func (mi *MessageInput) editor() {
 	mi.app.Suspend(func() {
 	mi.app.Suspend(func() {
 		err := cmd.Run()
 		err := cmd.Run()
 		if err != nil {
 		if err != nil {
-			slog.Error("failed to run command", "err", err, "command", cmd)
+			log.Error("failed to run command", "args", cmd.Args, "err", err)
 			return
 			return
 		}
 		}
 	})
 	})
 
 
 	msg, err := os.ReadFile(f.Name())
 	msg, err := os.ReadFile(f.Name())
 	if err != nil {
 	if err != nil {
-		slog.Error("failed to read temporary file", "err", err, "name", f.Name())
+		log.Error("failed to read temporary file", "name", f.Name(), "err", err)
 		return
 		return
 	}
 	}
 
 

+ 14 - 14
cmd/messages_text.go

@@ -4,7 +4,6 @@ import (
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
-	"log/slog"
 	"slices"
 	"slices"
 	"strconv"
 	"strconv"
 	"time"
 	"time"
@@ -12,6 +11,7 @@ import (
 	"github.com/atotto/clipboard"
 	"github.com/atotto/clipboard"
 	"github.com/ayn2op/discordo/internal/config"
 	"github.com/ayn2op/discordo/internal/config"
 	"github.com/ayn2op/discordo/internal/markdown"
 	"github.com/ayn2op/discordo/internal/markdown"
+	"github.com/charmbracelet/log"
 	"github.com/diamondburned/arikawa/v3/discord"
 	"github.com/diamondburned/arikawa/v3/discord"
 	"github.com/diamondburned/ningen/v3/discordmd"
 	"github.com/diamondburned/ningen/v3/discordmd"
 	"github.com/gdamore/tcell/v2"
 	"github.com/gdamore/tcell/v2"
@@ -68,7 +68,7 @@ func newMessagesText(app *tview.Application, cfg *config.Config) *MessagesText {
 func (mt *MessagesText) drawMsgs(cID discord.ChannelID) {
 func (mt *MessagesText) drawMsgs(cID discord.ChannelID) {
 	ms, err := discordState.Messages(cID, uint(mt.cfg.MessagesLimit))
 	ms, err := discordState.Messages(cID, uint(mt.cfg.MessagesLimit))
 	if err != nil {
 	if err != nil {
-		slog.Error("failed to get messages", "err", err, "channel_id", cID)
+		log.Error("failed to get messages in channel", "channel_id", cID, "err", err)
 		return
 		return
 	}
 	}
 
 
@@ -223,13 +223,13 @@ func (mt *MessagesText) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
 func (mt *MessagesText) _select(name string) {
 func (mt *MessagesText) _select(name string) {
 	ms, err := discordState.Cabinet.Messages(layout.guildsTree.selectedChannelID)
 	ms, err := discordState.Cabinet.Messages(layout.guildsTree.selectedChannelID)
 	if err != nil {
 	if err != nil {
-		slog.Error("failed to get messages", "err", err, "channel_id", layout.guildsTree.selectedChannelID)
+		log.Error("failed to get messages in channel", "channel_id", layout.guildsTree.selectedChannelID, "err", err)
 		return
 		return
 	}
 	}
 
 
 	messageIdx, err := mt.getSelectedMessageIndex()
 	messageIdx, err := mt.getSelectedMessageIndex()
 	if err != nil {
 	if err != nil {
-		slog.Error("failed to get selected message", "err", err)
+		log.Error("failed to get selected message", "err", err)
 		return
 		return
 	}
 	}
 
 
@@ -290,7 +290,7 @@ func (mt *MessagesText) onHighlighted(added, removed, remaining []string) {
 	if len(added) > 0 {
 	if len(added) > 0 {
 		mID, err := strconv.ParseInt(added[0], 10, 64)
 		mID, err := strconv.ParseInt(added[0], 10, 64)
 		if err != nil {
 		if err != nil {
-			slog.Error("Failed to parse region id as int to use as message id.", "err", err)
+			log.Error("failed to parse region ID", "id", added[0], "err", err)
 			return
 			return
 		}
 		}
 		mt.selectedMessageID = discord.MessageID(mID)
 		mt.selectedMessageID = discord.MessageID(mID)
@@ -300,13 +300,13 @@ func (mt *MessagesText) onHighlighted(added, removed, remaining []string) {
 func (mt *MessagesText) yank() {
 func (mt *MessagesText) yank() {
 	msg, err := mt.getSelectedMessage()
 	msg, err := mt.getSelectedMessage()
 	if err != nil {
 	if err != nil {
-		slog.Error("failed to get selected message", "err", err)
+		log.Error("failed to get selected message", "err", err)
 		return
 		return
 	}
 	}
 
 
 	err = clipboard.WriteAll(msg.Content)
 	err = clipboard.WriteAll(msg.Content)
 	if err != nil {
 	if err != nil {
-		slog.Error("failed to write to clipboard", "err", err)
+		log.Error("failed to write to clipboard", "err", err)
 		return
 		return
 	}
 	}
 }
 }
@@ -314,7 +314,7 @@ func (mt *MessagesText) yank() {
 func (mt *MessagesText) open() {
 func (mt *MessagesText) open() {
 	msg, err := mt.getSelectedMessage()
 	msg, err := mt.getSelectedMessage()
 	if err != nil {
 	if err != nil {
-		slog.Error("failed to get selected message", "err", err)
+		log.Error("failed to get selected message", "err", err)
 		return
 		return
 	}
 	}
 
 
@@ -326,7 +326,7 @@ func (mt *MessagesText) open() {
 	for _, a := range attachments {
 	for _, a := range attachments {
 		go func() {
 		go func() {
 			if err := open.Start(a.URL); err != nil {
 			if err := open.Start(a.URL); err != nil {
-				slog.Error("failed to open URL", "err", err, "url", a.URL)
+				log.Error("failed to open url", "content_type", a.ContentType, "url", a.URL, "err", err)
 			}
 			}
 		}()
 		}()
 	}
 	}
@@ -342,7 +342,7 @@ func (mt *MessagesText) reply(mention bool) {
 
 
 	msg, err := mt.getSelectedMessage()
 	msg, err := mt.getSelectedMessage()
 	if err != nil {
 	if err != nil {
-		slog.Error("failed to get selected message", "err", err)
+		log.Error("failed to get selected message", "err", err)
 		return
 		return
 	}
 	}
 
 
@@ -355,7 +355,7 @@ func (mt *MessagesText) reply(mention bool) {
 func (mt *MessagesText) delete() {
 func (mt *MessagesText) delete() {
 	msg, err := mt.getSelectedMessage()
 	msg, err := mt.getSelectedMessage()
 	if err != nil {
 	if err != nil {
-		slog.Error("failed to get selected message", "err", err)
+		log.Error("failed to get selected message", "err", err)
 		return
 		return
 	}
 	}
 
 
@@ -376,18 +376,18 @@ func (mt *MessagesText) delete() {
 	}
 	}
 
 
 	if err := discordState.DeleteMessage(layout.guildsTree.selectedChannelID, msg.ID, ""); err != nil {
 	if err := discordState.DeleteMessage(layout.guildsTree.selectedChannelID, msg.ID, ""); err != nil {
-		slog.Error("failed to delete message", "err", err, "channel_id", layout.guildsTree.selectedChannelID, "message_id", msg.ID)
+		log.Error("failed to delete message in channel", "channel_id", layout.guildsTree.selectedChannelID, "message_id", msg.ID, "err", err)
 		return
 		return
 	}
 	}
 
 
 	if err := discordState.MessageRemove(layout.guildsTree.selectedChannelID, msg.ID); err != nil {
 	if err := discordState.MessageRemove(layout.guildsTree.selectedChannelID, msg.ID); err != nil {
-		slog.Error("failed to delete message", "err", err, "channel_id", layout.guildsTree.selectedChannelID, "message_id", msg.ID)
+		log.Error("failed to delete message in channel", "channel_id", layout.guildsTree.selectedChannelID, "message_id", msg.ID, "err", err)
 		return
 		return
 	}
 	}
 
 
 	ms, err := discordState.Cabinet.Messages(layout.guildsTree.selectedChannelID)
 	ms, err := discordState.Cabinet.Messages(layout.guildsTree.selectedChannelID)
 	if err != nil {
 	if err != nil {
-		slog.Error("failed to delete message", "err", err, "channel_id", layout.guildsTree.selectedChannelID)
+		log.Error("failed to get messages in channel", "channel_id", layout.guildsTree.selectedChannelID, "err", err)
 		return
 		return
 	}
 	}
 
 

+ 2 - 2
cmd/state.go

@@ -2,11 +2,11 @@ package cmd
 
 
 import (
 import (
 	"context"
 	"context"
-	"log/slog"
 	"runtime"
 	"runtime"
 	"slices"
 	"slices"
 
 
 	"github.com/ayn2op/discordo/internal/config"
 	"github.com/ayn2op/discordo/internal/config"
+	"github.com/charmbracelet/log"
 	"github.com/diamondburned/arikawa/v3/api"
 	"github.com/diamondburned/arikawa/v3/api"
 	"github.com/diamondburned/arikawa/v3/discord"
 	"github.com/diamondburned/arikawa/v3/discord"
 	"github.com/diamondburned/arikawa/v3/gateway"
 	"github.com/diamondburned/arikawa/v3/gateway"
@@ -54,7 +54,7 @@ func openState(token string, app *tview.Application, cfg *config.Config) error {
 func (s *State) onRequest(r httpdriver.Request) error {
 func (s *State) onRequest(r httpdriver.Request) error {
 	req, ok := r.(*httpdriver.DefaultRequest)
 	req, ok := r.(*httpdriver.DefaultRequest)
 	if ok {
 	if ok {
-		slog.Info("new HTTP request", "method", req.Method, "path", req.URL.Path)
+		log.Info("new HTTP request", "method", req.Method, "path", req.URL.Path)
 	}
 	}
 
 
 	return nil
 	return nil

+ 8 - 1
go.mod

@@ -5,10 +5,10 @@ go 1.23.2
 require (
 require (
 	github.com/BurntSushi/toml v1.4.0
 	github.com/BurntSushi/toml v1.4.0
 	github.com/atotto/clipboard v0.1.4
 	github.com/atotto/clipboard v0.1.4
+	github.com/charmbracelet/log v0.4.0
 	github.com/diamondburned/arikawa/v3 v3.4.0
 	github.com/diamondburned/arikawa/v3 v3.4.0
 	github.com/diamondburned/ningen/v3 v3.0.1-0.20240808103805-f1a24c0da3d8
 	github.com/diamondburned/ningen/v3 v3.0.1-0.20240808103805-f1a24c0da3d8
 	github.com/gdamore/tcell/v2 v2.7.4
 	github.com/gdamore/tcell/v2 v2.7.4
-	github.com/lmittmann/tint v1.0.5
 	github.com/rivo/tview v0.0.0-20241103174730-c76f7879f592
 	github.com/rivo/tview v0.0.0-20241103174730-c76f7879f592
 	github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
 	github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
 	github.com/yuin/goldmark v1.7.8
 	github.com/yuin/goldmark v1.7.8
@@ -17,17 +17,24 @@ require (
 
 
 require (
 require (
 	al.essio.dev/pkg/shellescape v1.5.1 // indirect
 	al.essio.dev/pkg/shellescape v1.5.1 // indirect
+	github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
+	github.com/charmbracelet/lipgloss v0.10.0 // indirect
 	github.com/danieljoos/wincred v1.2.2 // indirect
 	github.com/danieljoos/wincred v1.2.2 // indirect
 	github.com/gdamore/encoding v1.0.1 // indirect
 	github.com/gdamore/encoding v1.0.1 // indirect
+	github.com/go-logfmt/logfmt v0.6.0 // indirect
 	github.com/godbus/dbus/v5 v5.1.0 // indirect
 	github.com/godbus/dbus/v5 v5.1.0 // indirect
 	github.com/gorilla/schema v1.4.1 // indirect
 	github.com/gorilla/schema v1.4.1 // indirect
 	github.com/gorilla/websocket v1.5.3 // indirect
 	github.com/gorilla/websocket v1.5.3 // indirect
 	github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
 	github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
+	github.com/mattn/go-isatty v0.0.18 // indirect
 	github.com/mattn/go-runewidth v0.0.16 // indirect
 	github.com/mattn/go-runewidth v0.0.16 // indirect
+	github.com/muesli/reflow v0.3.0 // indirect
+	github.com/muesli/termenv v0.15.2 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/rivo/uniseg v0.4.7 // indirect
 	github.com/rivo/uniseg v0.4.7 // indirect
 	github.com/twmb/murmur3 v1.1.8 // indirect
 	github.com/twmb/murmur3 v1.1.8 // indirect
 	go4.org v0.0.0-20230225012048-214862532bf5 // indirect
 	go4.org v0.0.0-20230225012048-214862532bf5 // indirect
+	golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
 	golang.org/x/sys v0.28.0 // indirect
 	golang.org/x/sys v0.28.0 // indirect
 	golang.org/x/term v0.27.0 // indirect
 	golang.org/x/term v0.27.0 // indirect
 	golang.org/x/text v0.21.0 // indirect
 	golang.org/x/text v0.21.0 // indirect

+ 19 - 2
go.sum

@@ -23,7 +23,13 @@ github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
 github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
 github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
 github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s=
+github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE=
+github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM=
+github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -46,6 +52,8 @@ github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAY
 github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
 github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
+github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
 github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
 github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
 github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -90,13 +98,18 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
 github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
-github.com/lmittmann/tint v1.0.5 h1:NQclAutOfYsqs2F1Lenue6OoWCajs5wJcP3DfWVpePw=
-github.com/lmittmann/tint v1.0.5/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
 github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
 github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
+github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
 github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
 github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
 github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
 github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
 github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
 github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
+github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
+github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
+github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -104,6 +117,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/rivo/tview v0.0.0-20241103174730-c76f7879f592 h1:YIJ+B1hePP6AgynC5TcqpO0H9k3SSoZa2BGyL6vDUzM=
 github.com/rivo/tview v0.0.0-20241103174730-c76f7879f592 h1:YIJ+B1hePP6AgynC5TcqpO0H9k3SSoZa2BGyL6vDUzM=
 github.com/rivo/tview v0.0.0-20241103174730-c76f7879f592/go.mod h1:02iFIz7K/A9jGCvrizLPvoqr4cEIx7q54RH5Qudkrss=
 github.com/rivo/tview v0.0.0-20241103174730-c76f7879f592/go.mod h1:02iFIz7K/A9jGCvrizLPvoqr4cEIx7q54RH5Qudkrss=
+github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
 github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
 github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
 github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
@@ -144,6 +158,8 @@ golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE
 golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
+golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -210,6 +226,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
 golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
 golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

+ 12 - 19
internal/logger/logger.go

@@ -1,43 +1,36 @@
 package logger
 package logger
 
 
 import (
 import (
-	"log/slog"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
+	"time"
 
 
 	"github.com/ayn2op/discordo/internal/config"
 	"github.com/ayn2op/discordo/internal/config"
-	"github.com/lmittmann/tint"
+	"github.com/charmbracelet/log"
 )
 )
 
 
-// Recursively creates the log directory if it does not exist already and returns the path to the log file.
-func initialize() (string, error) {
+// Opens the log file and configures the default logger.
+func Load() error {
+	log.SetReportTimestamp(true)
+	log.SetReportCaller(true)
+	log.SetTimeFormat(time.Kitchen)
+
 	path, err := os.UserCacheDir()
 	path, err := os.UserCacheDir()
 	if err != nil {
 	if err != nil {
-		return "", err
+		return err
 	}
 	}
 
 
 	path = filepath.Join(path, config.Name)
 	path = filepath.Join(path, config.Name)
 	if err := os.MkdirAll(path, os.ModePerm); err != nil {
 	if err := os.MkdirAll(path, os.ModePerm); err != nil {
-		return "", err
-	}
-
-	return filepath.Join(path, "logs.txt"), nil
-}
-
-// Opens the log file and configures standard logger.
-func Load() error {
-	path, err := initialize()
-	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, os.ModePerm)
+	path = filepath.Join(path, "logs.txt")
+	file, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND, os.ModePerm)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	h := tint.NewHandler(file, nil)
-	l := slog.New(h)
-	slog.SetDefault(l)
+	log.SetOutput(file)
 	return nil
 	return nil
 }
 }

+ 3 - 3
main.go

@@ -2,10 +2,10 @@ package main
 
 
 import (
 import (
 	"flag"
 	"flag"
-	"log/slog"
 
 
 	"github.com/ayn2op/discordo/cmd"
 	"github.com/ayn2op/discordo/cmd"
 	"github.com/ayn2op/discordo/internal/config"
 	"github.com/ayn2op/discordo/internal/config"
+	"github.com/charmbracelet/log"
 	"github.com/zalando/go-keyring"
 	"github.com/zalando/go-keyring"
 )
 )
 
 
@@ -17,13 +17,13 @@ func main() {
 	if *token == "" {
 	if *token == "" {
 		t, err := keyring.Get(config.Name, "token")
 		t, err := keyring.Get(config.Name, "token")
 		if err != nil {
 		if err != nil {
-			slog.Info("failed to get token from keyring", "err", err)
+			log.Info("failed to get token from keyring", "err", err)
 		} else {
 		} else {
 			*token = t
 			*token = t
 		}
 		}
 	}
 	}
 
 
 	if err := cmd.Run(*token); err != nil {
 	if err := cmd.Run(*token); err != nil {
-		slog.Error("failed to run", "err", err)
+		log.Fatal(err)
 	}
 	}
 }
 }