github.com/joshmeranda/wrash@v0.4.2/pkg/history.go (about)

     1  package wrash
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	prompt "github.com/joshmeranda/go-prompt"
     8  	"gopkg.in/yaml.v3"
     9  )
    10  
    11  type Entry struct {
    12  	Base string
    13  	Cmd  string
    14  
    15  	changes string
    16  }
    17  
    18  type history struct {
    19  	entries []*Entry
    20  
    21  	current int
    22  	base    string
    23  	w       io.Writer
    24  }
    25  
    26  func (h *history) Add(inputs ...string) {
    27  	h.entries = h.entries[:len(h.entries)-1]
    28  
    29  	var lastEntry *Entry
    30  	if len(h.entries) >= 1 {
    31  		lastEntry = h.entries[len(h.entries)-1]
    32  	}
    33  
    34  	for _, s := range inputs {
    35  		if s == "" || lastEntry != nil && s == lastEntry.Cmd {
    36  			continue
    37  		}
    38  
    39  		base := h.base
    40  		if isBuiltin(s) {
    41  			base = ""
    42  		}
    43  
    44  		h.entries = append(h.entries, &Entry{
    45  			Base: base,
    46  			Cmd:  s,
    47  		})
    48  	}
    49  	h.entries = append(h.entries, &Entry{
    50  		Base: h.base,
    51  	})
    52  }
    53  
    54  func (h *history) Clear() {
    55  	h.current = len(h.entries) - 1
    56  	for _, entry := range h.entries {
    57  		entry.changes = ""
    58  	}
    59  }
    60  
    61  func (h *history) nextOlder(text string) (*Entry, bool) {
    62  	if len(h.entries) == 1 || h.current == 0 {
    63  		return nil, false
    64  	}
    65  
    66  	entry := h.entries[h.current]
    67  	if entry.Cmd != text {
    68  		entry.changes = text
    69  	}
    70  
    71  	h.current--
    72  	entry = h.entries[h.current]
    73  
    74  	return entry, true
    75  }
    76  
    77  func (h *history) Older(buf *prompt.Buffer) (*prompt.Buffer, bool) {
    78  	for next, ok := h.nextOlder(buf.Text()); ok; next, ok = h.nextOlder(buf.Text()) {
    79  		if next.Base == h.base || isBuiltin(next.Cmd) {
    80  			var text string
    81  			if next.changes != "" {
    82  				text = next.changes
    83  			} else {
    84  				text = next.Cmd
    85  			}
    86  
    87  			new := prompt.NewBuffer()
    88  			new.InsertText(text, false, true)
    89  
    90  			return new, true
    91  		}
    92  	}
    93  
    94  	return buf, false
    95  }
    96  
    97  func (h *history) nextNewer(text string) (*Entry, bool) {
    98  	if h.current == len(h.entries)-1 {
    99  		return nil, false
   100  	}
   101  
   102  	entry := h.entries[h.current]
   103  	if entry.Cmd != text {
   104  		entry.changes = text
   105  	}
   106  
   107  	h.current++
   108  	entry = h.entries[h.current]
   109  
   110  	return entry, true
   111  }
   112  
   113  func (h *history) Newer(buf *prompt.Buffer) (*prompt.Buffer, bool) {
   114  	for next, ok := h.nextNewer(buf.Text()); ok; next, ok = h.nextNewer(buf.Text()) {
   115  		if next.Base == h.base || isBuiltin(next.Cmd) {
   116  			var text string
   117  			if next.changes != "" {
   118  				text = next.changes
   119  			} else {
   120  				text = next.Cmd
   121  			}
   122  
   123  			new := prompt.NewBuffer()
   124  			new.InsertText(text, false, true)
   125  
   126  			return new, true
   127  		}
   128  	}
   129  	fmt.Println()
   130  
   131  	return buf, false
   132  }
   133  
   134  func (h *history) Sync() error {
   135  	data, err := yaml.Marshal(h.entries[:len(h.entries)-1])
   136  	if err != nil {
   137  		return fmt.Errorf("could not marshal history entries: %w", err)
   138  	}
   139  
   140  	if _, err := h.w.Write(data); err != nil {
   141  		return fmt.Errorf("could not sync history: %w", err)
   142  	}
   143  
   144  	return nil
   145  }
   146  
   147  func NewHistory(base string, w io.Writer, entries []*Entry) prompt.History {
   148  	newEntries := make([]*Entry, len(entries), len(entries)+1)
   149  	copy(newEntries, entries)
   150  	newEntries = append(newEntries, &Entry{
   151  		Base: base,
   152  	})
   153  
   154  	return &history{
   155  		entries: newEntries,
   156  		current: len(newEntries) - 1,
   157  		base:    base,
   158  		w:       w,
   159  	}
   160  }