or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

code-highlighting.mddeprecated-options.mdhtml-postprocessing.mdindex.mdjson-serialization.mdlogo-management.mdtemplate-functions.mdtheme-builder.mdtheme-configuration.mdtoc-manipulation.md

toc-manipulation.mddocs/

0

# Table of Contents Manipulation

1

2

Advanced TOC processing system that restructures Sphinx's default table of contents by removing page titles from navigation, flattening hierarchical structures, and providing backward compatibility across different docutils versions for improved navigation usability.

3

4

## Capabilities

5

6

### Main TOC Transformation

7

8

Core function that modifies the on-page table of contents structure for better user experience.

9

10

```python { .api }

11

def change_toc(app: Sphinx, pagename: str, templatename: str,

12

context: dict[str, Any], doctree: Node) -> None:

13

"""

14

Change the way the {{ toc }} helper works.

15

16

Modifies Sphinx's default TOC behavior:

17

1. Removes the page title from the on-page TOC

18

2. Outdents nested bullet lists to create flattened structure

19

3. Updates template context with modified TOC HTML

20

21

Parameters:

22

- app (Sphinx): The Sphinx application instance

23

- pagename (str): Current page name

24

- templatename (str): Template being rendered

25

- context (dict[str, Any]): Template context dictionary

26

- doctree (Node): Document tree node

27

"""

28

```

29

30

### Backward Compatibility

31

32

Utility function that provides compatibility across different docutils versions.

33

34

```python { .api }

35

def findall(node: Node, selection: Node) -> Any:

36

"""

37

A backwards-compatible method to traverse docutils nodes.

38

39

Handles the API change in docutils 0.18 where 'findall' replaced 'traverse'.

40

This maintains compatibility with older Sphinx versions that use older docutils.

41

42

Parameters:

43

- node (Node): The docutils node to search

44

- selection (Node): The node type to find

45

46

Returns:

47

Any: Iterator or list of matching nodes

48

"""

49

```

50

51

## TOC Structure Transformation

52

53

### Default Sphinx TOC Structure

54

55

Sphinx generates TOC with page title included:

56

57

```html

58

<ul>

59

<li><a href="#">Page Title</a></li>

60

<ul>

61

<li><a href="#section-1">Section 1</a></li>

62

<li><a href="#section-2">Section 2</a></li>

63

<ul>

64

<li><a href="#subsection">Subsection</a></li>

65

</ul>

66

</ul>

67

</ul>

68

```

69

70

### After Transformation

71

72

Theme removes page title and flattens structure:

73

74

```html

75

<ul>

76

<li><a href="#section-1">Section 1</a></li>

77

<li><a href="#section-2">Section 2</a></li>

78

<ul>

79

<li><a href="#subsection">Subsection</a></li>

80

</ul>

81

</ul>

82

```

83

84

## Processing Steps

85

86

### 1. Page Title Removal

87

88

The transformation first identifies and removes the page title link:

89

90

```python

91

# Find reference nodes that link to the page itself (href="#")

92

for node in findall(toc, nodes.reference):

93

if node["refuri"] == "#":

94

# Remove the list_item wrapping the reference node

95

node.parent.parent.remove(node.parent)

96

```

97

98

### 2. Structure Flattening

99

100

After removing the page title, the system flattens nested structures:

101

102

```python

103

# Replace outer bullet lists with inner bullet lists

104

for node in findall(doc, nodes.bullet_list):

105

if (len(node.children) == 1

106

and isinstance(node.next_node(), nodes.list_item)

107

and isinstance(node.next_node().next_node(), nodes.bullet_list)):

108

doc.replace(node, node.next_node().next_node())

109

```

110

111

### 3. HTML Generation

112

113

The modified structure is converted back to HTML:

114

115

```python

116

if hasattr(app.builder, "_publisher"):

117

app.builder._publisher.set_source(doc)

118

app.builder._publisher.publish()

119

context["toc"] = app.builder._publisher.writer.parts["fragment"]

120

```

121

122

## Integration with Theme

123

124

### Template Usage

125

126

The modified TOC is available in templates as the standard `{{ toc }}` variable:

127

128

```html

129

<!-- In sidebar template -->

130

<div class="toc-tree">

131

{{ toc }}

132

</div>

133

```

134

135

### CSS Styling

136

137

The flattened structure works better with the theme's CSS:

138

139

```css

140

.toc-tree ul {

141

list-style: none;

142

padding-left: 1rem;

143

}

144

145

.toc-tree > ul {

146

padding-left: 0;

147

}

148

149

.toc-tree a {

150

display: block;

151

padding: 0.25rem 0;

152

color: var(--text-color);

153

text-decoration: none;

154

}

155

```

156

157

## Compatibility Considerations

158

159

### Docutils Version Support

160

161

The `findall` function ensures compatibility across docutils versions:

162

163

```python

164

# Modern docutils (>= 0.18)

165

node.findall(nodes.reference)

166

167

# Older docutils (< 0.18)

168

node.traverse(nodes.reference)

169

```

170

171

### Sphinx Version Support

172

173

The TOC manipulation works across different Sphinx versions by:

174

- Using the standard TocTree adapter

175

- Checking for publisher availability before HTML generation

176

- Graceful fallback if processing fails

177

178

## Error Handling

179

180

The TOC transformation includes robust error handling:

181

182

### Missing Publisher

183

184

```python

185

if hasattr(app.builder, "_publisher"):

186

# Process TOC with publisher

187

app.builder._publisher.set_source(doc)

188

app.builder._publisher.publish()

189

context["toc"] = app.builder._publisher.writer.parts["fragment"]

190

else:

191

# Fallback to original TOC if publisher unavailable

192

pass

193

```

194

195

### Malformed TOC Structure

196

197

The transformation safely handles edge cases:

198

- Empty TOC structures

199

- Missing reference nodes

200

- Deeply nested hierarchies

201

- Invalid document trees

202

203

## Performance Considerations

204

205

### Selective Processing

206

207

TOC manipulation only occurs during the `html-page-context` event, ensuring:

208

- Processing happens only when needed

209

- No impact on other build phases

210

- Minimal memory overhead

211

212

### Efficient Tree Traversal

213

214

The node traversal uses efficient algorithms:

215

- Single-pass processing for node removal

216

- Minimal tree reconstruction

217

- In-place modifications where possible

218

219

## Use Cases

220

221

### Improved Navigation

222

223

The flattened TOC structure provides:

224

- Cleaner sidebar navigation

225

- Better visual hierarchy

226

- Reduced redundancy (no duplicate page titles)

227

- More space for actual content sections

228

229

### Better Mobile Experience

230

231

Flattened structure works better on mobile devices:

232

- Less nested indentation

233

- Easier touch navigation

234

- Clearer visual hierarchy