Coverage for src/markdown_exec/mkdocs_plugin.py: 0.00%

46 statements  

« prev     ^ index     » next       coverage.py v7.2.3, created at 2023-04-18 14:41 +0200

1"""This module contains an optional plugin for MkDocs.""" 

2 

3from __future__ import annotations 

4 

5import logging 

6import os 

7from pathlib import Path 

8from typing import TYPE_CHECKING, Any, MutableMapping 

9 

10from mkdocs.config import Config, config_options 

11from mkdocs.plugins import BasePlugin 

12from mkdocs.utils import write_file 

13 

14from markdown_exec import formatter, formatters, validator 

15from markdown_exec.logger import patch_loggers 

16from markdown_exec.rendering import MarkdownConverter, markdown_config 

17 

18if TYPE_CHECKING: 

19 from jinja2 import Environment 

20 from mkdocs.structure.files import Files 

21 

22try: 

23 __import__("pygments_ansi_color") 

24except ImportError: 

25 ansi_ok = False 

26else: 

27 ansi_ok = True 

28 

29 

30class _LoggerAdapter(logging.LoggerAdapter): 

31 def __init__(self, prefix: str, logger: logging.Logger) -> None: 

32 super().__init__(logger, {}) 

33 self.prefix = prefix 

34 

35 def process(self, msg: str, kwargs: MutableMapping[str, Any]) -> tuple[str, MutableMapping[str, Any]]: 

36 return f"{self.prefix}: {msg}", kwargs 

37 

38 

39def _get_logger(name: str) -> _LoggerAdapter: 

40 logger = logging.getLogger(f"mkdocs.plugins.{name}") 

41 return _LoggerAdapter(name.split(".", 1)[0], logger) 

42 

43 

44patch_loggers(_get_logger) 

45 

46 

47class MarkdownExecPlugin(BasePlugin): 

48 """MkDocs plugin to easily enable custom fences for code blocks execution.""" 

49 

50 config_scheme = (("languages", config_options.Type(list, default=list(formatters.keys()))),) 

51 

52 def on_config(self, config: Config, **kwargs: Any) -> Config: # noqa: ARG002 

53 """Configure the plugin. 

54 

55 Hook for the [`on_config` event](https://www.mkdocs.org/user-guide/plugins/#on_config). 

56 In this hook, we add custom fences for all the supported languages. 

57 

58 We also save the Markdown extensions configuration 

59 into [`markdown_config`][markdown_exec.rendering.markdown_config]. 

60 

61 Arguments: 

62 config: The MkDocs config object. 

63 **kwargs: Additional arguments passed by MkDocs. 

64 

65 Returns: 

66 The modified config. 

67 """ 

68 self.languages = self.config["languages"] 

69 mdx_configs = config.setdefault("mdx_configs", {}) 

70 superfences = mdx_configs.setdefault("pymdownx.superfences", {}) 

71 custom_fences = superfences.setdefault("custom_fences", []) 

72 for language in self.languages: 

73 custom_fences.append( 

74 { 

75 "name": language, 

76 "class": language, 

77 "validator": validator, 

78 "format": formatter, 

79 }, 

80 ) 

81 markdown_config.save(config["markdown_extensions"], config["mdx_configs"]) 

82 return config 

83 

84 def on_env(self, env: Environment, *, config: Config, files: Files) -> Environment | None: # noqa: ARG002,D102 

85 css_filename = "assets/_markdown_exec_ansi.css" 

86 css_content = Path(__file__).parent.joinpath("ansi.css").read_text() 

87 write_file(css_content.encode("utf-8"), os.path.join(config["site_dir"], css_filename)) 

88 config["extra_css"].insert(0, css_filename) 

89 return env 

90 

91 def on_post_build(self, *, config: Config) -> None: # noqa: ARG002,D102 

92 MarkdownConverter.counter = 0 

93 markdown_config.reset()