Skip to content

Commit eefc2ea

Browse files
Revathyvenugopal162pyansys-ci-botjorgepiloto
authored
fix: add title breadcrumbs (#515)
Co-authored-by: pyansys-ci-bot <[email protected]> Co-authored-by: Jorge Martínez <[email protected]>
1 parent 6685c8e commit eefc2ea

File tree

2 files changed

+80
-39
lines changed

2 files changed

+80
-39
lines changed

doc/changelog.d/515.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fix: add title breadcrumbs

src/ansys_sphinx_theme/search/fuse_search.py

Lines changed: 79 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121
# SOFTWARE.
2222

23-
"""Module to fuse search."""
23+
"""Module for generating search indices."""
2424

2525
import json
2626
import re
@@ -29,84 +29,124 @@
2929

3030

3131
class SearchIndex:
32-
"""Class to get search index."""
32+
"""Generate a search index for a Sphinx document."""
3333

3434
def __init__(self, doc_name, app):
35-
"""Initialize the class.
35+
"""
36+
Initialize the search index object.
3637
3738
Parameters
3839
----------
3940
doc_name : str
40-
Document name.
41+
Name of the document.
4142
app : Sphinx
42-
Sphinx application.
43-
version : str
44-
Version of the document for prefixing the path.
43+
Sphinx application instance.
4544
"""
46-
self._doc_name = doc_name
47-
self.doc_path = f"{self._doc_name}.html"
48-
self.doc_title = app.env.titles[self._doc_name].astext()
49-
self._doc_tree = app.env.get_doctree(self._doc_name)
45+
self.doc_name = doc_name
46+
self.doc_path = f"{self.doc_name}.html"
47+
self.env = app.env
48+
self.doc_title = self.env.titles[self.doc_name].astext()
49+
self.doc_tree = self.env.get_doctree(self.doc_name)
5050
self.sections = []
5151

52-
def iterate_through_docs(self):
53-
"""Iterate through the document."""
54-
for node in self._doc_tree.traverse(nodes.section):
55-
self.section_title = node[0].astext()
56-
self.section_text = "\n".join(
52+
def build_sections(self):
53+
"""Build sections from the document tree."""
54+
for node in self.doc_tree.traverse(nodes.section):
55+
section_title = node[0].astext()
56+
section_text = "\n".join(
5757
n.astext()
5858
for node_type in [nodes.paragraph, nodes.literal_block]
5959
for n in node.traverse(node_type)
6060
)
61-
self.section_anchor_id = _title_to_anchor(self.section_title)
61+
section_anchor_id = _title_to_anchor(section_title)
6262
self.sections.append(
6363
{
64-
"section_title": self.section_title,
65-
"section_text": self.section_text,
66-
"section_anchor_id": self.section_anchor_id,
64+
"title": section_title,
65+
"text": section_text,
66+
"anchor_id": section_anchor_id,
6767
}
6868
)
6969

70+
def generate_breadcrumbs(self, section_title: str) -> str:
71+
"""
72+
Generate title breadcrumbs from the document structure.
73+
74+
Parameters
75+
----------
76+
section_title : str
77+
The section title to generate breadcrumbs for.
78+
79+
Returns
80+
-------
81+
str
82+
Breadcrumb string.
83+
84+
Notes
85+
-----
86+
The last part of `doc_name` is ignored because it represents the file name,
87+
which is not needed for the breadcrumb trail. The breadcrumb trail is generated
88+
by iterating over the parts of `doc_name` and fetching the title from the environment.
89+
"""
90+
docs_parts = self.doc_name.split("/")[:-1]
91+
92+
breadcrumb_parts = [
93+
self.env.titles[part].astext() for part in docs_parts if part in self.env.titles
94+
]
95+
96+
# Create breadcrumb hierarchy
97+
breadcrumbs = " > ".join(breadcrumb_parts)
98+
ignore_doc_title = section_title == self.doc_title
99+
100+
# Construct final breadcrumb path
101+
if ignore_doc_title:
102+
return f"{breadcrumbs} > {section_title}" if breadcrumbs else section_title
103+
104+
return (
105+
f"{breadcrumbs} > {self.doc_title} > {section_title}"
106+
if breadcrumbs
107+
else f"{self.doc_title} > {section_title}"
108+
)
109+
70110
@property
71111
def indices(self):
72-
"""Get search index."""
73-
for sections in self.sections:
74-
search_index = {
75-
"objectID": self._doc_name,
76-
"href": f"{self.doc_path}#{sections['section_anchor_id']}",
77-
"title": self.doc_title,
78-
"section": sections["section_title"],
79-
"text": sections["section_text"],
112+
"""Generate indices for each section."""
113+
for section in self.sections:
114+
breadcrumbs = self.generate_breadcrumbs(section["title"])
115+
yield {
116+
"objectID": self.doc_name,
117+
"href": f"{self.doc_path}#{section['anchor_id']}",
118+
"title": breadcrumbs,
119+
"section": section["title"],
120+
"text": section["text"],
80121
}
81-
yield search_index
82122

83123

84124
def _title_to_anchor(title: str) -> str:
85-
"""Convert title to anchor."""
125+
"""Convert a title to a URL-friendly anchor identifier."""
86126
return re.sub(r"[^\w\s-]", "", title.lower().strip().replace(" ", "-"))
87127

88128

89129
def create_search_index(app, exception):
90-
"""Create search index for the document in build finished.
130+
"""
131+
Generate search index at the end of the Sphinx build process.
91132
92133
Parameters
93134
----------
94135
app : Sphinx
95-
Sphinx application.
96-
exception : Any
97-
Exception.
136+
Sphinx application instance.
137+
exception : Exception
138+
Exception raised during the build process, if any.
98139
"""
99140
if exception:
100141
return
101142

102-
all_docs = app.env.found_docs
103143
search_index_list = []
104144

105-
for document in all_docs:
145+
for document in app.env.found_docs:
106146
search_index = SearchIndex(document, app)
107-
search_index.iterate_through_docs()
147+
search_index.build_sections()
108148
search_index_list.extend(search_index.indices)
109149

110-
search_index = app.builder.outdir / "_static" / "search.json"
111-
with search_index.open("w", encoding="utf-8") as index_file:
150+
search_index_path = app.builder.outdir / "_static" / "search.json"
151+
with search_index_path.open("w", encoding="utf-8") as index_file:
112152
json.dump(search_index_list, index_file, ensure_ascii=False, indent=4)

0 commit comments

Comments
 (0)