| ... | @@ -769,3 +769,109 @@ pub const Ref = struct { | ... | @@ -769,3 +769,109 @@ pub const Ref = struct { |
| 769 | commit: CommitId, | 769 | commit: CommitId, |
| 770 | tag: ?TagId, | 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 | }; |