From d57d1d2395c9f80ecdb7be4cd58858b299f95c42 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 2 Dec 2024 09:39:21 -0500 Subject: [PATCH 01/32] terminal: failing tracked pin test on fullReset --- src/terminal/PageList.zig | 6 +++++- src/terminal/Terminal.zig | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/terminal/PageList.zig b/src/terminal/PageList.zig index 70f972ebe..3d67278ba 100644 --- a/src/terminal/PageList.zig +++ b/src/terminal/PageList.zig @@ -2356,7 +2356,11 @@ pub fn countTrackedPins(self: *const PageList) usize { /// Checks if a pin is valid for this pagelist. This is a very slow and /// expensive operation since we traverse the entire linked list in the /// worst case. Only for runtime safety/debug. -fn pinIsValid(self: *const PageList, p: Pin) bool { +pub fn pinIsValid(self: *const PageList, p: Pin) bool { + // This is very slow so we want to ensure we only ever + // call this during slow runtime safety builds. + comptime assert(build_config.slow_runtime_safety); + var it = self.pages.first; while (it) |node| : (it = node.next) { if (node != p.node) continue; diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index a2cf510b1..0a2914f10 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -10575,6 +10575,16 @@ test "Terminal: fullReset default modes" { try testing.expect(t.modes.get(.grapheme_cluster)); } +test "Terminal: fullReset tracked pins" { + var t = try init(testing.allocator, .{ .cols = 80, .rows = 80 }); + defer t.deinit(testing.allocator); + + // Create a tracked pin + const p = try t.screen.pages.trackPin(t.screen.cursor.page_pin.*); + t.fullReset(); + try testing.expect(t.screen.pages.pinIsValid(p.*)); +} + // https://github.com/mitchellh/ghostty/issues/272 // This is also tested in depth in screen resize tests but I want to keep // this test around to ensure we don't regress at multiple layers. From d7fcaefdf3622a3aefadbf788c062065576ff928 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 2 Dec 2024 17:25:17 -0500 Subject: [PATCH 02/32] terminal: PageList.reset --- src/terminal/PageList.zig | 134 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/src/terminal/PageList.zig b/src/terminal/PageList.zig index 3d67278ba..aec0af278 100644 --- a/src/terminal/PageList.zig +++ b/src/terminal/PageList.zig @@ -330,6 +330,77 @@ pub fn deinit(self: *PageList) void { } } +/// Reset the PageList back to an empty state. This is similar to +/// deinit and reinit but it importantly preserves the pointer +/// stability of tracked pins (they're moved to the top-left since +/// all contents are cleared). +/// +/// This can't fail because we always retain at least enough allocated +/// memory to fit the active area. +pub fn reset(self: *PageList) void { + // We need enough pages/nodes to keep our active area. This should + // never fail since we by definition have allocated a page already + // that fits our size but I'm not confident to make that assertion. + const cap = std_capacity.adjust( + .{ .cols = self.cols }, + ) catch @panic("reset: std_capacity.adjust failed"); + assert(cap.rows > 0); // adjust should never return 0 rows + + // The number of pages we need is the number of rows in the active + // area divided by the row capacity of a page. + const page_count = std.math.divCeil( + usize, + self.rows, + cap.rows, + ) catch unreachable; + + // Before resetting our pools we need to free any pages that + // are non-standard size since those were allocated outside + // the pool. + { + const page_alloc = self.pool.pages.arena.child_allocator; + var it = self.pages.first; + while (it) |node| : (it = node.next) { + if (node.data.memory.len > std_size) { + page_alloc.free(node.data.memory); + } + } + } + + // Reset our pools to free as much memory as possible while retaining + // the capacity for at least the minimum number of pages we need. + // The return value is whether memory was reclaimed or not, but in + // either case the pool is left in a valid state. + _ = self.pool.pages.reset(.{ + .retain_with_limit = page_count * PagePool.item_size, + }); + _ = self.pool.nodes.reset(.{ + .retain_with_limit = page_count * NodePool.item_size, + }); + + // Initialize our pages. This should not be able to fail since + // we retained the capacity for the minimum number of pages we need. + self.pages, self.page_size = initPages( + &self.pool, + self.cols, + self.rows, + ) catch @panic("initPages failed"); + + // Update all our tracked pins to point to our first page top-left + { + var it = self.tracked_pins.iterator(); + while (it.next()) |entry| { + const p: *Pin = entry.key_ptr.*; + p.node = self.pages.first.?; + p.x = 0; + p.y = 0; + } + } + + // Move our viewport back to the active area since everything is gone. + self.viewport = .active; +} + pub const Clone = struct { /// The top and bottom (inclusive) points of the region to clone. /// The x coordinate is ignored; the full row is always cloned. @@ -8195,3 +8266,66 @@ test "PageList resize reflow wrap moves kitty placeholder" { } try testing.expect(it.next() == null); } + +test "PageList reset" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 80, 24, null); + defer s.deinit(); + s.reset(); + try testing.expect(s.viewport == .active); + try testing.expect(s.pages.first != null); + try testing.expectEqual(@as(usize, s.rows), s.totalRows()); + + // Active area should be the top + try testing.expectEqual(Pin{ + .node = s.pages.first.?, + .y = 0, + .x = 0, + }, s.getTopLeft(.active)); +} + +test "PageList reset across two pages" { + const testing = std.testing; + const alloc = testing.allocator; + + // Find a cap that makes it so that rows don't fit on one page. + const rows = 100; + const cap = cap: { + var cap = try std_capacity.adjust(.{ .cols = 50 }); + while (cap.rows >= rows) cap = try std_capacity.adjust(.{ + .cols = cap.cols + 50, + }); + + break :cap cap; + }; + + // Init + var s = try init(alloc, cap.cols, rows, null); + defer s.deinit(); + s.reset(); + try testing.expect(s.viewport == .active); + try testing.expect(s.pages.first != null); + try testing.expectEqual(@as(usize, s.rows), s.totalRows()); +} + +test "PageList clears history" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 80, 24, null); + defer s.deinit(); + try s.growRows(30); + s.reset(); + try testing.expect(s.viewport == .active); + try testing.expect(s.pages.first != null); + try testing.expectEqual(@as(usize, s.rows), s.totalRows()); + + // Active area should be the top + try testing.expectEqual(Pin{ + .node = s.pages.first.?, + .y = 0, + .x = 0, + }, s.getTopLeft(.active)); +} From 212bd3d5fb5ced7866f459fdc80f757811f14b3e Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 2 Dec 2024 17:43:56 -0500 Subject: [PATCH 03/32] terminal: fullReset uses the new screen reset methods --- src/terminal/Screen.zig | 48 +++++++++++++++++++++- src/terminal/Terminal.zig | 84 ++++++++++----------------------------- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index 4f3fe270e..d8787487f 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -83,8 +83,8 @@ pub const Dirty = packed struct { /// The cursor position and style. pub const Cursor = struct { // The x/y position within the viewport. - x: size.CellCountInt, - y: size.CellCountInt, + x: size.CellCountInt = 0, + y: size.CellCountInt = 0, /// The visual style of the cursor. This defaults to block because /// it has to default to something, but users of this struct are @@ -249,6 +249,50 @@ pub fn assertIntegrity(self: *const Screen) void { } } +/// Reset the screen according to the logic of a DEC RIS sequence. +/// +/// - Clears the screen and attempts to reclaim memory. +/// - Moves the cursor to the top-left. +/// - Clears any cursor state: style, hyperlink, etc. +/// - Resets the charset +/// - Clears the selection +/// - Deletes all Kitty graphics +/// - Resets Kitty Keyboard settings +/// - Disables protection mode +/// +pub fn reset(self: *Screen) void { + // Reset our pages + self.pages.reset(); + + // The above reset preserves tracked pins so we can still use + // our cursor pin, which should be at the top-left already. + const cursor_pin: *PageList.Pin = self.cursor.page_pin; + assert(cursor_pin.node == self.pages.pages.first.?); + assert(cursor_pin.x == 0); + assert(cursor_pin.y == 0); + const cursor_rac = cursor_pin.rowAndCell(); + self.cursor.deinit(self.alloc); + self.cursor = .{ + .page_pin = cursor_pin, + .page_row = cursor_rac.row, + .page_cell = cursor_rac.cell, + }; + + // Clear kitty graphics + self.kitty_images.delete( + self.alloc, + undefined, // All image deletion doesn't need the terminal + .{ .all = true }, + ); + + // Reset our basic state + self.saved_cursor = null; + self.charset = .{}; + self.kitty_keyboard = .{}; + self.protected_mode = .off; + self.clearSelection(); +} + /// Clone the screen. /// /// This will copy: diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index 0a2914f10..a11028304 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -2627,82 +2627,38 @@ pub fn plainStringUnwrapped(self: *Terminal, alloc: Allocator) ![]const u8 { /// Full reset. /// -/// This will attempt to free the existing screen memory and allocate -/// new screens but if that fails this will reuse the existing memory -/// from the prior screens. In the latter case, memory may be wasted -/// (since its unused) but it isn't leaked. +/// This will attempt to free the existing screen memory but if that fails +/// this will reuse the existing memory. In the latter case, memory may +/// be wasted (since its unused) but it isn't leaked. pub fn fullReset(self: *Terminal) void { - // Attempt to initialize new screens. - var new_primary = Screen.init( - self.screen.alloc, - self.cols, - self.rows, - self.screen.pages.explicit_max_size, - ) catch |err| { - log.warn("failed to allocate new primary screen, reusing old memory err={}", .{err}); - self.fallbackReset(); - return; - }; - const new_secondary = Screen.init( - self.secondary_screen.alloc, - self.cols, - self.rows, - 0, - ) catch |err| { - log.warn("failed to allocate new secondary screen, reusing old memory err={}", .{err}); - new_primary.deinit(); - self.fallbackReset(); - return; - }; + // Reset our screens + self.screen.reset(); + self.secondary_screen.reset(); - // If we got here, both new screens were successfully allocated - // and we can deinitialize the old screens. - self.screen.deinit(); - self.secondary_screen.deinit(); + // Ensure we're back on primary screen + if (self.active_screen != .primary) { + const old = self.screen; + self.screen = self.secondary_screen; + self.secondary_screen = old; + self.active_screen = .primary; + } - // Replace with the newly allocated screens. - self.screen = new_primary; - self.secondary_screen = new_secondary; - - self.resetCommonState(); -} - -fn fallbackReset(self: *Terminal) void { - // Clear existing screens without reallocation - self.primaryScreen(.{ .clear_on_exit = true, .cursor_save = false }); - self.screen.clearSelection(); - self.eraseDisplay(.scrollback, false); - self.eraseDisplay(.complete, false); - self.screen.cursorAbsolute(0, 0); - self.resetCommonState(); -} - -fn resetCommonState(self: *Terminal) void { - // We set the saved cursor to null and then restore. This will force - // our cursor to go back to the default which will also move the cursor - // to the top-left. - self.screen.saved_cursor = null; - self.restoreCursor() catch |err| { - log.warn("restore cursor on primary screen failed err={}", .{err}); - }; - - self.screen.endHyperlink(); - self.screen.charset = .{}; + // Rest our basic state self.modes.reset(); self.flags = .{}; self.tabstops.reset(TABSTOP_INTERVAL); - self.screen.kitty_keyboard = .{}; - self.secondary_screen.kitty_keyboard = .{}; - self.screen.protected_mode = .off; + self.previous_char = null; + self.pwd.clearRetainingCapacity(); + self.status_display = .main; self.scrolling_region = .{ .top = 0, .bottom = self.rows - 1, .left = 0, .right = self.cols - 1, }; - self.previous_char = null; - self.pwd.clearRetainingCapacity(); - self.status_display = .main; + + // Always mark dirty so we redraw everything + self.flags.dirty.clear = true; } /// Returns true if the point is dirty, used for testing. From e712314f31b55d84b689732cc6def8015e74c514 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 3 Dec 2024 08:57:42 -0500 Subject: [PATCH 04/32] terminal: PageList.reset has to zero arena memory to avoid reuse Fixes #2877 As the comment in the diff states, we rely on `mmap` to zero our memory. When we reset we are reusing previously allocated memory so we won't hit an `mmap`. We need to zero the memory ourselves. This is pretty slow if there is a lot of memory but in every case except allocation failures, we expect there to be only a few pages allocated. --- src/terminal/PageList.zig | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/terminal/PageList.zig b/src/terminal/PageList.zig index aec0af278..01e7ed71d 100644 --- a/src/terminal/PageList.zig +++ b/src/terminal/PageList.zig @@ -378,6 +378,25 @@ pub fn reset(self: *PageList) void { .retain_with_limit = page_count * NodePool.item_size, }); + // Our page pool relies on mmap to zero our page memory. Since we're + // retaining a certain amount of memory, it won't use mmap and won't + // be zeroed. This block zeroes out all the memory in the pool arena. + { + // Note: we only have to do this for the page pool because the + // nodes are always fully overwritten on each allocation. + const page_arena = &self.pool.pages.arena; + var it = page_arena.state.buffer_list.first; + while (it) |node| : (it = node.next) { + // The fully allocated buffer + const alloc_buf = @as([*]u8, @ptrCast(node))[0..node.data]; + + // The buffer minus our header + const BufNode = @TypeOf(page_arena.state.buffer_list).Node; + const data_buf = alloc_buf[@sizeOf(BufNode)..]; + @memset(data_buf, 0); + } + } + // Initialize our pages. This should not be able to fail since // we retained the capacity for the minimum number of pages we need. self.pages, self.page_size = initPages( From bcefbfd7b42dcb6389c738e0ebad95b0fc3c16cc Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 9 Nov 2024 09:37:03 -0800 Subject: [PATCH 05/32] terminal: move UTF8 encoding to Page and wrap around it --- src/terminal/PageList.zig | 38 ++++++++++++++ src/terminal/Screen.zig | 86 ++----------------------------- src/terminal/page.zig | 106 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+), 83 deletions(-) diff --git a/src/terminal/PageList.zig b/src/terminal/PageList.zig index 01e7ed71d..175e3f64f 100644 --- a/src/terminal/PageList.zig +++ b/src/terminal/PageList.zig @@ -2544,6 +2544,44 @@ pub fn getCell(self: *const PageList, pt: point.Point) ?Cell { }; } +pub const EncodeUtf8Options = struct { + /// The start and end points of the dump, both inclusive. The x will + /// be ignored and the full row will always be dumped. + tl: Pin, + br: ?Pin = null, + + /// If true, this will unwrap soft-wrapped lines. If false, this will + /// dump the screen as it is visually seen in a rendered window. + unwrap: bool = true, +}; + +/// Encode the pagelist to utf8 to the given writer. +/// +/// The writer should be buffered; this function does not attempt to +/// efficiently write and often writes one byte at a time. +/// +/// Note: this is tested using Screen.dumpString. This is a function that +/// predates this and is a thin wrapper around it so the tests all live there. +pub fn encodeUtf8( + self: *const PageList, + writer: anytype, + opts: EncodeUtf8Options, +) anyerror!void { + // We don't currently use self at all. There is an argument that this + // function should live on Pin instead but there is some future we might + // need state on here so... letting it go. + _ = self; + + var page_opts: Page.EncodeUtf8Options = .{ .unwrap = opts.unwrap }; + var iter = opts.tl.pageIterator(.right_down, opts.br); + while (iter.next()) |chunk| { + const page: *const Page = &chunk.node.data; + page_opts.start_y = chunk.start; + page_opts.end_y = chunk.end; + page_opts.preceding = try page.encodeUtf8(writer, page_opts); + } +} + /// Log a debug diagram of the page list to the provided writer. /// /// EXAMPLE: diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index d8787487f..bf63e7e05 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -2731,95 +2731,15 @@ pub fn promptPath( return .{ .x = to_x - from_x, .y = to_y - from_y }; } -pub const DumpString = struct { - /// The start and end points of the dump, both inclusive. The x will - /// be ignored and the full row will always be dumped. - tl: Pin, - br: ?Pin = null, - - /// If true, this will unwrap soft-wrapped lines. If false, this will - /// dump the screen as it is visually seen in a rendered window. - unwrap: bool = true, -}; - /// Dump the screen to a string. The writer given should be buffered; /// this function does not attempt to efficiently write and generally writes /// one byte at a time. pub fn dumpString( self: *const Screen, writer: anytype, - opts: DumpString, -) !void { - var blank_rows: usize = 0; - var blank_cells: usize = 0; - - var iter = opts.tl.rowIterator(.right_down, opts.br); - while (iter.next()) |row_offset| { - const rac = row_offset.rowAndCell(); - const row = rac.row; - const cells = cells: { - const cells: [*]pagepkg.Cell = @ptrCast(rac.cell); - break :cells cells[0..self.pages.cols]; - }; - - if (!pagepkg.Cell.hasTextAny(cells)) { - blank_rows += 1; - continue; - } - if (blank_rows > 0) { - for (0..blank_rows) |_| try writer.writeByte('\n'); - blank_rows = 0; - } - - if (!row.wrap or !opts.unwrap) { - // If we're not wrapped, we always add a newline. - // If we are wrapped, we only add a new line if we're unwrapping - // soft-wrapped lines. - blank_rows += 1; - } - - if (!row.wrap_continuation or !opts.unwrap) { - // We should also reset blank cell counts at the start of each row - // unless we're unwrapping and this row is a wrap continuation. - blank_cells = 0; - } - - for (cells) |*cell| { - // Skip spacers - switch (cell.wide) { - .narrow, .wide => {}, - .spacer_head, .spacer_tail => continue, - } - - // If we have a zero value, then we accumulate a counter. We - // only want to turn zero values into spaces if we have a non-zero - // char sometime later. - if (!cell.hasText()) { - blank_cells += 1; - continue; - } - if (blank_cells > 0) { - try writer.writeByteNTimes(' ', blank_cells); - blank_cells = 0; - } - - switch (cell.content_tag) { - .codepoint => { - try writer.print("{u}", .{cell.content.codepoint}); - }, - - .codepoint_grapheme => { - try writer.print("{u}", .{cell.content.codepoint}); - const cps = row_offset.node.data.lookupGrapheme(cell).?; - for (cps) |cp| { - try writer.print("{u}", .{cp}); - } - }, - - else => unreachable, - } - } - } + opts: PageList.EncodeUtf8Options, +) anyerror!void { + try self.pages.encodeUtf8(writer, opts); } /// You should use dumpString, this is a restricted version mostly for diff --git a/src/terminal/page.zig b/src/terminal/page.zig index 8c470d726..d41f37e8d 100644 --- a/src/terminal/page.zig +++ b/src/terminal/page.zig @@ -1481,6 +1481,112 @@ pub const Page = struct { return self.grapheme_map.map(self.memory).capacity(); } + /// Options for encoding the page as UTF-8. + pub const EncodeUtf8Options = struct { + /// The range of rows to encode. If end_y is null, then it will + /// encode to the end of the page. + start_y: size.CellCountInt = 0, + end_y: ?size.CellCountInt = null, + + /// If true, this will unwrap soft-wrapped lines. If false, this will + /// dump the screen as it is visually seen in a rendered window. + unwrap: bool = true, + + /// Preceding state from encoding the prior page. Used to preserve + /// blanks properly across multiple pages. + preceding: TrailingUtf8State = .{}, + + /// Trailing state for UTF-8 encoding. + pub const TrailingUtf8State = struct { + rows: usize = 0, + cells: usize = 0, + }; + }; + + /// Encode the page contents as UTF-8. + /// + /// If preceding is non-null, then it will be used to initialize our + /// blank rows/cells count so that we can accumulate blanks across + /// multiple pages. + /// + /// Note: The tests for this function are done via Screen.dumpString + /// tests since that function is a thin wrapper around this one and + /// it makes it easier to test input contents. + pub fn encodeUtf8( + self: *const Page, + writer: anytype, + opts: EncodeUtf8Options, + ) anyerror!EncodeUtf8Options.TrailingUtf8State { + var blank_rows: usize = opts.preceding.rows; + var blank_cells: usize = opts.preceding.cells; + + const start_y: size.CellCountInt = opts.start_y; + const end_y: size.CellCountInt = opts.end_y orelse self.size.rows; + for (start_y..end_y) |y| { + const row: *Row = self.getRow(y); + const cells: []const Cell = self.getCells(row); + + // If this row is blank, accumulate to avoid a bunch of extra + // work later. If it isn't blank, make sure we dump all our + // blanks. + if (!Cell.hasTextAny(cells)) { + blank_rows += 1; + continue; + } + for (0..blank_rows) |_| try writer.writeByte('\n'); + blank_rows = 0; + + // If we're not wrapped, we always add a newline so after + // the row is printed we can add a newline. + if (!row.wrap or !opts.unwrap) blank_rows += 1; + + // If the row doesn't continue a wrap then we need to reset + // our blank cell count. + if (!row.wrap_continuation or !opts.unwrap) blank_cells = 0; + + // Go through each cell and print it + for (cells) |*cell| { + // Skip spacers + switch (cell.wide) { + .narrow, .wide => {}, + .spacer_head, .spacer_tail => continue, + } + + // If we have a zero value, then we accumulate a counter. We + // only want to turn zero values into spaces if we have a non-zero + // char sometime later. + if (!cell.hasText()) { + blank_cells += 1; + continue; + } + if (blank_cells > 0) { + try writer.writeByteNTimes(' ', blank_cells); + blank_cells = 0; + } + + switch (cell.content_tag) { + .codepoint => { + try writer.print("{u}", .{cell.content.codepoint}); + }, + + .codepoint_grapheme => { + try writer.print("{u}", .{cell.content.codepoint}); + for (self.lookupGrapheme(cell).?) |cp| { + try writer.print("{u}", .{cp}); + } + }, + + // Unreachable since we do hasText() above + .bg_color_palette, + .bg_color_rgb, + => unreachable, + } + } + } + + return .{ .rows = blank_rows, .cells = blank_cells }; + } + /// Returns the bitset for the dirty bits on this page. /// /// The returned value is a DynamicBitSetUnmanaged but it is NOT From 204e4f86634451422e4ba3a6e3d0f1f855af480d Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 9 Nov 2024 09:37:03 -0800 Subject: [PATCH 06/32] terminal: support cell_map for encodeUtf8 --- src/terminal/PageList.zig | 8 +++- src/terminal/Screen.zig | 78 +++++++++++++++++++++++++++++++++++++++ src/terminal/page.zig | 75 +++++++++++++++++++++++++++++++++++-- 3 files changed, 156 insertions(+), 5 deletions(-) diff --git a/src/terminal/PageList.zig b/src/terminal/PageList.zig index 175e3f64f..f8afc801a 100644 --- a/src/terminal/PageList.zig +++ b/src/terminal/PageList.zig @@ -2553,6 +2553,9 @@ pub const EncodeUtf8Options = struct { /// If true, this will unwrap soft-wrapped lines. If false, this will /// dump the screen as it is visually seen in a rendered window. unwrap: bool = true, + + /// See Page.EncodeUtf8Options. + cell_map: ?*Page.CellMap = null, }; /// Encode the pagelist to utf8 to the given writer. @@ -2572,7 +2575,10 @@ pub fn encodeUtf8( // need state on here so... letting it go. _ = self; - var page_opts: Page.EncodeUtf8Options = .{ .unwrap = opts.unwrap }; + var page_opts: Page.EncodeUtf8Options = .{ + .unwrap = opts.unwrap, + .cell_map = opts.cell_map, + }; var iter = opts.tl.pageIterator(.right_down, opts.br); while (iter.next()) |chunk| { const page: *const Page = &chunk.node.data; diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index bf63e7e05..ac9483742 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -8468,3 +8468,81 @@ test "Screen: adjustCapacity cursor style ref count" { ); } } + +test "Screen UTF8 cell map with newlines" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try Screen.init(alloc, 80, 24, 0); + defer s.deinit(); + try s.testWriteString("A\n\nB\n\nC"); + + var cell_map = Page.CellMap.init(alloc); + defer cell_map.deinit(); + var builder = std.ArrayList(u8).init(alloc); + defer builder.deinit(); + try s.dumpString(builder.writer(), .{ + .tl = s.pages.getTopLeft(.screen), + .br = s.pages.getBottomRight(.screen), + .cell_map = &cell_map, + }); + + try testing.expectEqual(7, builder.items.len); + try testing.expectEqualStrings("A\n\nB\n\nC", builder.items); + try testing.expectEqual(builder.items.len, cell_map.items.len); + try testing.expectEqual(Page.CellMapEntry{ + .x = 0, + .y = 0, + }, cell_map.items[0]); + try testing.expectEqual(Page.CellMapEntry{ + .x = 1, + .y = 0, + }, cell_map.items[1]); + try testing.expectEqual(Page.CellMapEntry{ + .x = 0, + .y = 1, + }, cell_map.items[2]); + try testing.expectEqual(Page.CellMapEntry{ + .x = 0, + .y = 2, + }, cell_map.items[3]); +} + +test "Screen UTF8 cell map with blank prefix" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try Screen.init(alloc, 80, 24, 0); + defer s.deinit(); + s.cursorAbsolute(2, 1); + try s.testWriteString("B"); + + var cell_map = Page.CellMap.init(alloc); + defer cell_map.deinit(); + var builder = std.ArrayList(u8).init(alloc); + defer builder.deinit(); + try s.dumpString(builder.writer(), .{ + .tl = s.pages.getTopLeft(.screen), + .br = s.pages.getBottomRight(.screen), + .cell_map = &cell_map, + }); + + try testing.expectEqualStrings("\n B", builder.items); + try testing.expectEqual(builder.items.len, cell_map.items.len); + try testing.expectEqual(Page.CellMapEntry{ + .x = 0, + .y = 0, + }, cell_map.items[0]); + try testing.expectEqual(Page.CellMapEntry{ + .x = 0, + .y = 1, + }, cell_map.items[1]); + try testing.expectEqual(Page.CellMapEntry{ + .x = 1, + .y = 1, + }, cell_map.items[2]); + try testing.expectEqual(Page.CellMapEntry{ + .x = 2, + .y = 1, + }, cell_map.items[3]); +} diff --git a/src/terminal/page.zig b/src/terminal/page.zig index d41f37e8d..83164e163 100644 --- a/src/terminal/page.zig +++ b/src/terminal/page.zig @@ -1496,6 +1496,13 @@ pub const Page = struct { /// blanks properly across multiple pages. preceding: TrailingUtf8State = .{}, + /// If non-null, this will be cleared and filled with the x/y + /// coordinates of each byte in the UTF-8 encoded output. + /// The index in the array is the byte offset in the output + /// where 0 is the cursor of the writer when the function is + /// called. + cell_map: ?*CellMap = null, + /// Trailing state for UTF-8 encoding. pub const TrailingUtf8State = struct { rows: usize = 0, @@ -1503,13 +1510,22 @@ pub const Page = struct { }; }; + /// See cell_map + pub const CellMap = std.ArrayList(CellMapEntry); + + /// The x/y coordinate of a single cell in the cell map. + pub const CellMapEntry = struct { + y: size.CellCountInt, + x: size.CellCountInt, + }; + /// Encode the page contents as UTF-8. /// /// If preceding is non-null, then it will be used to initialize our /// blank rows/cells count so that we can accumulate blanks across /// multiple pages. /// - /// Note: The tests for this function are done via Screen.dumpString + /// Note: Many tests for this function are done via Screen.dumpString /// tests since that function is a thin wrapper around this one and /// it makes it easier to test input contents. pub fn encodeUtf8( @@ -1522,7 +1538,18 @@ pub const Page = struct { const start_y: size.CellCountInt = opts.start_y; const end_y: size.CellCountInt = opts.end_y orelse self.size.rows; - for (start_y..end_y) |y| { + + // We can probably avoid this by doing the logic below in a different + // way. The reason this exists is so that when we end a non-blank + // line with a newline, we can correctly map the cell map over to + // the correct x value. + // + // For example "A\nB". The cell map for "\n" should be (1, 0). + // This is tested in Screen.zig so feel free to refactor this. + var last_x: size.CellCountInt = 0; + + for (start_y..end_y) |y_usize| { + const y: size.CellCountInt = @intCast(y_usize); const row: *Row = self.getRow(y); const cells: []const Cell = self.getCells(row); @@ -1533,7 +1560,19 @@ pub const Page = struct { blank_rows += 1; continue; } - for (0..blank_rows) |_| try writer.writeByte('\n'); + for (1..blank_rows + 1) |i| { + try writer.writeByte('\n'); + + // This is tested in Screen.zig, i.e. one test is + // "cell map with newlines" + if (opts.cell_map) |cell_map| { + try cell_map.append(.{ + .x = last_x, + .y = @intCast(y - blank_rows + i - 1), + }); + last_x = 0; + } + } blank_rows = 0; // If we're not wrapped, we always add a newline so after @@ -1545,7 +1584,9 @@ pub const Page = struct { if (!row.wrap_continuation or !opts.unwrap) blank_cells = 0; // Go through each cell and print it - for (cells) |*cell| { + for (cells, 0..) |*cell, x_usize| { + const x: size.CellCountInt = @intCast(x_usize); + // Skip spacers switch (cell.wide) { .narrow, .wide => {}, @@ -1561,18 +1602,44 @@ pub const Page = struct { } if (blank_cells > 0) { try writer.writeByteNTimes(' ', blank_cells); + if (opts.cell_map) |cell_map| { + for (0..blank_cells) |i| try cell_map.append(.{ + .x = @intCast(x - blank_cells + i), + .y = y, + }); + } + blank_cells = 0; } switch (cell.content_tag) { .codepoint => { try writer.print("{u}", .{cell.content.codepoint}); + if (opts.cell_map) |cell_map| { + last_x = x + 1; + try cell_map.append(.{ + .x = x, + .y = y, + }); + } }, .codepoint_grapheme => { try writer.print("{u}", .{cell.content.codepoint}); + if (opts.cell_map) |cell_map| { + last_x = x + 1; + try cell_map.append(.{ + .x = x, + .y = y, + }); + } + for (self.lookupGrapheme(cell).?) |cp| { try writer.print("{u}", .{cp}); + if (opts.cell_map) |cell_map| try cell_map.append(.{ + .x = x, + .y = y, + }); } }, From 61c5fb81150a7924e1cba399dbe526a8ef254285 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 9 Nov 2024 09:37:03 -0800 Subject: [PATCH 07/32] terminal: single pagelist node search --- src/terminal/main.zig | 1 + src/terminal/search.zig | 148 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 src/terminal/search.zig diff --git a/src/terminal/main.zig b/src/terminal/main.zig index 3fc7d2600..df3788d30 100644 --- a/src/terminal/main.zig +++ b/src/terminal/main.zig @@ -18,6 +18,7 @@ pub const kitty = @import("kitty.zig"); pub const modes = @import("modes.zig"); pub const page = @import("page.zig"); pub const parse_table = @import("parse_table.zig"); +pub const search = @import("search.zig"); pub const size = @import("size.zig"); pub const tmux = @import("tmux.zig"); pub const x11_color = @import("x11_color.zig"); diff --git a/src/terminal/search.zig b/src/terminal/search.zig new file mode 100644 index 000000000..96a7b56a7 --- /dev/null +++ b/src/terminal/search.zig @@ -0,0 +1,148 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const assert = std.debug.assert; +const terminal = @import("main.zig"); +const point = terminal.point; +const Page = terminal.Page; +const PageList = terminal.PageList; +const Selection = terminal.Selection; +const Screen = terminal.Screen; + +pub const PageSearch = struct { + alloc: Allocator, + node: *PageList.List.Node, + needle: []const u8, + cell_map: Page.CellMap, + encoded: std.ArrayListUnmanaged(u8) = .{}, + i: usize = 0, + + pub fn init( + alloc: Allocator, + node: *PageList.List.Node, + needle: []const u8, + ) !PageSearch { + var result: PageSearch = .{ + .alloc = alloc, + .node = node, + .needle = needle, + .cell_map = Page.CellMap.init(alloc), + }; + + const page: *const Page = &node.data; + _ = try page.encodeUtf8(result.encoded.writer(alloc), .{ + .cell_map = &result.cell_map, + }); + + return result; + } + + pub fn deinit(self: *PageSearch) void { + self.encoded.deinit(self.alloc); + self.cell_map.deinit(); + } + + pub fn next(self: *PageSearch) ?Selection { + // Search our haystack for the needle. The resulting index is + // the offset from self.i not the absolute index. + const haystack: []const u8 = self.encoded.items[self.i..]; + const i_offset = std.mem.indexOf(u8, haystack, self.needle) orelse { + self.i = self.encoded.items.len; + return null; + }; + + // Get our full index into the encoded buffer. + const idx = self.i + i_offset; + + // We found our search term. Move the cursor forward one beyond + // the match. This lets us find every repeated match. + self.i = idx + 1; + + const tl: PageList.Pin = tl: { + const map = self.cell_map.items[idx]; + break :tl .{ + .node = self.node, + .y = map.y, + .x = map.x, + }; + }; + const br: PageList.Pin = br: { + const map = self.cell_map.items[idx + self.needle.len - 1]; + break :br .{ + .node = self.node, + .y = map.y, + .x = map.x, + }; + }; + + return Selection.init(tl, br, false); + } +}; + +test "search single page one match" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try Screen.init(alloc, 80, 24, 0); + defer s.deinit(); + try s.testWriteString("hello, world"); + + // We want to test single-page cases. + try testing.expect(s.pages.pages.first == s.pages.pages.last); + const node: *PageList.List.Node = s.pages.pages.first.?; + + var it = try PageSearch.init(alloc, node, "world"); + defer it.deinit(); + + const sel = it.next().?; + try testing.expectEqual(point.Point{ .active = .{ + .x = 7, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.start()).?); + try testing.expectEqual(point.Point{ .active = .{ + .x = 11, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.end()).?); + + try testing.expect(it.next() == null); +} + +test "search single page multiple match" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try Screen.init(alloc, 80, 24, 0); + defer s.deinit(); + try s.testWriteString("hello. boo! hello. boo!"); + + // We want to test single-page cases. + try testing.expect(s.pages.pages.first == s.pages.pages.last); + const node: *PageList.List.Node = s.pages.pages.first.?; + + var it = try PageSearch.init(alloc, node, "boo!"); + defer it.deinit(); + + { + const sel = it.next().?; + try testing.expectEqual(point.Point{ .active = .{ + .x = 7, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.start()).?); + try testing.expectEqual(point.Point{ .active = .{ + .x = 10, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.end()).?); + } + { + const sel = it.next().?; + try testing.expectEqual(point.Point{ .active = .{ + .x = 19, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.start()).?); + try testing.expectEqual(point.Point{ .active = .{ + .x = 22, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.end()).?); + } + + try testing.expect(it.next() == null); +} From eaddb695009e94f6c28fec22b63720506cc7ed4c Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 27 Nov 2024 09:48:26 -0800 Subject: [PATCH 08/32] datastruct: CircBuf can be initialized empty --- src/datastruct/circ_buf.zig | 53 +++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/src/datastruct/circ_buf.zig b/src/datastruct/circ_buf.zig index ccee41801..c0c658447 100644 --- a/src/datastruct/circ_buf.zig +++ b/src/datastruct/circ_buf.zig @@ -48,7 +48,7 @@ pub fn CircBuf(comptime T: type, comptime default: T) type { }; /// Initialize a new circular buffer that can store size elements. - pub fn init(alloc: Allocator, size: usize) !Self { + pub fn init(alloc: Allocator, size: usize) Allocator.Error!Self { const buf = try alloc.alloc(T, size); @memset(buf, default); @@ -56,7 +56,7 @@ pub fn CircBuf(comptime T: type, comptime default: T) type { .storage = buf, .head = 0, .tail = 0, - .full = false, + .full = size == 0, }; } @@ -67,7 +67,7 @@ pub fn CircBuf(comptime T: type, comptime default: T) type { /// Append a single value to the buffer. If the buffer is full, /// an error will be returned. - pub fn append(self: *Self, v: T) !void { + pub fn append(self: *Self, v: T) Allocator.Error!void { if (self.full) return error.OutOfMemory; self.storage[self.head] = v; self.head += 1; @@ -256,7 +256,7 @@ test { try testing.expectEqual(@as(usize, 0), buf.len()); } -test "append" { +test "CircBuf append" { const testing = std.testing; const alloc = testing.allocator; @@ -273,7 +273,7 @@ test "append" { try testing.expectError(error.OutOfMemory, buf.append(5)); } -test "forward iterator" { +test "CircBuf forward iterator" { const testing = std.testing; const alloc = testing.allocator; @@ -319,7 +319,7 @@ test "forward iterator" { } } -test "reverse iterator" { +test "CircBuf reverse iterator" { const testing = std.testing; const alloc = testing.allocator; @@ -365,7 +365,7 @@ test "reverse iterator" { } } -test "getPtrSlice fits" { +test "CircBuf getPtrSlice fits" { const testing = std.testing; const alloc = testing.allocator; @@ -379,7 +379,7 @@ test "getPtrSlice fits" { try testing.expectEqual(@as(usize, 11), buf.len()); } -test "getPtrSlice wraps" { +test "CircBuf getPtrSlice wraps" { const testing = std.testing; const alloc = testing.allocator; @@ -435,7 +435,7 @@ test "getPtrSlice wraps" { } } -test "rotateToZero" { +test "CircBuf rotateToZero" { const testing = std.testing; const alloc = testing.allocator; @@ -447,7 +447,7 @@ test "rotateToZero" { try buf.rotateToZero(alloc); } -test "rotateToZero offset" { +test "CircBuf rotateToZero offset" { const testing = std.testing; const alloc = testing.allocator; @@ -471,7 +471,7 @@ test "rotateToZero offset" { try testing.expectEqual(@as(usize, 1), buf.head); } -test "rotateToZero wraps" { +test "CircBuf rotateToZero wraps" { const testing = std.testing; const alloc = testing.allocator; @@ -511,7 +511,7 @@ test "rotateToZero wraps" { } } -test "rotateToZero full no wrap" { +test "CircBuf rotateToZero full no wrap" { const testing = std.testing; const alloc = testing.allocator; @@ -549,7 +549,32 @@ test "rotateToZero full no wrap" { } } -test "resize grow" { +test "CircBuf resize grow from zero" { + const testing = std.testing; + const alloc = testing.allocator; + + const Buf = CircBuf(u8, 0); + var buf = try Buf.init(alloc, 0); + defer buf.deinit(alloc); + try testing.expect(buf.full); + + // Resize + try buf.resize(alloc, 2); + try testing.expect(!buf.full); + try testing.expectEqual(@as(usize, 0), buf.len()); + try testing.expectEqual(@as(usize, 2), buf.capacity()); + + try buf.append(1); + try buf.append(2); + + { + const slices = buf.getPtrSlice(0, 2); + try testing.expectEqual(@as(u8, 1), slices[0][0]); + try testing.expectEqual(@as(u8, 2), slices[0][1]); + } +} + +test "CircBuf resize grow" { const testing = std.testing; const alloc = testing.allocator; @@ -582,7 +607,7 @@ test "resize grow" { } } -test "resize shrink" { +test "CircBuf resize shrink" { const testing = std.testing; const alloc = testing.allocator; From 8abbd80e06c9fb07fc265cb54214c10b7d4b5eb8 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 27 Nov 2024 09:48:26 -0800 Subject: [PATCH 09/32] CircBuf: add ensureUnusedCapacity, appendSlice --- src/datastruct/circ_buf.zig | 129 ++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/src/datastruct/circ_buf.zig b/src/datastruct/circ_buf.zig index c0c658447..e6378c855 100644 --- a/src/datastruct/circ_buf.zig +++ b/src/datastruct/circ_buf.zig @@ -75,6 +75,19 @@ pub fn CircBuf(comptime T: type, comptime default: T) type { self.full = self.head == self.tail; } + /// Append a slice to the buffer. If the buffer cannot fit the + /// entire slice then an error will be returned. It is up to the + /// caller to rotate the circular buffer if they want to overwrite + /// the oldest data. + pub fn appendSlice( + self: *Self, + slice: []const T, + ) Allocator.Error!void { + const storage = self.getPtrSlice(self.len(), slice.len); + fastmem.copy(T, storage[0], slice[0..storage[0].len]); + fastmem.copy(T, storage[1], slice[storage[0].len..]); + } + /// Clear the buffer. pub fn clear(self: *Self) void { self.head = 0; @@ -91,6 +104,34 @@ pub fn CircBuf(comptime T: type, comptime default: T) type { }; } + /// Get the first (oldest) value in the buffer. + pub fn first(self: Self) ?*T { + // Note: this can be more efficient by not using the + // iterator, but this was an easy way to implement it. + var it = self.iterator(.forward); + return it.next(); + } + + /// Get the last (newest) value in the buffer. + pub fn last(self: Self) ?*T { + // Note: this can be more efficient by not using the + // iterator, but this was an easy way to implement it. + var it = self.iterator(.reverse); + return it.next(); + } + + /// Ensures that there is enough capacity to store amount more + /// items via append. + pub fn ensureUnusedCapacity( + self: *Self, + alloc: Allocator, + amount: usize, + ) Allocator.Error!void { + const new_cap = self.len() + amount; + if (new_cap <= self.capacity()) return; + try self.resize(alloc, new_cap); + } + /// Resize the buffer to the given size (larger or smaller). /// If larger, new values will be set to the default value. pub fn resize(self: *Self, alloc: Allocator, size: usize) Allocator.Error!void { @@ -365,6 +406,94 @@ test "CircBuf reverse iterator" { } } +test "CircBuf first/last" { + const testing = std.testing; + const alloc = testing.allocator; + + const Buf = CircBuf(u8, 0); + var buf = try Buf.init(alloc, 3); + defer buf.deinit(alloc); + + try buf.append(1); + try buf.append(2); + try buf.append(3); + try testing.expectEqual(3, buf.last().?.*); + try testing.expectEqual(1, buf.first().?.*); +} + +test "CircBuf first/last empty" { + const testing = std.testing; + const alloc = testing.allocator; + + const Buf = CircBuf(u8, 0); + var buf = try Buf.init(alloc, 0); + defer buf.deinit(alloc); + + try testing.expect(buf.first() == null); + try testing.expect(buf.last() == null); +} + +test "CircBuf first/last empty with cap" { + const testing = std.testing; + const alloc = testing.allocator; + + const Buf = CircBuf(u8, 0); + var buf = try Buf.init(alloc, 3); + defer buf.deinit(alloc); + + try testing.expect(buf.first() == null); + try testing.expect(buf.last() == null); +} + +test "CircBuf append slice" { + const testing = std.testing; + const alloc = testing.allocator; + + const Buf = CircBuf(u8, 0); + var buf = try Buf.init(alloc, 5); + defer buf.deinit(alloc); + + try buf.appendSlice("hello"); + { + var it = buf.iterator(.forward); + try testing.expect(it.next().?.* == 'h'); + try testing.expect(it.next().?.* == 'e'); + try testing.expect(it.next().?.* == 'l'); + try testing.expect(it.next().?.* == 'l'); + try testing.expect(it.next().?.* == 'o'); + try testing.expect(it.next() == null); + } +} + +test "CircBuf append slice with wrap" { + const testing = std.testing; + const alloc = testing.allocator; + + const Buf = CircBuf(u8, 0); + var buf = try Buf.init(alloc, 4); + defer buf.deinit(alloc); + + // Fill the buffer + _ = buf.getPtrSlice(0, buf.capacity()); + try testing.expect(buf.full); + try testing.expectEqual(@as(usize, 4), buf.len()); + + // Delete + buf.deleteOldest(2); + try testing.expect(!buf.full); + try testing.expectEqual(@as(usize, 2), buf.len()); + + try buf.appendSlice("AB"); + { + var it = buf.iterator(.forward); + try testing.expect(it.next().?.* == 0); + try testing.expect(it.next().?.* == 0); + try testing.expect(it.next().?.* == 'A'); + try testing.expect(it.next().?.* == 'B'); + try testing.expect(it.next() == null); + } +} + test "CircBuf getPtrSlice fits" { const testing = std.testing; const alloc = testing.allocator; From 2a13c6b6a35a1689d3642aeaf123485dc0a0e66c Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 27 Nov 2024 09:48:26 -0800 Subject: [PATCH 10/32] terminal: working on a pagelist sliding window for search --- src/terminal/search.zig | 206 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) diff --git a/src/terminal/search.zig b/src/terminal/search.zig index 96a7b56a7..f35249ab2 100644 --- a/src/terminal/search.zig +++ b/src/terminal/search.zig @@ -1,6 +1,7 @@ const std = @import("std"); const Allocator = std.mem.Allocator; const assert = std.debug.assert; +const CircBuf = @import("../datastruct/main.zig").CircBuf; const terminal = @import("main.zig"); const point = terminal.point; const Page = terminal.Page; @@ -8,6 +9,211 @@ const PageList = terminal.PageList; const Selection = terminal.Selection; const Screen = terminal.Screen; +pub const PageListSearch = struct { + alloc: Allocator, + + /// The list we're searching. + list: *PageList, + + /// The search term we're searching for. + needle: []const u8, + + /// The window is our sliding window of pages that we're searching so + /// we can handle boundary cases where a needle is partially on the end + /// of one page and the beginning of the next. + /// + /// Note that we're not guaranteed to straddle exactly two pages. If + /// the needle is large enough and/or the pages are small enough then + /// the needle can straddle N pages. Additionally, pages aren't guaranteed + /// to be equal size so we can't precompute the window size. + window: SlidingWindow, + + pub fn init( + alloc: Allocator, + list: *PageList, + needle: []const u8, + ) !PageListSearch { + var window = try CircBuf.init(alloc, 0); + errdefer window.deinit(); + + return .{ + .alloc = alloc, + .list = list, + .current = list.pages.first, + .needle = needle, + .window = window, + }; + } + + pub fn deinit(self: *PageListSearch) void { + _ = self; + + // TODO: deinit window + } +}; + +/// The sliding window of the pages we're searching. The window is always +/// big enough so that the needle can fit in it. +const SlidingWindow = struct { + /// The data buffer is a circular buffer of u8 that contains the + /// encoded page text that we can use to search for the needle. + data: DataBuf, + + /// The meta buffer is a circular buffer that contains the metadata + /// about the pages we're searching. This usually isn't that large + /// so callers must iterate through it to find the offset to map + /// data to meta. + meta: MetaBuf, + + const DataBuf = CircBuf(u8, 0); + const MetaBuf = CircBuf(Meta, undefined); + const Meta = struct { + node: *PageList.List.Node, + cell_map: Page.CellMap, + + pub fn deinit(self: *Meta) void { + self.cell_map.deinit(); + } + }; + + pub fn initEmpty(alloc: Allocator) Allocator.Error!SlidingWindow { + var data = try DataBuf.init(alloc, 0); + errdefer data.deinit(alloc); + + var meta = try MetaBuf.init(alloc, 0); + errdefer meta.deinit(alloc); + + return .{ + .data = data, + .meta = meta, + }; + } + + pub fn deinit(self: *SlidingWindow, alloc: Allocator) void { + self.data.deinit(alloc); + + var meta_it = self.meta.iterator(.forward); + while (meta_it.next()) |meta| meta.deinit(); + self.meta.deinit(alloc); + } + + /// Add a new node to the sliding window. + /// + /// The window will prune itself if it can while always maintaining + /// the invariant that the `fixed_size` always fits within the window. + /// + /// Note it is possible for the window to be smaller than `fixed_size` + /// if not enough nodes have been added yet or the screen is just + /// smaller than the needle. + pub fn append( + self: *SlidingWindow, + alloc: Allocator, + node: *PageList.List.Node, + required_size: usize, + ) Allocator.Error!void { + // Initialize our metadata for the node. + var meta: Meta = .{ + .node = node, + .cell_map = Page.CellMap.init(alloc), + }; + errdefer meta.deinit(); + + // This is suboptimal but we need to encode the page once to + // temporary memory, and then copy it into our circular buffer. + // In the future, we should benchmark and see if we can encode + // directly into the circular buffer. + var encoded: std.ArrayListUnmanaged(u8) = .{}; + defer encoded.deinit(alloc); + + // Encode the page into the buffer. + const page: *const Page = &meta.node.data; + _ = page.encodeUtf8( + encoded.writer(alloc), + .{ .cell_map = &meta.cell_map }, + ) catch { + // writer uses anyerror but the only realistic error on + // an ArrayList is out of memory. + return error.OutOfMemory; + }; + assert(meta.cell_map.items.len == encoded.items.len); + + // Now that we know our buffer length, we can consider if we can + // prune our circular buffer or if we need to grow it. + prune: { + // Our buffer size after adding the new node. + const before_size: usize = self.data.len() + encoded.items.len; + + // Prune as long as removing the first (oldest) node retains + // our required size invariant. + var after_size: usize = before_size; + while (self.meta.first()) |oldest_meta| { + const new_size = after_size - oldest_meta.cell_map.items.len; + if (new_size < required_size) break :prune; + + // We can prune this node and retain our invariant. + // Update our new size, deinitialize the memory, and + // remove from the circular buffer. + after_size = new_size; + oldest_meta.deinit(); + self.meta.deleteOldest(1); + } + assert(after_size <= before_size); + + // If we didn't prune anything then we're done. + if (after_size == before_size) break :prune; + + // We need to prune our data buffer as well. + self.data.deleteOldest(before_size - after_size); + } + + // Ensure our buffers are big enough to store what we need. + try self.data.ensureUnusedCapacity(alloc, encoded.items.len); + try self.meta.ensureUnusedCapacity(alloc, 1); + + // Append our new node to the circular buffer. + try self.data.appendSlice(encoded.items); + try self.meta.append(meta); + + // Integrity check: verify our data matches our metadata exactly. + if (comptime std.debug.runtime_safety) { + var meta_it = self.meta.iterator(.forward); + var data_len: usize = 0; + while (meta_it.next()) |m| data_len += m.cell_map.items.len; + assert(data_len == self.data.len()); + } + } +}; + +test "SlidingWindow empty on init" { + const testing = std.testing; + const alloc = testing.allocator; + + var w = try SlidingWindow.initEmpty(alloc); + defer w.deinit(alloc); + try testing.expectEqual(0, w.data.len()); + try testing.expectEqual(0, w.meta.len()); +} + +test "SlidingWindow single append" { + const testing = std.testing; + const alloc = testing.allocator; + + var w = try SlidingWindow.initEmpty(alloc); + defer w.deinit(alloc); + + var s = try Screen.init(alloc, 80, 24, 0); + defer s.deinit(); + try s.testWriteString("hello. boo! hello. boo!"); + + // Imaginary needle for search + const needle = "boo!"; + + // We want to test single-page cases. + try testing.expect(s.pages.pages.first == s.pages.pages.last); + const node: *PageList.List.Node = s.pages.pages.first.?; + try w.append(alloc, node, needle.len); +} + pub const PageSearch = struct { alloc: Allocator, node: *PageList.List.Node, From 6ed298c9c1a46689440d4db2d690d0d7618bd156 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 3 Dec 2024 08:04:36 -0500 Subject: [PATCH 11/32] terminal: sliding window search starts working --- ' | 555 ++++++++++++++++++++++++++++++++++++ src/datastruct/circ_buf.zig | 11 + src/terminal/search.zig | 136 +++++++++ 3 files changed, 702 insertions(+) create mode 100644 ' diff --git a/' b/' new file mode 100644 index 000000000..0b79f1879 --- /dev/null +++ b/' @@ -0,0 +1,555 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const assert = std.debug.assert; +const CircBuf = @import("../datastruct/main.zig").CircBuf; +const terminal = @import("main.zig"); +const point = terminal.point; +const Page = terminal.Page; +const PageList = terminal.PageList; +const Pin = PageList.Pin; +const Selection = terminal.Selection; +const Screen = terminal.Screen; + +pub const PageListSearch = struct { + alloc: Allocator, + + /// The list we're searching. + list: *PageList, + + /// The search term we're searching for. + needle: []const u8, + + /// The window is our sliding window of pages that we're searching so + /// we can handle boundary cases where a needle is partially on the end + /// of one page and the beginning of the next. + /// + /// Note that we're not guaranteed to straddle exactly two pages. If + /// the needle is large enough and/or the pages are small enough then + /// the needle can straddle N pages. Additionally, pages aren't guaranteed + /// to be equal size so we can't precompute the window size. + window: SlidingWindow, + + pub fn init( + alloc: Allocator, + list: *PageList, + needle: []const u8, + ) !PageListSearch { + var window = try CircBuf.init(alloc, 0); + errdefer window.deinit(); + + return .{ + .alloc = alloc, + .list = list, + .current = list.pages.first, + .needle = needle, + .window = window, + }; + } + + pub fn deinit(self: *PageListSearch) void { + _ = self; + + // TODO: deinit window + } +}; + +/// The sliding window of the pages we're searching. The window is always +/// big enough so that the needle can fit in it. +const SlidingWindow = struct { + /// The data buffer is a circular buffer of u8 that contains the + /// encoded page text that we can use to search for the needle. + data: DataBuf, + + /// The meta buffer is a circular buffer that contains the metadata + /// about the pages we're searching. This usually isn't that large + /// so callers must iterate through it to find the offset to map + /// data to meta. + meta: MetaBuf, + + /// The cursor into the data buffer for our current search. + i: usize = 0, + + const DataBuf = CircBuf(u8, 0); + const MetaBuf = CircBuf(Meta, undefined); + const Meta = struct { + node: *PageList.List.Node, + cell_map: Page.CellMap, + + pub fn deinit(self: *Meta) void { + self.cell_map.deinit(); + } + }; + + pub fn initEmpty(alloc: Allocator) Allocator.Error!SlidingWindow { + var data = try DataBuf.init(alloc, 0); + errdefer data.deinit(alloc); + + var meta = try MetaBuf.init(alloc, 0); + errdefer meta.deinit(alloc); + + return .{ + .data = data, + .meta = meta, + }; + } + + pub fn deinit(self: *SlidingWindow, alloc: Allocator) void { + self.data.deinit(alloc); + + var meta_it = self.meta.iterator(.forward); + while (meta_it.next()) |meta| meta.deinit(); + self.meta.deinit(alloc); + } + + /// Search the window for the next occurrence of the needle. + pub fn next(self: *SlidingWindow, needle: []const u8) void { + const slices = self.data.getPtrSlice(0, self.data.len()); + + // Search the first slice for the needle. + if (std.mem.indexOf(u8, slices[0][self.i..], needle)) |idx| { + // Found, map the match to a selection. + var meta_it = self.meta.iterator(.forward); + var i: usize = 0; + while (meta_it.next()) |meta| { + const meta_idx = idx - i; + if (meta.cell_map.items.len < meta_idx) { + // This meta doesn't contain the match. + i += meta.cell_map.items.len; + continue; + } + + // We found the meta that contains the start of the match. + const tl: PageList.Pin = tl: { + const map = meta.cell_map.items[meta_idx]; + break :tl .{ + .node = meta.node, + .y = map.y, + .x = map.x, + }; + }; + + _ = tl; + } + + // Found, we can move our index to the next character + // after the match. This let's us find all matches even if + // they overlap. + + self.i = idx + 1; + + @panic("TODO"); + } + } + + /// Return a selection for the given start and length into the data + /// buffer and also prune the data/meta buffers if possible up to + /// this start index. + fn selectAndPrune( + self: *SlidingWindow, + start: usize, + len: usize, + ) Selection { + assert(start < self.data.len()); + assert(start + len < self.data.len()); + + var meta_it = self.meta.iterator(.forward); + var meta_: ?Meta = meta_it.next(); + + // Find the start of the match + var offset: usize = 0; + var skip_nodes: usize = 0; + const tl: PageList.Pin = tl: { + while (meta_) |meta| : (meta_ = meta_it.next()) { + // meta_i is the index we expect to find the match in the + // cell map within this meta if it contains it. + const meta_i = start - offset; + if (meta_i >= meta.cell_map.items.len) { + // This meta doesn't contain the match. This means we + // can also prune this set of data because we only look + // forward. + offset += meta.cell_map.items.len; + skip_nodes += 1; + continue; + } + + // We found the meta that contains the start of the match. + const map = meta.cell_map.items[start]; + break :tl .{ + .node = meta.node, + .y = map.y, + .x = map.x, + }; + } + + // We never found the top-left. This is unreachable because + // we assert that the start index is within the data buffer, + // and when building the data buffer we assert the cell map + // length exactly matches the data buffer length. + unreachable; + }; + + // Keep track of the number of nodes we skipped for the tl. + const tl_skip_nodes = skip_nodes; + skip_nodes = 0; + + // Find the end of the match + const br: PageList.Pin = br: { + const end_idx = start + len - 1; + while (meta_) |meta| : (meta_ = meta_it.next()) { + const meta_i = end_idx - offset; + if (meta_i >= meta.cell_map.items.len) { + offset += meta.cell_map.items.len; + skip_nodes += 1; + continue; + } + + // We found the meta that contains the start of the match. + const map = meta.cell_map.items[end_idx]; + break :br .{ + .node = meta.node, + .y = map.y, + .x = map.x, + }; + } + }; + + // If we skipped any nodes for the bottom-right then we can prune + // all the way up to the total. If we didn't, it means we found + // the bottom-right in the same node as the top-left and we can't + // prune the node that the match is on because there may be + // more matches. + if (skip_nodes > 0) skip_nodes += tl_skip_nodes; + + _ = tl; + _ = br; + } + + /// Convert a data index into a pin. + fn pin( + self: *const SlidingWindow, + idx: usize, + it: ?*MetaBuf.Iterator, + ) struct { + /// The pin for the data index. + pin: Pin, + + /// The offset into the meta buffer that the pin was found. + /// This can be used to prune the meta buffer (its safe to prune + /// before this i). + meta_i: usize, + } { + _ = self; + _ = idx; + _ = start; + + while (it.next()) |meta| { + // meta_i is the index we expect to find the match in the + // cell map within this meta if it contains it. + const meta_i = start - offset; + if (meta_i >= meta.cell_map.items.len) { + // This meta doesn't contain the match. This means we + // can also prune this set of data because we only look + // forward. + offset += meta.cell_map.items.len; + skip_nodes += 1; + continue; + } + + // We found the meta that contains the start of the match. + const map = meta.cell_map.items[start]; + break :tl .{ + .node = meta.node, + .y = map.y, + .x = map.x, + }; + } + + } + + /// Add a new node to the sliding window. + /// + /// The window will prune itself if it can while always maintaining + /// the invariant that the `fixed_size` always fits within the window. + /// + /// Note it is possible for the window to be smaller than `fixed_size` + /// if not enough nodes have been added yet or the screen is just + /// smaller than the needle. + pub fn append( + self: *SlidingWindow, + alloc: Allocator, + node: *PageList.List.Node, + required_size: usize, + ) Allocator.Error!void { + // Initialize our metadata for the node. + var meta: Meta = .{ + .node = node, + .cell_map = Page.CellMap.init(alloc), + }; + errdefer meta.deinit(); + + // This is suboptimal but we need to encode the page once to + // temporary memory, and then copy it into our circular buffer. + // In the future, we should benchmark and see if we can encode + // directly into the circular buffer. + var encoded: std.ArrayListUnmanaged(u8) = .{}; + defer encoded.deinit(alloc); + + // Encode the page into the buffer. + const page: *const Page = &meta.node.data; + _ = page.encodeUtf8( + encoded.writer(alloc), + .{ .cell_map = &meta.cell_map }, + ) catch { + // writer uses anyerror but the only realistic error on + // an ArrayList is out of memory. + return error.OutOfMemory; + }; + assert(meta.cell_map.items.len == encoded.items.len); + + // Now that we know our buffer length, we can consider if we can + // prune our circular buffer or if we need to grow it. + prune: { + // Our buffer size after adding the new node. + const before_size: usize = self.data.len() + encoded.items.len; + + // Prune as long as removing the first (oldest) node retains + // our required size invariant. + var after_size: usize = before_size; + while (self.meta.first()) |oldest_meta| { + const new_size = after_size - oldest_meta.cell_map.items.len; + if (new_size < required_size) break :prune; + + // We can prune this node and retain our invariant. + // Update our new size, deinitialize the memory, and + // remove from the circular buffer. + after_size = new_size; + oldest_meta.deinit(); + self.meta.deleteOldest(1); + } + assert(after_size <= before_size); + + // If we didn't prune anything then we're done. + if (after_size == before_size) break :prune; + + // We need to prune our data buffer as well. + self.data.deleteOldest(before_size - after_size); + } + + // Ensure our buffers are big enough to store what we need. + try self.data.ensureUnusedCapacity(alloc, encoded.items.len); + try self.meta.ensureUnusedCapacity(alloc, 1); + + // Append our new node to the circular buffer. + try self.data.appendSlice(encoded.items); + try self.meta.append(meta); + + // Integrity check: verify our data matches our metadata exactly. + if (comptime std.debug.runtime_safety) { + var meta_it = self.meta.iterator(.forward); + var data_len: usize = 0; + while (meta_it.next()) |m| data_len += m.cell_map.items.len; + assert(data_len == self.data.len()); + } + } +}; + +test "SlidingWindow empty on init" { + const testing = std.testing; + const alloc = testing.allocator; + + var w = try SlidingWindow.initEmpty(alloc); + defer w.deinit(alloc); + try testing.expectEqual(0, w.data.len()); + try testing.expectEqual(0, w.meta.len()); +} + +test "SlidingWindow single append" { + const testing = std.testing; + const alloc = testing.allocator; + + var w = try SlidingWindow.initEmpty(alloc); + defer w.deinit(alloc); + + var s = try Screen.init(alloc, 80, 24, 0); + defer s.deinit(); + try s.testWriteString("hello. boo! hello. boo!"); + + // Imaginary needle for search + const needle = "boo!"; + + // We want to test single-page cases. + try testing.expect(s.pages.pages.first == s.pages.pages.last); + const node: *PageList.List.Node = s.pages.pages.first.?; + try w.append(alloc, node, needle.len); +} + +test "SlidingWindow two pages" { + const testing = std.testing; + const alloc = testing.allocator; + + var w = try SlidingWindow.initEmpty(alloc); + defer w.deinit(alloc); + + var s = try Screen.init(alloc, 80, 24, 1000); + defer s.deinit(); + + // Fill up the first page. The final bytes in the first page + // are "boo!" + const first_page_rows = s.pages.pages.first.?.data.capacity.rows; + for (0..first_page_rows - 1) |_| try s.testWriteString("\n"); + for (0..s.pages.cols - 4) |_| try s.testWriteString("x"); + try s.testWriteString("boo!"); + try testing.expect(s.pages.pages.first == s.pages.pages.last); + try s.testWriteString("\n"); + try testing.expect(s.pages.pages.first != s.pages.pages.last); + try s.testWriteString("hello. boo!"); + + // Imaginary needle for search + const needle = "boo!"; + + // Add both pages + const node: *PageList.List.Node = s.pages.pages.first.?; + try w.append(alloc, node, needle.len); + try w.append(alloc, node.next.?, needle.len); + + // Ensure our data is correct +} + +pub const PageSearch = struct { + alloc: Allocator, + node: *PageList.List.Node, + needle: []const u8, + cell_map: Page.CellMap, + encoded: std.ArrayListUnmanaged(u8) = .{}, + i: usize = 0, + + pub fn init( + alloc: Allocator, + node: *PageList.List.Node, + needle: []const u8, + ) !PageSearch { + var result: PageSearch = .{ + .alloc = alloc, + .node = node, + .needle = needle, + .cell_map = Page.CellMap.init(alloc), + }; + + const page: *const Page = &node.data; + _ = try page.encodeUtf8(result.encoded.writer(alloc), .{ + .cell_map = &result.cell_map, + }); + + return result; + } + + pub fn deinit(self: *PageSearch) void { + self.encoded.deinit(self.alloc); + self.cell_map.deinit(); + } + + pub fn next(self: *PageSearch) ?Selection { + // Search our haystack for the needle. The resulting index is + // the offset from self.i not the absolute index. + const haystack: []const u8 = self.encoded.items[self.i..]; + const i_offset = std.mem.indexOf(u8, haystack, self.needle) orelse { + self.i = self.encoded.items.len; + return null; + }; + + // Get our full index into the encoded buffer. + const idx = self.i + i_offset; + + // We found our search term. Move the cursor forward one beyond + // the match. This lets us find every repeated match. + self.i = idx + 1; + + const tl: PageList.Pin = tl: { + const map = self.cell_map.items[idx]; + break :tl .{ + .node = self.node, + .y = map.y, + .x = map.x, + }; + }; + const br: PageList.Pin = br: { + const map = self.cell_map.items[idx + self.needle.len - 1]; + break :br .{ + .node = self.node, + .y = map.y, + .x = map.x, + }; + }; + + return Selection.init(tl, br, false); + } +}; + +test "search single page one match" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try Screen.init(alloc, 80, 24, 0); + defer s.deinit(); + try s.testWriteString("hello, world"); + + // We want to test single-page cases. + try testing.expect(s.pages.pages.first == s.pages.pages.last); + const node: *PageList.List.Node = s.pages.pages.first.?; + + var it = try PageSearch.init(alloc, node, "world"); + defer it.deinit(); + + const sel = it.next().?; + try testing.expectEqual(point.Point{ .active = .{ + .x = 7, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.start()).?); + try testing.expectEqual(point.Point{ .active = .{ + .x = 11, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.end()).?); + + try testing.expect(it.next() == null); +} + +test "search single page multiple match" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try Screen.init(alloc, 80, 24, 0); + defer s.deinit(); + try s.testWriteString("hello. boo! hello. boo!"); + + // We want to test single-page cases. + try testing.expect(s.pages.pages.first == s.pages.pages.last); + const node: *PageList.List.Node = s.pages.pages.first.?; + + var it = try PageSearch.init(alloc, node, "boo!"); + defer it.deinit(); + + { + const sel = it.next().?; + try testing.expectEqual(point.Point{ .active = .{ + .x = 7, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.start()).?); + try testing.expectEqual(point.Point{ .active = .{ + .x = 10, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.end()).?); + } + { + const sel = it.next().?; + try testing.expectEqual(point.Point{ .active = .{ + .x = 19, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.start()).?); + try testing.expectEqual(point.Point{ .active = .{ + .x = 22, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.end()).?); + } + + try testing.expect(it.next() == null); +} diff --git a/src/datastruct/circ_buf.zig b/src/datastruct/circ_buf.zig index e6378c855..c13bcc192 100644 --- a/src/datastruct/circ_buf.zig +++ b/src/datastruct/circ_buf.zig @@ -45,6 +45,17 @@ pub fn CircBuf(comptime T: type, comptime default: T) type { self.idx += 1; return &self.buf.storage[storage_idx]; } + + /// Seek the iterator by a given amount. This will clamp + /// the values to the bounds of the buffer so overflows are + /// not possible. + pub fn seekBy(self: *Iterator, amount: isize) void { + if (amount > 0) { + self.idx +|= @intCast(amount); + } else { + self.idx -|= @intCast(@abs(amount)); + } + } }; /// Initialize a new circular buffer that can store size elements. diff --git a/src/terminal/search.zig b/src/terminal/search.zig index f35249ab2..05b2919e0 100644 --- a/src/terminal/search.zig +++ b/src/terminal/search.zig @@ -6,6 +6,7 @@ const terminal = @import("main.zig"); const point = terminal.point; const Page = terminal.Page; const PageList = terminal.PageList; +const Pin = PageList.Pin; const Selection = terminal.Selection; const Screen = terminal.Screen; @@ -97,6 +98,85 @@ const SlidingWindow = struct { self.meta.deinit(alloc); } + /// Search the window for the next occurrence of the needle. As + /// the window moves, the window will prune itself while maintaining + /// the invariant that the window is always big enough to contain + /// the needle. + pub fn next(self: *SlidingWindow, needle: []const u8) ?Selection { + const slices = self.data.getPtrSlice(0, self.data.len()); + + // Search the first slice for the needle. + if (std.mem.indexOf(u8, slices[0], needle)) |idx| { + return self.selection(idx, needle.len); + } + + @panic("TODO"); + } + + /// Return a selection for the given start and length into the data + /// buffer and also prune the data/meta buffers if possible up to + /// this start index. + fn selection( + self: *SlidingWindow, + start: usize, + len: usize, + ) Selection { + assert(start < self.data.len()); + assert(start + len < self.data.len()); + + var meta_it = self.meta.iterator(.forward); + const tl: Pin = pin(&meta_it, start); + + // We have to seek back so that we reinspect our current + // iterator value again in case the start and end are in the + // same segment. + meta_it.seekBy(-1); + const br: Pin = pin(&meta_it, start + len - 1); + + // TODO: prune based on meta_it.idx + + return Selection.init(tl, br, false); + } + + /// Convert a data index into a pin. + /// + /// Tip: you can get the offset into the meta buffer we searched + /// by inspecting the iterator index after this function returns. + /// I note this because this is useful if you want to prune the + /// meta buffer after you find a match. + /// + /// Precondition: the index must be within the data buffer. + fn pin( + it: *MetaBuf.Iterator, + idx: usize, + ) Pin { + var offset: usize = 0; + while (it.next()) |meta| { + // meta_i is the index we expect to find the match in the + // cell map within this meta if it contains it. + const meta_i = idx - offset; + if (meta_i >= meta.cell_map.items.len) { + // This meta doesn't contain the match. This means we + // can also prune this set of data because we only look + // forward. + offset += meta.cell_map.items.len; + continue; + } + + // We found the meta that contains the start of the match. + const map = meta.cell_map.items[meta_i]; + return .{ + .node = meta.node, + .y = map.y, + .x = map.x, + }; + } + + // Unreachable because it is a precondition that the index is + // within the data buffer. + unreachable; + } + /// Add a new node to the sliding window. /// /// The window will prune itself if it can while always maintaining @@ -212,6 +292,62 @@ test "SlidingWindow single append" { try testing.expect(s.pages.pages.first == s.pages.pages.last); const node: *PageList.List.Node = s.pages.pages.first.?; try w.append(alloc, node, needle.len); + + // We should be able to find two matches. + { + const sel = w.next(needle).?; + try testing.expectEqual(point.Point{ .active = .{ + .x = 7, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.start()).?); + try testing.expectEqual(point.Point{ .active = .{ + .x = 10, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.end()).?); + } + { + const sel = w.next(needle).?; + try testing.expectEqual(point.Point{ .active = .{ + .x = 19, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.start()).?); + try testing.expectEqual(point.Point{ .active = .{ + .x = 22, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.end()).?); + } +} + +test "SlidingWindow two pages" { + const testing = std.testing; + const alloc = testing.allocator; + + var w = try SlidingWindow.initEmpty(alloc); + defer w.deinit(alloc); + + var s = try Screen.init(alloc, 80, 24, 1000); + defer s.deinit(); + + // Fill up the first page. The final bytes in the first page + // are "boo!" + const first_page_rows = s.pages.pages.first.?.data.capacity.rows; + for (0..first_page_rows - 1) |_| try s.testWriteString("\n"); + for (0..s.pages.cols - 4) |_| try s.testWriteString("x"); + try s.testWriteString("boo!"); + try testing.expect(s.pages.pages.first == s.pages.pages.last); + try s.testWriteString("\n"); + try testing.expect(s.pages.pages.first != s.pages.pages.last); + try s.testWriteString("hello. boo!"); + + // Imaginary needle for search + const needle = "boo!"; + + // Add both pages + const node: *PageList.List.Node = s.pages.pages.first.?; + try w.append(alloc, node, needle.len); + try w.append(alloc, node.next.?, needle.len); + + // Ensure our data is correct } pub const PageSearch = struct { From d307b02e40de5816e0ee8e49d70e0ce555e13c18 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 3 Dec 2024 13:06:52 -0500 Subject: [PATCH 12/32] terminal: sliding window search can move the cursor --- src/datastruct/circ_buf.zig | 5 +++ src/terminal/search.zig | 75 ++++++++++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/src/datastruct/circ_buf.zig b/src/datastruct/circ_buf.zig index c13bcc192..065bf6a1d 100644 --- a/src/datastruct/circ_buf.zig +++ b/src/datastruct/circ_buf.zig @@ -56,6 +56,11 @@ pub fn CircBuf(comptime T: type, comptime default: T) type { self.idx -|= @intCast(@abs(amount)); } } + + /// Reset the iterator back to the first value. + pub fn reset(self: *Iterator) void { + self.idx = 0; + } }; /// Initialize a new circular buffer that can store size elements. diff --git a/src/terminal/search.zig b/src/terminal/search.zig index 05b2919e0..e217f649e 100644 --- a/src/terminal/search.zig +++ b/src/terminal/search.zig @@ -66,6 +66,11 @@ const SlidingWindow = struct { /// data to meta. meta: MetaBuf, + /// Offset into data for our current state. This handles the + /// situation where our search moved through meta[0] but didn't + /// do enough to prune it. + data_offset: usize = 0, + const DataBuf = CircBuf(u8, 0); const MetaBuf = CircBuf(Meta, undefined); const Meta = struct { @@ -98,31 +103,60 @@ const SlidingWindow = struct { self.meta.deinit(alloc); } + /// Clear all data but retain allocated capacity. + pub fn clearAndRetainCapacity(self: *SlidingWindow) void { + var meta_it = self.meta.iterator(.forward); + while (meta_it.next()) |meta| meta.deinit(); + self.meta.clear(); + self.data.clear(); + self.data_offset = 0; + } + /// Search the window for the next occurrence of the needle. As /// the window moves, the window will prune itself while maintaining /// the invariant that the window is always big enough to contain /// the needle. pub fn next(self: *SlidingWindow, needle: []const u8) ?Selection { - const slices = self.data.getPtrSlice(0, self.data.len()); + const data_len = self.data.len(); + if (data_len == 0) return null; + const slices = self.data.getPtrSlice( + self.data_offset, + data_len - self.data_offset, + ); // Search the first slice for the needle. if (std.mem.indexOf(u8, slices[0], needle)) |idx| { return self.selection(idx, needle.len); } - @panic("TODO"); + // TODO: search overlap + + // Search the last slice for the needle. + if (std.mem.indexOf(u8, slices[1], needle)) |idx| { + if (true) @panic("TODO: test"); + return self.selection(slices[0].len + idx, needle.len); + } + + // No match. Clear everything. + self.clearAndRetainCapacity(); + return null; } /// Return a selection for the given start and length into the data /// buffer and also prune the data/meta buffers if possible up to /// this start index. + /// + /// The start index is assumed to be relative to the offset. i.e. + /// index zero is actually at `self.data[self.data_offset]`. The + /// selection will account for the offset. fn selection( self: *SlidingWindow, - start: usize, + start_offset: usize, len: usize, ) Selection { + const start = start_offset + self.data_offset; assert(start < self.data.len()); - assert(start + len < self.data.len()); + assert(start + len <= self.data.len()); var meta_it = self.meta.iterator(.forward); const tl: Pin = pin(&meta_it, start); @@ -132,8 +166,37 @@ const SlidingWindow = struct { // same segment. meta_it.seekBy(-1); const br: Pin = pin(&meta_it, start + len - 1); + assert(meta_it.idx >= 1); - // TODO: prune based on meta_it.idx + // meta_it.idx is now the index after the br pin. We can + // safely prune our data up to this index. (It is after + // because next() is called at least once). + const br_meta_idx: usize = meta_it.idx - 1; + meta_it.reset(); + var offset: usize = 0; + while (meta_it.next()) |meta| { + const meta_idx = start - offset; + if (meta_idx >= meta.cell_map.items.len) { + // Prior to our matches, we can prune it. + offset += meta.cell_map.items.len; + meta.deinit(); + } + + assert(meta_it.idx == br_meta_idx + 1); + break; + } + + // If we have metas to prune, then prune them. They should be + // deinitialized already from the while loop above. + if (br_meta_idx > 0) { + assert(offset > 0); + self.meta.deleteOldest(br_meta_idx); + self.data.deleteOldest(offset); + @panic("TODO: TEST"); + } + + // Move our data one beyond so we don't rematch. + self.data_offset = start - offset + 1; return Selection.init(tl, br, false); } @@ -316,6 +379,8 @@ test "SlidingWindow single append" { .y = 0, } }, s.pages.pointFromPin(.active, sel.end()).?); } + try testing.expect(w.next(needle) == null); + try testing.expect(w.next(needle) == null); } test "SlidingWindow two pages" { From b487aa8e1fbd1981103a00464333467068661006 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 3 Dec 2024 13:40:48 -0500 Subject: [PATCH 13/32] terminal: search across two pages and pruning appears to be working --- src/terminal/search.zig | 208 +++++++++++++++++++++++----------------- 1 file changed, 121 insertions(+), 87 deletions(-) diff --git a/src/terminal/search.zig b/src/terminal/search.zig index e217f649e..35f79ed23 100644 --- a/src/terminal/search.zig +++ b/src/terminal/search.zig @@ -53,8 +53,9 @@ pub const PageListSearch = struct { } }; -/// The sliding window of the pages we're searching. The window is always -/// big enough so that the needle can fit in it. +/// Search pages via a sliding window. The sliding window always maintains +/// the invariant that data isn't pruned until we've searched it and +/// accounted for overlaps across pages. const SlidingWindow = struct { /// The data buffer is a circular buffer of u8 that contains the /// encoded page text that we can use to search for the needle. @@ -137,8 +138,42 @@ const SlidingWindow = struct { return self.selection(slices[0].len + idx, needle.len); } - // No match. Clear everything. - self.clearAndRetainCapacity(); + // No match. We keep `needle.len - 1` bytes available to + // handle the future overlap case. + var meta_it = self.meta.iterator(.reverse); + prune: { + var saved: usize = 0; + while (meta_it.next()) |meta| { + const needed = needle.len - 1 - saved; + if (meta.cell_map.items.len >= needed) { + // We save up to this meta. We set our data offset + // to exactly where it needs to be to continue + // searching. + self.data_offset = meta.cell_map.items.len - needed; + break; + } + + saved += meta.cell_map.items.len; + } else { + // If we exited the while loop naturally then we + // never got the amount we needed and so there is + // nothing to prune. + assert(saved < needle.len - 1); + break :prune; + } + + const prune_count = self.meta.len() - meta_it.idx; + if (prune_count == 0) { + // This can happen if we need to save up to the first + // meta value to retain our window. + break :prune; + } + + // We can now delete all the metas up to but NOT including + // the meta we found through meta_it. + @panic("TODO: test"); + } + return null; } @@ -158,71 +193,74 @@ const SlidingWindow = struct { assert(start < self.data.len()); assert(start + len <= self.data.len()); + // meta_consumed is the number of bytes we've consumed in the + // data buffer up to and NOT including the meta where we've + // found our pin. This is important because it tells us the + // amount of data we can safely deleted from self.data since + // we can't partially delete a meta block's data. (The partial + // amount is represented by self.data_offset). var meta_it = self.meta.iterator(.forward); - const tl: Pin = pin(&meta_it, start); + var meta_consumed: usize = 0; + const tl: Pin = pin(&meta_it, &meta_consumed, start); // We have to seek back so that we reinspect our current // iterator value again in case the start and end are in the // same segment. meta_it.seekBy(-1); - const br: Pin = pin(&meta_it, start + len - 1); + const br: Pin = pin(&meta_it, &meta_consumed, start + len - 1); assert(meta_it.idx >= 1); - // meta_it.idx is now the index after the br pin. We can - // safely prune our data up to this index. (It is after - // because next() is called at least once). - const br_meta_idx: usize = meta_it.idx - 1; - meta_it.reset(); - var offset: usize = 0; - while (meta_it.next()) |meta| { - const meta_idx = start - offset; - if (meta_idx >= meta.cell_map.items.len) { - // Prior to our matches, we can prune it. - offset += meta.cell_map.items.len; - meta.deinit(); + // Our offset into the current meta block is the start index + // minus the amount of data fully consumed. We then add one + // to move one past the match so we don't repeat it. + self.data_offset = start - meta_consumed + 1; + + // meta_it.idx is br's meta index plus one (because the iterator + // moves one past the end; we call next() one last time). So + // we compare against one to check that the meta that we matched + // in has prior meta blocks we can prune. + if (meta_it.idx > 1) { + // Deinit all our memory in the meta blocks prior to our + // match. + const meta_count = meta_it.idx - 1; + meta_it.reset(); + for (0..meta_count) |_| meta_it.next().?.deinit(); + if (comptime std.debug.runtime_safety) { + assert(meta_it.idx == meta_count); + assert(meta_it.next().?.node == br.node); } + self.meta.deleteOldest(meta_count); - assert(meta_it.idx == br_meta_idx + 1); - break; + // Delete all the data up to our current index. + assert(meta_consumed > 0); + self.data.deleteOldest(meta_consumed); } - // If we have metas to prune, then prune them. They should be - // deinitialized already from the while loop above. - if (br_meta_idx > 0) { - assert(offset > 0); - self.meta.deleteOldest(br_meta_idx); - self.data.deleteOldest(offset); - @panic("TODO: TEST"); - } - - // Move our data one beyond so we don't rematch. - self.data_offset = start - offset + 1; - + self.assertIntegrity(); return Selection.init(tl, br, false); } /// Convert a data index into a pin. /// - /// Tip: you can get the offset into the meta buffer we searched - /// by inspecting the iterator index after this function returns. - /// I note this because this is useful if you want to prune the - /// meta buffer after you find a match. + /// The iterator and offset are both expected to be passed by + /// pointer so that the pin can be efficiently called for multiple + /// indexes (in order). See selection() for an example. /// /// Precondition: the index must be within the data buffer. fn pin( it: *MetaBuf.Iterator, + offset: *usize, idx: usize, ) Pin { - var offset: usize = 0; while (it.next()) |meta| { // meta_i is the index we expect to find the match in the // cell map within this meta if it contains it. - const meta_i = idx - offset; + const meta_i = idx - offset.*; if (meta_i >= meta.cell_map.items.len) { // This meta doesn't contain the match. This means we // can also prune this set of data because we only look // forward. - offset += meta.cell_map.items.len; + offset.* += meta.cell_map.items.len; continue; } @@ -240,19 +278,13 @@ const SlidingWindow = struct { unreachable; } - /// Add a new node to the sliding window. - /// - /// The window will prune itself if it can while always maintaining - /// the invariant that the `fixed_size` always fits within the window. - /// - /// Note it is possible for the window to be smaller than `fixed_size` - /// if not enough nodes have been added yet or the screen is just - /// smaller than the needle. + /// Add a new node to the sliding window. This will always grow + /// the sliding window; data isn't pruned until it is consumed + /// via a search (via next()). pub fn append( self: *SlidingWindow, alloc: Allocator, node: *PageList.List.Node, - required_size: usize, ) Allocator.Error!void { // Initialize our metadata for the node. var meta: Meta = .{ @@ -280,35 +312,6 @@ const SlidingWindow = struct { }; assert(meta.cell_map.items.len == encoded.items.len); - // Now that we know our buffer length, we can consider if we can - // prune our circular buffer or if we need to grow it. - prune: { - // Our buffer size after adding the new node. - const before_size: usize = self.data.len() + encoded.items.len; - - // Prune as long as removing the first (oldest) node retains - // our required size invariant. - var after_size: usize = before_size; - while (self.meta.first()) |oldest_meta| { - const new_size = after_size - oldest_meta.cell_map.items.len; - if (new_size < required_size) break :prune; - - // We can prune this node and retain our invariant. - // Update our new size, deinitialize the memory, and - // remove from the circular buffer. - after_size = new_size; - oldest_meta.deinit(); - self.meta.deleteOldest(1); - } - assert(after_size <= before_size); - - // If we didn't prune anything then we're done. - if (after_size == before_size) break :prune; - - // We need to prune our data buffer as well. - self.data.deleteOldest(before_size - after_size); - } - // Ensure our buffers are big enough to store what we need. try self.data.ensureUnusedCapacity(alloc, encoded.items.len); try self.meta.ensureUnusedCapacity(alloc, 1); @@ -317,13 +320,20 @@ const SlidingWindow = struct { try self.data.appendSlice(encoded.items); try self.meta.append(meta); + self.assertIntegrity(); + } + + fn assertIntegrity(self: *const SlidingWindow) void { + if (comptime !std.debug.runtime_safety) return; + // Integrity check: verify our data matches our metadata exactly. - if (comptime std.debug.runtime_safety) { - var meta_it = self.meta.iterator(.forward); - var data_len: usize = 0; - while (meta_it.next()) |m| data_len += m.cell_map.items.len; - assert(data_len == self.data.len()); - } + var meta_it = self.meta.iterator(.forward); + var data_len: usize = 0; + while (meta_it.next()) |m| data_len += m.cell_map.items.len; + assert(data_len == self.data.len()); + + // Integrity check: verify our data offset is within bounds. + assert(self.data_offset < self.data.len()); } }; @@ -354,7 +364,7 @@ test "SlidingWindow single append" { // We want to test single-page cases. try testing.expect(s.pages.pages.first == s.pages.pages.last); const node: *PageList.List.Node = s.pages.pages.first.?; - try w.append(alloc, node, needle.len); + try w.append(alloc, node); // We should be able to find two matches. { @@ -409,10 +419,34 @@ test "SlidingWindow two pages" { // Add both pages const node: *PageList.List.Node = s.pages.pages.first.?; - try w.append(alloc, node, needle.len); - try w.append(alloc, node.next.?, needle.len); + try w.append(alloc, node); + try w.append(alloc, node.next.?); - // Ensure our data is correct + // Search should find two matches + { + const sel = w.next(needle).?; + try testing.expectEqual(point.Point{ .active = .{ + .x = 76, + .y = 22, + } }, s.pages.pointFromPin(.active, sel.start()).?); + try testing.expectEqual(point.Point{ .active = .{ + .x = 79, + .y = 22, + } }, s.pages.pointFromPin(.active, sel.end()).?); + } + { + const sel = w.next(needle).?; + try testing.expectEqual(point.Point{ .active = .{ + .x = 7, + .y = 23, + } }, s.pages.pointFromPin(.active, sel.start()).?); + try testing.expectEqual(point.Point{ .active = .{ + .x = 10, + .y = 23, + } }, s.pages.pointFromPin(.active, sel.end()).?); + } + try testing.expect(w.next(needle) == null); + try testing.expect(w.next(needle) == null); } pub const PageSearch = struct { From 09e4cccd2c891d3a2e242fce486f8ff8fd83db02 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 3 Dec 2024 15:39:36 -0800 Subject: [PATCH 14/32] terminal: remove unused pagesearch --- src/terminal/search.zig | 139 ---------------------------------------- 1 file changed, 139 deletions(-) diff --git a/src/terminal/search.zig b/src/terminal/search.zig index 35f79ed23..40462491a 100644 --- a/src/terminal/search.zig +++ b/src/terminal/search.zig @@ -448,142 +448,3 @@ test "SlidingWindow two pages" { try testing.expect(w.next(needle) == null); try testing.expect(w.next(needle) == null); } - -pub const PageSearch = struct { - alloc: Allocator, - node: *PageList.List.Node, - needle: []const u8, - cell_map: Page.CellMap, - encoded: std.ArrayListUnmanaged(u8) = .{}, - i: usize = 0, - - pub fn init( - alloc: Allocator, - node: *PageList.List.Node, - needle: []const u8, - ) !PageSearch { - var result: PageSearch = .{ - .alloc = alloc, - .node = node, - .needle = needle, - .cell_map = Page.CellMap.init(alloc), - }; - - const page: *const Page = &node.data; - _ = try page.encodeUtf8(result.encoded.writer(alloc), .{ - .cell_map = &result.cell_map, - }); - - return result; - } - - pub fn deinit(self: *PageSearch) void { - self.encoded.deinit(self.alloc); - self.cell_map.deinit(); - } - - pub fn next(self: *PageSearch) ?Selection { - // Search our haystack for the needle. The resulting index is - // the offset from self.i not the absolute index. - const haystack: []const u8 = self.encoded.items[self.i..]; - const i_offset = std.mem.indexOf(u8, haystack, self.needle) orelse { - self.i = self.encoded.items.len; - return null; - }; - - // Get our full index into the encoded buffer. - const idx = self.i + i_offset; - - // We found our search term. Move the cursor forward one beyond - // the match. This lets us find every repeated match. - self.i = idx + 1; - - const tl: PageList.Pin = tl: { - const map = self.cell_map.items[idx]; - break :tl .{ - .node = self.node, - .y = map.y, - .x = map.x, - }; - }; - const br: PageList.Pin = br: { - const map = self.cell_map.items[idx + self.needle.len - 1]; - break :br .{ - .node = self.node, - .y = map.y, - .x = map.x, - }; - }; - - return Selection.init(tl, br, false); - } -}; - -test "search single page one match" { - const testing = std.testing; - const alloc = testing.allocator; - - var s = try Screen.init(alloc, 80, 24, 0); - defer s.deinit(); - try s.testWriteString("hello, world"); - - // We want to test single-page cases. - try testing.expect(s.pages.pages.first == s.pages.pages.last); - const node: *PageList.List.Node = s.pages.pages.first.?; - - var it = try PageSearch.init(alloc, node, "world"); - defer it.deinit(); - - const sel = it.next().?; - try testing.expectEqual(point.Point{ .active = .{ - .x = 7, - .y = 0, - } }, s.pages.pointFromPin(.active, sel.start()).?); - try testing.expectEqual(point.Point{ .active = .{ - .x = 11, - .y = 0, - } }, s.pages.pointFromPin(.active, sel.end()).?); - - try testing.expect(it.next() == null); -} - -test "search single page multiple match" { - const testing = std.testing; - const alloc = testing.allocator; - - var s = try Screen.init(alloc, 80, 24, 0); - defer s.deinit(); - try s.testWriteString("hello. boo! hello. boo!"); - - // We want to test single-page cases. - try testing.expect(s.pages.pages.first == s.pages.pages.last); - const node: *PageList.List.Node = s.pages.pages.first.?; - - var it = try PageSearch.init(alloc, node, "boo!"); - defer it.deinit(); - - { - const sel = it.next().?; - try testing.expectEqual(point.Point{ .active = .{ - .x = 7, - .y = 0, - } }, s.pages.pointFromPin(.active, sel.start()).?); - try testing.expectEqual(point.Point{ .active = .{ - .x = 10, - .y = 0, - } }, s.pages.pointFromPin(.active, sel.end()).?); - } - { - const sel = it.next().?; - try testing.expectEqual(point.Point{ .active = .{ - .x = 19, - .y = 0, - } }, s.pages.pointFromPin(.active, sel.start()).?); - try testing.expectEqual(point.Point{ .active = .{ - .x = 22, - .y = 0, - } }, s.pages.pointFromPin(.active, sel.end()).?); - } - - try testing.expect(it.next() == null); -} From 79026a114837ba0945d0f6948c7c2efc9f549516 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 3 Dec 2024 15:52:48 -0800 Subject: [PATCH 15/32] terminal: test no match pruning --- src/terminal/search.zig | 116 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/src/terminal/search.zig b/src/terminal/search.zig index 40462491a..71ac6aea4 100644 --- a/src/terminal/search.zig +++ b/src/terminal/search.zig @@ -171,9 +171,18 @@ const SlidingWindow = struct { // We can now delete all the metas up to but NOT including // the meta we found through meta_it. - @panic("TODO: test"); + meta_it = self.meta.iterator(.forward); + var prune_data_len: usize = 0; + for (0..prune_count) |_| { + const meta = meta_it.next().?; + prune_data_len += meta.cell_map.items.len; + meta.deinit(); + } + self.meta.deleteOldest(prune_count); + self.data.deleteOldest(prune_data_len); } + self.assertIntegrity(); return null; } @@ -393,6 +402,33 @@ test "SlidingWindow single append" { try testing.expect(w.next(needle) == null); } +test "SlidingWindow single append no match" { + const testing = std.testing; + const alloc = testing.allocator; + + var w = try SlidingWindow.initEmpty(alloc); + defer w.deinit(alloc); + + var s = try Screen.init(alloc, 80, 24, 0); + defer s.deinit(); + try s.testWriteString("hello. boo! hello. boo!"); + + // Imaginary needle for search + const needle = "nope!"; + + // We want to test single-page cases. + try testing.expect(s.pages.pages.first == s.pages.pages.last); + const node: *PageList.List.Node = s.pages.pages.first.?; + try w.append(alloc, node); + + // No matches + try testing.expect(w.next(needle) == null); + try testing.expect(w.next(needle) == null); + + // Should still keep the page + try testing.expectEqual(1, w.meta.len()); +} + test "SlidingWindow two pages" { const testing = std.testing; const alloc = testing.allocator; @@ -448,3 +484,81 @@ test "SlidingWindow two pages" { try testing.expect(w.next(needle) == null); try testing.expect(w.next(needle) == null); } + +test "SlidingWindow two pages no match prunes first page" { + const testing = std.testing; + const alloc = testing.allocator; + + var w = try SlidingWindow.initEmpty(alloc); + defer w.deinit(alloc); + + var s = try Screen.init(alloc, 80, 24, 1000); + defer s.deinit(); + + // Fill up the first page. The final bytes in the first page + // are "boo!" + const first_page_rows = s.pages.pages.first.?.data.capacity.rows; + for (0..first_page_rows - 1) |_| try s.testWriteString("\n"); + for (0..s.pages.cols - 4) |_| try s.testWriteString("x"); + try s.testWriteString("boo!"); + try testing.expect(s.pages.pages.first == s.pages.pages.last); + try s.testWriteString("\n"); + try testing.expect(s.pages.pages.first != s.pages.pages.last); + try s.testWriteString("hello. boo!"); + + // Add both pages + const node: *PageList.List.Node = s.pages.pages.first.?; + try w.append(alloc, node); + try w.append(alloc, node.next.?); + + // Imaginary needle for search. Doesn't match! + const needle = "nope!"; + + // Search should find nothing + try testing.expect(w.next(needle) == null); + try testing.expect(w.next(needle) == null); + + // We should've pruned our page because the second page + // has enough text to contain our needle. + try testing.expectEqual(1, w.meta.len()); +} + +test "SlidingWindow two pages no match keeps both pages" { + const testing = std.testing; + const alloc = testing.allocator; + + var w = try SlidingWindow.initEmpty(alloc); + defer w.deinit(alloc); + + var s = try Screen.init(alloc, 80, 24, 1000); + defer s.deinit(); + + // Fill up the first page. The final bytes in the first page + // are "boo!" + const first_page_rows = s.pages.pages.first.?.data.capacity.rows; + for (0..first_page_rows - 1) |_| try s.testWriteString("\n"); + for (0..s.pages.cols - 4) |_| try s.testWriteString("x"); + try s.testWriteString("boo!"); + try testing.expect(s.pages.pages.first == s.pages.pages.last); + try s.testWriteString("\n"); + try testing.expect(s.pages.pages.first != s.pages.pages.last); + try s.testWriteString("hello. boo!"); + + // Add both pages + const node: *PageList.List.Node = s.pages.pages.first.?; + try w.append(alloc, node); + try w.append(alloc, node.next.?); + + // Imaginary needle for search. Doesn't match! + var needle_list = std.ArrayList(u8).init(alloc); + defer needle_list.deinit(); + try needle_list.appendNTimes('x', first_page_rows * s.pages.cols); + const needle: []const u8 = needle_list.items; + + // Search should find nothing + try testing.expect(w.next(needle) == null); + try testing.expect(w.next(needle) == null); + + // No pruning because both pages are needed to fit needle. + try testing.expectEqual(2, w.meta.len()); +} From af1ee4d95f645d9a33841dcb5b77a93c8bdc9745 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 4 Dec 2024 10:36:14 -0800 Subject: [PATCH 16/32] terminal: search match across page boundary --- src/terminal/search.zig | 65 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/src/terminal/search.zig b/src/terminal/search.zig index 71ac6aea4..88da8304d 100644 --- a/src/terminal/search.zig +++ b/src/terminal/search.zig @@ -212,6 +212,12 @@ const SlidingWindow = struct { var meta_consumed: usize = 0; const tl: Pin = pin(&meta_it, &meta_consumed, start); + // Store the information required to prune later. We store this + // now because we only want to prune up to our START so we can + // find overlapping matches. + const tl_meta_idx = meta_it.idx - 1; + const tl_meta_consumed = meta_consumed; + // We have to seek back so that we reinspect our current // iterator value again in case the start and end are in the // same segment. @@ -222,27 +228,27 @@ const SlidingWindow = struct { // Our offset into the current meta block is the start index // minus the amount of data fully consumed. We then add one // to move one past the match so we don't repeat it. - self.data_offset = start - meta_consumed + 1; + self.data_offset = start - tl_meta_consumed + 1; // meta_it.idx is br's meta index plus one (because the iterator // moves one past the end; we call next() one last time). So // we compare against one to check that the meta that we matched // in has prior meta blocks we can prune. - if (meta_it.idx > 1) { + if (tl_meta_idx > 0) { // Deinit all our memory in the meta blocks prior to our // match. - const meta_count = meta_it.idx - 1; + const meta_count = tl_meta_idx; meta_it.reset(); for (0..meta_count) |_| meta_it.next().?.deinit(); if (comptime std.debug.runtime_safety) { assert(meta_it.idx == meta_count); - assert(meta_it.next().?.node == br.node); + assert(meta_it.next().?.node == tl.node); } self.meta.deleteOldest(meta_count); // Delete all the data up to our current index. - assert(meta_consumed > 0); - self.data.deleteOldest(meta_consumed); + assert(tl_meta_consumed > 0); + self.data.deleteOldest(tl_meta_consumed); } self.assertIntegrity(); @@ -485,6 +491,53 @@ test "SlidingWindow two pages" { try testing.expect(w.next(needle) == null); } +test "SlidingWindow two pages match across boundary" { + const testing = std.testing; + const alloc = testing.allocator; + + var w = try SlidingWindow.initEmpty(alloc); + defer w.deinit(alloc); + + var s = try Screen.init(alloc, 80, 24, 1000); + defer s.deinit(); + + // Fill up the first page. The final bytes in the first page + // are "boo!" + const first_page_rows = s.pages.pages.first.?.data.capacity.rows; + for (0..first_page_rows - 1) |_| try s.testWriteString("\n"); + for (0..s.pages.cols - 4) |_| try s.testWriteString("x"); + try s.testWriteString("hell"); + try testing.expect(s.pages.pages.first == s.pages.pages.last); + try s.testWriteString("o, world!"); + try testing.expect(s.pages.pages.first != s.pages.pages.last); + + // Imaginary needle for search + const needle = "hello, world"; + + // Add both pages + const node: *PageList.List.Node = s.pages.pages.first.?; + try w.append(alloc, node); + try w.append(alloc, node.next.?); + + // Search should find a match + { + const sel = w.next(needle).?; + try testing.expectEqual(point.Point{ .active = .{ + .x = 76, + .y = 22, + } }, s.pages.pointFromPin(.active, sel.start()).?); + try testing.expectEqual(point.Point{ .active = .{ + .x = 7, + .y = 23, + } }, s.pages.pointFromPin(.active, sel.end()).?); + } + try testing.expect(w.next(needle) == null); + try testing.expect(w.next(needle) == null); + + // We shouldn't prune because we don't have enough space + try testing.expectEqual(2, w.meta.len()); +} + test "SlidingWindow two pages no match prunes first page" { const testing = std.testing; const alloc = testing.allocator; From 852e04fa009eca31727762f2d72d2fec4fcea273 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 4 Dec 2024 10:58:22 -0800 Subject: [PATCH 17/32] terminal: test for match in second slice of circ buf --- src/terminal/search.zig | 73 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 7 deletions(-) diff --git a/src/terminal/search.zig b/src/terminal/search.zig index 88da8304d..7b6486429 100644 --- a/src/terminal/search.zig +++ b/src/terminal/search.zig @@ -118,12 +118,16 @@ const SlidingWindow = struct { /// the invariant that the window is always big enough to contain /// the needle. pub fn next(self: *SlidingWindow, needle: []const u8) ?Selection { - const data_len = self.data.len(); - if (data_len == 0) return null; - const slices = self.data.getPtrSlice( - self.data_offset, - data_len - self.data_offset, - ); + const slices = slices: { + // If we have less data then the needle then we can't possibly match + const data_len = self.data.len(); + if (data_len < needle.len) return null; + + break :slices self.data.getPtrSlice( + self.data_offset, + data_len - self.data_offset, + ); + }; // Search the first slice for the needle. if (std.mem.indexOf(u8, slices[0], needle)) |idx| { @@ -134,7 +138,6 @@ const SlidingWindow = struct { // Search the last slice for the needle. if (std.mem.indexOf(u8, slices[1], needle)) |idx| { - if (true) @panic("TODO: test"); return self.selection(slices[0].len + idx, needle.len); } @@ -182,6 +185,10 @@ const SlidingWindow = struct { self.data.deleteOldest(prune_data_len); } + // Our data offset now moves to needle.len - 1 from the end so + // that we can handle the overlap case. + self.data_offset = self.data.len() - needle.len + 1; + self.assertIntegrity(); return null; } @@ -615,3 +622,55 @@ test "SlidingWindow two pages no match keeps both pages" { // No pruning because both pages are needed to fit needle. try testing.expectEqual(2, w.meta.len()); } + +test "SlidingWindow single append across circular buffer boundary" { + const testing = std.testing; + const alloc = testing.allocator; + + var w = try SlidingWindow.initEmpty(alloc); + defer w.deinit(alloc); + + var s = try Screen.init(alloc, 80, 24, 0); + defer s.deinit(); + try s.testWriteString("XXXXXXXXXXXXXXXXXXXboo!XXXXX"); + + // We are trying to break a circular buffer boundary so the way we + // do this is to duplicate the data then do a failing search. This + // will cause the first page to be pruned. The next time we append we'll + // put it in the middle of the circ buffer. We assert this so that if + // our implementation changes our test will fail. + try testing.expect(s.pages.pages.first == s.pages.pages.last); + const node: *PageList.List.Node = s.pages.pages.first.?; + try w.append(alloc, node); + try w.append(alloc, node); + { + // No wrap around yet + const slices = w.data.getPtrSlice(0, w.data.len()); + try testing.expect(slices[0].len > 0); + try testing.expect(slices[1].len == 0); + } + + // Search non-match, prunes page + try testing.expect(w.next("abc") == null); + try testing.expectEqual(1, w.meta.len()); + + // Add new page, now wraps + try w.append(alloc, node); + { + const slices = w.data.getPtrSlice(0, w.data.len()); + try testing.expect(slices[0].len > 0); + try testing.expect(slices[1].len > 0); + } + { + const sel = w.next("boo!").?; + try testing.expectEqual(point.Point{ .active = .{ + .x = 19, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.start()).?); + try testing.expectEqual(point.Point{ .active = .{ + .x = 22, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.end()).?); + } + try testing.expect(w.next("boo!") == null); +} From 34fb840cf99fdfdd970557df8b8accbbc156b3ce Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 4 Dec 2024 11:16:36 -0800 Subject: [PATCH 18/32] terminal: search match on overlap case --- src/terminal/search.zig | 215 ++++++++++++++++++++++++++++------------ 1 file changed, 153 insertions(+), 62 deletions(-) diff --git a/src/terminal/search.zig b/src/terminal/search.zig index 7b6486429..304cc5a4e 100644 --- a/src/terminal/search.zig +++ b/src/terminal/search.zig @@ -72,6 +72,14 @@ const SlidingWindow = struct { /// do enough to prune it. data_offset: usize = 0, + /// The needle we're searching for. Does not own the memory. + needle: []const u8, + + /// A buffer to store the overlap search data. This is used to search + /// overlaps between pages where the match starts on one page and + /// ends on another. The length is always `needle.len * 2`. + overlap_buf: []u8, + const DataBuf = CircBuf(u8, 0); const MetaBuf = CircBuf(Meta, undefined); const Meta = struct { @@ -83,20 +91,29 @@ const SlidingWindow = struct { } }; - pub fn initEmpty(alloc: Allocator) Allocator.Error!SlidingWindow { + pub fn init( + alloc: Allocator, + needle: []const u8, + ) Allocator.Error!SlidingWindow { var data = try DataBuf.init(alloc, 0); errdefer data.deinit(alloc); var meta = try MetaBuf.init(alloc, 0); errdefer meta.deinit(alloc); + const overlap_buf = try alloc.alloc(u8, needle.len * 2); + errdefer alloc.free(overlap_buf); + return .{ .data = data, .meta = meta, + .needle = needle, + .overlap_buf = overlap_buf, }; } pub fn deinit(self: *SlidingWindow, alloc: Allocator) void { + alloc.free(self.overlap_buf); self.data.deinit(alloc); var meta_it = self.meta.iterator(.forward); @@ -117,11 +134,11 @@ const SlidingWindow = struct { /// the window moves, the window will prune itself while maintaining /// the invariant that the window is always big enough to contain /// the needle. - pub fn next(self: *SlidingWindow, needle: []const u8) ?Selection { + pub fn next(self: *SlidingWindow) ?Selection { const slices = slices: { // If we have less data then the needle then we can't possibly match const data_len = self.data.len(); - if (data_len < needle.len) return null; + if (data_len < self.needle.len) return null; break :slices self.data.getPtrSlice( self.data_offset, @@ -130,15 +147,46 @@ const SlidingWindow = struct { }; // Search the first slice for the needle. - if (std.mem.indexOf(u8, slices[0], needle)) |idx| { - return self.selection(idx, needle.len); + if (std.mem.indexOf(u8, slices[0], self.needle)) |idx| { + return self.selection(idx, self.needle.len); } - // TODO: search overlap + // Search the overlap buffer for the needle. + if (slices[0].len > 0 and slices[1].len > 0) overlap: { + // Get up to needle.len - 1 bytes from each side (as much as + // we can) and store it in the overlap buffer. + const prefix: []const u8 = prefix: { + const len = @min(slices[0].len, self.needle.len - 1); + const idx = slices[0].len - len; + break :prefix slices[0][idx..]; + }; + const suffix: []const u8 = suffix: { + const len = @min(slices[1].len, self.needle.len - 1); + break :suffix slices[1][0..len]; + }; + const overlap_len = prefix.len + suffix.len; + assert(overlap_len <= self.overlap_buf.len); + @memcpy(self.overlap_buf[0..prefix.len], prefix); + @memcpy(self.overlap_buf[prefix.len..overlap_len], suffix); + + // Search the overlap + const idx = std.mem.indexOf( + u8, + self.overlap_buf[0..overlap_len], + self.needle, + ) orelse break :overlap; + + // We found a match in the overlap buffer. We need to map the + // index back to the data buffer in order to get our selection. + return self.selection( + slices[0].len - prefix.len + idx, + self.needle.len, + ); + } // Search the last slice for the needle. - if (std.mem.indexOf(u8, slices[1], needle)) |idx| { - return self.selection(slices[0].len + idx, needle.len); + if (std.mem.indexOf(u8, slices[1], self.needle)) |idx| { + return self.selection(slices[0].len + idx, self.needle.len); } // No match. We keep `needle.len - 1` bytes available to @@ -147,7 +195,7 @@ const SlidingWindow = struct { prune: { var saved: usize = 0; while (meta_it.next()) |meta| { - const needed = needle.len - 1 - saved; + const needed = self.needle.len - 1 - saved; if (meta.cell_map.items.len >= needed) { // We save up to this meta. We set our data offset // to exactly where it needs to be to continue @@ -161,7 +209,7 @@ const SlidingWindow = struct { // If we exited the while loop naturally then we // never got the amount we needed and so there is // nothing to prune. - assert(saved < needle.len - 1); + assert(saved < self.needle.len - 1); break :prune; } @@ -187,7 +235,7 @@ const SlidingWindow = struct { // Our data offset now moves to needle.len - 1 from the end so // that we can handle the overlap case. - self.data_offset = self.data.len() - needle.len + 1; + self.data_offset = self.data.len() - self.needle.len + 1; self.assertIntegrity(); return null; @@ -363,7 +411,7 @@ test "SlidingWindow empty on init" { const testing = std.testing; const alloc = testing.allocator; - var w = try SlidingWindow.initEmpty(alloc); + var w = try SlidingWindow.init(alloc, "boo!"); defer w.deinit(alloc); try testing.expectEqual(0, w.data.len()); try testing.expectEqual(0, w.meta.len()); @@ -373,16 +421,13 @@ test "SlidingWindow single append" { const testing = std.testing; const alloc = testing.allocator; - var w = try SlidingWindow.initEmpty(alloc); + var w = try SlidingWindow.init(alloc, "boo!"); defer w.deinit(alloc); var s = try Screen.init(alloc, 80, 24, 0); defer s.deinit(); try s.testWriteString("hello. boo! hello. boo!"); - // Imaginary needle for search - const needle = "boo!"; - // We want to test single-page cases. try testing.expect(s.pages.pages.first == s.pages.pages.last); const node: *PageList.List.Node = s.pages.pages.first.?; @@ -390,7 +435,7 @@ test "SlidingWindow single append" { // We should be able to find two matches. { - const sel = w.next(needle).?; + const sel = w.next().?; try testing.expectEqual(point.Point{ .active = .{ .x = 7, .y = 0, @@ -401,7 +446,7 @@ test "SlidingWindow single append" { } }, s.pages.pointFromPin(.active, sel.end()).?); } { - const sel = w.next(needle).?; + const sel = w.next().?; try testing.expectEqual(point.Point{ .active = .{ .x = 19, .y = 0, @@ -411,32 +456,29 @@ test "SlidingWindow single append" { .y = 0, } }, s.pages.pointFromPin(.active, sel.end()).?); } - try testing.expect(w.next(needle) == null); - try testing.expect(w.next(needle) == null); + try testing.expect(w.next() == null); + try testing.expect(w.next() == null); } test "SlidingWindow single append no match" { const testing = std.testing; const alloc = testing.allocator; - var w = try SlidingWindow.initEmpty(alloc); + var w = try SlidingWindow.init(alloc, "nope!"); defer w.deinit(alloc); var s = try Screen.init(alloc, 80, 24, 0); defer s.deinit(); try s.testWriteString("hello. boo! hello. boo!"); - // Imaginary needle for search - const needle = "nope!"; - // We want to test single-page cases. try testing.expect(s.pages.pages.first == s.pages.pages.last); const node: *PageList.List.Node = s.pages.pages.first.?; try w.append(alloc, node); // No matches - try testing.expect(w.next(needle) == null); - try testing.expect(w.next(needle) == null); + try testing.expect(w.next() == null); + try testing.expect(w.next() == null); // Should still keep the page try testing.expectEqual(1, w.meta.len()); @@ -446,7 +488,7 @@ test "SlidingWindow two pages" { const testing = std.testing; const alloc = testing.allocator; - var w = try SlidingWindow.initEmpty(alloc); + var w = try SlidingWindow.init(alloc, "boo!"); defer w.deinit(alloc); var s = try Screen.init(alloc, 80, 24, 1000); @@ -463,9 +505,6 @@ test "SlidingWindow two pages" { try testing.expect(s.pages.pages.first != s.pages.pages.last); try s.testWriteString("hello. boo!"); - // Imaginary needle for search - const needle = "boo!"; - // Add both pages const node: *PageList.List.Node = s.pages.pages.first.?; try w.append(alloc, node); @@ -473,7 +512,7 @@ test "SlidingWindow two pages" { // Search should find two matches { - const sel = w.next(needle).?; + const sel = w.next().?; try testing.expectEqual(point.Point{ .active = .{ .x = 76, .y = 22, @@ -484,7 +523,7 @@ test "SlidingWindow two pages" { } }, s.pages.pointFromPin(.active, sel.end()).?); } { - const sel = w.next(needle).?; + const sel = w.next().?; try testing.expectEqual(point.Point{ .active = .{ .x = 7, .y = 23, @@ -494,15 +533,15 @@ test "SlidingWindow two pages" { .y = 23, } }, s.pages.pointFromPin(.active, sel.end()).?); } - try testing.expect(w.next(needle) == null); - try testing.expect(w.next(needle) == null); + try testing.expect(w.next() == null); + try testing.expect(w.next() == null); } test "SlidingWindow two pages match across boundary" { const testing = std.testing; const alloc = testing.allocator; - var w = try SlidingWindow.initEmpty(alloc); + var w = try SlidingWindow.init(alloc, "hello, world"); defer w.deinit(alloc); var s = try Screen.init(alloc, 80, 24, 1000); @@ -518,9 +557,6 @@ test "SlidingWindow two pages match across boundary" { try s.testWriteString("o, world!"); try testing.expect(s.pages.pages.first != s.pages.pages.last); - // Imaginary needle for search - const needle = "hello, world"; - // Add both pages const node: *PageList.List.Node = s.pages.pages.first.?; try w.append(alloc, node); @@ -528,7 +564,7 @@ test "SlidingWindow two pages match across boundary" { // Search should find a match { - const sel = w.next(needle).?; + const sel = w.next().?; try testing.expectEqual(point.Point{ .active = .{ .x = 76, .y = 22, @@ -538,8 +574,8 @@ test "SlidingWindow two pages match across boundary" { .y = 23, } }, s.pages.pointFromPin(.active, sel.end()).?); } - try testing.expect(w.next(needle) == null); - try testing.expect(w.next(needle) == null); + try testing.expect(w.next() == null); + try testing.expect(w.next() == null); // We shouldn't prune because we don't have enough space try testing.expectEqual(2, w.meta.len()); @@ -549,7 +585,7 @@ test "SlidingWindow two pages no match prunes first page" { const testing = std.testing; const alloc = testing.allocator; - var w = try SlidingWindow.initEmpty(alloc); + var w = try SlidingWindow.init(alloc, "nope!"); defer w.deinit(alloc); var s = try Screen.init(alloc, 80, 24, 1000); @@ -571,12 +607,9 @@ test "SlidingWindow two pages no match prunes first page" { try w.append(alloc, node); try w.append(alloc, node.next.?); - // Imaginary needle for search. Doesn't match! - const needle = "nope!"; - // Search should find nothing - try testing.expect(w.next(needle) == null); - try testing.expect(w.next(needle) == null); + try testing.expect(w.next() == null); + try testing.expect(w.next() == null); // We should've pruned our page because the second page // has enough text to contain our needle. @@ -587,9 +620,6 @@ test "SlidingWindow two pages no match keeps both pages" { const testing = std.testing; const alloc = testing.allocator; - var w = try SlidingWindow.initEmpty(alloc); - defer w.deinit(alloc); - var s = try Screen.init(alloc, 80, 24, 1000); defer s.deinit(); @@ -604,20 +634,23 @@ test "SlidingWindow two pages no match keeps both pages" { try testing.expect(s.pages.pages.first != s.pages.pages.last); try s.testWriteString("hello. boo!"); - // Add both pages - const node: *PageList.List.Node = s.pages.pages.first.?; - try w.append(alloc, node); - try w.append(alloc, node.next.?); - // Imaginary needle for search. Doesn't match! var needle_list = std.ArrayList(u8).init(alloc); defer needle_list.deinit(); try needle_list.appendNTimes('x', first_page_rows * s.pages.cols); const needle: []const u8 = needle_list.items; + var w = try SlidingWindow.init(alloc, needle); + defer w.deinit(alloc); + + // Add both pages + const node: *PageList.List.Node = s.pages.pages.first.?; + try w.append(alloc, node); + try w.append(alloc, node.next.?); + // Search should find nothing - try testing.expect(w.next(needle) == null); - try testing.expect(w.next(needle) == null); + try testing.expect(w.next() == null); + try testing.expect(w.next() == null); // No pruning because both pages are needed to fit needle. try testing.expectEqual(2, w.meta.len()); @@ -627,7 +660,7 @@ test "SlidingWindow single append across circular buffer boundary" { const testing = std.testing; const alloc = testing.allocator; - var w = try SlidingWindow.initEmpty(alloc); + var w = try SlidingWindow.init(alloc, "abc"); defer w.deinit(alloc); var s = try Screen.init(alloc, 80, 24, 0); @@ -651,9 +684,12 @@ test "SlidingWindow single append across circular buffer boundary" { } // Search non-match, prunes page - try testing.expect(w.next("abc") == null); + try testing.expect(w.next() == null); try testing.expectEqual(1, w.meta.len()); + // Change the needle, just needs to be the same length (not a real API) + w.needle = "boo"; + // Add new page, now wraps try w.append(alloc, node); { @@ -662,15 +698,70 @@ test "SlidingWindow single append across circular buffer boundary" { try testing.expect(slices[1].len > 0); } { - const sel = w.next("boo!").?; + const sel = w.next().?; try testing.expectEqual(point.Point{ .active = .{ .x = 19, .y = 0, } }, s.pages.pointFromPin(.active, sel.start()).?); try testing.expectEqual(point.Point{ .active = .{ - .x = 22, + .x = 21, .y = 0, } }, s.pages.pointFromPin(.active, sel.end()).?); } - try testing.expect(w.next("boo!") == null); + try testing.expect(w.next() == null); +} + +test "SlidingWindow single append match on boundary" { + const testing = std.testing; + const alloc = testing.allocator; + + var w = try SlidingWindow.init(alloc, "abcd"); + defer w.deinit(alloc); + + var s = try Screen.init(alloc, 80, 24, 0); + defer s.deinit(); + try s.testWriteString("o!XXXXXXXXXXXXXXXXXXXbo"); + + // We are trying to break a circular buffer boundary so the way we + // do this is to duplicate the data then do a failing search. This + // will cause the first page to be pruned. The next time we append we'll + // put it in the middle of the circ buffer. We assert this so that if + // our implementation changes our test will fail. + try testing.expect(s.pages.pages.first == s.pages.pages.last); + const node: *PageList.List.Node = s.pages.pages.first.?; + try w.append(alloc, node); + try w.append(alloc, node); + { + // No wrap around yet + const slices = w.data.getPtrSlice(0, w.data.len()); + try testing.expect(slices[0].len > 0); + try testing.expect(slices[1].len == 0); + } + + // Search non-match, prunes page + try testing.expect(w.next() == null); + try testing.expectEqual(1, w.meta.len()); + + // Change the needle, just needs to be the same length (not a real API) + w.needle = "boo!"; + + // Add new page, now wraps + try w.append(alloc, node); + { + const slices = w.data.getPtrSlice(0, w.data.len()); + try testing.expect(slices[0].len > 0); + try testing.expect(slices[1].len > 0); + } + { + const sel = w.next().?; + try testing.expectEqual(point.Point{ .active = .{ + .x = 21, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.start()).?); + try testing.expectEqual(point.Point{ .active = .{ + .x = 1, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.end()).?); + } + try testing.expect(w.next() == null); } From 6361bf47f7f8fda0993a15046829e8d42b085419 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 4 Dec 2024 11:23:09 -0800 Subject: [PATCH 19/32] terminal: update comments/docs on sliding window search --- src/terminal/search.zig | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/terminal/search.zig b/src/terminal/search.zig index 304cc5a4e..09078ae28 100644 --- a/src/terminal/search.zig +++ b/src/terminal/search.zig @@ -53,9 +53,22 @@ pub const PageListSearch = struct { } }; -/// Search pages via a sliding window. The sliding window always maintains -/// the invariant that data isn't pruned until we've searched it and -/// accounted for overlaps across pages. +/// Searches page nodes via a sliding window. The sliding window maintains +/// the invariant that data isn't pruned until (1) we've searched it and +/// (2) we've accounted for overlaps across pages to fit the needle. +/// +/// The sliding window is first initialized empty. Pages are then appended +/// in the order to search them. If you're doing a reverse search then the +/// pages should be appended in reverse order and the needle should be +/// reversed. +/// +/// All appends grow the window. The window is only pruned when a searc +/// is done (positive or negative match) via `next()`. +/// +/// To avoid unnecessary memory growth, the recommended usage is to +/// call `next()` until it returns null and then `append` the next page +/// and repeat the process. This will always maintain the minimum +/// required memory to search for the needle. const SlidingWindow = struct { /// The data buffer is a circular buffer of u8 that contains the /// encoded page text that we can use to search for the needle. From b9dda6ad87fff1ec01699a0b12ad28cbbe51b856 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 4 Dec 2024 12:15:32 -0800 Subject: [PATCH 20/32] terminal: PageListSearch works! --- src/terminal/search.zig | 101 +++++++++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 22 deletions(-) diff --git a/src/terminal/search.zig b/src/terminal/search.zig index 09078ae28..fe5ac0c29 100644 --- a/src/terminal/search.zig +++ b/src/terminal/search.zig @@ -10,46 +10,64 @@ const Pin = PageList.Pin; const Selection = terminal.Selection; const Screen = terminal.Screen; +/// Searches for a term in a PageList structure. pub const PageListSearch = struct { - alloc: Allocator, - /// The list we're searching. list: *PageList, - /// The search term we're searching for. - needle: []const u8, - - /// The window is our sliding window of pages that we're searching so - /// we can handle boundary cases where a needle is partially on the end - /// of one page and the beginning of the next. - /// - /// Note that we're not guaranteed to straddle exactly two pages. If - /// the needle is large enough and/or the pages are small enough then - /// the needle can straddle N pages. Additionally, pages aren't guaranteed - /// to be equal size so we can't precompute the window size. + /// The sliding window of page contents and nodes to search. window: SlidingWindow, + /// Initialize the page list search. + /// + /// The needle is not copied and must be kept alive for the duration + /// of the search operation. pub fn init( alloc: Allocator, list: *PageList, needle: []const u8, - ) !PageListSearch { - var window = try CircBuf.init(alloc, 0); - errdefer window.deinit(); + ) Allocator.Error!PageListSearch { + var window = try SlidingWindow.init(alloc, needle); + errdefer window.deinit(alloc); return .{ - .alloc = alloc, .list = list, - .current = list.pages.first, - .needle = needle, .window = window, }; } - pub fn deinit(self: *PageListSearch) void { - _ = self; + pub fn deinit(self: *PageListSearch, alloc: Allocator) void { + self.window.deinit(alloc); + } - // TODO: deinit window + /// Find the next match for the needle in the pagelist. This returns + /// null when there are no more matches. + pub fn next( + self: *PageListSearch, + alloc: Allocator, + ) Allocator.Error!?Selection { + // Try to search for the needle in the window. If we find a match + // then we can return that and we're done. + if (self.window.next()) |sel| return sel; + + // Get our next node. If we have a value in our window then we + // can determine the next node. If we don't, we've never setup the + // window so we use our first node. + var node_: ?*PageList.List.Node = if (self.window.meta.last()) |meta| + meta.node.next + else + self.list.pages.first; + + // Add one pagelist node at a time, look for matches, and repeat + // until we find a match or we reach the end of the pagelist. + // This append then next pattern limits memory usage of the window. + while (node_) |node| : (node_ = node.next) { + try self.window.append(alloc, node); + if (self.window.next()) |sel| return sel; + } + + // We've reached the end of the pagelist, no matches. + return null; } }; @@ -420,6 +438,45 @@ const SlidingWindow = struct { } }; +test "PageListSearch single page" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try Screen.init(alloc, 80, 24, 0); + defer s.deinit(); + try s.testWriteString("hello. boo! hello. boo!"); + try testing.expect(s.pages.pages.first == s.pages.pages.last); + + var search = try PageListSearch.init(alloc, &s.pages, "boo!"); + defer search.deinit(alloc); + + // We should be able to find two matches. + { + const sel = (try search.next(alloc)).?; + try testing.expectEqual(point.Point{ .active = .{ + .x = 7, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.start()).?); + try testing.expectEqual(point.Point{ .active = .{ + .x = 10, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.end()).?); + } + { + const sel = (try search.next(alloc)).?; + try testing.expectEqual(point.Point{ .active = .{ + .x = 19, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.start()).?); + try testing.expectEqual(point.Point{ .active = .{ + .x = 22, + .y = 0, + } }, s.pages.pointFromPin(.active, sel.end()).?); + } + try testing.expect((try search.next(alloc)) == null); + try testing.expect((try search.next(alloc)) == null); +} + test "SlidingWindow empty on init" { const testing = std.testing; const alloc = testing.allocator; From 50b36c5d8606a4fd0be5fafd4e641751f2625861 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 4 Dec 2024 12:38:29 -0800 Subject: [PATCH 21/32] comments --- src/terminal/search.zig | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/terminal/search.zig b/src/terminal/search.zig index fe5ac0c29..56b181c48 100644 --- a/src/terminal/search.zig +++ b/src/terminal/search.zig @@ -1,3 +1,26 @@ +//! Search functionality for the terminal. +//! +//! At the time of writing this comment, this is a **work in progress**. +//! +//! Search at the time of writing is implemented using a simple +//! boyer-moore-horspool algorithm. The suboptimal part of the implementation +//! is that we need to encode each terminal page into a text buffer in order +//! to apply BMH to it. This is because the terminal page is not laid out +//! in a flat text form. +//! +//! To minimize memory usage, we use a sliding window to search for the +//! needle. The sliding window only keeps the minimum amount of page data +//! in memory to search for a needle (i.e. `needle.len - 1` bytes of overlap +//! between terminal pages). +//! +//! Future work: +//! +//! - PageListSearch on a PageList concurrently with another thread +//! - Handle pruned pages in a PageList to ensure we don't keep references +//! - Repeat search a changing active area of the screen +//! - Reverse search so that more recent matches are found first +//! + const std = @import("std"); const Allocator = std.mem.Allocator; const assert = std.debug.assert; @@ -11,6 +34,10 @@ const Selection = terminal.Selection; const Screen = terminal.Screen; /// Searches for a term in a PageList structure. +/// +/// At the time of writing, this does not support searching a pagelist +/// simultaneously as its being used by another thread. This will be resolved +/// in the future. pub const PageListSearch = struct { /// The list we're searching. list: *PageList, From 7dd8e7c43f4c1da2a310dbd5d9c96c3a9de1d6e4 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 4 Dec 2024 12:48:00 -0800 Subject: [PATCH 22/32] remove unused file --- ' | 555 -------------------------------------------------------------- 1 file changed, 555 deletions(-) delete mode 100644 ' diff --git a/' b/' deleted file mode 100644 index 0b79f1879..000000000 --- a/' +++ /dev/null @@ -1,555 +0,0 @@ -const std = @import("std"); -const Allocator = std.mem.Allocator; -const assert = std.debug.assert; -const CircBuf = @import("../datastruct/main.zig").CircBuf; -const terminal = @import("main.zig"); -const point = terminal.point; -const Page = terminal.Page; -const PageList = terminal.PageList; -const Pin = PageList.Pin; -const Selection = terminal.Selection; -const Screen = terminal.Screen; - -pub const PageListSearch = struct { - alloc: Allocator, - - /// The list we're searching. - list: *PageList, - - /// The search term we're searching for. - needle: []const u8, - - /// The window is our sliding window of pages that we're searching so - /// we can handle boundary cases where a needle is partially on the end - /// of one page and the beginning of the next. - /// - /// Note that we're not guaranteed to straddle exactly two pages. If - /// the needle is large enough and/or the pages are small enough then - /// the needle can straddle N pages. Additionally, pages aren't guaranteed - /// to be equal size so we can't precompute the window size. - window: SlidingWindow, - - pub fn init( - alloc: Allocator, - list: *PageList, - needle: []const u8, - ) !PageListSearch { - var window = try CircBuf.init(alloc, 0); - errdefer window.deinit(); - - return .{ - .alloc = alloc, - .list = list, - .current = list.pages.first, - .needle = needle, - .window = window, - }; - } - - pub fn deinit(self: *PageListSearch) void { - _ = self; - - // TODO: deinit window - } -}; - -/// The sliding window of the pages we're searching. The window is always -/// big enough so that the needle can fit in it. -const SlidingWindow = struct { - /// The data buffer is a circular buffer of u8 that contains the - /// encoded page text that we can use to search for the needle. - data: DataBuf, - - /// The meta buffer is a circular buffer that contains the metadata - /// about the pages we're searching. This usually isn't that large - /// so callers must iterate through it to find the offset to map - /// data to meta. - meta: MetaBuf, - - /// The cursor into the data buffer for our current search. - i: usize = 0, - - const DataBuf = CircBuf(u8, 0); - const MetaBuf = CircBuf(Meta, undefined); - const Meta = struct { - node: *PageList.List.Node, - cell_map: Page.CellMap, - - pub fn deinit(self: *Meta) void { - self.cell_map.deinit(); - } - }; - - pub fn initEmpty(alloc: Allocator) Allocator.Error!SlidingWindow { - var data = try DataBuf.init(alloc, 0); - errdefer data.deinit(alloc); - - var meta = try MetaBuf.init(alloc, 0); - errdefer meta.deinit(alloc); - - return .{ - .data = data, - .meta = meta, - }; - } - - pub fn deinit(self: *SlidingWindow, alloc: Allocator) void { - self.data.deinit(alloc); - - var meta_it = self.meta.iterator(.forward); - while (meta_it.next()) |meta| meta.deinit(); - self.meta.deinit(alloc); - } - - /// Search the window for the next occurrence of the needle. - pub fn next(self: *SlidingWindow, needle: []const u8) void { - const slices = self.data.getPtrSlice(0, self.data.len()); - - // Search the first slice for the needle. - if (std.mem.indexOf(u8, slices[0][self.i..], needle)) |idx| { - // Found, map the match to a selection. - var meta_it = self.meta.iterator(.forward); - var i: usize = 0; - while (meta_it.next()) |meta| { - const meta_idx = idx - i; - if (meta.cell_map.items.len < meta_idx) { - // This meta doesn't contain the match. - i += meta.cell_map.items.len; - continue; - } - - // We found the meta that contains the start of the match. - const tl: PageList.Pin = tl: { - const map = meta.cell_map.items[meta_idx]; - break :tl .{ - .node = meta.node, - .y = map.y, - .x = map.x, - }; - }; - - _ = tl; - } - - // Found, we can move our index to the next character - // after the match. This let's us find all matches even if - // they overlap. - - self.i = idx + 1; - - @panic("TODO"); - } - } - - /// Return a selection for the given start and length into the data - /// buffer and also prune the data/meta buffers if possible up to - /// this start index. - fn selectAndPrune( - self: *SlidingWindow, - start: usize, - len: usize, - ) Selection { - assert(start < self.data.len()); - assert(start + len < self.data.len()); - - var meta_it = self.meta.iterator(.forward); - var meta_: ?Meta = meta_it.next(); - - // Find the start of the match - var offset: usize = 0; - var skip_nodes: usize = 0; - const tl: PageList.Pin = tl: { - while (meta_) |meta| : (meta_ = meta_it.next()) { - // meta_i is the index we expect to find the match in the - // cell map within this meta if it contains it. - const meta_i = start - offset; - if (meta_i >= meta.cell_map.items.len) { - // This meta doesn't contain the match. This means we - // can also prune this set of data because we only look - // forward. - offset += meta.cell_map.items.len; - skip_nodes += 1; - continue; - } - - // We found the meta that contains the start of the match. - const map = meta.cell_map.items[start]; - break :tl .{ - .node = meta.node, - .y = map.y, - .x = map.x, - }; - } - - // We never found the top-left. This is unreachable because - // we assert that the start index is within the data buffer, - // and when building the data buffer we assert the cell map - // length exactly matches the data buffer length. - unreachable; - }; - - // Keep track of the number of nodes we skipped for the tl. - const tl_skip_nodes = skip_nodes; - skip_nodes = 0; - - // Find the end of the match - const br: PageList.Pin = br: { - const end_idx = start + len - 1; - while (meta_) |meta| : (meta_ = meta_it.next()) { - const meta_i = end_idx - offset; - if (meta_i >= meta.cell_map.items.len) { - offset += meta.cell_map.items.len; - skip_nodes += 1; - continue; - } - - // We found the meta that contains the start of the match. - const map = meta.cell_map.items[end_idx]; - break :br .{ - .node = meta.node, - .y = map.y, - .x = map.x, - }; - } - }; - - // If we skipped any nodes for the bottom-right then we can prune - // all the way up to the total. If we didn't, it means we found - // the bottom-right in the same node as the top-left and we can't - // prune the node that the match is on because there may be - // more matches. - if (skip_nodes > 0) skip_nodes += tl_skip_nodes; - - _ = tl; - _ = br; - } - - /// Convert a data index into a pin. - fn pin( - self: *const SlidingWindow, - idx: usize, - it: ?*MetaBuf.Iterator, - ) struct { - /// The pin for the data index. - pin: Pin, - - /// The offset into the meta buffer that the pin was found. - /// This can be used to prune the meta buffer (its safe to prune - /// before this i). - meta_i: usize, - } { - _ = self; - _ = idx; - _ = start; - - while (it.next()) |meta| { - // meta_i is the index we expect to find the match in the - // cell map within this meta if it contains it. - const meta_i = start - offset; - if (meta_i >= meta.cell_map.items.len) { - // This meta doesn't contain the match. This means we - // can also prune this set of data because we only look - // forward. - offset += meta.cell_map.items.len; - skip_nodes += 1; - continue; - } - - // We found the meta that contains the start of the match. - const map = meta.cell_map.items[start]; - break :tl .{ - .node = meta.node, - .y = map.y, - .x = map.x, - }; - } - - } - - /// Add a new node to the sliding window. - /// - /// The window will prune itself if it can while always maintaining - /// the invariant that the `fixed_size` always fits within the window. - /// - /// Note it is possible for the window to be smaller than `fixed_size` - /// if not enough nodes have been added yet or the screen is just - /// smaller than the needle. - pub fn append( - self: *SlidingWindow, - alloc: Allocator, - node: *PageList.List.Node, - required_size: usize, - ) Allocator.Error!void { - // Initialize our metadata for the node. - var meta: Meta = .{ - .node = node, - .cell_map = Page.CellMap.init(alloc), - }; - errdefer meta.deinit(); - - // This is suboptimal but we need to encode the page once to - // temporary memory, and then copy it into our circular buffer. - // In the future, we should benchmark and see if we can encode - // directly into the circular buffer. - var encoded: std.ArrayListUnmanaged(u8) = .{}; - defer encoded.deinit(alloc); - - // Encode the page into the buffer. - const page: *const Page = &meta.node.data; - _ = page.encodeUtf8( - encoded.writer(alloc), - .{ .cell_map = &meta.cell_map }, - ) catch { - // writer uses anyerror but the only realistic error on - // an ArrayList is out of memory. - return error.OutOfMemory; - }; - assert(meta.cell_map.items.len == encoded.items.len); - - // Now that we know our buffer length, we can consider if we can - // prune our circular buffer or if we need to grow it. - prune: { - // Our buffer size after adding the new node. - const before_size: usize = self.data.len() + encoded.items.len; - - // Prune as long as removing the first (oldest) node retains - // our required size invariant. - var after_size: usize = before_size; - while (self.meta.first()) |oldest_meta| { - const new_size = after_size - oldest_meta.cell_map.items.len; - if (new_size < required_size) break :prune; - - // We can prune this node and retain our invariant. - // Update our new size, deinitialize the memory, and - // remove from the circular buffer. - after_size = new_size; - oldest_meta.deinit(); - self.meta.deleteOldest(1); - } - assert(after_size <= before_size); - - // If we didn't prune anything then we're done. - if (after_size == before_size) break :prune; - - // We need to prune our data buffer as well. - self.data.deleteOldest(before_size - after_size); - } - - // Ensure our buffers are big enough to store what we need. - try self.data.ensureUnusedCapacity(alloc, encoded.items.len); - try self.meta.ensureUnusedCapacity(alloc, 1); - - // Append our new node to the circular buffer. - try self.data.appendSlice(encoded.items); - try self.meta.append(meta); - - // Integrity check: verify our data matches our metadata exactly. - if (comptime std.debug.runtime_safety) { - var meta_it = self.meta.iterator(.forward); - var data_len: usize = 0; - while (meta_it.next()) |m| data_len += m.cell_map.items.len; - assert(data_len == self.data.len()); - } - } -}; - -test "SlidingWindow empty on init" { - const testing = std.testing; - const alloc = testing.allocator; - - var w = try SlidingWindow.initEmpty(alloc); - defer w.deinit(alloc); - try testing.expectEqual(0, w.data.len()); - try testing.expectEqual(0, w.meta.len()); -} - -test "SlidingWindow single append" { - const testing = std.testing; - const alloc = testing.allocator; - - var w = try SlidingWindow.initEmpty(alloc); - defer w.deinit(alloc); - - var s = try Screen.init(alloc, 80, 24, 0); - defer s.deinit(); - try s.testWriteString("hello. boo! hello. boo!"); - - // Imaginary needle for search - const needle = "boo!"; - - // We want to test single-page cases. - try testing.expect(s.pages.pages.first == s.pages.pages.last); - const node: *PageList.List.Node = s.pages.pages.first.?; - try w.append(alloc, node, needle.len); -} - -test "SlidingWindow two pages" { - const testing = std.testing; - const alloc = testing.allocator; - - var w = try SlidingWindow.initEmpty(alloc); - defer w.deinit(alloc); - - var s = try Screen.init(alloc, 80, 24, 1000); - defer s.deinit(); - - // Fill up the first page. The final bytes in the first page - // are "boo!" - const first_page_rows = s.pages.pages.first.?.data.capacity.rows; - for (0..first_page_rows - 1) |_| try s.testWriteString("\n"); - for (0..s.pages.cols - 4) |_| try s.testWriteString("x"); - try s.testWriteString("boo!"); - try testing.expect(s.pages.pages.first == s.pages.pages.last); - try s.testWriteString("\n"); - try testing.expect(s.pages.pages.first != s.pages.pages.last); - try s.testWriteString("hello. boo!"); - - // Imaginary needle for search - const needle = "boo!"; - - // Add both pages - const node: *PageList.List.Node = s.pages.pages.first.?; - try w.append(alloc, node, needle.len); - try w.append(alloc, node.next.?, needle.len); - - // Ensure our data is correct -} - -pub const PageSearch = struct { - alloc: Allocator, - node: *PageList.List.Node, - needle: []const u8, - cell_map: Page.CellMap, - encoded: std.ArrayListUnmanaged(u8) = .{}, - i: usize = 0, - - pub fn init( - alloc: Allocator, - node: *PageList.List.Node, - needle: []const u8, - ) !PageSearch { - var result: PageSearch = .{ - .alloc = alloc, - .node = node, - .needle = needle, - .cell_map = Page.CellMap.init(alloc), - }; - - const page: *const Page = &node.data; - _ = try page.encodeUtf8(result.encoded.writer(alloc), .{ - .cell_map = &result.cell_map, - }); - - return result; - } - - pub fn deinit(self: *PageSearch) void { - self.encoded.deinit(self.alloc); - self.cell_map.deinit(); - } - - pub fn next(self: *PageSearch) ?Selection { - // Search our haystack for the needle. The resulting index is - // the offset from self.i not the absolute index. - const haystack: []const u8 = self.encoded.items[self.i..]; - const i_offset = std.mem.indexOf(u8, haystack, self.needle) orelse { - self.i = self.encoded.items.len; - return null; - }; - - // Get our full index into the encoded buffer. - const idx = self.i + i_offset; - - // We found our search term. Move the cursor forward one beyond - // the match. This lets us find every repeated match. - self.i = idx + 1; - - const tl: PageList.Pin = tl: { - const map = self.cell_map.items[idx]; - break :tl .{ - .node = self.node, - .y = map.y, - .x = map.x, - }; - }; - const br: PageList.Pin = br: { - const map = self.cell_map.items[idx + self.needle.len - 1]; - break :br .{ - .node = self.node, - .y = map.y, - .x = map.x, - }; - }; - - return Selection.init(tl, br, false); - } -}; - -test "search single page one match" { - const testing = std.testing; - const alloc = testing.allocator; - - var s = try Screen.init(alloc, 80, 24, 0); - defer s.deinit(); - try s.testWriteString("hello, world"); - - // We want to test single-page cases. - try testing.expect(s.pages.pages.first == s.pages.pages.last); - const node: *PageList.List.Node = s.pages.pages.first.?; - - var it = try PageSearch.init(alloc, node, "world"); - defer it.deinit(); - - const sel = it.next().?; - try testing.expectEqual(point.Point{ .active = .{ - .x = 7, - .y = 0, - } }, s.pages.pointFromPin(.active, sel.start()).?); - try testing.expectEqual(point.Point{ .active = .{ - .x = 11, - .y = 0, - } }, s.pages.pointFromPin(.active, sel.end()).?); - - try testing.expect(it.next() == null); -} - -test "search single page multiple match" { - const testing = std.testing; - const alloc = testing.allocator; - - var s = try Screen.init(alloc, 80, 24, 0); - defer s.deinit(); - try s.testWriteString("hello. boo! hello. boo!"); - - // We want to test single-page cases. - try testing.expect(s.pages.pages.first == s.pages.pages.last); - const node: *PageList.List.Node = s.pages.pages.first.?; - - var it = try PageSearch.init(alloc, node, "boo!"); - defer it.deinit(); - - { - const sel = it.next().?; - try testing.expectEqual(point.Point{ .active = .{ - .x = 7, - .y = 0, - } }, s.pages.pointFromPin(.active, sel.start()).?); - try testing.expectEqual(point.Point{ .active = .{ - .x = 10, - .y = 0, - } }, s.pages.pointFromPin(.active, sel.end()).?); - } - { - const sel = it.next().?; - try testing.expectEqual(point.Point{ .active = .{ - .x = 19, - .y = 0, - } }, s.pages.pointFromPin(.active, sel.start()).?); - try testing.expectEqual(point.Point{ .active = .{ - .x = 22, - .y = 0, - } }, s.pages.pointFromPin(.active, sel.end()).?); - } - - try testing.expect(it.next() == null); -} From bb185cf6b695420ce8b43b5c1cadd16ef71c481a Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 5 Dec 2024 11:02:19 -0800 Subject: [PATCH 23/32] apprt/gtk: force X11 backend on GTK 4.14 I'm unsure if this is an environmental issue just for me or if this is more widespread or what other downsides this may have. I'm more than willing to revert this if it ends up causing different issues. I found that with NixOS 24.11 and GTK 4.14 on my system, the default Wayland GDK backend fails to initialize EGL. With GTK 4.16 everything is fine. If I force X11 then everything also works fine. This commit forces X11 for GTK 4.14 specifically (4.16+ is allowed to use Wayland). --- src/apprt/gtk/App.zig | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/apprt/gtk/App.zig b/src/apprt/gtk/App.zig index ead41de7c..6329644be 100644 --- a/src/apprt/gtk/App.zig +++ b/src/apprt/gtk/App.zig @@ -115,8 +115,25 @@ pub fn init(core_app: *CoreApp, opts: Options) !App { // reassess... // // Upstream issue: https://gitlab.gnome.org/GNOME/gtk/-/issues/6589 + // + // Specific details about values: + // - "opengl" - output OpenGL debug information + // - "gl-disable-gles" - disable GLES, Ghostty can't use GLES + // - "vulkan-disable" - disable Vulkan, Ghostty can't use Vulkan + // and initializing a Vulkan context was causing a longer delay + // on some systems. _ = internal_os.setenv("GDK_DEBUG", "opengl,gl-disable-gles,vulkan-disable"); + + // Wayland-EGL on GTK 4.14 causes "Failed to create EGL context" errors. + // This can be fixed by forcing the backend to prefer X11. This issue + // appears to be fixed in GTK 4.16 but I wasn't able to bisect why. + // The "*" at the end says that if X11 fails, try all remaining + // backends. + _ = internal_os.setenv("GDK_BACKEND", "x11,*"); } else { + // Versions prior to 4.14 are a bit of an unknown for Ghostty. It + // is an environment that isn't tested well and we don't have a + // good understanding of what we may need to do. _ = internal_os.setenv("GDK_DEBUG", "vulkan-disable"); } From 1ee7da174bb473e3348b30b83aaa1732edd40bc8 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 5 Dec 2024 11:00:02 -0800 Subject: [PATCH 24/32] flake: update to Nix 24.11 --- flake.lock | 14 +++++++------- flake.nix | 3 +-- nix/devShell.nix | 23 ++++++++++++++++------- src/build/MetallibStep.zig | 4 ++-- src/terminal/kitty/graphics_storage.zig | 2 +- 5 files changed, 27 insertions(+), 19 deletions(-) diff --git a/flake.lock b/flake.lock index b5e75bae7..f517f07e4 100644 --- a/flake.lock +++ b/flake.lock @@ -20,27 +20,27 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1726062281, - "narHash": "sha256-PyFVySdGj3enKqm8RQuo4v1KLJLmNLOq2yYOHsI6e2Q=", + "lastModified": 1733423277, + "narHash": "sha256-TxabjxEgkNbCGFRHgM/b9yZWlBj60gUOUnRT/wbVQR8=", "owner": "nixos", "repo": "nixpkgs", - "rev": "e65aa8301ba4f0ab8cb98f944c14aa9da07394f8", + "rev": "e36963a147267afc055f7cf65225958633e536bf", "type": "github" }, "original": { "owner": "nixos", - "ref": "release-24.05", + "ref": "release-24.11", "repo": "nixpkgs", "type": "github" } }, "nixpkgs-unstable": { "locked": { - "lastModified": 1719082008, - "narHash": "sha256-jHJSUH619zBQ6WdC21fFAlDxHErKVDJ5fpN0Hgx4sjs=", + "lastModified": 1733229606, + "narHash": "sha256-FLYY5M0rpa5C2QAE3CKLYAM6TwbKicdRK6qNrSHlNrE=", "owner": "nixos", "repo": "nixpkgs", - "rev": "9693852a2070b398ee123a329e68f0dab5526681", + "rev": "566e53c2ad750c84f6d31f9ccb9d00f823165550", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 01acca063..d52f96d72 100644 --- a/flake.nix +++ b/flake.nix @@ -7,7 +7,7 @@ # We want to stay as up to date as possible but need to be careful that the # glibc versions used by our dependencies from Nix are compatible with the # system glibc that the user is building for. - nixpkgs-stable.url = "github:nixos/nixpkgs/release-24.05"; + nixpkgs-stable.url = "github:nixos/nixpkgs/release-24.11"; zig = { url = "github:mitchellh/zig-overlay"; @@ -36,7 +36,6 @@ packages.${system} = let mkArgs = optimize: { - inherit (pkgs-unstable) zig_0_13 stdenv; inherit optimize; revision = self.shortRev or self.dirtyShortRev or "dirty"; diff --git a/nix/devShell.nix b/nix/devShell.nix index 7f0e206b7..b2502d92d 100644 --- a/nix/devShell.nix +++ b/nix/devShell.nix @@ -159,11 +159,20 @@ in # it to be "portable" across the system. LD_LIBRARY_PATH = lib.makeLibraryPath rpathLibs; - # On Linux we need to setup the environment so that all GTK data - # is available (namely icons). - shellHook = lib.optionalString stdenv.hostPlatform.isLinux '' - # Minimal subset of env set by wrapGAppsHook4 for icons and global settings - export XDG_DATA_DIRS=$XDG_DATA_DIRS:${hicolor-icon-theme}/share:${gnome.adwaita-icon-theme}/share - export XDG_DATA_DIRS=$XDG_DATA_DIRS:$GSETTINGS_SCHEMAS_PATH # from glib setup hook - ''; + shellHook = + (lib.optionalString stdenv.hostPlatform.isLinux '' + # On Linux we need to setup the environment so that all GTK data + # is available (namely icons). + + # Minimal subset of env set by wrapGAppsHook4 for icons and global settings + export XDG_DATA_DIRS=$XDG_DATA_DIRS:${hicolor-icon-theme}/share:${gnome.adwaita-icon-theme}/share + export XDG_DATA_DIRS=$XDG_DATA_DIRS:$GSETTINGS_SCHEMAS_PATH # from glib setup hook + '') + + (lib.optionalString stdenv.hostPlatform.isDarwin '' + # On macOS, we unset the macOS SDK env vars that Nix sets up because + # we rely on a system installation. Nix only provides a macOS SDK + # and we need iOS too. + unset SDKROOT + unset DEVELOPER_DIR + ''); } diff --git a/src/build/MetallibStep.zig b/src/build/MetallibStep.zig index e576b9c3a..587d276c1 100644 --- a/src/build/MetallibStep.zig +++ b/src/build/MetallibStep.zig @@ -42,7 +42,7 @@ pub fn create(b: *std.Build, opts: Options) *MetallibStep { b, b.fmt("metal {s}", .{opts.name}), ); - run_ir.addArgs(&.{ "xcrun", "-sdk", sdk, "metal", "-o" }); + run_ir.addArgs(&.{ "/usr/bin/xcrun", "-sdk", sdk, "metal", "-o" }); const output_ir = run_ir.addOutputFileArg(b.fmt("{s}.ir", .{opts.name})); run_ir.addArgs(&.{"-c"}); for (opts.sources) |source| run_ir.addFileArg(source); @@ -62,7 +62,7 @@ pub fn create(b: *std.Build, opts: Options) *MetallibStep { b, b.fmt("metallib {s}", .{opts.name}), ); - run_lib.addArgs(&.{ "xcrun", "-sdk", sdk, "metallib", "-o" }); + run_lib.addArgs(&.{ "/usr/bin/xcrun", "-sdk", sdk, "metallib", "-o" }); const output_lib = run_lib.addOutputFileArg(b.fmt("{s}.metallib", .{opts.name})); run_lib.addFileArg(output_ir); run_lib.step.dependOn(&run_ir.step); diff --git a/src/terminal/kitty/graphics_storage.zig b/src/terminal/kitty/graphics_storage.zig index bf8633c88..ee46b2a6c 100644 --- a/src/terminal/kitty/graphics_storage.zig +++ b/src/terminal/kitty/graphics_storage.zig @@ -690,7 +690,7 @@ pub const ImageStorage = struct { br.x = @min( // We need to sub one here because the x value is // one width already. So if the image is width "1" - // then we add zero to X because X itelf is width 1. + // then we add zero to X because X itself is width 1. pin.x + (grid_size.cols - 1), t.cols - 1, ); From aa4e704d95cb28c838482fc2dfdd1e6df6bdf95d Mon Sep 17 00:00:00 2001 From: Dmitry Zhlobo Date: Sun, 8 Dec 2024 17:20:22 +0100 Subject: [PATCH 25/32] doc: remove outdated statement for fullscreen option We can use `macos-non-native-fullscreen` with `fullscreen` together since #1377 was closed. --- src/config/Config.zig | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/config/Config.zig b/src/config/Config.zig index 7fda17289..19417fff0 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -668,9 +668,6 @@ link: RepeatableLink = .{}, /// does not apply to tabs, splits, etc. However, this setting will apply to all /// new windows, not just the first one. /// -/// On macOS, this always creates the window in native fullscreen. Non-native -/// fullscreen is not currently supported with this setting. -/// /// On macOS, this setting does not work if window-decoration is set to /// "false", because native fullscreen on macOS requires window decorations /// to be set. From 250bd35830f80788f4b80e5c83b34bfa6986f112 Mon Sep 17 00:00:00 2001 From: moni Date: Fri, 6 Dec 2024 09:44:20 +0800 Subject: [PATCH 26/32] termio: clear kitty images when deleting above the cursor --- src/termio/Termio.zig | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/termio/Termio.zig b/src/termio/Termio.zig index 1ebe84541..bbcee7906 100644 --- a/src/termio/Termio.zig +++ b/src/termio/Termio.zig @@ -478,6 +478,18 @@ pub fn clearScreen(self: *Termio, td: *ThreadData, history: bool) !void { ); } + // Clear all Kitty graphics state for this screen. This copies + // Kitty's behavior when Cmd+K deletes all Kitty graphics. I + // didn't spend time researching whether it only deletes Kitty + // graphics that are placed baove the cursor or if it deletes + // all of them. We delete all of them for now but if this behavior + // isn't fully correct we should fix this later. + self.terminal.screen.kitty_images.delete( + self.terminal.screen.alloc, + &self.terminal, + .{ .all = true }, + ); + return; } From eb138930e6b5b105808357ea21aefb2c7f8b3d75 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 8 Dec 2024 11:04:29 -0800 Subject: [PATCH 27/32] macos: prevent moveFocus from being an infinite loop Fixes #2900 It's possible for moveFocus to infinite loop if the surface view we're trying to move focus to NEVER gets attached to a window. This can happen if the window is destroyed. I think this issue should be more systemically fixed so it can't happen but this workaround for now prevents moveFocus from being an infinite loop source for the time being. --- .../Ghostty/Ghostty.TerminalSplit.swift | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/macos/Sources/Ghostty/Ghostty.TerminalSplit.swift b/macos/Sources/Ghostty/Ghostty.TerminalSplit.swift index d4f82620c..272cdabdb 100644 --- a/macos/Sources/Ghostty/Ghostty.TerminalSplit.swift +++ b/macos/Sources/Ghostty/Ghostty.TerminalSplit.swift @@ -429,12 +429,34 @@ extension Ghostty { /// will lose focus. There has to be some nice SwiftUI-native way to fix this but I can't /// figure it out so we're going to do this hacky thing to bring focus back to the terminal /// that should have it. - static func moveFocus(to: SurfaceView, from: SurfaceView? = nil) { - DispatchQueue.main.async { + static func moveFocus( + to: SurfaceView, + from: SurfaceView? = nil, + delay: TimeInterval? = nil + ) { + // The whole delay machinery is a bit of a hack to work around a + // situation where the window is destroyed and the surface view + // will never be attached to a window. Realistically, we should + // handle this upstream but we also don't want this function to be + // a source of infinite loops. + + // Our max delay before we give up + let maxDelay: TimeInterval = 0.5 + guard (delay ?? 0) < maxDelay else { return } + + // We start at a 50 millisecond delay and do a doubling backoff + let nextDelay: TimeInterval = if let delay { + delay * 2 + } else { + // 100 milliseconds + 0.05 + } + + let work: DispatchWorkItem = .init { // If the callback runs before the surface is attached to a view // then the window will be nil. We just reschedule in that case. guard let window = to.window else { - moveFocus(to: to, from: from) + moveFocus(to: to, from: from, delay: nextDelay) return } @@ -448,5 +470,12 @@ extension Ghostty { window.makeFirstResponder(to) } + + let queue = DispatchQueue.main + if let delay { + queue.asyncAfter(deadline: .now() + delay, execute: work) + } else { + queue.async(execute: work) + } } } From 43a7dece02953d90e76f057a730f4e614c4cd87e Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 8 Dec 2024 11:22:02 -0800 Subject: [PATCH 28/32] config: title can reload at runtime Related to #2898 --- src/Surface.zig | 8 ++++++++ src/config/Config.zig | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/src/Surface.zig b/src/Surface.zig index 78a842673..3e7300d08 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -1182,6 +1182,14 @@ pub fn updateConfig( log.warn("failed to notify renderer of config change err={}", .{err}); }; + // If we have a title set then we update our window to have the + // newly configured title. + if (config.title) |title| try self.rt_app.performAction( + .{ .surface = self }, + .set_title, + .{ .title = title }, + ); + // Notify the window try self.rt_app.performAction( .{ .surface = self }, diff --git a/src/config/Config.zig b/src/config/Config.zig index 7fda17289..1bb8f48c4 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -679,6 +679,12 @@ fullscreen: bool = false, /// The title Ghostty will use for the window. This will force the title of the /// window to be this title at all times and Ghostty will ignore any set title /// escape sequences programs (such as Neovim) may send. +/// +/// This configuration can be reloaded at runtime. If it is set, the title +/// will update for all windows. If it is unset, the next title change escape +/// sequence will be honored but previous changes will not retroactively +/// be set. This latter case may require you restart programs such as neovim +/// to get the new title. title: ?[:0]const u8 = null, /// The setting that will change the application class value. From 49f105cd27ecb7afd58d57a2df2ef6ae6f2e1765 Mon Sep 17 00:00:00 2001 From: Dmitry Zhlobo Date: Sun, 8 Dec 2024 16:04:51 +0100 Subject: [PATCH 29/32] macos: make non-native fullscreen windows not resizeable --- macos/Sources/Helpers/Fullscreen.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/macos/Sources/Helpers/Fullscreen.swift b/macos/Sources/Helpers/Fullscreen.swift index bb3859e07..56912a28a 100644 --- a/macos/Sources/Helpers/Fullscreen.swift +++ b/macos/Sources/Helpers/Fullscreen.swift @@ -198,6 +198,10 @@ class NonNativeFullscreen: FullscreenBase, FullscreenStyle { // Being untitled let's our content take up the full frame. window.styleMask.remove(.titled) + // We dont' want the non-native fullscreen window to be resizable + // from the edges. + window.styleMask.remove(.resizable) + // Focus window window.makeKeyAndOrderFront(nil) From 313752dee27690e3920d54bfc1b55ad1e7413c76 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 8 Dec 2024 16:48:15 -0800 Subject: [PATCH 30/32] update libxev This fixes a possible deadlock. This has never happened in reports by beta testers but good hygiene to get this fixed. --- build.zig.zon | 4 ++-- nix/zigCacheHash.nix | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index c5e2d8f70..35365af8a 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -5,8 +5,8 @@ .dependencies = .{ // Zig libs .libxev = .{ - .url = "https://github.com/mitchellh/libxev/archive/b8d1d93e5c899b27abbaa7df23b496c3e6a178c7.tar.gz", - .hash = "1220612bc023c21d75234882ec9a8c6a1cbd9d642da3dfb899297f14bb5bd7b6cd78", + .url = "https://github.com/mitchellh/libxev/archive/db6a52bafadf00360e675fefa7926e8e6c0e9931.tar.gz", + .hash = "12206029de146b685739f69b10a6f08baee86b3d0a5f9a659fa2b2b66c9602078bbf", }, .mach_glfw = .{ .url = "https://github.com/mitchellh/mach-glfw/archive/37c2995f31abcf7e8378fba68ddcf4a3faa02de0.tar.gz", diff --git a/nix/zigCacheHash.nix b/nix/zigCacheHash.nix index 55cb4a0f3..162f65500 100644 --- a/nix/zigCacheHash.nix +++ b/nix/zigCacheHash.nix @@ -1,3 +1,3 @@ # This file is auto-generated! check build-support/check-zig-cache-hash.sh for # more details. -"sha256-D1SQIlmdP9x1PDgRVOy1qJGmu9osDbuyxGOcFj646N4=" +"sha256-c3MQJG7vwQBOaxHQ8cYP0HxdsLqlgsVmAiT1d7gq6js=" From 247409d70577364dca801f3512b0802b03599444 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 9 Dec 2024 08:14:57 -0800 Subject: [PATCH 31/32] New Ghostty icon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ❤️👻 This is the icon that we'll launch Ghostty 1.0 with. It was designed by Michael Flareup at PixelResort. It retains the style of the original Ghostty icon by Alasdair Monk, but brings in the new Ghost character and adds details that make it more Apple-like. The new Ghost character is an important evolution from the original since it separates us from looking too much like PacMan. The new Ghost is more unique and recognizable to Ghostty (or, hopefully will be!). The icon itself has more details: the aluminum around the edge has texture for the large enough sizes, there are visible scanlines, the glow of a screen emanates from the ghost. The icon itself is stylistic more Apple-like than other platforms. I think Apple icons tend to look very good in more environments than the reverse and I'm a big fan of the Apple aesthetic so I wanted to bring that to Ghostty for all platforms. --- README.md | 2 +- build.zig | 18 +++++++------- dist/macos/Ghostty.icns | Bin 501433 -> 382978 bytes dist/windows/ghostty.ico | Bin 73070 -> 86258 bytes images/icons/icon_1024.png | Bin 0 -> 464853 bytes images/icons/icon_128.png | Bin 0 -> 15177 bytes images/icons/icon_128@2x.png | Bin 0 -> 68177 bytes images/icons/icon_128x128.png | Bin 7944 -> 0 bytes images/icons/icon_128x128@2x@2x.png | Bin 18209 -> 0 bytes images/icons/icon_16.png | Bin 0 -> 666 bytes images/icons/icon_16@2x.png | Bin 0 -> 1563 bytes images/icons/icon_16x16.png | Bin 649 -> 0 bytes images/icons/icon_16x16@2x@2x.png | Bin 1499 -> 0 bytes images/icons/icon_256.png | Bin 0 -> 68189 bytes images/icons/icon_256@2x.png | Bin 0 -> 221047 bytes images/icons/icon_256x256.png | Bin 17785 -> 0 bytes images/icons/icon_256x256@2x@2x.png | Bin 40443 -> 0 bytes images/icons/icon_32.png | Bin 0 -> 1562 bytes images/icons/icon_32@2x.png | Bin 0 -> 4485 bytes images/icons/icon_32x32.png | Bin 1499 -> 0 bytes images/icons/icon_32x32@2x@2x.png | Bin 3071 -> 0 bytes images/icons/icon_512.png | Bin 0 -> 221047 bytes images/icons/icon_512x512.png | Bin 40443 -> 0 bytes images/icons/icon_512x512@2x@2x.png | Bin 94863 -> 0 bytes .../AppIcon.appiconset/Contents.json | 22 +++++++++--------- .../AppIcon.appiconset/icon_128x128.png | Bin 7944 -> 0 bytes .../AppIcon.appiconset/icon_128x128@2x@2x.png | Bin 18209 -> 0 bytes .../AppIcon.appiconset/icon_16x16.png | Bin 582 -> 0 bytes .../AppIcon.appiconset/icon_16x16@2x@2x.png | Bin 1499 -> 0 bytes .../AppIcon.appiconset/icon_256x256.png | Bin 17785 -> 0 bytes .../AppIcon.appiconset/icon_256x256@2x@2x.png | Bin 40443 -> 0 bytes .../AppIcon.appiconset/icon_32x32.png | Bin 1499 -> 0 bytes .../AppIcon.appiconset/icon_32x32@2x@2x.png | Bin 3071 -> 0 bytes .../AppIcon.appiconset/icon_512x512.png | Bin 40443 -> 0 bytes .../icon_512x512@2x@2x 1.png | Bin 94863 -> 0 bytes .../AppIcon.appiconset/icon_512x512@2x@2x.png | Bin 94863 -> 0 bytes .../macOS-AppIcon-1024px 1.png | Bin 0 -> 464853 bytes .../macOS-AppIcon-1024px.png | Bin 0 -> 464853 bytes .../macOS-AppIcon-128px-128pt@1x.png | Bin 0 -> 15177 bytes .../macOS-AppIcon-16px-16pt@1x.png | Bin 0 -> 666 bytes .../macOS-AppIcon-256px-128pt@2x 1.png | Bin 0 -> 68177 bytes .../macOS-AppIcon-256px-128pt@2x.png | Bin 0 -> 68177 bytes .../macOS-AppIcon-32px-16pt@2x.png | Bin 0 -> 1562 bytes .../macOS-AppIcon-32px-32pt@1x.png | Bin 0 -> 1564 bytes .../macOS-AppIcon-512px-256pt@2x.png | Bin 0 -> 221047 bytes .../macOS-AppIcon-512px.png | Bin 0 -> 220725 bytes .../macOS-AppIcon-64px-32pt@2x.png | Bin 0 -> 4485 bytes .../AppIconImage.imageset/Contents.json | 6 ++--- .../AppIconImage.imageset/icon_128x128.png | Bin 7944 -> 0 bytes .../icon_128x128@2x@2x.png | Bin 18209 -> 0 bytes .../icon_256x256@2x@2x.png | Bin 40443 -> 0 bytes .../macOS-AppIcon-1024px.png | Bin 0 -> 464853 bytes .../macOS-AppIcon-256px-128pt@2x.png | Bin 0 -> 68177 bytes .../macOS-AppIcon-512px.png | Bin 0 -> 221146 bytes src/apprt/gtk/gresource.zig | 18 +++++++------- 55 files changed, 33 insertions(+), 33 deletions(-) mode change 100755 => 100644 dist/macos/Ghostty.icns create mode 100644 images/icons/icon_1024.png create mode 100644 images/icons/icon_128.png create mode 100644 images/icons/icon_128@2x.png delete mode 100755 images/icons/icon_128x128.png delete mode 100755 images/icons/icon_128x128@2x@2x.png create mode 100644 images/icons/icon_16.png create mode 100644 images/icons/icon_16@2x.png delete mode 100755 images/icons/icon_16x16.png delete mode 100755 images/icons/icon_16x16@2x@2x.png create mode 100644 images/icons/icon_256.png create mode 100644 images/icons/icon_256@2x.png delete mode 100755 images/icons/icon_256x256.png delete mode 100755 images/icons/icon_256x256@2x@2x.png create mode 100644 images/icons/icon_32.png create mode 100644 images/icons/icon_32@2x.png delete mode 100755 images/icons/icon_32x32.png delete mode 100755 images/icons/icon_32x32@2x@2x.png create mode 100644 images/icons/icon_512.png delete mode 100755 images/icons/icon_512x512.png delete mode 100755 images/icons/icon_512x512@2x@2x.png delete mode 100644 macos/Assets.xcassets/AppIcon.appiconset/icon_128x128.png delete mode 100644 macos/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x@2x.png delete mode 100644 macos/Assets.xcassets/AppIcon.appiconset/icon_16x16.png delete mode 100644 macos/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x@2x.png delete mode 100644 macos/Assets.xcassets/AppIcon.appiconset/icon_256x256.png delete mode 100644 macos/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x@2x.png delete mode 100644 macos/Assets.xcassets/AppIcon.appiconset/icon_32x32.png delete mode 100644 macos/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x@2x.png delete mode 100644 macos/Assets.xcassets/AppIcon.appiconset/icon_512x512.png delete mode 100644 macos/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x@2x 1.png delete mode 100644 macos/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x@2x.png create mode 100644 macos/Assets.xcassets/AppIcon.appiconset/macOS-AppIcon-1024px 1.png create mode 100644 macos/Assets.xcassets/AppIcon.appiconset/macOS-AppIcon-1024px.png create mode 100644 macos/Assets.xcassets/AppIcon.appiconset/macOS-AppIcon-128px-128pt@1x.png create mode 100644 macos/Assets.xcassets/AppIcon.appiconset/macOS-AppIcon-16px-16pt@1x.png create mode 100644 macos/Assets.xcassets/AppIcon.appiconset/macOS-AppIcon-256px-128pt@2x 1.png create mode 100644 macos/Assets.xcassets/AppIcon.appiconset/macOS-AppIcon-256px-128pt@2x.png create mode 100644 macos/Assets.xcassets/AppIcon.appiconset/macOS-AppIcon-32px-16pt@2x.png create mode 100644 macos/Assets.xcassets/AppIcon.appiconset/macOS-AppIcon-32px-32pt@1x.png create mode 100644 macos/Assets.xcassets/AppIcon.appiconset/macOS-AppIcon-512px-256pt@2x.png create mode 100644 macos/Assets.xcassets/AppIcon.appiconset/macOS-AppIcon-512px.png create mode 100644 macos/Assets.xcassets/AppIcon.appiconset/macOS-AppIcon-64px-32pt@2x.png delete mode 100644 macos/Assets.xcassets/AppIconImage.imageset/icon_128x128.png delete mode 100644 macos/Assets.xcassets/AppIconImage.imageset/icon_128x128@2x@2x.png delete mode 100644 macos/Assets.xcassets/AppIconImage.imageset/icon_256x256@2x@2x.png create mode 100644 macos/Assets.xcassets/AppIconImage.imageset/macOS-AppIcon-1024px.png create mode 100644 macos/Assets.xcassets/AppIconImage.imageset/macOS-AppIcon-256px-128pt@2x.png create mode 100644 macos/Assets.xcassets/AppIconImage.imageset/macOS-AppIcon-512px.png diff --git a/README.md b/README.md index 861e0937a..4cafc6ac1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

- Logo + Logo
Ghostty

diff --git a/build.zig b/build.zig index d233bff1f..093afe481 100644 --- a/build.zig +++ b/build.zig @@ -578,15 +578,15 @@ pub fn build(b: *std.Build) !void { // Various icons that our application can use, including the icon // that will be used for the desktop. - b.installFile("images/icons/icon_16x16.png", "share/icons/hicolor/16x16/apps/com.mitchellh.ghostty.png"); - b.installFile("images/icons/icon_32x32.png", "share/icons/hicolor/32x32/apps/com.mitchellh.ghostty.png"); - b.installFile("images/icons/icon_128x128.png", "share/icons/hicolor/128x128/apps/com.mitchellh.ghostty.png"); - b.installFile("images/icons/icon_256x256.png", "share/icons/hicolor/256x256/apps/com.mitchellh.ghostty.png"); - b.installFile("images/icons/icon_512x512.png", "share/icons/hicolor/512x512/apps/com.mitchellh.ghostty.png"); - b.installFile("images/icons/icon_16x16@2x@2x.png", "share/icons/hicolor/16x16@2/apps/com.mitchellh.ghostty.png"); - b.installFile("images/icons/icon_32x32@2x@2x.png", "share/icons/hicolor/32x32@2/apps/com.mitchellh.ghostty.png"); - b.installFile("images/icons/icon_128x128@2x@2x.png", "share/icons/hicolor/128x128@2/apps/com.mitchellh.ghostty.png"); - b.installFile("images/icons/icon_256x256@2x@2x.png", "share/icons/hicolor/256x256@2/apps/com.mitchellh.ghostty.png"); + b.installFile("images/icons/icon_16.png", "share/icons/hicolor/16x16/apps/com.mitchellh.ghostty.png"); + b.installFile("images/icons/icon_32.png", "share/icons/hicolor/32x32/apps/com.mitchellh.ghostty.png"); + b.installFile("images/icons/icon_128.png", "share/icons/hicolor/128x128/apps/com.mitchellh.ghostty.png"); + b.installFile("images/icons/icon_256.png", "share/icons/hicolor/256x256/apps/com.mitchellh.ghostty.png"); + b.installFile("images/icons/icon_512.png", "share/icons/hicolor/512x512/apps/com.mitchellh.ghostty.png"); + b.installFile("images/icons/icon_16@2x.png", "share/icons/hicolor/16x16@2/apps/com.mitchellh.ghostty.png"); + b.installFile("images/icons/icon_32@2x.png", "share/icons/hicolor/32x32@2/apps/com.mitchellh.ghostty.png"); + b.installFile("images/icons/icon_128@2x.png", "share/icons/hicolor/128x128@2/apps/com.mitchellh.ghostty.png"); + b.installFile("images/icons/icon_256@2x.png", "share/icons/hicolor/256x256@2/apps/com.mitchellh.ghostty.png"); } // libghostty (non-Darwin) diff --git a/dist/macos/Ghostty.icns b/dist/macos/Ghostty.icns old mode 100755 new mode 100644 index 52365a4057685a4dbd22e507132bd07a7d3fbacd..44a44711aac562d23a82630e3b374ba9c5325b14 GIT binary patch literal 382978 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