diff --git a/invoke/program.py b/invoke/program.py index 67b879b6..d49e9411 100644 --- a/invoke/program.py +++ b/invoke/program.py @@ -954,12 +954,13 @@ def print_columns( # Calculate column sizes: don't wrap flag specs, give what's left over # to the descriptions. name_width = max(len(x[0]) for x in tuples) - desc_width = ( + desc_width = max( + 1, pty_size()[0] - name_width - self.leading_indent_width - self.col_padding - - 1 + - 1, ) wrapper = textwrap.TextWrapper(width=desc_width) for name, help_str in tuples: diff --git a/tests/program.py b/tests/program.py index 3b6765cd..a08b2ff0 100644 --- a/tests/program.py +++ b/tests/program.py @@ -810,6 +810,21 @@ def docstrings_are_wrapped_to_terminal_width(self): ), ) + def long_task_names_may_exhaust_terminal_width(self): + name = ( + "my-very-long-task-name-that-is-completely-legit-but-make-" + "grep-crash-aaaaaa" + ) + + def body(c): + pass # pragma: no cover + + program = Program(namespace=Collection(Task(body, name=name))) + with patch("invoke.program.pty_size", return_value=(80, 24)): + stdout, _ = run("--list", program=program) + + assert " {}\n".format(name) in stdout + def empty_collections_say_no_tasks(self): expect( "-c empty -l", err="No tasks found in collection 'empty'!\n"