Skip to content

Instantly share code, notes, and snippets.

@panzi
Last active May 20, 2025 20:33
Show Gist options
  • Save panzi/b4a51b3968f67b9ff4c99459fb9c5b3d to your computer and use it in GitHub Desktop.
Save panzi/b4a51b3968f67b9ff4c99459fb9c5b3d to your computer and use it in GitHub Desktop.
Python argparse help formatter that keeps new lines and doesn't break words (so URLs are preserved), but still wraps lines. Use with: `argparse.ArgumentParser(formatter_class=SmartFormatter)`
# Version 2:
# This version preserves space, including indentation.
#
# Also if you have lists like this:
#
# foo ....... bla bla bla
# bar baz ... bla bla bla bla
#
# It will re-formated it to e.g. this:
#
# foo ....... bla bla
# bla
# bar baz ... bla bla
# bla bla
#
# This detects a sequence of >=3 periods or >=3 spaces.
#
# LICNESE: Public Domain/CC0
import argparse
import re
SPACE = re.compile(r'\s')
NON_SPACE = re.compile(r'\S')
class SmartFormatter(argparse.HelpFormatter):
def _split_lines(self, text: str, width: int) -> list[str]:
lines: list[str] = []
for line_str in text.split('\n'):
match = NON_SPACE.search(line_str)
if not match:
lines.append('')
continue
prefix = line_str[:match.start()]
if len(prefix) >= width:
lines.append('')
prefix = ''
line_len = prefix_len = len(prefix)
line: list[str] = [prefix]
pos = match.start()
while pos < len(line_str):
match = NON_SPACE.search(line_str, pos)
if not match:
break
next_pos = match.start()
space = line_str[pos:next_pos]
line_len += len(space)
if line_len >= width:
lines.append(''.join(line))
line.clear()
line.append(prefix)
line_len = prefix_len
else:
line.append(space)
pos = next_pos
match = SPACE.search(line_str, pos)
if not match:
next_pos = len(line_str)
else:
next_pos = match.start()
word = line_str[pos:next_pos]
word_len = len(word)
line_len += word_len
if line_len > width:
lines.append(''.join(line))
line.clear()
line.append(prefix)
line_len = prefix_len + word_len
elif word_len >= 3:
if all(c == '.' for c in word) and line_str[next_pos:next_pos + 1].isspace():
prefix_len = line_len + 1
prefix = ' ' * prefix_len
elif all(c == ' ' for c in word):
prefix_len = line_len
prefix = ' ' * prefix_len
line.append(word)
pos = next_pos
lines.append(''.join(line))
return lines
def _fill_text(self, text: str, width: int, indent: str) -> str:
return '\n'.join(indent + line for line in self._split_lines(text, width - len(indent)))
@chris-vecchio
Copy link

Thanks for sharing this! You just saved me a ton of time!

@swirle13
Copy link

swirle13 commented Feb 9, 2024

Thank you so much for this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment