///|
/// Metadata-only timeline entry; no mutable user data is exposed.
pub struct RevisionInfo {
index : Int
revision_id : Int
label : String
current : Bool
} derive(ToJson)
///|
pub extend RevisionInfo with ToJson::{to_json}
///|
pub fn[T] History::timeline(self : History[T]) -> Array[RevisionInfo] {
self.revisions.mapi(fn(i, r) {
{ index: i, revision_id: r.id, label: r.label, current: i == self.cursor, }
})
}
///|
pub fn[T] History::undo_depth(self : History[T]) -> Int {
self.cursor
}
///|
pub fn[T] History::redo_depth(self : History[T]) -> Int {
self.revisions.length() - self.cursor - 1
}
///|
pub fn[T] History::capacity(self : History[T]) -> Int {
self.limit
}
///|
pub fn[T] History::redo_label(self : History[T]) -> String? {
if self.can_redo() {
Some(self.revisions[self.cursor + 1].label)
} else {
None
}
}
///|
/// Navigate by current timeline index, not by stable revision identifier.
pub fn[T] History::jump_to(
self : History[T],
index : Int,
) -> Result[Bool, String] {
if !self.transactions.is_empty() {
return Err("cannot navigate during a transaction")
}
if index < 0 || index >= self.revisions.length() {
return Err("timeline index out of range")
}
self.merge_allowed = false
if index == self.cursor {
return Ok(false)
}
self.cursor = index
self.live = (self.copy)(self.revisions[index].value)
Ok(true)
}
///|
/// Reducing capacity keeps current state, closest past first, then future.
pub fn[T] History::set_capacity(
self : History[T],
limit : Int,
) -> Result[Unit, String] {
if !self.transactions.is_empty() {
return Err("cannot resize during a transaction")
}
if limit < 1 || limit > 10000 {
return Err("history limit must be between 1 and 10000")
}
self.merge_allowed = false
self.limit = limit
self.trim()
Ok(())
}
///|
/// Forget navigation history while retaining current state and revision id.
pub fn[T] History::clear(self : History[T]) -> Result[Unit, String] {
if !self.transactions.is_empty() {
return Err("cannot clear during a transaction")
}
self.merge_allowed = false
self.revisions = [self.revisions[self.cursor]]
self.cursor = 0
Ok(())
}