diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 0000000..f1b219b --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..af71dc5 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,26 @@ +--- +on: + - pull_request + +permissions: + contents: read + pull-requests: read +jobs: + ci: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - uses: actions/setup-go@v4 + with: + go-version-file: go.mod + cache: false + + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + only-new-issues: true + + - name: Test + run: make test diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..45dc65b --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,33 @@ +--- +on: + push: + tags: + - "v*" + +permissions: + contents: write + packages: write + +jobs: + release: + runs-on: ubuntu-latest + env: + REGISTRY: ghcr.io + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version-file: go.mod + + - name: Release Binaries + uses: goreleaser/goreleaser-action@v4 + with: + version: latest + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index ab071f6..b365835 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ *.dll *.so *.dylib -/build/def-matcher +/build/ # Test binary, built with `go test -c` *.test diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..5acb16d --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,14 @@ +--- +run: + timeout: 5m +linters: + disable-all: true + enable: + - errcheck + - gofmt + - gosimple + - govet + - ineffassign + - staticcheck + - typecheck + - unused diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..dea4ad9 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,22 @@ +# yaml-language-server: $schema=https://goreleaser.com/static/schema.json +--- +before: + hooks: + - go mod tidy + +builds: + - main: cmd/zsh-alias-matcher/main.go + binary: zsh-alias-matcher + goos: + - windows + - darwin + - linux + goarch: + - amd64 + - arm64 + +checksum: + name_template: checksums.txt + +changelog: + sort: asc diff --git a/.goreleaser.yml b/.goreleaser.yml deleted file mode 100644 index f3ec307..0000000 --- a/.goreleaser.yml +++ /dev/null @@ -1,14 +0,0 @@ -builds: - - main: def-matcher.go - binary: def-matcher - goos: - - windows - - darwin - - linux - goarch: - - amd64 - -release: - github: - owner: sei40kr - name: fast-alias-tips-bin diff --git a/LICENSE b/LICENSE index 778412c..cc6f4d3 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ MIT License Copyright (c) 2019 Seong Yong-ju +Copyright (c) 2023 Roman Komkov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index 29e77ed..47183cd 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,11 @@ -.PHONY: all -all: - go build -o build/def-matcher def-matcher.go +.PHONY: build +build: + GO111MODULE=on go build -o build/zsh-alias-matcher ./cmd/zsh-alias-matcher + .PHONY: test test: - go test -v def-matcher.go def-matcher_test.go + go test -v -race -buildvcs ./... + .PHONY: clean clean: - rm -f build/def-matcher + rm -f build/* diff --git a/README.md b/README.md index 38a07eb..04d272e 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Helps you remembering the aliases you defined once. +sei40kr/fast-alias-tips-bin + Written in zsh and Go. Ported from [djui/alias-tips](https://github.com/djui/alias-tips). ## Example @@ -19,7 +21,7 @@ nothing to commit, working tree clean ## Install -### Install with [zinit](https://github.com/zdharma/zinit) (recommended) +### Install with [zinit](https://github.com/zdharma/zinit) ```sh zinit ice from'gh-r' as'program' @@ -27,16 +29,9 @@ zinit light sei40kr/fast-alias-tips-bin zinit light sei40kr/zsh-fast-alias-tips ``` -### Install with [zplug](https://github.com/zplug/zplug) - -```sh -zplug sei40kr/fast-alias-tips-bin, from:gh-r, as:command, rename-to:def-matcher -zplug sei40kr/zsh-fast-alias-tips -``` - -## Customization +## Configuration -| Variable | Default value | Description | -| :-- | :-- | :-- | -| `FAST_ALIAS_TIPS_PREFIX` | `"💡 $(tput bold)"` | The prefix of the Tips | -| `FAST_ALIAS_TIPS_SUFFIX` | `"$(tput sgr0)"` | The suffix of the Tips | +| Variable | Default value | Description | +| :-- | :-- | :-- | +| `ZSH_FAST_ALIAS_TIPS_PREFIX` | `"💡 $(tput bold)"` | The prefix of the Tips | +| `ZSH_FAST_ALIAS_TIPS_SUFFIX` | `"$(tput sgr0)"` | The suffix of the Tips | diff --git a/build/.gitkeep b/build/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/cmd/zsh-alias-matcher/main.go b/cmd/zsh-alias-matcher/main.go new file mode 100644 index 0000000..f8d3798 --- /dev/null +++ b/cmd/zsh-alias-matcher/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/decayofmind/zsh-fast-alias-tips/pkg/matcher" + "github.com/decayofmind/zsh-fast-alias-tips/pkg/model" + "github.com/decayofmind/zsh-fast-alias-tips/pkg/parser" +) + +func main() { + if len(os.Args) != 2 { + fmt.Fprintln(os.Stderr, "Invalid number of arguments") + os.Exit(1) + } + + aliases := make([]model.AliasDef, 0, 1024) + excludes := strings.Split(os.Getenv("ZSH_FAST_ALIAS_TIPS_EXCLUDES"), " ") + + scanner := bufio.NewScanner(bufio.NewReaderSize(os.Stdin, 1024)) + for scanner.Scan() { + alias := parser.Parse(scanner.Text()) + + skip := false + + for _, exclude := range excludes { + if exclude == alias.Name { + skip = true + } + } + + if !skip { + aliases = append(aliases, alias) + } + } + + command := os.Args[1] + match := matcher.Match(aliases, command) + if match != nil { + fmt.Printf("%s%s\n", match.Name, command[len(match.Expanded):]) + } +} diff --git a/def-matcher.go b/def-matcher.go deleted file mode 100644 index f2368e7..0000000 --- a/def-matcher.go +++ /dev/null @@ -1,39 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "os" - - "github.com/sei40kr/zsh-fast-alias-tips/matcher" - "github.com/sei40kr/zsh-fast-alias-tips/model" - "github.com/sei40kr/zsh-fast-alias-tips/parser" -) - -// def-matcher.go -// author: Seong Yong-ju - -func main() { - if len(os.Args) != 2 { - fmt.Fprintln(os.Stderr, "Invalid number of arguments") - os.Exit(1) - } - - defs := make([]model.AliasDef, 0, 512) - - scanner := bufio.NewScanner(bufio.NewReaderSize(os.Stdin, 1024)) - for scanner.Scan() { - line := scanner.Text() - defs = append(defs, parser.Parse(line)) - } - - command := os.Args[1] - match, isFullMatch := matcher.Match(defs, command) - if match != nil { - if isFullMatch { - fmt.Printf("%s\n", match.Name) - } else { - fmt.Printf("%s%s\n", match.Name, command[len(match.Abbr):]) - } - } -} diff --git a/go.mod b/go.mod index 0204bb3..a0d9158 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,14 @@ -module github.com/sei40kr/zsh-fast-alias-tips +module github.com/decayofmind/zsh-fast-alias-tips -require github.com/stretchr/testify v1.4.0 +go 1.20 + +require github.com/stretchr/testify v1.8.4 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/objx v0.5.0 // indirect + gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 // indirect + gopkg.in/yaml.v2 v2.2.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) \ No newline at end of file diff --git a/go.sum b/go.sum index adc7cd7..0c681c0 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,18 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= \ No newline at end of file diff --git a/matcher/matcher.go b/matcher/matcher.go deleted file mode 100644 index 260897a..0000000 --- a/matcher/matcher.go +++ /dev/null @@ -1,46 +0,0 @@ -package matcher - -import ( - "fmt" - "sort" - "strings" - - "github.com/sei40kr/zsh-fast-alias-tips/model" -) - -func Match(defs []model.AliasDef, command string) (*model.AliasDef, bool) { - sort.Slice(defs, func(i, j int) bool { - return len(defs[j].Abbr) <= len(defs[i].Abbr) - }) - - var candidate model.AliasDef - isFullMatch := false - - for true { - var match model.AliasDef - for _, def := range defs { - - if command == def.Abbr { - match = def - isFullMatch = true - break - } else if strings.HasPrefix(command, def.Abbr) { - match = def - break - } - } - - if match != (model.AliasDef{}) { - command = fmt.Sprintf("%s%s", match.Name, command[len(match.Abbr):]) - candidate = match - } else { - break - } - } - - if candidate != (model.AliasDef{}) { - return &candidate, isFullMatch - } else { - return nil, false - } -} diff --git a/pkg/matcher/matcher.go b/pkg/matcher/matcher.go new file mode 100644 index 0000000..bf94240 --- /dev/null +++ b/pkg/matcher/matcher.go @@ -0,0 +1,42 @@ +package matcher + +import ( + "fmt" + "sort" + "strings" + + "github.com/decayofmind/zsh-fast-alias-tips/pkg/model" +) + +func Match(defs []model.AliasDef, command string) *model.AliasDef { + sort.Slice(defs, func(i, j int) bool { + return len(defs[j].Expanded) <= len(defs[i].Expanded) + }) + + var candidate model.AliasDef + + for { + var match model.AliasDef + for _, def := range defs { + + if command == def.Expanded || strings.HasPrefix(command, def.Expanded) { + match = def + break + } + } + + if match != (model.AliasDef{}) { + command = fmt.Sprintf("%s%s", match.Name, command[len(match.Expanded):]) + candidate = match + continue + } + + break + } + + if candidate != (model.AliasDef{}) { + return &candidate + } + + return nil +} diff --git a/matcher/matcher_test.go b/pkg/matcher/matcher_test.go similarity index 56% rename from matcher/matcher_test.go rename to pkg/matcher/matcher_test.go index ac9c837..c3518c0 100644 --- a/matcher/matcher_test.go +++ b/pkg/matcher/matcher_test.go @@ -3,59 +3,63 @@ package matcher import ( "testing" - "github.com/sei40kr/zsh-fast-alias-tips/model" + "github.com/decayofmind/zsh-fast-alias-tips/pkg/model" "github.com/stretchr/testify/assert" ) var mockAliasDefs = []model.AliasDef{ { - Name: "dk", - Abbr: "docker", + Name: "dk", + Expanded: "docker", }, { - Name: "gb", - Abbr: "git branch", + Name: "gb", + Expanded: "git branch", }, { - Name: "gco", - Abbr: "git checkout", + Name: "gco", + Expanded: "git checkout", }, { - Name: "gcb", - Abbr: "git checkout -b", + Name: "gcb", + Expanded: "git checkout -b", }, { - Name: "ls", - Abbr: "ls -G", + Name: "ls", + Expanded: "ls -G", }, { - Name: "ll", - Abbr: "ls -lh", + Name: "ll", + Expanded: "ls -lh", + }, + { + Name: "l", + Expanded: "ls", }, } func TestMatch_NoMatches(t *testing.T) { - candidate, _ := Match(mockAliasDefs, "cd ..") + candidate := Match(mockAliasDefs, "cd ..") assert.Nil(t, candidate, "should return nil when no matches found") } func TestMatch_SingleToken(t *testing.T) { - candidate, _ := Match(mockAliasDefs, "docker") + candidate := Match(mockAliasDefs, "docker") assert.Equal(t, candidate.Name, "dk") } func TestMatch_MultipleTokens(t *testing.T) { - candidate, _ := Match(mockAliasDefs, "git branch") + candidate := Match(mockAliasDefs, "git branch") assert.Equal(t, candidate.Name, "gb") } func TestMatch_MultipleMatches(t *testing.T) { - candidate, _ := Match(mockAliasDefs, "git checkout -b") + candidate := Match(mockAliasDefs, "git checkout -b") assert.Equal(t, candidate.Name, "gcb", "should return the alias definition that has the longest abbreviation when multiple matches found") } func TestMatch_RecursiveDefs(t *testing.T) { - candidate, _ := Match(mockAliasDefs, "ls -G -lh") + candidate := Match(mockAliasDefs, "ls -G -lh") assert.Equal(t, candidate.Name, "ll", "should apply aliases recursively") } diff --git a/model/aliasdef.go b/pkg/model/aliasdef.go similarity index 54% rename from model/aliasdef.go rename to pkg/model/aliasdef.go index 7db1736..a569bad 100644 --- a/model/aliasdef.go +++ b/pkg/model/aliasdef.go @@ -1,6 +1,6 @@ package model type AliasDef struct { - Name string - Abbr string + Name string + Expanded string } diff --git a/parser/parser.go b/pkg/parser/parser.go similarity index 70% rename from parser/parser.go rename to pkg/parser/parser.go index 015f544..b005062 100644 --- a/parser/parser.go +++ b/pkg/parser/parser.go @@ -1,10 +1,10 @@ package parser -import "github.com/sei40kr/zsh-fast-alias-tips/model" +import "github.com/decayofmind/zsh-fast-alias-tips/pkg/model" func Parse(line string) model.AliasDef { alias := make([]rune, 0, 1024) - abbr := make([]rune, 0, 1024) + expanded := make([]rune, 0, 1024) afterEscape := false inQuote := false @@ -25,11 +25,11 @@ func Parse(line string) model.AliasDef { } else if !inRightExp { alias = append(alias, aRune) } else { - abbr = append(abbr, aRune) + expanded = append(expanded, aRune) } afterEscape = false } - return model.AliasDef{Name: string(alias), Abbr: string(abbr)} + return model.AliasDef{Name: string(alias), Expanded: string(expanded)} } diff --git a/parser/parser_test.go b/pkg/parser/parser_test.go similarity index 73% rename from parser/parser_test.go rename to pkg/parser/parser_test.go index 6570739..0c35bee 100644 --- a/parser/parser_test.go +++ b/pkg/parser/parser_test.go @@ -3,18 +3,18 @@ package parser import ( "testing" - "github.com/sei40kr/zsh-fast-alias-tips/model" + "github.com/decayofmind/zsh-fast-alias-tips/pkg/model" "github.com/stretchr/testify/assert" ) func TestParse_NoQuotesInRightExp(t *testing.T) { - assert.Equal(t, Parse("dk=docker"), model.AliasDef{Name: "dk", Abbr: "docker"}) + assert.Equal(t, Parse("dk=docker"), model.AliasDef{Name: "dk", Expanded: "docker"}) } func TestParse_QuotesInRightExp(t *testing.T) { - assert.Equal(t, Parse("gb='git branch'"), model.AliasDef{Name: "gb", Abbr: "git branch"}) + assert.Equal(t, Parse("gb='git branch'"), model.AliasDef{Name: "gb", Expanded: "git branch"}) } func TestParse_QuotesInBothExps(t *testing.T) { - assert.Equal(t, Parse("'g cb'='git checkout -b'"), model.AliasDef{Name: "g cb", Abbr: "git checkout -b"}) + assert.Equal(t, Parse("'g cb'='git checkout -b'"), model.AliasDef{Name: "g cb", Expanded: "git checkout -b"}) } diff --git a/fast-alias-tips.plugin.zsh b/zsh-fast-alias-tips.plugin.zsh similarity index 74% rename from fast-alias-tips.plugin.zsh rename to zsh-fast-alias-tips.plugin.zsh index bb75efd..a8021c1 100644 --- a/fast-alias-tips.plugin.zsh +++ b/zsh-fast-alias-tips.plugin.zsh @@ -1,8 +1,8 @@ # fast-alias-tips.plugin.zsh # author: Seong Yong-ju -: ${FAST_ALIAS_TIPS_PREFIX:="💡 $(tput bold)"} -: ${FAST_ALIAS_TIPS_SUFFIX:="$(tput sgr0)"} +: ${ZSH_FAST_ALIAS_TIPS_PREFIX:="💡 $(tput bold)"} +: ${ZSH_FAST_ALIAS_TIPS_SUFFIX:="$(tput sgr0)"} __fast_alias_tips_preexec() { local cmd="$1" @@ -20,7 +20,7 @@ __fast_alias_tips_preexec() { return fi - echo "${FAST_ALIAS_TIPS_PREFIX}${suggested}${FAST_ALIAS_TIPS_SUFFIX}" + echo "${ZSH_FAST_ALIAS_TIPS_PREFIX}${suggested}${ZSH_FAST_ALIAS_TIPS_SUFFIX}" } autoload -Uz add-zsh-hook