# HG changeset patch # User Steve Losh # Date 1267660540 18000 # Node ID ddea94e8e13869d70d5e41c3429d3448717e18af # Parent f936bf37db174596948063cb4b911e6b336ce022 Refactor the diff-annotating functionality into the API. diff -r f936bf37db17 -r ddea94e8e138 review/api.py --- a/review/api.py Wed Mar 03 18:04:53 2010 -0500 +++ b/review/api.py Wed Mar 03 18:55:40 2010 -0500 @@ -369,6 +369,7 @@ self.node, filename, lines, message) comment._commit(self.ui, self.repo) + def full_diffs(self, filenames=None, opts={}): """Return full diffs of the given files (or all files). @@ -402,7 +403,7 @@ if not filenames: filenames = target_files else: - filenames = filter(lambda f: f in target_files, filenames) + filenames = filter(lambda f: self.has_diff(f), filenames) opts['unified'] = '100000' node2 = self.node @@ -457,8 +458,8 @@ There's a lot of structure there, but it will provide everything you need to display contextualized diffs. + """ - """ ds = self.full_diffs(filenames, {}) def _filter_diff(d): @@ -477,6 +478,83 @@ return ds + def annotated_diff(self, filename, context=5): + """Return a generator that yields annotated lines of a diff. + + The first item yielded will be a simple integer of the last line + number of the diff. This is ugly but useful when creating monospaced + line-number-prefixed output. + + Each line yielded will be of the form: + + { + # If 'skipped' is not None, this line is a "skip" line, which + # represents a group of lines that were skipped due to context. + 'skipped': 23, + + # The line number of this line, or None for skip lines. + 'number': 585, + + # The actual content of this line, or None for skip lines. + 'content': '+added line', + + # Any comments that apply to this line. + # If the line is a skip line, this will be any comments that apply + # to any line in the skipped group. + 'comments': [ReviewComment(), ReviewComment()], + } + """ + + diffs = self.diffs([filename], context).values() + if not diffs: + return + + diff = diffs[0] + max_line, content = diff['max'], diff['content'] + line_level_comments = self.line_level_comments(filename) + previous_n = -1 + + yield content[-1][0] + + for n, line in content: + if n - 1 > previous_n: + yield { + 'skipped': (n - previous_n) - (previous_n == -1 and 1 or 0), + 'number': None, 'content': None, + 'comments': filter( + lambda c: max(c.lines) in range(previous_n + 1, n), + line_level_comments + ), + } + + yield { + 'skipped': None, + 'number': n, 'content': line, + 'comments': filter( + lambda c: max(c.lines) == n, line_level_comments + ) + } + + previous_n = n + + if previous_n < max_line: + yield { + 'skipped': max_line - previous_n, + 'number': None, 'content': None, + 'comments': filter( + lambda c: max(c.lines) in range(previous_n + 1, max_line), + line_level_comments + ), + } + + def has_diff(self, filename): + """Return whether the given filename has a diff in this revision.""" + return filename in self.files() + + def files(self): + """Return the list of files in the revision for this ReviewChangeset.""" + return self.target[self.node].files() + def review_level_comments(self): """Comments on this changeset which aren't on a particular file.""" diff -r f936bf37db17 -r ddea94e8e138 review/extension_ui.py --- a/review/extension_ui.py Wed Mar 03 18:04:53 2010 -0500 +++ b/review/extension_ui.py Wed Mar 03 18:55:40 2010 -0500 @@ -147,6 +147,7 @@ ui.write(after) + if rcset.signoffs: ui.write('\n') for signoff in rcset.signoffs: @@ -161,53 +162,31 @@ if ui.quiet: return + if not fnames: + fnames = rcset.files() fnames = [sanitize_path(fname, repo) for fname in fnames] - diffs = rcset.diffs(fnames, context) + fnames = [fname for fname in fnames if rcset.has_diff(fname)] - for filename, diff in diffs.iteritems(): - max_line = diff['max'] - content = diff['content'] - + for filename in fnames: header = messages.REVIEW_LOG_FILE_HEADER % filename print '\n\n%s %s' % (header, '-'*(80-(len(header)+1))) for comment in rcset.file_level_comments(filename): _print_comment(comment) - line_level_comments = rcset.line_level_comments(filename) - prefix = '%%%dd: ' % len(str(content[-1][0])) - previous_n = -1 - for n, line in content: - if n - 1 > previous_n: - skipped = n - previous_n - if previous_n == -1: - skipped -= 1 - ui.write(messages.REVIEW_LOG_SKIPPED % skipped) - skipped_comments = filter( - lambda c: max(c.lines) in range(previous_n + 1, n), - line_level_comments - ) - for comment in skipped_comments: + annotated_diff = rcset.annotated_diff(filename, context) + prefix = '%%%dd: ' % len(str(annotated_diff.next())) + + for line in annotated_diff: + if line['skipped']: + ui.write(messages.REVIEW_LOG_SKIPPED % line['skipped']) + for comment in line['comments']: _print_comment(comment) + continue - ui.write('%s %s\n' % (prefix % n, line)) - - line_comments = filter( - lambda c: max(c.lines) == n, line_level_comments - ) - for comment in line_comments: - _print_comment(comment) + ui.write('%s %s\n' % (prefix % line['number'], line['content'])) - previous_n = n - - if previous_n < max_line: - skipped = max_line - previous_n - ui.write(messages.REVIEW_LOG_SKIPPED % skipped) - skipped_comments = filter( - lambda c: max(c.lines) in range(previous_n + 1, max_line), - line_level_comments - ) - for comment in skipped_comments: + for comment in line['comments']: _print_comment(comment)