Skip to content

Commit

Permalink
Add ReplaceLatest() to mutate top of history. Add comments. Expose De…
Browse files Browse the repository at this point in the history
…faultHistoryEntries as const (#5)

* Add ReplaceLatest() to mutate top of history. Add comments. Expose DefaultHistoryEntries as const

* Correct godoc for ReplaceLatest
  • Loading branch information
ldemailly authored Aug 9, 2024
1 parent e4cae6f commit ed77b0f
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 7 deletions.
32 changes: 25 additions & 7 deletions terminal.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
termHeight: 24,
echo: true,
historyIndex: -1,
history: NewHistory(defaultNumEntries),
history: NewHistory(DefaultHistoryEntries),
autoHistory: true,
}
}
Expand Down Expand Up @@ -844,6 +844,15 @@ func (t *Terminal) AutoHistory(onOff bool) {
t.lock.Unlock()
}

// ReplaceLatest replaces the most recent history entry with the given string.
// Enables to add invalid commands to the history for editing purpose and
// replace them with the corrected version. Returns the replaced entry.
func (t *Terminal) ReplaceLatest(entry string) string {
t.lock.Lock()
defer t.lock.Unlock()
return t.history.Replace(entry)
}

// SetPrompt sets the prompt to be used when reading subsequent lines.
func (t *Terminal) SetPrompt(prompt string) {
t.lock.Lock()
Expand Down Expand Up @@ -962,22 +971,23 @@ type stRingBuffer struct {
size int
}

// Creates a new ring buffer of strings with the given capacity.
func NewHistory(capacity int) *stRingBuffer {
return &stRingBuffer{
entries: make([]string, capacity),
max: capacity,
}
}

const defaultNumEntries = 100
// DefaultHistoryEntries is the default number of entries in the history.
const DefaultHistoryEntries = 100

func (s *stRingBuffer) Add(a string) {
if s.entries == nil {
s.entries = make([]string, defaultNumEntries)
s.max = defaultNumEntries
}
if s.entries[s.head] == a {
return // already there at the top
// Already there at the top, so don't add.
// Also has the nice side effect of ignoring empty strings,
// no s.size check on purpose.
return
}
s.head = (s.head + 1) % s.max
s.entries[s.head] = a
Expand All @@ -986,6 +996,14 @@ func (s *stRingBuffer) Add(a string) {
}
}

// Replace theoretically could panic on an empty ring buffer but
// it's harmless on strings.
func (s *stRingBuffer) Replace(a string) string {
previous := s.entries[s.head]
s.entries[s.head] = a
return previous
}

// NthPreviousEntry returns the value passed to the nth previous call to Add.
// If n is zero then the immediately prior value is returned, if one, then the
// next most recent, and so on. If such an element doesn't exist then ok is
Expand Down
5 changes: 5 additions & 0 deletions terminal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,4 +462,9 @@ func TestHistoryNoDuplicates(t *testing.T) {
if !reflect.DeepEqual(h, []string{"c", "b", "a"}) {
t.Errorf("history unexpected: %v", h)
}
ss.ReplaceLatest("x")
h = ss.History()
if !reflect.DeepEqual(h, []string{"x", "b", "a"}) {
t.Errorf("history unexpected: %v", h)
}
}

0 comments on commit ed77b0f

Please sign in to comment.