| ... | @@ -1,6 +1,5 @@ | ... | @@ -1,6 +1,5 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const string = []const u8; | 2 | const string = []const u8; |
| 3 | const top = @This(); | | |
| 4 | const time = @import("time"); | 3 | const time = @import("time"); |
| 5 | const extras = @import("extras"); | 4 | const extras = @import("extras"); |
| 6 | const tracer = @import("tracer"); | 5 | const tracer = @import("tracer"); |
| ... | @@ -1465,6 +1464,91 @@ pub const Tree = struct { | ... | @@ -1465,6 +1464,91 @@ pub const Tree = struct { |
| 1465 | } | 1464 | } |
| 1466 | }; | 1465 | }; |
| 1467 | }; | 1466 | }; |
| | 1467 | |
| | 1468 | pub fn walk(self: Tree, r: *Repository, arena: std.mem.Allocator) !Walker { |
| | 1469 | var stack: std.ArrayListUnmanaged(Walker.StackItem) = .empty; |
| | 1470 | |
| | 1471 | try stack.append(r.gpa, .{ |
| | 1472 | .tree = self, |
| | 1473 | .idx = 0, |
| | 1474 | .dirname_len = 0, |
| | 1475 | }); |
| | 1476 | return .{ |
| | 1477 | .repo = r, |
| | 1478 | .arena = arena, |
| | 1479 | .stack = stack, |
| | 1480 | .name_buffer = .empty, |
| | 1481 | }; |
| | 1482 | } |
| | 1483 | |
| | 1484 | pub const Walker = struct { |
| | 1485 | repo: *Repository, |
| | 1486 | arena: std.mem.Allocator, |
| | 1487 | stack: std.ArrayListUnmanaged(StackItem), |
| | 1488 | name_buffer: std.ArrayListUnmanaged(u8), |
| | 1489 | |
| | 1490 | pub const Entry = struct { |
| | 1491 | obj: Object, |
| | 1492 | path: [:0]const u8, |
| | 1493 | }; |
| | 1494 | |
| | 1495 | const StackItem = struct { |
| | 1496 | tree: Tree, |
| | 1497 | idx: usize, |
| | 1498 | dirname_len: usize, |
| | 1499 | }; |
| | 1500 | |
| | 1501 | pub fn next(self: *Walker) !?Walker.Entry { |
| | 1502 | const gpa = self.repo.gpa; |
| | 1503 | const arena = self.arena; |
| | 1504 | while (self.stack.items.len != 0) { |
| | 1505 | var top = &self.stack.items[self.stack.items.len - 1]; |
| | 1506 | var containing = top; |
| | 1507 | var dirname_len = top.dirname_len; |
| | 1508 | if (top.idx < top.tree.children.len()) { |
| | 1509 | const base = top.tree.children.get(top.idx); |
| | 1510 | top.idx += 1; |
| | 1511 | self.name_buffer.shrinkRetainingCapacity(dirname_len); |
| | 1512 | if (self.name_buffer.items.len != 0) { |
| | 1513 | try self.name_buffer.append(gpa, '/'); |
| | 1514 | dirname_len += 1; |
| | 1515 | } |
| | 1516 | try self.name_buffer.ensureUnusedCapacity(gpa, base.name.len + 1); |
| | 1517 | self.name_buffer.appendSliceAssumeCapacity(base.name); |
| | 1518 | self.name_buffer.appendAssumeCapacity(0); |
| | 1519 | if (base.id == .tree) { |
| | 1520 | const new_tree = try self.repo.getTreeA(arena, base.id.tree.id); |
| | 1521 | { |
| | 1522 | // errdefer new_dir.close(); |
| | 1523 | try self.stack.append(gpa, .{ |
| | 1524 | .tree = new_tree, |
| | 1525 | .idx = 0, |
| | 1526 | .dirname_len = self.name_buffer.items.len - 1, |
| | 1527 | }); |
| | 1528 | top = &self.stack.items[self.stack.items.len - 1]; |
| | 1529 | containing = &self.stack.items[self.stack.items.len - 2]; |
| | 1530 | } |
| | 1531 | } |
| | 1532 | return .{ |
| | 1533 | .obj = base, |
| | 1534 | .path = self.name_buffer.items[0 .. self.name_buffer.items.len - 1 :0], |
| | 1535 | }; |
| | 1536 | } else { |
| | 1537 | var item = self.stack.pop().?; |
| | 1538 | _ = &item; |
| | 1539 | // if (self.stack.items.len != 0) item.iter.dir.close(); |
| | 1540 | } |
| | 1541 | } |
| | 1542 | return null; |
| | 1543 | } |
| | 1544 | |
| | 1545 | pub fn deinit(self: *Walker) void { |
| | 1546 | const gpa = self.repo.gpa; |
| | 1547 | // for (self.stack.items) |*item| item.iter.dir.close(); |
| | 1548 | self.stack.deinit(gpa); |
| | 1549 | self.name_buffer.deinit(gpa); |
| | 1550 | } |
| | 1551 | }; |
| 1468 | }; | 1552 | }; |
| 1469 | | 1553 | |
| 1470 | pub const Commit = struct { | 1554 | pub const Commit = struct { |