mirror of
https://github.com/chenasraf/tx.git
synced 2026-05-17 17:28:08 +00:00
feat: config name case insensitivity
This commit is contained in:
@@ -33,12 +33,12 @@ func runAttach(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
item, exists := allConfig[key]
|
||||
item, actualKey, exists := allConfig.Get(key)
|
||||
if !exists {
|
||||
return NewUserError("tmux config item '" + key + "' not found")
|
||||
}
|
||||
|
||||
parsed := config.ParseConfig(key, item)
|
||||
parsed := config.ParseConfig(actualKey, item)
|
||||
|
||||
if !tmux.SessionExists(opts, parsed.Name) {
|
||||
return NewUserError("tmux session '" + parsed.Name + "' does not exist")
|
||||
|
||||
@@ -34,10 +34,11 @@ func runMain(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, exists := info.Merged.Config[selected]; !exists {
|
||||
if _, actualKey, exists := info.Merged.Config.Get(selected); !exists {
|
||||
return NewUserError("tmux config item '" + selected + "' not found")
|
||||
} else {
|
||||
key = actualKey
|
||||
}
|
||||
key = selected
|
||||
}
|
||||
|
||||
// Get config
|
||||
@@ -46,12 +47,12 @@ func runMain(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
item, exists := allConfig[key]
|
||||
item, actualKey, exists := allConfig.Get(key)
|
||||
if !exists {
|
||||
return NewUserError("tmux config item '" + key + "' not found")
|
||||
}
|
||||
|
||||
parsed := config.ParseConfig(key, item)
|
||||
parsed := config.ParseConfig(actualKey, item)
|
||||
|
||||
// Check if session exists
|
||||
if tmux.SessionExists(opts, parsed.Name) {
|
||||
|
||||
@@ -58,6 +58,41 @@ testproject:
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunMain_CaseInsensitiveKey(t *testing.T) {
|
||||
// Create a temp directory with a config file
|
||||
tmpDir := t.TempDir()
|
||||
configPath := filepath.Join(tmpDir, ".tmux.yaml")
|
||||
|
||||
content := `
|
||||
Notes:
|
||||
root: /tmp/notes
|
||||
windows:
|
||||
- ./src
|
||||
`
|
||||
err := os.WriteFile(configPath, []byte(content), 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to write temp config: %v", err)
|
||||
}
|
||||
|
||||
// Set XDG_CONFIG_HOME to temp directory so config is found
|
||||
oldXDG := os.Getenv("XDG_CONFIG_HOME")
|
||||
_ = os.Setenv("XDG_CONFIG_HOME", tmpDir)
|
||||
defer func() { _ = os.Setenv("XDG_CONFIG_HOME", oldXDG) }()
|
||||
|
||||
dry = true
|
||||
defer func() { dry = false }()
|
||||
|
||||
// Should succeed with different casings
|
||||
for _, key := range []string{"Notes", "notes", "NOTES", "nOtEs"} {
|
||||
t.Run(key, func(t *testing.T) {
|
||||
err := runMain(nil, []string{key})
|
||||
if err != nil {
|
||||
t.Errorf("expected no error for key %q, got %v", key, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunMain_InvalidKey(t *testing.T) {
|
||||
// Create a temp directory with a config file
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
@@ -33,11 +33,12 @@ func runRemove(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, exists := allConfig[key]; !exists {
|
||||
_, actualKey, exists := allConfig.Get(key)
|
||||
if !exists {
|
||||
return NewUserError("tmux config item '" + key + "' not found")
|
||||
}
|
||||
|
||||
err = config.RemoveConfigFromFile(key, removeLocal, opts.Dry)
|
||||
err = config.RemoveConfigFromFile(actualKey, removeLocal, opts.Dry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -49,12 +49,12 @@ func runShow(cmd *cobra.Command, args []string) error {
|
||||
key = selected
|
||||
}
|
||||
|
||||
item, exists := allConfig[key]
|
||||
item, actualKey, exists := allConfig.Get(key)
|
||||
if !exists {
|
||||
return NewUserError("tmux config item '" + key + "' not found")
|
||||
}
|
||||
|
||||
parsed := config.ParseConfig(key, item)
|
||||
parsed := config.ParseConfig(actualKey, item)
|
||||
|
||||
if showJSON {
|
||||
data, err := json.Marshal(parsed)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
@@ -15,6 +17,23 @@ type GlobalConfig struct {
|
||||
// ConfigFile represents the top-level config file: map of session name -> config
|
||||
type ConfigFile map[string]TmuxConfigItemInput
|
||||
|
||||
// Get performs a case-insensitive lookup of a key in the config file.
|
||||
// It returns the config item, the actual key as stored in the config, and whether it was found.
|
||||
func (c ConfigFile) Get(key string) (TmuxConfigItemInput, string, bool) {
|
||||
// Try exact match first
|
||||
if item, ok := c[key]; ok {
|
||||
return item, key, true
|
||||
}
|
||||
// Fall back to case-insensitive match
|
||||
lower := strings.ToLower(key)
|
||||
for k, v := range c {
|
||||
if strings.ToLower(k) == lower {
|
||||
return v, k, true
|
||||
}
|
||||
}
|
||||
return TmuxConfigItemInput{}, "", false
|
||||
}
|
||||
|
||||
// TmuxConfigItemInput represents a single tmux session configuration
|
||||
type TmuxConfigItemInput struct {
|
||||
Root string `yaml:"root"`
|
||||
|
||||
@@ -180,6 +180,102 @@ another:
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigFile_Get_ExactMatch(t *testing.T) {
|
||||
config := ConfigFile{
|
||||
"notes": {Root: "/tmp/notes"},
|
||||
"work": {Root: "/tmp/work"},
|
||||
}
|
||||
|
||||
item, actualKey, ok := config.Get("notes")
|
||||
if !ok {
|
||||
t.Fatal("expected to find 'notes'")
|
||||
}
|
||||
if actualKey != "notes" {
|
||||
t.Errorf("expected actualKey 'notes', got %q", actualKey)
|
||||
}
|
||||
if item.Root != "/tmp/notes" {
|
||||
t.Errorf("expected Root '/tmp/notes', got %q", item.Root)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigFile_Get_CaseInsensitive(t *testing.T) {
|
||||
config := ConfigFile{
|
||||
"Notes": {Root: "/tmp/notes"},
|
||||
"work": {Root: "/tmp/work"},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
lookup string
|
||||
wantKey string
|
||||
wantFound bool
|
||||
}{
|
||||
{"Notes", "Notes", true},
|
||||
{"notes", "Notes", true},
|
||||
{"NOTES", "Notes", true},
|
||||
{"nOtEs", "Notes", true},
|
||||
{"work", "work", true},
|
||||
{"Work", "work", true},
|
||||
{"WORK", "work", true},
|
||||
{"missing", "", false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.lookup, func(t *testing.T) {
|
||||
_, actualKey, ok := config.Get(tt.lookup)
|
||||
if ok != tt.wantFound {
|
||||
t.Errorf("Get(%q): found=%v, want %v", tt.lookup, ok, tt.wantFound)
|
||||
}
|
||||
if ok && actualKey != tt.wantKey {
|
||||
t.Errorf("Get(%q): actualKey=%q, want %q", tt.lookup, actualKey, tt.wantKey)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigFile_Get_ExactMatchTakesPrecedence(t *testing.T) {
|
||||
// If both "notes" and "Notes" exist, exact match should win
|
||||
config := ConfigFile{
|
||||
"notes": {Root: "/tmp/lower"},
|
||||
"Notes": {Root: "/tmp/upper"},
|
||||
}
|
||||
|
||||
_, actualKey, ok := config.Get("notes")
|
||||
if !ok {
|
||||
t.Fatal("expected to find 'notes'")
|
||||
}
|
||||
if actualKey != "notes" {
|
||||
t.Errorf("expected exact match 'notes', got %q", actualKey)
|
||||
}
|
||||
|
||||
_, actualKey, ok = config.Get("Notes")
|
||||
if !ok {
|
||||
t.Fatal("expected to find 'Notes'")
|
||||
}
|
||||
if actualKey != "Notes" {
|
||||
t.Errorf("expected exact match 'Notes', got %q", actualKey)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigFile_Get_NotFound(t *testing.T) {
|
||||
config := ConfigFile{
|
||||
"notes": {Root: "/tmp/notes"},
|
||||
}
|
||||
|
||||
_, _, ok := config.Get("missing")
|
||||
if ok {
|
||||
t.Error("expected not found for 'missing'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigFile_Get_EmptyConfig(t *testing.T) {
|
||||
config := ConfigFile{}
|
||||
|
||||
_, _, ok := config.Get("anything")
|
||||
if ok {
|
||||
t.Error("expected not found in empty config")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultEmptyLayout(t *testing.T) {
|
||||
if DefaultEmptyLayout.Cwd != "." {
|
||||
t.Errorf("expected Cwd to be '.', got %q", DefaultEmptyLayout.Cwd)
|
||||
|
||||
@@ -37,7 +37,7 @@ func AddSimpleConfigToFile(config ParsedTmuxConfigItem, local bool, dryRun bool)
|
||||
return err
|
||||
}
|
||||
|
||||
if _, exists := allConfigs[config.Name]; exists && !dryRun {
|
||||
if _, _, exists := allConfigs.Get(config.Name); exists && !dryRun {
|
||||
return fmt.Errorf("%w: '%s'", ErrConfigItemExists, config.Name)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user