sub patch_update_file()

in git-add--interactive.perl [1488:1788]


sub patch_update_file {
	my $quit = 0;
	my ($ix, $num);
	my $path = shift;
	my ($head, @hunk) = parse_diff($path);
	($head, my $mode, my $deletion, my $addition) = parse_diff_header($head);
	for (@{$head->{DISPLAY}}) {
		print;
	}

	if (@{$mode->{TEXT}}) {
		unshift @hunk, $mode;
	}
	if (@{$deletion->{TEXT}}) {
		foreach my $hunk (@hunk) {
			push @{$deletion->{TEXT}}, @{$hunk->{TEXT}};
			push @{$deletion->{DISPLAY}}, @{$hunk->{DISPLAY}};
		}
		@hunk = ($deletion);
	}

	$num = scalar @hunk;
	$ix = 0;

	while (1) {
		my ($prev, $next, $other, $undecided, $i);
		$other = '';

		last if ($ix and !$num);
		if ($num <= $ix) {
			$ix = 0;
		}
		for ($i = 0; $i < $ix; $i++) {
			if (!defined $hunk[$i]{USE}) {
				$prev = 1;
				$other .= ',k';
				last;
			}
		}
		if ($ix) {
			$other .= ',K';
		}
		for ($i = $ix + 1; $i < $num; $i++) {
			if (!defined $hunk[$i]{USE}) {
				$next = 1;
				$other .= ',j';
				last;
			}
		}
		if ($ix < $num - 1) {
			$other .= ',J';
		}
		if ($num > 1) {
			$other .= ',g,/';
		}
		for ($i = 0; $i < $num; $i++) {
			if (!defined $hunk[$i]{USE}) {
				$undecided = 1;
				last;
			}
		}
		last if (!$undecided && ($num || !$addition));

		if ($num) {
			if ($hunk[$ix]{TYPE} eq 'hunk' &&
			    hunk_splittable($hunk[$ix]{TEXT})) {
				$other .= ',s';
			}
			if ($hunk[$ix]{TYPE} eq 'hunk') {
				$other .= ',e';
			}
			for (@{$hunk[$ix]{DISPLAY}}) {
				print;
			}
		}
		my $type = $num ? $hunk[$ix]{TYPE} : $head->{TYPE};
		print colored $prompt_color, "(", ($ix+1), "/", ($num ? $num : 1), ") ",
			sprintf(__($patch_update_prompt_modes{$patch_mode}{$type}), $other);

		my $line = prompt_single_character;
		last unless defined $line;
		if ($line) {
			if ($line =~ /^y/i) {
				if ($num) {
					$hunk[$ix]{USE} = 1;
				} else {
					$head->{USE} = 1;
				}
			}
			elsif ($line =~ /^n/i) {
				if ($num) {
					$hunk[$ix]{USE} = 0;
				} else {
					$head->{USE} = 0;
				}
			}
			elsif ($line =~ /^a/i) {
				if ($num) {
					while ($ix < $num) {
						if (!defined $hunk[$ix]{USE}) {
							$hunk[$ix]{USE} = 1;
						}
						$ix++;
					}
				} else {
					$head->{USE} = 1;
					$ix++;
				}
				next;
			}
			elsif ($line =~ /^g(.*)/) {
				my $response = $1;
				unless ($other =~ /g/) {
					error_msg __("No other hunks to goto\n");
					next;
				}
				my $no = $ix > 10 ? $ix - 10 : 0;
				while ($response eq '') {
					$no = display_hunks(\@hunk, $no);
					if ($no < $num) {
						print __("go to which hunk (<ret> to see more)? ");
					} else {
						print __("go to which hunk? ");
					}
					$response = <STDIN>;
					if (!defined $response) {
						$response = '';
					}
					chomp $response;
				}
				if ($response !~ /^\s*\d+\s*$/) {
					error_msg sprintf(__("Invalid number: '%s'\n"),
							     $response);
				} elsif (0 < $response && $response <= $num) {
					$ix = $response - 1;
				} else {
					error_msg sprintf(__n("Sorry, only %d hunk available.\n",
							      "Sorry, only %d hunks available.\n", $num), $num);
				}
				next;
			}
			elsif ($line =~ /^d/i) {
				if ($num) {
					while ($ix < $num) {
						if (!defined $hunk[$ix]{USE}) {
							$hunk[$ix]{USE} = 0;
						}
						$ix++;
					}
				} else {
					$head->{USE} = 0;
					$ix++;
				}
				next;
			}
			elsif ($line =~ /^q/i) {
				if ($num) {
					for ($i = 0; $i < $num; $i++) {
						if (!defined $hunk[$i]{USE}) {
							$hunk[$i]{USE} = 0;
						}
					}
				} elsif (!defined $head->{USE}) {
					$head->{USE} = 0;
				}
				$quit = 1;
				last;
			}
			elsif ($line =~ m|^/(.*)|) {
				my $regex = $1;
				unless ($other =~ m|/|) {
					error_msg __("No other hunks to search\n");
					next;
				}
				if ($regex eq "") {
					print colored $prompt_color, __("search for regex? ");
					$regex = <STDIN>;
					if (defined $regex) {
						chomp $regex;
					}
				}
				my $search_string;
				eval {
					$search_string = qr{$regex}m;
				};
				if ($@) {
					my ($err,$exp) = ($@, $1);
					$err =~ s/ at .*git-add--interactive line \d+, <STDIN> line \d+.*$//;
					error_msg sprintf(__("Malformed search regexp %s: %s\n"), $exp, $err);
					next;
				}
				my $iy = $ix;
				while (1) {
					my $text = join ("", @{$hunk[$iy]{TEXT}});
					last if ($text =~ $search_string);
					$iy++;
					$iy = 0 if ($iy >= $num);
					if ($ix == $iy) {
						error_msg __("No hunk matches the given pattern\n");
						last;
					}
				}
				$ix = $iy;
				next;
			}
			elsif ($line =~ /^K/) {
				if ($other =~ /K/) {
					$ix--;
				}
				else {
					error_msg __("No previous hunk\n");
				}
				next;
			}
			elsif ($line =~ /^J/) {
				if ($other =~ /J/) {
					$ix++;
				}
				else {
					error_msg __("No next hunk\n");
				}
				next;
			}
			elsif ($line =~ /^k/) {
				if ($other =~ /k/) {
					while (1) {
						$ix--;
						last if (!$ix ||
							 !defined $hunk[$ix]{USE});
					}
				}
				else {
					error_msg __("No previous hunk\n");
				}
				next;
			}
			elsif ($line =~ /^j/) {
				if ($other !~ /j/) {
					error_msg __("No next hunk\n");
					next;
				}
			}
			elsif ($line =~ /^s/) {
				unless ($other =~ /s/) {
					error_msg __("Sorry, cannot split this hunk\n");
					next;
				}
				my @split = split_hunk($hunk[$ix]{TEXT}, $hunk[$ix]{DISPLAY});
				if (1 < @split) {
					print colored $header_color, sprintf(
						__n("Split into %d hunk.\n",
						    "Split into %d hunks.\n",
						    scalar(@split)), scalar(@split));
				}
				splice (@hunk, $ix, 1, @split);
				$num = scalar @hunk;
				next;
			}
			elsif ($line =~ /^e/) {
				unless ($other =~ /e/) {
					error_msg __("Sorry, cannot edit this hunk\n");
					next;
				}
				my $newhunk = edit_hunk_loop($head, \@hunk, $ix);
				if (defined $newhunk) {
					splice @hunk, $ix, 1, $newhunk;
				}
			}
			else {
				help_patch_cmd($other);
				next;
			}
			# soft increment
			while (1) {
				$ix++;
				last if ($ix >= $num ||
					 !defined $hunk[$ix]{USE});
			}
		}
	}

	@hunk = coalesce_overlapping_hunks(@hunk) if ($num);

	my $n_lofs = 0;
	my @result = ();
	for (@hunk) {
		if ($_->{USE}) {
			push @result, @{$_->{TEXT}};
		}
	}

	if (@result or $head->{USE}) {
		my @patch = reassemble_patch($head->{TEXT}, @result);
		my $apply_routine = $patch_mode_flavour{APPLY};
		&$apply_routine(@patch);
		refresh();
	}

	print "\n";
	return $quit;
}