implement a summary property on Content
Allow the user to set a summary and make Article extract its own summary when the Article.render is called and the summary is still missing. Extracted summaries only work when the first item of a markdown file is a paragraph.
This commit is contained in:
+22
-3
@@ -11,6 +11,7 @@ if TYPE_CHECKING:
|
||||
import yaml
|
||||
from markupsafe import Markup
|
||||
from markdown_it import MarkdownIt
|
||||
from markdown_it.token import Token
|
||||
from pygments import highlight as pygments_highlight
|
||||
from pygments.formatters import HtmlFormatter
|
||||
from pygments.lexers import get_lexer_by_name
|
||||
@@ -44,6 +45,9 @@ def highlight(code: str, lang: str, attrs: str) -> str:
|
||||
return pygments_highlight(code, lexer, html_formatter)
|
||||
|
||||
|
||||
md = MarkdownIt(options_update={"highlight": highlight})
|
||||
|
||||
|
||||
def read_frontmatter(path: Path) -> dict[str, Any]:
|
||||
lines = []
|
||||
with path.open("r", encoding="utf-8") as f:
|
||||
@@ -88,6 +92,7 @@ class Content(ABC):
|
||||
created: date,
|
||||
updated: date | None = None,
|
||||
tags: set[str] | None = None,
|
||||
summary: str | None = None,
|
||||
):
|
||||
if tags is None:
|
||||
tags = set()
|
||||
@@ -96,6 +101,7 @@ class Content(ABC):
|
||||
self.created = created
|
||||
self.updated = updated
|
||||
self.tags: set[str] = tags
|
||||
self.summary: str | None = summary
|
||||
self.uri: str = self.build_uri(section, slug)
|
||||
|
||||
@staticmethod
|
||||
@@ -131,14 +137,27 @@ class Article(Content):
|
||||
meta["date"],
|
||||
meta.get("updated", None),
|
||||
meta.get("tags", None),
|
||||
meta.get("summary", None),
|
||||
)
|
||||
self.title: str = meta["title"]
|
||||
self.content: Markup = Markup("")
|
||||
|
||||
@staticmethod
|
||||
def extract_summary(tokens: list[Token]) -> str:
|
||||
if not tokens or tokens[0].type != "paragraph_open" or tokens[0].hidden:
|
||||
raise ContentError(
|
||||
"Body does not start with a paragraph; set 'summary' in frontmatter"
|
||||
)
|
||||
for j in range(1, len(tokens)):
|
||||
if tokens[j].type == "paragraph_close":
|
||||
return cast(str, md.renderer.render(tokens[1:j], md.options, {}))
|
||||
raise ContentError("Content has no paragraph to use as summary")
|
||||
|
||||
def render(self, site: Site) -> None:
|
||||
md = MarkdownIt()
|
||||
md.options["highlight"] = highlight
|
||||
self.content = Markup(md.render(self.read_body()))
|
||||
tokens = md.parse(self.read_body())
|
||||
if self.summary is None:
|
||||
self.summary = Article.extract_summary(tokens)
|
||||
self.content = Markup(md.renderer.render(tokens, md.options, {}))
|
||||
|
||||
template = site.jinja_env.get_template("article.html")
|
||||
html = template.render(article=self, site=site)
|
||||
|
||||
Reference in New Issue
Block a user