From 9a95d624516ff6c5f65b4ababac98a0cd84b05f7 Mon Sep 17 00:00:00 2001 From: alstr Date: Fri, 4 Apr 2025 09:43:44 +0100 Subject: [PATCH] Improve handling of block comments Fixes #264 --- Issue.py | 4 +++- README.md | 3 --- TodoParser.py | 26 +++++++++++++++++++------- main.py | 2 +- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Issue.py b/Issue.py index 9b2c237..a3eb049 100644 --- a/Issue.py +++ b/Issue.py @@ -2,7 +2,8 @@ class Issue(object): """Basic Issue model for collecting the necessary info to send to GitHub.""" def __init__(self, title, labels, assignees, milestone, body, hunk, file_name, - start_line, num_lines, prefix, markdown_language, status, identifier, identifier_actual, ref, issue_url, issue_number, start_line_within_hunk=1): + start_line, num_lines, prefix, suffix, markdown_language, status, identifier, identifier_actual, + ref, issue_url, issue_number, start_line_within_hunk=1): self.title = title self.labels = labels self.assignees = assignees @@ -13,6 +14,7 @@ class Issue(object): self.start_line = start_line self.num_lines = num_lines self.prefix = prefix + self.suffix = suffix self.markdown_language = markdown_language self.status = status self.identifier = identifier diff --git a/README.md b/README.md index a54bcde..6d1b8ea 100644 --- a/README.md +++ b/README.md @@ -258,9 +258,6 @@ jobs: You will probably also want to use the setting `CLOSE_ISSUES: "true"`, to allow issues to be closed when a TODO is removed. -Please note, URL insertion works best with line comments, as it has to insert a line into the file. If using block -comments, you should put the start and end tags on their own lines. This may be improved in the future. - This feature is not perfect. Please make sure you're comfortable with that before enabling. ### Projects diff --git a/TodoParser.py b/TodoParser.py index 284eb02..1aa3be8 100644 --- a/TodoParser.py +++ b/TodoParser.py @@ -404,6 +404,15 @@ class TodoParser(object): """ return '\t'*num_tabs + ' '*num_spaces + @staticmethod + def _is_inline_block_comment(marker, line): + """ + Check if this is a block comment (with a start and end marker) on a single line. + """ + if marker['type'] == 'block': + return bool(re.match(fr'^[\s\+\-]*{marker["pattern"]["start"]}.*{marker["pattern"]["end"]}\s*$', line)) + return False + def _extract_issue_if_exists(self, comment_block, marker, hunk_info): """Check this comment for TODOs, and if found, build an Issue object.""" curr_issue = None @@ -438,9 +447,11 @@ class TodoParser(object): + comment_block['start'] + line_number_within_comment_block), start_line_within_hunk=comment_block['start'] + line_number_within_comment_block + 1, num_lines=1, - prefix=self._tabs_and_spaces(num_pre_marker_tabs, (pre_marker_length-num_pre_marker_tabs)) + - str(marker['pattern'] if marker['type'] == 'line' else '') + - self._tabs_and_spaces(num_post_marker_tabs, post_marker_length-num_post_marker_tabs), + prefix=self._tabs_and_spaces(num_pre_marker_tabs, (pre_marker_length - num_pre_marker_tabs)) + + str(marker['pattern'] if marker['type'] == 'line' else ( + marker['pattern']['start'] if self._is_inline_block_comment(marker, line) else '')) + + self._tabs_and_spaces(num_post_marker_tabs, post_marker_length - num_post_marker_tabs), + suffix=f' {marker["pattern"]["end"]}' if self._is_inline_block_comment(marker, line) else '', markdown_language=hunk_info['markdown_language'], status=line_status, identifier=identifier, @@ -547,14 +558,15 @@ class TodoParser(object): return LineStatus.DELETED, deletion_search.group(0) return LineStatus.UNCHANGED, comment[1:] - @staticmethod - def _clean_line(comment, marker): + def _clean_line(self, comment, marker): """Remove unwanted symbols and whitespace.""" post_marker_length = 0 num_post_marker_tabs = 0 if marker['type'] == 'block': original_comment = comment comment = comment.strip() + pre_marker_length = original_comment.find(comment) + num_pre_marker_tabs = comment.count('\t', 0, pre_marker_length) start_pattern = r'^' + marker['pattern']['start'] end_pattern = marker['pattern']['end'] + r'$' comment = re.sub(start_pattern, '', comment) @@ -563,8 +575,8 @@ class TodoParser(object): if '*' in start_pattern and comment.startswith('*'): comment = comment.lstrip('*') comment = comment.strip() - pre_marker_length = original_comment.find(comment) - num_pre_marker_tabs = comment.count('\t', 0, pre_marker_length) + if self._is_inline_block_comment(marker, original_comment): + post_marker_length = 1 else: comment_segments = re.search(fr'^(.*?)({marker["pattern"]})(\s*)(.*?)\s*$', comment) if comment_segments: diff --git a/main.py b/main.py index 59a0c36..f51d3c0 100644 --- a/main.py +++ b/main.py @@ -116,7 +116,7 @@ def process_diff(diff, client=Client(), insert_issue_urls=False, parser=TodoPars insert = f'Issue URL: {client.get_issue_url(new_issue_number)}' # note that the '\1' capture group is the line ending character sequence and # will only be non-empty in the case of a mixed line-endings file - new_line = re.sub('^.*'+remove, fr'{raw_issue.prefix + insert}\1', old_line) + new_line = re.sub('^.*' + remove, fr'{raw_issue.prefix + insert + raw_issue.suffix}\1', old_line) # make sure the above operation worked as intended if new_line != old_line: # Check if the URL line already exists, if so abort.