| ... | ... | @@ -769,3 +769,109 @@ pub const Ref = struct { |
| 769 | 769 | commit: CommitId, |
| 770 | 770 | tag: ?TagId, |
| 771 | 771 | }; |
| 772 | |
| 773 | // TODO make this inspect .git/objects |
| 774 | pub fn getBlame(alloc: std.mem.Allocator, dir: std.fs.Dir, at: CommitId, sub_path: string) !string { |
| 775 | const t = tracer.trace(@src(), " {s} -- {s}", .{ at.id, sub_path }); |
| 776 | defer t.end(); |
| 777 | |
| 778 | const result = try std.process.Child.run(.{ |
| 779 | .allocator = alloc, |
| 780 | .cwd_dir = dir, |
| 781 | .argv = &.{ "git", "blame", "-p", at.id, "--", sub_path }, |
| 782 | .max_output_bytes = 1024 * 1024 * 1024, |
| 783 | }); |
| 784 | extras.assertLog(result.term == .Exited and result.term.Exited == 0, "{s}", .{result.stderr}); |
| 785 | return result.stdout; |
| 786 | } |
| 787 | |
| 788 | pub const BlameIterator = struct { |
| 789 | inner: std.mem.SplitIterator(u8, .scalar), |
| 790 | |
| 791 | pub fn init(blamefile: []const u8) BlameIterator { |
| 792 | return .{ |
| 793 | .inner = std.mem.splitScalar(u8, blamefile, '\n'), |
| 794 | }; |
| 795 | } |
| 796 | |
| 797 | /// when line.continuity is >0 then .commit will be the same for the next continuity-1 iterations |
| 798 | pub fn next(self: *BlameIterator) ?Line { |
| 799 | var result: Line = .{ |
| 800 | .commit = undefined, |
| 801 | .prev_line = 0, |
| 802 | .curr_line = 0, |
| 803 | .continuity = 0, |
| 804 | .author = .{ .name = "", .email = "", .at = .initUnix(0) }, |
| 805 | .committer = .{ .name = "", .email = "", .at = .initUnix(0) }, |
| 806 | .summary = "", |
| 807 | .previous = null, |
| 808 | .filename = "", |
| 809 | .line = "", |
| 810 | }; |
| 811 | blk: { |
| 812 | var it = std.mem.splitScalar(u8, self.inner.next() orelse return null, ' '); |
| 813 | result.commit = ensureObjId(CommitId, extras.nullifyS(it.next().?) orelse return null); |
| 814 | result.prev_line = std.fmt.parseInt(u32, it.next().?, 10) catch unreachable; |
| 815 | result.curr_line = std.fmt.parseInt(u32, it.next().?, 10) catch unreachable; |
| 816 | result.continuity = std.fmt.parseInt(u32, it.next() orelse break :blk, 10) catch unreachable; |
| 817 | } |
| 818 | while (self.inner.next()) |line| { |
| 819 | if (line[0] == '\t') { |
| 820 | result.line = line[1..]; |
| 821 | break; |
| 822 | } |
| 823 | if (extras.trimPrefixEnsure(line, "author ")) |trimmed| { |
| 824 | result.author = .{ |
| 825 | .name = trimmed, |
| 826 | .email = extras.trimPrefixEnsure(self.inner.next().?, "author-mail ").?, |
| 827 | .at = parseAt( |
| 828 | extras.trimPrefixEnsure(self.inner.next().?, "author-time ").?, |
| 829 | extras.trimPrefixEnsure(self.inner.next().?, "author-tz ").?, |
| 830 | ), |
| 831 | }; |
| 832 | continue; |
| 833 | } |
| 834 | if (extras.trimPrefixEnsure(line, "committer ")) |trimmed| { |
| 835 | result.committer = .{ |
| 836 | .name = trimmed, |
| 837 | .email = extras.trimPrefixEnsure(self.inner.next().?, "committer-mail ").?, |
| 838 | .at = parseAt( |
| 839 | extras.trimPrefixEnsure(self.inner.next().?, "committer-time ").?, |
| 840 | extras.trimPrefixEnsure(self.inner.next().?, "committer-tz ").?, |
| 841 | ), |
| 842 | }; |
| 843 | continue; |
| 844 | } |
| 845 | if (extras.trimPrefixEnsure(line, "summary ")) |trimmed| { |
| 846 | result.summary = trimmed; |
| 847 | continue; |
| 848 | } |
| 849 | if (extras.trimPrefixEnsure(line, "previous ")) |trimmed| { |
| 850 | var it = std.mem.splitScalar(u8, trimmed, ' '); |
| 851 | result.previous = .{ |
| 852 | ensureObjId(CommitId, it.next().?), |
| 853 | it.next().?, |
| 854 | }; |
| 855 | continue; |
| 856 | } |
| 857 | if (extras.trimPrefixEnsure(line, "filename ")) |trimmed| { |
| 858 | result.filename = trimmed; |
| 859 | continue; |
| 860 | } |
| 861 | } |
| 862 | return result; |
| 863 | } |
| 864 | |
| 865 | pub const Line = struct { |
| 866 | commit: CommitId, |
| 867 | prev_line: u32, |
| 868 | curr_line: u32, |
| 869 | continuity: u32, |
| 870 | author: UserAndAt, |
| 871 | committer: UserAndAt, |
| 872 | summary: string, |
| 873 | previous: ?struct { CommitId, string }, |
| 874 | filename: string, |
| 875 | line: string, |
| 876 | }; |
| 877 | }; |