1515- ``zephyr:code-sample-category::`` - Defines a category for grouping code samples.
1616- ``zephyr:code-sample-listing::`` - Shows a listing of code samples found in a given category.
1717- ``zephyr:board-catalog::`` - Shows a listing of boards supported by Zephyr.
18+ - ``zephyr:board::`` - Flags a document as being the documentation page for a board.
1819
1920Roles
2021-----
2122
2223- ``:zephyr:code-sample:`` - References a code sample.
2324- ``:zephyr:code-sample-category:`` - References a code sample category.
25+ - ``:zephyr:board:`` - References a board.
2426
2527"""
2628
@@ -85,6 +87,10 @@ class CodeSampleListingNode(nodes.Element):
8587 pass
8688
8789
90+ class BoardNode (nodes .Element ):
91+ pass
92+
93+
8894class ConvertCodeSampleNode (SphinxTransform ):
8995 default_priority = 100
9096
@@ -213,6 +219,65 @@ def convert_node(self, node):
213219 node .replace_self (node .children [0 ])
214220
215221
222+ class ConvertBoardNode (SphinxTransform ):
223+ default_priority = 100
224+
225+ def apply (self ):
226+ matcher = NodeMatcher (BoardNode )
227+ for node in self .document .traverse (matcher ):
228+ self .convert_node (node )
229+
230+ def convert_node (self , node ):
231+ parent = node .parent
232+ siblings_to_move = []
233+ if parent is not None :
234+ index = parent .index (node )
235+ siblings_to_move = parent .children [index + 1 :]
236+
237+ new_section = nodes .section (ids = [node ["id" ]])
238+ new_section += nodes .title (text = node ["full_name" ])
239+
240+ # create a sidebar with all the board details
241+ sidebar = nodes .sidebar (classes = ["board-overview" ])
242+ new_section += sidebar
243+ sidebar += nodes .title (text = "Board Overview" )
244+
245+ if node ["image" ] is not None :
246+ figure = nodes .figure ()
247+ # set a scale of 100% to indicate we want a link to the full-size image
248+ figure += nodes .image (uri = f"/{ node ['image' ]} " , scale = 100 )
249+ figure += nodes .caption (text = node ["full_name" ])
250+ sidebar += figure
251+
252+ field_list = nodes .field_list ()
253+ sidebar += field_list
254+
255+ details = [
256+ ("Vendor" , node ["vendor" ]),
257+ ("Architecture" , ", " .join (node ["archs" ])),
258+ ("SoC" , ", " .join (node ["socs" ])),
259+ ]
260+
261+ for property_name , value in details :
262+ field = nodes .field ()
263+ field_name = nodes .field_name (text = property_name )
264+ field_body = nodes .field_body ()
265+ field_body += nodes .paragraph (text = value )
266+ field += field_name
267+ field += field_body
268+ field_list += field
269+
270+ # Move the sibling nodes under the new section
271+ new_section .extend (siblings_to_move )
272+
273+ # Replace the custom node with the new section
274+ node .replace_self (new_section )
275+
276+ # Remove the moved siblings from their original parent
277+ for sibling in siblings_to_move :
278+ parent .remove (sibling )
279+
280+
216281class CodeSampleCategoriesTocPatching (SphinxPostTransform ):
217282 default_priority = 5 # needs to run *before* ReferencesResolver
218283
@@ -569,6 +634,45 @@ def run(self):
569634 return [code_sample_listing_node ]
570635
571636
637+ class BoardDirective (SphinxDirective ):
638+ has_content = False
639+ required_arguments = 1
640+ optional_arguments = 0
641+
642+ def run (self ):
643+ # board_name is passed as the directive argument
644+ board_name = self .arguments [0 ]
645+
646+ boards = self .env .domaindata ["zephyr" ]["boards" ]
647+ vendors = self .env .domaindata ["zephyr" ]["vendors" ]
648+
649+ if board_name not in boards :
650+ logger .warning (
651+ f"Board { board_name } does not seem to be a valid board name." ,
652+ location = (self .env .docname , self .lineno ),
653+ )
654+ return []
655+ elif "docname" in boards [board_name ]:
656+ logger .warning (
657+ f"Board { board_name } is already documented in { boards [board_name ]['docname' ]} ." ,
658+ location = (self .env .docname , self .lineno ),
659+ )
660+ return []
661+ else :
662+ board = boards [board_name ]
663+ # flag board in the domain data as now having a documentation page so that it can be
664+ # cross-referenced etc.
665+ board ["docname" ] = self .env .docname
666+
667+ board_node = BoardNode (id = board_name )
668+ board_node ["full_name" ] = board ["full_name" ]
669+ board_node ["vendor" ] = vendors .get (board ["vendor" ], board ["vendor" ])
670+ board_node ["archs" ] = board ["archs" ]
671+ board_node ["socs" ] = board ["socs" ]
672+ board_node ["image" ] = board ["image" ]
673+ return [board_node ]
674+
675+
572676class BoardCatalogDirective (SphinxDirective ):
573677 has_content = False
574678 required_arguments = 0
@@ -602,18 +706,21 @@ class ZephyrDomain(Domain):
602706 roles = {
603707 "code-sample" : XRefRole (innernodeclass = nodes .inline , warn_dangling = True ),
604708 "code-sample-category" : XRefRole (innernodeclass = nodes .inline , warn_dangling = True ),
709+ "board" : XRefRole (innernodeclass = nodes .inline , warn_dangling = True ),
605710 }
606711
607712 directives = {
608713 "code-sample" : CodeSampleDirective ,
609714 "code-sample-listing" : CodeSampleListingDirective ,
610715 "code-sample-category" : CodeSampleCategoryDirective ,
611716 "board-catalog" : BoardCatalogDirective ,
717+ "board" : BoardDirective ,
612718 }
613719
614720 object_types : Dict [str , ObjType ] = {
615721 "code-sample" : ObjType ("code sample" , "code-sample" ),
616722 "code-sample-category" : ObjType ("code sample category" , "code-sample-category" ),
723+ "board" : ObjType ("board" , "board" ),
617724 }
618725
619726 initial_data : Dict [str , Any ] = {
@@ -647,6 +754,12 @@ def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
647754 self .data ["code-samples" ].update (otherdata ["code-samples" ])
648755 self .data ["code-samples-categories" ].update (otherdata ["code-samples-categories" ])
649756
757+ # self.data["boards"] contains all the boards right from builder-inited time, but it still # potentially needs merging since a board's docname property is set by BoardDirective to
758+ # indicate the board is documented in a specific document.
759+ for board_name , board in otherdata ["boards" ].items ():
760+ if "docname" in board :
761+ self .data ["boards" ][board_name ]["docname" ] = board ["docname" ]
762+
650763 # merge category trees by adding all the categories found in the "other" tree that to
651764 # self tree
652765 other_tree = otherdata ["code-samples-categories-tree" ]
@@ -689,6 +802,18 @@ def get_objects(self):
689802 1 ,
690803 )
691804
805+ for _ , board in self .data ["boards" ].items ():
806+ # only boards that do have a documentation page are to be considered as valid objects
807+ if "docname" in board :
808+ yield (
809+ board ["name" ],
810+ board ["full_name" ],
811+ "board" ,
812+ board ["docname" ],
813+ board ["name" ],
814+ 1 ,
815+ )
816+
692817 # used by Sphinx Immaterial theme
693818 def get_object_synopses (self ) -> Iterator [Tuple [Tuple [str , str ], str ]]:
694819 for _ , code_sample in self .data ["code-samples" ].items ():
@@ -702,18 +827,20 @@ def resolve_xref(self, env, fromdocname, builder, type, target, node, contnode):
702827 elem = self .data ["code-samples" ].get (target )
703828 elif type == "code-sample-category" :
704829 elem = self .data ["code-samples-categories" ].get (target )
830+ elif type == "board" :
831+ elem = self .data ["boards" ].get (target )
705832 else :
706833 return
707834
708835 if elem :
709836 if not node .get ("refexplicit" ):
710- contnode = [nodes .Text (elem ["name" ])]
837+ contnode = [nodes .Text (elem ["name" ] if type != "board" else elem [ "full_name" ] )]
711838
712839 return make_refnode (
713840 builder ,
714841 fromdocname ,
715842 elem ["docname" ],
716- elem ["id" ],
843+ elem ["id" ] if type != "board" else elem [ "name" ] ,
717844 contnode ,
718845 elem ["description" ].astext () if type == "code-sample" else None ,
719846 )
@@ -821,6 +948,7 @@ def setup(app):
821948
822949 app .add_transform (ConvertCodeSampleNode )
823950 app .add_transform (ConvertCodeSampleCategoryNode )
951+ app .add_transform (ConvertBoardNode )
824952
825953 app .add_post_transform (ProcessCodeSampleListingNode )
826954 app .add_post_transform (CodeSampleCategoriesTocPatching )
0 commit comments