]> 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:

Fix merging implicit multiline strings that have inline comments (#3956)
authorHenri Holopainen <henri.i.holopainen@gmail.com>
Fri, 20 Oct 2023 03:09:33 +0000 (06:09 +0300)
committerGitHub <noreply@github.com>
Fri, 20 Oct 2023 03:09:33 +0000 (20:09 -0700)
* Fix test behaviour

* Add new test cases

* Skip merging strings that have inline comments

* Don't merge lines with multiline strings with inline comments

* Changelog entry

* Document implicit multiline string merging rules

* Fix PR number

CHANGES.md
docs/the_black_code_style/future_style.md
src/black/linegen.py
src/black/lines.py
src/black/trans.py
tests/data/cases/preview_long_strings__regression.py
tests/data/cases/preview_multiline_strings.py

index 2a50e45655042f24c2219fdab0bce5ef7eb6ba4f..79b5c6034e8ad2044f1417a5ccd1c0f4ee1cdf25 100644 (file)
@@ -12,7 +12,7 @@
 
 ### Preview style
 
-<!-- Changes that affect Black's preview style -->
+- Fix merging implicit multiline strings that have inline comments (#3956)
 
 ### Configuration
 
index 861bb64bff4d10016fde5db5230d887fbca364ec..367ff98537c8ff333bd919b62d0411e5f2d9732e 100644 (file)
@@ -160,3 +160,67 @@ MULTILINE = """
 foobar
 """.replace("\n", "")
 ```
+
+Implicit multiline strings are special, because they can have inline comments. Strings
+without comments are merged, for example
+
+```python
+s = (
+    "An "
+    "implicit "
+    "multiline "
+    "string"
+)
+```
+
+becomes
+
+```python
+s = "An implicit multiline string"
+```
+
+A comment on any line of the string (or between two string lines) will block the
+merging, so
+
+```python
+s = (
+    "An "  # Important comment concerning just this line
+    "implicit "
+    "multiline "
+    "string"
+)
+```
+
+and
+
+```python
+s = (
+    "An "
+    "implicit "
+    # Comment in between
+    "multiline "
+    "string"
+)
+```
+
+will not be merged. Having the comment after or before the string lines (but still
+inside the parens) will merge the string. For example
+
+```python
+s = (  # Top comment
+    "An "
+    "implicit "
+    "multiline "
+    "string"
+    # Bottom comment
+)
+```
+
+becomes
+
+```python
+s = (  # Top comment
+    "An implicit multiline string"
+    # Bottom comment
+)
+```
index d12ca39d0372972cef62043b230fa5785d67bd7f..2bfe587fa0ec5120287d133c7371ee85716d5ec7 100644 (file)
@@ -587,6 +587,7 @@ def transform_line(
             or line.contains_unsplittable_type_ignore()
         )
         and not (line.inside_brackets and line.contains_standalone_comments())
+        and not line.contains_implicit_multiline_string_with_comments()
     ):
         # Only apply basic string preprocessing, since lines shouldn't be split here.
         if Preview.string_processing in mode:
index 48fde88820853deec0e5b6405a8b4bf116bf9fe4..6acc95e7a7e004dbf2e35a571bb08def6f1100fe 100644 (file)
@@ -239,6 +239,21 @@ class Line:
 
         return False
 
+    def contains_implicit_multiline_string_with_comments(self) -> bool:
+        """Chck if we have an implicit multiline string with comments on the line"""
+        for leaf_type, leaf_group_iterator in itertools.groupby(
+            self.leaves, lambda leaf: leaf.type
+        ):
+            if leaf_type != token.STRING:
+                continue
+            leaf_list = list(leaf_group_iterator)
+            if len(leaf_list) == 1:
+                continue
+            for leaf in leaf_list:
+                if self.comments_after(leaf):
+                    return True
+        return False
+
     def contains_uncollapsable_type_comments(self) -> bool:
         ignored_ids = set()
         try:
index a2bff7f227adb51bf1afa96242393384041374ed..a3f6467cc9e3920758ce3b5ddf00a5e2c41129b6 100644 (file)
@@ -390,7 +390,19 @@ class StringMerger(StringTransformer, CustomSplitMapMixin):
                 and is_valid_index(idx + 1)
                 and LL[idx + 1].type == token.STRING
             ):
-                if not is_part_of_annotation(leaf):
+                # Let's check if the string group contains an inline comment
+                # If we have a comment inline, we don't merge the strings
+                contains_comment = False
+                i = idx
+                while is_valid_index(i):
+                    if LL[i].type != token.STRING:
+                        break
+                    if line.comments_after(LL[i]):
+                        contains_comment = True
+                        break
+                    i += 1
+
+                if not is_part_of_annotation(leaf) and not contains_comment:
                     string_indices.append(idx)
 
                 # Advance to the next non-STRING leaf.
index 40d5e745cc82bdaf091cfa71feded01c77724f41..436157f4e0584b949c109db62b3a0bad3fb97cf0 100644 (file)
@@ -210,8 +210,8 @@ def foo():
 
 some_tuple = ("some string", "some string" " which should be joined")
 
-some_commented_string = (
-    "This string is long but not so long that it needs hahahah toooooo be so greatttt"  # This comment gets thrown to the top.
+some_commented_string = (  # This comment stays at the top.
+    "This string is long but not so long that it needs hahahah toooooo be so greatttt"
     " {} that I just can't think of any more good words to say about it at"
     " allllllllllll".format("ha")  # comments here are fine
 )
@@ -834,7 +834,7 @@ def foo():
 
 some_tuple = ("some string", "some string which should be joined")
 
-some_commented_string = (  # This comment gets thrown to the top.
+some_commented_string = (  # This comment stays at the top.
     "This string is long but not so long that it needs hahahah toooooo be so greatttt"
     " {} that I just can't think of any more good words to say about it at"
     " allllllllllll".format("ha")  # comments here are fine
index dec4ef2e548d0095b275035a4e74d36abe36b0c2..3ff643610b7d50cd190f9b17056e8b28f985ae5f 100644 (file)
@@ -157,6 +157,24 @@ Please use `--build-option` instead,
 `--global-option` is reserved to flags like `--verbose` or `--quiet`.
 """
 
+this_will_become_one_line = (
+    "a"
+    "b"
+    "c"
+)
+
+this_will_stay_on_three_lines = (
+    "a"  # comment
+    "b"
+    "c"
+)
+
+this_will_also_become_one_line = (  # comment
+    "a"
+    "b"
+    "c"
+)
+
 # output
 """cow
 say""",
@@ -357,3 +375,13 @@ msg = f"""The arguments {bad_arguments} were passed in.
 Please use `--build-option` instead,
 `--global-option` is reserved to flags like `--verbose` or `--quiet`.
 """
+
+this_will_become_one_line = "abc"
+
+this_will_stay_on_three_lines = (
+    "a"  # comment
+    "b"
+    "c"
+)
+
+this_will_also_become_one_line = "abc"  # comment