mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2026-03-07 04:38:35 -05:00
Add Sphinx extension for extracting prompt contents (#6671)
This commit is contained in:
154
docs/_ext/prompt_builder.py
Normal file
154
docs/_ext/prompt_builder.py
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from typing import Any, Dict, List, Set
|
||||||
|
|
||||||
|
from docutils import nodes
|
||||||
|
from docutils.io import StringOutput
|
||||||
|
from docutils.nodes import Element
|
||||||
|
|
||||||
|
from sphinx.application import Sphinx
|
||||||
|
from sphinx.builders.text import TextBuilder
|
||||||
|
from sphinx.writers.text import TextWriter
|
||||||
|
from sphinx.util import logging
|
||||||
|
from sphinx.util.docutils import SphinxTranslator
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class PromptTranslator(SphinxTranslator):
|
||||||
|
builder: PromptBuilder
|
||||||
|
|
||||||
|
def __init__(self, document: nodes.document, builder: PromptBuilder) -> None:
|
||||||
|
super().__init__(document, builder)
|
||||||
|
self.body = ""
|
||||||
|
self.prompts: List[Dict[str, str]] = []
|
||||||
|
|
||||||
|
def visit_document(self, node: Element) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def depart_document(self, node: Element) -> None:
|
||||||
|
if not self.prompts:
|
||||||
|
self.body = ""
|
||||||
|
return
|
||||||
|
if self.builder.out_suffix.endswith(".json"):
|
||||||
|
self.body = json.dumps(self.prompts, indent=4)
|
||||||
|
else:
|
||||||
|
self.body = "\n".join(prompt["content"] for prompt in self.prompts)
|
||||||
|
|
||||||
|
def unknown_visit(self, node: Element) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def unknown_departure(self, node: Element) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def visit_prompt(self, node: Element) -> None:
|
||||||
|
self.prompts.append(
|
||||||
|
{
|
||||||
|
"language": node.attributes["language"],
|
||||||
|
"prompts": node.attributes["prompts"],
|
||||||
|
"modifiers": node.attributes["modifiers"],
|
||||||
|
"rawsource": node.rawsource,
|
||||||
|
"content": node.children[0],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PromptWriter(TextWriter):
|
||||||
|
def translate(self) -> None:
|
||||||
|
visitor = self.builder.create_translator(self.document, self.builder)
|
||||||
|
self.document.walkabout(visitor)
|
||||||
|
self.output = visitor.body
|
||||||
|
|
||||||
|
|
||||||
|
class prompt(nodes.literal_block):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PromptBuilder(TextBuilder):
|
||||||
|
"""Extract prompts from documents."""
|
||||||
|
|
||||||
|
format = "json"
|
||||||
|
epilog = "The files with prompts are in %(outdir)s."
|
||||||
|
|
||||||
|
out_suffix = ".json"
|
||||||
|
default_translator_class = PromptTranslator
|
||||||
|
writer: PromptWriter
|
||||||
|
|
||||||
|
def init(self) -> None:
|
||||||
|
sphinx_prompt = __import__("sphinx-prompt")
|
||||||
|
|
||||||
|
def run(self) -> List[prompt]:
|
||||||
|
self.assert_has_content()
|
||||||
|
rawsource = "\n".join(self.content)
|
||||||
|
language = self.options.get("language") or "text"
|
||||||
|
prompts = [
|
||||||
|
p
|
||||||
|
for p in (
|
||||||
|
self.options.get("prompts") or sphinx_prompt.PROMPTS.get(language, "")
|
||||||
|
).split(",")
|
||||||
|
if p
|
||||||
|
]
|
||||||
|
modifiers = [
|
||||||
|
modifier for modifier in self.options.get("modifiers", "").split(",") if modifier
|
||||||
|
]
|
||||||
|
content = rawsource
|
||||||
|
if "auto" in modifiers:
|
||||||
|
parts = []
|
||||||
|
for line in self.content:
|
||||||
|
for p in prompts:
|
||||||
|
if line.startswith(p):
|
||||||
|
line = line[len(p) + 1 :].rstrip()
|
||||||
|
parts.append(line)
|
||||||
|
content = "\n".join(parts)
|
||||||
|
node = prompt(
|
||||||
|
rawsource,
|
||||||
|
content,
|
||||||
|
directive_content=self.content,
|
||||||
|
language=language,
|
||||||
|
prompts=self.options.get("prompts") or sphinx_prompt.PROMPTS.get(language, ""),
|
||||||
|
modifiers=modifiers,
|
||||||
|
)
|
||||||
|
return [node]
|
||||||
|
|
||||||
|
sphinx_prompt.PromptDirective.run = run
|
||||||
|
|
||||||
|
def prepare_writing(self, docnames: Set[str]) -> None:
|
||||||
|
del docnames
|
||||||
|
self.writer = PromptWriter(self)
|
||||||
|
|
||||||
|
def write_doc(self, docname: str, doctree: nodes.document) -> None:
|
||||||
|
self.writer.write(doctree, StringOutput(encoding="utf-8"))
|
||||||
|
if not self.writer.output:
|
||||||
|
# don't write empty files
|
||||||
|
return
|
||||||
|
|
||||||
|
filename = os.path.join(self.outdir, docname.replace("/", os.path.sep) + self.out_suffix)
|
||||||
|
os.makedirs(os.path.dirname(filename), exist_ok=True)
|
||||||
|
try:
|
||||||
|
with open(filename, "w", encoding="utf-8") as f:
|
||||||
|
f.write(self.writer.output)
|
||||||
|
except OSError as err:
|
||||||
|
logger.warning("error writing file %s: %s", filename, err)
|
||||||
|
|
||||||
|
|
||||||
|
class JsonPromptBuilder(PromptBuilder):
|
||||||
|
name = "jsonprompt"
|
||||||
|
out_suffix = ".json"
|
||||||
|
|
||||||
|
|
||||||
|
class TextPromptBuilder(PromptBuilder):
|
||||||
|
name = "textprompt"
|
||||||
|
out_suffix = ".txt"
|
||||||
|
|
||||||
|
|
||||||
|
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||||
|
app.add_builder(JsonPromptBuilder)
|
||||||
|
app.add_builder(TextPromptBuilder)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"version": "1.0",
|
||||||
|
"parallel_read_safe": True,
|
||||||
|
"parallel_write_safe": True,
|
||||||
|
}
|
||||||
@@ -46,6 +46,7 @@ extensions = [
|
|||||||
"sphinxcontrib_trio",
|
"sphinxcontrib_trio",
|
||||||
"sphinx-prompt",
|
"sphinx-prompt",
|
||||||
"deprecated_removed",
|
"deprecated_removed",
|
||||||
|
"prompt_builder",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ To install without additional config backend support:
|
|||||||
|
|
||||||
.. prompt:: bash
|
.. prompt:: bash
|
||||||
:prompts: (redenv) $
|
:prompts: (redenv) $
|
||||||
|
:modifiers: red-install-guide-install-normal
|
||||||
|
|
||||||
python -m pip install -U pip wheel
|
python -m pip install -U pip wheel
|
||||||
python -m pip install -U Red-DiscordBot
|
python -m pip install -U Red-DiscordBot
|
||||||
@@ -16,6 +17,7 @@ Or, to install with PostgreSQL support:
|
|||||||
|
|
||||||
.. prompt:: bash
|
.. prompt:: bash
|
||||||
:prompts: (redenv) $
|
:prompts: (redenv) $
|
||||||
|
:modifiers: red-install-guide-install-postgres
|
||||||
|
|
||||||
python -m pip install -U pip wheel
|
python -m pip install -U pip wheel
|
||||||
python -m pip install -U "Red-DiscordBot[postgres]"
|
python -m pip install -U "Red-DiscordBot[postgres]"
|
||||||
@@ -29,6 +31,7 @@ After installation, set up your instance with the following command:
|
|||||||
|
|
||||||
.. prompt:: bash
|
.. prompt:: bash
|
||||||
:prompts: (redenv) $
|
:prompts: (redenv) $
|
||||||
|
:modifiers: red-install-guide-setup
|
||||||
|
|
||||||
redbot-setup
|
redbot-setup
|
||||||
|
|
||||||
@@ -40,6 +43,7 @@ Once done setting up the instance, run the following command to run Red:
|
|||||||
|
|
||||||
.. prompt:: bash
|
.. prompt:: bash
|
||||||
:prompts: (redenv) $
|
:prompts: (redenv) $
|
||||||
|
:modifiers: red-install-guide-run
|
||||||
|
|
||||||
redbot <your instance name>
|
redbot <your instance name>
|
||||||
|
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ Run **one** of the following set of commands, depending on what extras you want
|
|||||||
|
|
||||||
.. prompt:: batch
|
.. prompt:: batch
|
||||||
:prompts: (redenv) C:\\>
|
:prompts: (redenv) C:\\>
|
||||||
|
:modifiers: red-install-guide-install-normal
|
||||||
|
|
||||||
python -m pip install -U pip wheel
|
python -m pip install -U pip wheel
|
||||||
python -m pip install -U Red-DiscordBot
|
python -m pip install -U Red-DiscordBot
|
||||||
@@ -141,6 +142,7 @@ Run **one** of the following set of commands, depending on what extras you want
|
|||||||
|
|
||||||
.. prompt:: batch
|
.. prompt:: batch
|
||||||
:prompts: (redenv) C:\\>
|
:prompts: (redenv) C:\\>
|
||||||
|
:modifiers: red-install-guide-install-postgres
|
||||||
|
|
||||||
python -m pip install -U pip wheel
|
python -m pip install -U pip wheel
|
||||||
python -m pip install -U Red-DiscordBot[postgres]
|
python -m pip install -U Red-DiscordBot[postgres]
|
||||||
@@ -153,6 +155,7 @@ After installation, set up your instance with the following command:
|
|||||||
|
|
||||||
.. prompt:: batch
|
.. prompt:: batch
|
||||||
:prompts: (redenv) C:\\>
|
:prompts: (redenv) C:\\>
|
||||||
|
:modifiers: red-install-guide-setup
|
||||||
|
|
||||||
redbot-setup
|
redbot-setup
|
||||||
|
|
||||||
@@ -164,6 +167,7 @@ Once done setting up the instance, run the following command to run Red:
|
|||||||
|
|
||||||
.. prompt:: batch
|
.. prompt:: batch
|
||||||
:prompts: (redenv) C:\\>
|
:prompts: (redenv) C:\\>
|
||||||
|
:modifiers: red-install-guide-run
|
||||||
|
|
||||||
redbot <your instance name>
|
redbot <your instance name>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user