88 lines
2.6 KiB
Python
88 lines
2.6 KiB
Python
from typing import Iterator
|
|
|
|
from django.utils.functional import cached_property
|
|
from django.utils.safestring import mark_safe
|
|
from pygments import highlight
|
|
from pygments.formatters.html import HtmlFormatter
|
|
from pygments.lexers import find_lexer_class, get_all_lexers
|
|
from pygments.lexers.python import PythonConsoleLexer, PythonLexer
|
|
from pygments.lexers.shell import BashLexer, BashSessionLexer
|
|
from pygments.lexers.special import TextLexer
|
|
from pygments.lexers.sql import PostgresConsoleLexer, PostgresLexer
|
|
from wagtail.blocks import CharBlock, ChoiceBlock, StructBlock, StructValue, TextBlock
|
|
|
|
from .utils import get_linguist_colours
|
|
|
|
|
|
def get_language_choices() -> Iterator[tuple[str, str]]:
|
|
for name, _, _, _ in sorted(get_all_lexers()):
|
|
yield (name, name.replace("+", " + "))
|
|
|
|
|
|
class CodeStructValue(StructValue):
|
|
LANGUAGE_DISPLAY_MAPPING = {
|
|
PythonConsoleLexer.name: PythonLexer.name,
|
|
PostgresLexer.name: "PostgreSQL",
|
|
}
|
|
|
|
LINGUIST_MAPPING = {
|
|
BashLexer.name: "Shell",
|
|
BashSessionLexer.name: "Shell",
|
|
PostgresLexer.name: "PLpgSQL",
|
|
PostgresConsoleLexer.name: "PLpgSQL",
|
|
}
|
|
|
|
def code(self) -> str:
|
|
lexer = find_lexer_class(self["language"])()
|
|
formatter = HtmlFormatter(
|
|
linenos=None,
|
|
)
|
|
return mark_safe(highlight(self["source"], lexer, formatter))
|
|
|
|
def header_text(self) -> str:
|
|
if filename := self["filename"]:
|
|
return filename
|
|
|
|
if self["language"] != TextLexer.name:
|
|
return self.language_display()
|
|
|
|
return ""
|
|
|
|
def language_display(self) -> str:
|
|
"""
|
|
Map ugly language names to something more useful
|
|
"""
|
|
return self.LANGUAGE_DISPLAY_MAPPING.get(self["language"], self["language"])
|
|
|
|
@cached_property
|
|
def colour(self) -> str | None:
|
|
"""
|
|
Expose the colour denoted by GitHub's linguist.
|
|
"""
|
|
linguist_colours = get_linguist_colours()
|
|
|
|
language = self.LINGUIST_MAPPING.get(self["language"], self["language"])
|
|
|
|
if exact_match := linguist_colours.get(language.lower()):
|
|
return exact_match
|
|
|
|
if language_display_match := linguist_colours.get(
|
|
self.LANGUAGE_DISPLAY_MAPPING.get(language, "").lower()
|
|
):
|
|
return language_display_match
|
|
|
|
return None
|
|
|
|
|
|
class CodeBlock(StructBlock):
|
|
filename = CharBlock(max_length=128, required=False)
|
|
language = ChoiceBlock(
|
|
choices=get_language_choices,
|
|
)
|
|
source = TextBlock()
|
|
|
|
class Meta:
|
|
icon = "code"
|
|
value_class = CodeStructValue
|
|
template = "contrib/blocks/code.html"
|