Skip to content

Commit

Permalink
chore: general cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
atrnh committed May 24, 2023
1 parent f2dc0cd commit a38686a
Show file tree
Hide file tree
Showing 17 changed files with 363 additions and 58 deletions.
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1 +1 @@
python 3.11.2
python 3.11.3
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# sphinx-revealjs
3 changes: 2 additions & 1 deletion example/conf.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
extensions = ["sei.sphinxext.revealjs"]
extensions = ["sphinx_revealjs"]
html_sidebars = {"**": []}
exclude_patterns = ["_build"]
html_theme = "revealjs"
revealjs_theme = "night.css"
24 changes: 24 additions & 0 deletions example/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,30 @@ Another Slide

Hi

More content

.. newslide:: Override title

Yet another slide

.. incr:: item

- One

- Two

- Three

Another Section
===============

Wow this is another section

Subsection title
----------------

Whee

=====
Index
=====
Expand Down
13 changes: 13 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
build: (_sphinx "sphinx-build" "revealjs" "example" "example" join("example", "_build"))

_sphinx cmd builder config source output *opts:
@echo "Using {{cmd}} to build {{source}}"
poetry run {{cmd}} \
-b {{builder}} \
-d {{output}}/doctrees \
-n \
-c {{config}} \
{{opts}} \
{{source}} {{join(output, builder)}}
@echo "Opening in browser..."
open {{join(output, builder, "index.html")}}
6 changes: 2 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
[tool.poetry]
name = "sei-sphinxext-revealjs"
name = "sphinx-revealjs"
version = "0.1.0"
description = ""
authors = ["Ashley Trinh <[email protected]>"]
readme = "README.md"
packages = [{include = "sei", from = "src"}]
packages = [{ include = "sphinx_revealjs", from = "src" }]
include = ["lib/reveal.js/dist", "lib/reveal.js/plugin"]

[tool.poetry.dependencies]
python = "^3.11"
sphinx = "^6.1.3"


[tool.poetry.group.dev.dependencies]
mypy = "^1.1.1"
black = "^23.1.0"


[tool.poetry.group.test.dependencies]
pytest = "^7.2.2"

Expand Down
15 changes: 0 additions & 15 deletions src/sei/sphinxext/revealjs/builder.py

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,36 +1,37 @@
from typing import TYPE_CHECKING, Any, List
from typing import TYPE_CHECKING, Any
import importlib.metadata
from pathlib import Path
from glob import glob
from sphinx.util.fileutil import copy_asset_file

from sei.sphinxext.revealjs import builder, overridenodes
from . import builder, overridenodes, directives

if TYPE_CHECKING:
from sphinx.application import Sphinx
from sphinx.config import Config

__name__ = "sei.sphinxext.revealjs"
__name__ = "sphinx_revealjs"
__version__ = importlib.metadata.version(__name__)

THEMES_DIRECTORY = (Path(__file__).parent / "themes").resolve()
LIB_DIRECTORY = (Path(__file__).parent / ".." / ".." / ".." / ".." / "lib").resolve()
LIB_DIRECTORY = (Path(__file__).parent / ".." / "lib").resolve()
REVEALJS_DIST = LIB_DIRECTORY / "reveal.js" / "dist"


def exclude_unused_theme_files(theme_name: str) -> List[str]:
"""Exclude theme files that don't match the configured theme."""
def init_builder(app: "Sphinx") -> None:
if app.builder.name == "revealjs":
add_revealjs_static_files(app)
override_nodes(app)

return [
str(p)
for p in glob("theme/*.css", root_dir=REVEALJS_DIST)
if Path(p).name != theme_name
]

def add_revealjs_static_files(app: "Sphinx") -> None:
app.add_css_file("reset.css", priority=500)
app.add_css_file("reveal.css", priority=500)
app.add_js_file("reveal.js", priority=500)
app.add_js_file("reveal.js.map", priority=500)
app.add_css_file(app.config.revealjs_theme, priority=600)

def add_theme(app: "Sphinx") -> None:
if app.builder.name == "revealjs":
app.add_css_file(app.config.revealjs_theme, priority=600)

def override_nodes(app: "Sphinx") -> None:
overridenodes.setup(app)


def copy_revealjs_files(app: "Sphinx", exc) -> None:
Expand All @@ -49,19 +50,16 @@ def copy_revealjs_files(app: "Sphinx", exc) -> None:


def setup(app: "Sphinx") -> dict[str, Any]:
builder.setup(app)
overridenodes.setup(app)

app.add_config_value("revealjs_theme", "white.css", "revealjs")

app.connect("builder-inited", add_theme)
app.add_config_value("revealjs_theme", "white.css", "html")
app.add_html_theme("revealjs", str(THEMES_DIRECTORY / "revealjs"))
app.add_builder(builder.RevealjsBuilder)
app.connect("builder-inited", init_builder)
app.connect("build-finished", copy_revealjs_files)

app.add_html_theme("revealjs", str(THEMES_DIRECTORY / "revealjs"))
app.add_css_file("reset.css", priority=500)
app.add_css_file("reveal.css", priority=500)
app.add_js_file("reveal.js", priority=500)
app.add_js_file("reveal.js.map", priority=500)
directives.incremental.setup(app)
directives.speakernote.setup(app)
directives.newslide.setup(app)

return {
"version": __version__,
"parallel_read_safe": True,
Expand Down
8 changes: 8 additions & 0 deletions src/sphinx_revealjs/builder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""sphinx_revealjs.builder"""

from sphinx.builders.html import StandaloneHTMLBuilder


class RevealjsBuilder(StandaloneHTMLBuilder):
name = "revealjs"
search = False
3 changes: 3 additions & 0 deletions src/sphinx_revealjs/directives/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""sphinx_revealjs.directives"""

from . import incremental, speakernote, newslide
31 changes: 31 additions & 0 deletions src/sphinx_revealjs/directives/_base_slide.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""sphinxext.revealjs.directives._base_slide
Common, slides-related stuff.
"""

from docutils.nodes import Element
from docutils.parsers.rst import Directive, directives


class BaseSlide(Directive):
"""Base for slide-related directives."""

option_spec = {
"class": directives.class_option,
"background": directives.unchanged,
# The choices below are all from Revealjs.
# See https://revealjs.com/transitions/
"transition": lambda arg: directives.choice(
arg, ("none", "fade", "slide", "convex", "concave", "zoom")
),
"transition-speed": lambda arg: directives.choice(
arg, ("default", "fast", "slow")
),
}

def attach_options(self, node: Element) -> None:
node["data-background"] = self.options.get("background")
node["data-transition"] = self.options.get("transition")
node["data-transition-speed"] = self.options.get("transition-speed")
node["data-state"] = self.options.get("state")
node["classes"] += self.options.get("class", [])
120 changes: 120 additions & 0 deletions src/sphinx_revealjs/directives/incremental.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
"""sphinxext.revealjs.directives.incremental
The `.. incremental::` directive. This will add a transition to its children so
they appear one at a time using Reveal.js's `fragment` class.
"""

from typing import TYPE_CHECKING, List

from docutils import nodes
from docutils.parsers.rst import Directive, directives

from sphinx.util import logging

if TYPE_CHECKING:
from sphinx.application import Sphinx

logger = logging.getLogger(__name__)


class Incremental(Directive):
"""Incremental directive."""

required_arguments = 1
has_content = True
option_spec = {"class": directives.class_option}

_valid_arguments = ("one", "item", "nest")

def run(self) -> List[nodes.Node]:
self.validate_args()
self.assert_has_content()

text = "\n".join(self.content)
node = nodes.container(text)
self.state.nested_parse(self.content, self.content_offset, node)

if self.arguments[0] == "one":
node["classes"] += self.options.get("class", [])
node["classes"].append("fragment")
return [node]
else:
# Now we're handling the 'item' and 'nest' cases, where we need to
# apply the 'fragment' class to nodes in node.children

self.assert_is_incrementable(node.children[0])

# Since we're gonna discard the parent node, copy
# classes set by the user onto the first child node
node.children[0]["classes"] += self.options.get("class", [])

if isinstance(node.children[0], nodes.definition_list):
self.contain_definition_list_items(node.children[0])

if self.arguments[0] == "item":
self.increment_list_items(node)
elif self.arguments[0] == "nest":
self.increment_nested_list_items(node)

return node.children

def validate_args(self) -> None:
"""Warn user if argument is invalid."""

location = self.state_machine.get_source_and_line(self.lineno)
if self.arguments[0] not in self._valid_arguments:
logger.warning(
f"Invalid argument: '{self.arguments[0]}' must be one of {', '.join(self._valid_arguments)}",
location=location,
)

def assert_is_incrementable(self, node: nodes.Element) -> None:
"""Warn user if we can't apply transitions to this node."""

location = self.state_machine.get_source_and_line(self.lineno)
if not isinstance(node, nodes.Sequential):
logger.warning(
"contents of directive 'incremental' must be a list or sequence",
location=location,
)

def increment_list_items(self, node: nodes.Sequential) -> None:
"""Add class 'fragment' to Sequential node's children."""

for list_item in node.children[0].children:
try:
list_item["classes"] += ["fragment"]
except TypeError:
continue

def increment_nested_list_items(self, node: nodes.Sequential) -> None:
"""Add class 'fragment' to a Sequential node's descendants."""

def traverse_condition(node: nodes.Node) -> bool:
return (
isinstance(node, nodes.list_item)
or isinstance(node, nodes.term)
or isinstance(node, nodes.definition)
)

for list_item in node.traverse(traverse_condition):
list_item["classes"] += ["fragment"]

@staticmethod
def contain_definition_list_items(dl_node: nodes.definition_list) -> None:
"""Group definitions and terms in containers."""

dl_children = []
for def_list_item in dl_node.children:
container = nodes.container()
container.children.append(def_list_item)
dl_children.append(container)

dl_node.children = dl_children


def setup(app: "Sphinx") -> None:
"""Setup the extension."""

app.add_directive("incremental", Incremental)
app.add_directive("incr", Incremental)
Loading

0 comments on commit a38686a

Please sign in to comment.