feat: integrate configuration file for clipboard history management

This commit is contained in:
Menno van Leeuwen 2025-05-21 00:22:39 +02:00
parent 380742a869
commit c42fa87c61
Signed by: vleeuwenmenno
SSH Key Fingerprint: SHA256:OJFmjANpakwD3F2Rsws4GLtbdz1TJ5tkQF0RZmF0TRE
8 changed files with 77 additions and 17 deletions

View File

@ -3,6 +3,7 @@ package commands
import ( import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/vleeuwenmenno/kcm/src/config"
"github.com/vleeuwenmenno/kcm/src/models" "github.com/vleeuwenmenno/kcm/src/models"
) )
@ -12,7 +13,8 @@ func NewClearCmd(history *models.History) *cobra.Command {
Short: "Clear clipboard history", Short: "Clear clipboard history",
Aliases: []string{"--clear"}, Aliases: []string{"--clear"},
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
history.Clear() cfg, _ := config.LoadConfig()
history.Clear(cfg.Clipboard.HistoryFile)
log.Info().Msg("Clipboard history cleared") log.Info().Msg("Clipboard history cleared")
}, },
} }

View File

@ -0,0 +1,27 @@
package commands
import (
"encoding/json"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/vleeuwenmenno/kcm/src/config"
)
// NewConfigCmd returns the cobra command for `kcm config`
func NewConfigCmd() *cobra.Command {
return &cobra.Command{
Use: "config",
Short: "Show the current configuration",
Run: func(cmd *cobra.Command, args []string) {
cfg, path := config.LoadConfig()
log.Info().Str("config_path", path).Msg("Config loaded from file")
cfgJson, err := json.MarshalIndent(cfg, "", " ")
if err != nil {
log.Error().Err(err).Msg("Failed to marshal config to JSON")
return
}
log.Info().Msgf("Loaded config:\n%s", string(cfgJson))
},
}
}

View File

@ -5,6 +5,7 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/vleeuwenmenno/kcm/src/config"
"github.com/vleeuwenmenno/kcm/src/models" "github.com/vleeuwenmenno/kcm/src/models"
"golang.design/x/clipboard" "golang.design/x/clipboard"
) )
@ -20,7 +21,8 @@ func NewCopyCmd(history *models.History) *cobra.Command {
if err != nil || index < 1 { if err != nil || index < 1 {
log.Fatal().Err(err).Msg("Invalid index") log.Fatal().Err(err).Msg("Invalid index")
} }
history.ReloadIfChanged() cfg, _ := config.LoadConfig()
history.ReloadIfChanged(cfg.Clipboard.HistoryFile)
historyLen := len(history.Items) historyLen := len(history.Items)
if index > historyLen { if index > historyLen {
log.Fatal().Int("index", index).Int("historyLen", historyLen).Msg("Index out of range") log.Fatal().Int("index", index).Int("historyLen", historyLen).Msg("Index out of range")

View File

@ -4,6 +4,7 @@ import (
"os" "os"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/vleeuwenmenno/kcm/src/config"
"github.com/vleeuwenmenno/kcm/src/models" "github.com/vleeuwenmenno/kcm/src/models"
) )
@ -14,7 +15,8 @@ func NewListCmd(history *models.History) *cobra.Command {
Short: "List clipboard history", Short: "List clipboard history",
Aliases: []string{"--list"}, Aliases: []string{"--list"},
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
history.ReloadIfChanged() cfg, _ := config.LoadConfig()
history.ReloadIfChanged(cfg.Clipboard.HistoryFile)
history.List(os.Stdout, noTrunc) history.List(os.Stdout, noTrunc)
}, },
} }

View File

@ -93,7 +93,9 @@ func NewWatchCmd(history *models.History) *cobra.Command {
Timestamp: time.Now(), Timestamp: time.Now(),
Pinned: false, Pinned: false,
} }
history.Add(item) // Load config for history file path
cfg, _ := config.LoadConfig()
history.Add(item, cfg.Clipboard.HistoryFile)
lastText = text lastText = text
log.Info().Str("content", text).Msg("Text item added ") log.Info().Str("content", text).Msg("Text item added ")
} }

View File

@ -16,6 +16,7 @@ type Config struct {
} `yaml:"logging"` } `yaml:"logging"`
Clipboard struct { Clipboard struct {
MaxItems int `yaml:"max_items"` MaxItems int `yaml:"max_items"`
HistoryFile string `yaml:"history_file"`
} `yaml:"clipboard"` } `yaml:"clipboard"`
} }
@ -43,6 +44,16 @@ func LoadConfig() (Config, string) {
if cfg.Logging.Path == "" { if cfg.Logging.Path == "" {
cfg.Logging.Path = logFilePath() cfg.Logging.Path = logFilePath()
} }
if cfg.Clipboard.HistoryFile == "" {
usr, err := user.Current()
if err != nil {
cfg.Clipboard.HistoryFile = "./history.gob"
} else {
dir := filepath.Join(usr.HomeDir, ".local", "share", "kcm")
os.MkdirAll(dir, 0700)
cfg.Clipboard.HistoryFile = filepath.Join(dir, "history.gob")
}
}
return cfg, path return cfg, path
} }
file.Close() file.Close()

View File

@ -36,7 +36,7 @@ func main() {
log.Debug().Str("config", cfgPath).Msg("Loaded configuration") log.Debug().Str("config", cfgPath).Msg("Loaded configuration")
history := &models.History{MaxItems: cfg.Clipboard.MaxItems} history := &models.History{MaxItems: cfg.Clipboard.MaxItems}
history.Load() history.Load(cfg.Clipboard.HistoryFile)
shouldReturn := handleDebugging() shouldReturn := handleDebugging()
if shouldReturn { if shouldReturn {
@ -56,7 +56,8 @@ func main() {
commands.NewSearchCmd(history), commands.NewSearchCmd(history),
commands.NewStatusCmd(), commands.NewStatusCmd(),
commands.NewVersionCmd(), commands.NewVersionCmd(),
commands.NewStopCmd(), // Add the stop command commands.NewStopCmd(),
commands.NewConfigCmd(),
) )
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {

View File

@ -30,10 +30,23 @@ func historyFilePath() string {
return filepath.Join(dir, "history.gob") return filepath.Join(dir, "history.gob")
} }
func (h *History) Save() error { func historyFilePathFromConfig(historyFile string) string {
if historyFile != "" {
return historyFile
}
usr, err := user.Current()
if err != nil {
return "./history.gob"
}
dir := filepath.Join(usr.HomeDir, ".local", "share", "kcm")
os.MkdirAll(dir, 0700)
return filepath.Join(dir, "history.gob")
}
func (h *History) Save(historyFile string) error {
h.mu.Lock() h.mu.Lock()
defer h.mu.Unlock() defer h.mu.Unlock()
file, err := os.Create(historyFilePath()) file, err := os.Create(historyFilePathFromConfig(historyFile))
if err != nil { if err != nil {
return err return err
} }
@ -42,10 +55,10 @@ func (h *History) Save() error {
return enc.Encode(h.Items) return enc.Encode(h.Items)
} }
func (h *History) Load() error { func (h *History) Load(historyFile string) error {
h.mu.Lock() h.mu.Lock()
defer h.mu.Unlock() defer h.mu.Unlock()
file, err := os.Open(historyFilePath()) file, err := os.Open(historyFilePathFromConfig(historyFile))
if err != nil { if err != nil {
return err return err
} }
@ -54,7 +67,7 @@ func (h *History) Load() error {
return dec.Decode(&h.Items) return dec.Decode(&h.Items)
} }
func (h *History) Add(item HistoryItem) { func (h *History) Add(item HistoryItem, historyFile string) {
h.mu.Lock() h.mu.Lock()
// Prevent duplicates: remove any existing item with the same hash // Prevent duplicates: remove any existing item with the same hash
itemHash := utils.HashBytes(item.Data) itemHash := utils.HashBytes(item.Data)
@ -77,14 +90,14 @@ func (h *History) Add(item HistoryItem) {
h.Items = h.Items[over:] h.Items = h.Items[over:]
} }
h.mu.Unlock() h.mu.Unlock()
h.Save() h.Save(historyFile)
} }
func (h *History) Clear() error { func (h *History) Clear(historyFile string) error {
h.mu.Lock() h.mu.Lock()
defer h.mu.Unlock() defer h.mu.Unlock()
h.Items = nil h.Items = nil
return h.Save() return h.Save(historyFile)
} }
func (h *History) List(w io.Writer, noTrunc bool) { func (h *History) List(w io.Writer, noTrunc bool) {
@ -110,6 +123,6 @@ func (h *History) List(w io.Writer, noTrunc bool) {
} }
} }
func (h *History) ReloadIfChanged() error { func (h *History) ReloadIfChanged(historyFile string) error {
return h.Load() return h.Load(historyFile)
} }