Improve handling of block comments

Fixes #264
This commit is contained in:
alstr 2025-04-04 09:43:44 +01:00
parent 0672dc170b
commit 9a95d62451
4 changed files with 23 additions and 12 deletions

View File

@ -2,7 +2,8 @@ class Issue(object):
"""Basic Issue model for collecting the necessary info to send to GitHub.""" """Basic Issue model for collecting the necessary info to send to GitHub."""
def __init__(self, title, labels, assignees, milestone, body, hunk, file_name, 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.title = title
self.labels = labels self.labels = labels
self.assignees = assignees self.assignees = assignees
@ -13,6 +14,7 @@ class Issue(object):
self.start_line = start_line self.start_line = start_line
self.num_lines = num_lines self.num_lines = num_lines
self.prefix = prefix self.prefix = prefix
self.suffix = suffix
self.markdown_language = markdown_language self.markdown_language = markdown_language
self.status = status self.status = status
self.identifier = identifier self.identifier = identifier

View File

@ -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 You will probably also want to use the setting `CLOSE_ISSUES: "true"`, to allow issues to be closed when a TODO is
removed. 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. This feature is not perfect. Please make sure you're comfortable with that before enabling.
### Projects ### Projects

View File

@ -404,6 +404,15 @@ class TodoParser(object):
""" """
return '\t'*num_tabs + ' '*num_spaces 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): def _extract_issue_if_exists(self, comment_block, marker, hunk_info):
"""Check this comment for TODOs, and if found, build an Issue object.""" """Check this comment for TODOs, and if found, build an Issue object."""
curr_issue = None curr_issue = None
@ -438,9 +447,11 @@ class TodoParser(object):
+ comment_block['start'] + line_number_within_comment_block), + comment_block['start'] + line_number_within_comment_block),
start_line_within_hunk=comment_block['start'] + line_number_within_comment_block + 1, start_line_within_hunk=comment_block['start'] + line_number_within_comment_block + 1,
num_lines=1, num_lines=1,
prefix=self._tabs_and_spaces(num_pre_marker_tabs, (pre_marker_length-num_pre_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 '') + str(marker['pattern'] if marker['type'] == 'line' else (
self._tabs_and_spaces(num_post_marker_tabs, post_marker_length-num_post_marker_tabs), 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'], markdown_language=hunk_info['markdown_language'],
status=line_status, status=line_status,
identifier=identifier, identifier=identifier,
@ -547,14 +558,15 @@ class TodoParser(object):
return LineStatus.DELETED, deletion_search.group(0) return LineStatus.DELETED, deletion_search.group(0)
return LineStatus.UNCHANGED, comment[1:] return LineStatus.UNCHANGED, comment[1:]
@staticmethod def _clean_line(self, comment, marker):
def _clean_line(comment, marker):
"""Remove unwanted symbols and whitespace.""" """Remove unwanted symbols and whitespace."""
post_marker_length = 0 post_marker_length = 0
num_post_marker_tabs = 0 num_post_marker_tabs = 0
if marker['type'] == 'block': if marker['type'] == 'block':
original_comment = comment original_comment = comment
comment = comment.strip() 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'] start_pattern = r'^' + marker['pattern']['start']
end_pattern = marker['pattern']['end'] + r'$' end_pattern = marker['pattern']['end'] + r'$'
comment = re.sub(start_pattern, '', comment) comment = re.sub(start_pattern, '', comment)
@ -563,8 +575,8 @@ class TodoParser(object):
if '*' in start_pattern and comment.startswith('*'): if '*' in start_pattern and comment.startswith('*'):
comment = comment.lstrip('*') comment = comment.lstrip('*')
comment = comment.strip() comment = comment.strip()
pre_marker_length = original_comment.find(comment) if self._is_inline_block_comment(marker, original_comment):
num_pre_marker_tabs = comment.count('\t', 0, pre_marker_length) post_marker_length = 1
else: else:
comment_segments = re.search(fr'^(.*?)({marker["pattern"]})(\s*)(.*?)\s*$', comment) comment_segments = re.search(fr'^(.*?)({marker["pattern"]})(\s*)(.*?)\s*$', comment)
if comment_segments: if comment_segments:

View File

@ -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)}' insert = f'Issue URL: {client.get_issue_url(new_issue_number)}'
# note that the '\1' capture group is the line ending character sequence and # 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 # 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 # make sure the above operation worked as intended
if new_line != old_line: if new_line != old_line:
# Check if the URL line already exists, if so abort. # Check if the URL line already exists, if so abort.