reset search on needle change or quit

pull/9687/head
Mitchell Hashimoto 2025-11-24 12:35:57 -08:00
parent dd9ed531ad
commit d0e3a79a74
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
3 changed files with 42 additions and 4 deletions

View File

@ -1342,6 +1342,8 @@ fn searchCallback_(
self: *Surface,
event: terminal.search.Thread.Event,
) !void {
// NOTE: This runs on the search thread.
switch (event) {
.viewport_matches => |matches_unowned| {
var arena: ArenaAllocator = .init(self.alloc);
@ -1361,6 +1363,18 @@ fn searchCallback_(
try self.renderer_thread.wakeup.notify();
},
// When we quit, tell our renderer to reset any search state.
.quit => {
_ = self.renderer_thread.mailbox.push(
.{ .search_viewport_matches = .{
.arena = .init(self.alloc),
.matches = &.{},
} },
.forever,
);
try self.renderer_thread.wakeup.notify();
},
// Unhandled, so far.
.total_matches,
.complete,

View File

@ -163,7 +163,14 @@ fn threadMain_(self: *Thread) !void {
// Run
log.debug("starting search thread", .{});
defer log.debug("starting search thread shutdown", .{});
defer {
log.debug("starting search thread shutdown", .{});
// Send the quit message
if (self.opts.event_cb) |cb| {
cb(.quit, self.opts.event_userdata);
}
}
// Unlike some of our other threads, we interleave search work
// with our xev loop so that we can try to make forward search progress
@ -247,6 +254,18 @@ fn changeNeedle(self: *Thread, needle: []const u8) !void {
if (self.search) |*s| {
s.deinit();
self.search = null;
// When the search changes then we need to emit that it stopped.
if (self.opts.event_cb) |cb| {
cb(
.{ .total_matches = 0 },
self.opts.event_userdata,
);
cb(
.{ .viewport_matches = &.{} },
self.opts.event_userdata,
);
}
}
// No needle means stop the search.
@ -381,6 +400,9 @@ pub const Message = union(enum) {
/// Events that can be emitted from the search thread. The caller
/// chooses to handle these as they see fit.
pub const Event = union(enum) {
/// Search is quitting. The search thread is exiting.
quit,
/// Search is complete for the given needle on all screens.
complete,
@ -668,6 +690,7 @@ test {
fn callback(event: Event, userdata: ?*anyopaque) void {
const ud: *Self = @ptrCast(@alignCast(userdata.?));
switch (event) {
.quit => {},
.complete => ud.reset.set(),
.total_matches => |v| ud.total = v,
.viewport_matches => |v| {

View File

@ -326,15 +326,16 @@ test "clear screen and search dirty tracking" {
try testing.expect(try search.update(&t.screens.active.pages));
{
const sel = search.next().?;
const h = search.next().?;
const sel = h.untracked();
try testing.expectEqual(point.Point{ .active = .{
.x = 0,
.y = 1,
} }, t.screens.active.pages.pointFromPin(.active, sel.start()).?);
} }, t.screens.active.pages.pointFromPin(.active, sel.start).?);
try testing.expectEqual(point.Point{ .active = .{
.x = 3,
.y = 1,
} }, t.screens.active.pages.pointFromPin(.active, sel.end()).?);
} }, t.screens.active.pages.pointFromPin(.active, sel.end).?);
}
try testing.expect(search.next() == null);
}