Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Add highlight-next-line #2850

Merged
merged 3 commits into from
Dec 21, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 74 additions & 3 deletions docs/_scripts/notebook_hooks.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import logging
import os
import re
from typing import Any, Dict

from mkdocs.structure.pages import Page
from mkdocs.structure.files import Files, File
from mkdocs.structure.pages import Page

from notebook_convert import convert_notebook

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -35,12 +37,81 @@ def on_files(files: Files, **kwargs: Dict[str, Any]):
return new_files


def _highlight_code_blocks(markdown: str) -> str:
"""Find code blocks with highlight comments and add hl_lines attribute.

Args:
markdown: The markdown content to process.

Returns:
updated Markdown code with code blocks containing highlight comments
updated to use the hl_lines attribute.
"""
# Pattern to find code blocks with highlight comments and without
# existing hl_lines for Python and JavaScript
# Pattern to find code blocks with highlight comments, handling optional indentation
code_block_pattern = re.compile(
r"(?P<indent>[ \t]*)```(?P<language>py|python|js|javascript)(?!\s+hl_lines=)\n"
r"(?P<code>((?:.*\n)*?))" # Capture the code inside the block using named group
r"(?P=indent)```" # Match closing backticks with the same indentation
)

def replace_highlight_comments(match: re.Match) -> str:
indent = match.group("indent")
language = match.group("language")
code_block = match.group("code")
lines = code_block.split("\n")
highlighted_lines = []

# Skip initial empty lines
while lines and not lines[0].strip():
lines.pop(0)

lines_to_keep = []

comment_syntax = (
"# highlight-next-line"
if language in ["py", "python"]
else "// highlight-next-line"
)

for line in lines:
if comment_syntax in line:
count = len(lines_to_keep) + 1
highlighted_lines.append(str(count))
else:
lines_to_keep.append(line)

# Reconstruct the new code block
new_code_block = "\n".join(lines_to_keep)

if highlighted_lines:
return (
f'{indent}```{language} hl_lines="{" ".join(highlighted_lines)}"\n'
# The indent and terminating \n is already included in the code block
f'{new_code_block}'
f'{indent}```'
)
else:
return (
f"{indent}```{language}\n"
# The indent and terminating \n is already included in the code block
f"{new_code_block}"
f"{indent}```"
)

# Replace all code blocks in the markdown
markdown = code_block_pattern.sub(replace_highlight_comments, markdown)
return markdown


def on_page_markdown(markdown: str, page: Page, **kwargs: Dict[str, Any]):
if DISABLED:
return markdown
if page.file.src_path.endswith(".ipynb"):
logger.info("Processing Jupyter notebook: %s", page.file.src_path)
body = convert_notebook(page.file.abs_src_path)
return body
markdown = convert_notebook(page.file.abs_src_path)
# Apply highlight comments to code blocks
markdown = _highlight_code_blocks(markdown)

return markdown
Loading