|
8 | 8 | :license: BSD, see LICENSE for details. |
9 | 9 | """ |
10 | 10 | from __future__ import annotations |
11 | | -from typing import List, Optional, Tuple, TYPE_CHECKING |
| 11 | +from typing import List, TYPE_CHECKING |
12 | 12 |
|
13 | 13 | from docutils import nodes |
14 | 14 |
|
15 | 15 | if TYPE_CHECKING: |
16 | 16 | from sphinx.enviornment import BuilderEnviornment |
17 | 17 |
|
18 | 18 |
|
19 | | -def _safe_descend(node:nodes.Node, *args: int) -> Optional[nodes.Node]: |
20 | | - """Get node descend in a safe way.""" |
21 | | - try: |
22 | | - for index in args: |
23 | | - node = node[index] |
24 | | - return node |
25 | | - except: |
26 | | - return None |
| 19 | +def resolve(env: BuilderEnviornment, docname:str, node:nodes.Node) -> List[nodes.title]: |
| 20 | + return resolve_section(node) + resolve_document(env, docname) |
27 | 21 |
|
28 | 22 |
|
29 | | -def resolve_fullpath(env: BuilderEnviornment, docname:str, node:nodes.Node, |
30 | | - include_project:bool=False) -> List[str]: |
31 | | - return [x.astext() for x in resolve_sectpath(node.document, node)] + \ |
32 | | - resolve_docpath(env, docname, include_project=include_project) |
33 | | - |
34 | | - |
35 | | -def resolve_sectpath(doctree:nodes.document, node:nodes.Node) -> List[nodes.title]: |
| 23 | +def resolve_section(node:nodes.section) -> List[nodes.title]: |
36 | 24 | # FIXME: doc is None |
37 | | - _, subtitlenode = resolve_doctitle(doctree) |
38 | 25 | titlenodes = [] |
39 | 26 | while node: |
40 | | - secttitle = resolve_secttitle(node) |
| 27 | + if len(node) > 0 and isinstance(node[0], nodes.title): |
| 28 | + titlenodes.append(node[0]) |
41 | 29 | node = node.parent |
42 | | - if not secttitle or secttitle == subtitlenode: |
43 | | - continue |
44 | | - titlenodes.append(secttitle) |
45 | 30 | return titlenodes |
46 | 31 |
|
47 | 32 |
|
48 | | -def resolve_secttitle(node:nodes.Node) -> Optional[nodes.title]: |
49 | | - titlenode = _safe_descend(node.parent, 0) |
50 | | - if not isinstance(titlenode, nodes.title): |
51 | | - return None |
52 | | - return titlenode |
53 | | - |
54 | | - |
55 | | -def resolve_docpath(env:BuilderEnviornment, docname:str, include_project:bool=False) -> List[str]: |
| 33 | +def resolve_document(env:BuilderEnviornment, docname:str) -> List[nodes.title]: |
| 34 | + """ |
| 35 | + .. note:: Title of document itself does not included in the returned list |
| 36 | + """ |
56 | 37 | titles = [] |
57 | | - |
58 | | - if include_project: |
59 | | - titles.append(env.config.project) |
60 | | - |
61 | 38 | master_doc = env.config.master_doc |
62 | 39 | v = docname.split('/') |
63 | | - if v.pop() == master_doc: |
64 | | - if v: |
65 | | - # If docname is "a/b/index", we need titles of "a" |
66 | | - v.pop() |
67 | | - else: |
68 | | - # docname is "index", no need to get docpath, it is root doc |
69 | | - return [] |
| 40 | + |
| 41 | + # Exclude self |
| 42 | + if v.pop() == master_doc and v: |
| 43 | + # If self is master_doc, like: "a/b/c/index", we only return titles |
| 44 | + # of "a/b/", so pop again |
| 45 | + v.pop() |
| 46 | + |
| 47 | + # Collect master doc title in docname |
70 | 48 | while v: |
71 | 49 | master_docname = '/'.join(v + [master_doc]) |
72 | 50 | if master_docname in env.titles: |
73 | | - title = env.titles[master_docname].astext() |
| 51 | + title = env.titles[master_docname] |
74 | 52 | else: |
75 | | - title = v[-1].title() |
| 53 | + title = nodes.title(text=v[-1].title()) # FIXME: Create mock title for now |
76 | 54 | titles.append(title) |
77 | 55 | v.pop() |
78 | 56 |
|
79 | | - return titles[::-1] # Reverse inplace |
80 | | - |
81 | | - |
82 | | -def resolve_doctitle(doctree:nodes.document) -> Tuple[Optional[nodes.title], |
83 | | - Optional[nodes.title]]: |
84 | | - |
85 | | - toplevel_sectnode = doctree.next_node(nodes.section) |
86 | | - if not toplevel_sectnode: |
87 | | - return (None, None) |
| 57 | + # Include title of top-level master doc |
| 58 | + if master_doc in env.titles: |
| 59 | + titles.append(env.titles[master_doc]) |
88 | 60 |
|
89 | | - titlenode = _safe_descend(toplevel_sectnode, 0) |
90 | | - # NOTE: nodes.subtitle does not make senses beacuse Sphinx doesn't support |
91 | | - # subtitle: |
92 | | - # |
93 | | - # > Sphinx does not support a "subtitle". |
94 | | - # > Sphinx recognizes it as a mere second level section |
95 | | - # |
96 | | - # ref: |
97 | | - # - https://github.com/sphinx-doc/sphinx/issues/3574#issuecomment-288722585 |
98 | | - # - https://github.com/sphinx-doc/sphinx/issues/3567#issuecomment-288093991 |
99 | | - if len(toplevel_sectnode) != 2: |
100 | | - return (titlenode, None) |
101 | | - # HACK: For our convenience, we regard second level section title |
102 | | - # (under document) as subtitle:: |
103 | | - # <section> |
104 | | - # <title> |
105 | | - # <section> |
106 | | - # <(sub)title> |
107 | | - subtitlenode = toplevel_sectnode[1][0] |
108 | | - if not isinstance(subtitlenode, nodes.title): |
109 | | - return (titlenode, None) |
110 | | - return (titlenode, subtitlenode) |
| 61 | + return titles |
0 commit comments