From 4f6d1ecb352ad8bba850ca5611ad4881d113bf52 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Thu, 20 Aug 2026 18:15:29 +0200 Subject: feat(compose): render markdown bodies with cmark-gfm, item 123 The composer's body is markdown and the text/html part is generated from it. cmark-gfm rather than plain cmark for autolink: under CommonMark a bare URL in a mail body is not a link, and in mail it is expected to be clickable. Three extensions are enabled and tables are deliberately not, since they render badly across mail clients whoever generates them. Raw HTML in the input is suppressed with CMARK_OPT_SAFE: the body is the user's own text, but a body that can inject markup into its own generated HTML part is a sharp edge with no upside. The build needs TWO lookups. Only the core library ships a pkg-config file; libcmark-gfm-extensions has none and is located with find_library, the way notmuch already is. All three extensions live in that second library, so finding only the first produces a build that compiles and silently renders plain CommonMark. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_015muoUo2GdxmBDSp5vjYcbE --- CMakeLists.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'CMakeLists.txt') diff --git a/CMakeLists.txt b/CMakeLists.txt index 97a1d90..47b0df6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,23 @@ message(STATUS "Found notmuch: ${NOTMUCH_LIBRARY}") find_package(PkgConfig REQUIRED) pkg_check_modules(GMIME REQUIRED IMPORTED_TARGET gmime-3.0) +# cmark-gfm renders the composer's markdown body into the HTML part. +# +# TWO lookups, not one, and this is the trap: only the CORE library ships a +# pkg-config file. `libcmark-gfm-extensions` has none (verified 2026-08-20 on +# Slackware, cmark-gfm-0.29.0.gfm.13), so it is located by hand exactly as +# notmuch is. The extensions library is not optional here: autolink, +# strikethrough and tasklist all live in it, and without it a bare URL in a +# mail body is not a link. +pkg_check_modules(CMARK_GFM REQUIRED IMPORTED_TARGET libcmark-gfm) +find_library(CMARK_GFM_EXTENSIONS_LIBRARY NAMES cmark-gfm-extensions) +if(NOT CMARK_GFM_EXTENSIONS_LIBRARY) + message(FATAL_ERROR + "libcmark-gfm-extensions not found. It ships with cmark-gfm but has " + "no pkg-config file; it provides autolink, strikethrough and tasklist.") +endif() +message(STATUS "Found cmark-gfm extensions: ${CMARK_GFM_EXTENSIONS_LIBRARY}") + # The version lives only in the project() call above; version.h is generated # from it so no source file repeats the literal. configure_file( -- cgit v1.2.3