or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

handler-system.mdindex.mdinventory-system.mdlogging-system.mdmarkdown-processing.mdplugin-integration.mdrendering-system.md

rendering-system.mddocs/

0

# Rendering System

1

2

HTML rendering components including syntax highlighting, heading management, and output formatting processors. The rendering system transforms collected documentation data into properly formatted HTML with consistent styling and structure.

3

4

## Capabilities

5

6

### Syntax Highlighting

7

8

Code syntax highlighter that matches Markdown configuration and provides consistent code formatting.

9

10

```python { .api }

11

class Highlighter(Highlight):

12

"""Code highlighter that matches Markdown configuration."""

13

14

_highlight_config_keys: frozenset[str]

15

"""Configuration keys supported by the highlighter."""

16

17

def __init__(self, md: Markdown) -> None:

18

"""

19

Configure to match a Markdown instance.

20

21

Args:

22

md: The Markdown instance to read configs from

23

"""

24

25

def highlight(

26

self,

27

src: str,

28

language: str | None = None,

29

*,

30

inline: bool = False,

31

dedent: bool = True,

32

linenums: bool | None = None,

33

**kwargs: Any

34

) -> str:

35

"""

36

Highlight a code-snippet.

37

38

Args:

39

src: The code to highlight

40

language: Explicitly tell what language to use for highlighting

41

inline: Whether to highlight as inline

42

dedent: Whether to dedent the code before highlighting it or not

43

linenums: Whether to add line numbers in the result

44

**kwargs: Pass on to pymdownx.highlight.Highlight.highlight

45

46

Returns:

47

The highlighted code as HTML text, marked safe (not escaped for HTML)

48

"""

49

```

50

51

**Usage Examples:**

52

53

Basic syntax highlighting:

54

```python

55

from mkdocstrings import Highlighter

56

from markdown import Markdown

57

58

md = Markdown(extensions=['codehilite'])

59

highlighter = Highlighter(md)

60

61

# Highlight Python code

62

python_code = """

63

def hello_world():

64

print("Hello, World!")

65

return True

66

"""

67

68

highlighted = highlighter.highlight(python_code, language="python")

69

print(highlighted) # Returns HTML with syntax highlighting

70

```

71

72

Inline code highlighting:

73

```python

74

# Highlight inline code

75

inline_code = "print('hello')"

76

highlighted_inline = highlighter.highlight(

77

inline_code,

78

language="python",

79

inline=True

80

)

81

```

82

83

With line numbers:

84

```python

85

# Highlight with line numbers

86

highlighted_with_lines = highlighter.highlight(

87

python_code,

88

language="python",

89

linenums=True

90

)

91

```

92

93

### Heading Management

94

95

Tree processor that shifts heading levels in rendered HTML content to maintain proper document hierarchy.

96

97

```python { .api }

98

class HeadingShiftingTreeprocessor(Treeprocessor):

99

"""Shift levels of all Markdown headings according to the configured base level."""

100

101

name: str = "mkdocstrings_headings"

102

"""The name of the treeprocessor."""

103

104

regex: re.Pattern = re.compile(r"([Hh])([1-6])")

105

"""The regex to match heading tags."""

106

107

shift_by: int

108

"""The number of heading 'levels' to add to every heading. <h2> with shift_by = 3 becomes <h5>."""

109

110

def __init__(self, md: Markdown, shift_by: int) -> None:

111

"""

112

Initialize the object.

113

114

Args:

115

md: A markdown.Markdown instance

116

shift_by: The number of heading 'levels' to add to every heading

117

"""

118

119

def run(self, root: Element) -> None:

120

"""

121

Shift the levels of all headings in the document.

122

123

Args:

124

root: Root element of the tree to process

125

"""

126

```

127

128

**Usage Examples:**

129

130

Shift headings in handler rendering:

131

```python

132

from mkdocstrings import HeadingShiftingTreeprocessor

133

from markdown import Markdown

134

from xml.etree.ElementTree import Element, fromstring

135

136

# Create processor that shifts headings down by 2 levels

137

md = Markdown()

138

processor = HeadingShiftingTreeprocessor(md, shift_by=2)

139

140

# Process HTML content

141

html_content = """

142

<h1>Main Title</h1>

143

<h2>Subtitle</h2>

144

<h3>Section</h3>

145

"""

146

147

root = fromstring(f"<div>{html_content}</div>")

148

processor.run(root)

149

150

# Now h1 becomes h3, h2 becomes h4, h3 becomes h5

151

```

152

153

Integration in handlers:

154

```python

155

class MyHandler(BaseHandler):

156

def render(self, data: CollectorItem, options: HandlerOptions, *, locale: str | None = None) -> str:

157

# Get heading level from options

158

heading_level = options.get("heading_level", 1)

159

160

# Create inner Markdown with heading shifter

161

inner_md = Markdown()

162

if heading_level > 1:

163

shifter = HeadingShiftingTreeprocessor(inner_md, shift_by=heading_level - 1)

164

inner_md.treeprocessors.register(shifter, "heading_shift", 5)

165

166

# Process docstring with proper heading levels

167

docstring_html = inner_md.convert(data.docstring)

168

169

return template.render(data=data, docstring_html=docstring_html)

170

```

171

172

### ID Management

173

174

Tree processor that prepends prefixes to HTML element IDs to avoid conflicts in the generated documentation.

175

176

```python { .api }

177

class IdPrependingTreeprocessor(Treeprocessor):

178

"""Prepend the configured prefix to IDs of all HTML elements."""

179

180

name: str = "mkdocstrings_ids"

181

"""The name of the treeprocessor."""

182

183

id_prefix: str

184

"""The prefix to add to every ID. It is prepended without any separator; specify your own separator if needed."""

185

186

def __init__(self, md: Markdown, id_prefix: str) -> None:

187

"""

188

Initialize the object.

189

190

Args:

191

md: A markdown.Markdown instance

192

id_prefix: The prefix to add to every ID. It is prepended without any separator

193

"""

194

195

def run(self, root: Element) -> None:

196

"""

197

Prepend the configured prefix to all IDs in the document.

198

199

Args:

200

root: Root element of the tree to process

201

"""

202

```

203

204

**Usage Examples:**

205

206

Prevent ID conflicts between multiple autodoc blocks:

207

```python

208

from mkdocstrings import IdPrependingTreeprocessor

209

210

# Create processor with prefix

211

processor = IdPrependingTreeprocessor(md, id_prefix="module1-")

212

213

# Process HTML with IDs

214

html_with_ids = """

215

<h2 id="function">My Function</h2>

216

<div id="example">Example</div>

217

"""

218

219

root = fromstring(f"<div>{html_with_ids}</div>")

220

processor.run(root)

221

222

# IDs become: "module1-function", "module1-example"

223

```

224

225

Handler integration:

226

```python

227

class MyHandler(BaseHandler):

228

def render(self, data: CollectorItem, options: HandlerOptions, *, locale: str | None = None) -> str:

229

# Create unique ID prefix for this object

230

id_prefix = data.name.replace(".", "-") + "-"

231

232

# Process with ID prefixing

233

inner_md = Markdown()

234

id_processor = IdPrependingTreeprocessor(inner_md, id_prefix)

235

inner_md.treeprocessors.register(id_processor, "id_prefix", 10)

236

237

# Convert content with prefixed IDs

238

content_html = inner_md.convert(data.content)

239

240

return template.render(data=data, content_html=content_html)

241

```

242

243

### Paragraph Stripping

244

245

Tree processor that unwraps single paragraph elements from output for cleaner formatting.

246

247

```python { .api }

248

class ParagraphStrippingTreeprocessor(Treeprocessor):

249

"""Unwraps the <p> element around the whole output."""

250

251

name: str = "mkdocstrings_strip_paragraph"

252

"""The name of the treeprocessor."""

253

254

strip: bool = False

255

"""Whether to strip <p> elements or not."""

256

257

def run(self, root: Element) -> Element | None:

258

"""

259

Unwrap the root element if it's a single <p> element.

260

261

Args:

262

root: Root element of the tree to process

263

264

Returns:

265

Modified root element or None

266

"""

267

```

268

269

**Usage Examples:**

270

271

Strip single paragraphs from docstring content:

272

```python

273

from mkdocstrings import ParagraphStrippingTreeprocessor

274

275

# Create processor

276

processor = ParagraphStrippingTreeprocessor()

277

processor.strip = True

278

279

# Process content that has unnecessary paragraph wrapper

280

html_content = "<p>Simple text content</p>"

281

root = fromstring(html_content)

282

result = processor.run(root)

283

284

# Result: "Simple text content" (paragraph wrapper removed)

285

```

286

287

Handler usage for inline content:

288

```python

289

def render_inline_docstring(self, docstring: str) -> str:

290

"""Render docstring as inline content without paragraph wrapper."""

291

inner_md = Markdown()

292

293

# Add paragraph stripper for inline rendering

294

stripper = ParagraphStrippingTreeprocessor()

295

stripper.strip = True

296

inner_md.treeprocessors.register(stripper, "strip_p", 15)

297

298

return inner_md.convert(docstring)

299

```

300

301

## Integration with Handlers

302

303

### Template Integration

304

305

Rendering components integrate with Jinja2 templates:

306

307

```python

308

def render(self, data: CollectorItem, options: HandlerOptions, *, locale: str | None = None) -> str:

309

# Set up rendering environment

310

highlighter = Highlighter(self.md)

311

312

# Configure template globals

313

template_globals = {

314

"highlight": highlighter.highlight,

315

"shift_headings": self.shift_headings,

316

"config": options

317

}

318

319

# Render template with rendering utilities

320

template = self.env.get_template("handler.html")

321

return template.render(

322

data=data,

323

**template_globals

324

)

325

```

326

327

### Markdown Configuration

328

329

Rendering components respect Markdown configuration:

330

331

```python

332

# Handler initialization

333

def __init__(self, *args, **kwargs):

334

super().__init__(*args, **kwargs)

335

336

# Create highlighter that matches main Markdown config

337

self.highlighter = Highlighter(self.md)

338

339

# Configure processors based on options

340

self.configure_processors()

341

342

def configure_processors(self):

343

"""Configure tree processors based on handler options."""

344

# Add heading shifter if needed

345

if self.config.get("heading_level", 1) > 1:

346

shift_by = self.config["heading_level"] - 1

347

shifter = HeadingShiftingTreeprocessor(self.inner_md, shift_by)

348

self.inner_md.treeprocessors.register(shifter, "shift_headings", 5)

349

350

# Add ID prefixer for unique IDs

351

if self.config.get("unique_ids", True):

352

id_prefix = self.get_id_prefix()

353

prefixer = IdPrependingTreeprocessor(self.inner_md, id_prefix)

354

self.inner_md.treeprocessors.register(prefixer, "prefix_ids", 10)

355

```

356

357

### Custom Rendering

358

359

Extend rendering for custom needs:

360

361

```python

362

class CustomHandler(BaseHandler):

363

def setup_rendering(self):

364

"""Set up custom rendering pipeline."""

365

# Create custom highlighter with additional languages

366

self.highlighter = Highlighter(self.md)

367

368

# Add custom tree processors

369

self.add_custom_processors()

370

371

def add_custom_processors(self):

372

"""Add custom tree processors."""

373

# Custom processor for special formatting

374

custom_processor = CustomTreeProcessor(self.inner_md)

375

self.inner_md.treeprocessors.register(custom_processor, "custom", 20)

376

377

def render_with_custom_formatting(self, content: str, language: str) -> str:

378

"""Render content with custom formatting."""

379

# Highlight code

380

highlighted = self.highlighter.highlight(content, language=language)

381

382

# Apply custom processing

383

processed = self.apply_custom_processing(highlighted)

384

385

return processed

386

```

387

388

### Markdown Inner Extension

389

390

Extension that should always be added to Markdown sub-documents that handlers request.

391

392

```python { .api }

393

class MkdocstringsInnerExtension(Extension):

394

"""Extension that should always be added to Markdown sub-documents that handlers request (and only them)."""

395

396

headings: list[Element]

397

"""The list that will be populated with all HTML heading elements encountered in the document."""

398

399

def __init__(self, headings: list[Element]) -> None:

400

"""

401

Initialize the object.

402

403

Args:

404

headings: A list that will be populated with all HTML heading elements encountered in the document

405

"""

406

407

def extendMarkdown(self, md: Markdown) -> None:

408

"""

409

Register the extension.

410

411

Args:

412

md: A markdown.Markdown instance

413

"""

414

```

415

416

**Usage Examples:**

417

418

Using the inner extension for handler sub-documents:

419

```python

420

from mkdocstrings import MkdocstringsInnerExtension

421

from markdown import Markdown

422

from xml.etree.ElementTree import Element

423

424

# Create list to collect headings

425

headings: list[Element] = []

426

427

# Create inner extension

428

inner_extension = MkdocstringsInnerExtension(headings)

429

430

# Create Markdown instance for sub-document processing

431

inner_md = Markdown(extensions=[inner_extension])

432

433

# Process handler content

434

content = """

435

# Function Documentation

436

437

## Parameters

438

439

### param1

440

Description of parameter 1.

441

442

### param2

443

Description of parameter 2.

444

"""

445

446

result = inner_md.convert(content)

447

448

# headings list now contains all heading elements found

449

print(f"Found {len(headings)} headings")

450

for heading in headings:

451

print(f"- {heading.tag}: {heading.text}")

452

```

453

454

Handler integration:

455

```python

456

class MyHandler(BaseHandler):

457

def render(self, data: CollectorItem, options: HandlerOptions, *, locale: str | None = None) -> str:

458

# Create headings collector

459

headings: list[Element] = []

460

461

# Set up inner Markdown with extension

462

inner_extension = MkdocstringsInnerExtension(headings)

463

inner_md = Markdown(extensions=[

464

inner_extension,

465

'toc',

466

'codehilite'

467

])

468

469

# Process docstring content

470

docstring_html = inner_md.convert(data.docstring)

471

472

# Use collected headings for navigation or TOC

473

toc_data = [(h.tag, h.text, h.get('id')) for h in headings]

474

475

# Render template with processed content

476

template = self.env.get_template('function.html')

477

return template.render(

478

data=data,

479

docstring_html=docstring_html,

480

toc_data=toc_data

481

)

482

```

483

484

This rendering system provides consistent, high-quality HTML output while maintaining flexibility for customization and integration with different themes and styling approaches.