Repository: fniessink/next-action

Issue:
Capitalise the sections in the help information

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2a6d5a5..8a3b394 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
 
+## [Unreleased]
+
+### Fixed
+
+- Capitalise the help information. Fixes #105.
+
 ## [0.16.2] - 2018-06-05
 
 ### Fixed
diff --git a/next_action/arguments/parser.py b/next_action/arguments/parser.py
index 2e2e9e2..6f6fd37 100644
--- a/next_action/arguments/parser.py
+++ b/next_action/arguments/parser.py
@@ -29,16 +29,25 @@ class NextActionArgumentParser(argparse.ArgumentParser):
                         "the tasks from which the next action is selected by specifying contexts the tasks must have "
                         "and/or projects the tasks must belong to.",
             epilog="Use -- to separate options with optional arguments from contexts and projects, in order to handle "
-                   "cases where a context or project is mistaken for an argument to an option.")
+                   "cases where a context or project is mistaken for an argument to an option.",
+            formatter_class=CapitalisedHelpFormatter)
         self.__default_filenames = ["~/todo.txt"]
         self.add_optional_arguments()
+        self.add_configuration_options()
+        self.add_input_options()
+        self.add_output_options()
+        self.add_number_options()
         self.add_filter_arguments()
 
     def add_optional_arguments(self) -> None:
         """ Add the optional arguments to the parser. """
+        self._optionals.title = self._optionals.title.capitalize()
         self.add_argument(
             "--version", action="version", version="%(prog)s {0}".format(next_action.__version__))
-        config_group = self.add_argument_group("configuration options")
+
+    def add_configuration_options(self) -> None:
+        """ Add the configuration options to the parser. """
+        config_group = self.add_argument_group("Configuration options")
         config_file = config_group.add_mutually_exclusive_group()
         config_file.add_argument(
             "-c", "--config-file", metavar="<config.cfg>", type=str, default="~/.next-action.cfg", nargs="?",
@@ -46,12 +55,18 @@ class NextActionArgumentParser(argparse.ArgumentParser):
                  "configuration file")
         config_file.add_argument(
             "-w", "--write-config-file", help="generate a sample configuration file and exit", action="store_true")
-        input_group = self.add_argument_group("input options")
+
+    def add_input_options(self) -> None:
+        """ Add the input options to the parser. """
+        input_group = self.add_argument_group("Input options")
         input_group.add_argument(
             "-f", "--file", action="append", metavar="<todo.txt>", default=self.__default_filenames[:], type=str,
             help="filename of todo.txt file to read; can be '-' to read from standard input; argument can be "
                  "repeated to read tasks from multiple todo.txt files (default: ~/todo.txt)")
-        output_group = self.add_argument_group("output options")
+
+    def add_output_options(self) -> None:
+        """ Add the output/styling options to the parser. """
+        output_group = self.add_argument_group("Output options")
         output_group.add_argument(
             "-r", "--reference", choices=["always", "never", "multiple"], default="multiple",
             help="reference next actions with the name of their todo.txt file (default: when reading multiple "
@@ -60,7 +75,10 @@ class NextActionArgumentParser(argparse.ArgumentParser):
         output_group.add_argument(
             "-s", "--style", metavar="<style>", choices=styles, default=None, nargs="?",
             help="colorize the output; available styles: {0} (default: %(default)s)".format(", ".join(styles)))
-        number_group = self.add_argument_group("show multiple next actions")
+
+    def add_number_options(self) -> None:
+        """ Add the number options to the parser. """
+        number_group = self.add_argument_group("Show multiple next actions")
         number = number_group.add_mutually_exclusive_group()
         number.add_argument(
             "-a", "--all", default=1, action="store_const", dest="number", const=sys.maxsize,
@@ -71,7 +89,7 @@ class NextActionArgumentParser(argparse.ArgumentParser):
 
     def add_filter_arguments(self) -> None:
         """ Add the filter arguments to the parser. """
-        filters = self.add_argument_group("limit the tasks from which the next actions are selected")
+        filters = self.add_argument_group("Limit the tasks from which the next actions are selected")
         date = filters.add_mutually_exclusive_group()
         date.add_argument(
             "-d", "--due", metavar="<due date>", type=date_type, nargs="?", const=datetime.date.max,
@@ -171,6 +189,13 @@ class NextActionArgumentParser(argparse.ArgumentParser):
         namespace.file = list(dict.fromkeys(filenames))
 
 
+class CapitalisedHelpFormatter(argparse.HelpFormatter):
+    """ Capitalise the usage string. """
+    def add_usage(self, usage, actions, groups, prefix=None):
+        prefix = prefix or 'Usage: '
+        return super(CapitalisedHelpFormatter, self).add_usage(usage, actions, groups, prefix or "Usage: ")
+
+
 def filter_type(value: str) -> str:
     """ Return the filter if it's valid, else raise an error. """
     if value.startswith("@") or value.startswith("+"):


Test patch:
diff --git a/tests/unittests/arguments/test_parser.py b/tests/unittests/arguments/test_parser.py
index 4e6a5ec..7a085f1 100644
--- a/tests/unittests/arguments/test_parser.py
+++ b/tests/unittests/arguments/test_parser.py
@@ -11,7 +11,7 @@ from next_action.arguments import config, parse_arguments
 
 
 USAGE_MESSAGE = textwrap.fill(
-    "usage: next-action [-h] [--version] [-c [<config.cfg>] | -w] [-f <todo.txt> ...] [-r <ref>] [-s [<style>]] "
+    "Usage: next-action [-h] [--version] [-c [<config.cfg>] | -w] [-f <todo.txt> ...] [-r <ref>] [-s [<style>]] "
     "[-a | -n <number>] [-d [<due date>] | -o] [-p [<priority>]] [--] [<context|project> ...]", 120) + "\n"
 
 
diff --git a/tests/unittests/test_cli.py b/tests/unittests/test_cli.py
index 8c8978b..23c4ee7 100644
--- a/tests/unittests/test_cli.py
+++ b/tests/unittests/test_cli.py
@@ -65,30 +65,30 @@ class CLITest(unittest.TestCase):
         os.environ['COLUMNS'] = "120"  # Fake that the terminal is wide enough.
         self.assertRaises(SystemExit, next_action)
         self.assertEqual(call("""\
-usage: next-action [-h] [--version] [-c [<config.cfg>] | -w] [-f <todo.txt> ...] [-r <ref>] [-s [<style>]] [-a | -n
+Usage: next-action [-h] [--version] [-c [<config.cfg>] | -w] [-f <todo.txt> ...] [-r <ref>] [-s [<style>]] [-a | -n
 <number>] [-d [<due date>] | -o] [-p [<priority>]] [--] [<context|project> ...]
 
 Show the next action in your todo.txt. The next action is selected from the tasks in the todo.txt file based on task
 properties such as priority, due date, and creation date. Limit the tasks from which the next action is selected by
 specifying contexts the tasks must have and/or projects the tasks must belong to.
 
-optional arguments:
+Optional arguments:
   -h, --help            show this help message and exit
   --version             show program's version number and exit
 
-configuration options:
+Configuration options:
   -c [<config.cfg>], --config-file [<config.cfg>]
                         filename of configuration file to read (default: ~/.next-action.cfg); omit filename to not
                         read any configuration file
   -w, --write-config-file
                         generate a sample configuration file and exit
 
-input options:
+Input options:
   -f <todo.txt>, --file <todo.txt>
                         filename of todo.txt file to read; can be '-' to read from standard input; argument can be
                         repeated to read tasks from multiple todo.txt files (default: ~/todo.txt)
 
-output options:
+Output options:
   -r {always,never,multiple}, --reference {always,never,multiple}
                         reference next actions with the name of their todo.txt file (default: when reading multiple
                         todo.txt files)
@@ -98,12 +98,12 @@ output options:
                         paraiso-dark, paraiso-light, pastie, perldoc, rainbow_dash, rrt, tango, trac, vim, vs, xcode
                         (default: None)
 
-show multiple next actions:
+Show multiple next actions:
   -a, --all             show all next actions
   -n <number>, --number <number>
                         number of next actions to show (default: 1)
 
-limit the tasks from which the next actions are selected:
+Limit the tasks from which the next actions are selected:
   -d [<due date>], --due [<due date>]
                         show only next actions with a due date; if a date is given, show only next actions due on or
                         before that date