~linuxgoose/bocpress

3113af5edfa5fa4c6bc49cdbf981319cfcc1e9bf — Jordan Robinson 4 months ago 8412fe3
add pygments code block syntax highlighting
M main/templates/assets/style.css => main/templates/assets/style.css +2 -1
@@ 268,8 268,9 @@ td {
}

pre {
    background: var(--airy-grey-color);
    background: var(--airy-grey-color) !important;
    overflow-x: auto;
    padding: 12px;
}

code {

M main/templates/main/page_detail.html => main/templates/main/page_detail.html +15 -0
@@ 8,6 8,21 @@
{% include 'partials/rsl_license_head.html' %}
{% endblock head_rsl_license %}

{% block head_extra %}
<style>

    /* Light theme */
    @media (prefers-color-scheme: light) {
    {{ light_css|safe }}
    }

    /* Dark theme */
    @media (prefers-color-scheme: dark) {
    {{ dark_css|safe }}
    }
</style>
{% endblock head_extra %}

{% block content %}
<main>
    {% if blog_user.blog_title %}

M main/templates/main/post_detail.html => main/templates/main/post_detail.html +15 -0
@@ 8,6 8,21 @@
{% include 'partials/rsl_license_head.html' %}
{% endblock head_rsl_license %}

{% block head_extra %}
<style>

    /* Light theme */
    @media (prefers-color-scheme: light) {
    {{ light_css|safe }}
    }

    /* Dark theme */
    @media (prefers-color-scheme: dark) {
    {{ dark_css|safe }}
    }
</style>
{% endblock head_extra %}

{% block content %}
<main>
    {% if blog_user.blog_title %}

M main/util.py => main/util.py +16 -1
@@ 15,6 15,7 @@ from django.utils.text import slugify
from pygments.formatters import HtmlFormatter
from pygments.lexers import ClassNotFound, get_lexer_by_name, get_lexer_for_filename
from l2m4m import LaTeX2MathMLExtension
from pygments import highlight

from main import denylist, models



@@ 24,13 25,15 @@ from mdit_py_plugins.tasklists import tasklists_plugin
from graphviz import Source

md = (
    MarkdownIt("commonmark", {"html": True})
    MarkdownIt("commonmark", {"html": True, "highlight": None})
    .enable("strikethrough")
    .enable("table")
    .use(footnote_plugin)
    .use(tasklists_plugin)
)

formatter = HtmlFormatter(nowrap=True)

# Define allowed CSS properties and SVG attributes
ALLOWED_CSS_PROPERTIES = frozenset([
    "azimuth", "background-color", "border-bottom-color", "border-collapse",


@@ 162,6 165,15 @@ def syntax_highlight(text):

    return processed_text

def highlight_code(code: str, lang: str) -> str:
    try:
        lexer = get_lexer_by_name(lang, stripall=True)
    except Exception:
        # fallback for unknown languages
        return f"<pre><code>{code}</code></pre>"
    return f'<pre class="code-block {lang}"><code>' + \
           highlight(code, lexer, formatter) + \
           "</code></pre>"

def clean_html(dirty_html, strip_tags=False):
    allowed_tags = list(bleach.sanitizer.ALLOWED_TAGS) + denylist.ALLOWED_HTML_ELEMENTS + SVG_TAGS + MATHML_TAGS


@@ 191,6 203,9 @@ def fence_override(tokens, idx, options, env):
            return svg_str
        except Exception:
            return f"<pre>{code}</pre>"
        
    if lang:
        return highlight_code(code, lang)

    # fallback to default renderer
    if default_fence:

M main/views/general.py => main/views/general.py +14 -0
@@ 41,6 41,8 @@ from main import denylist, forms, models, util
from main.sitemaps import PageSitemap, PostSitemap, StaticSitemap
from main.views import billing

from pygments.formatters import HtmlFormatter

logger = logging.getLogger(__name__)




@@ 334,6 336,8 @@ def post_detail_redir(request, slug):

class PostDetail(DetailView):
    model = models.Post
    light_css = HtmlFormatter(style="default").get_style_defs('.code-block')
    dark_css = HtmlFormatter(style="monokai").get_style_defs('.code-block')

    def get_queryset(self):
        queryset = models.Post.objects.filter(owner__username=self.request.subdomain)


@@ 367,6 371,10 @@ class PostDetail(DetailView):
        # Reading time calculation
        context["reading_time"] = util.reading_time(self.object.body)

        # Pygments CSS for code highlighting
        context["light_css"] = self.light_css
        context["dark_css"] = self.dark_css

        # do not record analytic if post is authed user's
        if (
            self.request.user.is_authenticated


@@ 931,6 939,8 @@ class PageCreate(LoginRequiredMixin, SuccessMessageMixin, CreateView):

class PageDetail(DetailView):
    model = models.Page
    light_css = HtmlFormatter(style="default").get_style_defs('.code-block')
    dark_css = HtmlFormatter(style="monokai").get_style_defs('.code-block')

    def get_queryset(self):
        queryset = models.Page.objects.filter(owner__username=self.request.subdomain)


@@ 955,6 965,10 @@ class PageDetail(DetailView):

        context["license_url"] = license_url

        # Pygments CSS for code highlighting
        context["light_css"] = self.light_css
        context["dark_css"] = self.dark_css

        # do not record analytic if post is authed user's
        if (
            self.request.user.is_authenticated