feat(config): add config get subcommand with suggestions

This commit is contained in:
Lewis Wynne 2026-02-11 23:37:52 +00:00
parent cc19ee5c0f
commit 6bba227654
3 changed files with 66 additions and 1 deletions

View file

@ -2,6 +2,7 @@ package cmd
import (
"fmt"
"strings"
"github.com/spf13/cobra"
)
@ -27,6 +28,27 @@ var configListCmd = &cobra.Command{
},
}
var configGetCmd = &cobra.Command{
Use: "get <key>",
Short: "Print a configuration value",
Args: cobra.ExactArgs(1),
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
defaults := defaultConfig()
fields := configFields(&config, &defaults)
f := findConfigField(fields, args[0])
if f == nil {
err := fmt.Errorf("unknown config key '%s'", args[0])
if suggestions := suggestConfigKey(fields, args[0]); len(suggestions) > 0 {
return withHint(err, fmt.Sprintf("did you mean '%s'?", strings.Join(suggestions, "', '")))
}
return err
}
fmt.Printf("%v\n", f.Value)
return nil
},
}
var configPathCmd = &cobra.Command{
Use: "path",
Short: "Print config file path",
@ -43,6 +65,7 @@ var configPathCmd = &cobra.Command{
}
func init() {
configCmd.AddCommand(configGetCmd)
configCmd.AddCommand(configListCmd)
configCmd.AddCommand(configPathCmd)
rootCmd.AddCommand(configCmd)

View file

@ -1,6 +1,10 @@
package cmd
import "reflect"
import (
"reflect"
"github.com/agnivade/levenshtein"
)
// ConfigField represents a single leaf field in the Config struct,
// mapped to its dotted TOML key path.
@ -53,3 +57,28 @@ func walk(cv, dv reflect.Value, prefix string, out *[]ConfigField) {
})
}
}
// findConfigField returns the ConfigField matching the given dotted key,
// or nil if not found.
func findConfigField(fields []ConfigField, key string) *ConfigField {
for i := range fields {
if fields[i].Key == key {
return &fields[i]
}
}
return nil
}
// suggestConfigKey returns Levenshtein-based suggestions for a mistyped config key.
func suggestConfigKey(fields []ConfigField, target string) []string {
minThreshold := 1
maxThreshold := 4
threshold := min(max(len(target)/3, minThreshold), maxThreshold)
var suggestions []string
for _, f := range fields {
if levenshtein.ComputeDistance(target, f.Key) <= threshold {
suggestions = append(suggestions, f.Key)
}
}
return suggestions
}

13
testdata/config-get.ct vendored Normal file
View file

@ -0,0 +1,13 @@
$ pda config get display_ascii_art
true
$ pda config get store.default_store_name
default
$ pda config get git.auto_commit
false
# Unknown key with suggestion
$ pda config get git.auto_comit --> FAIL
FAIL unknown config key 'git.auto_comit'
hint did you mean 'git.auto_commit'?