diff --git a/go.mod b/go.mod index 83b796964abf2f2a39af6ca76da7d7a16163d11a..1bd1b27a7707b29632e9069368e3dfca100fbb2b 100644 --- a/go.mod +++ b/go.mod @@ -76,7 +76,7 @@ require ( github.com/charmbracelet/colorprofile v0.3.2 // indirect github.com/charmbracelet/ultraviolet v0.0.0-20250813213450-50737e162af5 github.com/charmbracelet/x/cellbuf v0.0.14-0.20250811133356-e0c5dbe5ea4a // indirect - github.com/charmbracelet/x/exp/slice v0.0.0-20250611152503-f53cdd7e01ef + github.com/charmbracelet/x/exp/slice v0.0.0-20250829135019-44e44e21330d github.com/charmbracelet/x/term v0.2.1 github.com/charmbracelet/x/termios v0.1.1 // indirect github.com/charmbracelet/x/windows v0.2.2 // indirect diff --git a/go.sum b/go.sum index df215cd1458bc6a49da822616e21847628c7730d..74cff4241beb8bf7551cc327422b8431ef95085a 100644 --- a/go.sum +++ b/go.sum @@ -102,8 +102,8 @@ github.com/charmbracelet/x/exp/charmtone v0.0.0-20250708181618-a60a724ba6c3 h1:1 github.com/charmbracelet/x/exp/charmtone v0.0.0-20250708181618-a60a724ba6c3/go.mod h1:T9jr8CzFpjhFVHjNjKwbAD7KwBNyFnj2pntAO7F2zw0= github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a h1:FsHEJ52OC4VuTzU8t+n5frMjLvpYWEznSr/u8tnkCYw= github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= -github.com/charmbracelet/x/exp/slice v0.0.0-20250611152503-f53cdd7e01ef h1:v7qwsZ2OxzlwvpKwz8dtZXp7fIJlcDEUOyFBNE4fz4Q= -github.com/charmbracelet/x/exp/slice v0.0.0-20250611152503-f53cdd7e01ef/go.mod h1:vI5nDVMWi6veaYH+0Fmvpbe/+cv/iJfMntdh+N0+Tms= +github.com/charmbracelet/x/exp/slice v0.0.0-20250829135019-44e44e21330d h1:H2oh4WlSsXy8qwLd7I3eAvPd/X3S40aM9l+h47WF1eA= +github.com/charmbracelet/x/exp/slice v0.0.0-20250829135019-44e44e21330d/go.mod h1:vI5nDVMWi6veaYH+0Fmvpbe/+cv/iJfMntdh+N0+Tms= github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY= diff --git a/internal/shell/shell.go b/internal/shell/shell.go index 618899d808b90163ac82c6970440c26c0110db76..ef3abf8d30d37490e452478abe38ef39efd8a7fa 100644 --- a/internal/shell/shell.go +++ b/internal/shell/shell.go @@ -20,7 +20,7 @@ import ( "strings" "sync" - "github.com/charmbracelet/crush/internal/slicesext" + "github.com/charmbracelet/x/exp/slice" "mvdan.cc/sh/moreinterp/coreutils" "mvdan.cc/sh/v3/expand" "mvdan.cc/sh/v3/interp" @@ -186,7 +186,7 @@ func ArgumentsBlocker(cmd string, args []string, flags []string) BlockFunc { } argsMatch := slices.Equal(argParts[:len(args)], args) - flagsMatch := slicesext.IsSubset(flags, flagParts) + flagsMatch := slice.IsSubset(flags, flagParts) return argsMatch && flagsMatch } diff --git a/internal/slicesext/slices.go b/internal/slicesext/slices.go deleted file mode 100644 index 9d4e1a07d4439f9d686562e1b9b91894289726a8..0000000000000000000000000000000000000000 --- a/internal/slicesext/slices.go +++ /dev/null @@ -1,17 +0,0 @@ -package slicesext - -func IsSubset[T comparable](a, b []T) bool { - if len(a) > len(b) { - return false - } - set := make(map[T]struct{}, len(b)) - for _, item := range b { - set[item] = struct{}{} - } - for _, item := range a { - if _, exists := set[item]; !exists { - return false - } - } - return true -} diff --git a/internal/slicesext/slices_test.go b/internal/slicesext/slices_test.go deleted file mode 100644 index 3593209513f44e55a51f510094aeebf550f08f75..0000000000000000000000000000000000000000 --- a/internal/slicesext/slices_test.go +++ /dev/null @@ -1,158 +0,0 @@ -package slicesext - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestIsSubset(t *testing.T) { - tests := []struct { - name string - a []string - b []string - expect bool - }{ - // Basic subset cases - { - name: "empty subset of empty", - a: []string{}, - b: []string{}, - expect: true, - }, - { - name: "empty subset of non-empty", - a: []string{}, - b: []string{"a", "b", "c"}, - expect: true, - }, - { - name: "non-empty not subset of empty", - a: []string{"a"}, - b: []string{}, - expect: false, - }, - { - name: "single element subset", - a: []string{"b"}, - b: []string{"a", "b", "c"}, - expect: true, - }, - { - name: "single element not subset", - a: []string{"d"}, - b: []string{"a", "b", "c"}, - expect: false, - }, - { - name: "multiple elements subset", - a: []string{"a", "c"}, - b: []string{"a", "b", "c", "d"}, - expect: true, - }, - { - name: "multiple elements not subset", - a: []string{"a", "e"}, - b: []string{"a", "b", "c", "d"}, - expect: false, - }, - { - name: "equal sets are subsets", - a: []string{"a", "b", "c"}, - b: []string{"a", "b", "c"}, - expect: true, - }, - { - name: "larger set not subset of smaller", - a: []string{"a", "b", "c", "d"}, - b: []string{"a", "b"}, - expect: false, - }, - - // Order independence - { - name: "subset with different order", - a: []string{"c", "a"}, - b: []string{"b", "a", "d", "c"}, - expect: true, - }, - - // Duplicate handling - { - name: "duplicates in subset", - a: []string{"a", "a", "b"}, - b: []string{"a", "b", "c"}, - expect: true, - }, - { - name: "duplicates in superset", - a: []string{"a", "b"}, - b: []string{"a", "a", "b", "b", "c"}, - expect: true, - }, - { - name: "duplicates in both", - a: []string{"a", "a", "b"}, - b: []string{"a", "a", "b", "b", "c"}, - expect: true, - }, - - // Real-world examples - { - name: "npm flags subset", - a: []string{"-g"}, - b: []string{"-g", "--verbose", "--save-dev"}, - expect: true, - }, - { - name: "npm flags not subset", - a: []string{"--global"}, - b: []string{"-g", "--verbose", "--save-dev"}, - expect: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := IsSubset(tt.a, tt.b) - require.Equal(t, tt.expect, result, - "IsSubset(%v, %v) should be %v", tt.a, tt.b, tt.expect) - }) - } -} - -func TestIsSubsetWithInts(t *testing.T) { - tests := []struct { - name string - a []int - b []int - expect bool - }{ - { - name: "int subset", - a: []int{1, 3}, - b: []int{1, 2, 3, 4}, - expect: true, - }, - { - name: "int not subset", - a: []int{1, 5}, - b: []int{1, 2, 3, 4}, - expect: false, - }, - { - name: "empty int subset", - a: []int{}, - b: []int{1, 2, 3}, - expect: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := IsSubset(tt.a, tt.b) - require.Equal(t, tt.expect, result, - "IsSubset(%v, %v) should be %v", tt.a, tt.b, tt.expect) - }) - } -}