diff --git a/README.md b/README.md index 9ae7ec5b..9d342fd6 100644 --- a/README.md +++ b/README.md @@ -196,13 +196,14 @@ very specific format. You must opt in to this by setting [`files`](https://pre- #### `trailing-whitespace` -Trims trailing whitespace. +Detects and optionally trims trailing whitespace. + - By default, this hook trims all whitespace from the ends of lines. + To specify a custom set of characters to trim instead, use `args: [--chars,""]`. + To only lint files without fixing them, specify `--no-fix`. - To preserve Markdown [hard linebreaks](https://github.github.com/gfm/#hard-line-break) use `args: [--markdown-linebreak-ext=md]` (or other extensions used by your markdownfiles). If for some reason you want to treat all files as markdown, use `--markdown-linebreak-ext=*`. - - By default, this hook trims all whitespace from the ends of lines. - To specify a custom set of characters to trim instead, use `args: [--chars,""]`. ### Deprecated / replaced hooks diff --git a/pre_commit_hooks/trailing_whitespace_fixer.py b/pre_commit_hooks/trailing_whitespace_fixer.py index 84f50671..7495e75a 100644 --- a/pre_commit_hooks/trailing_whitespace_fixer.py +++ b/pre_commit_hooks/trailing_whitespace_fixer.py @@ -5,18 +5,20 @@ from typing import Sequence -def _fix_file( +def _process_file( filename: str, is_markdown: bool, chars: bytes | None, + fix: bool, ) -> bool: with open(filename, mode='rb') as file_processed: lines = file_processed.readlines() newlines = [_process_line(line, is_markdown, chars) for line in lines] if newlines != lines: - with open(filename, mode='wb') as file_processed: - for line in newlines: - file_processed.write(line) + if fix: + with open(filename, mode='wb') as file_processed: + for line in newlines: + file_processed.write(line) return True else: return False @@ -61,10 +63,29 @@ def main(argv: Sequence[str] | None = None) -> int: parser.add_argument( '--chars', help=( - 'The set of characters to strip from the end of lines. ' + 'The set of characters to consider as whitespace at the end of ' + 'lines. ' 'Defaults to all whitespace characters.' ), ) + parser.add_argument( + '--fix', + action='store_true', + help=( + 'Fix files by stripping detected trailing whitespace. ' + 'Default: On' + ), + ) + parser.add_argument( + '--no-fix', + dest='fix', + action='store_false', + help=( + 'Do not fix files by stripping detected trailing whitespace. ' + 'Default: Off, meaning files do get fixed.' + ), + ) + parser.set_defaults(fix=True) parser.add_argument('filenames', nargs='*', help='Filenames to fix') args = parser.parse_args(argv) @@ -93,8 +114,8 @@ def main(argv: Sequence[str] | None = None) -> int: for filename in args.filenames: _, extension = os.path.splitext(filename.lower()) md = all_markdown or extension in md_exts - if _fix_file(filename, md, chars): - print(f'Fixing {filename}') + if _process_file(filename, md, chars, args.fix): + print(('Fixing ' if args.fix else 'Not fixing ') + filename) return_code = 1 return return_code diff --git a/tests/trailing_whitespace_fixer_test.py b/tests/trailing_whitespace_fixer_test.py index c07497a2..78a74cb1 100644 --- a/tests/trailing_whitespace_fixer_test.py +++ b/tests/trailing_whitespace_fixer_test.py @@ -19,6 +19,21 @@ def test_fixes_trailing_whitespace(input_s, expected, tmpdir): assert path.read() == expected +@pytest.mark.parametrize( + ('arg', 'expected'), + ( + ('--fix', 'foo\nbar\n'), + ('--no-fix', 'foo \nbar \n'), + ), +) +def test_fix_no_fix(tmpdir, arg, expected): + input_s = 'foo \nbar \n' + path = tmpdir.join('file.txt') + path.write(input_s) + assert main((str(path), arg)) == 1 + assert path.read() == expected + + def test_ok_no_newline_end_of_file(tmpdir): filename = tmpdir.join('f') filename.write_binary(b'foo\nbar')