on main help sign in
chore: `IsSubset` was moved to `x/exp/slice` (#923)
commita2e89c82fb02965730366f347f91d702f0cd99f6 authorAndrey Nering <andreynering@users.noreply.github.com> dateFri 29 Aug 2025, 12:12 (1 year ago) parent72dc566
5 files changed+5−180
go.mod+1−1 go.sum+2−2 internal/shell/shell.go+2−2 internal/slicesext/slices.go−17 internal/slicesext/slices_test.go−158
go.mod+1−1
@@ -76,7 +76,7 @@ require (
7676 github.com/charmbracelet/colorprofile v0.3.2 // indirect
7777 github.com/charmbracelet/ultraviolet v0.0.0-20250813213450-50737e162af5
7878 github.com/charmbracelet/x/cellbuf v0.0.14-0.20250811133356-e0c5dbe5ea4a // indirect
79− github.com/charmbracelet/x/exp/slice v0.0.0-20250611152503-f53cdd7e01ef
79+ github.com/charmbracelet/x/exp/slice v0.0.0-20250829135019-44e44e21330d
8080 github.com/charmbracelet/x/term v0.2.1
8181 github.com/charmbracelet/x/termios v0.1.1 // indirect
8282 github.com/charmbracelet/x/windows v0.2.2 // indirect
go.sum+2−2
@@ -102,8 +102,8 @@ github.com/charmbracelet/x/exp/charmtone v0.0.0-20250708181618-a60a724ba6c3 h1:1
102102github.com/charmbracelet/x/exp/charmtone v0.0.0-20250708181618-a60a724ba6c3/go.mod h1:T9jr8CzFpjhFVHjNjKwbAD7KwBNyFnj2pntAO7F2zw0=
103103github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a h1:FsHEJ52OC4VuTzU8t+n5frMjLvpYWEznSr/u8tnkCYw=
104104github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
105−github.com/charmbracelet/x/exp/slice v0.0.0-20250611152503-f53cdd7e01ef h1:v7qwsZ2OxzlwvpKwz8dtZXp7fIJlcDEUOyFBNE4fz4Q=
106−github.com/charmbracelet/x/exp/slice v0.0.0-20250611152503-f53cdd7e01ef/go.mod h1:vI5nDVMWi6veaYH+0Fmvpbe/+cv/iJfMntdh+N0+Tms=
105+github.com/charmbracelet/x/exp/slice v0.0.0-20250829135019-44e44e21330d h1:H2oh4WlSsXy8qwLd7I3eAvPd/X3S40aM9l+h47WF1eA=
106+github.com/charmbracelet/x/exp/slice v0.0.0-20250829135019-44e44e21330d/go.mod h1:vI5nDVMWi6veaYH+0Fmvpbe/+cv/iJfMntdh+N0+Tms=
107107github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
108108github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
109109github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY=
internal/shell/shell.go+2−2
@@ -20,7 +20,7 @@ import (
2020 "strings"
2121 "sync"
2222
23− "github.com/charmbracelet/crush/internal/slicesext"
23+ "github.com/charmbracelet/x/exp/slice"
2424 "mvdan.cc/sh/moreinterp/coreutils"
2525 "mvdan.cc/sh/v3/expand"
2626 "mvdan.cc/sh/v3/interp"
@@ -186,7 +186,7 @@ func ArgumentsBlocker(cmd string, args []string, flags []string) BlockFunc {
186186 }
187187
188188 argsMatch := slices.Equal(argParts[:len(args)], args)
189− flagsMatch := slicesext.IsSubset(flags, flagParts)
189+ flagsMatch := slice.IsSubset(flags, flagParts)
190190
191191 return argsMatch && flagsMatch
192192 }
internal/slicesext/slices.godeleted−17
@@ -1,17 +0,0 @@
1−package slicesext
2−
3−func IsSubset[T comparable](a, b []T) bool {
4− if len(a) > len(b) {
5− return false
6− }
7− set := make(map[T]struct{}, len(b))
8− for _, item := range b {
9− set[item] = struct{}{}
10− }
11− for _, item := range a {
12− if _, exists := set[item]; !exists {
13− return false
14− }
15− }
16− return true
17−}
internal/slicesext/slices_test.godeleted−158
@@ -1,158 +0,0 @@
1−package slicesext
2−
3−import (
4− "testing"
5−
6− "github.com/stretchr/testify/require"
7−)
8−
9−func TestIsSubset(t *testing.T) {
10− tests := []struct {
11− name string
12− a []string
13− b []string
14− expect bool
15− }{
16− // Basic subset cases
17− {
18− name: "empty subset of empty",
19− a: []string{},
20− b: []string{},
21− expect: true,
22− },
23− {
24− name: "empty subset of non-empty",
25− a: []string{},
26− b: []string{"a", "b", "c"},
27− expect: true,
28− },
29− {
30− name: "non-empty not subset of empty",
31− a: []string{"a"},
32− b: []string{},
33− expect: false,
34− },
35− {
36− name: "single element subset",
37− a: []string{"b"},
38− b: []string{"a", "b", "c"},
39− expect: true,
40− },
41− {
42− name: "single element not subset",
43− a: []string{"d"},
44− b: []string{"a", "b", "c"},
45− expect: false,
46− },
47− {
48− name: "multiple elements subset",
49− a: []string{"a", "c"},
50− b: []string{"a", "b", "c", "d"},
51− expect: true,
52− },
53− {
54− name: "multiple elements not subset",
55− a: []string{"a", "e"},
56− b: []string{"a", "b", "c", "d"},
57− expect: false,
58− },
59− {
60− name: "equal sets are subsets",
61− a: []string{"a", "b", "c"},
62− b: []string{"a", "b", "c"},
63− expect: true,
64− },
65− {
66− name: "larger set not subset of smaller",
67− a: []string{"a", "b", "c", "d"},
68− b: []string{"a", "b"},
69− expect: false,
70− },
71−
72− // Order independence
73− {
74− name: "subset with different order",
75− a: []string{"c", "a"},
76− b: []string{"b", "a", "d", "c"},
77− expect: true,
78− },
79−
80− // Duplicate handling
81− {
82− name: "duplicates in subset",
83− a: []string{"a", "a", "b"},
84− b: []string{"a", "b", "c"},
85− expect: true,
86− },
87− {
88− name: "duplicates in superset",
89− a: []string{"a", "b"},
90− b: []string{"a", "a", "b", "b", "c"},
91− expect: true,
92− },
93− {
94− name: "duplicates in both",
95− a: []string{"a", "a", "b"},
96− b: []string{"a", "a", "b", "b", "c"},
97− expect: true,
98− },
99−
100− // Real-world examples
101− {
102− name: "npm flags subset",
103− a: []string{"-g"},
104− b: []string{"-g", "--verbose", "--save-dev"},
105− expect: true,
106− },
107− {
108− name: "npm flags not subset",
109− a: []string{"--global"},
110− b: []string{"-g", "--verbose", "--save-dev"},
111− expect: false,
112− },
113− }
114−
115− for _, tt := range tests {
116− t.Run(tt.name, func(t *testing.T) {
117− result := IsSubset(tt.a, tt.b)
118− require.Equal(t, tt.expect, result,
119− "IsSubset(%v, %v) should be %v", tt.a, tt.b, tt.expect)
120− })
121− }
122−}
123−
124−func TestIsSubsetWithInts(t *testing.T) {
125− tests := []struct {
126− name string
127− a []int
128− b []int
129− expect bool
130− }{
131− {
132− name: "int subset",
133− a: []int{1, 3},
134− b: []int{1, 2, 3, 4},
135− expect: true,
136− },
137− {
138− name: "int not subset",
139− a: []int{1, 5},
140− b: []int{1, 2, 3, 4},
141− expect: false,
142− },
143− {
144− name: "empty int subset",
145− a: []int{},
146− b: []int{1, 2, 3},
147− expect: true,
148− },
149− }
150−
151− for _, tt := range tests {
152− t.Run(tt.name, func(t *testing.T) {
153− result := IsSubset(tt.a, tt.b)
154− require.Equal(t, tt.expect, result,
155− "IsSubset(%v, %v) should be %v", tt.a, tt.b, tt.expect)
156− })
157− }
158−}