summaryrefslogtreecommitdiff
path: root/autoload/filetype/diff-parse.pl
diff options
context:
space:
mode:
authorthing1 <thing1@seacrossedlovers.xyz>2025-01-28 09:14:32 +0000
committerthing1 <thing1@seacrossedlovers.xyz>2025-01-28 09:14:32 +0000
commit904cec3c4a329cf89fc3219d359239910d61f3f6 (patch)
tree8d113899921dfbaca0e77c49ab5fc827362d1091 /autoload/filetype/diff-parse.pl
init commitHEADmaster
Diffstat (limited to 'autoload/filetype/diff-parse.pl')
-rw-r--r--autoload/filetype/diff-parse.pl143
1 files changed, 143 insertions, 0 deletions
diff --git a/autoload/filetype/diff-parse.pl b/autoload/filetype/diff-parse.pl
new file mode 100644
index 0000000..203e9b1
--- /dev/null
+++ b/autoload/filetype/diff-parse.pl
@@ -0,0 +1,143 @@
+#!/usr/bin/env perl
+
+use warnings;
+
+sub quote {
+ my $token = shift;
+ $token =~ s/'/''/g;
+ return "'$token'";
+}
+sub fail {
+ my $reason = shift;
+ print "set-register e fail " . quote("diff-parse.pl: $reason");
+ exit;
+}
+
+my $begin;
+my $end;
+
+while (defined $ARGV[0]) {
+ if ($ARGV[0] eq "--") {
+ shift;
+ last;
+ }
+ if ($ARGV[0] =~ m{^(BEGIN|END)$}) {
+ if (not defined $ARGV[1]) {
+ fail "missing argument to $ARGV[0]";
+ }
+ if ($ARGV[0] eq "BEGIN") {
+ $begin = $ARGV[1];
+ } else {
+ $end = $ARGV[1];
+ }
+ shift, shift;
+ next;
+ }
+ fail "unknown argument: $ARGV[0]";
+}
+
+# Inputs
+our $directory = $ENV{PWD};
+our $strip;
+our $in_file;
+our $in_file_line;
+our $version = "+";
+
+eval $begin if defined $begin;
+
+$in_file = "$directory/$in_file" if defined $in_file;
+
+# Outputs
+our $diff_line = 0;
+our $commit;
+our $file;
+our $file_line;
+our $diff_line_text;
+
+my $other_version;
+if ($version eq "+") {
+ $other_version = "-";
+} else {
+ $other_version = "+";
+}
+my $is_recursive_diff = 0;
+my $state = "header";
+my $fallback_file;
+my $other_file;
+my $other_file_line;
+
+sub strip {
+ my $is_recursive_diff = shift;
+ my $f = shift;
+
+ my $effective_strip;
+ if (defined $strip) {
+ $effective_strip = $strip;
+ } else {
+ # A "diff -r" or "git diff" adds "diff" lines to
+ # the output. If no such line is present, we have
+ # a plain diff between files (not directories), so
+ # there should be no need to strip the directory.
+ $effective_strip = $is_recursive_diff ? 1 : 0;
+ }
+
+ if ($f !~ m{^/}) {
+ $f =~ s,^([^/]+/+){$effective_strip},, or fail "directory prefix underflow";
+ $f = "$directory/$f";
+ }
+ return $f;
+}
+
+while (<STDIN>) {
+ $diff_line++;
+ s/^(> )*//g;
+ $diff_line_text = $_;
+ if (m{^commit (\w+)}) {
+ $commit = $1;
+ next;
+ }
+ if (m{^diff\b}) {
+ $state = "header";
+ $is_recursive_diff = 1;
+ if (m{^diff -\S* (\S+) (\S+)$}) {
+ $fallback_file = strip $is_recursive_diff, ($version eq "+" ? $2 : $1);
+ }
+ next;
+ }
+ if ($state eq "header") {
+ if (m{^[$version]{3} ([^\t\n]+)}) {
+ $file = strip $is_recursive_diff, $1;
+ next;
+ }
+ if (m{^[$other_version]{3} ([^\t\n]+)}) {
+ $other_file = strip $is_recursive_diff, $1;
+ next;
+ }
+ }
+ if (m{^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@}) {
+ $state = "contents";
+ $file_line = ($version eq "+" ? $2 : $1) - 1;
+ $other_file_line = ($version eq "+" ? $1 : $2) - 1;
+ } else {
+ my $iscontext = m{^[ ]};
+ if (m{^[ $version]}) {
+ $file_line++ if defined $file_line;
+ }
+ if (m{^[ $other_version]}) {
+ $other_file_line++ if defined $other_file_line;
+ }
+ }
+ if (defined $in_file and defined $file and $file eq $in_file) {
+ if (defined $in_file_line and defined $file_line and $file_line >= $in_file_line) {
+ last;
+ }
+ }
+}
+if (not defined $file) {
+ $file = ($fallback_file or $other_file);
+}
+if (not defined $file) {
+ fail "missing diff header";
+}
+
+eval $end if defined $end;