diff --git a/internal/config/alias_config.go b/internal/config/alias_config.go index ab576b8dd..59e6a24c5 100644 --- a/internal/config/alias_config.go +++ b/internal/config/alias_config.go @@ -1,6 +1,7 @@ package config import ( + "errors" "fmt" "gopkg.in/yaml.v3" @@ -11,14 +12,6 @@ type AliasConfig struct { Parent Config } -// TODO at what point should the alias top level be added? Lazily on first write, I think; -// but then we aren't initializing the default aliases that we want. also want to ensure that we -// don't re-add the default aliases if people delete them. -// -// I think I'm not going to worry about it for now; config setup will add the aliases and existing -// users can take some step later on to add them if they want them. we'll otherwise lazily create -// the aliases: section on first write. - func (a *AliasConfig) Exists(alias string) bool { if a.Empty() { return false @@ -36,10 +29,13 @@ func (a *AliasConfig) Get(alias string) string { func (a *AliasConfig) Add(alias, expansion string) error { if a.Root == nil { - // then we don't actually have an aliases stanza in the config yet. - keyNode := &yaml.Node{ - Kind: yaml.ScalarNode, - Value: "aliases", + // TODO awful hack bad type conversion i'm sorry + entry, err := a.Parent.(*fileConfig).FindEntryPrime("aliases") + + var notFound *NotFoundError + + if err != nil && !errors.As(err, ¬Found) { + return err } valueNode := &yaml.Node{ Kind: yaml.MappingNode, @@ -47,7 +43,29 @@ func (a *AliasConfig) Add(alias, expansion string) error { } a.Root = valueNode - a.Parent.Root().Content = append(a.Parent.Root().Content, keyNode, valueNode) + if errors.As(err, ¬Found) { + // No aliases: key; just append new aliases key and empty map to end + keyNode := &yaml.Node{ + Kind: yaml.ScalarNode, + Value: "aliases", + } + a.Parent.Root().Content = append(a.Parent.Root().Content, keyNode, valueNode) + } else { + // Empty aliases; inject new value node after existing aliases key + newContent := []*yaml.Node{} + for i := 0; i < len(a.Parent.Root().Content); i++ { + node := a.Parent.Root().Content[i] + if i == entry.Index { + } + if i == entry.Index { + newContent = append(newContent, entry.KeyNode, valueNode) + i++ + } else { + newContent = append(newContent, a.Parent.Root().Content[i]) + } + } + a.Parent.Root().Content = newContent + } } err := a.SetStringValue(alias, expansion) diff --git a/internal/config/config_type.go b/internal/config/config_type.go index ddcd13401..ca8d23a29 100644 --- a/internal/config/config_type.go +++ b/internal/config/config_type.go @@ -73,6 +73,32 @@ func (cm *ConfigMap) SetStringValue(key, value string) error { return nil } +type ConfigEntry struct { + KeyNode *yaml.Node + ValueNode *yaml.Node + Index int +} + +func (cm *ConfigMap) FindEntryPrime(key string) (ce *ConfigEntry, err error) { + err = nil + + ce = &ConfigEntry{} + + topLevelKeys := cm.Root.Content + for i, v := range topLevelKeys { + if v.Value == key { + ce.KeyNode = v + ce.Index = i + if i+1 < len(topLevelKeys) { + ce.ValueNode = topLevelKeys[i+1] + } + return + } + } + + return ce, &NotFoundError{errors.New("not found")} +} + func (cm *ConfigMap) FindEntry(key string) (keyNode, valueNode *yaml.Node, err error) { err = nil @@ -195,7 +221,9 @@ func (c *fileConfig) Aliases() (*AliasConfig, error) { func (c *fileConfig) parseAliasConfig(aliasesEntry *yaml.Node) (*AliasConfig, error) { if aliasesEntry.Kind != yaml.MappingNode { - return nil, errors.New("expected aliases to be a map") + return &AliasConfig{ + Parent: c, + }, nil } aliasConfig := AliasConfig{