Prohlížeč zdrojového kódu
docs/specs/markdown-code-highlighting.md
Spec: Markdown Code Block Syntax Highlighting
- Status: active
- Created: 2026-03-12
- Related code:
app/helpers/highlight_helper.rb,spec/helpers/highlight_helper_spec.rb
Overview
Fenced code blocks in Markdown content are syntax-highlighted using Rouge, consistent with the manually-highlighted source code blocks elsewhere in the app. This applies wherever Markdown is rendered: example detail pages and the source browser Markdown view.
Behaviour
- A fenced code block with a recognised language hint (e.g.
`ruby) is highlighted using the matching Rouge lexer. - A fenced code block with no language hint, or an unrecognised language, falls back to plain-text rendering without raising an error.
- The rendered HTML uses the same markup structure as
highlight_codeso existing Rouge CSS applies without additional stylesheet changes. - Highlighting applies wherever
render_markdownis called. - A fenced code block may include an optional label in the info string, separated from the language hint by a space (e.g.
ruby app/models/log.rb ` or `ruby log_header.rb, log_item.rb). The label is arbitrary text extending to the end of the fence line. When present, the label is displayed above the code block. A label without a language hint is not supported.
Implementation Notes
SourceAwareMarkdownRenderer#block_codedelegates toHighlightHelper.rouge_highlight, a module-level method extracted from the oldhighlight_codeinstance method.HighlightHelper.rouge_highlightreturns a plain HTML string (norawwrapping); callers that need anActiveSupport::SafeBuffercallrawthemselves (highlight_codehelper method,render_markdownvia Redcarpet).block_codereceivesnilfor language when no hint is given;Rouge::Lexer.find(nil)returnsnil, so the fallback toPlainTexthandles both the no-hint and unknown-language cases.- No CSS changes needed for highlighting —
rouge.scssalready covers.highlightfor both light and dark themes. - Label pre-processing workaround: Redcarpet stops reading the fence info string at the first space, causing fenced blocks with labels to not be recognised as code blocks at all.
render_markdownpre-processes the Markdown with agsubthat replaces all spaces inside fence info lines (lines starting withor~~~) with\x1F(ASCII Unit Separator) before handing the text to Redcarpet.block_codethen decodes\x1Fback to spaces and splits on the first space to separate the language from the label. Labels are rendered as raw HTML (not escaped) in aelement before the`.
Tests
spec/helpers/highlight_helper_spec.rb— fenced block with language renders Rouge HTML; fenced block without language renders plain; unknown language does not raisespec/helpers/highlight_helper_spec.rb— fenced block withruby path/to/file.rbrenders.code-block__labelcontaining the path; fenced block with only a language hint renders no label; label text is HTML-escaped
See Also
- Rich Example Content — example detail pages render Markdown via
render_markdown, which is the primary consumer. - Source Browser — source browser Markdown view also uses
render_markdown. - Styling and CSS — Rouge CSS (
rouge.scss) provides the colour rules consumed by the highlighted output.
Change Log
- 2026-03-12: Initial prospective spec.
- 2026-03-23: Added optional label in fence info string (space-separated, arbitrary text, raw HTML).