Skip to content

Commit

Permalink
feat: add config command
Browse files Browse the repository at this point in the history
Configuration flags:
--styling disable or enable styling (0: default, 1: enable, 2: disable)
--map-colors allows to map colors to other colors, e.g. 0:230,1:213
--color-range display color range. Useful for finding colors to map
  • Loading branch information
radulucut committed Aug 17, 2024
1 parent 206f323 commit e803595
Show file tree
Hide file tree
Showing 8 changed files with 465 additions and 16 deletions.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,31 @@ cleed list
# Show all feeds in a list
cleed list mylist
```

#### Configuration

```bash
# Display configuration
cleed config

# Disable styling
cleed config --styling=false

# Map color 0 to 230 and color 1 to 213
cleed config --map-colors=0:230,1:213

# Remove color mapping for color 0
cleed config --map-colors=0:

# Clear all color mappings
cleed config --map-colors=

# Display color range. Useful for finding colors to map
cleed config --color-range
```

> **Color mapping**
>
> You can map the colors used in the feed reader to any color you want. This is useful if certain colors are not visible in your terminal based on the color scheme that you are using.
>
> Run `cleed config --color-range` to see the color range and map the colors that you want using the `cleed config --map-colors` command.
59 changes: 59 additions & 0 deletions cmd/cleed/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package cleed

import (
"github.com/spf13/cobra"
)

func (r *Root) initConfig() {
cmd := &cobra.Command{
Use: "config",
Short: "Display or change configuration",
Long: `Display or change configuration
Examples:
# Display configuration
cleed config
# Disable styling
cleed config --styling=false
# Map color 0 to 230 and color 1 to 213
cleed config --map-colors=0:230,1:213
# Remove color mapping for color 0
cleed config --map-colors=0:
# Clear all color mappings
cleed config --map-colors=
# Display color range. Useful for finding colors to map
cleed config --color-range
`,
RunE: r.RunConfig,
}

flags := cmd.Flags()
flags.Uint8("styling", 0, "disable or enable styling (0: default, 1: enable, 2: disable)")
flags.String("map-colors", "", "map colors to other colors, e.g. 0:230,1:213. Use --color-range to check available colors")
flags.Bool("color-range", false, "display color range. Useful for finding colors to map")

r.Cmd.AddCommand(cmd)
}

func (r *Root) RunConfig(cmd *cobra.Command, args []string) error {
if cmd.Flag("styling").Changed {
styling, err := cmd.Flags().GetUint8("styling")
if err != nil {
return err
}
return r.feed.SetStyling(styling)
}
if cmd.Flag("map-colors").Changed {
return r.feed.UpdateColorMap(cmd.Flag("map-colors").Value.String())
}
if cmd.Flag("color-range").Changed {
r.feed.DisplayColorRange()
return nil
}
return r.feed.DisplayConfig()
}
244 changes: 244 additions & 0 deletions cmd/cleed/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
package cleed

import (
"bytes"
"fmt"
"os"
"testing"
"time"

"github.com/radulucut/cleed/internal"
_storage "github.com/radulucut/cleed/internal/storage"
"github.com/radulucut/cleed/mocks"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
)

func Test_Config(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

timeMock := mocks.NewMockTime(ctrl)
timeMock.EXPECT().Now().Return(defaultCurrentTime).AnyTimes()

out := new(bytes.Buffer)
printer := internal.NewPrinter(nil, out, out)
storage := _storage.NewLocalStorage("cleed_test", timeMock)
defer localStorageCleanup(t, storage)

feed := internal.NewTerminalFeed(timeMock, printer, storage)
feed.SetAgent("cleed/test")

root, err := NewRoot("0.1.0", timeMock, printer, storage, feed)
assert.NoError(t, err)

os.Args = []string{"cleed", "config"}

err = root.Cmd.Execute()
assert.NoError(t, err)
assert.Equal(t, `Styling: enabled
Color map:
`, out.String())

config, err := storage.LoadConfig()
assert.NoError(t, err)
expectedConfig := &_storage.Config{
Version: "0.1.0",
LastRun: time.Time{},
Styling: 0,
ColorMap: make(map[uint8]uint8),
}
assert.Equal(t, expectedConfig, config)
}

func Test_Config_Styling(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

timeMock := mocks.NewMockTime(ctrl)
timeMock.EXPECT().Now().Return(defaultCurrentTime).AnyTimes()

out := new(bytes.Buffer)
printer := internal.NewPrinter(nil, out, out)
storage := _storage.NewLocalStorage("cleed_test", timeMock)
defer localStorageCleanup(t, storage)

feed := internal.NewTerminalFeed(timeMock, printer, storage)
feed.SetAgent("cleed/test")

root, err := NewRoot("0.1.0", timeMock, printer, storage, feed)
assert.NoError(t, err)

os.Args = []string{"cleed", "config", "--styling", "2"}

err = root.Cmd.Execute()
assert.NoError(t, err)
assert.Equal(t, "styling was updated\n", out.String())

config, err := storage.LoadConfig()
assert.NoError(t, err)
expectedConfig := &_storage.Config{
Version: "0.1.0",
LastRun: time.Time{},
Styling: 2,
ColorMap: make(map[uint8]uint8),
}
assert.Equal(t, expectedConfig, config)
}

func Test_Config_MapColors(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

timeMock := mocks.NewMockTime(ctrl)
timeMock.EXPECT().Now().Return(defaultCurrentTime).AnyTimes()

out := new(bytes.Buffer)
printer := internal.NewPrinter(nil, out, out)
storage := _storage.NewLocalStorage("cleed_test", timeMock)
defer localStorageCleanup(t, storage)

feed := internal.NewTerminalFeed(timeMock, printer, storage)
feed.SetAgent("cleed/test")

root, err := NewRoot("0.1.0", timeMock, printer, storage, feed)
assert.NoError(t, err)

os.Args = []string{"cleed", "config", "--map-colors", "1:2,3:4"}

err = root.Cmd.Execute()
assert.NoError(t, err)
assert.Equal(t, "color map updated\n", out.String())

config, err := storage.LoadConfig()
assert.NoError(t, err)
expectedConfig := &_storage.Config{
Version: "0.1.0",
LastRun: time.Time{},
Styling: 0,
ColorMap: map[uint8]uint8{1: 2, 3: 4},
}
assert.Equal(t, expectedConfig, config)
}

func Test_Config_MapColors_RemoveColorMapping(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

timeMock := mocks.NewMockTime(ctrl)
timeMock.EXPECT().Now().Return(defaultCurrentTime).AnyTimes()

out := new(bytes.Buffer)
printer := internal.NewPrinter(nil, out, out)
storage := _storage.NewLocalStorage("cleed_test", timeMock)
defer localStorageCleanup(t, storage)
storage.Init("0.1.0")

config, err := storage.LoadConfig()
assert.NoError(t, err)
config.ColorMap = map[uint8]uint8{1: 2, 3: 4}
err = storage.SaveConfig()
assert.NoError(t, err)

feed := internal.NewTerminalFeed(timeMock, printer, storage)
feed.SetAgent("cleed/test")

root, err := NewRoot("0.1.0", timeMock, printer, storage, feed)
assert.NoError(t, err)

os.Args = []string{"cleed", "config", "--map-colors", "1:"}

err = root.Cmd.Execute()
assert.NoError(t, err)
assert.Equal(t, "color map updated\n", out.String())

config, err = storage.LoadConfig()
assert.NoError(t, err)
expectedConfig := &_storage.Config{
Version: "0.1.0",
LastRun: time.Time{},
Styling: 0,
ColorMap: map[uint8]uint8{3: 4},
}
assert.Equal(t, expectedConfig, config)
}

func Test_Config_MapColors_ClearColorMapping(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

timeMock := mocks.NewMockTime(ctrl)
timeMock.EXPECT().Now().Return(defaultCurrentTime).AnyTimes()

out := new(bytes.Buffer)
printer := internal.NewPrinter(nil, out, out)
storage := _storage.NewLocalStorage("cleed_test", timeMock)
defer localStorageCleanup(t, storage)
storage.Init("0.1.0")

config, err := storage.LoadConfig()
assert.NoError(t, err)
config.ColorMap = map[uint8]uint8{1: 2, 3: 4}
err = storage.SaveConfig()
assert.NoError(t, err)

feed := internal.NewTerminalFeed(timeMock, printer, storage)
feed.SetAgent("cleed/test")

root, err := NewRoot("0.1.0", timeMock, printer, storage, feed)
assert.NoError(t, err)

os.Args = []string{"cleed", "config", "--map-colors="}

err = root.Cmd.Execute()
assert.NoError(t, err)
assert.Equal(t, "color map updated\n", out.String())

config, err = storage.LoadConfig()
assert.NoError(t, err)
expectedConfig := &_storage.Config{
Version: "0.1.0",
LastRun: time.Time{},
Styling: 0,
ColorMap: map[uint8]uint8{},
}
assert.Equal(t, expectedConfig, config)
}

func Test_Config_ColorRange(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

timeMock := mocks.NewMockTime(ctrl)
timeMock.EXPECT().Now().Return(defaultCurrentTime).AnyTimes()

out := new(bytes.Buffer)
printer := internal.NewPrinter(nil, out, out)
storage := _storage.NewLocalStorage("cleed_test", timeMock)
defer localStorageCleanup(t, storage)
storage.Init("0.1.0")

config, err := storage.LoadConfig()
assert.NoError(t, err)
config.ColorMap = map[uint8]uint8{1: 2, 3: 4}
err = storage.SaveConfig()
assert.NoError(t, err)

feed := internal.NewTerminalFeed(timeMock, printer, storage)
feed.SetAgent("cleed/test")

root, err := NewRoot("0.1.0", timeMock, printer, storage, feed)
assert.NoError(t, err)

os.Args = []string{"cleed", "config", "--color-range"}

err = root.Cmd.Execute()
assert.NoError(t, err)

expectedOutput := ""
for i := 0; i < 256; i++ {
expectedOutput += fmt.Sprintf("\033[38;5;%dm%d \033[0m", i, i)
}
expectedOutput += "\n"
assert.Equal(t, expectedOutput, out.String())
}
9 changes: 9 additions & 0 deletions cmd/cleed/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ func NewRoot(
return nil, fmt.Errorf("failed to initialize storage: %v", err)
}

config, err := root.storage.LoadConfig()
if err != nil {
return nil, fmt.Errorf("failed to load config: %v", err)
}
if config.Styling != 0 {
root.printer.SetStyling(config.Styling == 1)
}

root.Cmd = &cobra.Command{
Use: "cleed",
Short: "A command line feed reader",
Expand Down Expand Up @@ -101,6 +109,7 @@ Examples:
root.initFollow()
root.initUnfollow()
root.initList()
root.initConfig()

return root, nil
}
Expand Down
Loading

0 comments on commit e803595

Please sign in to comment.