Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PDF build for documentation #18

Merged
merged 2 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion adi_doctools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ def config_inited(app, config):
except Exception as err:
pass
config.version = doc_version

# Parameter to enable PDF output tweaks
media_print = getenv("ADOC_MEDIA_PRINT", default="0")
media_print = True if media_print == "1" else False
config.media_print = media_print

def builder_inited(app):
if app.builder.format == 'html':
Expand Down
14 changes: 10 additions & 4 deletions adi_doctools/directive/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,25 +101,32 @@ def column_entries(self, rows, items, uid: Optional[str]=None):
uid=uid)
rows.append(row)

def generic_table(self, description, uid: Optional[str]=None):
def generic_table(self, description, uid: Optional[str]=None, media_print=False):
tgroup = nodes.tgroup(cols=2)
for _ in range(2):
colspec = nodes.colspec(colwidth=1)
tgroup.append(colspec)
table = nodes.table()
table += tgroup

# example: self.table_header(tgroup, ["Bear with me", "Description"])
self.table_header(tgroup, ["Name", "Description"])

rows = []
for key in description:
row = nodes.row()

entry = nodes.entry()
entry += nodes.literal(text="{:s}".format(key))
if not media_print: # Check if not in PDF mode
entry += nodes.literal(text="{:s}".format(key))
else:
entry += nodes.paragraph(text="{:s}".format(key)) # Use paragraph for PDF mode
row += entry

entry = nodes.entry()
entry += parse_rst(self.state, description[key], uid=uid)
row += entry

rows.append(row)

tbody = nodes.tbody()
Expand Down Expand Up @@ -154,8 +161,7 @@ def table_header(tgroup, columns):

thead.append(row)

def collapsible(self, section,
text: [str, Tuple[str, str]] = "", node=None):
def collapsible(self, section, text: [str, Tuple[str, str]] = "", node=None):
"""
Creates a collapsible content.
text: When a tuple, the first string is a unique id, useful when the
Expand Down
77 changes: 48 additions & 29 deletions adi_doctools/directive/hdl.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from ..parser.hdl import parse_hdl_build_status
from ..writer.hdl_component import hdl_component


log = {
'signal': "{lib}/component.xml: Signal {signal} defined in the hdl-interfaces directive does not exist in the IP-XACT!", # noqa: E501
'path': "Inconsistent paths, {cwd} not in {doc}",
Expand All @@ -39,11 +40,11 @@ def pretty_dep(string, parent):
else:
return string.replace("'MODELPARAM_VALUE.", '').replace("'", '')

def tables(self, subnode, content, component, lib_name):
def tables(self, subnode, content, component, lib_name, media_print = False):
description = self.get_descriptions(content)

if component is None:
subnode += self.generic_table(description)
subnode += self.generic_table(description, media_print = media_print)
return subnode

bs = component['bus_interface']
Expand Down Expand Up @@ -79,14 +80,17 @@ def tables(self, subnode, content, component, lib_name):

self.table_header(tgroup, ["Physical Port", "Logical Port", "Direction", "Dependency"]) # noqa: E501

# change type of tables entries when outputing to PDF
literal_ = 'literal' if not media_print else 'paragraph'

rows = []
pm = bs[tag]['port_map']
for key in pm:
self.column_entries(rows, [
[key, 'literal'],
[pm[key]['logical_port'], 'literal'],
[key, literal_ ],
[pm[key]['logical_port'], literal_],
[pm[key]['direction'], 'paragraph'],
[self.pretty_dep(pm[key]['dependency'], key), 'literal'],
[self.pretty_dep(pm[key]['dependency'], key), literal_],
])

tbody = nodes.tbody()
Expand All @@ -108,15 +112,18 @@ def tables(self, subnode, content, component, lib_name):

self.table_header(tgroup, ["Physical Port", "Direction", "Dependency", "Description"]) # noqa: E501

# change type of tables entries when outputing to PDF
literal_ = 'literal' if not media_print else 'paragraph'

rows = []
pr = component['ports']
dm = component['bus_domain']
for key in pr:
row = nodes.row()
self.column_entry(row, key, 'literal')
self.column_entry(row, key, literal_)
self.column_entry(row, pr[key]['direction'], 'paragraph')
self.column_entry(row, self.pretty_dep(pr[key]['dependency'], key),
'literal')
self.column_entry(row, self.pretty_dep(pr[key]['dependency'], key), literal_)

if 'clk' in key or 'clock' in key:
domain = 'clock domain'
elif 'reset':
Expand Down Expand Up @@ -154,6 +161,8 @@ def tables(self, subnode, content, component, lib_name):
def run(self):
env = self.state.document.settings.env

media_print = env.config.media_print

node = node_div()

if 'path' in self.options:
Expand All @@ -163,9 +172,9 @@ def run(self):

discover_hdl_component(env, lib_name)
if lib_name in env.component:
self.tables(node, self.content, env.component[lib_name], lib_name)
self.tables(node, self.content, env.component[lib_name], lib_name, media_print)
else:
self.tables(node, self.content, None, lib_name)
self.tables(node, self.content, None, lib_name, media_print)

return [node]

Expand All @@ -187,7 +196,7 @@ def get_hex_addr(addr: int, addr_incr: int):

return (dword, byte)

def tables(self, subnode, obj, key):
def tables(self, subnode, obj, key, media_print = False):
uid = "hdl-regmap-" + key
section = nodes.section(ids=[uid])

Expand All @@ -202,14 +211,17 @@ def tables(self, subnode, obj, key):
self.table_header(tgroup, ["DWORD", "BYTE", ["Reg Name", 3], "Description"]) # noqa: E501
self.table_header(tgroup, [["", 1], "BITS", "Field Name", "Type", "Default Value", "Description"]) # noqa: E501

# change type of tables entries when outputing to PDF
literal_ = 'literal' if not media_print else 'paragraph'

rows = []
for reg in obj['regmap']:
dword, byte = self.get_hex_addr(reg['address'], reg['addr_incr'])
self.column_entries(rows, [
[dword, 'literal', ['bold']],
[byte, 'literal', ['bold']],
[reg['name'], 'literal', ['bold'], 3],
[reg['description'], 'reST', ['description', 'bold']],
[dword, literal_, ['bold']],
[byte, literal_, ['bold']],
[reg['name'], literal_, ['bold'], 3],
[reg['description'], 'reST' if not media_print else 'paragraph', ['description', 'bold']],
], uid=uid)

for field in reg['fields']:
Expand All @@ -234,12 +246,12 @@ def tables(self, subnode, obj, key):
bits = f"{bits[0]}:{bits[1]}"

self.column_entries(rows, [
["", 'literal', [''], 1],
[f"[{bits}]", 'literal'],
[field['name'], 'literal'],
[field['rw'], 'literal'],
[default, 'literal', ['default']],
[field['description'], 'reST', ['description']],
["", literal_, [''], 1],
[f"[{bits}]", literal_],
[field['name'], literal_],
[field['rw'], literal_],
[default, 'default_value' if not media_print else 'paragraph', ['default']],
[field['description'], 'reST' if not media_print else 'paragraph', ['description']],
], uid=uid)

tbody = nodes.tbody()
Expand Down Expand Up @@ -280,6 +292,8 @@ def run(self):
env = self.state.document.settings.env
owner = env.docname

media_print = env.config.media_print

node = node_div()

if 'name' in self.options:
Expand All @@ -303,7 +317,7 @@ def run(self):

if owner not in env.regmaps[f]['owners']:
env.regmaps[f]['owners'].append(owner)
self.tables(subnode, env.regmaps[f]['subregmap'][lib_name], lib_name)
self.tables(subnode, env.regmaps[f]['subregmap'][lib_name], lib_name, media_print)

node += subnode
return [node]
Expand All @@ -320,11 +334,11 @@ def dot_fix(self, string):
else:
return string

def tables(self, content, parameter, lib_name):
def tables(self, content, parameter, lib_name, media_print = False):
description = self.get_descriptions(content)

if parameter is None:
return self.generic_table(description)
return self.generic_table(description, media_print = media_print)

tgroup = nodes.tgroup(cols=5)
for _ in range(5):
Expand All @@ -334,11 +348,14 @@ def tables(self, content, parameter, lib_name):
table += tgroup

self.table_header(tgroup, ["Name", "Description", "Default Value", "Choices/Range"]) # noqa: E501

# change type of tables entries when outputing to PDF
literal_ = 'literal' if not media_print else 'paragraph'

rows = []
for key in parameter:
row = nodes.row()
self.column_entry(row, "{:s}".format(key), 'literal')
self.column_entry(row, "{:s}".format(key), literal_)
if key in description:
self.column_entry(row, description[key],
'reST', classes=['description'])
Expand All @@ -348,7 +365,7 @@ def tables(self, content, parameter, lib_name):
classes=['description'])
for tag, ty in zip(['default'], ['literal']):
if parameter[key][tag] is not None:
self.column_entry(row, parameter[key][tag], ty,
self.column_entry(row, parameter[key][tag], ty if not media_print else 'paragraph',
classes=[tag])
else:
logger.warning(f"Got empty {tag} at parameter {key}!")
Expand All @@ -375,7 +392,9 @@ def tables(self, content, parameter, lib_name):
def run(self):
env = self.state.document.settings.env

node = node_div()
media_print = env.config.media_print

node = node_div()

if 'path' not in self.options:
self.options['path'] = env.docname.replace('/index', '')
Expand All @@ -386,9 +405,9 @@ def run(self):
if lib_name in env.component:
subnode += self.tables(self.content,
env.component[lib_name]['parameters'],
lib_name)
lib_name, media_print)
else:
subnode += self.tables(self.content, None, lib_name)
subnode += self.tables(self.content, None, lib_name, media_print)

node += subnode

Expand Down
10 changes: 9 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@
project = 'Doctools'
copyright = '2024, Analog Devices, Inc.'
author = 'Analog Devices, Inc.'
version = '0.3'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary? I don't want to manually increment this every time.
I prefer injecting it in CI with the ADOC_DOC_VERSION environment variable based on the git release tag, that may or may not be a python version variable.
The option from ..adi_doctools/__init__ import __version__ as version is fine for python projects like this one and pyadi-iio, but not for others like scopy, iio-osc, etc.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This field is necessary as it specifies on the first page of the PDF the mentioned version of the document. If we don't want to specify the version, I will remove this field or will change it so that it automatically updates.


locale_dirs = ['locales/'] # path is relative to the source directory
language = 'en'

# -- General configuration ---------------------------------------------------

extensions = [
"adi_doctools",
'adi_doctools',
'rst2pdf.pdfbuilder'
]

needs_extensions = {
Expand All @@ -24,6 +29,9 @@

export_metadata = True

# -- Options for PDF output --------------------------------------------------
# draft comment, future options for exporting to PDF

# -- Options for HTML output --------------------------------------------------

html_theme = 'cosmic'
Expand Down
23 changes: 23 additions & 0 deletions docs/docs_guidelines.rst
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,29 @@ if the target directory is:
* *./prs/1234*: ``2``
* *./staging/user/branch*: ``3``

Exporting to PDF
--------------------------------------------------------------------------------

The whole documentation can be exported to a PDF document for a more compact
format. This is done by setting the enviroment variable called
``ADOC_MEDIA_PRINT`` to 1 (default it's 0) and building the documentation using
this command:

.. code-block::

user@analog:~/doctools/docs$ sphinx-build -b pdf . _build/pdfbuild

In the output folder, you’ll find a PDF document named after the repository
(e.g. Doctools.pdf). This document includes an auto-generated cover, followed by
the remaining pages. Note that an HTML build of the documentation is not
required for the PDF build.

.. warning::

The enviroment variable ``ADOC_MEDIA_PRINT`` should be set to 0 when building
the HTML pages of documentation. If not set, some components of the pages
may not render properly.

References
--------------------------------------------------------------------------------

Expand Down
3 changes: 3 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
sphinx
matplotlib
rst2pdf
svglib
https://github.com/analogdevicesinc/doctools/releases/download/latest/adi-doctools.tar.gz
Loading