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

feat: initial release and djc_py code block with DjangoComponentsPythonLexer #1

Merged
merged 3 commits into from
Feb 12, 2025

Conversation

JuroOravec
Copy link
Contributor

@JuroOravec JuroOravec commented Feb 11, 2025

Part of django-components/django-components#966.

This package that allows us to write djc_py code blocks like so:

\```djc_py
class table(Component):
    template = """
        ...
    """
\```

Using djc_py, the inlined HTML / CSS / JS will be properly highlighted:

demo

@@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The project skeleton is based on django-components.

# Register the Lexer. Unfortunately Pygments doesn't support registering a Lexer
# without it living in the pygments codebase.
# See https://github.com/pygments/pygments/issues/1096#issuecomment-1821807464
LEXERS["DjangoComponentsPythonLexer"] = (
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned here - Pygments has an (IMO) strange design, where they keep all the Lexers as part of the codebase and part of the package, and don't provide some official way to add own Lexers. So we have to do so here.

Thus, when one imports pygments_djc, our Lexer will be added.

# ```djc_py
# ```
# will be highlighted by this Lexer.
["djc_py", "djc_python"],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This configures which code blocks will the syntax highlight work with.

@@ -0,0 +1,117 @@
from pygments.lexer import Lexer, bygroups, using
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the actual business logic.

The way Pygments Lexers work is that each Lexer defines a list of states. And for each state, it defines various regex patterns that the program will try to match against the text at current cursor. And then the program reads the text, and at each step it:

  1. Finds which state it's currently in
  2. Fidns all regex patterns to test in current state
  3. Tries the pattern one after another, until it finds match.
  4. When it finds match, there is some "action" associated with the match - e.g. that if we match token """, then this token should be marked as Literal.Quote.Triple, or something like that. This is how the Lexers match pieces of text with different colors, for example.
  5. Lastly, a match may also specify the next state to transition to. If so, the state changes. Either way, the program finds the end of the regex match, and continues comparing regexes on the remainder of the text.

# - The pattern to capture
# - The token to highlight
# - The next state
return (
Copy link
Contributor Author

@JuroOravec JuroOravec Feb 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you can see that the returned value is actually a tuple of 3:

  • The pattern to capture
  • The token to highlight
  • The next state (if any)


tokens = {
**PythonLexer.tokens,
"root": [
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where we define the Lexer states, and the regex patterns in each state. template_string and similar are our custom states, which mark when we're inside inlined template / js / css.

@JuroOravec JuroOravec force-pushed the jo-feat-pygments-lexer branch from 22262cd to 8f3a317 Compare February 11, 2025 20:54
Copy link

@EmilStenstrom EmilStenstrom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great from a quick read-through. Feels safe since it's only used in the docs.

@JuroOravec JuroOravec merged commit e3f0bfe into main Feb 12, 2025
7 checks passed
@JuroOravec JuroOravec deleted the jo-feat-pygments-lexer branch February 12, 2025 20:46
@JuroOravec
Copy link
Contributor Author

Thanks, I've just released this https://pypi.org/project/pygments-djc/ 🎉

Again I've used my PyPI account, and I've saved the API access token to repository secrets.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants