From 762ed8540a1635784fe84682582617b0c0981ceb Mon Sep 17 00:00:00 2001 From: benkrikler <4083697+benkrikler@users.noreply.github.com> Date: Fri, 28 Jul 2023 06:52:48 +0200 Subject: [PATCH] Add line numbers in ``sphinx.ext.viewdoc`` (#6319) Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com> --- CHANGES | 3 ++ doc/usage/extensions/viewcode.rst | 8 +++++ sphinx/ext/viewcode.py | 17 ++++++----- tests/test_ext_viewcode.py | 51 +++++++++++++++++++------------ 4 files changed, 53 insertions(+), 26 deletions(-) diff --git a/CHANGES b/CHANGES index 1b6d26b3369..7eba3029a0d 100644 --- a/CHANGES +++ b/CHANGES @@ -24,6 +24,9 @@ Features added in many more places. * #5474: coverage: Print summary statistics tables. Patch by Jorge Leitao. +* #6319: viewcode: Add :confval:`viewcode_line_numbers` to control + whether line numbers are added to rendered source code. + Patch by Ben Krikler. Bugs fixed ---------- diff --git a/doc/usage/extensions/viewcode.rst b/doc/usage/extensions/viewcode.rst index d3c3c44fbd5..c90d2ba552d 100644 --- a/doc/usage/extensions/viewcode.rst +++ b/doc/usage/extensions/viewcode.rst @@ -73,6 +73,14 @@ Configuration `epubcheck `_'s score becomes worse even if the reader supports. +.. confval:: viewcode_line_numbers + + Default: ``False``. + + If set to ``True``, inline line numbers will be added to the highlighted code. + + .. versionadded:: 7.2 + .. event:: viewcode-find-source (app, modname) .. versionadded:: 1.8 diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index 6bb957db8f0..40d9250d93c 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -253,7 +253,8 @@ def collect_pages(app: Sphinx) -> Generator[tuple[str, dict[str, Any], str], Non lexer = env.config.highlight_language else: lexer = 'python' - highlighted = highlighter.highlight_block(code, lexer, linenos=False) + linenos = 'inline' * env.config.viewcode_line_numbers + highlighted = highlighter.highlight_block(code, lexer, linenos=linenos) # split the code into lines lines = highlighted.splitlines() # split off wrap markup from the first line of the actual code @@ -263,15 +264,16 @@ def collect_pages(app: Sphinx) -> Generator[tuple[str, dict[str, Any], str], Non # now that we have code lines (starting at index 1), insert anchors for # the collected tags (HACK: this only works if the tag boundaries are # properly nested!) - maxindex = len(lines) - 1 + max_index = len(lines) - 1 + link_text = _('[docs]') for name, docname in used.items(): type, start, end = tags[name] backlink = urito(pagename, docname) + '#' + refname + '.' + name - lines[start] = ( - '
%s' % (name, backlink, _('[docs]')) + - lines[start]) - lines[min(end, maxindex)] += '
' + lines[start] = (f'
\n' + f'{link_text}\n' + + lines[start]) + lines[min(end, max_index)] += '
\n' + # try to find parents (for submodules) parents = [] parent = modname @@ -327,6 +329,7 @@ def setup(app: Sphinx) -> dict[str, Any]: app.add_config_value('viewcode_import', None, False) app.add_config_value('viewcode_enable_epub', False, False) app.add_config_value('viewcode_follow_imported_members', True, False) + app.add_config_value('viewcode_line_numbers', False, 'env', (bool,)) app.connect('doctree-read', doctree_read) app.connect('env-merge-info', env_merge_info) app.connect('env-purge-doc', env_purge_doc) diff --git a/tests/test_ext_viewcode.py b/tests/test_ext_viewcode.py index 444f2f348da..74df2a4c566 100644 --- a/tests/test_ext_viewcode.py +++ b/tests/test_ext_viewcode.py @@ -7,10 +7,7 @@ import pytest -@pytest.mark.sphinx(testroot='ext-viewcode', freshenv=True) -def test_viewcode(app, status, warning): - app.builder.build_all() - +def check_viewcode_output(app, warning): warnings = re.sub(r'\\+', '/', warning.getvalue()) assert re.findall( r"index.rst:\d+: WARNING: Object named 'func1' not found in include " + @@ -32,23 +29,39 @@ def test_viewcode(app, status, warning): assert result.count('this is the class attribute class_attr') == 2 result = (app.outdir / '_modules/spam/mod1.html').read_text(encoding='utf8') - result = re.sub('', '', result) # filter pygments classes + result = re.sub('', '', result) # filter pygments classes + assert ('
\n' + '[docs]\n') in result + assert '@decorator\n' in result + assert 'class Class1:\n' in result if pygments.__version__ >= '2.14.0': - assert ('
[docs]' - '@decorator\n' - 'class Class1:\n' - ' """\n' - ' this is Class1\n' - ' """
\n') in result + assert ' """\n' in result else: - assert ('
[docs]' - '@decorator\n' - 'class Class1:\n' - ' """\n' - ' this is Class1\n' - ' """
\n') in result + assert ' """\n' in result + assert ' this is Class1\n' in result + assert ' """\n' in result + + return result + + +@pytest.mark.sphinx(testroot='ext-viewcode', freshenv=True, + confoverrides={"viewcode_line_numbers": True}) +def test_viewcode_linenos(app, warning): + shutil.rmtree(app.outdir / '_modules', ignore_errors=True) + app.builder.build_all() + + result = check_viewcode_output(app, warning) + assert ' 1' in result + + +@pytest.mark.sphinx(testroot='ext-viewcode', freshenv=True, + confoverrides={"viewcode_line_numbers": False}) +def test_viewcode(app, warning): + shutil.rmtree(app.outdir / '_modules', ignore_errors=True) + app.builder.build_all() + + result = check_viewcode_output(app, warning) + assert 'class="linenos">' not in result @pytest.mark.sphinx('epub', testroot='ext-viewcode')