Skip to content

Commit 1e4f1e2

Browse files
committed
added config
1 parent 1252671 commit 1e4f1e2

File tree

5 files changed

+189
-19
lines changed

5 files changed

+189
-19
lines changed

command.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"os"
77
"strings"
88

9+
"github.com/rsteube/carapace/internal/config"
910
"github.com/rsteube/carapace/internal/uid"
1011
"github.com/rsteube/carapace/pkg/style"
1112
"github.com/spf13/cobra"
@@ -104,4 +105,35 @@ func addCompletionCommand(cmd *cobra.Command) {
104105
Carapace{styleSetCmd}.PositionalAnyCompletion(
105106
ActionStyleConfig(),
106107
)
108+
109+
addConfigCommand(carapaceCmd)
110+
}
111+
112+
func addConfigCommand(cmd *cobra.Command) {
113+
configCmd := &cobra.Command{
114+
Use: "config",
115+
Args: cobra.ExactArgs(1),
116+
Run: func(cmd *cobra.Command, args []string) {},
117+
}
118+
cmd.AddCommand(configCmd)
119+
120+
configSetCmd := &cobra.Command{
121+
Use: "set",
122+
Args: cobra.MinimumNArgs(1),
123+
Run: func(cmd *cobra.Command, args []string) {
124+
for _, arg := range args {
125+
if splitted := strings.SplitN(arg, "=", 2); len(splitted) == 2 {
126+
if err := config.SetConfig(splitted[0], splitted[1]); err != nil {
127+
fmt.Fprint(cmd.ErrOrStderr(), err.Error())
128+
}
129+
} else {
130+
fmt.Fprintf(cmd.ErrOrStderr(), "invalid format: '%v'", arg)
131+
}
132+
}
133+
},
134+
}
135+
configCmd.AddCommand(configSetCmd)
136+
Carapace{configSetCmd}.PositionalAnyCompletion(
137+
ActionConfigs(),
138+
)
107139
}

config.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package carapace
2+
3+
import (
4+
"strings"
5+
6+
"github.com/rsteube/carapace/internal/config"
7+
)
8+
9+
type carapaceConfig struct {
10+
DescriptionLength int
11+
}
12+
13+
func (c *carapaceConfig) Completion() ActionMap {
14+
return ActionMap{
15+
"DescriptionLength": ActionValues("40", "30"),
16+
}
17+
}
18+
19+
var conf = carapaceConfig{
20+
DescriptionLength: 40,
21+
}
22+
23+
func init() {
24+
config.RegisterConfig("carapace", &conf)
25+
}
26+
27+
type configI interface {
28+
Completion() ActionMap
29+
}
30+
31+
func ActionConfigs() Action {
32+
return ActionMultiParts("=", func(c Context) Action {
33+
switch len(c.Parts) {
34+
case 0:
35+
return ActionMultiParts(".", func(c Context) Action {
36+
switch len(c.Parts) {
37+
case 0:
38+
return ActionValues(config.GetConfigs()...).Invoke(c).Suffix(".").ToA()
39+
case 1:
40+
fields, err := config.GetConfigFields(c.Parts[0])
41+
if err != nil {
42+
return ActionMessage(err.Error())
43+
}
44+
45+
vals := make([]string, 0)
46+
for _, field := range fields {
47+
vals = append(vals, field.Name, field.Description, field.Style)
48+
}
49+
return ActionStyledValuesDescribed(vals...).Invoke(c).Suffix("=").ToA()
50+
default:
51+
return ActionValues()
52+
}
53+
})
54+
case 1:
55+
if m := config.GetConfigMap(strings.Split(c.Parts[0], ".")[0]); m != nil {
56+
if i, ok := m.(configI); ok {
57+
// TODO check splitted length
58+
return i.Completion()[strings.Split(c.Parts[0], ".")[1]]
59+
}
60+
}
61+
return ActionValues()
62+
default:
63+
return ActionValues()
64+
}
65+
})
66+
}

internal/config/config.go

Lines changed: 74 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"os"
88
"path/filepath"
99
"reflect"
10+
"strconv"
1011
"strings"
1112

1213
"github.com/rsteube/carapace/pkg/xdg"
@@ -22,34 +23,60 @@ func (c configMap) Keys() []string {
2223
return keys
2324
}
2425

25-
type Field struct {
26-
Name string
27-
Description string
28-
Style string
29-
Tag string
30-
}
31-
32-
func (c configMap) Fields(name string) ([]Field, error) {
26+
// func (c configMap) Fields(name string, styled bool) ([]string, error) {
27+
// if i, ok := c[name]; ok {
28+
// fields := make([]string, 0)
29+
// t := reflect.TypeOf(i).Elem()
30+
// for index := 0; index < t.NumField(); index++ {
31+
// field := t.Field(index)
32+
// style := ""
33+
// if styled {
34+
// if field.Type.Name() != "string" {
35+
// return nil, fmt.Errorf("invalid field type [name: '%v', type: '%v']", field.Name, field.Type.Name())
36+
// }
37+
// v := reflect.ValueOf(i).Elem()
38+
// style = v.FieldByName(field.Name).String()
39+
// }
40+
// fields = append(fields, field.Name, field.Tag.Get("desc"), style)
41+
// }
42+
// return fields, nil
43+
// }
44+
// return nil, fmt.Errorf("unknown config: '%v'", name)
45+
// }
46+
47+
func (c configMap) Fields(name string, styled bool) ([]Field, error) {
3348
if i, ok := c[name]; ok {
3449
fields := make([]Field, 0)
3550
t := reflect.TypeOf(i).Elem()
3651
v := reflect.ValueOf(i).Elem()
3752
for index := 0; index < t.NumField(); index++ {
3853
field := t.Field(index)
39-
if field.Type.Name() != "string" {
54+
if styled && field.Type.Name() != "string" {
4055
return nil, fmt.Errorf("invalid field type [name: '%v', type: '%v']", field.Name, field.Type.Name())
4156
}
42-
fields = append(fields, Field{field.Name, field.Tag.Get("desc"), v.FieldByName(field.Name).String(), field.Tag.Get("tag")})
57+
fields = append(fields, Field{
58+
Name: field.Name,
59+
Description: field.Tag.Get("desc"),
60+
Style: v.FieldByName(field.Name).String(), // TODO only if styled
61+
Tag: field.Tag.Get("tag"),
62+
Type: field.Type,
63+
})
4364
}
4465
return fields, nil
4566
}
4667
return nil, fmt.Errorf("unknown config: '%v'", name)
4768
}
4869

4970
var config = struct {
50-
Styles configMap
71+
Configs configMap
72+
Styles configMap
5173
}{
52-
Styles: make(configMap),
74+
Configs: make(configMap),
75+
Styles: make(configMap),
76+
}
77+
78+
func RegisterConfig(name string, i interface{}) {
79+
config.Configs[name] = i
5380
}
5481

5582
func RegisterStyle(name string, i interface{}) {
@@ -60,6 +87,11 @@ func Load() error {
6087
if err := load("styles", config.Styles); err != nil {
6188
return err
6289
}
90+
91+
// TODO duplicated, ok or improve?
92+
if err := load("configs", config.Configs); err != nil {
93+
return err
94+
}
6395
return nil
6496
}
6597

@@ -73,7 +105,7 @@ func load(name string, c configMap) error {
73105
return err
74106
}
75107

76-
var unmarshalled map[string]map[string]string
108+
var unmarshalled map[string]map[string]interface{}
77109
if err := json.Unmarshal(content, &unmarshalled); err != nil {
78110
return err
79111
}
@@ -83,7 +115,7 @@ func load(name string, c configMap) error {
83115
elem := reflect.ValueOf(s).Elem()
84116
for k, v := range value {
85117
if field := elem.FieldByName(k); field != (reflect.Value{}) {
86-
field.SetString(v)
118+
field.Set(reflect.ValueOf(v).Convert(field.Type()))
87119
}
88120
}
89121
}
@@ -92,8 +124,16 @@ func load(name string, c configMap) error {
92124
return nil
93125
}
94126

127+
func SetConfig(key, value string) error {
128+
return set("configs", key, strings.Replace(value, ",", " ", -1))
129+
}
130+
131+
func GetConfigs() []string { return config.Configs.Keys() }
132+
func GetConfigFields(name string) ([]Field, error) { return config.Configs.Fields(name, false) }
133+
func GetConfigMap(name string) interface{} { return config.Configs[name] }
134+
95135
func GetStyleConfigs() []string { return config.Styles.Keys() }
96-
func GetStyleFields(name string) ([]Field, error) { return config.Styles.Fields(name) }
136+
func GetStyleFields(name string) ([]Field, error) { return config.Styles.Fields(name, true) }
97137
func SetStyle(key, value string) error {
98138
return set("styles", key, strings.Replace(value, ",", " ", -1))
99139
}
@@ -116,7 +156,7 @@ func set(name, key, value string) error {
116156
content = []byte("{}")
117157
}
118158

119-
var config map[string]map[string]string
159+
var config map[string]map[string]interface{}
120160
if err := json.Unmarshal(content, &config); err != nil {
121161
return err
122162
}
@@ -125,18 +165,33 @@ func set(name, key, value string) error {
125165
return errors.New("invalid key")
126166
} else {
127167
if _, ok := config[splitted[0]]; !ok {
128-
config[splitted[0]] = make(map[string]string, 0)
168+
config[splitted[0]] = make(map[string]interface{}, 0)
129169
}
130170
if strings.TrimSpace(value) == "" {
131171
delete(config[splitted[0]], splitted[1])
132172
} else {
133-
config[splitted[0]][splitted[1]] = value
173+
switch reflect.TypeOf(config[splitted[0]][splitted[1]]).Kind() {
174+
case reflect.Int:
175+
intValue, err := strconv.Atoi(value)
176+
if err != nil {
177+
return err
178+
}
179+
config[splitted[0]][splitted[1]] = intValue
180+
181+
case reflect.String:
182+
config[splitted[0]][splitted[1]] = value
183+
184+
case reflect.Slice:
185+
// TODO
186+
}
134187
}
135188
}
136189

137190
marshalled, err := json.MarshalIndent(config, "", " ")
138191
if err != nil {
139192
return err
140193
}
141-
return os.WriteFile(file, marshalled, os.ModePerm)
194+
os.WriteFile(file, marshalled, os.ModePerm)
195+
196+
return nil
142197
}

internal/config/field.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package config
2+
3+
import "reflect"
4+
5+
type Field struct {
6+
Name string
7+
Description string
8+
Style string
9+
Tag string
10+
Type reflect.Type
11+
}

pkg/config/config.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package config
2+
3+
import "github.com/rsteube/carapace/internal/config"
4+
5+
6+
func Register(name string, i interface{}) { config.RegisterConfig(name, i) }

0 commit comments

Comments
 (0)