github.com/koron/hk@v0.0.0-20150303213137-b8aeaa3ab34c/suggest.go (about)

     1  package main
     2  
     3  import (
     4  	"sort"
     5  	"strconv"
     6  )
     7  
     8  type Suggestion struct {
     9  	s string
    10  	d int
    11  }
    12  
    13  type Suggestions []Suggestion
    14  
    15  func (a Suggestions) Len() int           { return len(a) }
    16  func (a Suggestions) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
    17  func (a Suggestions) Less(i, j int) bool { return a[i].d < a[j].d }
    18  
    19  // suggest returns command names that are similar to s.
    20  func suggest(s string) (a []string) {
    21  	var g Suggestions
    22  	for _, c := range commands {
    23  		if d := editDistance(s, c.Name()); d < 4 {
    24  			if c.Runnable() {
    25  				g = append(g, Suggestion{c.Name(), d})
    26  			} else {
    27  				g = append(g, Suggestion{strconv.Quote("help " + c.Name()), d})
    28  			}
    29  		}
    30  	}
    31  	sort.Sort(g)
    32  	for i, s := range g {
    33  		a = append(a, s.s)
    34  		if i >= 4 {
    35  			break
    36  		}
    37  	}
    38  	return a
    39  }
    40  
    41  func editDistance(a, b string) int {
    42  	var d [][]int
    43  	d = append(d, make([]int, len(b)+1))
    44  	for i := range b {
    45  		d[0][i+1] = i + 1
    46  	}
    47  	for i := range a {
    48  		v := make([]int, len(b)+1)
    49  		d = append(d, v)
    50  		v[0] = i + 1
    51  	}
    52  	for j, cb := range []byte(b) {
    53  		for i, ca := range []byte(a) {
    54  			if ca == cb {
    55  				d[i+1][j+1] = d[i][j]
    56  			} else {
    57  				cost := d[i][j+1]             // delete
    58  				if v := d[i+1][j]; v < cost { // insert
    59  					cost = v
    60  				}
    61  				if v := d[i][j]; v < cost { // substitute
    62  					cost = v
    63  				}
    64  				if i > 0 && j > 0 {
    65  					if ca == b[j-1] && cb == a[i-1] {
    66  						if v := d[i-1][j-1]; v < cost { // transpose
    67  							cost = v
    68  						}
    69  					}
    70  				}
    71  				d[i+1][j+1] = cost + 1
    72  			}
    73  		}
    74  	}
    75  	return d[len(a)][len(b)]
    76  }