We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Reconsider the choice of adding a newline after multi-line option definitions
First, thanks for your work.

I ask you to reconsider the feature introduced with PR https://github.com/pallets/click/pull/1081.

1. Adding a newline only to some options feels inconsistent and leads to a weird-looking "non-uniform" help strings. It's even worse when you use an extension that adds new help sections (e.g. [Cloup](https://github.com/janluke/cloup) for option groups), since some sections are not clearly demarked or too much demarked. It looks like a complete mess.

2. I'm pretty sure it's non-standard. Why should it be the default?

As a consequence, it feels like a bug. I did mistake it for a bug. Another developer reported it as a bug (issue https://github.com/pallets/click/issues/1559). The few people I asked don't like it and consider it a problem worth the effort of writing additional code to get rid of it. Most people in the original issue (https://github.com/pallets/click/issues/1075) are for an all-or-nothing behavior and described the current behviour as inconsistent as well.

Here's some alternative proposals.
1. Remove the feature.
2. Make it possible but non-default. Two solutions here:
    1. Add a parameter to `HelpFormatter`. It can be made as simple as a boolean or as complex as a "list item separation strategy". A user can pass a custom factory function as `Context.formatter_class` (which probably could be called `formatter_factory`).
    2. Refactor `HelpFormatter` to make it easy for people to override without copying, pasting and modiyfing the current code of `HelpFormatter.write_dl`.

Thank you again.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/click/formatting.py`
Content:
```
1 import typing as t
2 from contextlib import contextmanager
3 
4 from ._compat import term_len
5 from .parser import split_opt
6 
7 # Can force a width.  This is used by the test system
8 FORCED_WIDTH: t.Optional[int] = None
9 
10 
11 def measure_table(rows):
12     widths = {}
13     for row in rows:
14         for idx, col in enumerate(row):
15             widths[idx] = max(widths.get(idx, 0), term_len(col))
16     return tuple(y for x, y in sorted(widths.items()))
17 
18 
19 def iter_rows(rows, col_count):
20     for row in rows:
21         row = tuple(row)
22         yield row + ("",) * (col_count - len(row))
23 
24 
25 def wrap_text(
26     text, width=78, initial_indent="", subsequent_indent="", preserve_paragraphs=False
27 ):
28     """A helper function that intelligently wraps text.  By default, it
29     assumes that it operates on a single paragraph of text but if the
30     `preserve_paragraphs` parameter is provided it will intelligently
31     handle paragraphs (defined by two empty lines).
32 
33     If paragraphs are handled, a paragraph can be prefixed with an empty
34     line containing the ``\\b`` character (``\\x08``) to indicate that
35     no rewrapping should happen in that block.
36 
37     :param text: the text that should be rewrapped.
38     :param width: the maximum width for the text.
39     :param initial_indent: the initial indent that should be placed on the
40                            first line as a string.
41     :param subsequent_indent: the indent string that should be placed on
42                               each consecutive line.
43     :param preserve_paragraphs: if this flag is set then the wrapping will
44                                 intelligently handle paragraphs.
45     """
46     from ._textwrap import TextWrapper
47 
48     text = text.expandtabs()
49     wrapper = TextWrapper(
50         width,
51         initial_indent=initial_indent,
52         subsequent_indent=subsequent_indent,
53         replace_whitespace=False,
54     )
55     if not preserve_paragraphs:
56         return wrapper.fill(text)
57 
58     p = []
59     buf = []
60     indent = None
61 
62     def _flush_par():
63         if not buf:
64             return
65         if buf[0].strip() == "\b":
66             p.append((indent or 0, True, "\n".join(buf[1:])))
67         else:
68             p.append((indent or 0, False, " ".join(buf)))
69         del buf[:]
70 
71     for line in text.splitlines():
72         if not line:
73             _flush_par()
74             indent = None
75         else:
76             if indent is None:
77                 orig_len = term_len(line)
78                 line = line.lstrip()
79                 indent = orig_len - term_len(line)
80             buf.append(line)
81     _flush_par()
82 
83     rv = []
84     for indent, raw, text in p:
85         with wrapper.extra_indent(" " * indent):
86             if raw:
87                 rv.append(wrapper.indent_only(text))
88             else:
89                 rv.append(wrapper.fill(text))
90 
91     return "\n\n".join(rv)
92 
93 
94 class HelpFormatter:
95     """This class helps with formatting text-based help pages.  It's
96     usually just needed for very special internal cases, but it's also
97     exposed so that developers can write their own fancy outputs.
98 
99     At present, it always writes into memory.
100 
101     :param indent_increment: the additional increment for each level.
102     :param width: the width for the text.  This defaults to the terminal
103                   width clamped to a maximum of 78.
104     """
105 
106     def __init__(self, indent_increment=2, width=None, max_width=None):
107         import shutil
108 
109         self.indent_increment = indent_increment
110         if max_width is None:
111             max_width = 80
112         if width is None:
113             width = FORCED_WIDTH
114             if width is None:
115                 width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50)
116         self.width = width
117         self.current_indent = 0
118         self.buffer = []
119 
120     def write(self, string):
121         """Writes a unicode string into the internal buffer."""
122         self.buffer.append(string)
123 
124     def indent(self):
125         """Increases the indentation."""
126         self.current_indent += self.indent_increment
127 
128     def dedent(self):
129         """Decreases the indentation."""
130         self.current_indent -= self.indent_increment
131 
132     def write_usage(self, prog, args="", prefix="Usage: "):
133         """Writes a usage line into the buffer.
134 
135         :param prog: the program name.
136         :param args: whitespace separated list of arguments.
137         :param prefix: the prefix for the first line.
138         """
139         usage_prefix = f"{prefix:>{self.current_indent}}{prog} "
140         text_width = self.width - self.current_indent
141 
142         if text_width >= (term_len(usage_prefix) + 20):
143             # The arguments will fit to the right of the prefix.
144             indent = " " * term_len(usage_prefix)
145             self.write(
146                 wrap_text(
147                     args,
148                     text_width,
149                     initial_indent=usage_prefix,
150                     subsequent_indent=indent,
151                 )
152             )
153         else:
154             # The prefix is too long, put the arguments on the next line.
155             self.write(usage_prefix)
156             self.write("\n")
157             indent = " " * (max(self.current_indent, term_len(prefix)) + 4)
158             self.write(
159                 wrap_text(
160                     args, text_width, initial_indent=indent, subsequent_indent=indent
161                 )
162             )
163 
164         self.write("\n")
165 
166     def write_heading(self, heading):
167         """Writes a heading into the buffer."""
168         self.write(f"{'':>{self.current_indent}}{heading}:\n")
169 
170     def write_paragraph(self):
171         """Writes a paragraph into the buffer."""
172         if self.buffer:
173             self.write("\n")
174 
175     def write_text(self, text):
176         """Writes re-indented text into the buffer.  This rewraps and
177         preserves paragraphs.
178         """
179         text_width = max(self.width - self.current_indent, 11)
180         indent = " " * self.current_indent
181         self.write(
182             wrap_text(
183                 text,
184                 text_width,
185                 initial_indent=indent,
186                 subsequent_indent=indent,
187                 preserve_paragraphs=True,
188             )
189         )
190         self.write("\n")
191 
192     def write_dl(self, rows, col_max=30, col_spacing=2):
193         """Writes a definition list into the buffer.  This is how options
194         and commands are usually formatted.
195 
196         :param rows: a list of two item tuples for the terms and values.
197         :param col_max: the maximum width of the first column.
198         :param col_spacing: the number of spaces between the first and
199                             second column.
200         """
201         rows = list(rows)
202         widths = measure_table(rows)
203         if len(widths) != 2:
204             raise TypeError("Expected two columns for definition list")
205 
206         first_col = min(widths[0], col_max) + col_spacing
207 
208         for first, second in iter_rows(rows, len(widths)):
209             self.write(f"{'':>{self.current_indent}}{first}")
210             if not second:
211                 self.write("\n")
212                 continue
213             if term_len(first) <= first_col - col_spacing:
214                 self.write(" " * (first_col - term_len(first)))
215             else:
216                 self.write("\n")
217                 self.write(" " * (first_col + self.current_indent))
218 
219             text_width = max(self.width - first_col - 2, 10)
220             wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True)
221             lines = wrapped_text.splitlines()
222 
223             if lines:
224                 self.write(f"{lines[0]}\n")
225 
226                 for line in lines[1:]:
227                     self.write(f"{'':>{first_col + self.current_indent}}{line}\n")
228 
229                 if len(lines) > 1:
230                     # separate long help from next option
231                     self.write("\n")
232             else:
233                 self.write("\n")
234 
235     @contextmanager
236     def section(self, name):
237         """Helpful context manager that writes a paragraph, a heading,
238         and the indents.
239 
240         :param name: the section name that is written as heading.
241         """
242         self.write_paragraph()
243         self.write_heading(name)
244         self.indent()
245         try:
246             yield
247         finally:
248             self.dedent()
249 
250     @contextmanager
251     def indentation(self):
252         """A context manager that increases the indentation."""
253         self.indent()
254         try:
255             yield
256         finally:
257             self.dedent()
258 
259     def getvalue(self):
260         """Returns the buffer contents."""
261         return "".join(self.buffer)
262 
263 
264 def join_options(options):
265     """Given a list of option strings this joins them in the most appropriate
266     way and returns them in the form ``(formatted_string,
267     any_prefix_is_slash)`` where the second item in the tuple is a flag that
268     indicates if any of the option prefixes was a slash.
269     """
270     rv = []
271     any_prefix_is_slash = False
272     for opt in options:
273         prefix = split_opt(opt)[0]
274         if prefix == "/":
275             any_prefix_is_slash = True
276         rv.append((len(prefix), opt))
277 
278     rv.sort(key=lambda x: x[0])
279 
280     rv = ", ".join(x[1] for x in rv)
281     return rv, any_prefix_is_slash
282
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/click/formatting.py b/src/click/formatting.py
--- a/src/click/formatting.py
+++ b/src/click/formatting.py
@@ -225,10 +225,6 @@
 
                 for line in lines[1:]:
                     self.write(f"{'':>{first_col + self.current_indent}}{line}\n")
-
-                if len(lines) > 1:
-                    # separate long help from next option
-                    self.write("\n")
             else:
                 self.write("\n")

{"golden_diff": "diff --git a/src/click/formatting.py b/src/click/formatting.py\n--- a/src/click/formatting.py\n+++ b/src/click/formatting.py\n@@ -225,10 +225,6 @@\n \n                 for line in lines[1:]:\n                     self.write(f\"{'':>{first_col + self.current_indent}}{line}\\n\")\n-\n-                if len(lines) > 1:\n-                    # separate long help from next option\n-                    self.write(\"\\n\")\n             else:\n                 self.write(\"\\n\")\n", "issue": "Reconsider the choice of adding a newline after multi-line option definitions\nFirst, thanks for your work.\r\n\r\nI ask you to reconsider the feature introduced with PR https://github.com/pallets/click/pull/1081.\r\n\r\n1. Adding a newline only to some options feels inconsistent and leads to a weird-looking \"non-uniform\" help strings. It's even worse when you use an extension that adds new help sections (e.g. [Cloup](https://github.com/janluke/cloup) for option groups), since some sections are not clearly demarked or too much demarked. It looks like a complete mess.\r\n\r\n2. I'm pretty sure it's non-standard. Why should it be the default?\r\n\r\nAs a consequence, it feels like a bug. I did mistake it for a bug. Another developer reported it as a bug (issue https://github.com/pallets/click/issues/1559). The few people I asked don't like it and consider it a problem worth the effort of writing additional code to get rid of it. Most people in the original issue (https://github.com/pallets/click/issues/1075) are for an all-or-nothing behavior and described the current behviour as inconsistent as well.\r\n\r\nHere's some alternative proposals.\r\n1. Remove the feature.\r\n2. Make it possible but non-default. Two solutions here:\r\n    1. Add a parameter to `HelpFormatter`. It can be made as simple as a boolean or as complex as a \"list item separation strategy\". A user can pass a custom factory function as `Context.formatter_class` (which probably could be called `formatter_factory`).\r\n    2. Refactor `HelpFormatter` to make it easy for people to override without copying, pasting and modiyfing the current code of `HelpFormatter.write_dl`.\r\n\r\nThank you again.\r\n\n", "before_files": [{"content": "import typing as t\nfrom contextlib import contextmanager\n\nfrom ._compat import term_len\nfrom .parser import split_opt\n\n# Can force a width.  This is used by the test system\nFORCED_WIDTH: t.Optional[int] = None\n\n\ndef measure_table(rows):\n    widths = {}\n    for row in rows:\n        for idx, col in enumerate(row):\n            widths[idx] = max(widths.get(idx, 0), term_len(col))\n    return tuple(y for x, y in sorted(widths.items()))\n\n\ndef iter_rows(rows, col_count):\n    for row in rows:\n        row = tuple(row)\n        yield row + (\"\",) * (col_count - len(row))\n\n\ndef wrap_text(\n    text, width=78, initial_indent=\"\", subsequent_indent=\"\", preserve_paragraphs=False\n):\n    \"\"\"A helper function that intelligently wraps text.  By default, it\n    assumes that it operates on a single paragraph of text but if the\n    `preserve_paragraphs` parameter is provided it will intelligently\n    handle paragraphs (defined by two empty lines).\n\n    If paragraphs are handled, a paragraph can be prefixed with an empty\n    line containing the ``\\\\b`` character (``\\\\x08``) to indicate that\n    no rewrapping should happen in that block.\n\n    :param text: the text that should be rewrapped.\n    :param width: the maximum width for the text.\n    :param initial_indent: the initial indent that should be placed on the\n                           first line as a string.\n    :param subsequent_indent: the indent string that should be placed on\n                              each consecutive line.\n    :param preserve_paragraphs: if this flag is set then the wrapping will\n                                intelligently handle paragraphs.\n    \"\"\"\n    from ._textwrap import TextWrapper\n\n    text = text.expandtabs()\n    wrapper = TextWrapper(\n        width,\n        initial_indent=initial_indent,\n        subsequent_indent=subsequent_indent,\n        replace_whitespace=False,\n    )\n    if not preserve_paragraphs:\n        return wrapper.fill(text)\n\n    p = []\n    buf = []\n    indent = None\n\n    def _flush_par():\n        if not buf:\n            return\n        if buf[0].strip() == \"\\b\":\n            p.append((indent or 0, True, \"\\n\".join(buf[1:])))\n        else:\n            p.append((indent or 0, False, \" \".join(buf)))\n        del buf[:]\n\n    for line in text.splitlines():\n        if not line:\n            _flush_par()\n            indent = None\n        else:\n            if indent is None:\n                orig_len = term_len(line)\n                line = line.lstrip()\n                indent = orig_len - term_len(line)\n            buf.append(line)\n    _flush_par()\n\n    rv = []\n    for indent, raw, text in p:\n        with wrapper.extra_indent(\" \" * indent):\n            if raw:\n                rv.append(wrapper.indent_only(text))\n            else:\n                rv.append(wrapper.fill(text))\n\n    return \"\\n\\n\".join(rv)\n\n\nclass HelpFormatter:\n    \"\"\"This class helps with formatting text-based help pages.  It's\n    usually just needed for very special internal cases, but it's also\n    exposed so that developers can write their own fancy outputs.\n\n    At present, it always writes into memory.\n\n    :param indent_increment: the additional increment for each level.\n    :param width: the width for the text.  This defaults to the terminal\n                  width clamped to a maximum of 78.\n    \"\"\"\n\n    def __init__(self, indent_increment=2, width=None, max_width=None):\n        import shutil\n\n        self.indent_increment = indent_increment\n        if max_width is None:\n            max_width = 80\n        if width is None:\n            width = FORCED_WIDTH\n            if width is None:\n                width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50)\n        self.width = width\n        self.current_indent = 0\n        self.buffer = []\n\n    def write(self, string):\n        \"\"\"Writes a unicode string into the internal buffer.\"\"\"\n        self.buffer.append(string)\n\n    def indent(self):\n        \"\"\"Increases the indentation.\"\"\"\n        self.current_indent += self.indent_increment\n\n    def dedent(self):\n        \"\"\"Decreases the indentation.\"\"\"\n        self.current_indent -= self.indent_increment\n\n    def write_usage(self, prog, args=\"\", prefix=\"Usage: \"):\n        \"\"\"Writes a usage line into the buffer.\n\n        :param prog: the program name.\n        :param args: whitespace separated list of arguments.\n        :param prefix: the prefix for the first line.\n        \"\"\"\n        usage_prefix = f\"{prefix:>{self.current_indent}}{prog} \"\n        text_width = self.width - self.current_indent\n\n        if text_width >= (term_len(usage_prefix) + 20):\n            # The arguments will fit to the right of the prefix.\n            indent = \" \" * term_len(usage_prefix)\n            self.write(\n                wrap_text(\n                    args,\n                    text_width,\n                    initial_indent=usage_prefix,\n                    subsequent_indent=indent,\n                )\n            )\n        else:\n            # The prefix is too long, put the arguments on the next line.\n            self.write(usage_prefix)\n            self.write(\"\\n\")\n            indent = \" \" * (max(self.current_indent, term_len(prefix)) + 4)\n            self.write(\n                wrap_text(\n                    args, text_width, initial_indent=indent, subsequent_indent=indent\n                )\n            )\n\n        self.write(\"\\n\")\n\n    def write_heading(self, heading):\n        \"\"\"Writes a heading into the buffer.\"\"\"\n        self.write(f\"{'':>{self.current_indent}}{heading}:\\n\")\n\n    def write_paragraph(self):\n        \"\"\"Writes a paragraph into the buffer.\"\"\"\n        if self.buffer:\n            self.write(\"\\n\")\n\n    def write_text(self, text):\n        \"\"\"Writes re-indented text into the buffer.  This rewraps and\n        preserves paragraphs.\n        \"\"\"\n        text_width = max(self.width - self.current_indent, 11)\n        indent = \" \" * self.current_indent\n        self.write(\n            wrap_text(\n                text,\n                text_width,\n                initial_indent=indent,\n                subsequent_indent=indent,\n                preserve_paragraphs=True,\n            )\n        )\n        self.write(\"\\n\")\n\n    def write_dl(self, rows, col_max=30, col_spacing=2):\n        \"\"\"Writes a definition list into the buffer.  This is how options\n        and commands are usually formatted.\n\n        :param rows: a list of two item tuples for the terms and values.\n        :param col_max: the maximum width of the first column.\n        :param col_spacing: the number of spaces between the first and\n                            second column.\n        \"\"\"\n        rows = list(rows)\n        widths = measure_table(rows)\n        if len(widths) != 2:\n            raise TypeError(\"Expected two columns for definition list\")\n\n        first_col = min(widths[0], col_max) + col_spacing\n\n        for first, second in iter_rows(rows, len(widths)):\n            self.write(f\"{'':>{self.current_indent}}{first}\")\n            if not second:\n                self.write(\"\\n\")\n                continue\n            if term_len(first) <= first_col - col_spacing:\n                self.write(\" \" * (first_col - term_len(first)))\n            else:\n                self.write(\"\\n\")\n                self.write(\" \" * (first_col + self.current_indent))\n\n            text_width = max(self.width - first_col - 2, 10)\n            wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True)\n            lines = wrapped_text.splitlines()\n\n            if lines:\n                self.write(f\"{lines[0]}\\n\")\n\n                for line in lines[1:]:\n                    self.write(f\"{'':>{first_col + self.current_indent}}{line}\\n\")\n\n                if len(lines) > 1:\n                    # separate long help from next option\n                    self.write(\"\\n\")\n            else:\n                self.write(\"\\n\")\n\n    @contextmanager\n    def section(self, name):\n        \"\"\"Helpful context manager that writes a paragraph, a heading,\n        and the indents.\n\n        :param name: the section name that is written as heading.\n        \"\"\"\n        self.write_paragraph()\n        self.write_heading(name)\n        self.indent()\n        try:\n            yield\n        finally:\n            self.dedent()\n\n    @contextmanager\n    def indentation(self):\n        \"\"\"A context manager that increases the indentation.\"\"\"\n        self.indent()\n        try:\n            yield\n        finally:\n            self.dedent()\n\n    def getvalue(self):\n        \"\"\"Returns the buffer contents.\"\"\"\n        return \"\".join(self.buffer)\n\n\ndef join_options(options):\n    \"\"\"Given a list of option strings this joins them in the most appropriate\n    way and returns them in the form ``(formatted_string,\n    any_prefix_is_slash)`` where the second item in the tuple is a flag that\n    indicates if any of the option prefixes was a slash.\n    \"\"\"\n    rv = []\n    any_prefix_is_slash = False\n    for opt in options:\n        prefix = split_opt(opt)[0]\n        if prefix == \"/\":\n            any_prefix_is_slash = True\n        rv.append((len(prefix), opt))\n\n    rv.sort(key=lambda x: x[0])\n\n    rv = \", \".join(x[1] for x in rv)\n    return rv, any_prefix_is_slash\n", "path": "src/click/formatting.py"}], "after_files": [{"content": "import typing as t\nfrom contextlib import contextmanager\n\nfrom ._compat import term_len\nfrom .parser import split_opt\n\n# Can force a width.  This is used by the test system\nFORCED_WIDTH: t.Optional[int] = None\n\n\ndef measure_table(rows):\n    widths = {}\n    for row in rows:\n        for idx, col in enumerate(row):\n            widths[idx] = max(widths.get(idx, 0), term_len(col))\n    return tuple(y for x, y in sorted(widths.items()))\n\n\ndef iter_rows(rows, col_count):\n    for row in rows:\n        row = tuple(row)\n        yield row + (\"\",) * (col_count - len(row))\n\n\ndef wrap_text(\n    text, width=78, initial_indent=\"\", subsequent_indent=\"\", preserve_paragraphs=False\n):\n    \"\"\"A helper function that intelligently wraps text.  By default, it\n    assumes that it operates on a single paragraph of text but if the\n    `preserve_paragraphs` parameter is provided it will intelligently\n    handle paragraphs (defined by two empty lines).\n\n    If paragraphs are handled, a paragraph can be prefixed with an empty\n    line containing the ``\\\\b`` character (``\\\\x08``) to indicate that\n    no rewrapping should happen in that block.\n\n    :param text: the text that should be rewrapped.\n    :param width: the maximum width for the text.\n    :param initial_indent: the initial indent that should be placed on the\n                           first line as a string.\n    :param subsequent_indent: the indent string that should be placed on\n                              each consecutive line.\n    :param preserve_paragraphs: if this flag is set then the wrapping will\n                                intelligently handle paragraphs.\n    \"\"\"\n    from ._textwrap import TextWrapper\n\n    text = text.expandtabs()\n    wrapper = TextWrapper(\n        width,\n        initial_indent=initial_indent,\n        subsequent_indent=subsequent_indent,\n        replace_whitespace=False,\n    )\n    if not preserve_paragraphs:\n        return wrapper.fill(text)\n\n    p = []\n    buf = []\n    indent = None\n\n    def _flush_par():\n        if not buf:\n            return\n        if buf[0].strip() == \"\\b\":\n            p.append((indent or 0, True, \"\\n\".join(buf[1:])))\n        else:\n            p.append((indent or 0, False, \" \".join(buf)))\n        del buf[:]\n\n    for line in text.splitlines():\n        if not line:\n            _flush_par()\n            indent = None\n        else:\n            if indent is None:\n                orig_len = term_len(line)\n                line = line.lstrip()\n                indent = orig_len - term_len(line)\n            buf.append(line)\n    _flush_par()\n\n    rv = []\n    for indent, raw, text in p:\n        with wrapper.extra_indent(\" \" * indent):\n            if raw:\n                rv.append(wrapper.indent_only(text))\n            else:\n                rv.append(wrapper.fill(text))\n\n    return \"\\n\\n\".join(rv)\n\n\nclass HelpFormatter:\n    \"\"\"This class helps with formatting text-based help pages.  It's\n    usually just needed for very special internal cases, but it's also\n    exposed so that developers can write their own fancy outputs.\n\n    At present, it always writes into memory.\n\n    :param indent_increment: the additional increment for each level.\n    :param width: the width for the text.  This defaults to the terminal\n                  width clamped to a maximum of 78.\n    \"\"\"\n\n    def __init__(self, indent_increment=2, width=None, max_width=None):\n        import shutil\n\n        self.indent_increment = indent_increment\n        if max_width is None:\n            max_width = 80\n        if width is None:\n            width = FORCED_WIDTH\n            if width is None:\n                width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50)\n        self.width = width\n        self.current_indent = 0\n        self.buffer = []\n\n    def write(self, string):\n        \"\"\"Writes a unicode string into the internal buffer.\"\"\"\n        self.buffer.append(string)\n\n    def indent(self):\n        \"\"\"Increases the indentation.\"\"\"\n        self.current_indent += self.indent_increment\n\n    def dedent(self):\n        \"\"\"Decreases the indentation.\"\"\"\n        self.current_indent -= self.indent_increment\n\n    def write_usage(self, prog, args=\"\", prefix=\"Usage: \"):\n        \"\"\"Writes a usage line into the buffer.\n\n        :param prog: the program name.\n        :param args: whitespace separated list of arguments.\n        :param prefix: the prefix for the first line.\n        \"\"\"\n        usage_prefix = f\"{prefix:>{self.current_indent}}{prog} \"\n        text_width = self.width - self.current_indent\n\n        if text_width >= (term_len(usage_prefix) + 20):\n            # The arguments will fit to the right of the prefix.\n            indent = \" \" * term_len(usage_prefix)\n            self.write(\n                wrap_text(\n                    args,\n                    text_width,\n                    initial_indent=usage_prefix,\n                    subsequent_indent=indent,\n                )\n            )\n        else:\n            # The prefix is too long, put the arguments on the next line.\n            self.write(usage_prefix)\n            self.write(\"\\n\")\n            indent = \" \" * (max(self.current_indent, term_len(prefix)) + 4)\n            self.write(\n                wrap_text(\n                    args, text_width, initial_indent=indent, subsequent_indent=indent\n                )\n            )\n\n        self.write(\"\\n\")\n\n    def write_heading(self, heading):\n        \"\"\"Writes a heading into the buffer.\"\"\"\n        self.write(f\"{'':>{self.current_indent}}{heading}:\\n\")\n\n    def write_paragraph(self):\n        \"\"\"Writes a paragraph into the buffer.\"\"\"\n        if self.buffer:\n            self.write(\"\\n\")\n\n    def write_text(self, text):\n        \"\"\"Writes re-indented text into the buffer.  This rewraps and\n        preserves paragraphs.\n        \"\"\"\n        text_width = max(self.width - self.current_indent, 11)\n        indent = \" \" * self.current_indent\n        self.write(\n            wrap_text(\n                text,\n                text_width,\n                initial_indent=indent,\n                subsequent_indent=indent,\n                preserve_paragraphs=True,\n            )\n        )\n        self.write(\"\\n\")\n\n    def write_dl(self, rows, col_max=30, col_spacing=2):\n        \"\"\"Writes a definition list into the buffer.  This is how options\n        and commands are usually formatted.\n\n        :param rows: a list of two item tuples for the terms and values.\n        :param col_max: the maximum width of the first column.\n        :param col_spacing: the number of spaces between the first and\n                            second column.\n        \"\"\"\n        rows = list(rows)\n        widths = measure_table(rows)\n        if len(widths) != 2:\n            raise TypeError(\"Expected two columns for definition list\")\n\n        first_col = min(widths[0], col_max) + col_spacing\n\n        for first, second in iter_rows(rows, len(widths)):\n            self.write(f\"{'':>{self.current_indent}}{first}\")\n            if not second:\n                self.write(\"\\n\")\n                continue\n            if term_len(first) <= first_col - col_spacing:\n                self.write(\" \" * (first_col - term_len(first)))\n            else:\n                self.write(\"\\n\")\n                self.write(\" \" * (first_col + self.current_indent))\n\n            text_width = max(self.width - first_col - 2, 10)\n            wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True)\n            lines = wrapped_text.splitlines()\n\n            if lines:\n                self.write(f\"{lines[0]}\\n\")\n\n                for line in lines[1:]:\n                    self.write(f\"{'':>{first_col + self.current_indent}}{line}\\n\")\n            else:\n                self.write(\"\\n\")\n\n    @contextmanager\n    def section(self, name):\n        \"\"\"Helpful context manager that writes a paragraph, a heading,\n        and the indents.\n\n        :param name: the section name that is written as heading.\n        \"\"\"\n        self.write_paragraph()\n        self.write_heading(name)\n        self.indent()\n        try:\n            yield\n        finally:\n            self.dedent()\n\n    @contextmanager\n    def indentation(self):\n        \"\"\"A context manager that increases the indentation.\"\"\"\n        self.indent()\n        try:\n            yield\n        finally:\n            self.dedent()\n\n    def getvalue(self):\n        \"\"\"Returns the buffer contents.\"\"\"\n        return \"\".join(self.buffer)\n\n\ndef join_options(options):\n    \"\"\"Given a list of option strings this joins them in the most appropriate\n    way and returns them in the form ``(formatted_string,\n    any_prefix_is_slash)`` where the second item in the tuple is a flag that\n    indicates if any of the option prefixes was a slash.\n    \"\"\"\n    rv = []\n    any_prefix_is_slash = False\n    for opt in options:\n        prefix = split_opt(opt)[0]\n        if prefix == \"/\":\n            any_prefix_is_slash = True\n        rv.append((len(prefix), opt))\n\n    rv.sort(key=lambda x: x[0])\n\n    rv = \", \".join(x[1] for x in rv)\n    return rv, any_prefix_is_slash\n", "path": "src/click/formatting.py"}]}