src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/edit/store_api.go (about)

     1  package edit
     2  
     3  import (
     4  	"errors"
     5  
     6  	"src.elv.sh/pkg/cli"
     7  	"src.elv.sh/pkg/cli/histutil"
     8  	"src.elv.sh/pkg/cli/tk"
     9  	"src.elv.sh/pkg/eval"
    10  	"src.elv.sh/pkg/eval/vals"
    11  	"src.elv.sh/pkg/parse/parseutil"
    12  	"src.elv.sh/pkg/store/storedefs"
    13  )
    14  
    15  var errStoreOffline = errors.New("store offline")
    16  
    17  type cmdhistOpt struct{ CmdOnly, Dedup, NewestFirst bool }
    18  
    19  func (o *cmdhistOpt) SetDefaultOptions() {}
    20  
    21  func commandHistory(opts cmdhistOpt, fuser histutil.Store, out eval.ValueOutput) error {
    22  	if fuser == nil {
    23  		return errStoreOffline
    24  	}
    25  	cmds, err := fuser.AllCmds()
    26  	if err != nil {
    27  		return err
    28  	}
    29  	if opts.Dedup {
    30  		cmds = dedupCmds(cmds, opts.NewestFirst)
    31  	} else if opts.NewestFirst {
    32  		reverseCmds(cmds)
    33  	}
    34  	if opts.CmdOnly {
    35  		for _, cmd := range cmds {
    36  			err := out.Put(cmd.Text)
    37  			if err != nil {
    38  				return err
    39  			}
    40  		}
    41  	} else {
    42  		for _, cmd := range cmds {
    43  			err := out.Put(vals.MakeMap("id", cmd.Seq, "cmd", cmd.Text))
    44  			if err != nil {
    45  				return err
    46  			}
    47  		}
    48  	}
    49  	return nil
    50  }
    51  
    52  func dedupCmds(allCmds []storedefs.Cmd, newestFirst bool) []storedefs.Cmd {
    53  	// Capacity allocation below is based on some personal empirical observation.
    54  	uniqCmds := make([]storedefs.Cmd, 0, len(allCmds)/4)
    55  	seenCmds := make(map[string]bool, len(allCmds)/4)
    56  	for i := len(allCmds) - 1; i >= 0; i-- {
    57  		if !seenCmds[allCmds[i].Text] {
    58  			seenCmds[allCmds[i].Text] = true
    59  			uniqCmds = append(uniqCmds, allCmds[i])
    60  		}
    61  	}
    62  	if !newestFirst {
    63  		reverseCmds(uniqCmds)
    64  	}
    65  	return uniqCmds
    66  }
    67  
    68  // Reverse the order of commands, in place, in the slice. This reorders the
    69  // command history between oldest or newest command being first in the slice.
    70  func reverseCmds(cmds []storedefs.Cmd) {
    71  	for i, j := 0, len(cmds)-1; i < j; i, j = i+1, j-1 {
    72  		cmds[i], cmds[j] = cmds[j], cmds[i]
    73  	}
    74  }
    75  
    76  func insertLastWord(app cli.App, histStore histutil.Store) error {
    77  	codeArea, ok := focusedCodeArea(app)
    78  	if !ok {
    79  		return nil
    80  	}
    81  	c := histStore.Cursor("")
    82  	c.Prev()
    83  	cmd, err := c.Get()
    84  	if err != nil {
    85  		return err
    86  	}
    87  	words := parseutil.Wordify(cmd.Text)
    88  	if len(words) > 0 {
    89  		codeArea.MutateState(func(s *tk.CodeAreaState) {
    90  			s.Buffer.InsertAtDot(words[len(words)-1])
    91  		})
    92  	}
    93  	return nil
    94  }
    95  
    96  func initStoreAPI(app cli.App, nb eval.NsBuilder, fuser histutil.Store) {
    97  	nb.AddGoFns(map[string]any{
    98  		"command-history": func(fm *eval.Frame, opts cmdhistOpt) error {
    99  			return commandHistory(opts, fuser, fm.ValueOutput())
   100  		},
   101  		"insert-last-word": func() { insertLastWord(app, fuser) },
   102  	})
   103  }