poxy 0.18.0__py3-none-any.whl → 0.19.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- poxy/generated/poxy.css +2 -1
- poxy/main.py +9 -2
- poxy/mcss/CONTRIBUTING.rst +1 -1
- poxy/mcss/CREDITS.rst +2 -0
- poxy/mcss/css/m-components.css +1 -1
- poxy/mcss/css/m-debug.css +1 -1
- poxy/mcss/css/m-documentation.css +1 -1
- poxy/mcss/css/m-grid.css +1 -1
- poxy/mcss/css/m-layout.css +1 -1
- poxy/mcss/documentation/__init__.py +1 -1
- poxy/mcss/documentation/_search.py +1 -1
- poxy/mcss/documentation/doxygen.py +202 -25
- poxy/mcss/documentation/python.py +66 -22
- poxy/mcss/documentation/search.js +1 -1
- poxy/mcss/plugins/ansilexer.py +1 -1
- poxy/mcss/plugins/dot2svg.py +1 -1
- poxy/mcss/plugins/latex2svgextra.py +1 -1
- poxy/mcss/plugins/m/__init__.py +1 -1
- poxy/mcss/plugins/m/abbr.py +1 -1
- poxy/mcss/plugins/m/alias.py +1 -1
- poxy/mcss/plugins/m/code.py +4 -5
- poxy/mcss/plugins/m/components.py +1 -1
- poxy/mcss/plugins/m/dot.py +1 -1
- poxy/mcss/plugins/m/dox.py +1 -1
- poxy/mcss/plugins/m/filesize.py +1 -1
- poxy/mcss/plugins/m/gh.py +1 -1
- poxy/mcss/plugins/m/gl.py +1 -1
- poxy/mcss/plugins/m/htmlsanity.py +14 -6
- poxy/mcss/plugins/m/images.py +1 -1
- poxy/mcss/plugins/m/link.py +1 -1
- poxy/mcss/plugins/m/math.py +1 -1
- poxy/mcss/plugins/m/metadata.py +1 -1
- poxy/mcss/plugins/m/plots.py +1 -1
- poxy/mcss/plugins/m/qr.py +1 -1
- poxy/mcss/plugins/m/sphinx.py +1 -1
- poxy/mcss/plugins/m/vk.py +1 -1
- poxy/project.py +25 -5
- poxy/run.py +103 -17
- poxy/version.txt +1 -1
- {poxy-0.18.0.dist-info → poxy-0.19.1.dist-info}/METADATA +182 -170
- {poxy-0.18.0.dist-info → poxy-0.19.1.dist-info}/RECORD +46 -46
- {poxy-0.18.0.dist-info → poxy-0.19.1.dist-info}/WHEEL +1 -1
- {poxy-0.18.0.dist-info → poxy-0.19.1.dist-info}/LICENSE.txt +0 -0
- {poxy-0.18.0.dist-info → poxy-0.19.1.dist-info}/entry_points.txt +0 -0
- {poxy-0.18.0.dist-info → poxy-0.19.1.dist-info}/top_level.txt +0 -0
- {poxy-0.18.0.dist-info → poxy-0.19.1.dist-info}/zip-safe +0 -0
poxy/generated/poxy.css
CHANGED
@@ -3,7 +3,8 @@ This file was automatically generated from multiple sources,
|
|
3
3
|
some of which included stylesheets from mosra/m.css.
|
4
4
|
The license for that project is as follows:
|
5
5
|
|
6
|
-
Copyright © 2017, 2018, 2019, 2020
|
6
|
+
Copyright © 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024
|
7
|
+
Vladimír Vondruš <mosra@centrum.cz> and contributors
|
7
8
|
|
8
9
|
Permission is hereby granted, free of charge, to any person obtaining a
|
9
10
|
copy of this software and associated documentation files (the "Software"),
|
poxy/main.py
CHANGED
@@ -59,7 +59,7 @@ def _invoker(func, **kwargs):
|
|
59
59
|
|
60
60
|
|
61
61
|
def make_boolean_optional_arg(args, name, default, help='', **kwargs):
|
62
|
-
if sys.version_info
|
62
|
+
if sys.version_info >= (3, 9):
|
63
63
|
args.add_argument(rf'--{name}', default=default, help=help, action=argparse.BooleanOptionalAction, **kwargs)
|
64
64
|
else:
|
65
65
|
args.add_argument(rf'--{name}', action=r'store_true', help=help, **kwargs)
|
@@ -329,7 +329,11 @@ def multi_version_git_tags(args: argparse.Namespace):
|
|
329
329
|
|
330
330
|
|
331
331
|
def bug_report(args: argparse.Namespace):
|
332
|
-
bug_report_args = [
|
332
|
+
bug_report_args = [
|
333
|
+
arg
|
334
|
+
for arg in sys.argv[1:]
|
335
|
+
if arg not in (r'--bug-report', r'--worker', r'-v', r'--verbose', r'--keep-original-xml')
|
336
|
+
]
|
333
337
|
for key in (r'--output-dir', r'--temp-dir', r'--copy-config-to'):
|
334
338
|
pos = -1
|
335
339
|
try:
|
@@ -357,6 +361,7 @@ def bug_report(args: argparse.Namespace):
|
|
357
361
|
r'--worker',
|
358
362
|
r'--verbose',
|
359
363
|
r'--nocleanup',
|
364
|
+
r'--keep-original-xml',
|
360
365
|
r'--output-dir',
|
361
366
|
str(paths.BUG_REPORT_DIR),
|
362
367
|
r'--temp-dir',
|
@@ -520,6 +525,7 @@ def main(invoker=True):
|
|
520
525
|
args.add_argument(r'--temp-dir', type=Path, default=None, help=argparse.SUPPRESS) #
|
521
526
|
args.add_argument(r'--copy-config-to', type=Path, default=None, help=argparse.SUPPRESS) #
|
522
527
|
args.add_argument(r'--versions-in-navbar', action=r'store_true', help=argparse.SUPPRESS) #
|
528
|
+
args.add_argument(r'--keep-original-xml', action=r'store_true', help=argparse.SUPPRESS) #
|
523
529
|
args = args.parse_args()
|
524
530
|
|
525
531
|
# --------------------------------------------------------------
|
@@ -632,6 +638,7 @@ def main(invoker=True):
|
|
632
638
|
temp_dir=args.temp_dir,
|
633
639
|
copy_config_to=args.copy_config_to,
|
634
640
|
versions_in_navbar=args.versions_in_navbar,
|
641
|
+
keep_original_xml=args.keep_original_xml,
|
635
642
|
# kwargs:
|
636
643
|
xml_v2=args.xml_v2,
|
637
644
|
)
|
poxy/mcss/CONTRIBUTING.rst
CHANGED
@@ -37,7 +37,7 @@ Code contribution
|
|
37
37
|
/*
|
38
38
|
This file is part of m.css.
|
39
39
|
|
40
|
-
Copyright © 2017, 2018, 2019, 2020, 2021, 2022, 2023
|
40
|
+
Copyright © 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024
|
41
41
|
Vladimír Vondruš <mosra@centrum.cz>
|
42
42
|
Copyright © YEAR YOUR_NAME <your@mail.com>
|
43
43
|
|
poxy/mcss/CREDITS.rst
CHANGED
@@ -30,6 +30,8 @@ Listing only people with code contributions, because otherwise there's too many
|
|
30
30
|
- `@gotchafr <https://github.com/gotchafr>`_ --- Linux-related fixes
|
31
31
|
- Guillaume Jacquemin (`@williamjcm <https://github.com/williamjcm>`_) ---
|
32
32
|
Pelican theme fixes, semantic improvements to the ``m.htmlsanity`` plugin
|
33
|
+
- `John Turner <https://github.com/jturner65>`_ --- docutils compatibility
|
34
|
+
fixes
|
33
35
|
- `@joshyrobot <https://github.com/joshyrobot>`_ --- CSS validity fixes
|
34
36
|
- Lukas Pirl (`@lpirl <https://github.com/lpirl>`_) --- Pelican theme
|
35
37
|
improvements, fixes for Pelican 4.5+ support
|
poxy/mcss/css/m-components.css
CHANGED
poxy/mcss/css/m-debug.css
CHANGED
poxy/mcss/css/m-grid.css
CHANGED
poxy/mcss/css/m-layout.css
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#
|
2
2
|
# This file is part of m.css.
|
3
3
|
#
|
4
|
-
# Copyright © 2017, 2018, 2019, 2020, 2021, 2022, 2023
|
4
|
+
# Copyright © 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024
|
5
5
|
# Vladimír Vondruš <mosra@centrum.cz>
|
6
6
|
#
|
7
7
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#
|
2
2
|
# This file is part of m.css.
|
3
3
|
#
|
4
|
-
# Copyright © 2017, 2018, 2019, 2020, 2021, 2022, 2023
|
4
|
+
# Copyright © 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024
|
5
5
|
# Vladimír Vondruš <mosra@centrum.cz>
|
6
6
|
#
|
7
7
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# This file is part of m.css.
|
5
5
|
#
|
6
|
-
# Copyright © 2017, 2018, 2019, 2020, 2021, 2022, 2023
|
6
|
+
# Copyright © 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024
|
7
7
|
# Vladimír Vondruš <mosra@centrum.cz>
|
8
8
|
# Copyright © 2020 Yuri Edward <nicolas1.fraysse@epitech.eu>
|
9
9
|
# Copyright © 2022 Mark Gillard <mark.gillard@outlook.com.au>
|
@@ -219,10 +219,18 @@ def parse_ref(state: State, element: ET.Element, add_inline_css_class: str = Non
|
|
219
219
|
id = element.attrib['refid']
|
220
220
|
|
221
221
|
if element.attrib['kindref'] == 'compound':
|
222
|
+
# TODO Unlike below, where the filename is dropped if it matches the
|
223
|
+
# current compound URL, here I don't really know what to do because
|
224
|
+
# <a> with empty href="" gets treated as a non-link by browsers.
|
222
225
|
url = id + '.html'
|
223
226
|
elif element.attrib['kindref'] == 'member':
|
224
227
|
i = id.rindex('_1')
|
225
|
-
url = id[:i] + '.html'
|
228
|
+
url = id[:i] + '.html'
|
229
|
+
# There's no point in including the filename itself if linking to an
|
230
|
+
# anchor on the same page.
|
231
|
+
if url == state.current_compound_url:
|
232
|
+
url = ''
|
233
|
+
url += '#' + id[i+2:]
|
226
234
|
else: # pragma: no cover
|
227
235
|
logging.critical("{}: unknown <ref> kind {}".format(state.current, element.attrib['kindref']))
|
228
236
|
assert False
|
@@ -440,7 +448,7 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
|
|
440
448
|
# some silly reason, and then the Markdown is processed as a HTML,
|
441
449
|
# resulting in <blockquote><para><zwj/>. Drop the <zwj/> from there, as
|
442
450
|
# it's useless and messes up with our <para> patching logic.
|
443
|
-
if index == 0 and i.tag == 'zwj' and element.tag == 'para' and immediate_parent and immediate_parent.tag == 'blockquote':
|
451
|
+
if index == 0 and i.tag == 'zwj' and element.tag == 'para' and immediate_parent is not None and immediate_parent.tag == 'blockquote':
|
444
452
|
if i.tail:
|
445
453
|
tail: str = html.escape(i.tail)
|
446
454
|
if trim:
|
@@ -473,7 +481,7 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
|
|
473
481
|
# In a blockquote we need to not count the initial <zwj/> added by
|
474
482
|
# Doxygen 1.9. Otherwise all code blocks alone in a blockquote
|
475
483
|
# would be treated as inline.
|
476
|
-
if element.tag == 'para' and immediate_parent and immediate_parent.tag == 'blockquote':
|
484
|
+
if element.tag == 'para' and immediate_parent is not None and immediate_parent.tag == 'blockquote':
|
477
485
|
element_children_count = 0
|
478
486
|
for listing_index, listing in enumerate(element):
|
479
487
|
if listing_index == 0 and listing.tag == 'zwj': continue
|
@@ -503,7 +511,7 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
|
|
503
511
|
# and begin of a code block by a paragraph even if there is
|
504
512
|
# a blank line. But it does so for xrefitems such as @todo.
|
505
513
|
# I don't even.)
|
506
|
-
((previous_section or (previous_element and previous_element.tag == 'blockquote')) and (not i.tail or not i.tail.strip()) and index + 1 == element_children_count)
|
514
|
+
((previous_section or (previous_element is not None and previous_element.tag == 'blockquote')) and (not i.tail or not i.tail.strip()) and index + 1 == element_children_count)
|
507
515
|
):
|
508
516
|
code_block = True
|
509
517
|
|
@@ -581,7 +589,7 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
|
|
581
589
|
out.parsed = out.parsed.rstrip()
|
582
590
|
if not out.parsed:
|
583
591
|
out.write_paragraph_start_tag = False
|
584
|
-
elif immediate_parent and immediate_parent.tag == 'listitem' and i.tag in ['itemizedlist', 'orderedlist']:
|
592
|
+
elif immediate_parent is not None and immediate_parent.tag == 'listitem' and i.tag in ['itemizedlist', 'orderedlist']:
|
585
593
|
out.write_paragraph_start_tag = False
|
586
594
|
elif out.write_paragraph_close_tag:
|
587
595
|
out.parsed += '</p>'
|
@@ -600,8 +608,9 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
|
|
600
608
|
out.parsed += '<p>'
|
601
609
|
out.write_paragraph_close_tag = True
|
602
610
|
|
603
|
-
# Block elements
|
604
|
-
|
611
|
+
# Block elements. Until Doxygen 1.10 it was at most <sect4>, 1.11 seems
|
612
|
+
# to have up to 6: https://github.com/doxygen/doxygen/issues/11016
|
613
|
+
if i.tag in ['sect1', 'sect2', 'sect3', 'sect4', 'sect5', 'sect6']:
|
605
614
|
assert element.tag != 'para' # should be top-level block element
|
606
615
|
has_block_elements = True
|
607
616
|
|
@@ -640,6 +649,11 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
|
|
640
649
|
tag = 'h4'
|
641
650
|
elif element.tag == 'sect4':
|
642
651
|
tag = 'h5'
|
652
|
+
elif element.tag == 'sect5':
|
653
|
+
tag = 'h6'
|
654
|
+
elif element.tag == 'sect6':
|
655
|
+
tag = 'h6'
|
656
|
+
logging.warning("{}: more than five levels of sections are not supported, stopping at <h6>".format(state.current))
|
643
657
|
elif not element.tag == 'simplesect': # pragma: no cover
|
644
658
|
assert False
|
645
659
|
|
@@ -675,7 +689,11 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
|
|
675
689
|
out.parsed += '<{0} id="{1}">{2}</{0}>'.format(tag, id, title)
|
676
690
|
|
677
691
|
# Apparently, in 1.8.18, <heading> is used for Markdown headers only if
|
678
|
-
# we run out of sect1-4 tags.
|
692
|
+
# we run out of sect1-4 tags. Which also happens when there's a heading
|
693
|
+
# with a ####### underline. In 1.11+ it doesn't produce a <heading>,
|
694
|
+
# and instead just puts the #'s to the output verbatim. Which means we
|
695
|
+
# can't warn for that. See test_contents.SectionsHeadings for repro
|
696
|
+
# cases.
|
679
697
|
elif i.tag == 'heading':
|
680
698
|
assert element.tag == 'para' # is inside a paragraph :/
|
681
699
|
has_block_elements = True
|
@@ -1159,6 +1177,15 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
|
|
1159
1177
|
# Adding a custom CSS class to the immediately following block/inline
|
1160
1178
|
# element
|
1161
1179
|
elif i.tag == '{http://mcss.mosra.cz/doxygen/}class':
|
1180
|
+
# Doxygen may put one or more spaces before, depending on the
|
1181
|
+
# version. Replace them with just one to have consistent output
|
1182
|
+
# across all versions. Have to keep at least one as it's often
|
1183
|
+
# intentional, block elements such as <mcss:div> have both the
|
1184
|
+
# leading and trailing spaces stripped always. Sane is done for
|
1185
|
+
# <mcss:span> below.
|
1186
|
+
if out.parsed.endswith(' '):
|
1187
|
+
out.parsed = out.parsed.rstrip() + ' '
|
1188
|
+
|
1162
1189
|
# Bubble up in case we are alone in a paragraph, as that's meant to
|
1163
1190
|
# affect the next paragraph content.
|
1164
1191
|
if len([listing for listing in element]) == 1:
|
@@ -1401,6 +1428,15 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
|
|
1401
1428
|
# in _document_all_stuff(). In that case the class attribute is not
|
1402
1429
|
# present.
|
1403
1430
|
elif i.tag == '{http://mcss.mosra.cz/doxygen/}span':
|
1431
|
+
# Doxygen may put one or more spaces before, depending on the
|
1432
|
+
# version. Replace them with just one to have consistent output
|
1433
|
+
# across all versions. Have to keep at least one as it's often
|
1434
|
+
# intentional, block elements such as <mcss:div> have both the
|
1435
|
+
# leading and trailing spaces stripped always. Sane is done for
|
1436
|
+
# <mcss:class> above.
|
1437
|
+
if out.parsed.endswith(' '):
|
1438
|
+
out.parsed = out.parsed.rstrip() + ' '
|
1439
|
+
|
1404
1440
|
content = parse_inline_desc(state, i).strip()
|
1405
1441
|
if '{http://mcss.mosra.cz/doxygen/}class' in i.attrib:
|
1406
1442
|
out.parsed += '<span class="{}">{}</span>'.format(i.attrib['{http://mcss.mosra.cz/doxygen/}class'], content)
|
@@ -1698,13 +1734,14 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
|
|
1698
1734
|
# is done by the caller.
|
1699
1735
|
out.parsed += html.escape(i.tail.lstrip())
|
1700
1736
|
|
1701
|
-
# Otherwise strip if requested by the caller
|
1702
|
-
# a
|
1737
|
+
# Otherwise strip if requested by the caller, if this is right after a
|
1738
|
+
# line break or a <mcss:div>, or if <mcss:class> was before (which
|
1739
|
+
# likely had a space before itself as well)
|
1703
1740
|
elif i.tail:
|
1704
1741
|
tail: str = html.escape(i.tail)
|
1705
1742
|
if trim:
|
1706
1743
|
tail = tail.strip()
|
1707
|
-
elif out.parsed.endswith('<br />'):
|
1744
|
+
elif out.parsed.endswith('<br />') or i.tag in ['{http://mcss.mosra.cz/doxygen/}div', '{http://mcss.mosra.cz/doxygen/}class']:
|
1708
1745
|
tail = tail.lstrip()
|
1709
1746
|
out.parsed += tail
|
1710
1747
|
|
@@ -1756,7 +1793,10 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
|
|
1756
1793
|
# In 1.8.18+, if ///> is accidentally used to mark "a docblock for
|
1757
1794
|
# the following symbol", it leads to a <blockquote> contained in
|
1758
1795
|
# the brief. Not much to do except for ignoring the whole thing.
|
1759
|
-
# See the contents_autobrief_blockquote test for details.
|
1796
|
+
# See the contents_autobrief_blockquote test for details. Doesn't
|
1797
|
+
# happen in 1.12 anymore, not sure if that changed due to
|
1798
|
+
# https://github.com/doxygen/doxygen/issues/10902 or something
|
1799
|
+
# else in some earlier version.
|
1760
1800
|
if has_block_elements or paragraph_count > 1:
|
1761
1801
|
logging.warning("{}: ignoring brief description containing multiple paragraphs. Please modify your markup to remove any block elements from the following: {}".format(state.current, out.parsed))
|
1762
1802
|
out.parsed = ''
|
@@ -1860,7 +1900,11 @@ def parse_enum(state: State, element: ET.Element):
|
|
1860
1900
|
state.current_definition_url_base, enum.base_url, enum.id, enum.include, enum.has_details = parse_id_and_include(state, element)
|
1861
1901
|
enum.type = parse_type(state, element.find('type'))
|
1862
1902
|
enum.name = element.find('name').text
|
1863
|
-
|
1903
|
+
# Doxygen < 1.9.7 puts a generated name into the XML, starting with @,
|
1904
|
+
# newer versions strip those away, leading to an empty name
|
1905
|
+
# https://github.com/doxygen/doxygen/commit/a18e4c76ed6415893800c7d77a2f798614fb638b
|
1906
|
+
if not enum.name or enum.name.startswith('@'):
|
1907
|
+
enum.name = '(anonymous)'
|
1864
1908
|
enum.brief = parse_desc(state, element.find('briefdescription'))
|
1865
1909
|
enum.description, search_keywords, search_enum_values_as_keywords, enum.deprecated, enum.since = parse_enum_desc(state, element)
|
1866
1910
|
enum.is_protected = element.attrib['prot'] == 'protected'
|
@@ -2106,6 +2150,15 @@ def parse_func(state: State, element: ET.Element):
|
|
2106
2150
|
else:
|
2107
2151
|
func.is_noexcept = False
|
2108
2152
|
func.is_conditional_noexcept = False
|
2153
|
+
# Noexcept can be also an attribute (since 1.8.16), merge with that. Until
|
2154
|
+
# https://github.com/doxygen/doxygen/commit/b51d6d2dd2cb6a4945a3775a649e7eca8e120515
|
2155
|
+
# (1.11) it seems it was present both in the signature and in the attribs.
|
2156
|
+
if 'noexcept' in element.attrib:
|
2157
|
+
func.is_noexcept = func.is_noexcept or element.attrib['noexcept'] == 'yes'
|
2158
|
+
# noexceptexpression is since 1.11. If not present, it's not conditionally
|
2159
|
+
# noexcept.
|
2160
|
+
if 'noexceptexpression' in element.attrib:
|
2161
|
+
func.is_conditional_noexcept = True
|
2109
2162
|
# Put the rest (const, volatile, ...) into a suffix
|
2110
2163
|
func.suffix = html.escape(signature[signature.rindex(')') + 1:].strip())
|
2111
2164
|
if func.suffix: func.suffix = ' ' + func.suffix
|
@@ -2203,6 +2256,24 @@ def parse_var(state: State, element: ET.Element):
|
|
2203
2256
|
|
2204
2257
|
var = Empty()
|
2205
2258
|
state.current_definition_url_base, var.base_url, var.id, var.include, var.has_details = parse_id_and_include(state, element)
|
2259
|
+
var.type = parse_type(state, element.find('type'))
|
2260
|
+
if var.type.startswith('constexpr'):
|
2261
|
+
var.type = var.type[10:]
|
2262
|
+
var.is_constexpr = True
|
2263
|
+
else:
|
2264
|
+
var.is_constexpr = False
|
2265
|
+
# When 1.8.18 encounters `constexpr static`, it keeps the static there. For
|
2266
|
+
# `static constexpr` it doesn't. In both cases the static="yes" is put
|
2267
|
+
# there correctly. Same case is for functions, although there it's further
|
2268
|
+
# complicated with other possible keyword combinations. Fixed in 1.11.
|
2269
|
+
if var.type.startswith('static'):
|
2270
|
+
var.type = var.type[7:]
|
2271
|
+
# Constexpr can be also an attribute, merge with that. Until
|
2272
|
+
# https://github.com/doxygen/doxygen/commit/b51d6d2dd2cb6a4945a3775a649e7eca8e120515
|
2273
|
+
# (1.11) it seems it was present both in the signature and in the attribs.
|
2274
|
+
if 'constexpr' in element.attrib:
|
2275
|
+
var.is_constexpr = var.is_constexpr or element.attrib['constexpr'] == 'yes'
|
2276
|
+
var.is_static = element.attrib['static'] == 'yes'
|
2206
2277
|
var.is_protected = element.attrib['prot'] == 'protected'
|
2207
2278
|
var.is_private = element.attrib['prot'] == 'private'
|
2208
2279
|
var.name = element.find('name').text
|
@@ -2289,7 +2360,11 @@ def parse_define(state: State, element: ET.Element):
|
|
2289
2360
|
def _document_all_stuff(compounddef: ET.Element):
|
2290
2361
|
for i in compounddef.findall('.//briefdescription/..'):
|
2291
2362
|
brief = i.find('briefdescription')
|
2292
|
-
|
2363
|
+
# ElementTree deprecated the __bool__ conversion of Element, so I now
|
2364
|
+
# have to check that `detaileddescription` actually has any children.
|
2365
|
+
# Checking against None is not enough as it could be present but be
|
2366
|
+
# empty.
|
2367
|
+
if not len(brief) and not len(i.find('detaileddescription')):
|
2293
2368
|
# Add an empty <span> to the paragraph so it doesn't look empty.
|
2294
2369
|
# Can't use strong/emphasis, as those are collapsed if empty as
|
2295
2370
|
# well; on the other hand it's very unlikely that someone would
|
@@ -2366,8 +2441,10 @@ def extract_metadata(state: State, xml):
|
|
2366
2441
|
compound.id = compounddef.attrib['id']
|
2367
2442
|
compound.kind = compounddef.attrib['kind']
|
2368
2443
|
# Compound name is page filename, so we have to use title there. The same
|
2369
|
-
# is for groups.
|
2370
|
-
|
2444
|
+
# is for groups. In some cases, such as anonymous namespaces in Doxygen
|
2445
|
+
# 1.9.7+, <compoundname> is empty. Corresponding test case is in
|
2446
|
+
# test_compound.Ignored. https://github.com/doxygen/doxygen/commit/a18e4c76ed6415893800c7d77a2f798614fb638b
|
2447
|
+
compound.name = html.escape(compounddef.find('title').text if compound.kind in ['page', 'group'] and compounddef.findtext('title') else compounddef.findtext('compoundname'))
|
2371
2448
|
# Compound URL is ID, except for index page, where it is named "indexpage"
|
2372
2449
|
# and so I have to override it back to "index". Can't use <compoundname>
|
2373
2450
|
# for pages because that doesn't reflect CASE_SENSE_NAMES. THANKS DOXYGEN.
|
@@ -2377,7 +2454,11 @@ def extract_metadata(state: State, xml):
|
|
2377
2454
|
# Groups are explicitly created so they *have details*, other
|
2378
2455
|
# things need to have at least some documentation. Pages are treated as
|
2379
2456
|
# having something unless they're stupid. See the function for details.
|
2380
|
-
|
2457
|
+
#
|
2458
|
+
# ElementTree deprecated the __bool__ conversion of Element, so I now have
|
2459
|
+
# to check that `detaileddescription` actually has any children. Checking
|
2460
|
+
# against None is not enough as it could be present but be empty.
|
2461
|
+
compound.has_details = compound.kind == 'group' or compound.brief or len(compounddef.find('detaileddescription')) or (compound.kind == 'page' and not is_a_stupid_empty_markdown_page(compounddef))
|
2381
2462
|
compound.children = []
|
2382
2463
|
|
2383
2464
|
# Version badges, deprecation status. If @since is followed by
|
@@ -2423,7 +2504,18 @@ def extract_metadata(state: State, xml):
|
|
2423
2504
|
for i in compounddef.findall('innerclass'):
|
2424
2505
|
compound.children += [i.attrib['refid']]
|
2425
2506
|
for i in compounddef.findall('innernamespace'):
|
2426
|
-
|
2507
|
+
# Children of inline namespaces get listed also in their parents as
|
2508
|
+
# of 1.9.0 and https://github.com/doxygen/doxygen/commit/4372054e0b7af9c0cd1c1390859d8fef3581d8bb
|
2509
|
+
# So e.g. if Bar is inline, Foo::Bar::Baz gets shortened to
|
2510
|
+
# Foo::Baz, and listed as <innernamespace> of both Foo and
|
2511
|
+
# Foo::Bar. Compare their IDs (because they don't get shortened)
|
2512
|
+
# and add the namespace only if it's a direct descendant. Another
|
2513
|
+
# patching gets done in postprocess_state() below, then the same
|
2514
|
+
# child filtering is done in parse_xml(), and finally the
|
2515
|
+
# duplicates have to be removed in parse_index_xml() as well. See
|
2516
|
+
# test_compound.InlineNamespace for a matching test case.
|
2517
|
+
if i.attrib['refid'].rpartition('_1_1')[0] == compound.id:
|
2518
|
+
compound.children += [i.attrib['refid']]
|
2427
2519
|
for i in compounddef.findall('innerconcept'):
|
2428
2520
|
compound.children += [i.attrib['refid']]
|
2429
2521
|
elif compounddef.attrib['kind'] in ['dir', 'file']:
|
@@ -2453,8 +2545,15 @@ def postprocess_state(state: State):
|
|
2453
2545
|
compound.leaf_name = compound.name
|
2454
2546
|
continue
|
2455
2547
|
|
2548
|
+
# Extract leaf namespace name from symbol name, take just everything
|
2549
|
+
# after the last ::, as the parent names may have intermediate inline
|
2550
|
+
# namespaces removed since 1.9.0 and https://github.com/doxygen/doxygen/commit/4372054e0b7af9c0cd1c1390859d8fef3581d8bb
|
2551
|
+
# The full name is reconstructed in a second step below.
|
2552
|
+
if compound.kind == 'namespace':
|
2553
|
+
compound.leaf_name = compound.name.rpartition('::')[2]
|
2554
|
+
|
2456
2555
|
# Strip parent namespace/class from symbol name
|
2457
|
-
|
2556
|
+
elif compound.kind in ['struct', 'class', 'union', 'concept']:
|
2458
2557
|
prefix = state.compounds[compound.parent].name + '::'
|
2459
2558
|
assert compound.name.startswith(prefix)
|
2460
2559
|
compound.leaf_name = compound.name[len(prefix):]
|
@@ -2471,6 +2570,18 @@ def postprocess_state(state: State):
|
|
2471
2570
|
# Other compounds are not in any index pages or breadcrumb, so leaf
|
2472
2571
|
# name not needed
|
2473
2572
|
|
2573
|
+
# Now that we have leaf names for all namespaces made above, reconstruct
|
2574
|
+
# full names from them. FFS, so much extra code just to undo this crap.
|
2575
|
+
for _, compound in state.compounds.items():
|
2576
|
+
if not compound.kind == 'namespace':
|
2577
|
+
continue
|
2578
|
+
compound.name = compound.leaf_name
|
2579
|
+
parent = compound.parent
|
2580
|
+
while parent:
|
2581
|
+
compound_parent = state.compounds[parent]
|
2582
|
+
compound.name = compound_parent.leaf_name + '::' + compound.name
|
2583
|
+
parent = compound_parent.parent
|
2584
|
+
|
2474
2585
|
# Build reverse header name to ID mapping for #include information, unless
|
2475
2586
|
# it's explicitly disabled. Doxygen doesn't provide full path for files so
|
2476
2587
|
# we need to combine that ourselves. Ugh. (Yes, I know SHOW_INCLUDE_FILES
|
@@ -2628,9 +2739,14 @@ def parse_xml(state: State, xml: str):
|
|
2628
2739
|
|
2629
2740
|
assert len([i for i in root]) == 1
|
2630
2741
|
|
2631
|
-
# Ignoring private structs/classes
|
2742
|
+
# Ignoring private structs/classes and unnamed namespaces
|
2632
2743
|
if ((compounddef.attrib['kind'] in ['struct', 'class', 'union', 'concept'] and 'prot' in compounddef.attrib and compounddef.attrib['prot'] == 'private') or
|
2633
|
-
|
2744
|
+
# Doxygen 1.9.7+ makes <compoundname> empty for anonymous namespaces,
|
2745
|
+
# earlier versions put a generated name with @ there. See
|
2746
|
+
# test_compound.Ignored for a corresponding test case. Similar
|
2747
|
+
# difference is with anonymous enums.
|
2748
|
+
# https://github.com/doxygen/doxygen/commit/a18e4c76ed6415893800c7d77a2f798614fb638b
|
2749
|
+
(compounddef.attrib['kind'] == 'namespace' and (compounddef.find('compoundname').text is None or '@' in compounddef.find('compoundname').text))):
|
2634
2750
|
logging.debug("{}: only private things, skipping".format(state.current))
|
2635
2751
|
return None
|
2636
2752
|
|
@@ -2642,7 +2758,12 @@ def parse_xml(state: State, xml: str):
|
|
2642
2758
|
# Ignoring compounds w/o any description, except for groups,
|
2643
2759
|
# which are created explicitly. Pages are treated as having something
|
2644
2760
|
# unless they're stupid. See the function for details.
|
2645
|
-
|
2761
|
+
#
|
2762
|
+
# ElementTree deprecated the __bool__ conversion of Element, so I now have
|
2763
|
+
# to check that `briefdescription` / `detaileddescription` actually has any
|
2764
|
+
# children. Checking against None is not enough as it could be present but
|
2765
|
+
# be empty.
|
2766
|
+
if not len(compounddef.find('briefdescription')) and not len(compounddef.find('detaileddescription')) and not compounddef.attrib['kind'] == 'group' and (not compounddef.attrib['kind'] == 'page' or is_a_stupid_empty_markdown_page(compounddef)):
|
2646
2767
|
logging.debug("{}: neither brief nor detailed description present, skipping".format(state.current))
|
2647
2768
|
return None
|
2648
2769
|
|
@@ -2852,7 +2973,21 @@ def parse_xml(state: State, xml: str):
|
|
2852
2973
|
namespace.deprecated = symbol.deprecated
|
2853
2974
|
namespace.since = symbol.since
|
2854
2975
|
namespace.is_inline = compounddef_child.attrib.get('inline') == 'yes'
|
2855
|
-
|
2976
|
+
|
2977
|
+
# Children of inline namespaces get listed also in their
|
2978
|
+
# parents as of 1.9.0 and https://github.com/doxygen/doxygen/commit/4372054e0b7af9c0cd1c1390859d8fef3581d8bb
|
2979
|
+
# So e.g. if Bar is inline, Foo::Bar::Baz gets shortened to
|
2980
|
+
# Foo::Baz, and listed as <innernamespace> of both Foo and
|
2981
|
+
# Foo::Bar. Compare their IDs (because they don't get
|
2982
|
+
# shortened) and add the namespace only if it's a direct
|
2983
|
+
# descendant. Same is done in extract_metadata() above. See
|
2984
|
+
# test_compound.InlineNamespace for a matching test case.
|
2985
|
+
#
|
2986
|
+
# Note that file / group compounds can also contain
|
2987
|
+
# <innernamespace>. Those should list all namespaces
|
2988
|
+
# always.
|
2989
|
+
if compound.kind != 'namespace' or compounddef_child.attrib['refid'].rpartition('_1_1')[0] == compound.id:
|
2990
|
+
compound.namespaces += [namespace]
|
2856
2991
|
|
2857
2992
|
else:
|
2858
2993
|
assert compounddef_child.tag in ('innerclass', 'innerconcept')
|
@@ -2959,6 +3094,33 @@ def parse_xml(state: State, xml: str):
|
|
2959
3094
|
|
2960
3095
|
# Other, grouped in sections
|
2961
3096
|
elif compounddef_child.tag == 'sectiondef':
|
3097
|
+
# If grouping is used in the documentation, Doxygen 1.9.7+ no
|
3098
|
+
# longer puts the whole <memberdef> info into file and namespace
|
3099
|
+
# docs, but instead only <member> references, forcing the parsers
|
3100
|
+
# to look for the identifier in other XML files.
|
3101
|
+
#
|
3102
|
+
# The reason for this, as discussed in the linked PR, is because
|
3103
|
+
# some random downstream project failed due to encountering
|
3104
|
+
# duplicate IDs (which are there for file/namespace members also,
|
3105
|
+
# by the way! or for relatedalso members!!). And Doxygen maintainer
|
3106
|
+
# VERY HELPFULLY OFFERED TO CRIPPLE THE XML OUTPUT FOR EVERYONE
|
3107
|
+
# ELSE just to fix that damn thing. Once I calm down I may try to
|
3108
|
+
# convince them to revert this insanity, until then enjoy the
|
3109
|
+
# crappy output.
|
3110
|
+
#
|
3111
|
+
# Also, yes, it may happen that there are combined <memberdef> and
|
3112
|
+
# <member> children. But handling that means adding the same damn
|
3113
|
+
# piece of code, or some dumb filtering, to all branches below,
|
3114
|
+
# just to counter a dumb decision. Nope. Nononono.
|
3115
|
+
is_stupid = False
|
3116
|
+
for memberdef in compounddef_child:
|
3117
|
+
if memberdef.tag == 'member':
|
3118
|
+
logging.warning("{}: sorry, parsing of non-self-contained XML not implemented: due to https://github.com/doxygen/doxygen/issues/8790 the output will not list file / namespace {} members".format(state.current, compounddef_child.attrib['kind']))
|
3119
|
+
is_stupid = True
|
3120
|
+
break
|
3121
|
+
if is_stupid:
|
3122
|
+
continue
|
3123
|
+
|
2962
3124
|
if compounddef_child.attrib['kind'] == 'enum':
|
2963
3125
|
for memberdef in compounddef_child:
|
2964
3126
|
enum = parse_enum(state, memberdef)
|
@@ -3376,8 +3538,12 @@ def parse_xml(state: State, xml: str):
|
|
3376
3538
|
entry.include = None
|
3377
3539
|
|
3378
3540
|
# Add the compound to search data, if it's documented
|
3541
|
+
#
|
3542
|
+
# ElementTree deprecated the __bool__ conversion of Element, so I now have
|
3543
|
+
# to check that `detaileddescription` actually has any children. Checking
|
3544
|
+
# against None is not enough as it could be present but be empty.
|
3379
3545
|
# TODO: add example sources there? how?
|
3380
|
-
if not state.config['SEARCH_DISABLED'] and not compound.kind == 'example' and (compound.kind == 'group' or compound.brief or compounddef.find('detaileddescription')):
|
3546
|
+
if not state.config['SEARCH_DISABLED'] and not compound.kind == 'example' and (compound.kind == 'group' or compound.brief or len(compounddef.find('detaileddescription'))):
|
3381
3547
|
if compound.kind == 'namespace':
|
3382
3548
|
kind = EntryType.NAMESPACE
|
3383
3549
|
elif compound.kind == 'struct':
|
@@ -3460,6 +3626,17 @@ def parse_index_xml(state: State, xml):
|
|
3460
3626
|
entry.has_concept_descendents = compound.kind == 'concept'
|
3461
3627
|
if compound.kind == 'namespace':
|
3462
3628
|
entry.is_inline = compound.is_inline
|
3629
|
+
|
3630
|
+
# As of 1.9.0 and https://github.com/doxygen/doxygen/commit/4372054e0b7af9c0cd1c1390859d8fef3581d8bb
|
3631
|
+
# children of inline namespaces are listed twice in index.xml, once
|
3632
|
+
# with their full name, and once with the intermediate inline
|
3633
|
+
# namespaces removed. Keep just the ones with full names, i.e.
|
3634
|
+
# where the name matches what was painstakingly reconstructed
|
3635
|
+
# in postprocess_state() before. I hate this fucking tool of a
|
3636
|
+
# tool.
|
3637
|
+
if compound.name != i.findtext('name'):
|
3638
|
+
continue
|
3639
|
+
|
3463
3640
|
if compound.kind in ['class', 'struct', 'union']:
|
3464
3641
|
entry.is_final = compound.is_final
|
3465
3642
|
|