diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b599ea64..f3544e17 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -74,6 +74,15 @@ updates: commit-message: prefix: "chore" include: "scope" + - package-ecosystem: "gomod" + directory: "/exp/maps" + schedule: + interval: "daily" + labels: + - "dependencies" + commit-message: + prefix: "chore" + include: "scope" - package-ecosystem: "gomod" directory: "/exp/open" schedule: diff --git a/.github/workflows/maps.yml b/.github/workflows/maps.yml new file mode 100644 index 00000000..8285fc4b --- /dev/null +++ b/.github/workflows/maps.yml @@ -0,0 +1,30 @@ +# auto-generated by scripts/dependabot. DO NOT EDIT. +name: maps + +on: + push: + branches: + - main + pull_request: + paths: + - exp/maps/** + - .github/workflows/maps.yml + +jobs: + build: + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + defaults: + run: + working-directory: ./exp/maps + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: ./exp/maps/go.mod + cache: true + cache-dependency-path: ./exp/maps/go.sum + - run: go build -v ./... + - run: go test -race -v ./... diff --git a/README.md b/README.md index b55cc825..4b1e4ea4 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Currently the following packages are available: - [`higherorder`](./exp/higherorder): generic higher order functions • [Docs](https://pkg.go.dev/github.com/charmbracelet/x/exp/higherorder) - [`input`](./input): terminal event input handler and driver • [Docs](https://pkg.go.dev/github.com/charmbracelet/x/input) - [`json`](./json): JSON parsing using generics • [Docs](https://pkg.go.dev/github.com/charmbracelet/x/json) +- [`maps`](./exp/maps): generic maps utilities - [`open`](./exp/open): open a file/URL using `open`, `xdg-open`, etc • [Docs](https://pkg.go.dev/github.com/charmbracelet/x/exp/open) - [`ordered`](./exp/ordered): generic `min`, `max`, and `clamp` functions for ordered types • [Docs](https://pkg.go.dev/github.com/charmbracelet/x/exp/ordered) - [`slice`](./exp/slice): generic slice utilities • [Docs](https://pkg.go.dev/github.com/charmbracelet/x/exp/slice) diff --git a/exp/maps/go.mod b/exp/maps/go.mod new file mode 100644 index 00000000..b473264d --- /dev/null +++ b/exp/maps/go.mod @@ -0,0 +1,3 @@ +module github.com/charmbracelet/x/exp/maps + +go 1.21 diff --git a/exp/maps/go.sum b/exp/maps/go.sum new file mode 100644 index 00000000..e69de29b diff --git a/exp/maps/maps.go b/exp/maps/maps.go new file mode 100644 index 00000000..47b5ed79 --- /dev/null +++ b/exp/maps/maps.go @@ -0,0 +1,23 @@ +package maps + +import ( + "cmp" + "slices" +) + +// SortedKeys returns the keys of the map m. +// The keys will be sorted. +func SortedKeys[M ~map[K]V, K cmp.Ordered, V any](m M) []K { + r := Keys(m) + slices.Sort(r) + return r +} + +// Keys returns the keys of the map m. +func Keys[M ~map[K]V, K cmp.Ordered, V any](m M) []K { + r := make([]K, 0, len(m)) + for k := range m { + r = append(r, k) + } + return r +} diff --git a/exp/maps/maps_test.go b/exp/maps/maps_test.go new file mode 100644 index 00000000..d1007cef --- /dev/null +++ b/exp/maps/maps_test.go @@ -0,0 +1,34 @@ +package maps + +import ( + "slices" + "testing" +) + +func TestSortedKeys(t *testing.T) { + m := map[string]int{ + "foo": 1, + "bar": 10, + "aaaaa": 11, + } + + keys := SortedKeys(m) + if slices.Compare(keys, []string{"aaaaa", "bar", "foo"}) != 0 { + t.Fatalf("unexpected keys order: %v", keys) + } +} + +func TestKeys(t *testing.T) { + m := map[string]int{ + "foo": 1, + "bar": 10, + "aaaaa": 11, + } + + keys := Keys(m) + for _, s := range []string{"aaaaa", "bar", "foo"} { + if !slices.Contains(keys, s) { + t.Fatalf("unexpected keys: %v", keys) + } + } +} diff --git a/go.work b/go.work index 438ec629..89a0553a 100644 --- a/go.work +++ b/go.work @@ -8,6 +8,7 @@ use ( ./errors ./exp/golden ./exp/higherorder + ./exp/maps ./exp/open ./exp/ordered ./exp/slice diff --git a/go.work.sum b/go.work.sum index 62fe5ed5..37c12a42 100644 --- a/go.work.sum +++ b/go.work.sum @@ -14,10 +14,14 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -35,3 +39,4 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=