github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/store/dir.go (about) 1 package store 2 3 import ( 4 "sort" 5 "strconv" 6 7 bolt "go.etcd.io/bbolt" 8 . "github.com/markusbkk/elvish/pkg/store/storedefs" 9 ) 10 11 // Parameters for directory history scores. 12 const ( 13 DirScoreDecay = 0.986 // roughly 0.5^(1/50) 14 DirScoreIncrement = 10 15 DirScorePrecision = 6 16 ) 17 18 func init() { 19 initDB["initialize directory history table"] = func(tx *bolt.Tx) error { 20 _, err := tx.CreateBucketIfNotExists([]byte(bucketDir)) 21 return err 22 } 23 } 24 25 func marshalScore(score float64) []byte { 26 return []byte(strconv.FormatFloat(score, 'E', DirScorePrecision, 64)) 27 } 28 29 func unmarshalScore(data []byte) float64 { 30 f, _ := strconv.ParseFloat(string(data), 64) 31 return f 32 } 33 34 // AddDir adds a directory to the directory history. 35 func (s *dbStore) AddDir(d string, incFactor float64) error { 36 return s.db.Update(func(tx *bolt.Tx) error { 37 b := tx.Bucket([]byte(bucketDir)) 38 39 c := b.Cursor() 40 for k, v := c.First(); k != nil; k, v = c.Next() { 41 score := unmarshalScore(v) * DirScoreDecay 42 b.Put(k, marshalScore(score)) 43 } 44 45 k := []byte(d) 46 score := float64(0) 47 if v := b.Get(k); v != nil { 48 score = unmarshalScore(v) 49 } 50 score += DirScoreIncrement * incFactor 51 return b.Put(k, marshalScore(score)) 52 }) 53 } 54 55 // AddDir adds a directory and its score to history. 56 func (s *dbStore) AddDirRaw(d string, score float64) error { 57 return s.db.Update(func(tx *bolt.Tx) error { 58 b := tx.Bucket([]byte(bucketDir)) 59 return b.Put([]byte(d), marshalScore(score)) 60 }) 61 } 62 63 // DelDir deletes a directory record from history. 64 func (s *dbStore) DelDir(d string) error { 65 return s.db.Update(func(tx *bolt.Tx) error { 66 b := tx.Bucket([]byte(bucketDir)) 67 return b.Delete([]byte(d)) 68 }) 69 } 70 71 // Dirs lists all directories in the directory history whose names are not 72 // in the blacklist. The results are ordered by scores in descending order. 73 func (s *dbStore) Dirs(blacklist map[string]struct{}) ([]Dir, error) { 74 var dirs []Dir 75 76 err := s.db.View(func(tx *bolt.Tx) error { 77 b := tx.Bucket([]byte(bucketDir)) 78 c := b.Cursor() 79 for k, v := c.First(); k != nil; k, v = c.Next() { 80 d := string(k) 81 if _, ok := blacklist[d]; ok { 82 continue 83 } 84 dirs = append(dirs, Dir{ 85 Path: d, 86 Score: unmarshalScore(v), 87 }) 88 } 89 sort.Sort(sort.Reverse(dirList(dirs))) 90 return nil 91 }) 92 return dirs, err 93 } 94 95 type dirList []Dir 96 97 func (dl dirList) Len() int { 98 return len(dl) 99 } 100 101 func (dl dirList) Less(i, j int) bool { 102 return dl[i].Score < dl[j].Score 103 } 104 105 func (dl dirList) Swap(i, j int) { 106 dl[i], dl[j] = dl[j], dl[i] 107 }