ENH: Multiline help (#1559) * ENH: Multiline help * STY: Use %(default)r * DOC: Document rationale
diff --git a/codespell_lib/__main__.py b/codespell_lib/__main__.py new file mode 100644 index 0000000..2d8f4b6 --- /dev/null +++ b/codespell_lib/__main__.py
@@ -0,0 +1,4 @@ +from ._codespell import _script_main + +if __name__ == '__main__': + _script_main()
diff --git a/codespell_lib/_codespell.py b/codespell_lib/_codespell.py index 68a0bb4..2e6689f 100755 --- a/codespell_lib/_codespell.py +++ b/codespell_lib/_codespell.py
@@ -25,6 +25,7 @@ import os import re import sys +import textwrap word_regex_def = u"[\\w\\-'’`]+" encodings = ('utf-8', 'iso-8859-1') @@ -206,8 +207,34 @@ # -.-:-.-:-.-:-.:-.-:-.-:-.-:-.-:-.:-.-:-.-:-.-:-.-:-.:-.-:- +# If someday this breaks, we can just switch to using RawTextHelpFormatter, +# but it has the disadvantage of not wrapping our long lines. + +class NewlineHelpFormatter(argparse.HelpFormatter): + """Help formatter that preserves newlines and deals with lists.""" + + def _split_lines(self, text, width): + parts = text.split('\n') + out = list() + for pi, part in enumerate(parts): + # Eventually we could allow others... + indent_start = '- ' + if part.startswith(indent_start): + offset = len(indent_start) + else: + offset = 0 + part = part[offset:] + part = self._whitespace_matcher.sub(' ', part).strip() + parts = textwrap.wrap(part, width - offset) + parts = [' ' * offset + p for p in parts] + if offset: + parts[0] = indent_start + parts[0][offset:] + out.extend(parts) + return out + + def parse_options(args): - parser = argparse.ArgumentParser() + parser = argparse.ArgumentParser(formatter_class=NewlineHelpFormatter) parser.set_defaults(colors=sys.stdout.isatty()) parser.add_argument('--version', action='version', version=VERSION) @@ -231,16 +258,15 @@ 'corrections. If this flag is not specified or ' 'equals "-" then the default dictionary is used. ' 'This option can be specified multiple times.') - builtin_opts = ', '.join( - '%r %s' % (d[0], d[1]) for d in _builtin_dictionaries) + builtin_opts = '\n- '.join([''] + [ + '%r %s' % (d[0], d[1]) for d in _builtin_dictionaries]) parser.add_argument('--builtin', dest='builtin', default=_builtin_default, metavar='BUILTIN-LIST', help='Comma-separated list of builtin dictionaries ' 'to include (when "-D -" or no "-D" is passed). ' - 'Current options are:\n%s. The default is ' - '"--builtin %s".' - % (builtin_opts, _builtin_default)) + 'Current options are:' + builtin_opts + '\n' + 'The default is %(default)r.') parser.add_argument('-I', '--ignore-words', action='append', metavar='FILE', help='File that contains words which will be ignored ' @@ -276,22 +302,21 @@ parser.add_argument('-i', '--interactive', action='store', type=int, default=0, - help='Set interactive mode when writing changes. ' - '0: no interactivity. 1: ask for confirmation. ' - '2 ask user to choose one fix when more than one ' - 'is available. 3: both 1 and 2') + help='Set interactive mode when writing changes:\n' + '- 0: no interactivity.\n' + '- 1: ask for confirmation.\n' + '- 2: ask user to choose one fix when more than one is available.\n' # noqa: E501 + '- 3: both 1 and 2') parser.add_argument('-q', '--quiet-level', action='store', type=int, default=2, - help='Bitmask that allows suppressing messages. ' - '0: print all messages. ' - '1: disable warnings about wrong encoding. ' - '2: disable warnings about binary files. ' - '4: omit warnings about automatic fixes that ' - 'were disabled in the dictionary. ' - '8: don\'t print anything for non-automatic ' - 'fixes. ' - '16: don\'t print the list of fixed files. ' + help='Bitmask that allows suppressing messages:\n' + '- 0: print all messages.\n' + '- 1: disable warnings about wrong encoding.\n' + '- 2: disable warnings about binary files.\n' + '- 4: omit warnings about automatic fixes that were disabled in the dictionary.\n' # noqa: E501 + '- 8: don\'t print anything for non-automatic fixes.\n' # noqa: E501 + '- 16: don\'t print the list of fixed files.\n' 'As usual with bitmasks, these levels can be ' 'combined; e.g. use 3 for levels 1+2, 7 for ' '1+2+4, 23 for 1+2+4+16, etc. '