╭ changed ───────────╮ │src/ui/Repo/Undo.zig│ ╰────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │117 // a push consumes the events it carried in its own transaction │ │118 var buttons: std.ArrayList(DetailButton) = .empty; │ │119 if (try pushUser(arena, haxy_moment, record.payload)) |button| try buttons.append(aa, button); │ │120 - const count = try momentEventCount(opts, moment) orelse 0; │ │120 + const count = try momentEventCount(opts, core, moment, history_index) orelse 0; │ │121 if (count > 0) try buttons.append(aa, try eventsButton(arena, identity, history_index, count));│ │122 return .{ .action = "push", .description = "received a push", .buttons = buttons.items }; │ │123 } │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │124 if (!std.mem.eql(u8, record.action_kind, evt.undo_action)) return null; │ │125 │ │126 - const count = try momentEventCount(opts, moment) orelse return .{ .action = "events", .description = "updated the event database" }; │ │126 + const count = try momentEventCount(opts, core, moment, history_index) orelse return .{ .action = "events", .description = "updated the event database" };│ │127 // a transaction that consumed only merge commits indexed no events of its own │ │128 if (count == 0) return .{ .action = "events", .description = "merged the event history" }; │ │129 const buttons = try aa.dupe(DetailButton, &.{try eventsButton(arena, identity, history_index, count)}); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │196 }; │ │197 } │ │198 │ │199 -// how many events the transaction's moment wrote: zero when it named a moment │ │200 -// but indexed nothing, null when its state cannot be read at all │ │201 -fn momentEventCount(comptime opts: rp.RepoOpts(.xit), moment: rp.Repo(.xit, opts).DB.HashMap(.read_only)) !?u64 { │ │199 +// how many events the transaction wrote: zero when it consumed nothing, null │ │200 +// when its state cannot be read at all │ │201 +fn momentEventCount( │ │202 + comptime opts: rp.RepoOpts(.xit), │ │203 + core: *rp.Repo(.xit, opts).Core, │ │204 + moment: rp.Repo(.xit, opts).DB.HashMap(.read_only), │ │205 + history_index: u64, │ │206 +) !?u64 { │ │207 const DB = rp.Repo(.xit, opts).DB; │ │208 const haxy_moment = evt.currentMomentFromRepoMoment(opts.hash, moment) catch return null; │ │204 - const index_cursor = try haxy_moment.getCursor(hash.hashInt(opts.hash, evt.moment_index_key)) orelse return null; │ │205 - const ids = try evt.momentEventIds(DB, opts.hash, haxy_moment, try index_cursor.readUint()) orelse return 0; │ │209 + const index = try momentIndex(opts, haxy_moment) orelse return null; │ │210 + │ │211 + // a transaction that consumed nothing inherits the moment it was cloned │ │212 + // from, whose events belong to the transaction that wrote it │ │213 + inherited: { │ │214 + if (history_index == 0) break :inherited; │ │215 + const previous = evt.currentMomentFromRepoMoment(opts.hash, try core.momentAt(history_index - 1)) catch break :inherited;│ │216 + if (try momentIndex(opts, previous)) |value| if (value == index) return 0; │ │217 + } │ │218 + │ │219 + const ids = try evt.momentEventIds(DB, opts.hash, haxy_moment, index) orelse return 0; │ │220 return try ids.count(); │ │221 +} │ │222 + │ │223 +// the moment's own position in the haxy history │ │224 +fn momentIndex(comptime opts: rp.RepoOpts(.xit), haxy_moment: evt.EventDB(opts.hash).HashMap(.read_only)) !?u64 { │ │225 + const cursor = try haxy_moment.getCursor(hash.hashInt(opts.hash, evt.moment_index_key)) orelse return null; │ │226 + return try cursor.readUint(); │ │227 } │ │228 │ │229 pub fn formatTimestamp(aa: std.mem.Allocator, timestamp: i64) ![]const u8 { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯