docs: def add_search_index_criteria(prepend=False):
      """
      Add the search criteria used when calling :meth:`register() <cqparts.search.register>`
      on a :class:`Component <cqparts.Component>` as a table to the *docstring*.
  
      This is only intended to be used with *sphinx autodoc*.
  
      In your *sphinx* ``config.py`` file::
  
          from cqparts.utils.sphinx import add_search_index_criteria
          def setup(app):
              app.connect("autodoc-process-docstring", add_search_index_criteria())
  
      Then, when documenting your :class:`Part <cqparts.Part>` or
      :class:`Assembly <cqparts.Assembly>` the
      search criteria will also be documented in the output.
  
      :param prepend: if True, table is added to the beginning of the *docstring*.
                      otherwise, it's appended at the end.
      :type prepend: :class:`bool`
      """
  
      from ..search import class_criteria
      from .. import Component
  
      COLUMN_INFO = [
          # (<title>, <width>, <method>),
          ('Key', 50, lambda k, v: "``%s``" % k),
          ('Value', 10, lambda k, v: ', '.join("``%s``" % w for w in v)),
      ]  # note: last column width is irrelevant
  
      def param_lines(app, obj):
          doc_lines = []
  
          criteria = class_criteria.get(obj, {})
          row_seperator = ' '.join(('=' * w) for (_, w, _) in COLUMN_INFO)
  
          # Header
          if criteria:  # only add a header if it's relevant
              doc_lines += [
                  "**Search Criteria:**",
                  "",
                  "This object can be found with :meth:`find() <cqparts.search.find>` ",
                  "and :meth:`search() <cqparts.search.search>` using the following ",
                  "search criteria.",
                  "",
                  row_seperator,
                  ' '.join((("%%-%is" % w) % t) for (t, w, _) in COLUMN_INFO),
                  row_seperator,
              ]
  
          # Add criteria
          for (key, value) in sorted(criteria.items(), key=lambda x: x[0]):
              doc_lines.append(' '.join(
                  ("%%-%is" % w) % m(key, value)
                  for (_, w, m) in COLUMN_INFO
              ))
  
          # Footer
          if criteria:
              doc_lines += [
                  row_seperator,
                  "",
              ]
  
          return doc_lines
  
      # Conditions for running above `param_lines` function (in order)
      conditions = [  # (all conditions must be met)
          lambda o: type(o) == type,
          lambda o: o is not Component,
          lambda o: issubclass(o, Component),
      ]
  
      def callback(app, what, name, obj, options, lines):
          # sphinx callback
          # (this method is what actually gets sent to the sphinx runtime)
          if all(c(obj) for c in conditions):
              new_lines = param_lines(app, obj)
              _add_lines(lines, new_lines, prepend=prepend)
  
      return callback