╭ changed ───────────────╮ │src/ui/widget/thread.zig│ ╰────────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭─────────────────────────────────────────────────────────╮ │20 const Attachment = @import("../Repo/Attachment.zig");│ │21 │ │22 const Widget = widget.Widget; │ │23 -const TagFlow = widget.TagFlow; │ │23 +const WordFlow = widget.WordFlow; │ │24 const Center = widget.Center; │ │25 const SubmitButton = widget.SubmitButton; │ │26 const Spacer = widget.Spacer; │ ╰─────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │86 .ours = .{ .text = ours.event.title, .author = our_author }, │ │87 .theirs = .{ .text = theirs.event.title, .author = their_author }, │ │88 }; │ │89 - } else if (std.mem.eql(u8, field, "tags")) { │ │90 - conflict.tags = .{ │ │91 - .ours = .{ .text = ours.event.tags, .author = our_author }, │ │92 - .theirs = .{ .text = theirs.event.tags, .author = their_author }, │ │89 + } else if (std.mem.eql(u8, field, "labels")) { │ │90 + conflict.labels = .{ │ │91 + .ours = .{ .text = ours.event.labels, .author = our_author }, │ │92 + .theirs = .{ .text = theirs.event.labels, .author = their_author },│ │93 }; │ │94 } else if (std.mem.eql(u8, field, "description")) { │ │95 conflict.description = .{ │ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────╮ │165 return try DB.SortedSet(.read_only).init(cursor); │ │166 } │ │167 │ │168 -pub fn tagStatusSet( │ │168 +pub fn labelStatusSet( │ │169 comptime Data: type, │ │170 comptime DB: type, │ │171 - tag_statuses: DB.SortedMap(.read_only), │ │172 - tag: []const u8, │ │171 + label_statuses: DB.SortedMap(.read_only), │ │172 + label: []const u8, │ │173 status: Data.Status, │ │174 ) !?DB.SortedSet(.read_only) { │ │175 - var key_buffer: Data.Event.TagStatusKey = undefined; │ │176 - const key = Data.Event.tagStatusKey(&key_buffer, tag, status) catch return null; │ │177 - const cursor = (try tag_statuses.getCursor(key)) orelse return null; │ │175 + var key_buffer: Data.Event.LabelStatusKey = undefined; │ │176 + const key = Data.Event.labelStatusKey(&key_buffer, label, status) catch return null;│ │177 + const cursor = (try label_statuses.getCursor(key)) orelse return null; │ │178 return try DB.SortedSet(.read_only).init(cursor); │ │179 } │ │180 │ ╰─────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────╮ │181 -pub fn loadTags( │ │181 +pub fn loadLabels( │ │182 comptime Data: type, │ │183 comptime hash_kind: hash.HashKind,│ │184 arena: *std.heap.ArenaAllocator, │ ╰───────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │186 ) ![]const []const u8 { │ │187 const aa = arena.allocator(); │ │188 const DB = evt.EventDB(hash_kind); │ │189 - const cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, Data.Event.tag_status_to_id_set_key)) orelse return &.{}; │ │190 - const tag_statuses = try DB.SortedMap(.read_only).init(cursor); │ │191 - var tags: std.ArrayList([]const u8) = .empty; │ │192 - var iter = try tag_statuses.iterator(); │ │189 + const cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, Data.Event.label_status_to_id_set_key)) orelse return &.{};│ │190 + const label_statuses = try DB.SortedMap(.read_only).init(cursor); │ │191 + var labels: std.ArrayList([]const u8) = .empty; │ │192 + var iter = try label_statuses.iterator(); │ │193 while (try iter.next()) |pair_cursor| { │ │194 - if (tags.items.len == Data.max_tags) break; │ │194 + if (labels.items.len == Data.max_labels) break; │ │195 var entry_cursor = pair_cursor; │ │196 const pair = try entry_cursor.readKeyValuePair(); │ │197 const key = try pair.key_cursor.readBytesAlloc(aa, null); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────╮ │198 const space = std.mem.indexOfScalar(u8, key, ' ') orelse continue;│ │199 - const tag = key[0..space]; │ │200 - if (tags.getLastOrNull()) |last| { │ │201 - if (std.mem.eql(u8, last, tag)) continue; │ │199 + const label = key[0..space]; │ │200 + if (labels.getLastOrNull()) |last| { │ │201 + if (std.mem.eql(u8, last, label)) continue; │ │202 } │ │203 - try tags.append(aa, tag); │ │203 + try labels.append(aa, label); │ │204 } │ │205 - return tags.items; │ │205 + return labels.items; │ │206 } │ │207 │ │208 // the key a list set (and the search index) stores a thread under │ ╰───────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │661 return null; │ │662 } │ │663 │ │664 - fn listRoute(identity: []const u8, status: Status, tag: []const u8, selected: []const u8) ?ui.RoutablePage { │ │665 - return Data.listRoute(identity, status, tag, selected); │ │664 + fn listRoute(identity: []const u8, status: Status, label: []const u8, selected: []const u8) ?ui.RoutablePage {│ │665 + return Data.listRoute(identity, status, label, selected); │ │666 } │ │667 │ │668 fn draftsRoute(identity: []const u8) ?ui.RoutablePage { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │681 return if (supports_conflicts) Data.resolveRoute(identity, selected, picks) else null; │ │682 } │ │683 │ │684 - // a list link keeps the filters the page carries: the tag, and the │ │684 + // a list link keeps the filters the page carries: the label, and the │ │685 // search query when one is set │ │686 - fn listLink(page_arena: *std.heap.ArenaAllocator, identity: []const u8, status: Status, tag: []const u8, id: []const u8, search: []const u8) ![]const u8 { │ │687 - var route = listRoute(identity, status, tag, id) orelse return error.RouteTooLong; │ │686 + fn listLink(page_arena: *std.heap.ArenaAllocator, identity: []const u8, status: Status, label: []const u8, id: []const u8, search: []const u8) ![]const u8 {│ │687 + var route = listRoute(identity, status, label, id) orelse return error.RouteTooLong; │ │688 if (search.len != 0) route = route.withSearch(search) orelse return error.RouteTooLong; │ │689 return std.fmt.allocPrint(page_arena.allocator(), "a:{s}", .{try route.toUrl(page_arena)}); │ │690 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │691 │ │692 - fn tagLink(page_arena: *std.heap.ArenaAllocator, identity: []const u8, status: Status, tag: []const u8, search: []const u8) ![]const u8 { │ │693 - const encoded = try ui.urlEncodeRef(page_arena.allocator(), tag); │ │692 + fn labelLink(page_arena: *std.heap.ArenaAllocator, identity: []const u8, status: Status, label: []const u8, search: []const u8) ![]const u8 {│ │693 + const encoded = try ui.urlEncodeRef(page_arena.allocator(), label); │ │694 return listLink(page_arena, identity, status, encoded, "", search); │ │695 } │ │696 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │829 try inner_box.children.put(allocator, author.getFocus().id, .{ .widget = .{ .text_box = author }, .rect = null, .min_size = null }); │ │830 self.author_id = author.getFocus().id; │ │831 │ │832 - var items: std.ArrayList(TagFlow.Item) = .empty; │ │832 + var items: std.ArrayList(WordFlow.Item) = .empty; │ │833 defer items.deinit(allocator); │ │834 - var tag_iter = Event.tagIterator(entry.record.event.tags); │ │835 - while (tag_iter.next()) |tag| { │ │836 - if (tag.len == 0) continue; │ │837 - try items.append(allocator, .{ .text = tag, .link = try tagLink(self.session.page_arena, self.data.identity, entryStatus(entry), tag, self.data.search orelse "") }); │ │834 + var label_iter = Event.labelIterator(entry.record.event.labels); │ │835 + while (label_iter.next()) |label| { │ │836 + if (label.len == 0) continue; │ │837 + try items.append(allocator, .{ .text = label, .link = try labelLink(self.session.page_arena, self.data.identity, entryStatus(entry), label, self.data.search orelse "") });│ │838 } │ │839 if (items.items.len > 0) { │ │840 - var tags = try TagFlow.init(allocator); │ │841 - errdefer tags.deinit(allocator); │ │842 - try tags.setItems(allocator, items.items); │ │843 - try inner_box.children.put(allocator, tags.getFocus().id, .{ .widget = .{ .tag_flow = tags }, .rect = null, .min_size = null }); │ │840 + var labels = try WordFlow.init(allocator); │ │841 + errdefer labels.deinit(allocator); │ │842 + try labels.setItems(allocator, items.items); │ │843 + try inner_box.children.put(allocator, labels.getFocus().id, .{ .widget = .{ .word_flow = labels }, .rect = null, .min_size = null }); │ │844 } │ │845 } │ │846 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯