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 (golang#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.