Skip to content

Commit

Permalink
improvements to target flag handling
Browse files Browse the repository at this point in the history
  • Loading branch information
landmaj committed Dec 22, 2023
1 parent 8a51564 commit 5802a5d
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 36 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ A plugin for embedding D2 diagrams in MkDocs.
## Requirements

* [MkDocs](https://www.mkdocs.org/) >= 1.5.0
* [D2](https://d2lang.com)
* [D2](https://d2lang.com) >= 0.6.3

## Installation

Expand Down
4 changes: 2 additions & 2 deletions d2/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from functools import partial
from typing import Callable, Dict, Tuple
from typing import Callable, List, Tuple

from mkdocs.plugins import log

Expand All @@ -9,4 +9,4 @@
warning = partial(log.warning, f"{NAME}: %s")
error = partial(log.error, f"{NAME}: %s")

Renderer = Callable[[bytes, Dict[str, str]], Tuple[str, bool]]
Renderer = Callable[[bytes, List[str]], Tuple[str, bool]]
23 changes: 11 additions & 12 deletions d2/config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict
from typing import List

from mkdocs.config import config_options
from mkdocs.config.base import Config
Expand All @@ -17,7 +17,7 @@ class PluginConfig(Config):
pad = config_options.Type(int, default=100)
scale = config_options.Type(float, default=-1.0)
force_appendix = config_options.Type(bool, default=False)
target = config_options.Type(str, default="\'\'")
target = config_options.Type(str, default="''")

def d2_config(self):
_dict = {}
Expand All @@ -38,17 +38,16 @@ class D2Config(BaseModel, extra="forbid"):
force_appendix: bool
target: str

def env(self) -> list[str]:
def opts(self) -> List[str]:
opts = [
"--layout", self.layout,
"--theme", str(self.theme),
"--dark-theme", str(self.dark_theme),
"--pad", str(self.pad),
"--scale", str(self.scale),
"--target", str(self.target)
f"--layout={self.layout}",
f"--theme={self.theme}",
f"--dark-theme={self.dark_theme}",
f"--sketch={str(self.sketch).lower()}",
f"--pad={self.pad}",
f"--scale={self.scale}",
f"--force-appendix={str(self.force_appendix).lower()}",
f"--target={self.target}",
]

opts = opts + [ "--sketch" ] if self.sketch else opts
opts = opts + [ "--force-appendix" ] if self.force_appendix else opts

return opts
4 changes: 2 additions & 2 deletions d2/fence.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def validator(
error(e)
return False

options["env"] = cfg.env()
options["opts"] = cfg.opts()
return True

def formatter(
Expand All @@ -52,7 +52,7 @@ def formatter(
source, language, class_name, options, md, **kwargs
)

result, ok = self.renderer(source.encode(), options["env"])
result, ok = self.renderer(source.encode(), options["opts"])
if not ok:
error(result)
return fence_code_format(
Expand Down
2 changes: 1 addition & 1 deletion d2/img.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def run(self, root: etree.Element) -> etree.Element | None:
error(e)
continue

result, ok = self.renderer(source, cfg.env())
result, ok = self.renderer(source, cfg.opts())
if not ok:
error(result)
continue
Expand Down
35 changes: 24 additions & 11 deletions d2/plugin.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import dbm
import os
import shutil
import subprocess
from functools import partial
from hashlib import sha1
from pathlib import Path
from typing import Dict, MutableMapping, Tuple
from typing import List, MutableMapping, Tuple

from mkdocs.config.defaults import MkDocsConfig
from mkdocs.exceptions import ConfigurationError
from mkdocs.plugins import BasePlugin
from mkdocs.utils.yaml import RelativeDirPlaceholder
from packaging import version

from d2 import info
from d2.config import PluginConfig
from d2.fence import D2CustomFence

REQUIRED_VERSION = version.parse("0.6.3")


class Plugin(BasePlugin[PluginConfig]):
def on_config(self, config: MkDocsConfig) -> MkDocsConfig | None:
Expand All @@ -28,8 +30,18 @@ def on_config(self, config: MkDocsConfig) -> MkDocsConfig | None:
info(f"Using cache at {path} ({backend})")
cache = dbm.open(path, "c")

if shutil.which(self.config.executable) is None:
try:
result = subprocess.run(
[self.config.executable, "--version"],
capture_output=True,
)
except FileNotFoundError:
raise ConfigurationError(f"executable '{self.config.executable}' not found")
d2_version = version.parse(result.stdout.decode().strip())
if d2_version < REQUIRED_VERSION:
raise ConfigurationError(
f"required d2 version {REQUIRED_VERSION} not satisfied, found {d2_version}"
)

renderer = partial(render, self.config.executable, cache) # type: ignore

Expand Down Expand Up @@ -65,30 +77,31 @@ def render(
executable: str,
cache: MutableMapping[bytes, bytes] | None,
source: bytes,
env: list[str],
opts: List[str],
) -> Tuple[str, bool]:
key = ""
if cache is not None:
brute_key = f"{source.hex()}.{env}"
key = sha1(brute_key.encode()).digest()
key = source.hex()
for opt in opts:
key = f"{key}.{opt}"
key = sha1(key.encode()).digest()
if key in cache:
return cache[key].decode(), True

process = [ executable ] + env + [ "-", "-" ]

try:
result = subprocess.run(
process,
[executable, *opts, "-", "-"],
input=source,
capture_output=True,
)
except Exception as e:
return str(e), False

stdout = result.stdout.decode().strip()
if result.returncode != 0:
return stdout, False
stderr = result.stderr.decode().strip()
return stderr, False

stdout = result.stdout.decode().strip()
if key != "" and cache is not None:
cache[key] = stdout.encode()
return stdout, True
29 changes: 29 additions & 0 deletions docs/docs/guide/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ plugins:
pad: 100
scale: -1.0
force_appendix: False
target: "''"
```
If an option is not specified, default value (seen above) will be used.
Expand Down Expand Up @@ -97,6 +98,34 @@ Bob -> Alice
Bob -> Alice
```

##### Rendering specific target

````md
```d2 pad="10" scale="1" target="alternative"
scenarios: {
main: {
Bob -> Alice
}
alternative: {
Alice -> Bob
}
}
```
````

```d2 pad="10" scale="1" target="alternative"
scenarios: {
main: {
Bob -> Alice
}
alternative: {
Alice -> Bob
}
}
```

### Image tags

Image tags use [attr_list](https://python-markdown.github.io/extensions/attr_list/)
Expand Down
5 changes: 0 additions & 5 deletions docs/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,3 @@ plugins:
The plugin will automatically add `pymdownx.superfences` and `attr_list` to the
list of enabled markdown extensions.

## Known issues

* [Layered diagrams](https://d2lang.com/tour/composition/) (animations) are not supported.
D2 does not allow outputing such diagrams to stdout.
9 changes: 7 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

setup(
name="mkdocs-d2-plugin",
version="1.1.0",
version="1.2.0",
description="MkDocs plugin for D2",
long_description=long_description,
long_description_content_type="text/markdown",
Expand All @@ -18,7 +18,12 @@
author_email="michal@wielunski.net",
license="MIT",
python_requires=">=3.8",
install_requires=["mkdocs>=1.5.0", "pymdown-extensions>=9.0", "pydantic>=2.0"],
install_requires=[
"mkdocs>=1.5.0",
"pymdown-extensions>=9.0",
"pydantic>=2.0",
"packaging",
],
classifiers=[
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
Expand Down

0 comments on commit 5802a5d

Please sign in to comment.