diff --git a/source/_extensions/delta2.py b/source/_extensions/delta2.py new file mode 100644 index 0000000000..300fe9d01e --- /dev/null +++ b/source/_extensions/delta2.py @@ -0,0 +1,112 @@ +import os +from functools import wraps +from typing import Any, Dict + +from docutils import nodes +from sphinx import addnodes +from sphinx.application import Sphinx +from sphinx.application import logger +from sphinx.directives.other import TocTree + + +def NoWarnings(func): + @wraps(func) + def wrapped(self, *args, **kwargs): + stream = self.state.document.reporter.stream + self.state.document.reporter.stream = None + ret = func(self, *args, **kwargs) + self.state.document.reporter.stream = stream + ret = list(filter(lambda node: not isinstance(node, nodes.system_message), ret)) + return ret + + return wrapped + + +class NoWarningsToctree(TocTree): + @NoWarnings + def run(self): + return super().run() + + @NoWarnings + def parse_content(self, toctree: addnodes.toctree): + return super().parse_content(toctree) + + +def on_rtd() -> bool: + return os.getenv("READTHEDOCS") == "True" + + +def on_pr(html_context: Dict[str, str]) -> bool: + return ( + html_context["github_version"].startswith( + os.environ.get("READTHEDOCS_GIT_COMMIT_HASH")[:8] + ) + or os.getenv("GITHUB_EVENT_NAME") == "pull_request" + ) + + +def inject_changed_files(html_context: Dict[str, str], app: Sphinx) -> None: + import requests + + res = requests.get( + f"https://api.github.com/repos/{html_context['github_user']}/{html_context['github_repo']}/pulls/{os.environ.get('READTHEDOCS_VERSION_NAME')}/files" + ) + + if res.status_code != requests.codes.ok: + return + + changes_rst = "".join( + [ + "\n", + ".. nowarningstoctree::\n", + " :maxdepth: 1\n", + " :caption: PR CHANGED FILES\n", + "\n", + ] + ) + + if app.config.delta_inject_location is None: + inject_location = "index.rst" + else: + inject_location = app.config.delta_inject_location + + for file_context in res.json(): + status: str = file_context["status"] + filename: str = file_context["filename"] + + if app.config.delta_doc_path is None: + logger.error("Required option delta_doc_path is not set!") + if status == "removed": + continue + if not filename.startswith(app.config.delta_doc_path): + continue + if not filename.endswith(".rst"): + continue + + rel_path = os.path.relpath(filename, app.config.delta_doc_path) + if rel_path == inject_location: + continue + changes_rst += f" {rel_path}\n" + + changes_rst += "\n\n.. todolist::\n" + + inject_location = os.path.join(app.srcdir, inject_location) + with open(inject_location, "a") as f: + f.write(changes_rst) + + +def config_inited(app: Sphinx, config: Dict[str, Any]): + if on_rtd() and on_pr(config["html_context"]): + inject_changed_files(config["html_context"], app) + + +def setup(app: Sphinx) -> Dict[str, Any]: + app.connect("config-inited", config_inited) + app.add_config_value("delta_doc_path", None, str) + app.add_config_value("delta_inject_location", None, str) + app.add_directive("nowarningstoctree", NoWarningsToctree) + + return { + "parallel_read_safe": True, + "parallel_write_safe": True, + } diff --git a/source/conf.py b/source/conf.py index ddacca26b4..a451f5c91d 100644 --- a/source/conf.py +++ b/source/conf.py @@ -42,7 +42,7 @@ "sphinx.ext.intersphinx", "sphinxcontrib.rsvgconverter", "sphinxcontrib.video", - "sphinxext.delta", + # "sphinxext.delta", "sphinxext.opengraph", "sphinxext.photofinish", "sphinxext.rediraffe", @@ -67,6 +67,7 @@ "_extensions.wpilib_release", "_extensions.default_latex_image_settings", "_extensions.redown", + "_extensions.delta2", ] extensions += local_extensions diff --git a/source/docs/software/pathplanning/pathweaver/introduction.rst b/source/docs/software/pathplanning/pathweaver/introduction.rst index 9345ba0524..70ad38576f 100644 --- a/source/docs/software/pathplanning/pathweaver/introduction.rst +++ b/source/docs/software/pathplanning/pathweaver/introduction.rst @@ -9,3 +9,5 @@ A more advanced approach to autonomous is called "path planning". Instead of dri WPILib contains a trajectory generation suite that can be used by teams to generate and follow trajectories. This series of articles will go over how to generate and visualize trajectories using PathWeaver. For a comprehensive tutorial on following trajectories, please visit the :ref:`end-to-end trajectory tutorial `. .. note:: :ref:`Trajectory following ` code is required to use PathWeaver. We recommend that you start with Trajectory following and get that working with simple paths. From there you can continue on to testing more complicated paths generated by PathWeaver. + +test change