whitespace-format 0.0.5__py3-none-any.whl → 0.0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {whitespace_format-0.0.5.dist-info → whitespace_format-0.0.7.dist-info}/METADATA +11 -9
- whitespace_format-0.0.7.dist-info/RECORD +6 -0
- {whitespace_format-0.0.5.dist-info → whitespace_format-0.0.7.dist-info}/WHEEL +1 -1
- whitespace_format.py +439 -353
- whitespace_format-0.0.5.dist-info/RECORD +0 -6
- {whitespace_format-0.0.5.dist-info → whitespace_format-0.0.7.dist-info}/LICENSE +0 -0
- {whitespace_format-0.0.5.dist-info → whitespace_format-0.0.7.dist-info}/entry_points.txt +0 -0
@@ -1,12 +1,11 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.3
|
2
2
|
Name: whitespace-format
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.7
|
4
4
|
Summary: Linter and formatter for source code files and text files
|
5
|
-
Home-page: https://github.com/DavidPal/whitespace-format
|
6
5
|
License: MIT
|
7
6
|
Author: David Pal
|
8
7
|
Author-email: davidko.pal@gmail.com
|
9
|
-
Requires-Python: >=3.
|
8
|
+
Requires-Python: >=3.8.0,<4.0.0
|
10
9
|
Classifier: License :: OSI Approved :: MIT License
|
11
10
|
Classifier: Programming Language :: Python
|
12
11
|
Classifier: Programming Language :: Python :: 3
|
@@ -15,6 +14,8 @@ Classifier: Programming Language :: Python :: 3.9
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.10
|
16
15
|
Classifier: Programming Language :: Python :: 3.11
|
17
16
|
Classifier: Programming Language :: Python :: 3.12
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
18
|
+
Project-URL: Homepage, https://github.com/DavidPal/whitespace-format
|
18
19
|
Project-URL: Repository, https://github.com/DavidPal/whitespace-format
|
19
20
|
Description-Content-Type: text/markdown
|
20
21
|
|
@@ -50,7 +51,7 @@ second time (with the same parameters) has no effect.
|
|
50
51
|
pip install whitespace-format
|
51
52
|
```
|
52
53
|
|
53
|
-
Installation requires Python 3.
|
54
|
+
Installation requires Python 3.8.0 or higher.
|
54
55
|
|
55
56
|
## Usage
|
56
57
|
|
@@ -95,14 +96,15 @@ The regular expression is evaluated on the path of each file.
|
|
95
96
|
|
96
97
|
* `--add-new-line-marker-at-end-of-file` -- Add missing new line marker at end of each file.
|
97
98
|
* `--remove-new-line-marker-from-end-of-file` -- Remove all new line marker(s) from the end of each file.
|
98
|
-
This option
|
99
|
-
Empty lines at the end of the file are removed.
|
99
|
+
This option cannot be used in combination with `--add-new-line-marker-at-end-of-file`.
|
100
|
+
Empty lines at the end of the file are removed, i.e., this option implies `--remove-trailing-empty-lines`
|
101
|
+
option.
|
100
102
|
* `--normalize-new-line-markers` -- Make new line markers consistent in each file
|
101
103
|
by replacing `\r\n`, `\n`, and `\r` with a consistent new line marker.
|
102
104
|
* `--remove-trailing-whitespace` -- Remove whitespace at the end of each line.
|
103
105
|
* `--remove-trailing-empty-lines` -- Remove empty lines at the end of each file.
|
104
|
-
* `--new-line-marker=MARKER` -- This option specifies what new line marker to
|
105
|
-
`MARKER` must be one of the following:
|
106
|
+
* `--new-line-marker=MARKER` -- This option specifies what new line marker to when
|
107
|
+
adding or replacing new line markers. `MARKER` must be one of the following:
|
106
108
|
* `auto` -- Use new line marker that is the most common in each individual file.
|
107
109
|
If no new line marker is present in the file, Linux `\n` is used.
|
108
110
|
This is the default option.
|
@@ -0,0 +1,6 @@
|
|
1
|
+
whitespace_format.py,sha256=Jl5SqNgDhgG9GixsCtTk2bFwri3Ez6msa8Asrqe99os,28942
|
2
|
+
whitespace_format-0.0.7.dist-info/LICENSE,sha256=rT6UNfWDYFQc-eo65FioDJRMAyVOndtF95wNCUhkK74,1076
|
3
|
+
whitespace_format-0.0.7.dist-info/METADATA,sha256=n9Nta0jpn-EVz1gVaMNtU7SuyAN9eECs87N0l3FIcvw,10411
|
4
|
+
whitespace_format-0.0.7.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
5
|
+
whitespace_format-0.0.7.dist-info/entry_points.txt,sha256=LbXoevzUZAF5MVbI2foNC9xeDjKS_Woz7VbA1ZNF5CY,60
|
6
|
+
whitespace_format-0.0.7.dist-info/RECORD,,
|
whitespace_format.py
CHANGED
@@ -3,7 +3,8 @@
|
|
3
3
|
"""Formatter of whitespace in text files.
|
4
4
|
|
5
5
|
Author: David Pal <davidko.pal@gmail.com>
|
6
|
-
Date: 2023
|
6
|
+
Date: 2023 - 2024
|
7
|
+
License: MIT License
|
7
8
|
|
8
9
|
Usage:
|
9
10
|
|
@@ -13,21 +14,37 @@ Usage:
|
|
13
14
|
from __future__ import annotations
|
14
15
|
|
15
16
|
import argparse
|
16
|
-
import copy
|
17
17
|
import dataclasses
|
18
18
|
import pathlib
|
19
19
|
import re
|
20
20
|
import sys
|
21
|
-
from
|
22
|
-
from typing import Dict
|
21
|
+
from enum import Enum
|
23
22
|
from typing import List
|
23
|
+
from typing import Tuple
|
24
24
|
|
25
|
-
VERSION = "0.0.
|
25
|
+
VERSION = "0.0.7"
|
26
26
|
|
27
27
|
# Regular expression that does NOT match any string.
|
28
28
|
UNMATCHABLE_REGEX = "$."
|
29
29
|
|
30
|
-
|
30
|
+
# Whitespace characters
|
31
|
+
CARRIAGE_RETURN = "\r"
|
32
|
+
LINE_FEED = "\n"
|
33
|
+
SPACE = " "
|
34
|
+
TAB = "\t"
|
35
|
+
VERTICAL_TAB = "\v"
|
36
|
+
FORM_FEED = "\f"
|
37
|
+
|
38
|
+
WHITESPACE_CHARACTERS = {
|
39
|
+
CARRIAGE_RETURN,
|
40
|
+
LINE_FEED,
|
41
|
+
SPACE,
|
42
|
+
TAB,
|
43
|
+
VERTICAL_TAB,
|
44
|
+
FORM_FEED,
|
45
|
+
}
|
46
|
+
|
47
|
+
NEW_LINE_MARKERS = {
|
31
48
|
"windows": "\r\n",
|
32
49
|
"linux": "\n",
|
33
50
|
"mac": "\r",
|
@@ -59,6 +76,122 @@ COLORS = {
|
|
59
76
|
"WHITE": "\033[97m",
|
60
77
|
}
|
61
78
|
|
79
|
+
ESCAPE_TRANSLATION_TABLE = str.maketrans(
|
80
|
+
{
|
81
|
+
CARRIAGE_RETURN: "\\r",
|
82
|
+
LINE_FEED: "\\n",
|
83
|
+
TAB: "\\t",
|
84
|
+
VERTICAL_TAB: "\\v",
|
85
|
+
FORM_FEED: "\\f",
|
86
|
+
}
|
87
|
+
)
|
88
|
+
|
89
|
+
|
90
|
+
class ChangeType(Enum):
|
91
|
+
"""Type of change that happened to a file."""
|
92
|
+
|
93
|
+
# New line marker was added to the end of the file (because it was missing).
|
94
|
+
ADDED_NEW_LINE_MARKER_TO_END_OF_FILE = 1
|
95
|
+
|
96
|
+
# New line marker was removed from the end of the file.
|
97
|
+
REMOVED_NEW_LINE_MARKER_FROM_END_OF_FILE = 2
|
98
|
+
|
99
|
+
# New line marker was replaced by another one.
|
100
|
+
REPLACED_NEW_LINE_MARKER = 3
|
101
|
+
|
102
|
+
# White at the end of a line was removed.
|
103
|
+
REMOVED_TRAILING_WHITESPACE = 4
|
104
|
+
|
105
|
+
# Empty line(s) at the end of file were removed.
|
106
|
+
REMOVED_EMPTY_LINES = 5
|
107
|
+
|
108
|
+
# An empty file was replaced by a file consisting of single empty line.
|
109
|
+
REPLACED_EMPTY_FILE_WITH_ONE_LINE = 6
|
110
|
+
|
111
|
+
# A file consisting of only whitespace was replaced by an empty file.
|
112
|
+
REPLACED_WHITESPACE_ONLY_FILE_WITH_EMPTY_FILE = 7
|
113
|
+
|
114
|
+
# A file consisting of only whitespace was replaced by a file consisting of single empty line.
|
115
|
+
REPLACED_WHITESPACE_ONLY_FILE_WITH_ONE_LINE = 8
|
116
|
+
|
117
|
+
# A tab character was replaces by space character(s).
|
118
|
+
REPLACED_TAB_WITH_SPACES = 9
|
119
|
+
|
120
|
+
# A tab character was removed.
|
121
|
+
REMOVED_TAB = 10
|
122
|
+
|
123
|
+
# A non-standard whitespace character (`\f` or `\v`) was replaced by a space character.
|
124
|
+
REPLACED_NONSTANDARD_WHITESPACE = 11
|
125
|
+
|
126
|
+
# A non-standard whitespace character (`\f` or `\v`) was removed.
|
127
|
+
REMOVED_NONSTANDARD_WHITESPACE = 12
|
128
|
+
|
129
|
+
|
130
|
+
@dataclasses.dataclass
|
131
|
+
class Change:
|
132
|
+
"""Description of a change of the content of a file."""
|
133
|
+
|
134
|
+
change_type: ChangeType
|
135
|
+
line_number: int
|
136
|
+
changed_from: str = ""
|
137
|
+
changed_to: str = ""
|
138
|
+
|
139
|
+
def message(self, check_only: bool) -> str:
|
140
|
+
"""Returns a message describing the change."""
|
141
|
+
check_only_word = " would be " if check_only else " "
|
142
|
+
|
143
|
+
if self.change_type == ChangeType.ADDED_NEW_LINE_MARKER_TO_END_OF_FILE:
|
144
|
+
return f"New line marker{check_only_word}added to the end of the file."
|
145
|
+
|
146
|
+
if self.change_type == ChangeType.REMOVED_NEW_LINE_MARKER_FROM_END_OF_FILE:
|
147
|
+
return f"New line marker{check_only_word}removed from the end of the file."
|
148
|
+
|
149
|
+
if self.change_type == ChangeType.REPLACED_NEW_LINE_MARKER:
|
150
|
+
return (
|
151
|
+
f"New line marker '{escape_chars(self.changed_from)}'"
|
152
|
+
f"{check_only_word}replaced by '{escape_chars(self.changed_to)}'."
|
153
|
+
)
|
154
|
+
|
155
|
+
if self.change_type == ChangeType.REMOVED_TRAILING_WHITESPACE:
|
156
|
+
return f"Trailing whitespace{check_only_word}removed."
|
157
|
+
|
158
|
+
if self.change_type == ChangeType.REMOVED_EMPTY_LINES:
|
159
|
+
return f"Empty line(s) at the end of the file{check_only_word}removed."
|
160
|
+
|
161
|
+
if self.change_type == ChangeType.REPLACED_EMPTY_FILE_WITH_ONE_LINE:
|
162
|
+
return f"Empty file{check_only_word}replaced with a single empty line."
|
163
|
+
|
164
|
+
if self.change_type == ChangeType.REPLACED_WHITESPACE_ONLY_FILE_WITH_EMPTY_FILE:
|
165
|
+
return f"File{check_only_word}replaced with an empty file."
|
166
|
+
|
167
|
+
if self.change_type == ChangeType.REPLACED_WHITESPACE_ONLY_FILE_WITH_ONE_LINE:
|
168
|
+
return f"File{check_only_word}replaced with a single empty line."
|
169
|
+
|
170
|
+
if self.change_type == ChangeType.REPLACED_TAB_WITH_SPACES:
|
171
|
+
return f"Tab{check_only_word}replaced with spaces."
|
172
|
+
|
173
|
+
if self.change_type == ChangeType.REMOVED_TAB:
|
174
|
+
return f"Tab{check_only_word}removed."
|
175
|
+
|
176
|
+
if self.change_type == ChangeType.REPLACED_NONSTANDARD_WHITESPACE:
|
177
|
+
return (
|
178
|
+
f"Non-standard whitespace character '{escape_chars(self.changed_from)}'"
|
179
|
+
f"{check_only_word}replaced by a space."
|
180
|
+
)
|
181
|
+
|
182
|
+
if self.change_type == ChangeType.REMOVED_NONSTANDARD_WHITESPACE:
|
183
|
+
return f"Non-standard whitespace character '{escape_chars(self.changed_from)}'{check_only_word}removed."
|
184
|
+
|
185
|
+
raise ValueError(f"Unknown change type: {self.change_type}")
|
186
|
+
|
187
|
+
def color_print(self, parsed_arguments: argparse.Namespace) -> None:
|
188
|
+
"""Prints a message in color."""
|
189
|
+
color_print(
|
190
|
+
f"[BOLD][BLUE]↳ line {self.line_number}: "
|
191
|
+
f"[WHITE]{self.message(parsed_arguments.check_only)}[RESET_ALL]",
|
192
|
+
parsed_arguments,
|
193
|
+
)
|
194
|
+
|
62
195
|
|
63
196
|
def color_print(message: str, parsed_arguments: argparse.Namespace):
|
64
197
|
"""Outputs a colored message."""
|
@@ -72,6 +205,11 @@ def color_print(message: str, parsed_arguments: argparse.Namespace):
|
|
72
205
|
print(message)
|
73
206
|
|
74
207
|
|
208
|
+
def escape_chars(text: str) -> str:
|
209
|
+
"""Escapes special characters in a string."""
|
210
|
+
return text.translate(ESCAPE_TRANSLATION_TABLE)
|
211
|
+
|
212
|
+
|
75
213
|
def string_to_hex(text: str) -> str:
|
76
214
|
"""Converts a string into a human-readable hexadecimal representation.
|
77
215
|
|
@@ -88,7 +226,10 @@ def die(error_code: int, message: str = ""):
|
|
88
226
|
|
89
227
|
|
90
228
|
def read_file_content(file_name: str, encoding: str) -> str:
|
91
|
-
"""Reads content of a file.
|
229
|
+
"""Reads content of a file.
|
230
|
+
|
231
|
+
New line markers are preserved in their original form.
|
232
|
+
"""
|
92
233
|
try:
|
93
234
|
with open(file_name, "r", encoding=encoding, newline="") as file:
|
94
235
|
return file.read()
|
@@ -108,369 +249,298 @@ def write_file(file_name: str, file_content: str, encoding: str):
|
|
108
249
|
die(4, f"Cannot write to file '{file_name}': {exception}")
|
109
250
|
|
110
251
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
The line is split into two parts:
|
116
|
-
1) Content
|
117
|
-
2) End of line marker ("\n", or "\r", or "\r\n")
|
118
|
-
"""
|
119
|
-
|
120
|
-
content: str
|
121
|
-
end_of_line_marker: str
|
122
|
-
|
123
|
-
@staticmethod
|
124
|
-
def create_from_string(line: str) -> Line:
|
125
|
-
"""Creates a line from a string.
|
126
|
-
|
127
|
-
The function splits the input into content and end_of_line_marker.
|
128
|
-
"""
|
129
|
-
for end_of_line_marker in ["\r\n", "\n", "\r"]:
|
130
|
-
if line.endswith(end_of_line_marker):
|
131
|
-
return Line(line[: -len(end_of_line_marker)], end_of_line_marker)
|
132
|
-
return Line(line, "")
|
133
|
-
|
134
|
-
def to_hex(self):
|
135
|
-
"""Returns a human-readable hexadecimal representation of the line.
|
136
|
-
|
137
|
-
This function is for debugging purposes only. It is used only during development.
|
138
|
-
"""
|
139
|
-
return f"({string_to_hex(self.content)}, {string_to_hex(self.end_of_line_marker)})"
|
140
|
-
|
141
|
-
|
142
|
-
def split_lines(text: str) -> List[Line]:
|
143
|
-
"""Splits a string into lines."""
|
144
|
-
lines: List[Line] = []
|
145
|
-
current_line = ""
|
146
|
-
for i, char in enumerate(text):
|
147
|
-
current_line += char
|
148
|
-
if (char == "\n") or (
|
149
|
-
(char == "\r") and ((i >= len(text) - 1) or (not text[i + 1] == "\n"))
|
150
|
-
):
|
151
|
-
lines.append(Line.create_from_string(current_line))
|
152
|
-
current_line = ""
|
153
|
-
|
154
|
-
if current_line:
|
155
|
-
lines.append(Line.create_from_string(current_line))
|
156
|
-
|
157
|
-
return lines
|
158
|
-
|
159
|
-
|
160
|
-
def concatenate_lines(lines: List[Line]) -> str:
|
161
|
-
"""Concatenates a list of lines into a single string including end-of-line markers."""
|
162
|
-
return "".join(line.content + line.end_of_line_marker for line in lines)
|
163
|
-
|
164
|
-
|
165
|
-
def guess_end_of_line_marker(lines: List[Line]) -> str:
|
166
|
-
"""Guesses the end of line marker.
|
167
|
-
|
168
|
-
The function returns the most common end-of-line marker.
|
169
|
-
Ties are broken in order Linux "\n", Mac "\r", Windows "\r\n".
|
170
|
-
If no end-of-line marker is present, default to the Linux "\n" end-of-line marker.
|
171
|
-
"""
|
172
|
-
counts: Dict[str, int] = {"\n": 0, "\r": 0, "\r\n": 0}
|
173
|
-
for line in lines:
|
174
|
-
if line.end_of_line_marker in counts:
|
175
|
-
counts[line.end_of_line_marker] += 1
|
176
|
-
max_count = max(counts.values())
|
177
|
-
for end_of_line_marker, count in counts.items():
|
178
|
-
if count == max_count:
|
179
|
-
return end_of_line_marker
|
180
|
-
return "\n" # This return statement is never executed.
|
181
|
-
|
182
|
-
|
183
|
-
def remove_trailing_empty_lines(lines: List[Line]) -> List[Line]:
|
184
|
-
"""Removes trailing empty lines.
|
185
|
-
|
186
|
-
If there are no lines, empty list is returned.
|
187
|
-
If all lines are empty, the first line is kept.
|
188
|
-
"""
|
189
|
-
num_empty_trailing_lines = 0
|
190
|
-
while (num_empty_trailing_lines < len(lines) - 1) and (
|
191
|
-
not lines[-num_empty_trailing_lines - 1].content
|
192
|
-
):
|
193
|
-
num_empty_trailing_lines += 1
|
194
|
-
return copy.deepcopy(lines[: len(lines) - num_empty_trailing_lines])
|
195
|
-
|
196
|
-
|
197
|
-
def remove_dummy_lines(lines: List[Line]) -> List[Line]:
|
198
|
-
"""Remove empty lines that also have empty end-of-line markers."""
|
199
|
-
return [line for line in lines if line.content or line.end_of_line_marker]
|
200
|
-
|
201
|
-
|
202
|
-
def remove_trailing_whitespace(lines: List[Line]) -> List[Line]:
|
203
|
-
"""Removes trailing whitespace from every line."""
|
204
|
-
lines = [
|
205
|
-
Line(
|
206
|
-
re.sub(r"[ \n\r\t\f\v]*$", "", line.content),
|
207
|
-
line.end_of_line_marker,
|
208
|
-
)
|
209
|
-
for line in lines
|
210
|
-
]
|
211
|
-
return remove_dummy_lines(lines)
|
212
|
-
|
213
|
-
|
214
|
-
def normalize_end_of_line_markers(lines: List[Line], new_end_of_line_marker: str) -> List[Line]:
|
215
|
-
"""Replaces end-of-line marker in all lines with a new end-of-line marker.
|
216
|
-
|
217
|
-
Lines without end-of-line markers (i.e. possibly the last line) are left unchanged.
|
218
|
-
"""
|
219
|
-
return [
|
220
|
-
Line(line.content, new_end_of_line_marker) if line.end_of_line_marker else line
|
221
|
-
for line in lines
|
222
|
-
]
|
223
|
-
|
224
|
-
|
225
|
-
def remove_all_end_of_line_markers_from_end_of_file(lines: List[Line]) -> List[Line]:
|
226
|
-
"""Removes all end-of-line markers from the end of the file."""
|
227
|
-
lines = remove_trailing_empty_lines(lines)
|
228
|
-
if not lines:
|
229
|
-
return []
|
230
|
-
lines[-1] = Line(lines[-1].content, "")
|
231
|
-
return remove_dummy_lines(lines)
|
232
|
-
|
233
|
-
|
234
|
-
def add_end_of_line_marker_at_end_of_file(
|
235
|
-
lines: List[Line], new_end_of_line_marker: str
|
236
|
-
) -> List[Line]:
|
237
|
-
"""Adds new end-of-line marker to the end of file if it is missing."""
|
238
|
-
if not lines:
|
239
|
-
return [Line("", new_end_of_line_marker)]
|
240
|
-
lines = copy.deepcopy(lines)
|
241
|
-
lines[-1] = Line(lines[-1].content, new_end_of_line_marker)
|
242
|
-
return lines
|
243
|
-
|
244
|
-
|
245
|
-
def normalize_empty_file(lines: List[Line], mode: str, new_end_of_line_marker: str) -> List[Line]:
|
246
|
-
"""Replaces file with an empty file."""
|
247
|
-
if mode == "empty":
|
248
|
-
return []
|
249
|
-
if mode == "one-line":
|
250
|
-
return [Line("", new_end_of_line_marker)]
|
251
|
-
return copy.deepcopy(lines)
|
252
|
-
|
253
|
-
|
254
|
-
def is_whitespace_only(lines: List[Line]) -> bool:
|
255
|
-
"""Determines if file consists only of whitespace."""
|
256
|
-
for line in lines:
|
257
|
-
if line.content.strip(" \n\r\t\v\f"):
|
252
|
+
def is_whitespace_only(text: str) -> bool:
|
253
|
+
"""Determines if a string consists of only whitespace characters."""
|
254
|
+
for char in text:
|
255
|
+
if char not in WHITESPACE_CHARACTERS:
|
258
256
|
return False
|
259
257
|
return True
|
260
258
|
|
261
259
|
|
262
|
-
def
|
263
|
-
"""
|
264
|
-
if mode == "ignore":
|
265
|
-
return copy.deepcopy(lines)
|
266
|
-
if mode == "replace":
|
267
|
-
return [
|
268
|
-
Line(line.content.translate(str.maketrans("\v\f", " ", "")), line.end_of_line_marker)
|
269
|
-
for line in lines
|
270
|
-
]
|
271
|
-
return [
|
272
|
-
Line(line.content.translate(str.maketrans("", "", "\v\f")), line.end_of_line_marker)
|
273
|
-
for line in lines
|
274
|
-
]
|
275
|
-
|
276
|
-
|
277
|
-
def replace_tabs_with_spaces(lines: List[Line], num_spaces: int) -> List[Line]:
|
278
|
-
"""Replaces tabs with spaces."""
|
279
|
-
if num_spaces < 0:
|
280
|
-
return copy.deepcopy(lines)
|
281
|
-
return [
|
282
|
-
Line(line.content.replace("\t", num_spaces * " "), line.end_of_line_marker)
|
283
|
-
for line in lines
|
284
|
-
]
|
285
|
-
|
286
|
-
|
287
|
-
def compute_difference(original_lines: List[Line], new_lines: List[Line]) -> List[int]:
|
288
|
-
"""Computes the indices of lines that differ."""
|
289
|
-
line_numbers = [
|
290
|
-
line_number
|
291
|
-
for line_number, (original_line, new_line) in enumerate(zip(original_lines, new_lines))
|
292
|
-
if not original_line == new_line
|
293
|
-
]
|
294
|
-
if len(original_lines) != len(new_lines):
|
295
|
-
line_numbers.append(min(len(original_lines), len(new_lines)))
|
296
|
-
return line_numbers
|
297
|
-
|
260
|
+
def find_most_common_new_line_marker(text: str) -> str:
|
261
|
+
"""Returns the most common new line marker in a string.
|
298
262
|
|
299
|
-
|
300
|
-
|
301
|
-
"""Description of a change of the content of a file."""
|
263
|
+
If there are ties, prefer Linux '\n' to Windows '\r\n' to Mac '\r'.
|
264
|
+
If there are no new line markers, return Linux.
|
302
265
|
|
303
|
-
|
304
|
-
|
266
|
+
Args:
|
267
|
+
text: A string.
|
305
268
|
|
269
|
+
Returns:
|
270
|
+
Either '\n', or '\r\n' or '\r'.
|
271
|
+
"""
|
272
|
+
linux_count = 0
|
273
|
+
mac_count = 0
|
274
|
+
windows_count = 0
|
275
|
+
i = 0
|
306
276
|
|
307
|
-
|
308
|
-
|
309
|
-
|
277
|
+
while i < len(text):
|
278
|
+
if text[i] == CARRIAGE_RETURN:
|
279
|
+
if i < len(text) - 1 and text[i + 1] == LINE_FEED:
|
280
|
+
windows_count += 1
|
281
|
+
i += 1
|
282
|
+
else:
|
283
|
+
mac_count += 1
|
284
|
+
elif text[i] == LINE_FEED:
|
285
|
+
linux_count += 1
|
286
|
+
i += 1
|
310
287
|
|
311
|
-
|
312
|
-
|
313
|
-
line_number: int
|
288
|
+
if mac_count > windows_count and mac_count > linux_count:
|
289
|
+
return "\r"
|
314
290
|
|
291
|
+
if windows_count > linux_count:
|
292
|
+
return "\r\n"
|
315
293
|
|
316
|
-
|
317
|
-
"""Tracks changes of the content of a file as it undergoes formatting."""
|
294
|
+
return "\n"
|
318
295
|
|
319
|
-
def __init__(self, lines: List[Line]):
|
320
|
-
"""Initializes an instance of the file content tracker."""
|
321
|
-
self.initial_lines = lines
|
322
|
-
self.lines = copy.deepcopy(lines)
|
323
|
-
self.line_changes: List[LineChange] = []
|
324
296
|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
line_numbers = compute_difference(previous_content, self.lines)
|
331
|
-
for line_number in line_numbers:
|
332
|
-
self.line_changes.append(LineChange(change.check_only, change.change, line_number))
|
297
|
+
def format_file_content(
|
298
|
+
file_content: str,
|
299
|
+
parsed_arguments: argparse.Namespace,
|
300
|
+
) -> Tuple[str, List[Change]]:
|
301
|
+
"""Formats content of a file.
|
333
302
|
|
334
|
-
|
335
|
-
"""Determines if the file content has changed."""
|
336
|
-
return self.lines != self.initial_lines
|
303
|
+
The formatting options are specified in the parsed_arguments.
|
337
304
|
|
305
|
+
Args:
|
306
|
+
file_content: Content of the file.
|
307
|
+
parsed_arguments: Parsed command line arguments.
|
338
308
|
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
"""Formats the content of file represented as a string."""
|
344
|
-
new_line_marker = END_OF_LINE_MARKERS.get(
|
309
|
+
Returns:
|
310
|
+
A pair consisting of the formatted file content and a list of changes.
|
311
|
+
"""
|
312
|
+
output_new_line_marker = NEW_LINE_MARKERS.get(
|
345
313
|
parsed_arguments.new_line_marker,
|
346
|
-
|
314
|
+
find_most_common_new_line_marker(file_content),
|
347
315
|
)
|
348
316
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
"
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
317
|
+
# Handle empty file:
|
318
|
+
if not file_content:
|
319
|
+
if parsed_arguments.normalize_empty_files in ["ignore", "empty"]:
|
320
|
+
return "", []
|
321
|
+
if parsed_arguments.normalize_empty_files == "one-line":
|
322
|
+
return output_new_line_marker, [Change(ChangeType.REPLACED_EMPTY_FILE_WITH_ONE_LINE, 1)]
|
323
|
+
|
324
|
+
# Handle non-empty file consisting of whitespace only.
|
325
|
+
if is_whitespace_only(file_content):
|
326
|
+
if parsed_arguments.normalize_whitespace_only_files == "empty":
|
327
|
+
return "", [Change(ChangeType.REPLACED_WHITESPACE_ONLY_FILE_WITH_EMPTY_FILE, 1)]
|
328
|
+
if parsed_arguments.normalize_whitespace_only_files == "one-line":
|
329
|
+
if file_content == output_new_line_marker:
|
330
|
+
return file_content, []
|
331
|
+
return output_new_line_marker, [
|
332
|
+
Change(ChangeType.REPLACED_WHITESPACE_ONLY_FILE_WITH_ONE_LINE, 1)
|
333
|
+
]
|
334
|
+
if parsed_arguments.normalize_whitespace_only_files == "ignore":
|
335
|
+
return file_content, []
|
336
|
+
|
337
|
+
# Index into the input buffer.
|
338
|
+
i = 0
|
339
|
+
|
340
|
+
# List of changes
|
341
|
+
changes: List[Change] = []
|
342
|
+
|
343
|
+
# Line number. It is incremented every time we encounter a new end of line marker.
|
344
|
+
line_number = 1
|
345
|
+
|
346
|
+
# Position one character past the end of last line in the output buffer
|
347
|
+
# including the last end of line marker.
|
348
|
+
last_end_of_line_including_eol_marker = 0
|
349
|
+
|
350
|
+
# Position one character past the last non-whitespace character in the output buffer.
|
351
|
+
last_non_whitespace = 0
|
352
|
+
|
353
|
+
# Position one character past the end of last non-empty line in the output buffer
|
354
|
+
# excluding the last end of line marker.
|
355
|
+
last_end_of_non_empty_line_excluding_eol_marker = 0
|
356
|
+
|
357
|
+
# Position one character past the end of last non-empty line in the output buffer,
|
358
|
+
# including the last end of line marker.
|
359
|
+
last_end_of_non_empty_line_including_eol_marker = 0
|
360
|
+
|
361
|
+
# Line number of the last non-empty line.
|
362
|
+
last_non_empty_line_number = 0
|
363
|
+
|
364
|
+
# Formatted output
|
365
|
+
output = ""
|
366
|
+
|
367
|
+
while i < len(file_content):
|
368
|
+
if file_content[i] in [CARRIAGE_RETURN, LINE_FEED]:
|
369
|
+
# Parse the new line marker
|
370
|
+
new_line_marker = ""
|
371
|
+
if file_content[i] == LINE_FEED:
|
372
|
+
new_line_marker = LINE_FEED
|
373
|
+
elif i < len(file_content) - 1 and file_content[i + 1] == LINE_FEED:
|
374
|
+
new_line_marker = "\r\n"
|
375
|
+
# Windows new line marker consists of two characters.
|
376
|
+
# Skip the extra character.
|
377
|
+
i += 1
|
378
|
+
else:
|
379
|
+
new_line_marker = CARRIAGE_RETURN
|
380
|
+
|
381
|
+
# Remove trailing whitespace
|
382
|
+
if parsed_arguments.remove_trailing_whitespace and max(
|
383
|
+
last_non_whitespace, last_end_of_line_including_eol_marker
|
384
|
+
) < len(output):
|
385
|
+
changes.append(
|
386
|
+
Change(
|
387
|
+
ChangeType.REMOVED_TRAILING_WHITESPACE,
|
388
|
+
line_number,
|
389
|
+
)
|
390
|
+
)
|
391
|
+
output = output[
|
392
|
+
: max(
|
393
|
+
last_non_whitespace,
|
394
|
+
last_end_of_line_including_eol_marker,
|
395
|
+
)
|
396
|
+
]
|
397
|
+
|
398
|
+
# Determine if the last line is empty
|
399
|
+
is_empty_line: bool = last_end_of_line_including_eol_marker == len(output)
|
400
|
+
|
401
|
+
# Position one character past the end of last line in the output buffer
|
402
|
+
# excluding the last end of line marker.
|
403
|
+
last_end_of_line_excluding_eol_marker = len(output)
|
404
|
+
|
405
|
+
# Add new line marker
|
406
|
+
if (
|
407
|
+
parsed_arguments.normalize_new_line_markers
|
408
|
+
and output_new_line_marker != new_line_marker
|
409
|
+
):
|
410
|
+
changes.append(
|
411
|
+
Change(
|
412
|
+
ChangeType.REPLACED_NEW_LINE_MARKER,
|
413
|
+
line_number,
|
414
|
+
new_line_marker,
|
415
|
+
output_new_line_marker,
|
416
|
+
)
|
417
|
+
)
|
418
|
+
output += output_new_line_marker
|
419
|
+
else:
|
420
|
+
output += new_line_marker
|
389
421
|
|
390
|
-
|
391
|
-
file_content_tracker.format(
|
392
|
-
ChangeDescription(
|
393
|
-
check_only="Empty line(s) at the end of file need to be removed.",
|
394
|
-
change="Empty line(s) at the end of file were removed.",
|
395
|
-
),
|
396
|
-
remove_trailing_empty_lines,
|
397
|
-
)
|
422
|
+
last_end_of_line_including_eol_marker = len(output)
|
398
423
|
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
424
|
+
# Update position of last non-empty line.
|
425
|
+
if not is_empty_line:
|
426
|
+
last_end_of_non_empty_line_excluding_eol_marker = (
|
427
|
+
last_end_of_line_excluding_eol_marker
|
428
|
+
)
|
429
|
+
last_end_of_non_empty_line_including_eol_marker = (
|
430
|
+
last_end_of_line_including_eol_marker
|
431
|
+
)
|
432
|
+
last_non_empty_line_number = line_number
|
433
|
+
|
434
|
+
line_number += 1
|
435
|
+
|
436
|
+
elif file_content[i] == SPACE:
|
437
|
+
output += file_content[i]
|
438
|
+
|
439
|
+
elif file_content[i] == TAB:
|
440
|
+
if parsed_arguments.replace_tabs_with_spaces < 0:
|
441
|
+
output += file_content[i]
|
442
|
+
elif parsed_arguments.replace_tabs_with_spaces > 0:
|
443
|
+
changes.append(Change(ChangeType.REPLACED_TAB_WITH_SPACES, line_number))
|
444
|
+
output += SPACE * parsed_arguments.replace_tabs_with_spaces
|
445
|
+
else:
|
446
|
+
# Remove the tab character.
|
447
|
+
changes.append(Change(ChangeType.REMOVED_TAB, line_number))
|
448
|
+
|
449
|
+
elif file_content[i] in [VERTICAL_TAB, FORM_FEED]:
|
450
|
+
if parsed_arguments.normalize_non_standard_whitespace == "ignore":
|
451
|
+
output += file_content[i]
|
452
|
+
elif parsed_arguments.normalize_non_standard_whitespace == "replace":
|
453
|
+
output += SPACE
|
454
|
+
changes.append(
|
455
|
+
Change(
|
456
|
+
ChangeType.REPLACED_NONSTANDARD_WHITESPACE,
|
457
|
+
line_number,
|
458
|
+
file_content[i],
|
459
|
+
SPACE,
|
460
|
+
)
|
461
|
+
)
|
462
|
+
elif parsed_arguments.normalize_non_standard_whitespace == "remove":
|
463
|
+
changes.append(
|
464
|
+
Change(
|
465
|
+
ChangeType.REMOVED_NONSTANDARD_WHITESPACE, line_number, file_content[i], ""
|
466
|
+
)
|
467
|
+
)
|
468
|
+
else:
|
469
|
+
raise ValueError("Unknown value of normalize_non_standard_whitespace")
|
470
|
+
else:
|
471
|
+
output += file_content[i]
|
472
|
+
last_non_whitespace = len(output)
|
407
473
|
|
408
|
-
|
409
|
-
|
410
|
-
check_only=(
|
411
|
-
"Non-standard whitespace characters need to be removed or replaced by spaces."
|
412
|
-
),
|
413
|
-
change="Non-standard whitespace characters were removed or replaced by spaces.",
|
414
|
-
),
|
415
|
-
normalize_non_standard_whitespace,
|
416
|
-
parsed_arguments.normalize_non_standard_whitespace,
|
417
|
-
)
|
474
|
+
# Move to the next character
|
475
|
+
i += 1
|
418
476
|
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
477
|
+
# Remove trailing whitespace from the last line.
|
478
|
+
if (
|
479
|
+
parsed_arguments.remove_trailing_whitespace
|
480
|
+
and last_end_of_line_including_eol_marker < len(output)
|
481
|
+
and last_non_whitespace < len(output)
|
482
|
+
):
|
483
|
+
changes.append(Change(ChangeType.REMOVED_TRAILING_WHITESPACE, line_number))
|
484
|
+
output = output[:last_non_whitespace]
|
485
|
+
|
486
|
+
# Remove trailing empty lines.
|
487
|
+
if (
|
488
|
+
parsed_arguments.remove_trailing_empty_lines
|
489
|
+
and last_end_of_line_including_eol_marker == len(output)
|
490
|
+
and last_end_of_non_empty_line_including_eol_marker < len(output)
|
491
|
+
):
|
492
|
+
line_number = last_non_empty_line_number + 1
|
493
|
+
last_end_of_line_including_eol_marker = last_end_of_non_empty_line_including_eol_marker
|
494
|
+
changes.append(Change(ChangeType.REMOVED_EMPTY_LINES, line_number))
|
495
|
+
output = output[:last_end_of_non_empty_line_including_eol_marker]
|
496
|
+
|
497
|
+
# Add new line marker at the end of the file
|
498
|
+
if (
|
499
|
+
parsed_arguments.add_new_line_marker_at_end_of_file
|
500
|
+
and last_end_of_line_including_eol_marker < len(output)
|
501
|
+
):
|
502
|
+
changes.append(Change(ChangeType.ADDED_NEW_LINE_MARKER_TO_END_OF_FILE, line_number))
|
503
|
+
output += output_new_line_marker
|
504
|
+
last_end_of_line_including_eol_marker = len(output)
|
505
|
+
line_number += 1
|
506
|
+
|
507
|
+
# Remove new line marker(s) from the end of the file
|
508
|
+
if (
|
509
|
+
parsed_arguments.remove_new_line_marker_from_end_of_file
|
510
|
+
and last_end_of_line_including_eol_marker == len(output)
|
511
|
+
and line_number >= 2
|
512
|
+
):
|
513
|
+
line_number = last_non_empty_line_number
|
514
|
+
changes.append(Change(ChangeType.REMOVED_NEW_LINE_MARKER_FROM_END_OF_FILE, line_number))
|
515
|
+
output = output[:last_end_of_non_empty_line_excluding_eol_marker]
|
430
516
|
|
431
|
-
|
432
|
-
file_content_tracker.format(
|
433
|
-
ChangeDescription(
|
434
|
-
check_only=f"New line marker needs to be added to the end of the file, "
|
435
|
-
f"or replaced with {repr(new_line_marker)}.",
|
436
|
-
change=f"New line marker was added to the end of the file, "
|
437
|
-
f"or replaced with {repr(new_line_marker)}.",
|
438
|
-
),
|
439
|
-
add_end_of_line_marker_at_end_of_file,
|
440
|
-
new_line_marker,
|
441
|
-
)
|
442
|
-
elif parsed_arguments.remove_new_line_marker_from_end_of_file:
|
443
|
-
file_content_tracker.format(
|
444
|
-
ChangeDescription(
|
445
|
-
check_only="New line marker(s) need to removed from the end of the file.",
|
446
|
-
change="New line marker(s) were removed from the end of the file.",
|
447
|
-
),
|
448
|
-
remove_all_end_of_line_markers_from_end_of_file,
|
449
|
-
)
|
517
|
+
return output, changes
|
450
518
|
|
451
519
|
|
452
520
|
def reformat_file(file_name: str, parsed_arguments: argparse.Namespace) -> bool:
|
453
|
-
"""Reformats a file.
|
521
|
+
"""Reformats a file.
|
522
|
+
|
523
|
+
Args:
|
524
|
+
file_name: Name of the file to reformat.
|
525
|
+
parsed_arguments: Parsed command line arguments.
|
526
|
+
|
527
|
+
Returns:
|
528
|
+
True if the file was changed, False otherwise.
|
529
|
+
"""
|
454
530
|
file_content = read_file_content(file_name, parsed_arguments.encoding)
|
455
|
-
|
456
|
-
file_content_tracker = FileContentTracker(lines)
|
457
|
-
format_file_content(file_content_tracker, parsed_arguments)
|
458
|
-
is_changed = file_content_tracker.is_changed()
|
531
|
+
formatted_file_content, file_changes = format_file_content(file_content, parsed_arguments)
|
459
532
|
if parsed_arguments.verbose:
|
460
|
-
color_print(f"Processing file
|
533
|
+
color_print(f"[WHITE]Processing file [BOLD]{file_name}[RESET_ALL]...", parsed_arguments)
|
461
534
|
if parsed_arguments.check_only:
|
462
|
-
if
|
535
|
+
if file_changes:
|
463
536
|
color_print(
|
464
537
|
f"[RED]✘[RESET_ALL] [BOLD][WHITE]{file_name} "
|
465
538
|
f"[RED]needs to be formatted[RESET_ALL]",
|
466
539
|
parsed_arguments,
|
467
540
|
)
|
468
|
-
for line_change in
|
469
|
-
|
470
|
-
|
471
|
-
f"[WHITE]{line_change.check_only}[RESET_ALL]",
|
472
|
-
parsed_arguments,
|
473
|
-
)
|
541
|
+
for line_change in file_changes:
|
542
|
+
print(" ", end="")
|
543
|
+
line_change.color_print(parsed_arguments)
|
474
544
|
else:
|
475
545
|
if parsed_arguments.verbose:
|
476
546
|
color_print(
|
@@ -479,21 +549,21 @@ def reformat_file(file_name: str, parsed_arguments: argparse.Namespace) -> bool:
|
|
479
549
|
parsed_arguments,
|
480
550
|
)
|
481
551
|
else:
|
482
|
-
if
|
552
|
+
if file_changes:
|
483
553
|
color_print(f"[WHITE]Reformatted [BOLD]{file_name}[RESET_ALL]", parsed_arguments)
|
484
|
-
for line_change in
|
485
|
-
|
486
|
-
|
487
|
-
f"[WHITE]{line_change.change}[RESET_ALL]",
|
488
|
-
parsed_arguments,
|
489
|
-
)
|
554
|
+
for line_change in file_changes:
|
555
|
+
print(" ", end="")
|
556
|
+
line_change.color_print(parsed_arguments)
|
490
557
|
write_file(
|
491
|
-
file_name,
|
558
|
+
file_name,
|
559
|
+
formatted_file_content,
|
560
|
+
parsed_arguments.encoding,
|
492
561
|
)
|
493
562
|
else:
|
494
563
|
if parsed_arguments.verbose:
|
495
|
-
color_print(f"[WHITE]{file_name}
|
496
|
-
|
564
|
+
color_print(f"[WHITE]Unchanged [BOLD]{file_name}[RESET_ALL]", parsed_arguments)
|
565
|
+
|
566
|
+
return bool(file_changes)
|
497
567
|
|
498
568
|
|
499
569
|
def reformat_files(file_names: List[str], parsed_arguments: argparse.Namespace):
|
@@ -586,20 +656,24 @@ def parse_command_line() -> argparse.Namespace:
|
|
586
656
|
default="utf-8",
|
587
657
|
type=str,
|
588
658
|
)
|
589
|
-
|
659
|
+
|
660
|
+
# Mutually exclusive group of parameters.
|
661
|
+
group1 = parser.add_mutually_exclusive_group()
|
662
|
+
group1.add_argument(
|
590
663
|
"--verbose",
|
591
664
|
help="Print more messages than normally.",
|
592
665
|
required=False,
|
593
666
|
action="store_true",
|
594
667
|
default=False,
|
595
668
|
)
|
596
|
-
|
669
|
+
group1.add_argument(
|
597
670
|
"--quiet",
|
598
671
|
help="Do not print any messages, except for errors when reading or writing files.",
|
599
672
|
required=False,
|
600
673
|
action="store_true",
|
601
674
|
default=False,
|
602
675
|
)
|
676
|
+
|
603
677
|
parser.add_argument(
|
604
678
|
"--color",
|
605
679
|
help="Print messages in color.",
|
@@ -637,6 +711,10 @@ def parse_command_line() -> argparse.Namespace:
|
|
637
711
|
"mac: Use Mac new line marker '\\r'. "
|
638
712
|
"windows: Use Windows new line marker '\\r\\n'. "
|
639
713
|
),
|
714
|
+
required=False,
|
715
|
+
type=str,
|
716
|
+
choices=["auto", "linux", "mac", "windows"],
|
717
|
+
default="auto",
|
640
718
|
)
|
641
719
|
parser.add_argument(
|
642
720
|
"--normalize-new-line-markers",
|
@@ -676,20 +754,27 @@ def parse_command_line() -> argparse.Namespace:
|
|
676
754
|
default="ignore",
|
677
755
|
choices=["ignore", "empty", "one-line"],
|
678
756
|
)
|
679
|
-
|
757
|
+
|
758
|
+
# Mutually exclusive group of parameters.
|
759
|
+
group2 = parser.add_mutually_exclusive_group()
|
760
|
+
group2.add_argument(
|
680
761
|
"--add-new-line-marker-at-end-of-file",
|
681
762
|
help="Add missing new line marker at end of each file.",
|
682
763
|
required=False,
|
683
764
|
default=False,
|
684
765
|
action="store_true",
|
685
766
|
)
|
686
|
-
|
767
|
+
group2.add_argument(
|
687
768
|
"--remove-new-line-marker-from-end-of-file",
|
688
|
-
help="Remove new line markers from the end of each file."
|
769
|
+
help="Remove new line markers from the end of each file. "
|
770
|
+
"This option conflicts with --add-new-line-marker-at-end-of-file. "
|
771
|
+
"This option implies --remove-trailing-empty-lines option, i.e., "
|
772
|
+
"all empty lines at the end of the file are removed.",
|
689
773
|
required=False,
|
690
774
|
default=False,
|
691
775
|
action="store_true",
|
692
776
|
)
|
777
|
+
|
693
778
|
parser.add_argument(
|
694
779
|
"--remove-trailing-whitespace",
|
695
780
|
help="Remove whitespace at the end of each line.",
|
@@ -699,7 +784,8 @@ def parse_command_line() -> argparse.Namespace:
|
|
699
784
|
)
|
700
785
|
parser.add_argument(
|
701
786
|
"--remove-trailing-empty-lines",
|
702
|
-
help="Remove empty lines at the end of each file."
|
787
|
+
help="Remove empty lines at the end of each file. "
|
788
|
+
"If --remove-new-line-marker-from-end-of-file is used, this option is used automatically.",
|
703
789
|
required=False,
|
704
790
|
default=False,
|
705
791
|
action="store_true",
|
@@ -736,8 +822,8 @@ def parse_command_line() -> argparse.Namespace:
|
|
736
822
|
if parsed_arguments.normalize_whitespace_only_files == "empty":
|
737
823
|
parsed_arguments.normalize_empty_files = parsed_arguments.normalize_whitespace_only_files
|
738
824
|
|
739
|
-
if parsed_arguments.
|
740
|
-
parsed_arguments.
|
825
|
+
if parsed_arguments.remove_new_line_marker_from_end_of_file:
|
826
|
+
parsed_arguments.remove_empty_lines = True
|
741
827
|
|
742
828
|
return parsed_arguments
|
743
829
|
|
@@ -1,6 +0,0 @@
|
|
1
|
-
whitespace_format.py,sha256=uqu0SZ76nyFGEDX6gMIyLZpmVv_rtJRx0IjcEC601Cs,26016
|
2
|
-
whitespace_format-0.0.5.dist-info/LICENSE,sha256=rT6UNfWDYFQc-eo65FioDJRMAyVOndtF95wNCUhkK74,1076
|
3
|
-
whitespace_format-0.0.5.dist-info/METADATA,sha256=Pq-GTLKbXw9u6uj7CGwItBpi15yDrOdjSyTXVzdnuVU,10233
|
4
|
-
whitespace_format-0.0.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
5
|
-
whitespace_format-0.0.5.dist-info/entry_points.txt,sha256=LbXoevzUZAF5MVbI2foNC9xeDjKS_Woz7VbA1ZNF5CY,60
|
6
|
-
whitespace_format-0.0.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|