Repository: sphinx-doc/sphinx

Issue:
Why deprecate the `html_codeblock_linenos_style`  option?
**Is your feature request related to a problem? Please describe.**
We've been porting the mkdocs-material theme to sphinx-immaterial, and found the the mkdocs-material theme uses tables to represent literal code blocks with line numbers. With Sphinx's default setting
```py
html_codeblock_linenos_style = "inline"
```
We found a few problems:
1. The line numbers are copied to the clipboard when using clipboard.js.
2. The CSS inherited from mkdocs-material cannot distinguish line numbers from the rest of the literal code block. Thus no intended CSS gets used.
3. Line numbers scroll horizontally with the rest of the literal code block. Ideally, we expect the line numbers to be statically positioned while horizontally scrolling the rest of the literal code block.

**Describe the solution you'd like**
Please don't deprecate the `html_codeblock_linenos_style` config option in Sphinx v6.0.

**Describe alternatives you've considered**
For now, we're thinking of having the sphinx-immaterial theme assert the option to use
```py
html_codeblock_linenos_style = "table"
```
When/If Sphinx v6.0 removes the option, we're going to have to overwrite the `visit_literal_block()` to restore this functionality.

**Additional context**
> I talked with @tk0miya at the Sphinx(jp) hack-a-thon event, and we discussed that there is no need to leave table output in the future.

I've read https://github.com/sphinx-doc/sphinx/pull/7879#issuecomment-650717211, but I don't see any good rationality to deem the option deprecated. The sphinx builtin themes aren't the only themes that supply their own CSS (we don't inherit any CSS from sphinx builtin themes). If writing CSS for code blocks with line numbers (using `"table"`) is too complex, then leave it to the theme designers to choose how to set the option - don't deprive them of the option all together.

We're not as flexible as we'd like to be concerning CSS changes. This is because we need to minimize the possible merge conflicts when merging in updates from the mkdocs-material theme. Same reason goes for using clipboard.js instead of executablebooks/sphinx-copy-button extension (though this isn't as strict a requirement as keeping the CSS unaltered).

Original issue for the sphinx-immaterial theme is https://github.com/jbms/sphinx-immaterial/issues/26



Discussion:

Patch:
diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst
index ff428a655..941b6038d 100644
--- a/doc/usage/configuration.rst
+++ b/doc/usage/configuration.rst
@@ -1065,6 +1065,20 @@ that use Sphinx's HTMLWriter class.
 
    .. versionadded:: 1.8
 
+.. confval:: html_codeblock_linenos_style
+
+   The style of line numbers for code-blocks.
+
+   * ``'table'`` -- display line numbers using ``<table>`` tag
+   * ``'inline'`` -- display line numbers using ``<span>`` tag (default)
+
+   .. versionadded:: 3.2
+   .. versionchanged:: 4.0
+
+      It defaults to ``'inline'``.
+
+   .. deprecated:: 4.0
+
 .. confval:: html_context
 
    A dictionary of values to pass into the template engine's context for all
diff --git a/sphinx/builders/html/__init__.py b/sphinx/builders/html/__init__.py
index 71952199b..d5264e43e 100644
--- a/sphinx/builders/html/__init__.py
+++ b/sphinx/builders/html/__init__.py
@@ -23,7 +23,7 @@
 from sphinx import version_info as sphinx_version
 from sphinx.application import Sphinx
 from sphinx.builders import Builder
-from sphinx.config import Config
+from sphinx.config import ENUM, Config
 from sphinx.deprecation import RemovedInSphinx70Warning, deprecated_alias
 from sphinx.domains import Domain, Index, IndexEntry
 from sphinx.environment import BuildEnvironment
@@ -1371,6 +1371,8 @@ def setup(app: Sphinx) -> Dict[str, Any]:
     app.add_config_value('html_search_scorer', '', None)
     app.add_config_value('html_scaled_image_link', True, 'html')
     app.add_config_value('html_baseurl', '', 'html')
+    app.add_config_value('html_codeblock_linenos_style', 'inline', 'html',  # RemovedInSphinx70Warning  # NOQA
+                         ENUM('table', 'inline'))
     app.add_config_value('html_math_renderer', None, 'env')
     app.add_config_value('html4_writer', False, 'html')
 
diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py
index cb0794c04..680a47ac8 100644
--- a/sphinx/writers/html.py
+++ b/sphinx/writers/html.py
@@ -446,11 +446,14 @@ def visit_literal_block(self, node: Element) -> None:
             return super().visit_literal_block(node)
 
         lang = node.get('language', 'default')
-        linenos = node.get('linenos', False) and "inline"
+        linenos = node.get('linenos', False)
         highlight_args = node.get('highlight_args', {})
         highlight_args['force'] = node.get('force', False)
         opts = self.config.highlight_options.get(lang, {})
 
+        if linenos and self.config.html_codeblock_linenos_style:
+            linenos = self.config.html_codeblock_linenos_style
+
         highlighted = self.highlighter.highlight_block(
             node.rawsource, lang, opts=opts, linenos=linenos,
             location=node, **highlight_args
diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py
index a169c6069..a68951a7f 100644
--- a/sphinx/writers/html5.py
+++ b/sphinx/writers/html5.py
@@ -404,11 +404,14 @@ def visit_literal_block(self, node: Element) -> None:
             return super().visit_literal_block(node)
 
         lang = node.get('language', 'default')
-        linenos = node.get('linenos', False) and "inline"
+        linenos = node.get('linenos', False)
         highlight_args = node.get('highlight_args', {})
         highlight_args['force'] = node.get('force', False)
         opts = self.config.highlight_options.get(lang, {})
 
+        if linenos and self.config.html_codeblock_linenos_style:
+            linenos = self.config.html_codeblock_linenos_style
+
         highlighted = self.highlighter.highlight_block(
             node.rawsource, lang, opts=opts, linenos=linenos,
             location=node, **highlight_args


Test patch:
diff --git a/tests/test_build_html.py b/tests/test_build_html.py
index 1a717f152..fa0bbac7c 100644
--- a/tests/test_build_html.py
+++ b/tests/test_build_html.py
@@ -1598,8 +1598,21 @@ def test_html_scaled_image_link(app):
                      context)
 
 
-@pytest.mark.sphinx('html', testroot='reST-code-block')
-def test_html_codeblock_linenos_style(app):
+@pytest.mark.sphinx('html', testroot='reST-code-block',
+                    confoverrides={'html_codeblock_linenos_style': 'table'})
+def test_html_codeblock_linenos_style_table(app):
+    app.build()
+    content = (app.outdir / 'index.html').read_text(encoding='utf8')
+
+    assert ('<div class="linenodiv"><pre><span class="normal">1</span>\n'
+            '<span class="normal">2</span>\n'
+            '<span class="normal">3</span>\n'
+            '<span class="normal">4</span></pre></div>') in content
+
+
+@pytest.mark.sphinx('html', testroot='reST-code-block',
+                    confoverrides={'html_codeblock_linenos_style': 'inline'})
+def test_html_codeblock_linenos_style_inline(app):
     app.build()
     content = (app.outdir / 'index.html').read_text(encoding='utf8')