diff --git a/git_cl.py b/git_cl.py index 0ea39e8c3..803ef2462 100755 --- a/git_cl.py +++ b/git_cl.py @@ -626,12 +626,20 @@ def _print_tryjobs(options, builds): print('Total: %d tryjobs' % total) -def _ComputeFormatDiffLineRanges(files, upstream_commit): +def _ComputeFormatDiffLineRanges(files, upstream_commit, expand=0): """Gets the changed line ranges for each file since upstream_commit. Parses a git diff on provided files and returns a dict that maps a file name to an ordered list of range tuples in the form (start_line, count). Ranges are in the same format as a git diff. + + Args: + files: List of paths to diff. + upstream_commit: Commit to diff against to find changed lines. + expand: Expand diff ranges by this many lines before & after. + + Returns: + A dict of path->[(start_line, end_line), ...] """ # If files is empty then diff_output will be a full diff. if len(files) == 0: @@ -662,6 +670,7 @@ def _ComputeFormatDiffLineRanges(files, upstream_commit): # Will match the second filename in diff --git a/a.py b/b.py. curr_file = match[0] line_diffs[curr_file] = [] + prev_end = 1 else: # Matches +14,3 if ',' in match[1]: @@ -673,10 +682,10 @@ def _ComputeFormatDiffLineRanges(files, upstream_commit): diff_start = int(diff_start) diff_count = int(diff_count) - diff_end = diff_start + diff_count - 1 - - # Only format added ranges (not removed ones). - if diff_end >= diff_start: + diff_end = diff_start + diff_count + expand + diff_start = max(prev_end + 1, diff_start - expand) + if diff_start <= diff_end: + prev_end = diff_end line_diffs[curr_file].append((diff_start, diff_end)) return line_diffs @@ -6136,10 +6145,26 @@ def _RunGoogleJavaFormat(opts, paths, top_dir, upstream_commit): changed_lines_only = not (opts.full or settings.GetFormatFullByDefault()) if changed_lines_only: - line_diffs = _ComputeFormatDiffLineRanges(paths, upstream_commit) + # Format two lines around each changed line so that the correct amount + # of blank lines will be added between symbols. + line_diffs = _ComputeFormatDiffLineRanges(paths, + upstream_commit, + expand=2) + + def RunFormat(cmd, path, range_args, **kwds): + stdout = RunCommand(cmd + range_args + [path], **kwds) + + if changed_lines_only: + # google-java-format will not remove unused imports because they + # do not fall within the changed lines. Run the command again to + # remove them. + if opts.diff: + stdout = RunCommand(cmd + ['--fix-imports-only', '-'], + stdin=stdout.encode(), + **kwds) + else: + stdout += RunCommand(cmd + ['--fix-imports-only', path], **kwds) - def RunFormat(cmd, path, **kwds): - stdout = RunCommand(cmd + [path], **kwds) # If --diff is passed, google-java-format will output formatted content. # Diff it with the existing file in the checkout and output the result. if opts.diff: @@ -6152,15 +6177,18 @@ def _RunGoogleJavaFormat(opts, paths, top_dir, upstream_commit): with multiprocessing.pool.ThreadPool() as pool: for path in paths: cmd = base_cmd.copy() + range_args = [] if changed_lines_only: ranges = line_diffs.get(path) if not ranges: # E.g. There were only deleted lines. continue - cmd.extend('--lines={}:{}'.format(a, b) for a, b in ranges) + range_args = ['--lines={}:{}'.format(a, b) for a, b in ranges] results.append( - pool.apply_async(RunFormat, args=[cmd, path], kwds=kwds)) + pool.apply_async(RunFormat, + args=[cmd, path, range_args], + kwds=kwds)) return_value = 0 for result in results: