]> git.madduck.net Git - etc/vim.git/commitdiff

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Remove newline after code block open (#3035)
authorSagi Shadur <saroad2@gmail.com>
Sat, 11 Jun 2022 06:55:01 +0000 (09:55 +0300)
committerGitHub <noreply@github.com>
Sat, 11 Jun 2022 06:55:01 +0000 (09:55 +0300)
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
AUTHORS.md
CHANGES.md
docs/the_black_code_style/future_style.md
src/black/lines.py
src/black/mode.py
tests/data/preview/remove_newline_after_code_block_open.py [new file with mode: 0644]
tests/data/preview_310/remove_newline_after match.py [new file with mode: 0644]
tests/test_black.py
tests/test_format.py

index 8aa6263313edbf68ab085070e1ae74b5d2444e39..faa2b05840f0c8090cf5f26a2428a9528280b8b4 100644 (file)
@@ -148,6 +148,7 @@ Multiple contributions by:
 - [Rishikesh Jha](mailto:rishijha424@gmail.com)
 - [Rupert Bedford](mailto:rupert@rupertb.com)
 - Russell Davis
+- [Sagi Shadur](mailto:saroad2@gmail.com)
 - [Rémi Verschelde](mailto:rverschelde@gmail.com)
 - [Sami Salonen](mailto:sakki@iki.fi)
 - [Samuel Cormier-Iijima](mailto:samuel@cormier-iijima.com)
index a6b6594b57a1c0084572b214dec7b718d5cef3b2..7001271087a9c9035ca1642098acdc6fa0d0e9c6 100644 (file)
@@ -21,6 +21,7 @@
 - Remove redundant parentheses around awaited objects (#2991)
 - Parentheses around return annotations are now managed (#2990)
 - Remove unnecessary parentheses from `with` statements (#2926)
+- Remove trailing newlines after code block open (#3035)
 
 ### _Blackd_
 
index 2ec2c0333a5fb3a1db077c20f74578956ef20739..8d159e9b0a21cf0890934b56f48e8f1931901ca6 100644 (file)
@@ -49,3 +49,28 @@ plain strings. User-made splits are respected when they do not exceed the line l
 limit. Line continuation backslashes are converted into parenthesized strings.
 Unnecessary parentheses are stripped. The stability and status of this feature is
 tracked in [this issue](https://github.com/psf/black/issues/2188).
+
+### Removing trailing newlines after code block open
+
+_Black_ will remove trailing newlines after code block openings. That means that the
+following code:
+
+```python
+def my_func():
+
+    print("The line above me will be deleted!")
+
+    print("But the line above me won't!")
+```
+
+Will be changed to:
+
+```python
+def my_func():
+    print("The line above me will be deleted!")
+
+    print("But the line above me won't!")
+```
+
+This new feature will be applied to **all code blocks**: `def`, `class`, `if`, `for`,
+`while`, `with`, `case` and `match`.
index e455a5075392e6405b6c2472c371bbce36a7d1d5..8b591c324a5da6a27fc7fb7613f2900df2da9b7b 100644 (file)
@@ -168,6 +168,13 @@ class Line:
             and self.leaves[0].value.startswith(('"""', "'''"))
         )
 
+    @property
+    def opens_block(self) -> bool:
+        """Does this line open a new level of indentation."""
+        if len(self.leaves) == 0:
+            return False
+        return self.leaves[-1].type == token.COLON
+
     def contains_standalone_comments(self, depth_limit: int = sys.maxsize) -> bool:
         """If so, needs to be split before emitting."""
         for leaf in self.leaves:
@@ -513,6 +520,12 @@ class EmptyLineTracker:
         ):
             return before, 1
 
+        if (
+            Preview.remove_block_trailing_newline in current_line.mode
+            and self.previous_line
+            and self.previous_line.opens_block
+        ):
+            return 0, 0
         return before, 0
 
     def _maybe_empty_lines_for_class_or_def(
index bf79f6a31489276bcd79a611650db0d20038332a..896c516df79e16967744fd083436644a473f56d9 100644 (file)
@@ -150,6 +150,7 @@ class Preview(Enum):
     one_element_subscript = auto()
     annotation_parens = auto()
     long_docstring_quotes_on_newline = auto()
+    remove_block_trailing_newline = auto()
 
 
 class Deprecated(UserWarning):
diff --git a/tests/data/preview/remove_newline_after_code_block_open.py b/tests/data/preview/remove_newline_after_code_block_open.py
new file mode 100644 (file)
index 0000000..ef2e5c2
--- /dev/null
@@ -0,0 +1,189 @@
+import random
+
+
+def foo1():
+
+    print("The newline above me should be deleted!")
+
+
+def foo2():
+
+
+
+    print("All the newlines above me should be deleted!")
+
+
+def foo3():
+
+    print("No newline above me!")
+
+    print("There is a newline above me, and that's OK!")
+
+
+def foo4():
+
+    # There is a comment here
+
+    print("The newline above me should not be deleted!")
+
+
+class Foo:
+    def bar(self):
+
+        print("The newline above me should be deleted!")
+
+
+for i in range(5):
+
+    print(f"{i}) The line above me should be removed!")
+
+
+for i in range(5):
+
+
+
+    print(f"{i}) The lines above me should be removed!")
+
+
+for i in range(5):
+
+    for j in range(7):
+
+        print(f"{i}) The lines above me should be removed!")
+
+
+if random.randint(0, 3) == 0:
+
+    print("The new line above me is about to be removed!")
+
+
+if random.randint(0, 3) == 0:
+
+
+
+
+    print("The new lines above me is about to be removed!")
+
+
+if random.randint(0, 3) == 0:
+    if random.uniform(0, 1) > 0.5:
+        print("Two lines above me are about to be removed!")
+
+
+while True:
+
+    print("The newline above me should be deleted!")
+
+
+while True:
+
+
+
+    print("The newlines above me should be deleted!")
+
+
+while True:
+
+    while False:
+
+        print("The newlines above me should be deleted!")
+
+
+with open("/path/to/file.txt", mode="w") as file:
+
+    file.write("The new line above me is about to be removed!")
+
+
+with open("/path/to/file.txt", mode="w") as file:
+
+
+
+    file.write("The new lines above me is about to be removed!")
+
+
+with open("/path/to/file.txt", mode="r") as read_file:
+
+    with open("/path/to/output_file.txt", mode="w") as write_file:
+
+        write_file.writelines(read_file.readlines())
+
+# output
+
+import random
+
+
+def foo1():
+    print("The newline above me should be deleted!")
+
+
+def foo2():
+    print("All the newlines above me should be deleted!")
+
+
+def foo3():
+    print("No newline above me!")
+
+    print("There is a newline above me, and that's OK!")
+
+
+def foo4():
+    # There is a comment here
+
+    print("The newline above me should not be deleted!")
+
+
+class Foo:
+    def bar(self):
+        print("The newline above me should be deleted!")
+
+
+for i in range(5):
+    print(f"{i}) The line above me should be removed!")
+
+
+for i in range(5):
+    print(f"{i}) The lines above me should be removed!")
+
+
+for i in range(5):
+    for j in range(7):
+        print(f"{i}) The lines above me should be removed!")
+
+
+if random.randint(0, 3) == 0:
+    print("The new line above me is about to be removed!")
+
+
+if random.randint(0, 3) == 0:
+    print("The new lines above me is about to be removed!")
+
+
+if random.randint(0, 3) == 0:
+    if random.uniform(0, 1) > 0.5:
+        print("Two lines above me are about to be removed!")
+
+
+while True:
+    print("The newline above me should be deleted!")
+
+
+while True:
+    print("The newlines above me should be deleted!")
+
+
+while True:
+    while False:
+        print("The newlines above me should be deleted!")
+
+
+with open("/path/to/file.txt", mode="w") as file:
+    file.write("The new line above me is about to be removed!")
+
+
+with open("/path/to/file.txt", mode="w") as file:
+    file.write("The new lines above me is about to be removed!")
+
+
+with open("/path/to/file.txt", mode="r") as read_file:
+    with open("/path/to/output_file.txt", mode="w") as write_file:
+        write_file.writelines(read_file.readlines())
diff --git a/tests/data/preview_310/remove_newline_after match.py b/tests/data/preview_310/remove_newline_after match.py
new file mode 100644 (file)
index 0000000..f7bcfbf
--- /dev/null
@@ -0,0 +1,34 @@
+def http_status(status):
+
+    match status:
+
+        case 400:
+
+            return "Bad request"
+
+        case 401:
+
+            return "Unauthorized"
+
+        case 403:
+
+            return "Forbidden"
+
+        case 404:
+
+            return "Not found"
+
+# output
+def http_status(status):
+    match status:
+        case 400:
+            return "Bad request"
+
+        case 401:
+            return "Unauthorized"
+
+        case 403:
+            return "Forbidden"
+
+        case 404:
+            return "Not found"
\ No newline at end of file
index 02a707e8996aa25beab3137a91281623126f0af5..8adcaed5ef8a78665d63adbe138586ba00d142fb 100644 (file)
@@ -1461,7 +1461,6 @@ class BlackTestCase(BlackBaseTestCase):
         black.assert_stable(source, output, mode=DEFAULT_MODE)
 
     def test_bpo_2142_workaround(self) -> None:
-
         # https://bugs.python.org/issue2142
 
         source, _ = read_data("miscellaneous", "missing_final_newline")
index 005a5771c2b644c9feb9bb881adfefbaa5be7547..a8a922d17db908cf21ed41cc8c3f74d6dadfdef8 100644 (file)
@@ -86,6 +86,13 @@ def test_preview_minimum_python_39_format(filename: str) -> None:
     assert_format(source, expected, mode, minimum_version=(3, 9))
 
 
+@pytest.mark.parametrize("filename", all_data_cases("preview_310"))
+def test_preview_minimum_python_310_format(filename: str) -> None:
+    source, expected = read_data("preview_310", filename)
+    mode = black.Mode(preview=True)
+    assert_format(source, expected, mode, minimum_version=(3, 10))
+
+
 @pytest.mark.parametrize("filename", SOURCES)
 def test_source_is_formatted(filename: str) -> None:
     check_file("", filename, DEFAULT_MODE, data=False)