# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Path setup --------------------------------------------------------------

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import json
import datetime
import runpy
import sys
import subprocess
import pathlib

# -- Project information -----------------------------------------------------

project = "Awkward Array"
copyright = f"{datetime.datetime.now().year}, Awkward Array development team"
author = "Jim Pivarski"

# -- General configuration ---------------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named "sphinx.ext.*") or your custom
# ones.
extensions = [
    "sphinx_copybutton",
    "sphinx_design",
    "sphinx_external_toc",
    "sphinx.ext.intersphinx",
    "myst_nb",
    # Preserve old links
    "sphinx_reredirects",
    "jupyterlite_sphinx",
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ["_build", "_templates", "Thumbs.db", "jupyter_execute", ".*"]

# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#
html_context = {
    "github_user": "scikit-hep",
    "github_repo": "awkward",
    # TODO: set this
    "github_version": os.environ.get("READTHEDOCS_VERSION", "main"),
    "doc_path": "docs-sphinx",
}
html_theme = "pydata_sphinx_theme"
html_show_sourcelink = True
html_theme_options = {
    "logo": {
        "image_light": "image/logo-300px.png",
        "image_dark": "image/logo-300px-white.png",
    },
    "github_url": "https://github.com/scikit-hep/awkward",
    # Add light/dark mode and documentation version switcher:
    "navbar_end": ["theme-switcher", "navbar-icon-links"],
    "footer_items": ["copyright", "sphinx-version", "funding"],
    "icon_links": [
        {
            "name": "PyPI",
            "url": "https://pypi.org/project/awkward",
            "icon": "fab fa-python",
        }
    ],
    "use_edit_page_button": True,
    "external_links": [
        {
            "name": "Contributor guide",
            "url": "https://github.com/scikit-hep/awkward/blob/main/CONTRIBUTING.md",
        },
        {
            "name": "Release history",
            "url": "https://github.com/scikit-hep/awkward/releases",
        },
    ],
}

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]
html_css_files = ["css/awkward.css"]

# MyST settings
myst_enable_extensions = [
    "colon_fence",
]

nb_execution_mode = "cache"
nb_execution_raise_on_error = True
# unpkg is currently _very_ slow
nb_ipywidgets_js = {
    # Load RequireJS, used by the IPywidgets for dependency management
    "https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js": {
        "integrity": "sha256-Ae2Vz/4ePdIu6ZyI/5ZGsYnb+m0JlOmKPjt6XZ9JJkA=",
        "crossorigin": "anonymous",
    },
    # Load IPywidgets bundle for embedding.
    "https://cdn.jsdelivr.net/npm/@jupyter-widgets/html-manager@0.20.0/dist/embed-amd.js": {
        "data-jupyter-widgets-cdn": "https://cdn.jsdelivr.net/npm/",
        "crossorigin": "anonymous",
    },
}
# Additional stuff
master_doc = "index"

# Cross-reference existing Python objects
intersphinx_mapping = {
    "python": ("https://docs.python.org/3/", None),
    "pandas": ("https://pandas.pydata.org/pandas-docs/stable", None),
    "numpy": ("https://numpy.org/doc/stable", None),
    "scipy": ("https://docs.scipy.org/doc/scipy", None),
    "numba": ("https://numba.pydata.org/numba-doc/latest", None),
    "arrow": ("https://arrow.apache.org/docs/", None),
    "jax": ("https://jax.readthedocs.io/en/latest", None),
}

# Preserve legacy routes
with open("redirects.json") as f:
    redirects = json.load(f)

redirect_html_template_file = "_templates/redirect.html"

# JupyterLite configuration
jupyterlite_dir = "./lite"
# Don't override ipynb format
jupyterlite_bind_ipynb_suffix = False
# We've disabled localstorage, so we must provide the contents explicitly
jupyterlite_contents = ["getting-started/demo/*"]

HERE = pathlib.Path(__file__).parent

# Generate C++ bindings
subprocess.check_call(
    ["doxygen", str(HERE.parent / "docs-doxygen" / "Doxyfile")], cwd=HERE.parent
)

# Generate Python docstrings
runpy.run_path(HERE / "prepare_docstrings.py", run_name="__main__")

# Generate kernel docs
runpy.run_path(HERE.parent / "dev" / "generate-kerneldocs.py", run_name="__main__")

docs-sphinx/conf.py
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Path setup --------------------------------------------------------------

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import json
import datetime
import runpy
import sys
import subprocess
import pathlib

# -- Project information -----------------------------------------------------

project = "Awkward Array"
copyright = f"{datetime.datetime.now().year}, Awkward Array development team"
author = "Jim Pivarski"

# -- General configuration ---------------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named "sphinx.ext.*") or your custom
# ones.
extensions = [
    "sphinx_copybutton",
    "sphinx_design",
    "sphinx_external_toc",
    "sphinx.ext.intersphinx",
    "myst_nb",
    # Preserve old links
    "sphinx_reredirects",
    "jupyterlite_sphinx",
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ["_build", "_templates", "Thumbs.db", "jupyter_execute", ".*"]

# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#
html_context = {
    "github_user": "scikit-hep",
    "github_repo": "awkward",
    # TODO: set this
    "github_version": os.environ.get("READTHEDOCS_VERSION", "main"),
    "doc_path": "docs-sphinx",
}
html_theme = "pydata_sphinx_theme"
html_show_sourcelink = True
html_theme_options = {
    "logo": {
        "image_light": "image/logo-300px.png",
        "image_dark": "image/logo-300px-white.png",
    },
    "github_url": "https://github.com/scikit-hep/awkward",
    # Add light/dark mode and documentation version switcher:
    "navbar_end": ["theme-switcher", "navbar-icon-links"],
    "footer_items": ["copyright", "sphinx-version", "funding"],
    "icon_links": [
        {
            "name": "PyPI",
            "url": "https://pypi.org/project/awkward",
            "icon": "fab fa-python",
        }
    ],
    "use_edit_page_button": True,
    "external_links": [
        {
            "name": "Contributor guide",
            "url": "https://github.com/scikit-hep/awkward/blob/main/CONTRIBUTING.md",
        },
        {
            "name": "Release history",
            "url": "https://github.com/scikit-hep/awkward/releases",
        },
    ],
    "analytics": {
        "plausible_analytics_domain": "awkward-array.org",
        "plausible_analytics_url": "https://views.scientific-python.org/js/plausible.js"
    }
}

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]
html_css_files = ["css/awkward.css"]

# MyST settings
myst_enable_extensions = [
    "colon_fence",
]

nb_execution_mode = "cache"
nb_execution_raise_on_error = True
# unpkg is currently _very_ slow
nb_ipywidgets_js = {
    # Load RequireJS, used by the IPywidgets for dependency management
    "https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js": {
        "integrity": "sha256-Ae2Vz/4ePdIu6ZyI/5ZGsYnb+m0JlOmKPjt6XZ9JJkA=",
        "crossorigin": "anonymous",
    },
    # Load IPywidgets bundle for embedding.
    "https://cdn.jsdelivr.net/npm/@jupyter-widgets/html-manager@0.20.0/dist/embed-amd.js": {
        "data-jupyter-widgets-cdn": "https://cdn.jsdelivr.net/npm/",
        "crossorigin": "anonymous",
    },
}
# Additional stuff
master_doc = "index"

# Cross-reference existing Python objects
intersphinx_mapping = {
    "python": ("https://docs.python.org/3/", None),
    "pandas": ("https://pandas.pydata.org/pandas-docs/stable", None),
    "numpy": ("https://numpy.org/doc/stable", None),
    "scipy": ("https://docs.scipy.org/doc/scipy", None),
    "numba": ("https://numba.pydata.org/numba-doc/latest", None),
    "arrow": ("https://arrow.apache.org/docs/", None),
    "jax": ("https://jax.readthedocs.io/en/latest", None),
}

# Preserve legacy routes
with open("redirects.json") as f:
    redirects = json.load(f)

redirect_html_template_file = "_templates/redirect.html"

# JupyterLite configuration
jupyterlite_dir = "./lite"
# Don't override ipynb format
jupyterlite_bind_ipynb_suffix = False
# We've disabled localstorage, so we must provide the contents explicitly
jupyterlite_contents = ["getting-started/demo/*"]

HERE = pathlib.Path(__file__).parent

# Generate C++ bindings
subprocess.check_call(
    ["doxygen", str(HERE.parent / "docs-doxygen" / "Doxyfile")], cwd=HERE.parent
)

# Generate Python docstrings
runpy.run_path(HERE / "prepare_docstrings.py")

# Generate kernel docs
runpy.run_path(HERE.parent / "dev" / "generate-kerneldocs.py")

docs-sphinx/conf.py
diff --git a/docs-sphinx/conf.py b/docs-sphinx/conf.py
index d6fdfda12e..8f822be792 100644
--- a/docs-sphinx/conf.py
+++ b/docs-sphinx/conf.py
@@ -89,6 +89,10 @@
             "url": "https://github.com/scikit-hep/awkward/releases",
         },
     ],
+    "analytics": {
+        "plausible_analytics_domain": "awkward-array.org",
+        "plausible_analytics_url": "https://views.scientific-python.org/js/plausible.js"
+    }
 }
 
 # Add any paths that contain custom static files (such as style sheets) here,

Add statistics tracker to the new website
### Which documentation?

Tutorials site

### What needs to be documented?

Stefan gave us a `data-domain` for Plausible; we should add this text

```html
<script defer data-domain="awkward-array.org" src="https://views.scientific-python.org/js/plausible.js"></script>
```

to every HTML page. The HTML is generated by Sphinx, so it has to go into a template somewhere. I think we don't actually have the default HTML templates; I think that all of the HTML in [docs-sphinx/_templates](https://github.com/scikit-hep/awkward/tree/main/docs-sphinx/_templates) is an override. For instance, the [breadcrumbs.html](https://github.com/scikit-hep/awkward/blob/main/docs-sphinx/_templates/breadcrumbs.html) is just to eliminate something that would be on the default page (the "fork me on GitHub" ribbon?).

@agoose77, you've recently added [funding.html](https://github.com/scikit-hep/awkward/blob/main/docs-sphinx/_templates/funding.html), which appears at the bottom of every page. (I just checked.) If the `<script>` is added there, I think it would reach every page.

Except redirects. The [redirect.html](https://github.com/scikit-hep/awkward/blob/main/docs-sphinx/_templates/redirect.html) describes an entire page. It's debatable whether we'd want to count redirects. It would tell us how many people are using old URLs versus new URLs, but I don't see how useful that information is, and it would have to be disaggregated from the totals, since redirected links shouldn't be counted twice if we're interested in how many people went to a given _topic_ (not _page_). I vote for no statistics on redirects, and I'm not even sure if the script will work if the redirect happens through the meta mechanism (because such an access has `<noscript>`.

Arguably, a `<script>` element ought to go in the HTML `<head>`, rather than the `<body>` (`footer.html`). That's where I usually see them. Actually, I stand corrected: they're legal anywhere, and there are reasons to put them in the `<body>`. [This StackOverflow post](https://stackoverflow.com/a/24070373/1623645) presents the pros and cons: page rendering will pause while a script is being downloaded an executed, and that's no good. We could follow that page's "antiquated recommendation" by putting the `<script>` at the end of the page (`footer.html`); the reason against it doesn't apply: we don't need the statistics-counter script to run to render the page—that can happen late. The "modern approach" is to use `async` or `defer`, which I just noticed is in our snippet, so there are no constraints on when this snippet can be placed. (And it could be `async`, rather than `defer`, because we don't care whether it runs before or after other scripts on the page.)

The only argument I can see for putting it in the `<head>`, then, is that if the statistics-counter starts too late, we could undercount our bounce rate: users click the back button before rendering gets to the `<script>` and the page view gets counted. There will always be some cut-off in the bounce rate, much like $p_T$ in a tracking distribution, since very small values are hard to measure. Having a lower implicit cut on bounce rate, rather than a higher implicit cut, doesn't sound very important to me.

Trying to get it into the `<head>` would mean overloading more templates, and I don't like to overload Sphinx templates because it means we no longer get version updates for that part of the page, and who knows if the template designer intends some relationship between two parts of a page, starting with a particular version number? So I'm in favor of adding the `<script>` to `footer.html`, and `defer` may be replaced by `async` just to loosen an unnecessary constraint for the browser.

Sorry for the long-winded write-up; just thinking through the issues while I type!

Oh, one last thing: let's add the statistics-counter to the new documentation _only_. In other words, _not_ the one with the `latest` tag. The v1 documentation (`latest`) is split between two sites, I don't want to add it to the Netlify site, and the statistics will be easier to interpret if we have it on only one site: we'll know what page is meant by a given URL. We should also see the turn-on curve when the new documentation goes public. If we include the old documentation, we might not be able to filter it out of the statistics, since some of the URLs are the same.
