diff options
author | Matthias Clasen <mclasen@redhat.com> | 2020-10-01 19:05:39 +0000 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2020-10-01 19:05:39 +0000 |
commit | a4a1e8ffa996922f01f846972bf4de817567fa6d (patch) | |
tree | 8e798085c0da8f59f6e1c95a34d48480955b85ed | |
parent | b6fa56d3760c2dff2f8f1950c21ae49d5a2eee67 (diff) | |
parent | 9ed9350cd96b9e6ec0a4d30f88933e448eb33f98 (diff) | |
download | gtk-doc-a4a1e8ffa996922f01f846972bf4de817567fa6d.tar.gz |
Merge branch 'gtk-doc-for-gtk4' into 'master'
Gtk doc for gtk4
See merge request GNOME/gtk-doc!59
-rw-r--r-- | NEWS | 10 | ||||
-rw-r--r-- | gtk-doc.xsl | 8 | ||||
-rw-r--r-- | gtkdoc/mkdb.py | 203 | ||||
-rw-r--r-- | gtkdoc/scan.py | 6 | ||||
-rw-r--r-- | gtkdoc/scangobj.py | 93 | ||||
-rw-r--r-- | meson.build | 2 | ||||
-rw-r--r-- | style/style.css | 16 | ||||
-rwxr-xr-x | tests/mkdb.py | 34 |
8 files changed, 346 insertions, 26 deletions
@@ -1,3 +1,13 @@ +GTK-Doc 1.33 (Oct 1 2020) +============= + +Support documenting GTK actions +Recognize GDK_DECLARE_ macros +Better table styling in html output +Use plain C types for basic types +Make builds more reproducible +Translation updates + GTK-Doc 1.32.1 (Aug 15 2019) =============== diff --git a/gtk-doc.xsl b/gtk-doc.xsl index 1a7a1ee..7d6530b 100644 --- a/gtk-doc.xsl +++ b/gtk-doc.xsl @@ -41,6 +41,7 @@ <xsl:param name="html.ext" select="'.html'"/> <xsl:param name="refentry.generate.name" select="0"/> <xsl:param name="refentry.generate.title" select="1"/> + <xsl:param name="abstract.notitle.enabled" select="1"/> <!-- don't generate all those link tags (very slow and hardly used) it does not show much effect as we have a user.head.content template <xsl:param name="html.extra.head.links" select="0" /> @@ -399,6 +400,7 @@ Get a newer version at http://docbook.sourceforge.net/projects/xsl/ <xsl:variable name="sect_derived_interfaces" select="./refsect1[@role='derived_interfaces']"/> <xsl:variable name="sect_implementations" select="./refsect1[@role='implementations']"/> <xsl:variable name="sect_properties" select="./refsect1[@role='properties']"/> + <xsl:variable name="sect_actions" select="./refsect1[@role='actions']"/> <xsl:variable name="sect_child_properties" select="./refsect1[@role='child_properties']"/> <xsl:variable name="sect_style_properties" select="./refsect1[@role='style_properties']"/> <xsl:variable name="sect_signal_proto" select="./refsect1[@role='signal_proto']"/> @@ -481,6 +483,12 @@ Get a newer version at http://docbook.sourceforge.net/projects/xsl/ <xsl:value-of select="./refsect1[@role='signal_proto']/title"/> </a></span> </xsl:if> + <xsl:if test="count($sect_actions) > 0"> + <span id="nav_properties">  <span class="dim">|</span>  + <a href="#{$section_id}.actions" class="shortcut"> + <xsl:value-of select="./refsect1[@role='actions']/title"/> + </a></span> + </xsl:if> </xsl:when> <!-- this is not yet very nice, as it requires all glossdic/indexdiv elements having a anchor element. maybe we can customize the xsl diff --git a/gtkdoc/mkdb.py b/gtkdoc/mkdb.py index 87fdf24..9a68da4 100644 --- a/gtkdoc/mkdb.py +++ b/gtkdoc/mkdb.py @@ -57,6 +57,11 @@ ArgBlurbs = [] # Docstring of the Arg. ArgDefaults = [] # Default value of the Arg. ArgRanges = [] # The range of the Arg type +ActionObjects = [] +ActionNames = [] +ActionParams = [] +ActionProperties = [] + # These global hashes store declaration info keyed on a symbol name. Declarations = {} DeclarationTypes = {} @@ -207,7 +212,7 @@ DB_REFENTRY = string.Template('''${header} <refpurpose>${short_desc}</refpurpose> </refnamediv> ${stability} -${functions_synop}${args_synop}${signals_synop}${object_anchors}${other_synop}${hierarchy}${prerequisites}${derived}${interfaces}${implementations} +${functions_synop}${args_synop}${signals_synop}${actions_synop}${object_anchors}${other_synop}${hierarchy}${prerequisites}${derived}${interfaces}${implementations} ${include_output} <refsect1 id="${section_id}.description" role="desc"> <title role="desc.title">Description</title> @@ -217,7 +222,7 @@ ${extralinks}${long_desc} <title role="details.title">Functions</title> ${functions_details} </refsect1> -${other_desc}${args_desc}${signals_desc}${see_also} +${other_desc}${args_desc}${signals_desc}${actions_desc}${see_also} </refentry> ''') @@ -285,6 +290,7 @@ def Run(options): ReadKnownSymbols(os.path.join(ROOT_DIR, MODULE + "-sections.txt")) ReadSignalsFile(os.path.join(ROOT_DIR, MODULE + ".signals")) ReadArgsFile(os.path.join(ROOT_DIR, MODULE + ".args")) + ReadActionsFile(os.path.join(ROOT_DIR, MODULE + ".actions")) obj_tree = ReadObjectHierarchy(os.path.join(ROOT_DIR, MODULE + ".hierarchy")) ReadInterfaces(os.path.join(ROOT_DIR, MODULE + ".interfaces")) ReadPrerequisites(os.path.join(ROOT_DIR, MODULE + ".prerequisites")) @@ -513,6 +519,8 @@ def OutputDB(file, options): args_desc = '' child_args_desc = '' style_args_desc = '' + actions_synop = '' + actions_desc = '' hierarchy_str = '' hierarchy = [] interfaces = '' @@ -627,6 +635,30 @@ def OutputDB(file, options): args_desc += make_refsect1_desc(style_args_desc, 'Style Property Details', section_id, 'style-property-details') + actions_synop = re.sub(r'^\n*', '', actions_synop) + actions_synop = re.sub(r'\n+$', '\n', actions_synop) + if actions_synop != '': + actions_synop = '''<refsect1 id="%s.actions" role="actions"> +<title role="actions.title">Actions</title> +<informaltable frame="none"> +<tgroup cols="3"> +<colspec colname="actions_none" colwidth="150px"/> +<colspec colname="actions_name" colwidth="300px"/> +<colspec colname="actions_param" colwidth="200px"/> +<tbody> +%s +</tbody> +</tgroup> +</informaltable> +</refsect1> +''' % (section_id, actions_synop) + actions_desc = trim_leading_and_trailing_nl(actions_desc) + actions_desc = '''<refsect1 id="%s.action-details" role="action_details"> +<title role="action_details.title">Action Details</title> +%s +</refsect1> +''' % (section_id, actions_desc) + hierarchy_str = AddTreeLineArt(hierarchy) if hierarchy_str != '': hierarchy_str = make_refsect1_desc('<screen>' + hierarchy_str + '\n</screen>', @@ -657,6 +689,7 @@ def OutputDB(file, options): functions_details, other_desc, signals_synop, signals_desc, args_synop, args_desc, + actions_synop, actions_desc, hierarchy_str, interfaces, implementations, prerequisites, derived, @@ -683,6 +716,8 @@ def OutputDB(file, options): args_desc = '' child_args_desc = '' style_args_desc = '' + actions_synop = '' + actions_desc = '' hierarchy_str = '' hierarchy = [] interfaces = '' @@ -721,6 +756,7 @@ def OutputDB(file, options): sig_synop, sig_desc = GetSignals(symbol) arg_synop, child_arg_synop, style_arg_synop, arg_desc, child_arg_desc, style_arg_desc = GetArgs( symbol) + action_synop, action_desc = GetActions(symbol) ifaces = GetInterfaces(symbol) impls = GetImplementations(symbol) prereqs = GetPrerequisites(symbol) @@ -735,6 +771,8 @@ def OutputDB(file, options): args_desc += arg_desc child_args_desc += child_arg_desc style_args_desc += style_arg_desc + actions_synop += action_synop + actions_desc += action_desc interfaces += ifaces implementations += impls prerequisites += prereqs @@ -905,6 +943,7 @@ def OutputIndex(basename, apiindex): logging.info("trying symbol %s", symbol) m1 = re.search(r'(.*)::(.*)', symbol) m2 = re.search(r'(.*):(.*)', symbol) + m3 = re.search(r'(.*)\|(.*)', symbol) if m1: oname = m1.group(1) osym = m1.group(2) @@ -929,6 +968,18 @@ def OutputIndex(basename, apiindex): symbol_section = SymbolSection[oname] symbol_section_id = SymbolSectionId[oname] break + elif m3: + oname = m3.group(1) + osym = m3.group(2) + logging.info(" trying action %s|%s in %d actions", oname, osym, len(ActionNames)) + for name in ActionNames: + logging.info(" " + name) + if name == osym: + symbol_type = "action" + if oname in SymbolSection: + symbol_section = SymbolSection[oname] + symbol_section_id = SymbolSectionId[oname] + break else: if symbol in SymbolSection: symbol_section = SymbolSection[symbol] @@ -1123,6 +1174,7 @@ def OutputDeclaration(symbol, declaration): """ dtype = DeclarationTypes[symbol] + logging.info('Output Symbol: "%s" "%s"', symbol, dtype) if dtype == 'MACRO': return OutputMacro(symbol, declaration) elif dtype == 'TYPEDEF': @@ -2051,7 +2103,7 @@ def ParseStabilityLevel(stability, file, line, message): return str(stability) -def OutputDBFile(file, title, section_id, includes, functions_synop, other_synop, functions_details, other_desc, signals_synop, signals_desc, args_synop, args_desc, hierarchy, interfaces, implementations, prerequisites, derived, file_objects, default_stability): +def OutputDBFile(file, title, section_id, includes, functions_synop, other_synop, functions_details, other_desc, signals_synop, signals_desc, args_synop, args_desc, actions_synop, actions_desc, hierarchy, interfaces, implementations, prerequisites, derived, file_objects, default_stability): """Outputs the final DocBook file for one section. Args: @@ -2068,6 +2120,8 @@ def OutputDBFile(file, title, section_id, includes, functions_synop, other_synop signal_desc (str): the DocBook for the Signal Description part args_synop (str): the DocBook for the Arg Synopsis part args_desc (str): the DocBook for the Arg Description part + actions_synop (str): the DocBook for the Action Synopsis part + actions_desc (str): the DocBook for the Action Description part hierarchy (str): the DocBook for the Object Hierarchy part interfaces (str): the DocBook for the Interfaces part implementations (str): the DocBook for the Known Implementations part @@ -2187,6 +2241,8 @@ def OutputDBFile(file, title, section_id, includes, functions_synop, other_synop # "<refentry id="$section_id" revision="$mday $month $year">" OUTPUT.write(DB_REFENTRY.substitute({ + 'actions_desc': actions_desc, + 'actions_synop': actions_synop, 'args_desc': args_desc, 'args_synop': args_synop, 'derived': derived, @@ -3601,6 +3657,72 @@ def GetArgs(gobject): return (synop, child_synop, style_synop, desc, child_desc, style_desc) +def GetActions(gobject): + """Generate action docs. + + Returns the synopsis and detailed description DocBook output + for the actions of a given GtkWidget subclass. + + Args: + object (str): the GObject subclass, e.g. 'GtkButton'. + + Returns: + str: action docs + """ + synop = '' + desc = '' + + for i in range(len(ActionObjects)): + if ActionObjects[i] == gobject: + logging.info("Found action: %s", ActionNames[i]) + name = ActionNames[i] + params = ActionParams[i] + prop = ActionProperties[i] + + # Remember: pipe, so we don't clash with signals. + symbol = '%s|%s' % (gobject, name) + sid = common.CreateValidSGMLID(symbol) + + AllSymbols[symbol] = 1 + blurb = '' + if symbol in SymbolDocs and not IsEmptyDoc(SymbolDocs[symbol]): + blurb = ConvertMarkDown(symbol, SymbolDocs[symbol]) + logging.info(".. [%s][%s]", SymbolDocs[symbol], blurb) + AllDocumentedSymbols[symbol] = 1 + + else: + # FIXME: print a warning? + logging.info(".. no description") + + pad1 = '' + if len(name) < 24: + pad1 = " " * (24 - len(name)) + + action_synop = "<row><entry></entry><entry role=\"action_name\"><link linkend=\"%s\">%s</link></entry><entry role=\"parameter_type\">%s</entry></row>\n" % ( + sid, name, params) + action_desc = u"<refsect2 id=\"%s\" role=\"action\"><title>The <literal>ā%sā</literal> action</title>\n" % ( + sid, name) + action_desc += MakeIndexterms(symbol, sid) + action_desc += "\n" + action_desc += OutputSymbolExtraLinks(symbol) + if blurb != '': + action_desc += blurb + elif prop != '': + action_desc += "<para>The %s action sets the %s property.</para>\n" % (name, MakeHashXRef (gobject + ':' + prop, "type")) + action_desc += MakeDeprecationNote(symbol) + + if params != '': + action_desc += "<para>Parameter type: %s</para>\n" % params + + action_desc += OutputParamDescriptions("ACTION", symbol, None) + action_desc += OutputSymbolTraits(symbol) + action_desc += "</refsect2>\n" + + synop += action_synop + desc += action_desc + + return (synop, desc) + def IgnorePath(path, source_dirs, ignore_files): for sdir in source_dirs: # Cut off base directory @@ -3763,9 +3885,18 @@ def SegmentCommentBlock(lines, line_number=0, ifile=''): logging.info("scanning[%s] :%s", in_part, line.strip()) # If we haven't found the symbol name yet, look for it. + # We need to allow for the following cases: + # function: + # Class::signal: + # Class:property: + # Class|action: + # Signal and property names can contain dashes, action names + # can contain period. + # In all cases, there might be annotations in parentheses + # following the symbol name. if not symbol: m1 = re.search(r'^\s*((SECTION|PROGRAM):\s*\S+)', line) - m2 = re.search(r'^\s*([\w:-]*\w)\s*:?\s*(\(.+?\)\s*)*$', line) + m2 = re.search(r'^\s*([\w:.|-]*\w)\s*:?\s*(\(.+?\)\s*)*$', line) if m1: symbol = m1.group(1) logging.info("docs found in source for : '%s'", symbol) @@ -4664,6 +4795,70 @@ def ReadArgsFile(ifile): INPUT.close() +def ReadActionsFile(ifile): + """Reads information about object actions + + It creates the arrays ActionObjects, ActionNames, ActionParams + and ActionProperties containing info on the actions. + + Args: + ifile (str): the input filename. + """ + in_action = False + action_object = None + action_name = None + action_param = None + action_prop = None + + # Reset the args info. + ActionObjects[:] = [] + ActionNames[:] = [] + ActionParams[:] = [] + ActionProperties[:] = [] + + if not os.path.isfile(ifile): + return + + INPUT = open(ifile, 'r', encoding='utf-8') + line_number = 0 + for line in INPUT: + line_number += 1 + if not in_action: + if line.startswith('<ACTION>'): + in_action = True + action_object = '' + action_name = '' + action_param = '' + action_prop = '' + + else: + m1 = re.search(r'^<NAME>(.*)</NAME>', line) + m2 = re.search(r'^<PARAMETER>(.*)</PARAMETER>', line) + m3 = re.search(r'^<PROPERTY>(.*)</PROPERTY>', line) + if m1: + action_name = m1.group(1) + m1_1 = re.search(r'^(.*):::(.*)$', action_name) + if m1_1: + action_object = m1_1.group(1) + action_name = m1_1.group(2).replace('_', '-') + logging.info("Found action: %s", action_name) + else: + common.LogWarning(ifile, line_number, "Invalid action name: " + action_name) + + elif m2: + action_param = m2.group(1) + elif m3: + action_prop = m3.group(1) + elif re.search(r'^</ACTION>', line): + logging.info("Found end of action: %s::%s", action_object, action_name) + ActionObjects.append(action_object) + ActionNames.append(action_name) + ActionParams.append(action_param) + ActionProperties.append(action_prop) + in_action = False + + INPUT.close() + def AddTreeLineArt(tree): """Generate a line art tree. diff --git a/gtkdoc/scan.py b/gtkdoc/scan.py index 6c6534a..4b5b8a9 100644 --- a/gtkdoc/scan.py +++ b/gtkdoc/scan.py @@ -111,8 +111,8 @@ CLINE_MATCHER = [ \s*\=""" % VAR_TYPE_MODIFIER, re.VERBOSE), # 17: G_DECLARE_* re.compile( - r""".*G_DECLARE_ - (FINAL_TYPE|DERIVABLE_TYPE|INTERFACE) # 1: variant + r""".*(G_DECLARE_|GDK_DECLARE_) + (FINAL_TYPE|DERIVABLE_TYPE|INTERNAL_TYPE|INTERFACE) # 1: variant \s*\(""", re.VERBOSE), # 18-21: FUNCTIONS None, # in InitScanner() @@ -733,7 +733,7 @@ def ScanHeaderContent(input_lines, decl_list, get_types, options): elif cm[17]: in_declaration = 'g-declare' - symbol = 'G_DECLARE_' + cm[17].group(1) + symbol = cm[17].group(1) + cm[17].group(2) decl = line[cm[17].end():] # FUNCTIONS diff --git a/gtkdoc/scangobj.py b/gtkdoc/scangobj.py index 003c517..bf4e1ea 100644 --- a/gtkdoc/scangobj.py +++ b/gtkdoc/scangobj.py @@ -100,6 +100,7 @@ const gchar *hierarchy_filename = "${new_hierarchy_filename}"; const gchar *interfaces_filename = "${new_interfaces_filename}"; const gchar *prerequisites_filename = "${new_prerequisites_filename}"; const gchar *args_filename = "${new_args_filename}"; +const gchar *actions_filename = "${new_actions_filename}"; static void output_signals (void); static void output_object_signals (FILE *fp, @@ -125,6 +126,9 @@ static void output_prerequisites (FILE *fp, static void output_args (void); static void output_object_args (FILE *fp, GType object_type); +static void output_actions (void); +static void output_object_actions (FILE *fp, GType object_type); + int main (${main_func_params}) { @@ -137,6 +141,7 @@ main (${main_func_params}) output_object_interfaces (); output_interface_prerequisites (); output_args (); + output_actions (); return 0; } @@ -334,29 +339,37 @@ get_type_name (GType type, gboolean * is_pointer) switch (type) { case G_TYPE_NONE: - case G_TYPE_CHAR: case G_TYPE_UCHAR: case G_TYPE_BOOLEAN: - case G_TYPE_INT: case G_TYPE_UINT: case G_TYPE_LONG: case G_TYPE_ULONG: - case G_TYPE_FLOAT: - case G_TYPE_DOUBLE: case G_TYPE_POINTER: /* These all have normal C type names so they are OK. */ return type_name; + case G_TYPE_CHAR: + return "char"; + + case G_TYPE_INT: + return "int"; + + case G_TYPE_FLOAT: + return "float"; + + case G_TYPE_DOUBLE: + return "double"; + case G_TYPE_STRING: /* A GtkString is really a gchar*. */ *is_pointer = TRUE; - return "gchar"; + return "char"; case G_TYPE_ENUM: case G_TYPE_FLAGS: /* We use a gint for both of these. Hopefully a subtype with a decent name will be registered and used instead, as GTK+ does itself. */ - return "gint"; + return "int"; case G_TYPE_BOXED: /* The boxed type shouldn't be used itself, only subtypes. Though we @@ -566,6 +579,71 @@ output_prerequisites (FILE *fp, } static void +output_actions (void) +{ + FILE *fp; + gint i; + + fp = fopen (actions_filename, "w"); + if (fp == NULL) { + g_warning ("Couldn't open output file: %s : %s", actions_filename, g_strerror(errno)); + return; + } + + for (i = 0; object_types[i]; i++) { + output_object_actions (fp, object_types[i]); + } + + fclose (fp); +} + +static void +output_object_actions (FILE *fp, GType object_type) +{ + gpointer class; + + if (!G_TYPE_IS_OBJECT (object_type)) + return; + + class = g_type_class_peek (object_type); + if (!class) + return; + +#ifdef GTK_IS_WIDGET_CLASS +#if GTK_CHECK_VERSION(3,96,0) + if (GTK_IS_WIDGET_CLASS (class)) { + guint i = 0; + const char *action_name; + GType owner; + const GVariantType *parameter_type; + const char *property_name; + const gchar *object_class_name; + + object_class_name = g_type_name (object_type); + while (gtk_widget_class_query_action (GTK_WIDGET_CLASS (class), + i, + &owner, + &action_name, + ¶meter_type, + &property_name)) { + i++; + if (owner == G_TYPE_FROM_CLASS (class)) + fprintf (fp, "<ACTION>\\n" + "<NAME>%s:::%s</NAME>\\n" + "<PARAMETER>%s</PARAMETER>\\n" + "<PROPERTY>%s</PROPERTY>\\n" + "</ACTION>\\n\\n", + object_class_name, + action_name, + parameter_type ? g_variant_type_peek_string (parameter_type) : "", + property_name ? property_name : ""); + } + } +#endif +#endif +} + +static void output_args (void) { FILE *fp; @@ -1225,6 +1303,8 @@ def run(options): new_prerequisites_filename = base_filename + '.prerequisites.new' old_args_filename = base_filename + '.args' new_args_filename = base_filename + '.args.new' + old_actions_filename = base_filename + '.actions' + new_actions_filename = base_filename + '.actions.new' # generate a C program to scan the types @@ -1335,5 +1415,6 @@ def run(options): common.UpdateFileIfChanged(old_interfaces_filename, new_interfaces_filename, False) common.UpdateFileIfChanged(old_prerequisites_filename, new_prerequisites_filename, False) common.UpdateFileIfChanged(old_args_filename, new_args_filename, False) + common.UpdateFileIfChanged(old_actions_filename, new_actions_filename, False) return 0 diff --git a/meson.build b/meson.build index 0345989..ba3e179 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gtk-doc', 'c', - version: '1.32.1', + version: '1.33.0', license: 'GPL2+', meson_version: '>= 0.50.0', # needed for https://mesonbuild.com/Python-module.html#path ) diff --git a/style/style.css b/style/style.css index 6f0bc25..e62807a 100644 --- a/style/style.css +++ b/style/style.css @@ -61,18 +61,6 @@ a:hover color: #729fcf; } -div.informaltable table -{ - border-collapse: separate; - border-spacing: 1em 0.3em; - border: none; -} - -div.informaltable table td, div.informaltable table th -{ - vertical-align: top; -} - .function_type, .variable_type, .property_type, @@ -127,6 +115,7 @@ td p margin: 0.25em; } +div.informaltable table[border="1"], div.table table { border-collapse: collapse; @@ -135,6 +124,8 @@ div.table table border: solid 1px #babdb6; } +div.informaltable table[border="1"] td, +div.informaltable table th, div.table table td, div.table table th { /* tango:aluminium 3 */ @@ -143,6 +134,7 @@ div.table table td, div.table table th vertical-align: top; } +div.informaltable table[border="1"] th, div.table table th { /* tango:aluminium 2 */ diff --git a/tests/mkdb.py b/tests/mkdb.py index d41bd8c..3f04fba 100755 --- a/tests/mkdb.py +++ b/tests/mkdb.py @@ -66,7 +66,35 @@ class ParseCommentBlock(ScanSourceContentTestCase): """).splitlines(keepends=True)) self.assertEqual({'symbol': 'Description.\n'}, mkdb.SourceSymbolDocs) + def test_FindsDocCommentForSignal(self): + mkdb.SourceSymbolDocs = {} + mkdb.ParseCommentBlock(textwrap.dedent("""\ + Class::signal-with-dashes: + + Description. + """).splitlines(keepends=True)) + self.assertEqual({'Class::signal-with-dashes': 'Description.\n'}, mkdb.SourceSymbolDocs) + + def test_FindsDocCommentForProperty(self): + mkdb.SourceSymbolDocs = {} + mkdb.ParseCommentBlock(textwrap.dedent("""\ + Class:property-with-dashes: + + Description. + """).splitlines(keepends=True)) + self.assertEqual({'Class:property-with-dashes': 'Description.\n'}, mkdb.SourceSymbolDocs) + + def test_FindsDocCommentForActions(self): + mkdb.SourceSymbolDocs = {} + mkdb.ParseCommentBlock(textwrap.dedent("""\ + Class|action.with.dots-and-dashes: + + Description. + """).splitlines(keepends=True)) + self.assertEqual({'Class|action.with.dots-and-dashes': 'Description.\n'}, mkdb.SourceSymbolDocs) + def test_FindsDocCommentWithParam(self): + mkdb.SourceSymbolDocs = {} mkdb.ParseCommentBlock(textwrap.dedent("""\ symbol: @par: value @@ -78,6 +106,7 @@ class ParseCommentBlock(ScanSourceContentTestCase): self.assertEqual({'par': 'value\n'}, mkdb.SourceSymbolParams['symbol']) def test_FindsDocCommentWithMultilineParam(self): + mkdb.SourceSymbolDocs = {} mkdb.ParseCommentBlock(textwrap.dedent("""\ symbol: @par: value docs with @@ -90,6 +119,7 @@ class ParseCommentBlock(ScanSourceContentTestCase): self.assertEqual({'par': 'value docs with\ntwo lines\n'}, mkdb.SourceSymbolParams['symbol']) def test_FindsDocCommentWithReturns(self): + mkdb.SourceSymbolDocs = {} mkdb.ParseCommentBlock(textwrap.dedent("""\ symbol: @@ -104,6 +134,7 @@ class ParseCommentBlock(ScanSourceContentTestCase): self.assertEqual({'Returns': ' result\n'}, mkdb.SourceSymbolParams['symbol']) def test_FindsDocCommentWithSince(self): + mkdb.SourceSymbolDocs = {} mkdb.ParseCommentBlock(textwrap.dedent("""\ symbol: @@ -113,6 +144,7 @@ class ParseCommentBlock(ScanSourceContentTestCase): self.assertEqual('0.1', mkdb.Since['symbol']) def test_FindsDocCommentWithDeprecated(self): + mkdb.SourceSymbolDocs = {} mkdb.ParseCommentBlock(textwrap.dedent("""\ symbol: @@ -123,6 +155,7 @@ class ParseCommentBlock(ScanSourceContentTestCase): self.assertEqual(' use function() instead\n', mkdb.Deprecated['symbol']) def test_FindsDocCommentWithStability(self): + mkdb.SourceSymbolDocs = {} mkdb.ParseCommentBlock(textwrap.dedent("""\ symbol: @@ -132,6 +165,7 @@ class ParseCommentBlock(ScanSourceContentTestCase): self.assertEqual('Stable', mkdb.StabilityLevel['symbol']) def test_HandlesHTMLEntities(self): + mkdb.SourceSymbolDocs = {} mkdb.ParseCommentBlock(textwrap.dedent("""\ symbol: |