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

Highlight specific lines of code using comments #7296

Closed
4 of 8 tasks
heitorlessa opened this issue Jun 26, 2024 · 6 comments
Closed
4 of 8 tasks

Highlight specific lines of code using comments #7296

heitorlessa opened this issue Jun 26, 2024 · 6 comments
Labels
change request Issue requests a new feature or improvement upstream Issue must be taken upstream

Comments

@heitorlessa
Copy link
Sponsor

Context

As of today, you can highlight lines using hl_lines= syntax when adding a code block. This is great when you start, or when you rarely update the code block.

def bubble_sort(items):
    for i in range(len(items)):
        for j in range(len(items) - 1 - i):
            if items[j] > items[j + 1]:
                items[j], items[j + 1] = items[j + 1], items[j]

As we grow way beyond 500 code snippets, we run into issues where sometimes a new import, or code snippet improvements break highlight. Two years ago we also added formatting and linting of all code snippets for quality and consistency, but it aggravated the issue at scale.

For example, if we make a minor update to the code snippet above it will break the highlight:

from __future__ import annotations

def bubble_sort(items: list):
    for i in range(len(items)):
        for j in range(len(items) - 1 - i):
            if items[j] > items[j + 1]:
                items[j], items[j + 1] = items[j + 1], items[j]

Description

It'd be great to be able to highlight a specific code line using comments. For example:

def bubble_sort(items):
    for i in range(len(items)):  # hl
        for j in range(len(items) - 1 - i):  # hl
            if items[j] > items[j + 1]:
                items[j], items[j + 1] = items[j + 1], items[j]

This removes the need to manually fix each code snippet hl_lines whenever there's a change in the code that shifts the line number where the highlight is. This is similar to the great code annotation feature today, whereas instead of # (1) we'd use another term to highlight it.

Related links

Use Cases

In our case, we want to add from __future__ import annotations to all code snippets for older Python versions (e.g., Python 3.8), along with other enhancements. This however would turn into days of work to change, format, lint, verify, and fix each code highlighted line we had before / after the change.

Off the top of my head, this would benefit people:

  • supporting multiple versions of a given programming language, where code is largely the same with syntax/idioms differences
  • large documentation with code snippets being refactored
  • any documentation size where code snippets are updated on a regular basis
  • documentation websites that use formatting, linting, and testing tools at CI to ensure code snippets are testable

One of the examples that would break should we make that change: https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/#recommended

Visuals

image image

Before submitting

@squidfunk
Copy link
Owner

Thanks for suggesting! Definitely a sound use case, and yes, the current situation is not ideal.

Line highlighting is implemented in pymdownx.highlight. I'd recommend taking this upstream to Python Markdown Extensions, as it's the package that provides the original highlighting functionality. Code annotations are mounted in the browser (with non-JS fallback), but highlighting needs to be implemented in Python a we would have no fallback, with no lines being highlighted without JS. It might be an extension to the current parser or some custom SuperFences logic.

I'm taking this back with me to the drawing board where I'm currently at, thinking deeply about the UX/DX/AX of Material for MkDocs. For now, we'd consider this upstream, but we'll look into improving the highlighting capabilities.

@squidfunk
Copy link
Owner

Just another idea: as mentioned, you could write a simple custom fence that pre-processes each code block looking for # hl or even # hl:start and # hl:end comments to support multi-line highlighting. This fence would then extract and remove those from the code block and configure pygments with the appropriate hl_lines. If that proves to be viable, we can think about abstracting this further and bring it to the Material for MkDocs code base.

@heitorlessa
Copy link
Sponsor Author

heitorlessa commented Jun 26, 2024 via email

@alexvoss
Copy link
Sponsor Collaborator

The documentation for custom fences should contain all you need. One thing I am not sure about is how to do some processing and then allow the standard processing to take place afterwards. Perhaps @facelessuser can comment on that. Would it be possible to modify the code block in a validator and return False from it to pass through to the next validator/formatter?

@squidfunk
Copy link
Owner

Hmm, I searched but no, not really, except for the official documentation on custom fences. Maybe @facelessuser has a quick snippet where a custom fence extends / pre-configures the functionality of another fence? As TL;DR, turning this:

``` py
def bubble_sort(items):
    for i in range(len(items)):  # hl
        for j in range(len(items) - 1 - i):  # hl
            if items[j] > items[j + 1]:
                items[j], items[j + 1] = items[j + 1], items[j] #hl
```

Into this:

``` py hl_lines="2-3,5"
def bubble_sort(items):
    for i in range(len(items)):
        for j in range(len(items) - 1 - i): 
            if items[j] > items[j + 1]:
                items[j], items[j + 1] = items[j + 1], items[j]
```

... and then feeding it into Pygments.

@squidfunk
Copy link
Owner

squidfunk commented Jun 26, 2024

@alexvoss is faster than Lucky Luke 🤠 Sorry for double-tagging, Issac.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
change request Issue requests a new feature or improvement upstream Issue must be taken upstream
3 participants