Repository: sphinx-doc/sphinx

Issue:
Improve index for command line options
### Problem
Index entries created for command line options (the **cmdoption** and **option** directives) contains contain full line describing the option, with arguments and aliases. As result, similar options for different programs are not grouped, and separate entries for aliases are not created.

```
.. cmdoption:: --create <tarfile> <source1> ... <sourceN>
```
and
```
.. cmdoption:: --create <zipfile> <source1> ... <sourceN>
```
create two separate entries because the name of argument is different.

```
.. cmdoption:: -h, --help
```
creates a single entry for `-h, --help`, while
```
.. cmdoption:: -h
            --help
```
creates two entries, for `-h` and `--help`.

#### Procedure to reproduce the problem
Look for example at the index of Python documentation: https://docs.python.org/3/genindex-Symbols.html . It contains options for the Python interpreter itself and for some modules that provides a command line interface.

#### Error logs / results
```
--create <tarfile> <source1> ... <sourceN>
    tarfile command line option
--create <zipfile> <source1> ... <sourceN>
    zipfile command line option
```
```
--help
    command line option
    trace command line option
```
```
-c <command>
    command line option
-c <tarfile> <source1> ... <sourceN>
    tarfile command line option
-c <zipfile> <source1> ... <sourceN>
    zipfile command line option
-c, --catch
    unittest command line option
-c, --compress
    zipapp command line option
-c, --count
    trace command line option
```
```
-h
    command line option
-h, --help
    command line option
    timeit command line option
    tokenize command line option
    zipapp command line option
```
- https://docs.python.org/3/genindex-Symbols.html

#### Expected results
I expect all options with the same name are grouped and separate entries are created for aliases.
```
--create
    tarfile command line option
    zipfile command line option
```
```
--help
    command line option
    gzip command line option
    json.tool command line option
    timeit command line option
    tokenize command line option
    trace command line option
    zipapp command line option
```
```
-c
    command line option
    tarfile command line option
    trace command line option
    unittest command line option
    zipapp command line option
    zipfile command line option
```
```
-h
    command line option
    gzip command line option
    json.tool command line option
    timeit command line option
    tokenize command line option
    zipapp command line option
```


Discussion:

Patch:
diff --git a/CHANGES b/CHANGES
index 8f7b497f3..10b188ca0 100644
--- a/CHANGES
+++ b/CHANGES
@@ -51,6 +51,8 @@ Bugs fixed
 * #6531: Failed to load last environment object when extension added
 * #736: Invalid sort in pair index
 * #6527: :confval:`last_updated` wrongly assumes timezone as UTC
+* #5592: std domain: :rst:dir:`option` directive registers an index entry for
+  each comma separated option
 
 Testing
 --------
diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py
index 971589367..66171646a 100644
--- a/sphinx/domains/std.py
+++ b/sphinx/domains/std.py
@@ -198,12 +198,14 @@ def add_target_and_index(self, firstname: str, sig: str, signode: desc_signature
             domain.add_program_option(currprogram, optname,
                                       self.env.docname, signode['ids'][0])
 
-            # create only one index entry for the whole option
-            if optname == firstname:
-                self.indexnode['entries'].append(
-                    ('pair', _('%scommand line option; %s') %
-                     ((currprogram and currprogram + ' ' or ''), sig),
-                     signode['ids'][0], '', None))
+        # create an index entry
+        if currprogram:
+            descr = _('%s command line option') % currprogram
+        else:
+            descr = _('command line option')
+        for option in sig.split(', '):
+            entry = '; '.join([descr, option])
+            self.indexnode['entries'].append(('pair', entry, signode['ids'][0], '', None))
 
 
 class Program(SphinxDirective):


Test patch:
diff --git a/tests/test_domain_std.py b/tests/test_domain_std.py
index b4528a6c9..1a03060e6 100644
--- a/tests/test_domain_std.py
+++ b/tests/test_domain_std.py
@@ -261,22 +261,24 @@ def test_cmdoption(app):
 
 
 def test_multiple_cmdoptions(app):
-    text = (".. program:: ls\n"
+    text = (".. program:: cmd\n"
             "\n"
-            ".. option:: -h, --help\n")
+            ".. option:: -o directory, --output directory\n")
     domain = app.env.get_domain('std')
     doctree = restructuredtext.parse(app, text)
     assert_node(doctree, (addnodes.index,
-                          [desc, ([desc_signature, ([desc_name, "-h"],
-                                                    [desc_addname, ()],
+                          [desc, ([desc_signature, ([desc_name, "-o"],
+                                                    [desc_addname, " directory"],
                                                     [desc_addname, ", "],
-                                                    [desc_name, "--help"],
-                                                    [desc_addname, ()])],
+                                                    [desc_name, "--output"],
+                                                    [desc_addname, " directory"])],
                                   [desc_content, ()])]))
     assert_node(doctree[0], addnodes.index,
-                entries=[('pair', 'ls command line option; -h, --help',
-                          'cmdoption-ls-h', '', None)])
-    assert ('ls', '-h') in domain.progoptions
-    assert ('ls', '--help') in domain.progoptions
-    assert domain.progoptions[('ls', '-h')] == ('index', 'cmdoption-ls-h')
-    assert domain.progoptions[('ls', '--help')] == ('index', 'cmdoption-ls-h')
+                entries=[('pair', 'cmd command line option; -o directory',
+                          'cmdoption-cmd-o', '', None),
+                         ('pair', 'cmd command line option; --output directory',
+                          'cmdoption-cmd-o', '', None)])
+    assert ('cmd', '-o') in domain.progoptions
+    assert ('cmd', '--output') in domain.progoptions
+    assert domain.progoptions[('cmd', '-o')] == ('index', 'cmdoption-cmd-o')
+    assert domain.progoptions[('cmd', '--output')] == ('index', 'cmdoption-cmd-o')