Markdown Detection and Processing in Help and Whatis

When you run module help <name> or module whatis <name>, Lmod gets the raw string from the modulefile’s help() or whatis() (via the sandbox). Two pieces handle markdown: MarkdownDetector decides if the content looks like markdown, and MarkdownProcessor converts it to ANSI output for the terminal.

Flow

src/MC_Access.lua handles module help; src/MC_Show.lua handles module show and the whatis portion of module display. Both get the string from the modulefile and pass it to MarkdownDetector.isMarkdown(). If that returns true, the content goes to MarkdownProcessor.toTerminal(). The result is appended to the output buffer and printed. If it’s not markdown, the content is shown as plain text. For toPlainText() (used when stripping formatting), images become [Image: alt] (url).

Key files: src/MarkdownDetector.lua (detection), src/MarkdownProcessor.lua (conversion), src/MC_Access.lua, src/MC_Show.lua.

MarkdownDetector

The detector scores the content. Things like headers, lists, emphasis, code blocks, and links add points. If the score reaches 3 or more, the content is treated as markdown. This avoids formatting plain text (e.g., env var dumps) as markdown.

Line splitting: Content is split into lines with splitLines(), which uses string.find() instead of string.gmatch(). Lua’s gmatch() behaves differently across 5.1–5.4 for some patterns; find() gives consistent behavior.

Indicators: atx_headers (^#+%s+%S), setext_headers (^===+$ or ^---+$ with a non-empty line above), lists (^[-*+]%s+%S or ^%d+\.%s+%S with 0–3 spaces), emphasis, code, links, images, structure. Heavier list indentation is ignored. Content under 30 characters is never markdown. Setext underlines must have a non-empty line above.

MarkdownProcessor

The processor goes through the content line by line and converts markdown to ANSI.

Order: Code blocks first (dim/cyan), then setext headers, ATX headers, list items, then inline elements (code, emphasis, images, links) within paragraphs and lists.

Color: Used when supportsColor() returns true (TERM has xterm or color, or LMOD_COLORIZE=yes). Disabled during regression tests (optionTbl().rt == true). Codes live in the ANSI table in MarkdownProcessor.lua.

Images: ![alt](url) becomes [Image: alt] (url) in cyan. Processed before links to avoid conflicts.

Regression tests

See Lmod Regression Testing Guide for how to run the markdown tests.