Skip to content

Commit

Permalink
Refactor def-matcher
Browse files Browse the repository at this point in the history
  • Loading branch information
sei40kr committed Nov 16, 2019
1 parent 2a551bd commit e2e22f6
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 149 deletions.
1 change: 0 additions & 1 deletion .go-version

This file was deleted.

3 changes: 3 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
# go-tests = true
# unused-packages = true

[[constraint]]
name = "github.com/stretchr/testify"
version = "~1.4.0"

[prune]
go-tests = true
Expand Down
90 changes: 9 additions & 81 deletions def-matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,108 +4,36 @@ import (
"bufio"
"fmt"
"os"
"sort"
"strings"

"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 <[email protected]>

type Def struct {
alias string
abbr string
}

func ParseDef(line string) Def {
alias := make([]rune, 0, 1024)
abbr := make([]rune, 0, 1024)

afterEscape := false
inQuote := false
inRightExp := false
for _, aRune := range line {
if aRune == '\\' {
afterEscape = !afterEscape

if afterEscape {
continue
}
}

if aRune == '\'' && !afterEscape {
inQuote = !inQuote
} else if aRune == '=' && !inQuote {
inRightExp = true
} else if !inRightExp {
alias = append(alias, aRune)
} else {
abbr = append(abbr, aRune)
}

afterEscape = false
}

return Def{alias: string(alias), abbr: string(abbr)}
}

func MatchDef(defs []Def, command string) (*Def, bool) {
sort.Slice(defs, func(i, j int) bool {
return len(defs[j].abbr) <= len(defs[i].abbr)
})

var candidate Def
isFullMatch := false

for true {
var match Def
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 != (Def{}) {
command = fmt.Sprintf("%s%s", match.alias, command[len(match.abbr):])
candidate = match
} else {
break
}
}

if candidate != (Def{}) {
return &candidate, isFullMatch
} else {
return nil, false
}
}

func main() {
if len(os.Args) != 2 {
fmt.Fprintln(os.Stderr, "Invalid number of arguments")
os.Exit(1)
}

defs := make([]Def, 0, 512)
defs := make([]model.AliasDef, 0, 512)

scanner := bufio.NewScanner(bufio.NewReaderSize(os.Stdin, 1024))
for scanner.Scan() {
line := scanner.Text()
defs = append(defs, ParseDef(line))
defs = append(defs, parser.Parse(line))
}

command := os.Args[1]
match, isFullMatch := MatchDef(defs, command)
match, isFullMatch := matcher.Match(defs, command)
if match != nil {
if isFullMatch {
fmt.Printf("%s\n", match.alias)
fmt.Printf("%s\n", match.Name)
} else {
fmt.Printf("%s%s\n", match.alias, command[len(match.abbr):])
fmt.Printf("%s%s\n", match.Name, command[len(match.Abbr):])
}
}
}
67 changes: 0 additions & 67 deletions def-matcher_test.go

This file was deleted.

46 changes: 46 additions & 0 deletions matcher/matcher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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
}
}
61 changes: 61 additions & 0 deletions matcher/matcher_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package matcher

import (
"testing"

"github.com/sei40kr/zsh-fast-alias-tips/model"
"github.com/stretchr/testify/assert"
)

var mockAliasDefs = []model.AliasDef{
{
Name: "dk",
Abbr: "docker",
},
{
Name: "gb",
Abbr: "git branch",
},
{
Name: "gco",
Abbr: "git checkout",
},
{
Name: "gcb",
Abbr: "git checkout -b",
},
{
Name: "ls",
Abbr: "ls -G",
},
{
Name: "ll",
Abbr: "ls -lh",
},
}

func TestMatch_NoMatches(t *testing.T) {
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")
assert.Equal(t, candidate.Name, "dk")
}

func TestMatch_MultipleTokens(t *testing.T) {
candidate, _ := Match(mockAliasDefs, "git branch")
assert.Equal(t, candidate.Name, "gb")
}

func TestMatch_MultipleMatches(t *testing.T) {
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")
assert.Equal(t, candidate.Name, "ll", "should apply aliases recursively")
}
6 changes: 6 additions & 0 deletions model/aliasdef.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package model

type AliasDef struct {
Name string
Abbr string
}
35 changes: 35 additions & 0 deletions parser/parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package parser

import "github.com/sei40kr/zsh-fast-alias-tips/model"

func Parse(line string) model.AliasDef {
alias := make([]rune, 0, 1024)
abbr := make([]rune, 0, 1024)

afterEscape := false
inQuote := false
inRightExp := false
for _, aRune := range line {
if aRune == '\\' {
afterEscape = !afterEscape

if afterEscape {
continue
}
}

if aRune == '\'' && !afterEscape {
inQuote = !inQuote
} else if aRune == '=' && !inQuote {
inRightExp = true
} else if !inRightExp {
alias = append(alias, aRune)
} else {
abbr = append(abbr, aRune)
}

afterEscape = false
}

return model.AliasDef{Name: string(alias), Abbr: string(abbr)}
}
20 changes: 20 additions & 0 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package parser

import (
"testing"

"github.com/sei40kr/zsh-fast-alias-tips/model"
"github.com/stretchr/testify/assert"
)

func TestParse_NoQuotesInRightExp(t *testing.T) {
assert.Equal(t, Parse("dk=docker"), model.AliasDef{Name: "dk", Abbr: "docker"})
}

func TestParse_QuotesInRightExp(t *testing.T) {
assert.Equal(t, Parse("gb='git branch'"), model.AliasDef{Name: "gb", Abbr: "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"})
}

0 comments on commit e2e22f6

Please sign in to comment.