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  }