diff --git a/.gitignore b/.gitignore index 11ca46f..512caa4 100644 --- a/.gitignore +++ b/.gitignore @@ -139,4 +139,5 @@ dmypy.json # Cython debug symbols cython_debug/ - +# JetBrains +.idea \ No newline at end of file diff --git a/main.py b/main.py index cbc6f0a..e592de3 100644 --- a/main.py +++ b/main.py @@ -413,7 +413,32 @@ class TodoParser(object): for marker in block['markers']: # Check if there are line or block comments. if marker['type'] == 'line': - comment_pattern = r'(^[+\-\s].*' + marker['pattern'] + r'\s.+$)' + # Add a negative lookup include the second character from alternative comment patterns + # This step is essential to handle cases like in Julia, where '#' and '#=' are comment patterns. + # It ensures that when a space after the comment is optional ('\s' => '\s*'), + # the second character would be matched because of the any character expression ('.+'). + suff_escape_list = [] + pref_escape_list = [] + for to_escape in block['markers']: + if to_escape['type'] == 'line': + if to_escape['pattern'] == marker['pattern']: + continue + if marker['pattern'][0] == to_escape['pattern'][0]: + suff_escape_list.append(self._extract_character(to_escape['pattern'], 1)) + else: + # Block comments and line comments cannot have the same comment pattern, + # so a check if the string is the same is unnecessary + if to_escape['pattern']['start'][0] == marker['pattern'][0]: + suff_escape_list.append(self._extract_character(to_escape['pattern']['start'], 1)) + search = to_escape['pattern']['end'].find(marker['pattern']) + if search != -1: + pref_escape_list.append(self._extract_character(to_escape['pattern']['end'], search - 1)) + + comment_pattern = (r'(^[+\-\s].*' + + (r'(? 0 else '') + + marker['pattern'] + + (r'(?!(' + '|'.join(suff_escape_list) + r'))' if len(suff_escape_list) > 0 else '') + + r'\s*.+$)') comments = re.finditer(comment_pattern, block['hunk'], re.MULTILINE) extracted_comments = [] prev_comment = None @@ -564,6 +589,26 @@ class TodoParser(object): escaped += c return escaped + @staticmethod + def _extract_character(input_str, pos): + # Extracts a character from the input string at the specified position, + # considering escape sequences when applicable. + # Test cases + # print(_extract_character("/\\*", 1)) # Output: "\*" + # print(_extract_character("\\*", 0)) # Output: "\*" + # print(_extract_character("\\", 0)) # Output: "\\" + # print(_extract_character("w", 0)) # Output: "w" + # print(_extract_character("wa", 1)) # Output: "a" + # print(_extract_character("\\\\w", 1)) # Output: "\\" + if input_str[pos] == '\\': + if pos >= 1 and not input_str[pos - 1] == '\\' and len(input_str) > pos + 1: + return '\\' + input_str[pos + 1] + return '\\\\' + if pos >= 1: + if input_str[pos - 1] == '\\': + return '\\' + input_str[pos] + return input_str[pos] + def _get_line_status(self, comment): """Return a Tuple indicating whether this is an addition/deletion/unchanged, plus the cleaned comment.""" addition_search = self.ADDITION_PATTERN.search(comment) diff --git a/tests/test_closed.diff b/tests/test_closed.diff index d3ee0fb..e8219ac 100644 --- a/tests/test_closed.diff +++ b/tests/test_closed.diff @@ -153,12 +153,17 @@ index 0000000..7cccc5b --- /dev/null +++ b/src/tests/example_file.jl @@ -0,0 +1,2 @@ -- # TODO: Hopefully this comment turns into an issue +- #TODO: Hopefully this comment turns into an issue +- # TODO: Hopefully this comment also turns into an issue - print("Hello World") - #= TODO: Multiline comments - also need to be turned into task, and hopefully - kept together as one. - =# +- #=TODO: Another copied multiline comment +- also need to be turned into task, and hopefully +- kept together as one. +- =# diff --git a/tests/defs.bzl b/tests/defs.bzl index 525e25d..ba4e68d 100644 --- a/tests/defs.bzl diff --git a/tests/test_todo_parser.py b/tests/test_todo_parser.py index d71bb0a..1f8a008 100644 --- a/tests/test_todo_parser.py +++ b/tests/test_todo_parser.py @@ -129,7 +129,7 @@ class ClosedIssueTests(unittest.TestCase): self.assertEqual(count_issues_for_file_type(self.raw_issues, 'tex'), 2) def test_julia_issues(self): - self.assertEqual(count_issues_for_file_type(self.raw_issues, 'julia'), 2) + self.assertEqual(count_issues_for_file_type(self.raw_issues, 'julia'), 4) def test_starlark_issues(self): self.assertEqual(count_issues_for_file_type(self.raw_issues, 'python'), 5)