From ead7d493d7b2bfd2c6fe356ce255c490326acd94 Mon Sep 17 00:00:00 2001 From: "sashakoshka@tebibyte.media" Date: Thu, 5 Sep 2024 20:11:40 -0400 Subject: [PATCH] Add history mechanism --- internal/history/history.go | 77 +++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 internal/history/history.go diff --git a/internal/history/history.go b/internal/history/history.go new file mode 100644 index 0000000..720a611 --- /dev/null +++ b/internal/history/history.go @@ -0,0 +1,77 @@ +package history + +import "time" + +// History stores a stack of items, always keeping the bottom-most one. It must +// be created using the NewHistory constructor, otherwise it will be invalid. +type History[T any] struct { + max int + stack []T + topIndex int + topTime time.Time +} + +// NewHistory creates a new History. The initial item will be on the bottom, and +// it will remain there until the History overflows and chooses the item after +// it to be the initial item. +func NewHistory[T any] (initial T, max int) *History[T] { + return &History[T] { + max: max, + stack: []T { initial }, + } +} + +// Top returns the most recent item. +func (this *History[T]) Top () T { + return this.stack[this.topIndex] +} + +// Swap replaces the most recent item with another. +func (this *History[T]) Swap (item T) { + this.topTime = time.Now() + this.stack[this.topIndex] = item +} + +// Push pushes a new item onto the stack. +func (this *History[T]) Push (item T) { + this.topTime = time.Now() + this.topIndex ++ + this.stack = append(this.stack[:this.topIndex], item) +} + +// PushWeak replaces the most recent item if it was added recently (sooner than +// specified by minAge), and will otherwise push the item normally. If the +// history was popped or cleared beforehand, the item will always be pushed +// normally. This is intended to be used for things such as keystrokes. +func (this *History[T]) PushWeak (item T, minAge time.Duration) { + if time.Since(this.topTime) > minAge { + this.Push(item) + } else { + this.Swap(item) + } +} + +// Redo undoes an Undo operation and returns the resulting top of the stack. +func (this *History[T]) Redo () T { + if this.topIndex < len(this.stack) - 1 { + this.topIndex ++ + } + return this.Top() +} + +// Undo removes the most recent item and returns what was under it. If there is +// only one item (the initial item), it will kept and returned. +func (this *History[T]) Undo () T { + this.topTime = time.Time { } + if this.topIndex > 0 { + this.topIndex -- + } + return this.Top() +} + +// Clear removes all items except for the initial one. +func (this *History[T]) Clear () { + this.topTime = time.Time { } + this.stack = this.stack[:1] + this.topIndex = 0 +}