Coverage for hdl_registers/generator/html/page.py: 100%

42 statements  

« prev     ^ index     » next       coverage.py v7.6.3, created at 2024-10-17 20:51 +0000

1# -------------------------------------------------------------------------------------------------- 

2# Copyright (c) Lukas Vik. All rights reserved. 

3# 

4# This file is part of the hdl-registers project, an HDL register generator fast enough to run 

5# in real time. 

6# https://hdl-registers.com 

7# https://github.com/hdl-registers/hdl-registers 

8# -------------------------------------------------------------------------------------------------- 

9 

10# Standard libraries 

11from pathlib import Path 

12from typing import Any, Optional 

13 

14# First party libraries 

15from hdl_registers.register_modes import REGISTER_MODES 

16 

17# Local folder libraries 

18from .constant_table import HtmlConstantTableGenerator 

19from .html_generator_common import HtmlGeneratorCommon 

20from .register_table import HtmlRegisterTableGenerator 

21 

22 

23class HtmlPageGenerator(HtmlGeneratorCommon): 

24 """ 

25 Generate a HTML page with register and constant information. 

26 See the :ref:`generator_html` article for usage details. 

27 """ 

28 

29 __version__ = "1.0.0" 

30 

31 SHORT_DESCRIPTION = "HTML page" 

32 

33 @property 

34 def output_file(self) -> Path: 

35 """ 

36 Result will be placed in this file. 

37 """ 

38 return self.output_folder / f"{self.name}_regs.html" 

39 

40 def get_code(self, **kwargs: Any) -> str: 

41 """ 

42 Get a complete HTML page with register and constant information. 

43 """ 

44 title = f"Documentation of {self.name} registers" 

45 html = f"""\ 

46{self.header} 

47<!DOCTYPE html> 

48<html> 

49<head> 

50 <title>{title}</title> 

51 <!-- Include the style both inline and as a link to a separate CSS file. --> 

52 <!-- Some tools, e.g. Jenkins, will not render with an inline stylesheet. --> 

53 <!-- For other tools, e.g. page inclusion in sphinx, the style must be in the file. --> 

54 <link rel="stylesheet" href="regs_style.css"> 

55 <style> 

56 {self.get_page_style()} 

57 </style> 

58</head> 

59<body> 

60 <h1>{title}</h1> 

61 <p>This document is a specification for the register interface of the FPGA module \ 

62<b>{self.name}</b>.</p> 

63 <p>{' '.join(self.generated_source_info)}</p> 

64 <h2>Register modes</h2> 

65 <p>The following register modes are available.</p> 

66{self._get_mode_descriptions()} 

67""" 

68 

69 html += " <h2>Registers</h2>\n" 

70 if self.register_list.register_objects: 

71 register_table_generator = HtmlRegisterTableGenerator( 

72 register_list=self.register_list, output_folder=self.output_folder 

73 ) 

74 html += f""" 

75 <p>The following registers make up the register map.</p> 

76{register_table_generator.get_code()} 

77""" 

78 else: 

79 html += " <p>This module does not have any registers.</p>" 

80 

81 html += " <h2>Constants</h2>\n" 

82 if self.register_list.constants: 

83 constant_table_generator = HtmlConstantTableGenerator( 

84 register_list=self.register_list, output_folder=self.output_folder 

85 ) 

86 html += f""" 

87 <p>The following constants are part of the register interface.</p> 

88{constant_table_generator.get_code()}""" 

89 else: 

90 html += " <p>This module does not have any constants.</p>" 

91 

92 html += """ 

93</body> 

94</html>""" 

95 

96 return html 

97 

98 @staticmethod 

99 def get_page_style( 

100 table_style: Optional[str] = None, font_style: Optional[str] = None, extra_style: str = "" 

101 ) -> str: 

102 """ 

103 Get a CSS style for the register pages. Shall be saved to a file called ``regs_style.css``. 

104 

105 Return: 

106 str: CSS code. 

107 """ 

108 if font_style is None: 

109 font_style = """ 

110html * { 

111 font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; 

112}""" 

113 

114 if table_style is None: 

115 table_style = """ 

116table { 

117 border-collapse: collapse; 

118} 

119td, th { 

120 border-width: 1px; 

121 border-style: solid; 

122 border-color: #ddd; 

123 padding: 8px; 

124} 

125td.array_header { 

126 border-top-width: 10px; 

127 border-top-color: #4cacaf; 

128} 

129td.array_footer { 

130 border-bottom-width: 10px; 

131 border-bottom-color: #4cacaf; 

132} 

133tr:nth-child(even) { 

134 background-color: #f2f2f2; 

135} 

136th { 

137 padding-top: 12px; 

138 padding-bottom: 12px; 

139 text-align: left; 

140 background-color: #4CAF50; 

141 color: white; 

142}""" 

143 

144 style = f""" 

145{font_style} 

146{table_style} 

147{extra_style}""" 

148 return style 

149 

150 @staticmethod 

151 def _get_mode_descriptions() -> str: 

152 html = """ 

153<table> 

154<thead> 

155 <tr> 

156 <th>Mode</th> 

157 <th>Description</th> 

158 </tr> 

159</thead> 

160<tbody>""" 

161 

162 for mode in REGISTER_MODES.values(): 

163 html += f""" 

164<tr> 

165 <td>{mode.name}</td> 

166 <td>{mode.description}</td> 

167</tr> 

168""" 

169 html += """ 

170</tbody> 

171</table>""" 

172 return html