docs: fix crossrefs and allow function parameters to be referenced (#1585)

This fixes several old cross references from when the docs were plain
stardoc generated markdown files.

Also fixes how function parameters create their reference name so they
can be referenced.

Also formats conf.py to reduce future diffs. The only semantic change to
conf.py is
removing the suppressing of warnings.
diff --git a/docs/sphinx/_includes/py_console_script_binary.md b/docs/sphinx/_includes/py_console_script_binary.md
index bf2fa64..7373c8a 100644
--- a/docs/sphinx/_includes/py_console_script_binary.md
+++ b/docs/sphinx/_includes/py_console_script_binary.md
@@ -60,5 +60,5 @@
 ```
 
 [specification]: https://packaging.python.org/en/latest/specifications/entry-points/
-[`py_console_script_binary.binary_rule`]: #py_console_script_binary-binary_rule
+[`py_console_script_binary.binary_rule`]: #py_console_script_binary_binary_rule
 
diff --git a/docs/sphinx/conf.py b/docs/sphinx/conf.py
index cfc819f..e9af97a 100644
--- a/docs/sphinx/conf.py
+++ b/docs/sphinx/conf.py
@@ -32,25 +32,29 @@
 # Adapted from the template code:
 # https://github.com/readthedocs/readthedocs.org/blob/main/readthedocs/doc_builder/templates/doc_builder/conf.py.tmpl
 if os.environ.get("READTHEDOCS") == "True":
-  # Must come first because it can interfere with other extensions, according
-  # to the original conf.py template comments
-  extensions.insert(0, "readthedocs_ext.readthedocs")
+    # Must come first because it can interfere with other extensions, according
+    # to the original conf.py template comments
+    extensions.insert(0, "readthedocs_ext.readthedocs")
 
-  if os.environ.get("READTHEDOCS_VERSION_TYPE") == "external":
-    # Insert after the main extension
-    extensions.insert(1, "readthedocs_ext.external_version_warning")
-    readthedocs_vcs_url = "http://github.com/bazelbuild/rules_python/pull/{}".format(
-        os.environ.get("READTHEDOCS_VERSION", "")
-    )
-    # The build id isn't directly available, but it appears to be encoded
-    # into the host name, so we can parse it from that. The format appears
-    # to be `build-X-project-Y-Z`, where:
-    # * X is an integer build id
-    # * Y is an integer project id
-    # * Z is the project name
-    _build_id = os.environ.get("HOSTNAME", "build-0-project-0-rules-python")
-    _build_id = _build_id.split("-")[1]
-    readthedocs_build_url = f"https://readthedocs.org/projects/rules-python/builds/{_build_id}"
+    if os.environ.get("READTHEDOCS_VERSION_TYPE") == "external":
+        # Insert after the main extension
+        extensions.insert(1, "readthedocs_ext.external_version_warning")
+        readthedocs_vcs_url = (
+            "http://github.com/bazelbuild/rules_python/pull/{}".format(
+                os.environ.get("READTHEDOCS_VERSION", "")
+            )
+        )
+        # The build id isn't directly available, but it appears to be encoded
+        # into the host name, so we can parse it from that. The format appears
+        # to be `build-X-project-Y-Z`, where:
+        # * X is an integer build id
+        # * Y is an integer project id
+        # * Z is the project name
+        _build_id = os.environ.get("HOSTNAME", "build-0-project-0-rules-python")
+        _build_id = _build_id.split("-")[1]
+        readthedocs_build_url = (
+            f"https://readthedocs.org/projects/rules-python/builds/{_build_id}"
+        )
 
 exclude_patterns = ["_includes/*"]
 templates_path = ["_templates"]
@@ -103,22 +107,21 @@
     # * For RTD builds, the flyout menu is always automatically injected,
     #   so having it be True makes the flyout show up twice.
     "READTHEDOCS": False,
-    'PRODUCTION_DOMAIN': "readthedocs.org",
+    "PRODUCTION_DOMAIN": "readthedocs.org",
     # This is the path to a page's source (after the github user/repo/commit)
     "conf_py_path": "/docs/sphinx/",
-    'github_user': 'bazelbuild',
-    'github_repo': 'rules_python',
+    "github_user": "bazelbuild",
+    "github_repo": "rules_python",
     # The git version that was checked out, e.g. the tag or branch name
-    'github_version': os.environ.get("READTHEDOCS_GIT_IDENTIFIER", ""),
+    "github_version": os.environ.get("READTHEDOCS_GIT_IDENTIFIER", ""),
     # For local builds, the github link won't work. Disabling it replaces
     # it with a "view source" link to view the source Sphinx saw, which
     # is useful for local development.
-    'display_github': os.environ.get("READTHEDOCS") == "True",
-    'commit': os.environ.get("READTHEDOCS_GIT_COMMIT_HASH", "unknown commit"),
-
+    "display_github": os.environ.get("READTHEDOCS") == "True",
+    "commit": os.environ.get("READTHEDOCS_GIT_COMMIT_HASH", "unknown commit"),
     # Used by readthedocs_ext.external_version_warning extension
     # This is the PR number being built
-    'current_version': os.environ.get("READTHEDOCS_VERSION", ""),
+    "current_version": os.environ.get("READTHEDOCS_VERSION", ""),
 }
 
 # Keep this in sync with the stardoc templates
@@ -136,10 +139,12 @@
 # -- Options for EPUB output
 epub_show_urls = "footnote"
 
-suppress_warnings = ["myst.header", "myst.xref_missing"]
+suppress_warnings = []
+
 
 def setup(app):
-  # Pygments says it supports starlark, but it doesn't seem to actually
-  # recognize `starlark` as a name. So just manually map it to python.
-  from sphinx.highlighting import lexer_classes
-  app.add_lexer('starlark', lexer_classes['python'])
+    # Pygments says it supports starlark, but it doesn't seem to actually
+    # recognize `starlark` as a name. So just manually map it to python.
+    from sphinx.highlighting import lexer_classes
+
+    app.add_lexer("starlark", lexer_classes["python"])
diff --git a/docs/sphinx/pip.md b/docs/sphinx/pip.md
index 180d0b4..34248d2 100644
--- a/docs/sphinx/pip.md
+++ b/docs/sphinx/pip.md
@@ -1,10 +1,9 @@
 (pip-integration)=
 # Pip Integration
 
-To pull in dependencies from PyPI, the `pip_parse` macro is used.
+To pull in dependencies from PyPI, the `pip_parse` function is used, which
+invokes `pip` to download and install dependencies from PyPI.
 
-
-This macro wraps the [`pip_repository`](./pip_repository.md) rule that invokes `pip`.
 In your WORKSPACE file:
 
 ```starlark
diff --git a/docs/sphinx/pypi-dependencies.md b/docs/sphinx/pypi-dependencies.md
index 9838f29..ab32609 100644
--- a/docs/sphinx/pypi-dependencies.md
+++ b/docs/sphinx/pypi-dependencies.md
@@ -3,8 +3,9 @@
 Using PyPI packages (aka "pip install") involves two main steps.
 
 1. [Installing third party packages](#installing-third-party-packages)
-2. [Using third party packages as dependencies](#using-third-party-packages-as-dependencies)
+2. [Using third party packages as dependencies](#using-third-party-packages)
 
+{#installing-third-party-packages}
 ## Installing third party packages
 
 ### Using bzlmod
@@ -77,6 +78,7 @@
 existing `requirements.txt` with a fully resolved set of dependencies using a
 tool such as `pip-tools` or the `compile_pip_requirements` repository rule.
 
+{#using-third-party-packages}
 ## Using third party packages as dependencies
 
 Each extracted wheel repo contains a `py_library` target representing
diff --git a/python/packaging.bzl b/python/packaging.bzl
index 48423e3..f811965 100644
--- a/python/packaging.bzl
+++ b/python/packaging.bzl
@@ -66,7 +66,7 @@
     implementation = _py_wheel_dist_impl,
     attrs = {
         "out": attr.string(doc = "name of the resulting directory", mandatory = True),
-        "wheel": attr.label(doc = "a [py_wheel rule](/docs/packaging.md#py_wheel_rule)", providers = [PyWheelInfo]),
+        "wheel": attr.label(doc = "a [py_wheel target](#py_wheel)", providers = [PyWheelInfo]),
     },
 )
 
@@ -115,9 +115,9 @@
     )
     ```
 
-    To publish the wheel to Pypi, the twine package is required.
-    rules_python doesn't provide twine itself, see https://github.com/bazelbuild/rules_python/issues/1016
-    However you can install it with pip_parse, just like we do in the WORKSPACE file in rules_python.
+    To publish the wheel to PyPI, the twine package is required.
+    rules_python doesn't provide twine itself, see [https://github.com/bazelbuild/rules_python/issues/1016].
+    However you can install it with [pip_parse](#pip_parse), just like we do in the WORKSPACE file in rules_python.
 
     Once you've installed twine, you can pass its label to the `twine` attribute of this macro,
     to get a "[name].publish" target.
diff --git a/python/pip.bzl b/python/pip.bzl
index 26e99fe..b6b8801 100644
--- a/python/pip.bzl
+++ b/python/pip.bzl
@@ -37,7 +37,7 @@
         requirements (Label): A 'requirements.txt' pip requirements file.
         name (str, optional): A unique name for the created external repository (default 'pip').
         allow_pip_install (bool, optional): change this to keep this rule working (default False).
-        **kwargs (dict): Additional arguments to the [`pip_repository`](./pip_repository.md) repository rule.
+        **kwargs (dict): Additional arguments to the [`pip_parse`](#pip_parse) repository rule.
     """
 
     if allow_pip_install:
diff --git a/python/pip_install/pip_repository.bzl b/python/pip_install/pip_repository.bzl
index f7c4656..07e3353 100644
--- a/python/pip_install/pip_repository.bzl
+++ b/python/pip_install/pip_repository.bzl
@@ -586,7 +586,6 @@
 Those dependencies become available in a generated `requirements.bzl` file.
 You can instead check this `requirements.bzl` file into your repo, see the "vendoring" section below.
 
-This macro wraps the [`pip_repository`](./pip_repository.md) rule that invokes `pip`.
 In your WORKSPACE file:
 
 ```starlark
diff --git a/python/private/py_wheel.bzl b/python/private/py_wheel.bzl
index 1f5792b..f451389 100644
--- a/python/private/py_wheel.bzl
+++ b/python/private/py_wheel.bzl
@@ -106,10 +106,10 @@
 Note that Bazel's output filename cannot include the stamp information, as outputs must be known
 during the analysis phase and the stamp data is available only during the action execution.
 
-The [`py_wheel`](/docs/packaging.md#py_wheel) macro produces a `.dist`-suffix target which creates a
+The [`py_wheel`](#py_wheel) macro produces a `.dist`-suffix target which creates a
 `dist/` folder containing the wheel with the stamped name, suitable for publishing.
 
-See [`py_wheel_dist`](/docs/packaging.md#py_wheel_dist) for more info.
+See [`py_wheel_dist`](#py_wheel_dist) for more info.
 """,
     ),
     "_stamp_flag": attr.label(
@@ -509,7 +509,7 @@
 py_wheel = rule(
     implementation = py_wheel_lib.implementation,
     doc = """\
-Internal rule used by the [py_wheel macro](/docs/packaging.md#py_wheel).
+Internal rule used by the [py_wheel macro](#py_wheel).
 
 These intentionally have the same name to avoid sharp edges with Bazel macros.
 For example, a `bazel query` for a user's `py_wheel` macro expands to `py_wheel` targets,
diff --git a/sphinxdocs/private/func_template.vm b/sphinxdocs/private/func_template.vm
index ee6a2bf..81dd203 100644
--- a/sphinxdocs/private/func_template.vm
+++ b/sphinxdocs/private/func_template.vm
@@ -32,8 +32,9 @@
 {.params-box}
 #end
 ## The .span wrapper is necessary so the trailing colon doesn't wrap
-:[${param.name}[¶](#$link){.headerlink}]{.span}: []{#$link}
-#if(!$param.getDefaultValue().isEmpty())(_default `${param.getDefaultValue()}`_) #end
+:[${param.name}[¶](#$link){.headerlink}]{.span}:
+  {#$link}
+#if(!$param.getDefaultValue().isEmpty())  (_default `${param.getDefaultValue()}`_) #end
 #if(!$param.docString.isEmpty())
   $param.docString.replaceAll("$nl", "$nl  ")
 #else
diff --git a/sphinxdocs/private/provider_template.vm b/sphinxdocs/private/provider_template.vm
index 55e6871..49ae894 100644
--- a/sphinxdocs/private/provider_template.vm
+++ b/sphinxdocs/private/provider_template.vm
@@ -19,6 +19,7 @@
 $providerInfo.docString
 
 #if ($hasFields)
+{#${pnl}_fields}
 **FIELDS** [¶](#${pnl}_fields){.headerlink}
 
 #foreach ($field in $providerInfo.getFieldInfoList())