diff --git a/pre_commit/languages/pygrep.py b/pre_commit/languages/pygrep.py index 878f57d0..7eead9e1 100644 --- a/pre_commit/languages/pygrep.py +++ b/pre_commit/languages/pygrep.py @@ -27,6 +27,23 @@ def _process_filename_by_line(pattern, filename): return retv +def _process_filename_at_once(pattern, filename): + retv = 0 + with open(filename, 'rb') as f: + contents = f.read() + match = pattern.search(contents) + if match: + retv = 1 + line_no = contents[:match.start()].count(b'\n') + output.write('{}:{}:'.format(filename, line_no + 1)) + + matched_lines = match.group().split(b'\n') + matched_lines[0] = contents.split(b'\n')[line_no] + + output.write_line(b'\n'.join(matched_lines)) + return retv + + def run_hook(prefix, hook, file_args): exe = (sys.executable, '-m', __name__) exe += tuple(hook['args']) + (hook['entry'],) @@ -42,16 +59,23 @@ def main(argv=None): ), ) parser.add_argument('-i', '--ignore-case', action='store_true') + parser.add_argument('--multiline', action='store_true') parser.add_argument('pattern', help='python regex pattern.') parser.add_argument('filenames', nargs='*') args = parser.parse_args(argv) flags = re.IGNORECASE if args.ignore_case else 0 + if args.multiline: + flags |= re.MULTILINE | re.DOTALL + pattern = re.compile(args.pattern.encode(), flags) retv = 0 for filename in args.filenames: - retv |= _process_filename_by_line(pattern, filename) + if args.multiline: + retv |= _process_filename_at_once(pattern, filename) + else: + retv |= _process_filename_by_line(pattern, filename) return retv diff --git a/tests/languages/pygrep_test.py b/tests/languages/pygrep_test.py index 048a5908..d91363e2 100644 --- a/tests/languages/pygrep_test.py +++ b/tests/languages/pygrep_test.py @@ -38,3 +38,31 @@ def test_ignore_case(some_files, cap_out): out = cap_out.get() assert ret == 1 assert out == 'f2:1:[INFO] hi\n' + + +def test_multiline(some_files, cap_out): + ret = pygrep.main(('--multiline', r'foo\nbar', 'f1', 'f2', 'f3')) + out = cap_out.get() + assert ret == 1 + assert out == 'f1:1:foo\nbar\n' + + +def test_multiline_line_number(some_files, cap_out): + ret = pygrep.main(('--multiline', r'ar', 'f1', 'f2', 'f3')) + out = cap_out.get() + assert ret == 1 + assert out == 'f1:2:bar\n' + + +def test_multiline_dotall_flag_is_enabled(some_files, cap_out): + ret = pygrep.main(('--multiline', r'o.*bar', 'f1', 'f2', 'f3')) + out = cap_out.get() + assert ret == 1 + assert out == 'f1:1:foo\nbar\n' + + +def test_multiline_multiline_flag_is_enabled(some_files, cap_out): + ret = pygrep.main(('--multiline', r'foo$.*bar', 'f1', 'f2', 'f3')) + out = cap_out.get() + assert ret == 1 + assert out == 'f1:1:foo\nbar\n'