From: Vladimír Vondruš Date: Sat, 16 Nov 2019 22:45:14 +0000 (+0100) Subject: documentation/doxygen: support \since as labels in entry lists. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~cjwatson/git?a=commitdiff_plain;h=a56227e89de90d0ea5751d0ebfa96734a5e55b96;p=blog.git documentation/doxygen: support \since as labels in entry lists. Makes everything much easier to discover. Since I'm by far no longer the only user, I have a fear of breaking things, so this is completely opt-in. Also recognizes a combination of \since and \deprecated as "a version in which given API got deprecated", expanding the red deprecated label with a custom text. --- diff --git a/doc/documentation/doxygen.rst b/doc/documentation/doxygen.rst index 9388c3e8..621abd9e 100644 --- a/doc/documentation/doxygen.rst +++ b/doc/documentation/doxygen.rst @@ -389,6 +389,10 @@ Variable Description search is offered. See `Search options`_ for more information. Has effect only if :ini:`M_SEARCH_DISABLED` is not ``YES``. +:ini:`M_VERSION_LABELS` Show the ``@since`` annotation as labels + visible in entry listing and detailed docs. + Defaults to ``NO``, see `Version labels`_ + for more information. :ini:`M_SHOW_UNDOCUMENTED` Include undocumented symbols, files and directories in the output. If not set, ``NO`` is used. See `Showing undocumented symbols and files`_ @@ -1187,6 +1191,52 @@ suffix of the title. */ template lerp(const T& x, const T& y, float a); +`Version labels`_ +----------------- + +By default, to keep compatibility with existing content, the ``@since`` block +is rendered as a note directly in the text flow. If you enable the +:ini:`M_SINCE_BADGES` option, content of the ``@since`` block is expected to be +a single label that can optionally link to a changelog entry. The label is then +placed visibly next to given entry and detailed description as well as all +listings. Additionally, if ``@since`` is followed by ``@deprecated``, it adds +version info to the deprecation notice (instead of denoting when given feature +was added) --- in this case it expects just a textual info, without any label +styling. Recommended use is in combination with an alias that takes care of the +label rendering and For example (the ``@m_class`` is the same as described in +`Theme-specific commands`_ above): + +.. code:: ini + + M_VERSION_LABELS = YES + ALIASES = \ + "m_class{1}=@xmlonly@endxmlonly" \ + "m_since{2}=@since @m_class{m-label m-success m-flat} @ref changelog-\1-\2 \"since v\1.\2\"" \ + "m_deprecated_since{2}=@since deprecated in v\1.\2 @deprecated" + +With the above configuration, the following markup will render a +:label-flat-success:`since v1.3` label leading to a page named ``changelog-1-3`` +next to both function entry and detailed docs in the first case, and a +:label-danger:`deprecated since v1.3` label in the second case: + +.. code:: c++ + + /** + @brief Fast inverse square root + @m_since{1,3} + + Faster than `1.0f/sqrt(a)`. + */ + float fastinvsqrt(float a); + + /** + @brief Slow inverse square root + + Attempts to figure out the value by a binary search. + @m_deprecated_since{1,3} Use @ref fastinvsqrt() instead. + */ + float slowinvsqrt(float a); + `Command-line options`_ ======================= @@ -1471,7 +1521,9 @@ Property Description :py:`compound.brief` Brief description. Can be empty. [1]_ :py:`compound.is_final` Whether the class is :cpp:`final`. Set only for classes. -:py:`compound.is_deprecated` Whether the compound is deprecated. [7]_ +:py:`compound.deprecated` Deprecation status [7]_ +:py:`compound.since` Since which version the compound is + available [8]_ :py:`compound.description` Detailed description. Can be empty. [2]_ :py:`compound.modules` List of submodules in this compound. Set only for modules. See @@ -1632,7 +1684,8 @@ Property Description :py:`module.url` URL of the file containing detailed module docs :py:`module.name` Module name (just the leaf) :py:`module.brief` Brief description. Can be empty. [1]_ -:py:`module.is_deprecated` Whether the module is deprecated. [7]_ +:py:`module.deprecated` Deprecation status [7]_ +:py:`module.since` Since which version the module is available [8]_ =========================== =================================================== `Directory properties`_ @@ -1649,7 +1702,8 @@ Property Description :py:`dir.url` URL of the file containing detailed directory docs :py:`dir.name` Directory name (just the leaf) :py:`dir.brief` Brief description. Can be empty. [1]_ -:py:`dir.is_deprecated` Whether the directory is deprecated. [7]_ +:py:`dir.deprecated` Deprecation status [7]_ +:py:`dir.since` Since which version the directory is available [8]_ =========================== =================================================== `File properties`_ @@ -1666,7 +1720,8 @@ Property Description :py:`file.url` URL of the file containing detailed file docs :py:`file.name` File name (just the leaf) :py:`file.brief` Brief description. Can be empty. [1]_ -:py:`file.is_deprecated` Whether the file is deprecated. [7]_ +:py:`file.deprecated` Deprecation status [7]_ +:py:`file.since` Since which version the file is available [8]_ =========================== =================================================== `Namespace properties`_ @@ -1686,7 +1741,9 @@ Property Description a file documentation, just the leaf name if in a namespace documentation. :py:`namespace.brief` Brief description. Can be empty. [1]_ -:py:`namespace.is_deprecated` Whether the namespace is deprecated. [7]_ +:py:`namespace.deprecated` Deprecation status [7]_ +:py:`namespace.since` Since which version the namespace is available + [8]_ =============================== =============================================== `Class properties`_ @@ -1708,7 +1765,8 @@ Property Description :py:`class.templates` Template specification. See `Template properties`_ for details. :py:`class.brief` Brief description. Can be empty. [1]_ -:py:`class.is_deprecated` Whether the class is deprecated. [7]_ +:py:`class.deprecated` Deprecation status [7]_ +:py:`class.since` Since which version the class is available [8]_ :py:`class.is_protected` Whether this is a protected base class. Set only for base classes. :py:`class.is_virtual` Whether this is a virtual base class or a @@ -1744,7 +1802,8 @@ Property Description :py:`enum.description` Detailed description. Can be empty. [2]_ :py:`enum.has_details` If there is enough content for the full description block [5]_ -:py:`enum.is_deprecated` Whether the enum is deprecated. [7]_ +:py:`enum.deprecated` Deprecation status [7]_ +:py:`enum.since` Since which version the enum is available [8]_ :py:`enum.is_protected` If the enum is :cpp:`protected`. Set only for member types. :py:`enum.values` List of enum values @@ -1763,7 +1822,8 @@ Property Description :py:`value.id` Identifier hash [3]_ :py:`value.name` Value name [4]_ :py:`value.initializer` Value initializer. Can be empty. [1]_ -:py:`value.is_deprecated` Whether the value is deprecated. [7]_ +:py:`value.deprecated` Deprecation status [7]_ +:py:`value.since` Since which version the value is available [8]_ :py:`value.brief` Brief description. Can be empty. [1]_ :py:`value.description` Detailed description. Can be empty. [2]_ =========================== =================================================== @@ -1800,7 +1860,9 @@ Property Description for details. :py:`typedef.has_template_details` If template parameters have description :py:`typedef.brief` Brief description. Can be empty. [1]_ -:py:`typedef.is_deprecated` Whether the typedef is deprecated. [7]_ +:py:`typedef.deprecated` Deprecation status [7]_ +:py:`typedef.since` Since which version the typedef is + available [8]_ :py:`typedef.description` Detailed description. Can be empty. [2]_ :py:`typedef.has_details` If there is enough content for the full description block [4]_ @@ -1863,7 +1925,9 @@ Property Description and :cpp:`delete`\ d / :cpp:`default`\ ed functions is removed from the suffix and available via other properties. -:py:`func.is_deprecated` Whether the function is deprecated. [7]_ +:py:`func.deprecated` Deprecation status [7]_ +:py:`func.since` Since which version the function is + available [8]_ :py:`func.is_protected` If the function is :cpp:`protected`. Set only for member functions. :py:`func.is_private` If the function is :cpp:`private`. Set only @@ -1948,7 +2012,9 @@ Property Description :py:`var.description` Detailed description. Can be empty. [2]_ :py:`var.has_details` If there is enough content for the full description block [5]_ -:py:`var.is_deprecated` Whether the variable is deprecated. [7]_ +:py:`var.deprecated` Deprecation status [7]_ +:py:`var.since` Since which version the variable is available + [8]_ :py:`var.is_static` If the variable is :cpp:`static`. Set only for member variables. :py:`var.is_protected` If the variable is :cpp:`protected`. Set only @@ -1981,7 +2047,9 @@ Property Description :py:`define.return_value` Return value description. Can be empty. :py:`define.brief` Brief description. Can be empty. [1]_ :py:`define.description` Detailed description. Can be empty. [2]_ -:py:`define.is_deprecated` Whether the define is deprecated. [7]_ +:py:`define.deprecated` Deprecation status [7]_ +:py:`define.since` Since which version the define is available + [8]_ :py:`define.has_details` If there is enough content for the full description block [5]_ =============================== =============================================== @@ -2107,7 +2175,8 @@ Property Description :py:`i.name` Name :py:`i.url` URL of the file with detailed documentation :py:`i.brief` Brief documentation -:py:`i.is_deprecated` Whether the entry is deprecated. [7]_ +:py:`i.deprecated` Deprecation status [7]_ +:py:`i.since` Since which version the entry is available [8]_ :py:`i.is_final` Whether the class is :cpp:`final`. Set only for classes. :py:`i.has_nestable_children` If the list has nestable children (i.e., dirs @@ -2140,5 +2209,8 @@ all directories are before all files. :py:`compound.url`, its :py:`i.has_details` is always set to :py:`False`. .. [6] :py:`i.type` and :py:`param.default` is rendered as HTML and usually contains links to related documentation -.. [7] :py:`i.is_deprecated` is set to :py:`True` if detailed docs of given - symbol contain the ``@deprecated`` command and to :py:`False` otherwise +.. [7] :py:`i.deprecated` is set to a string containing the deprecation + status if detailed docs of given symbol contain the ``@deprecated`` command and to :py:`None` otherwise. See also `Version labels`_ for more + information. +.. [8] :py:`i.status` HTML code with a label or :py:`None`. See + `Version labels`_ for more information. diff --git a/documentation/doxygen.py b/documentation/doxygen.py index 6d4e4d54..cb12de00 100755 --- a/documentation/doxygen.py +++ b/documentation/doxygen.py @@ -103,7 +103,7 @@ class StateCompound: self.url: str self.brief: str self.has_details: bool - self.is_deprecated: bool + self.deprecated: str self.is_final: bool = None self.children: List[str] self.parent: str = None @@ -301,7 +301,8 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET. out.example_navigation = None out.search_keywords = [] out.search_enum_values_as_keywords = False - out.is_deprecated = False + out.deprecated = None + out.since = None # DOXYGEN PATCHING 1/4 # @@ -356,6 +357,11 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET. out.return_values += parsed.return_values if parsed.exceptions: out.exceptions += parsed.exceptions + if parsed.since: + out.since = parsed.since + if parsed.deprecated: + assert not out.since + out.deprecated = parsed.deprecated i: ET.Element for index, i in enumerate(element): @@ -659,7 +665,6 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET. if parsed.example_navigation: out.example_navigation = parsed.example_navigation out.search_keywords += parsed.search_keywords if parsed.search_enum_values_as_keywords: out.search_enum_values_as_keywords = True - if parsed.is_deprecated: out.is_deprecated = True # Assert we didn't miss anything important assert not parsed.section @@ -742,6 +747,14 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET. logging.warning("{}: superfluous @return section found, ignoring: {} ".format(state.current, ''.join(i.itertext()))) else: out.return_value = parse_desc(state, i) + + # Content of @since tags is put as-is into entry description / + # details, if enabled. + elif i.attrib['kind'] == 'since' and state.doxyfile['M_VERSION_LABELS']: + since = parse_inline_desc(state, i).strip() + assert since.startswith('

') and since.endswith('

') + out.since = since[3:-4] + else: has_block_elements = True @@ -848,15 +861,24 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET. id = i.attrib['id'] match = xref_id_rx.match(id) file = match.group(1) + title = i.find('xreftitle').text if add_css_class: css_class = add_css_class heading = 'h3' else: heading = 'h4' css_class = 'm-note ' + # If we have version info from a previous Since badge, use it + # instead of the title if file.startswith('deprecated'): css_class += 'm-danger' - out.is_deprecated = True + if out.since: + out.deprecated = out.since + title = out.since.capitalize() + out.since = None + else: + out.deprecated = 'deprecated' + title = 'Deprecated' elif file.startswith('bug'): css_class += 'm-danger' elif file.startswith('todo'): @@ -868,7 +890,7 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET. heading=heading, file=file, anchor=match.group(2), - title=i.find('xreftitle').text, + title=title, description=parse_desc(state, i.find('xrefdescription'))) elif i.tag == 'parameterlist': @@ -1624,14 +1646,14 @@ def parse_enum_desc(state: State, element: ET.Element) -> Tuple[str, List[Tuple[ if parsed.templates or parsed.params or parsed.return_value or parsed.return_values or parsed.exceptions: logging.warning("{}: unexpected @tparam / @param / @return / @retval / @exception found in enum description, ignoring".format(state.current)) assert not parsed.section # might be problematic - return parsed.parsed, parsed.search_keywords, parsed.search_enum_values_as_keywords, parsed.is_deprecated + return parsed.parsed, parsed.search_keywords, parsed.search_enum_values_as_keywords, parsed.deprecated, parsed.since def parse_enum_value_desc(state: State, element: ET.Element) -> Tuple[str, List[Tuple[str, str, int]], bool]: parsed = parse_desc_internal(state, element.find('detaileddescription')) if parsed.templates or parsed.params or parsed.return_value or parsed.return_values or parsed.exceptions: logging.warning("{}: unexpected @tparam / @param / @return / @retval / @exception found in enum value description, ignoring".format(state.current)) assert not parsed.section # might be problematic - return parsed.parsed, parsed.search_keywords, parsed.is_deprecated + return parsed.parsed, parsed.search_keywords, parsed.deprecated, parsed.since def parse_var_desc(state: State, element: ET.Element) -> Tuple[str, List[Any], List[Tuple[str, str, int]], bool]: parsed = parse_desc_internal(state, element.find('detaileddescription')) @@ -1639,7 +1661,7 @@ def parse_var_desc(state: State, element: ET.Element) -> Tuple[str, List[Any], L if parsed.params or parsed.return_value or parsed.return_values or parsed.exceptions: logging.warning("{}: unexpected @param / @return / @retval / @exception found in variable description, ignoring".format(state.current)) assert not parsed.section # might be problematic - return parsed.parsed, parsed.templates, parsed.search_keywords, parsed.is_deprecated + return parsed.parsed, parsed.templates, parsed.search_keywords, parsed.deprecated, parsed.since def parse_toplevel_desc(state: State, element: ET.Element) -> Tuple[str, List[Any], str, Any, Any, List[Tuple[str, str, int]], bool]: state.parsing_toplevel_desc = True @@ -1647,7 +1669,7 @@ def parse_toplevel_desc(state: State, element: ET.Element) -> Tuple[str, List[An state.parsing_toplevel_desc = False if parsed.params or parsed.return_value or parsed.return_values or parsed.exceptions: logging.warning("{}: unexpected @param / @return / @retval / @exception found in top-level description, ignoring".format(state.current)) - return parsed.parsed, parsed.templates, parsed.section[2] if parsed.section else '', parsed.footer_navigation, parsed.example_navigation, parsed.search_keywords, parsed.is_deprecated + return parsed.parsed, parsed.templates, parsed.section[2] if parsed.section else '', parsed.footer_navigation, parsed.example_navigation, parsed.search_keywords, parsed.deprecated, parsed.since def parse_typedef_desc(state: State, element: ET.Element) -> Tuple[str, List[Any], List[Tuple[str, str, int]], bool]: parsed = parse_desc_internal(state, element.find('detaileddescription')) @@ -1655,13 +1677,13 @@ def parse_typedef_desc(state: State, element: ET.Element) -> Tuple[str, List[Any if parsed.params or parsed.return_value or parsed.return_values or parsed.exceptions: logging.warning("{}: unexpected @param / @return / @retval / @exception found in typedef description, ignoring".format(state.current)) assert not parsed.section # might be problematic - return parsed.parsed, parsed.templates, parsed.search_keywords, parsed.is_deprecated + return parsed.parsed, parsed.templates, parsed.search_keywords, parsed.deprecated, parsed.since def parse_func_desc(state: State, element: ET.Element) -> Tuple[str, List[Any], List[Any], str, List[Any], List[Any], List[Tuple[str, str, int]], bool]: parsed = parse_desc_internal(state, element.find('detaileddescription')) parsed.parsed += parse_desc(state, element.find('inbodydescription')) assert not parsed.section # might be problematic - return parsed.parsed, parsed.templates, parsed.params, parsed.return_value, parsed.return_values, parsed.exceptions, parsed.search_keywords, parsed.is_deprecated + return parsed.parsed, parsed.templates, parsed.params, parsed.return_value, parsed.return_values, parsed.exceptions, parsed.search_keywords, parsed.deprecated, parsed.since def parse_define_desc(state: State, element: ET.Element) -> Tuple[str, List[Any], str, List[Tuple[str, str, int]], bool]: parsed = parse_desc_internal(state, element.find('detaileddescription')) @@ -1669,7 +1691,7 @@ def parse_define_desc(state: State, element: ET.Element) -> Tuple[str, List[Any] if parsed.templates or parsed.return_values or parsed.exceptions: logging.warning("{}: unexpected @tparam / @retval / @exception found in macro description, ignoring".format(state.current)) assert not parsed.section # might be problematic - return parsed.parsed, parsed.params, parsed.return_value, parsed.search_keywords, parsed.is_deprecated + return parsed.parsed, parsed.params, parsed.return_value, parsed.search_keywords, parsed.deprecated, parsed.since def parse_inline_desc(state: State, element: ET.Element) -> str: if element is None: return '' @@ -1689,7 +1711,7 @@ def parse_enum(state: State, element: ET.Element): enum.name = element.find('name').text if enum.name.startswith('@'): enum.name = '(anonymous)' enum.brief = parse_desc(state, element.find('briefdescription')) - enum.description, search_keywords, search_enum_values_as_keywords, enum.is_deprecated = parse_enum_desc(state, element) + enum.description, search_keywords, search_enum_values_as_keywords, enum.deprecated, enum.since = parse_enum_desc(state, element) enum.is_protected = element.attrib['prot'] == 'protected' enum.is_strong = False if 'strong' in element.attrib: @@ -1707,11 +1729,11 @@ def parse_enum(state: State, element: ET.Element): # There can be an implicit initializer for enum value value.initializer = html.escape(enumvalue.findtext('initializer', '')) value.brief = parse_desc(state, enumvalue.find('briefdescription')) - value.description, value_search_keywords, value.is_deprecated = parse_enum_value_desc(state, enumvalue) + value.description, value_search_keywords, value.deprecated, value.since = parse_enum_value_desc(state, enumvalue) if value.brief or value.description: if enum.base_url == state.current_compound_url and not state.doxyfile['M_SEARCH_DISABLED']: result = Empty() - result.flags = ResultFlag.from_type(ResultFlag.DEPRECATED if value.is_deprecated else ResultFlag(0), EntryType.ENUM_VALUE) + result.flags = ResultFlag.from_type(ResultFlag.DEPRECATED if value.deprecated else ResultFlag(0), EntryType.ENUM_VALUE) result.url = enum.base_url + '#' + value.id result.prefix = state.current_prefix + [enum.name] result.name = value.name @@ -1736,7 +1758,7 @@ def parse_enum(state: State, element: ET.Element): if enum.brief or enum.has_details or enum.has_value_details: if enum.base_url == state.current_compound_url and not state.doxyfile['M_SEARCH_DISABLED']: result = Empty() - result.flags = ResultFlag.from_type(ResultFlag.DEPRECATED if enum.is_deprecated else ResultFlag(0), EntryType.ENUM) + result.flags = ResultFlag.from_type(ResultFlag.DEPRECATED if enum.deprecated else ResultFlag(0), EntryType.ENUM) result.url = enum.base_url + '#' + enum.id result.prefix = state.current_prefix result.name = enum.name @@ -1802,7 +1824,7 @@ def parse_typedef(state: State, element: ET.Element): typedef.args = parse_type(state, element.find('argsstring')) typedef.name = element.find('name').text typedef.brief = parse_desc(state, element.find('briefdescription')) - typedef.description, templates, search_keywords, typedef.is_deprecated = parse_typedef_desc(state, element) + typedef.description, templates, search_keywords, typedef.deprecated, typedef.since = parse_typedef_desc(state, element) typedef.is_protected = element.attrib['prot'] == 'protected' typedef.has_template_details, typedef.templates = parse_template_params(state, element.find('templateparamlist'), templates) @@ -1812,7 +1834,7 @@ def parse_typedef(state: State, element: ET.Element): # Avoid duplicates in search if typedef.base_url == state.current_compound_url and not state.doxyfile['M_SEARCH_DISABLED']: result = Empty() - result.flags = ResultFlag.from_type(ResultFlag.DEPRECATED if typedef.is_deprecated else ResultFlag(0), EntryType.TYPEDEF) + result.flags = ResultFlag.from_type(ResultFlag.DEPRECATED if typedef.deprecated else ResultFlag(0), EntryType.TYPEDEF) result.url = typedef.base_url + '#' + typedef.id result.prefix = state.current_prefix result.name = typedef.name @@ -1829,7 +1851,7 @@ def parse_func(state: State, element: ET.Element): func.type = parse_type(state, element.find('type')) func.name = fix_type_spacing(html.escape(element.find('name').text)) func.brief = parse_desc(state, element.find('briefdescription')) - func.description, templates, params, func.return_value, func.return_values, func.exceptions, search_keywords, func.is_deprecated = parse_func_desc(state, element) + func.description, templates, params, func.return_value, func.return_values, func.exceptions, search_keywords, func.deprecated, func.since = parse_func_desc(state, element) # Friend functions have friend as type. That's just awful. COME ON. if func.type.startswith('friend '): @@ -1957,7 +1979,7 @@ def parse_func(state: State, element: ET.Element): # Avoid duplicates in search if func.base_url == state.current_compound_url and not state.doxyfile['M_SEARCH_DISABLED']: result = Empty() - result.flags = ResultFlag.from_type((ResultFlag.DEPRECATED if func.is_deprecated else ResultFlag(0))|(ResultFlag.DELETED if func.is_deleted else ResultFlag(0)), EntryType.FUNC) + result.flags = ResultFlag.from_type((ResultFlag.DEPRECATED if func.deprecated else ResultFlag(0))|(ResultFlag.DELETED if func.is_deleted else ResultFlag(0)), EntryType.FUNC) result.url = func.base_url + '#' + func.id result.prefix = state.current_prefix result.name = func.name @@ -1984,7 +2006,7 @@ def parse_var(state: State, element: ET.Element): var.is_private = element.attrib['prot'] == 'private' var.name = element.find('name').text var.brief = parse_desc(state, element.find('briefdescription')) - var.description, templates, search_keywords, var.is_deprecated = parse_var_desc(state, element) + var.description, templates, search_keywords, var.deprecated, var.since = parse_var_desc(state, element) var.has_template_details, var.templates = parse_template_params(state, element.find('templateparamlist'), templates) if var.base_url == state.current_compound_url and (var.description or var.has_template_details): @@ -1993,7 +2015,7 @@ def parse_var(state: State, element: ET.Element): # Avoid duplicates in search if var.base_url == state.current_compound_url and not state.doxyfile['M_SEARCH_DISABLED']: result = Empty() - result.flags = ResultFlag.from_type(ResultFlag.DEPRECATED if var.is_deprecated else ResultFlag(0), EntryType.VAR) + result.flags = ResultFlag.from_type(ResultFlag.DEPRECATED if var.deprecated else ResultFlag(0), EntryType.VAR) result.url = var.base_url + '#' + var.id result.prefix = state.current_prefix result.name = var.name @@ -2009,7 +2031,7 @@ def parse_define(state: State, element: ET.Element): state.current_definition_url_base, define.base_url, define.id, define.include, define.has_details = parse_id_and_include(state, element) define.name = element.find('name').text define.brief = parse_desc(state, element.find('briefdescription')) - define.description, params, define.return_value, search_keywords, define.is_deprecated = parse_define_desc(state, element) + define.description, params, define.return_value, search_keywords, define.deprecated, define.since = parse_define_desc(state, element) define.has_param_details = False define.params = None for p in element.findall('param'): @@ -2033,7 +2055,7 @@ def parse_define(state: State, element: ET.Element): # Avoid duplicates in search if define.base_url == state.current_compound_url and not state.doxyfile['M_SEARCH_DISABLED']: result = Empty() - result.flags = ResultFlag.from_type(ResultFlag.DEPRECATED if define.is_deprecated else ResultFlag(0), EntryType.DEFINE) + result.flags = ResultFlag.from_type(ResultFlag.DEPRECATED if define.deprecated else ResultFlag(0), EntryType.DEFINE) result.url = define.base_url + '#' + define.id result.prefix = [] result.name = define.name @@ -2120,14 +2142,26 @@ def extract_metadata(state: State, xml): compound.has_details = compound.kind == 'group' or compound.brief or compounddef.find('detaileddescription') or (compound.kind == 'page' and not is_a_stupid_empty_markdown_page(compounddef)) compound.children = [] - # Deprecation status - compound.is_deprecated = False + # Version badges, deprecation status. If @since is followed by + # @deprecated, treat it as version in which given feature was deprecated + compound.deprecated = None + compound.since = None + if state.doxyfile['M_VERSION_LABELS']: + for i in compounddef.find('detaileddescription').findall('.//simplesect'): + if i.attrib['kind'] != 'since': continue + since = parse_inline_desc(state, i).strip() + assert since.startswith('

') and since.endswith('

') + compound.since = since[3:-4] for i in compounddef.find('detaileddescription').findall('.//xrefsect'): id = i.attrib['id'] match = xref_id_rx.match(id) file = match.group(1) if file.startswith('deprecated'): - compound.is_deprecated = True + if compound.since: + compound.deprecated = compound.since + compound.since = None + else: + compound.deprecated = 'deprecated' break # Final classes @@ -2429,7 +2463,7 @@ def parse_xml(state: State, xml: str): compound.has_template_details = False compound.templates = None compound.brief = parse_desc(state, compounddef.find('briefdescription')) - compound.description, templates, compound.sections, footer_navigation, example_navigation, search_keywords, compound.is_deprecated = parse_toplevel_desc(state, compounddef.find('detaileddescription')) + compound.description, templates, compound.sections, footer_navigation, example_navigation, search_keywords, compound.deprecated, compound.since = parse_toplevel_desc(state, compounddef.find('detaileddescription')) compound.example_navigation = None compound.footer_navigation = None compound.modules = [] @@ -2583,7 +2617,8 @@ def parse_xml(state: State, xml: str): f.url = file.url f.name = file.leaf_name f.brief = file.brief - f.is_deprecated = file.is_deprecated + f.deprecated = file.deprecated + f.since = file.since if compounddef_child.tag == 'innerdir': compound.dirs += [f] @@ -2604,7 +2639,8 @@ def parse_xml(state: State, xml: str): namespace.url = symbol.url namespace.name = symbol.leaf_name if compound.kind == 'namespace' else symbol.name namespace.brief = symbol.brief - namespace.is_deprecated = symbol.is_deprecated + namespace.deprecated = symbol.deprecated + namespace.since = symbol.since compound.namespaces += [namespace] else: @@ -2615,7 +2651,8 @@ def parse_xml(state: State, xml: str): class_.url = symbol.url class_.name = symbol.leaf_name if compound.kind in ['namespace', 'class', 'struct', 'union'] else symbol.name class_.brief = symbol.brief - class_.is_deprecated = symbol.is_deprecated + class_.deprecated = symbol.deprecated + class_.since = symbol.since class_.templates = symbol.templates # Put classes into the public/protected section for @@ -2647,7 +2684,8 @@ def parse_xml(state: State, xml: str): class_.name = symbol.leaf_name if state.compounds[compound.id].parent and symbol.parent and symbol.parent.startswith(state.compounds[compound.id].parent) else symbol.name class_.brief = symbol.brief class_.templates = symbol.templates - class_.is_deprecated = symbol.is_deprecated + class_.deprecated = symbol.deprecated + class_.since = symbol.since class_.is_protected = compounddef_child.attrib['prot'] == 'protected' class_.is_virtual = compounddef_child.attrib['virt'] == 'virtual' @@ -2670,7 +2708,8 @@ def parse_xml(state: State, xml: str): class_.name = symbol.leaf_name if state.compounds[compound.id].parent and symbol.parent and symbol.parent.startswith(state.compounds[compound.id].parent) else symbol.name class_.brief = symbol.brief class_.templates = symbol.templates - class_.is_deprecated = symbol.is_deprecated + class_.deprecated = symbol.deprecated + class_.since = symbol.since class_.is_virtual = compounddef_child.attrib['virt'] == 'virtual' class_.is_final = symbol.is_final @@ -2685,7 +2724,8 @@ def parse_xml(state: State, xml: str): g.url = group.url g.name = group.leaf_name g.brief = group.brief - g.is_deprecated = group.is_deprecated + g.deprecated = group.deprecated + g.since = group.since compound.modules += [g] # Other, grouped in sections @@ -3125,7 +3165,7 @@ def parse_xml(state: State, xml: str): else: assert False # pragma: no cover result = Empty() - result.flags = ResultFlag.from_type(ResultFlag.DEPRECATED if compound.is_deprecated else ResultFlag(0), kind) + result.flags = ResultFlag.from_type(ResultFlag.DEPRECATED if compound.deprecated else ResultFlag(0), kind) result.url = compound.url result.prefix = state.current_prefix[:-1] result.name = state.current_prefix[-1] @@ -3178,7 +3218,8 @@ def parse_index_xml(state: State, xml): entry.url = compound.url entry.brief = compound.brief entry.children = [] - entry.is_deprecated = compound.is_deprecated + entry.deprecated = compound.deprecated + entry.since = compound.since entry.has_nestable_children = False if compound.kind in ['class', 'struct', 'union']: entry.is_final = compound.is_final @@ -3303,7 +3344,8 @@ copy a link to the result using ⌘ """], 'M_SEARCH_BASE_URL': [''], 'M_SEARCH_EXTERNAL_URL': [''], - 'M_SHOW_UNDOCUMENTED': ['NO'] + 'M_SHOW_UNDOCUMENTED': ['NO'], + 'M_VERSION_LABELS': ['NO'] } # Defaults so we don't fail with minimal Doxyfiles and also that the @@ -3423,7 +3465,8 @@ copy a link to the result using ⌘ 'M_EXPAND_INNER_TYPES', 'M_SEARCH_DISABLED', 'M_SEARCH_DOWNLOAD_BINARY', - 'M_SHOW_UNDOCUMENTED']: + 'M_SHOW_UNDOCUMENTED', + 'M_VERSION_LABELS']: if i in config: state.doxyfile[i] = ' '.join(config[i]) == 'YES' # List values that we want. Drop empty lines. diff --git a/documentation/templates/doxygen/annotated.html b/documentation/templates/doxygen/annotated.html index a81e2031..338ad881 100644 --- a/documentation/templates/doxygen/annotated.html +++ b/documentation/templates/doxygen/annotated.html @@ -7,13 +7,13 @@ {% for i in index.symbols recursive %} {% if i.children %}
  • - {{ i.kind }} {{ i.name }}{% if i.is_deprecated %} deprecated{% endif %} {{ i.brief }} + {{ i.kind }} {{ i.name }}{% if i.deprecated %} {{ i.deprecated }}{% endif %}{% if i.since %} {{ i.since }}{% endif %} {{ i.brief }}
      {{ loop(i.children)|rtrim|indent(4, true) }}
  • {% else %} -
  • {{ i.kind }} {{ i.name }}{% if i.is_final %} final{% endif %}{% if i.is_deprecated %} deprecated{% endif %} {{ i.brief }}
  • +
  • {{ i.kind }} {{ i.name }}{% if i.is_final %} final{% endif %}{% if i.deprecated %} {{ i.deprecated }}{% endif %}{% if i.since %} {{ i.since }}{% endif %} {{ i.brief }}
  • {% endif %} {% endfor %} diff --git a/documentation/templates/doxygen/base-class-reference.html b/documentation/templates/doxygen/base-class-reference.html index abcb996c..7c7eae52 100644 --- a/documentation/templates/doxygen/base-class-reference.html +++ b/documentation/templates/doxygen/base-class-reference.html @@ -24,7 +24,7 @@ {% set j = joiner(', ') %}
    template<{% for t in compound.templates %}{{ j() }}{{ t.type }}{% if t.name %} {{ t.name }}{% endif %}{% if t.default %} = {{ t.default }}{% endif%}{% endfor %}>
    {% endif %} - {%+ for name, target in compound.breadcrumb[:-1] %}{{ name }}::{% endfor %}{{ compound.breadcrumb[-1][0] }} {{ compound.kind }}{% if compound.is_final %} final{% endif %} + {%+ for name, target in compound.breadcrumb[:-1] %}{{ name }}::{% endfor %}{{ compound.breadcrumb[-1][0] }} {{ compound.kind }}{% if compound.is_final %} final{% endif %}{% if compound.since %} {{ compound.since }}{% endif %} {# need an explicit space here otherwise the newline gets removed #} {% if compound.include and compound.templates == None %} diff --git a/documentation/templates/doxygen/details-define.html b/documentation/templates/doxygen/details-define.html index 63cc720b..6e30eadf 100644 --- a/documentation/templates/doxygen/details-define.html +++ b/documentation/templates/doxygen/details-define.html @@ -1,7 +1,7 @@

    {% set j = joiner(',\n ') %} - #define {{ define.name }}{% if define.params != None %}({% for param in define.params %}{{ j() }}{{ param[0] }}{% endfor %}){% endif %} + #define {{ define.name }}{% if define.params != None %}({% for param in define.params %}{{ j() }}{{ param[0] }}{% endfor %}){% endif %}{% if define.since %} {{ define.since }}{% endif %} {% if define.include %} {% endif %} diff --git a/documentation/templates/doxygen/details-enum.html b/documentation/templates/doxygen/details-enum.html index 72ef6756..01343041 100644 --- a/documentation/templates/doxygen/details-enum.html +++ b/documentation/templates/doxygen/details-enum.html @@ -6,7 +6,7 @@ template<{% for t in compound.templates %}{{ j() }}{{ t.type }} {% if t.name %}{{ t.name }}{% else %}_{{ loop.index }}{% endif %}{% endfor %}>

    {% endif %} - enum {% if enum.is_strong %}class {% endif %}{{ prefix }}{{ enum.name }}{% if enum.type %}: {{ enum.type }}{% endif %}{% if enum.is_protected %} protected{% endif %} + enum {% if enum.is_strong %}class {% endif %}{{ prefix }}{{ enum.name }}{% if enum.type %}: {{ enum.type }}{% endif %}{% if enum.is_protected %} protected{% endif %}{% if enum.since %} {{ enum.since }}{% endif %} {# not sure why there needs to be this space #} {% if enum.include %} @@ -29,7 +29,7 @@ {% for value in enum.values %} - {{ value.name }} + {{ value.name }}{% if value.since %} {{ value.since }}{% endif %} {% if value.brief %}{# brief is not required for values #}

    {{ value.brief }}

    diff --git a/documentation/templates/doxygen/details-func.html b/documentation/templates/doxygen/details-func.html index 5db4d2dc..5044dc95 100644 --- a/documentation/templates/doxygen/details-func.html +++ b/documentation/templates/doxygen/details-func.html @@ -16,7 +16,7 @@ {% endif %} {% set j = joiner(',\n ') %} - {{ func.prefix }}{{ func.type }} {{ prefix }}{{ func.name }}({% for param in func.params %}{{ j() }}{{ param.type_name }}{% if param.default %} = {{ param.default }}{% endif %}{% endfor %}){{ func.suffix }}{% if func.is_explicit %} explicit {% endif %}{% if func.is_final %} final{% elif func.is_override %} override{% elif func.is_pure_virtual %} pure virtual{% elif func.is_virtual %} virtual{% endif %}{% if func.is_protected %} protected{% if func.is_slot %} slot{% endif %}{% elif func.is_private %} private{% if func.is_slot %} slot{% endif %}{% elif func.is_signal %} signal{% elif func.is_slot %} public slot{% endif %}{% if func.is_defaulted %} defaulted{% endif %}{% if func.is_deleted %} deleted{% endif %}{% if func.is_constexpr %} constexpr{% endif %}{% if func.is_conditional_noexcept %} noexcept(…){% elif func.is_noexcept %} noexcept{% endif %} + {{ func.prefix }}{{ func.type }} {{ prefix }}{{ func.name }}({% for param in func.params %}{{ j() }}{{ param.type_name }}{% if param.default %} = {{ param.default }}{% endif %}{% endfor %}){{ func.suffix }}{% if func.is_explicit %} explicit {% endif %}{% if func.is_final %} final{% elif func.is_override %} override{% elif func.is_pure_virtual %} pure virtual{% elif func.is_virtual %} virtual{% endif %}{% if func.is_protected %} protected{% if func.is_slot %} slot{% endif %}{% elif func.is_private %} private{% if func.is_slot %} slot{% endif %}{% elif func.is_signal %} signal{% elif func.is_slot %} public slot{% endif %}{% if func.is_defaulted %} defaulted{% endif %}{% if func.is_deleted %} deleted{% endif %}{% if func.is_constexpr %} constexpr{% endif %}{% if func.is_conditional_noexcept %} noexcept(…){% elif func.is_noexcept %} noexcept{% endif %}{% if func.since %} {{ func.since }}{% endif %} {% if func.include and compound.templates == None and func.templates == None %} {% endif %} diff --git a/documentation/templates/doxygen/details-typedef.html b/documentation/templates/doxygen/details-typedef.html index b0b37c92..76346baa 100644 --- a/documentation/templates/doxygen/details-typedef.html +++ b/documentation/templates/doxygen/details-typedef.html @@ -16,9 +16,9 @@ {% endif %} {% if typedef.is_using %} - using {{ prefix }}{{ typedef.name }} = {{ typedef.type }}{{ typedef.args }}{% if typedef.is_protected %} protected{% endif %} + using {{ prefix }}{{ typedef.name }} = {{ typedef.type }}{{ typedef.args }}{% if typedef.is_protected %} protected{% endif %}{% if typedef.since %} {{ typedef.since }}{% endif %} {% else %} - typedef {{ typedef.type }}{% if not typedef.args %} {% endif %}{{ prefix }}{{ typedef.name }}{{ typedef.args }}{% if typedef.is_protected %} protected{% endif %} + typedef {{ typedef.type }}{% if not typedef.args %} {% endif %}{{ prefix }}{{ typedef.name }}{{ typedef.args }}{% if typedef.is_protected %} protected{% endif %}{% if typedef.since %} {{ typedef.since }}{% endif %} {% endif %} {# the empty line has to be here to prevent the lines from merging #} diff --git a/documentation/templates/doxygen/details-var.html b/documentation/templates/doxygen/details-var.html index 89ce64ae..da2edbdf 100644 --- a/documentation/templates/doxygen/details-var.html +++ b/documentation/templates/doxygen/details-var.html @@ -15,7 +15,7 @@ {% endif %} {% endif %} - {%+ if var.is_static %}static {% endif %}{{ var.type }} {{ prefix }}{{ var.name }}{% if var.is_protected %} protected{% endif %}{% if var.is_constexpr %} constexpr{% endif %} + {%+ if var.is_static %}static {% endif %}{{ var.type }} {{ prefix }}{{ var.name }}{% if var.is_protected %} protected{% endif %}{% if var.is_constexpr %} constexpr{% endif %}{% if var.since %} {{ var.since }}{% endif %} {# the empty line needs to be here to prevent the lines from merging #} {% if var.include and compound.templates == None and var.templates == None %} diff --git a/documentation/templates/doxygen/dir.html b/documentation/templates/doxygen/dir.html index 666f07d0..a5fd5323 100644 --- a/documentation/templates/doxygen/dir.html +++ b/documentation/templates/doxygen/dir.html @@ -4,6 +4,8 @@ {% block header %}

    - {%+ for name, target in compound.breadcrumb[:-1] %}{{ name }}/{% endfor %}{{ compound.breadcrumb[-1][0] }}/ directory + {%+ for name, target in compound.breadcrumb[:-1] %}{{ name }}/{% endfor %}{{ compound.breadcrumb[-1][0] }}/ directory{% if compound.since %} {{ compound.since }}{% endif %} + {# need an explicit space here otherwise the newline gets removed #} +

    {% endblock %} diff --git a/documentation/templates/doxygen/entry-class.html b/documentation/templates/doxygen/entry-class.html index 2d8dcdd0..fa291b5d 100644 --- a/documentation/templates/doxygen/entry-class.html +++ b/documentation/templates/doxygen/entry-class.html @@ -3,7 +3,7 @@ {% set j = joiner(', ') %}
    template<{% for t in class.templates %}{{ j() }}{{ t.type }}{% if t.name %} {{ t.name }}{% endif %}{% if t.default %} = {{ t.default }}{% endif %}{% endfor %}>
    {% endif %} - {{ class.kind }} {{ class.name }}{% if class.is_deprecated %} deprecated{% endif %}{% if class.is_protected %} protected{% endif %}{% if class.is_final %} final{% elif class.is_virtual %} virtual{% endif %} + {{ class.kind }} {{ class.name }}{% if class.deprecated %} {{ class.deprecated }}{% endif %}{% if class.is_protected %} protected{% endif %}{% if class.is_final %} final{% elif class.is_virtual %} virtual{% endif %}{% if class.since %} {{ class.since }}{% endif %} {# the empty line is above to fix spacing #} diff --git a/documentation/templates/doxygen/entry-define.html b/documentation/templates/doxygen/entry-define.html index c6a03347..c1972899 100644 --- a/documentation/templates/doxygen/entry-define.html +++ b/documentation/templates/doxygen/entry-define.html @@ -1,5 +1,5 @@ {% set j = joiner(',\n ') %} - #define {{ define.name }}{% if define.params != None %}({% for param in define.params %}{{ j() }}{{ param[0] }}{% endfor %}){% endif %}{% if define.is_deprecated %} deprecated{% endif %} + #define {{ define.name }}{% if define.params != None %}({% for param in define.params %}{{ j() }}{{ param[0] }}{% endfor %}){% endif %}{% if define.deprecated %} {{ define.deprecated }}{% endif %}{% if define.since %} {{ define.since }}{% endif %}
    {{ define.brief }}
    diff --git a/documentation/templates/doxygen/entry-dir.html b/documentation/templates/doxygen/entry-dir.html index 39b475a4..701d17ff 100644 --- a/documentation/templates/doxygen/entry-dir.html +++ b/documentation/templates/doxygen/entry-dir.html @@ -1,2 +1,2 @@ -
    directory {{ dir.name }}/{% if dir.is_deprecated %} deprecated{% endif %}
    +
    directory {{ dir.name }}/{% if dir.deprecated %} {{ dir.deprecated }}{% endif %}{% if dir.since %} {{ dir.since }}{% endif %}
    {{ dir.brief }}
    diff --git a/documentation/templates/doxygen/entry-enum.html b/documentation/templates/doxygen/entry-enum.html index dcfc5680..e1cd2c1b 100644 --- a/documentation/templates/doxygen/entry-enum.html +++ b/documentation/templates/doxygen/entry-enum.html @@ -1,5 +1,5 @@ {% set j = joiner(',\n ') %} - enum {% if enum.is_strong %}class {% endif %}{{ enum.name }}{% if enum.type %}: {{ enum.type }}{% endif %} { {% for value in enum.values %}{{ j() }}{{ value.name }}{% if value.initializer %} {{ value.initializer }}{% endif %}{% if value.is_deprecated %} deprecated{% endif %}{% endfor %} }{% if enum.is_deprecated %} deprecated{% endif %}{% if mark_nonpublic and enum.is_protected %} protected{% endif %} + enum {% if enum.is_strong %}class {% endif %}{{ enum.name }}{% if enum.type %}: {{ enum.type }}{% endif %} { {% for value in enum.values %}{{ j() }}{{ value.name }}{% if value.initializer %} {{ value.initializer }}{% endif %}{% if value.since %} {{ value.since }}{% endif %}{% if value.deprecated %} {{ value.deprecated }}{% endif %}{% endfor %} }{% if enum.deprecated %} {{ enum.deprecated }}{% endif %}{% if mark_nonpublic and enum.is_protected %} protected{% endif %}{% if enum.since %} {{ enum.since }}{% endif %}
    {{ enum.brief }}
    diff --git a/documentation/templates/doxygen/entry-file.html b/documentation/templates/doxygen/entry-file.html index 908c5e1c..43a70c4a 100644 --- a/documentation/templates/doxygen/entry-file.html +++ b/documentation/templates/doxygen/entry-file.html @@ -1,2 +1,2 @@ -
    file {{ file.name }}{% if file.is_deprecated %} deprecated{% endif %}
    +
    file {{ file.name }}{% if file.deprecated %} {{ file.deprecated }}{% endif %}{% if file.since %} {{ file.since }}{% endif %}
    {{ file.brief }}
    diff --git a/documentation/templates/doxygen/entry-func.html b/documentation/templates/doxygen/entry-func.html index 80bd6678..0738fe90 100644 --- a/documentation/templates/doxygen/entry-func.html +++ b/documentation/templates/doxygen/entry-func.html @@ -4,6 +4,6 @@
    template<{% for t in func.templates %}{{ j() }}{{ t.type }}{% if t.name %} {{ t.name }}{% endif %}{% if t.default %} = {{ t.default }}{% endif %}{% endfor %}>
    {% endif %} {% set j = joiner(',\n ') %} - {{ func.prefix }}{% if func.type == 'void' %}void {% elif func.type %}auto {% endif %}{{ func.name }}({% for param in func.params %}{{ j() }}{{ param.type_name }}{% if param.default %} = {{ param.default }}{% endif %}{% endfor %}){{ func.suffix }}{% if func.type and func.type != 'void' %} -> {{ func.type }}{% endif %}{% if func.is_deprecated %} deprecated{% endif %}{% if not func.type or mark_nonpublic %}{% if func.is_protected %} protected{% if func.is_slot %} slot{% endif %}{% elif func.is_private %} private{% if func.is_slot %} slot{% endif %}{% elif func.is_signal %} signal{% elif func.is_slot %} public slot{% endif %}{% endif %}{% if func.is_defaulted %} defaulted{% endif %}{% if func.is_deleted %} deleted{% endif %}{% if func.is_explicit %} explicit {% endif %}{% if func.is_final %} final{% elif func.is_override %} override{% elif func.is_pure_virtual %} pure virtual{% elif func.is_virtual %} virtual{% endif %}{% if func.is_constexpr %} constexpr{% endif %}{% if func.is_conditional_noexcept %} noexcept(…){% elif func.is_noexcept %} noexcept{% endif %} + {{ func.prefix }}{% if func.type == 'void' %}void {% elif func.type %}auto {% endif %}{{ func.name }}({% for param in func.params %}{{ j() }}{{ param.type_name }}{% if param.default %} = {{ param.default }}{% endif %}{% endfor %}){{ func.suffix }}{% if func.type and func.type != 'void' %} -> {{ func.type }}{% endif %}{% if func.deprecated %} {{ func.deprecated }}{% endif %}{% if not func.type or mark_nonpublic %}{% if func.is_protected %} protected{% if func.is_slot %} slot{% endif %}{% elif func.is_private %} private{% if func.is_slot %} slot{% endif %}{% elif func.is_signal %} signal{% elif func.is_slot %} public slot{% endif %}{% endif %}{% if func.is_defaulted %} defaulted{% endif %}{% if func.is_deleted %} deleted{% endif %}{% if func.is_explicit %} explicit {% endif %}{% if func.is_final %} final{% elif func.is_override %} override{% elif func.is_pure_virtual %} pure virtual{% elif func.is_virtual %} virtual{% endif %}{% if func.is_constexpr %} constexpr{% endif %}{% if func.is_conditional_noexcept %} noexcept(…){% elif func.is_noexcept %} noexcept{% endif %}{% if func.since %} {{ func.since }}{% endif %}
    {{ func.brief }}
    diff --git a/documentation/templates/doxygen/entry-module.html b/documentation/templates/doxygen/entry-module.html index 504066de..78e0b81f 100644 --- a/documentation/templates/doxygen/entry-module.html +++ b/documentation/templates/doxygen/entry-module.html @@ -1,2 +1,2 @@ -
    module {{ module.name }}{% if module.is_deprecated %} deprecated{% endif %}
    +
    module {{ module.name }}{% if module.deprecated %} {{ module.deprecated }}{% endif %}{% if module.since %} {{ module.since }}{% endif %}
    {{ module.brief }}
    diff --git a/documentation/templates/doxygen/entry-namespace.html b/documentation/templates/doxygen/entry-namespace.html index 83687525..9e90087b 100644 --- a/documentation/templates/doxygen/entry-namespace.html +++ b/documentation/templates/doxygen/entry-namespace.html @@ -1,2 +1,2 @@ -
    namespace {{ namespace.name }}{% if namespace.is_deprecated %} deprecated{% endif %}
    +
    namespace {{ namespace.name }}{% if namespace.deprecated %} {{ namespace.deprecated }}{% endif %}{% if namespace.since %} {{ namespace.since }}{% endif %}
    {{ namespace.brief }}
    diff --git a/documentation/templates/doxygen/entry-typedef.html b/documentation/templates/doxygen/entry-typedef.html index e2395d0f..5285beee 100644 --- a/documentation/templates/doxygen/entry-typedef.html +++ b/documentation/templates/doxygen/entry-typedef.html @@ -3,7 +3,7 @@ {% set j = joiner(', ') %}
    template<{% for t in typedef.templates %}{{ j() }}{{ t.type }}{% if t.name %} {{ t.name }}{% endif %}{% if t.default %} = {{ t.default }}{% endif%}{% endfor %}>
    {% endif %} - using {{ typedef.name }} = {{ typedef.type }}{{ typedef.args }}{% if typedef.is_deprecated %} deprecated{% endif %}{% if mark_nonpublic and typedef.is_protected %} protected{% endif %} + using {{ typedef.name }} = {{ typedef.type }}{{ typedef.args }}{% if typedef.deprecated %} {{ typedef.deprecated }}{% endif %}{% if mark_nonpublic and typedef.is_protected %} protected{% endif %}{% if typedef.since %} {{ typedef.since }}{% endif %} {# This empty line needs to be there otherwise it's eaten #} diff --git a/documentation/templates/doxygen/entry-var.html b/documentation/templates/doxygen/entry-var.html index a1740271..52f21d49 100644 --- a/documentation/templates/doxygen/entry-var.html +++ b/documentation/templates/doxygen/entry-var.html @@ -3,7 +3,7 @@ {% set j = joiner(', ') %}
    template<{% for t in var.templates %}{{ j() }}{{ t.type }}{% if t.name %} {{ t.name }}{% endif %}{% if t.default %} = {{ t.default }}{% endif%}{% endfor %}>
    {% endif %} - {%+ if var.is_static %}static {% endif %}{{ var.type }} {{ var.name }}{% if var.is_deprecated %} deprecated{% endif %}{% if mark_nonpublic and var.is_protected %} protected{% endif %}{% if var.is_constexpr %} constexpr{% endif %} + {%+ if var.is_static %}static {% endif %}{{ var.type }} {{ var.name }}{% if var.deprecated %} {{ var.deprecated }}{% endif %}{% if mark_nonpublic and var.is_protected %} protected{% endif %}{% if var.is_constexpr %} constexpr{% endif %}{% if var.since %} {{ var.since }}{% endif %} {# This empty line needs to be there otherwise it's eaten #} diff --git a/documentation/templates/doxygen/file.html b/documentation/templates/doxygen/file.html index 126ccaa5..2427983b 100644 --- a/documentation/templates/doxygen/file.html +++ b/documentation/templates/doxygen/file.html @@ -4,6 +4,8 @@ {% block header %}

    - {%+ for name, target in compound.breadcrumb[:-1] %}{{ name }}/{% endfor %}{{ compound.breadcrumb[-1][0] }} file + {%+ for name, target in compound.breadcrumb[:-1] %}{{ name }}/{% endfor %}{{ compound.breadcrumb[-1][0] }} file{% if compound.since %} {{ compound.since }}{% endif %} + {# need an explicit space here otherwise the newline gets removed #} +

    {% endblock %} diff --git a/documentation/templates/doxygen/files.html b/documentation/templates/doxygen/files.html index 972ca7d0..7400a5d1 100644 --- a/documentation/templates/doxygen/files.html +++ b/documentation/templates/doxygen/files.html @@ -7,13 +7,13 @@ {% for i in index.files recursive %} {% if i.children %}
  • - {{ i.kind }} {{ i.name }}{% if i.is_deprecated %} deprecated{% endif %} {{ i.brief }} + {{ i.kind }} {{ i.name }}{% if i.deprecated %} {{ i.deprecated }}{% endif %}{% if i.since %} {{ i.since }}{% endif %} {{ i.brief }}
      {{ loop(i.children)|rtrim|indent(4, true) }}
  • {% else %} -
  • {{ i.kind }} {{ i.name }}{% if i.is_deprecated %} deprecated{% endif %} {{ i.brief }}
  • +
  • {{ i.kind }} {{ i.name }}{% if i.deprecated %} {{ i.deprecated }}{% endif %}{% if i.since %} {{ i.since }}{% endif %} {{ i.brief }}
  • {% endif %} {% endfor %} diff --git a/documentation/templates/doxygen/group.html b/documentation/templates/doxygen/group.html index 991657fb..86b34d2a 100644 --- a/documentation/templates/doxygen/group.html +++ b/documentation/templates/doxygen/group.html @@ -7,5 +7,5 @@ {% for name, target in compound.breadcrumb[:-1] %} {{ name }} » {% endfor %} - {{ compound.breadcrumb[-1][0] }} module + {{ compound.breadcrumb[-1][0] }} module{% if compound.since %} {{ compound.since }}{% endif %} {% endblock %} diff --git a/documentation/templates/doxygen/modules.html b/documentation/templates/doxygen/modules.html index 8487a1bd..a8547112 100644 --- a/documentation/templates/doxygen/modules.html +++ b/documentation/templates/doxygen/modules.html @@ -7,13 +7,13 @@ {% for i in index.modules recursive %} {% if i.has_nestable_children %}
  • - module {{ i.name }}{% if i.is_deprecated %} deprecated{% endif %} {{ i.brief }} + module {{ i.name }}{% if i.deprecated %} {{ i.deprecated }}{% endif %}{% if i.since %} {{ i.since }}{% endif %} {{ i.brief }}
      {{ loop(i.children)|rtrim|indent(4, true) }}
  • {% else %} -
  • module {{ i.name }}{% if i.is_deprecated %} deprecated{% endif %} {{ i.brief }}
  • +
  • module {{ i.name }}{% if i.deprecated %} {{ i.deprecated }}{% endif %}{% if i.since %} {{ i.since }}{% endif %} {{ i.brief }}
  • {% endif %} {% endfor %} diff --git a/documentation/templates/doxygen/namespace.html b/documentation/templates/doxygen/namespace.html index e5925ade..9cab47fc 100644 --- a/documentation/templates/doxygen/namespace.html +++ b/documentation/templates/doxygen/namespace.html @@ -4,7 +4,9 @@ {% block header %}

    - {%+ for name, target in compound.breadcrumb[:-1] %}{{ name }}::{% endfor %}{{ compound.breadcrumb[-1][0] }} namespace + {%+ for name, target in compound.breadcrumb[:-1] %}{{ name }}::{% endfor %}{{ compound.breadcrumb[-1][0] }} namespace{% if compound.since %} {{ compound.since }}{% endif %} + {# need an explicit space here otherwise the newline gets removed #} + {% if compound.include %} {% endif %} diff --git a/documentation/templates/doxygen/namespaces.html b/documentation/templates/doxygen/namespaces.html index 986ab38c..5ff416bf 100644 --- a/documentation/templates/doxygen/namespaces.html +++ b/documentation/templates/doxygen/namespaces.html @@ -7,13 +7,13 @@ {% for i in index.symbols|selectattr('kind', 'equalto', 'namespace') recursive %} {% if i.has_nestable_children %}
  • - {{ i.kind }} {{ i.name }}{% if i.is_deprecated %} deprecated{% endif %} {{ i.brief }} + {{ i.kind }} {{ i.name }}{% if i.deprecated %} {{ i.deprecated }}{% endif %}{% if i.since %} {{ i.since }}{% endif %} {{ i.brief }}
      {{ loop(i.children|selectattr('kind', 'equalto', 'namespace'))|rtrim|indent(4, true) }}
  • {% else %} -
  • {{ i.kind }} {{ i.name }}{% if i.is_deprecated %} deprecated{% endif %} {{ i.brief }}
  • +
  • {{ i.kind }} {{ i.name }}{% if i.deprecated %} {{ i.deprecated }}{% endif %}{% if i.since %} {{ i.since }}{% endif %} {{ i.brief }}
  • {% endif %} {% endfor %} diff --git a/documentation/templates/doxygen/page.html b/documentation/templates/doxygen/page.html index 473d30f3..8494f253 100644 --- a/documentation/templates/doxygen/page.html +++ b/documentation/templates/doxygen/page.html @@ -16,7 +16,9 @@ {% for name, target in compound.breadcrumb[:-1] %} {{ name }} » {% endfor %} - {{ compound.breadcrumb[-1][0] }} + {{ compound.breadcrumb[-1][0] }}{% if compound.since %} {{ compound.since }}{% endif %} + {# need an explicit space here otherwise the newline gets removed #} +

    {% if compound.brief %}

    {{ compound.brief }}

    diff --git a/documentation/templates/doxygen/pages.html b/documentation/templates/doxygen/pages.html index 8d52dd8a..46bf87b8 100644 --- a/documentation/templates/doxygen/pages.html +++ b/documentation/templates/doxygen/pages.html @@ -7,13 +7,13 @@ {% for i in index.pages recursive %} {% if i.children %}
  • - {{ i.name }}{% if i.is_deprecated %} deprecated{% endif %} {{ i.brief }} + {{ i.name }}{% if i.deprecated %} {{ i.deprecated }}{% endif %}{% if i.since %} {{ i.since }}{% endif %} {{ i.brief }}
      {{ loop(i.children)|rtrim|indent(4, true) }}
  • {% else %} -
  • {{ i.name }}{% if i.is_deprecated %} deprecated{% endif %} {{ i.brief }}
  • +
  • {{ i.name }}{% if i.deprecated %} {{ i.deprecated }}{% endif %}{% if i.since %} {{ i.since }}{% endif %} {{ i.brief }}
  • {% endif %} {% endfor %} diff --git a/documentation/test_doxygen/compound_since/Class_8h.html b/documentation/test_doxygen/compound_since/Class_8h.html new file mode 100644 index 00000000..286705d0 --- /dev/null +++ b/documentation/test_doxygen/compound_since/Class_8h.html @@ -0,0 +1,100 @@ + + + + + Directory/Class.h file | My Project + + + + + +
    +
    +
    +
    +
    +

    + Directory/Class.h file since 2010.02 +

    +

    Pretty old things.

    +
    +

    Contents

    + +
    +
    +

    Namespaces

    +
    +
    namespace Foo since 2010.02
    +
    A namespace.
    +
    +
    +
    +

    Classes

    +
    +
    + class Foo::Class since 2019.11 +
    +
    A class.
    +
    + struct Foo::Subclass since 2019.11 +
    +
    A subclass.
    +
    +
    +
    +

    Defines

    +
    +
    + #define A_DEFINE since 2010.02 +
    +
    A define.
    +
    +
    +
    +

    Define documentation

    +
    +

    + #define A_DEFINE since 2010.02 +

    +

    A define.

    +

    Details should have the badge too.

    +
    +
    +
    +
    +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/DeprecatedClass_8h.html b/documentation/test_doxygen/compound_since/DeprecatedClass_8h.html new file mode 100644 index 00000000..5b3bce61 --- /dev/null +++ b/documentation/test_doxygen/compound_since/DeprecatedClass_8h.html @@ -0,0 +1,101 @@ + + + + + DeprecatedDirectory/DeprecatedClass.h file | My Project + + + + + +
    +
    +
    +
    +
    +

    + DeprecatedDirectory/DeprecatedClass.h file +

    +

    Pretty old things.

    +
    +

    Contents

    + +
    + +
    +

    Namespaces

    +
    +
    namespace DeprecatedFoo deprecated since 2010.02
    +
    A namespace.
    +
    +
    +
    +

    Classes

    +
    +
    + class DeprecatedFoo::DeprecatedClass deprecated since 2010.02 +
    +
    A class.
    +
    + struct DeprecatedFoo::DeprecatedSubclass deprecated since 2010.02 +
    +
    A subclass.
    +
    +
    +
    +

    Defines

    +
    +
    + #define DEPRECATED_DEFINE deprecated since 2010.02 +
    +
    A define.
    +
    +
    +
    +

    Define documentation

    +
    +

    + #define DEPRECATED_DEFINE +

    +

    A define.

    +

    Details should have the badge too.

    +
    +
    +
    +
    +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/DeprecatedDirectory/DeprecatedClass.h b/documentation/test_doxygen/compound_since/DeprecatedDirectory/DeprecatedClass.h new file mode 100644 index 00000000..1a4284d1 --- /dev/null +++ b/documentation/test_doxygen/compound_since/DeprecatedDirectory/DeprecatedClass.h @@ -0,0 +1,81 @@ +/** @dir DeprecatedDirectory + * @brief A dir with pretty old things. + * @m_deprecated_since{2010,02} Yes it is. + */ + +/** @file + * @brief Pretty old things. + * @m_deprecated_since{2010,02} Yes it is. + */ + +/** +@brief A namespace +@m_deprecated_since{2010,02} Yes it is. +*/ +namespace DeprecatedFoo { + +/** +@brief A class +@m_deprecated_since{2010,02} Yes it is. +*/ +class DeprecatedClass {}; + +/** +@brief A subclass +@m_deprecated_since{2010,02} Yes it is. +*/ +struct DeprecatedSubclass: DeprecatedClass {}; + +/** +@brief A function +@m_deprecated_since{2010,02} Yes it is. + +Details should have the badge too. +*/ +void deprecatedFoo(); + +/** +@brief A typedef +@m_deprecated_since{2010,02} Yes it is. + +Details should have the badge too. +*/ +typedef DeprecatedClass DeprecatedKlazz; + +/** +@brief An enum +@m_deprecated_since{2010,02} Yes it is. + +Details should have the badge too. +*/ +enum DeprecatedEnum { + /** + * This thing is deprecated. + * + * Yes. + * + * @m_deprecated_since{2010,02} Yes it is. + */ + DeprecatedOldValue = 0, + + /* Some other. */ + NewValue = 3 +}; + +/** +@brief A constant +@m_deprecated_since{2010,02} Yes it is. + +Details should have the badge too. +*/ +constexpr int DeprecatedFive = 5; + +} + +/** +@brief A define +@m_deprecated_since{2010,02} Yes it is. + +Details should have the badge too. +*/ +#define DEPRECATED_DEFINE diff --git a/documentation/test_doxygen/compound_since/Directory/Class.h b/documentation/test_doxygen/compound_since/Directory/Class.h new file mode 100644 index 00000000..998f1bc2 --- /dev/null +++ b/documentation/test_doxygen/compound_since/Directory/Class.h @@ -0,0 +1,81 @@ +/* WHAT THE FUCK DOXYGEN WHY IS THIS MATCHING THE NAME PARTIALLY?! WHAT */ +/** @dir compound_since/Directory + * @brief A dir with pretty old things. + * @m_since{2010,02} + */ + +/** @file + * @brief Pretty old things. + * @m_since{2010,02} + */ + +/** +@brief A namespace +@m_since{2010,02} +*/ +namespace Foo { + +/** +@brief A class +@m_since{2019,11} +*/ +class Class {}; + +/** +@brief A subclass +@m_since{2019,11} +*/ +struct Subclass: Class {}; + +/** +@brief A function +@m_since{2010,02} + +Details should have the badge too. +*/ +void foo(); + +/** +@brief A typedef +@m_since{2010,02} + +Details should have the badge too. +*/ +typedef Class Klazz; + +/** +@brief An enum +@m_since{2010,02} + +Details should have the badge too. +*/ +enum Enum { + OldValue = 0, + + /** + * This thing is new. + * + * Yes. + * + * @m_since{2019,11} + */ + NewValue = 3 +}; + +/** +@brief A constant +@m_since{2010,02} + +Details should have the badge too. +*/ +constexpr int Five = 5; + +} + +/** +@brief A define +@m_since{2010,02} + +Details should have the badge too. +*/ +#define A_DEFINE diff --git a/documentation/test_doxygen/compound_since/Doxyfile b/documentation/test_doxygen/compound_since/Doxyfile new file mode 100644 index 00000000..2bd734b4 --- /dev/null +++ b/documentation/test_doxygen/compound_since/Doxyfile @@ -0,0 +1,19 @@ +INPUT = Directory/Class.h DeprecatedDirectory/DeprecatedClass.h pages.dox +QUIET = YES +GENERATE_HTML = NO +GENERATE_LATEX = NO +GENERATE_XML = YES +XML_PROGRAMLISTING = NO +CASE_SENSE_NAMES = YES + +##! M_PAGE_FINE_PRINT = +##! M_THEME_COLOR = +##! M_FAVICON = +##! M_LINKS_NAVBAR1 = pages namespaces modules +##! M_SEARCH_DISABLED = YES +##! M_VERSION_LABELS = YES + +ALIASES = \ + "m_class{1}=@xmlonly@endxmlonly" \ + "m_since{2}=@since @m_class{m-label m-success m-flat} @ref changelog-\1-\2 \"since \1.\2\"" \ + "m_deprecated_since{2}=@since deprecated since \1.\2 @deprecated" diff --git a/documentation/test_doxygen/compound_since/a.html b/documentation/test_doxygen/compound_since/a.html new file mode 100644 index 00000000..33a9ae25 --- /dev/null +++ b/documentation/test_doxygen/compound_since/a.html @@ -0,0 +1,48 @@ + + + + + This is new. | My Project + + + + + +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/annotated.html b/documentation/test_doxygen/compound_since/annotated.html new file mode 100644 index 00000000..8a00a8dd --- /dev/null +++ b/documentation/test_doxygen/compound_since/annotated.html @@ -0,0 +1,77 @@ + + + + + My Project + + + + + +
    +
    +
    +
    +
    +

    Classes

    + + +
    +
    +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/classDeprecatedFoo_1_1DeprecatedClass.html b/documentation/test_doxygen/compound_since/classDeprecatedFoo_1_1DeprecatedClass.html new file mode 100644 index 00000000..8479e407 --- /dev/null +++ b/documentation/test_doxygen/compound_since/classDeprecatedFoo_1_1DeprecatedClass.html @@ -0,0 +1,59 @@ + + + + + DeprecatedFoo::DeprecatedClass class | My Project + + + + + +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/classFoo_1_1Class.html b/documentation/test_doxygen/compound_since/classFoo_1_1Class.html new file mode 100644 index 00000000..e4bf1016 --- /dev/null +++ b/documentation/test_doxygen/compound_since/classFoo_1_1Class.html @@ -0,0 +1,58 @@ + + + + + Foo::Class class | My Project + + + + + +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/deprecated-a.html b/documentation/test_doxygen/compound_since/deprecated-a.html new file mode 100644 index 00000000..7ec5e083 --- /dev/null +++ b/documentation/test_doxygen/compound_since/deprecated-a.html @@ -0,0 +1,48 @@ + + + + + This is old. | My Project + + + + + +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/dir_4b0d5f8864bf89936129251a2d32609b.html b/documentation/test_doxygen/compound_since/dir_4b0d5f8864bf89936129251a2d32609b.html new file mode 100644 index 00000000..894d6e86 --- /dev/null +++ b/documentation/test_doxygen/compound_since/dir_4b0d5f8864bf89936129251a2d32609b.html @@ -0,0 +1,66 @@ + + + + + Directory/ directory | My Project + + + + + +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/dir_73d1500434dee6f1c83b12ee799c54af.html b/documentation/test_doxygen/compound_since/dir_73d1500434dee6f1c83b12ee799c54af.html new file mode 100644 index 00000000..4c56516d --- /dev/null +++ b/documentation/test_doxygen/compound_since/dir_73d1500434dee6f1c83b12ee799c54af.html @@ -0,0 +1,67 @@ + + + + + DeprecatedDirectory/ directory | My Project + + + + + +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/files.html b/documentation/test_doxygen/compound_since/files.html new file mode 100644 index 00000000..e49e3910 --- /dev/null +++ b/documentation/test_doxygen/compound_since/files.html @@ -0,0 +1,75 @@ + + + + + My Project + + + + + +
    +
    +
    +
    +
    +

    Files

    + + +
    +
    +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/group__deprecated-group.html b/documentation/test_doxygen/compound_since/group__deprecated-group.html new file mode 100644 index 00000000..64bfdceb --- /dev/null +++ b/documentation/test_doxygen/compound_since/group__deprecated-group.html @@ -0,0 +1,65 @@ + + + + + A group module | My Project + + + + + +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/group__group.html b/documentation/test_doxygen/compound_since/group__group.html new file mode 100644 index 00000000..2cc969dc --- /dev/null +++ b/documentation/test_doxygen/compound_since/group__group.html @@ -0,0 +1,65 @@ + + + + + A group module | My Project + + + + + +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/modules.html b/documentation/test_doxygen/compound_since/modules.html new file mode 100644 index 00000000..0c49d815 --- /dev/null +++ b/documentation/test_doxygen/compound_since/modules.html @@ -0,0 +1,75 @@ + + + + + My Project + + + + + +
    +
    +
    +
    +
    +

    Modules

    + + +
    +
    +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/namespaceDeprecatedFoo.html b/documentation/test_doxygen/compound_since/namespaceDeprecatedFoo.html new file mode 100644 index 00000000..6373de20 --- /dev/null +++ b/documentation/test_doxygen/compound_since/namespaceDeprecatedFoo.html @@ -0,0 +1,174 @@ + + + + + DeprecatedFoo namespace | My Project + + + + + +
    +
    +
    +
    +
    +

    + DeprecatedFoo namespace +

    +

    A namespace.

    +
    +

    Contents

    + +
    + +
    +

    Classes

    +
    +
    + class DeprecatedClass deprecated since 2010.02 +
    +
    A class.
    +
    + struct DeprecatedSubclass deprecated since 2010.02 +
    +
    A subclass.
    +
    +
    +
    +

    Enums

    +
    +
    + enum DeprecatedEnum { DeprecatedOldValue = 0 deprecated since 2010.02, + NewValue = 3 } deprecated since 2010.02 +
    +
    An enum.
    +
    +
    +
    +

    Typedefs

    +
    +
    + using DeprecatedKlazz = DeprecatedClass deprecated since 2010.02 +
    +
    A typedef.
    +
    +
    +
    +

    Functions

    +
    +
    + void deprecatedFoo() deprecated since 2010.02 +
    +
    A function.
    +
    +
    +
    +

    Variables

    +
    +
    + int DeprecatedFive deprecated since 2010.02 constexpr +
    +
    A constant.
    +
    +
    +
    +

    Enum documentation

    +
    +

    + enum DeprecatedFoo::DeprecatedEnum + +

    +

    An enum.

    +

    Details should have the badge too.

    + + + + + + + + + + + + +
    Enumerators
    DeprecatedOldValue +

    This thing is deprecated.

    Yes.

    +
    NewValue +
    +
    +
    +
    +

    Typedef documentation

    +
    +

    + typedef DeprecatedClass DeprecatedFoo::DeprecatedKlazz + +

    +

    A typedef.

    +

    Details should have the badge too.

    +
    +
    +
    +

    Function documentation

    +
    +

    + void DeprecatedFoo::deprecatedFoo() + +

    +

    A function.

    +

    Details should have the badge too.

    +
    +
    +
    +

    Variable documentation

    +
    +

    + int DeprecatedFoo::DeprecatedFive constexpr + +

    +

    A constant.

    +

    Details should have the badge too.

    +
    +
    +
    +
    +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/namespaceFoo.html b/documentation/test_doxygen/compound_since/namespaceFoo.html new file mode 100644 index 00000000..4254b62e --- /dev/null +++ b/documentation/test_doxygen/compound_since/namespaceFoo.html @@ -0,0 +1,173 @@ + + + + + Foo namespace | My Project + + + + + +
    +
    +
    +
    +
    +

    + Foo namespace since 2010.02 +

    +

    A namespace.

    +
    +

    Contents

    + +
    +
    +

    Classes

    +
    +
    + class Class since 2019.11 +
    +
    A class.
    +
    + struct Subclass since 2019.11 +
    +
    A subclass.
    +
    +
    +
    +

    Enums

    +
    +
    + enum Enum { OldValue = 0, + NewValue = 3 since 2019.11 } since 2010.02 +
    +
    An enum.
    +
    +
    +
    +

    Typedefs

    +
    +
    + using Klazz = Class since 2010.02 +
    +
    A typedef.
    +
    +
    +
    +

    Functions

    +
    +
    + void foo() since 2010.02 +
    +
    A function.
    +
    +
    +
    +

    Variables

    +
    +
    + int Five constexpr since 2010.02 +
    +
    A constant.
    +
    +
    +
    +

    Enum documentation

    +
    +

    + enum Foo::Enum since 2010.02 + +

    +

    An enum.

    +

    Details should have the badge too.

    + + + + + + + + + + + + +
    Enumerators
    OldValue +
    NewValue since 2019.11 +

    This thing is new.

    Yes.

    +
    +
    +
    +
    +

    Typedef documentation

    +
    +

    + typedef Class Foo::Klazz since 2010.02 + +

    +

    A typedef.

    +

    Details should have the badge too.

    +
    +
    +
    +

    Function documentation

    +
    +

    + void Foo::foo() since 2010.02 + +

    +

    A function.

    +

    Details should have the badge too.

    +
    +
    +
    +

    Variable documentation

    +
    +

    + int Foo::Five constexpr since 2010.02 + +

    +

    A constant.

    +

    Details should have the badge too.

    +
    +
    +
    +
    +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/namespaces.html b/documentation/test_doxygen/compound_since/namespaces.html new file mode 100644 index 00000000..0800f35c --- /dev/null +++ b/documentation/test_doxygen/compound_since/namespaces.html @@ -0,0 +1,65 @@ + + + + + My Project + + + + + +
    +
    +
    +
    +
    +

    Namespaces

    + + +
    +
    +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/pages.dox b/documentation/test_doxygen/compound_since/pages.dox new file mode 100644 index 00000000..6aa3944c --- /dev/null +++ b/documentation/test_doxygen/compound_since/pages.dox @@ -0,0 +1,54 @@ +/** @page a This is new. + +Yes. + +@m_since{2019,11} + +*/ + +/** @page deprecated-a This is old. + +Yes. + +@m_deprecated_since{2010,02} Yes it is. + +*/ + +/** @page changelog Changelog + +@section changelog-2019-11 Version 2019.11 + +Stuff happened. + +@section changelog-2010-02 Version 2010.02 + +Ages ago. Who knows. +*/ + +/** @defgroup group A group + +@m_since{2019,11} + +Detailed description. + +@defgroup subgroup A subgroup +@ingroup group + +@m_since{2019,11} + +More. +*/ + +/** @defgroup deprecated-group A group + +@m_deprecated_since{2010,02} Yes it is. + +Detailed description. + +@defgroup deprecated-subgroup A subgroup +@ingroup deprecated-group + +More. + +@m_deprecated_since{2019,11} Yep. +*/ diff --git a/documentation/test_doxygen/compound_since/pages.html b/documentation/test_doxygen/compound_since/pages.html new file mode 100644 index 00000000..1e206169 --- /dev/null +++ b/documentation/test_doxygen/compound_since/pages.html @@ -0,0 +1,67 @@ + + + + + My Project + + + + + +
    +
    +
    +
    +
    +

    Pages

    + + +
    +
    +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/structDeprecatedFoo_1_1DeprecatedSubclass.html b/documentation/test_doxygen/compound_since/structDeprecatedFoo_1_1DeprecatedSubclass.html new file mode 100644 index 00000000..a5f49f89 --- /dev/null +++ b/documentation/test_doxygen/compound_since/structDeprecatedFoo_1_1DeprecatedSubclass.html @@ -0,0 +1,59 @@ + + + + + DeprecatedFoo::DeprecatedSubclass struct | My Project + + + + + +
    +
    + + diff --git a/documentation/test_doxygen/compound_since/structFoo_1_1Subclass.html b/documentation/test_doxygen/compound_since/structFoo_1_1Subclass.html new file mode 100644 index 00000000..22390d94 --- /dev/null +++ b/documentation/test_doxygen/compound_since/structFoo_1_1Subclass.html @@ -0,0 +1,58 @@ + + + + + Foo::Subclass struct | My Project + + + + + +
    +
    + + diff --git a/documentation/test_doxygen/test_compound.py b/documentation/test_doxygen/test_compound.py index 15422e0c..ace70e42 100644 --- a/documentation/test_doxygen/test_compound.py +++ b/documentation/test_doxygen/test_compound.py @@ -326,3 +326,37 @@ class BaseDerivedInRootNamespace(IntegrationTestCase): # Shouldn't crash or anything self.assertEqual(*self.actual_expected_contents('structNamespace_1_1BothBaseAndDerivedInRootNamespace.html')) + +class Since(IntegrationTestCase): + def __init__(self, *args, **kwargs): + super().__init__(__file__, 'since', *args, **kwargs) + + def test(self): + self.run_doxygen(wildcard='*.xml') + + # Verify all entries and details get the Since badge with a link to + # changelog. Not class/namespace/file/dir entries yet because we don't + # propagate those right now. + self.assertEqual(*self.actual_expected_contents('dir_4b0d5f8864bf89936129251a2d32609b.html')) + self.assertEqual(*self.actual_expected_contents('Class_8h.html')) + self.assertEqual(*self.actual_expected_contents('group__group.html')) + self.assertEqual(*self.actual_expected_contents('namespaceFoo.html')) + self.assertEqual(*self.actual_expected_contents('classFoo_1_1Class.html')) + self.assertEqual(*self.actual_expected_contents('structFoo_1_1Subclass.html')) + self.assertEqual(*self.actual_expected_contents('a.html')) + + # And these should have an extended deprecation badge + self.assertEqual(*self.actual_expected_contents('dir_73d1500434dee6f1c83b12ee799c54af.html')) + self.assertEqual(*self.actual_expected_contents('DeprecatedClass_8h.html')) + self.assertEqual(*self.actual_expected_contents('group__deprecated-group.html')) + self.assertEqual(*self.actual_expected_contents('namespaceDeprecatedFoo.html')) + self.assertEqual(*self.actual_expected_contents('classDeprecatedFoo_1_1DeprecatedClass.html')) + self.assertEqual(*self.actual_expected_contents('structDeprecatedFoo_1_1DeprecatedSubclass.html')) + self.assertEqual(*self.actual_expected_contents('deprecated-a.html')) + + # The listings should have both + self.assertEqual(*self.actual_expected_contents('annotated.html')) + self.assertEqual(*self.actual_expected_contents('files.html')) + self.assertEqual(*self.actual_expected_contents('modules.html')) + self.assertEqual(*self.actual_expected_contents('namespaces.html')) + self.assertEqual(*self.actual_expected_contents('pages.html')) diff --git a/documentation/test_doxygen/test_doxyfile.py b/documentation/test_doxygen/test_doxyfile.py index 0a9a7adb..7e522fa2 100644 --- a/documentation/test_doxygen/test_doxyfile.py +++ b/documentation/test_doxygen/test_doxyfile.py @@ -75,6 +75,7 @@ copy a link to the result using ⌘ """, 'M_SHOW_UNDOCUMENTED': False, 'M_THEME_COLOR': '#22272e', + 'M_VERSION_LABELS': False, 'OUTPUT_DIRECTORY': '', 'PROJECT_BRIEF': 'is cool', 'PROJECT_LOGO': '',