Coverage for hdl_registers/generator/html/page.py: 98%
47 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-12 11:11 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-12 11:11 +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# --------------------------------------------------------------------------------------------------
10from __future__ import annotations
12from typing import TYPE_CHECKING, Any
14from hdl_registers.register_modes import REGISTER_MODES
16from .constant_table import HtmlConstantTableGenerator
17from .html_generator_common import HtmlGeneratorCommon
18from .html_translator import HtmlTranslator
19from .register_table import HtmlRegisterTableGenerator
21if TYPE_CHECKING:
22 from pathlib import Path
25class HtmlPageGenerator(HtmlGeneratorCommon):
26 """
27 Generate a HTML page with register and constant information.
28 See the :ref:`generator_html` article for usage details.
29 """
31 __version__ = "1.0.0"
33 SHORT_DESCRIPTION = "HTML page"
35 @property
36 def output_file(self) -> Path:
37 """
38 Result will be placed in this file.
39 """
40 return self.output_folder / f"{self.name}_regs.html"
42 def get_code(
43 self,
44 **kwargs: Any, # noqa: ANN401, ARG002
45 ) -> str:
46 """
47 Get a complete HTML page with register and constant information.
48 """
49 title = f"Documentation of {self.name} registers"
51 generated_info = HtmlTranslator().translate(
52 " ".join(self._get_generated_source_info(use_rst_annotation=True))
53 )
55 html = f"""\
56<!DOCTYPE html>
57<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
58<head>
59 <meta charset="utf-8" />
60 <meta name="viewport" content="width=device-width, initial-scale=1" />
61 <title>{title}</title>
62 <style type="text/css">
63{self.get_page_style()}
64 </style>
65</head>
66<body>
67 <h1>{title}</h1>
68 <p>This document is a specification for the register interface of the FPGA module \
69<b>{self.name}</b>.</p>
70{generated_info}
71 <h2>Register modes</h2>
72 <p>The following register modes are available.</p>
73{self._get_mode_descriptions()}
74"""
76 html += " <h2>Registers</h2>\n"
77 if self.register_list.register_objects:
78 register_table_generator = HtmlRegisterTableGenerator(
79 register_list=self.register_list, output_folder=self.output_folder
80 )
81 html += f"""
82 <p>The following registers make up the register list.</p>
83{register_table_generator.get_code()}
84"""
85 else:
86 html += " <p>This module does not have any registers.</p>"
88 html += " <h2>Constants</h2>\n"
89 if self.register_list.constants:
90 constant_table_generator = HtmlConstantTableGenerator(
91 register_list=self.register_list, output_folder=self.output_folder
92 )
93 html += f"""
94 <p>The following constants are part of the register interface.</p>
95{constant_table_generator.get_code()}"""
96 else:
97 html += " <p>This module does not have any constants.</p>"
99 html += """
100</body>
101</html>
102"""
104 return html
106 @staticmethod
107 def get_page_style(
108 font_style: str | None = None,
109 table_style: str | None = None,
110 math_style: str | None = None,
111 extra_style: str = "",
112 ) -> str:
113 """
114 Get a CSS style for the register pages.
116 Return:
117 str: CSS code.
118 """
119 if font_style is None:
120 font_style = """\
121html * {
122 font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
123}
125a {
126 color: #4C7AAF;
127}
128"""
130 if table_style is None:
131 table_style = """\
132table {
133 border-collapse: collapse;
134}
136td, th {
137 border-width: 0.1em;
138 border-style: solid;
139 border-color: #ddd;
140 padding-left: 0.5em;
141 padding-right: 0.5em;
142 padding-top: 0;
143 padding-bottom: 0;
144}
146th {
147 padding-top: 0.7em;
148 padding-bottom: 0.7em;
149 text-align: left;
150 background-color: #4CAF50;
151 color: white;
152}
154tr:nth-child(odd) {
155 background-color: #ffffff;
156}
158tr:nth-child(even) {
159 background-color: #ebebeb;
160}
162td.array_header {
163 border-top-width: 0.7em;
164 border-top-color: #4C7AAF;
165}
167td.array_footer {
168 border-bottom-width: 0.7em;
169 border-bottom-color: #4C7AAF;
170}
172td > p {
173 margin-top: 0.5em;
174 margin-bottom: 0.5em;
176 &:not(:last-child) {
177 margin-bottom: 0.9em;
178 }
179}
181li > p {
182 margin-top: 0.4em;
183 margin-bottom: 0.4em;
184}
185"""
187 if math_style is None:
188 math_style = """\
189/*
190* CSS below is taken from the HTML output of 'docutils'.
191* Original code is released under the terms of the 2-Clause BSD license and is Copyright (C)
192* 2009,2010 Alex Fernandez
193* 2021 Gunter Milde
194*
195* Code is generated by running
196* from docutils.core import publish_parts
197* from docutils.writers.html5_polyglot import Writer
198* print(publish_parts(rst, writer=Writer())["stylesheet"])
199* where 'rst' contains both inline and block math.
200*/
202/* Formulas */
203.formula {
204 text-align: center;
205 margin: 1.2em 0;
206 line-height: 1.4;
207}
208span.formula {
209 white-space: nowrap;
210}
211div.formula {
212 padding: 0.5ex;
213 margin-left: auto;
214 margin-right: auto;
215}
217/* Basic features */
218a.eqnumber {
219 display: inline-block;
220 float: right;
221 clear: right;
222 font-weight: bold;
223}
224span.unknown {
225 color: #800000;
226}
227span.ignored, span.arraydef {
228 display: none;
229}
230.phantom {
231 visibility: hidden;
232}
233.formula i {
234 letter-spacing: 0.1ex;
235}
237/* Alignment */
238.align-left, .align-l {
239 text-align: left;
240}
241.align-right, .align-r {
242 text-align: right;
243}
244.align-center, .align-c {
245 text-align: center;
246}
248/* Structures */
249span.hspace {
250 display: inline-block;
251}
252span.overline, span.bar {
253 text-decoration: overline;
254}
255.fraction, .fullfraction, .textfraction {
256 display: inline-block;
257 vertical-align: middle;
258 text-align: center;
259}
260span.formula .fraction,
261.textfraction,
262span.smallmatrix {
263 font-size: 80%;
264 line-height: 1;
265}
266span.numerator {
267 display: block;
268 line-height: 1;
269}
270span.denominator {
271 display: block;
272 line-height: 1;
273 padding: 0ex;
274 border-top: thin solid;
275}
276.formula sub, .formula sup {
277 font-size: 80%;
278}
279sup.numerator, sup.unit {
280 vertical-align: 80%;
281}
282sub.denominator, sub.unit {
283 vertical-align: -20%;
284}
285span.smallsymbol {
286 font-size: 75%;
287 line-height: 75%;
288}
289span.boldsymbol {
290 font-weight: bold;
291}
292span.sqrt {
293 display: inline-block;
294 vertical-align: middle;
295 padding: 0.1ex;
296}
297sup.root {
298 position: relative;
299 left: 1.4ex;
300}
301span.radical {
302 display: inline-block;
303 padding: 0ex;
304 /* font-size: 160%; for DejaVu, not required with STIX */
305 line-height: 100%;
306 vertical-align: top;
307 vertical-align: middle;
308}
310span.root {
311 display: inline-block;
312 border-top: thin solid;
313 padding: 0ex;
314 vertical-align: middle;
315}
316div.formula .bigoperator,
317.displaystyle .bigoperator,
318.displaystyle .bigoperator {
319 line-height: 120%;
320 font-size: 140%;
321 padding-right: 0.2ex;
322}
323span.fraction .bigoperator,
324span.scriptstyle .bigoperator {
325 line-height: inherit;
326 font-size: inherit;
327 padding-right: 0;
328}
329span.bigdelimiter {
330 display: inline-block;
331}
332span.bigdelimiter.size1 {
333 transform: scale(1, 1.2);
334 line-height: 1.2;
335}
336span.bigdelimiter.size2 {
337 transform: scale(1, 1.62);
338 line-height: 1.62%;
340}
341span.bigdelimiter.size3 {
342 transform: scale(1, 2.05);
343 line-height: 2.05%;
344}
345span.bigdelimiter.size4 {
346 transform: scale(1, 2.47);
347 line-height: 2.47%;
348}
349/* vertically stacked sub and superscript */
350span.scripts {
351 display: inline-table;
352 vertical-align: middle;
353 padding-right: 0.2ex;
354}
355.script {
356 display: table-row;
357 text-align: left;
358 line-height: 150%;
359}
360span.limits {
361 display: inline-table;
362 vertical-align: middle;
363}
364.limit {
365 display: table-row;
366 line-height: 99%;
367}
368sup.limit, sub.limit {
369 line-height: 100%;
370}
371span.embellished,
372span.embellished > .base {
373 display: inline-block;
374}
375span.embellished > sup,
376span.embellished > sub {
377 display: inline-block;
378 font-size: 100%;
379 position: relative;
380 bottom: 0.3em;
381 width: 0px;
382}
383span.embellished > sub {
384 top: 0.4em;
385}
387/* Environments */
388span.array, span.bracketcases, span.binomial, span.environment {
389 display: inline-table;
390 text-align: center;
391 vertical-align: middle;
392}
393span.arrayrow, span.binomrow {
394 display: table-row;
395 padding: 0;
396 border: 0;
397}
398span.arraycell, span.bracket, span.case, span.binomcell, span.environmentcell {
399 display: table-cell;
400 padding: 0ex 0.2ex;
401 line-height: 1; /* 99%; */
402 border: 0ex;
403}
404.environment.align > .arrayrow > .arraycell.align-l {
405 padding-right: 2em;
406}
408/* Inline binomials */
409span.binom {
410 display: inline-block;
411 vertical-align: middle;
412 text-align: center;
413 font-size: 80%;
414}
415span.binomstack {
416 display: block;
417 padding: 0em;
418}
420/* Over- and underbraces */
421span.overbrace {
422 border-top: 2pt solid;
423}
424span.underbrace {
425 border-bottom: 2pt solid;
426}
428/* Stackrel */
429span.stackrel {
430 display: inline-block;
431 text-align: center;
432}
433span.upstackrel {
434 display: block;
435 padding: 0em;
436 font-size: 80%;
437 line-height: 64%;
438 position: relative;
439 top: 0.15em;
441}
442span.downstackrel {
443 display: block;
444 vertical-align: bottom;
445 padding: 0em;
446}
448/* Fonts */
449.formula {
450 font-family: STIX, "DejaVu Serif", "DejaVu Math TeX Gyre", serif;
451}
452span.radical, /* ensure correct size of square-root sign */
453span.integral { /* upright integral signs for better alignment of indices */
454 font-family: "STIXIntegralsUp", STIX;
455 /* font-size: 115%; match apparent size with DejaVu */
456}
457span.bracket {
458 /* some "STIX" and "DejaVu Math TeX Gyre" bracket pieces don't fit */
459 font-family: "DejaVu Serif", serif;
460}
461span.mathsf, span.textsf {
462 font-family: sans-serif;
463}
464span.mathrm, span.textrm {
465 font-family: STIX, "DejaVu Serif", "DejaVu Math TeX Gyre", serif;
466}
467span.mathtt, span.texttt {
468 font-family: monospace;
469}
470span.text, span.textnormal,
471span.mathsf, span.mathtt, span.mathrm {
472 font-style: normal;
473}
474span.fraktur {
475 font-family: "Lucida Blackletter", eufm10, blackletter;
476}
477span.blackboard {
478 font-family: Blackboard, msbm10, serif;
479}
480span.scriptfont {
481 font-family: "Monotype Corsiva", "Apple Chancery", "URW Chancery L", cursive;
482 font-style: italic;
483}
484span.mathscr {
485 font-family: MathJax_Script, rsfs10, cursive;
486 font-style: italic;
487}
488span.textsc {
489 font-variant: small-caps;
490}
491span.textsl {
492 font-style: oblique;
493}
495/* Colors */
496span.colorbox {
497 display: inline-block;
498 padding: 5px;
499}
500span.fbox {
501 display: inline-block;
502 border: thin solid black;
503 padding: 2px;
504}
505span.boxed, span.framebox {
506 display: inline-block;
507 border: thin solid black;
508 padding: 5px;
509}
510/* End docutils CSS */
511"""
513 return f"""\
514.literal {
515 font-family: monospace;
516 white-space: pre-wrap;
517 color: #e74c3c;
518 background-color: #ffffff;
519 padding-left: 0.4em;
520 padding-right: 0.4em;
521 padding-top: 0.2em;
522 padding-bottom: 0.2em;
523 border-width: 0.1em;
524 border-style: solid;
525 border-color: #ddd;
526}
528.literal > span.pre {
529 white-space: nowrap;
530}
532{font_style}
533{table_style}
534{math_style}
535{extra_style}"""
537 @staticmethod
538 def _get_mode_descriptions() -> str:
539 html = """
540<table>
541<thead>
542 <tr>
543 <th>Mode</th>
544 <th>Description</th>
545 </tr>
546</thead>
547<tbody>"""
549 for mode in REGISTER_MODES.values():
550 html += f"""
551<tr>
552 <td><p>{mode.name}</p></td>
553 <td><p>{mode.description}</p></td>
554</tr>
555"""
556 html += """
557</tbody>
558</table>"""
559 return html