diff --git a/mkdocs_simple_plugin/plugin.py b/mkdocs_simple_plugin/plugin.py index 505f4f57..fc07cc2a 100644 --- a/mkdocs_simple_plugin/plugin.py +++ b/mkdocs_simple_plugin/plugin.py @@ -36,7 +36,7 @@ ### Example usage (defaults) -{% include "mkdocs_simple_plugin/example.snippet" %} +{% include "mkdocs_simple_plugin/defaults.snippet" %} ### Inline parameters @@ -54,7 +54,7 @@ Below are the default settings of the plugin. ```yaml -{{ config.mkdocs_simple_config }} +{{ mkdocs_simple_config }} ``` !!!Note @@ -90,6 +90,7 @@ from mkdocs.plugins import BasePlugin +from mkdocs.config.base import Config from mkdocs.config import config_options from mkdocs import config as mkdocs_config from mkdocs import utils @@ -97,164 +98,256 @@ from mkdocs_simple_plugin.simple import Simple -class SimplePlugin(BasePlugin): - """SimplePlugin adds documentation throughout your repo to a mkdocs wiki.""" +class ExtractConfig(Config): + """Semiliterate extraction configuration.""" + # md file="extract_config.snippet" + # ##### start + # + # (optional) The regex pattern to indicate the start of extraction. + # + # Only the first mode whose `start` expression matches is activated, so at + # most one mode of extraction can be active at any time. + # When an extraction is active, lines from the scanned + # file are processed into the destination file. + # + # !!!Note + # The (last) extraction mode (if any) with no `start` + # parameter is active starting at the first line of the scanned + # file; there is no way this mode can be reactivated if it stops. + # This convention allows for convenient "front-matter" extraction. + start = config_options.Optional(config_options.Type(str)) + # + # ##### stop + # + # (optional) The regex pattern to indicate the stop of extraction. + # + # After the extraction has stopped, the file will continue to be searched + # for matching patterns starting with the _next_ line of the scanned file. + # In this way the entire file will be processed looking for start-stop + # pairs. + stop = config_options.Optional(config_options.Type(str)) + # + # ##### replace + # + # (optional) The `replace` parameter allows extracted lines from a file to + # be transformed in simple ways by regular expressions, for + # example to strip leading comment symbols if necessary. + # + # The `replace` parameter is a list of substitutions to attempt. + # Each substitution is specified either by a two-element list of a + # regular expression and a template, or by just a regular expression. + # + # Once one of the + # `replace` patterns matches, processing stops; no further expressions + # are checked. + replace = config_options.Optional(config_options.Type(list)) + # + # /md + + +class SemiliterateConfig(Config): + """Semiliterate configuration.""" + # md file="semiliterate_config.snippet" + # #### pattern + # + # Any file in the searched directories whose name contains this + # required regular expression parameter will be scanned. + pattern = config_options.Type(str) + # + # #### destination + # + # By default, the extracted documentation will be copied to a file + # whose name is generated by removing the (last) extension from the + # original filename, if any, and appending `.md`. However, if this + # parameter is specified, it will be expanded as a template using + # the match object from matching "pattern" against the filename, + # to produce the name of the destination file. + destination = config_options.Optional(config_options.Type(str)) + # + # #### terminate + # + # If specified, all extraction from the file is terminated when + # a line containing this regexp is encountered (whether or not + # any extraction is currently active per the parameters below). + # The last matching group in the `terminate` expression, if any, + # is written to the destination file; note that "start" and "stop" + # below share that same behavior. + terminate = config_options.Optional(config_options.Type(str)) + # + # #### extract + # + # This parameter determines what will be extracted from a scanned + # file that matches the pattern above. Its value should be a block + # or list of blocks of settings. + # + # {% include "mkdocs_simple_plugin/extract_config.snippet" %} + extract = config_options.Optional(config_options.ListOfItems( + config_options.SubConfig(ExtractConfig))) + # + # /md + +def semiliterate_defaults(): + """Default plugin values for extracting documentation.""" + return [{ + 'pattern': r'.*', + 'terminate': r'^\W*md-ignore', + 'extract': [ + { + # md file="defaults.snippet" + # block comments starting with: `"""md` + 'start': r'^\s*"""\W?md\b', + 'stop': r'^\s*"""\s*$', + # + # ```python + # """md + # This is a documentation comment. + # """ + # ``` + # + }, + { + # line comments starting with: + # `# md` and ending with `# /md`, + 'start': r'^\s*#+\W?md\b', + 'stop': r'^\s*#\s?\/md\s*$', + # stripping leading spaces and `#``, + # and only capturing comment lines. + 'replace': [r'^\s*# ?(.*\n?)$', r'^.*$'], + # + # ```python + # # md + # # This is a documentation comment. + # # /md + # ``` + # + }, + { + # block comments starting with: `/** md` + 'start': r'^\s*/\*+\W?md\b', + 'stop': r'^\s*\*\*/\s*$', + # + # ```c + # /** md + # This is a documentation comment. + # **/ + # ``` + # + }, + { + # in line comments starting with + # `// md`, ending with `// end md`, + 'start': r'^\s*\/\/+\W?md\b', + 'stop': r'^\s*\/\/\send\smd\s*$', + # stripping leading spaces and `//`, + # and only capturing comment lines. + 'replace': [r'^\s*\/\/\s?(.*\n?)$', r'^.*$'], + # + # ```c + # // md + # // This is a documentation comment. + # // end md + # ``` + # + }, + { + # block comments starting with + # `` + 'start': r'\s*$', + # + # ```xml + # + # ``` + # + } + # /md + ] + }] + + +class SimplePluginConfig(Config): + """Simple plugin configuration.""" # md file=config_scheme.snippet - config_scheme = ( - # ### include_folders - # - # Directories whose name matches a glob pattern in this list will be - # searched for documentation - ('include_folders', config_options.Type(list, default=['*'])), - # - # ### ignore_folders - # - # Directories whose name matches a glob pattern in this list will NOT be - # searched for documentation. - ('ignore_folders', config_options.Type(list, default=[])), - # - # ### ignore_hidden - # - # Hidden directories will not be searched if this is true. - ('ignore_hidden', config_options.Type(bool, default=True)), - # - # ### merge_docs_dir - # - # If true, the contents of the docs directory (if any) will be merged - # at the same level as all other documentation. - # Otherwise, the docs directory will be retained as a subdirectory in - # the result. - ('merge_docs_dir', config_options.Type(bool, default=True)), - # - # ### build_docs_dir - # - # If set, the directory where docs will be collated to be build. - # Otherwise, the build docs directory will be a temporary directory. - ('build_docs_dir', config_options.Type(str, default='')), - # - # ### include_extensions - # - # Any file in the searched directories whose name contains a string in - # this list will simply be copied to the generated documentation. - ('include_extensions', - config_options.Type( - list, - default=[ - ".bmp", ".tif", ".tiff", ".gif", ".svg", ".jpeg", - ".jpg", ".jif", ".jiff", ".jp2", ".jpx", ".j2k", - ".j2c", ".fpx", ".pcd", ".png", ".pdf", "CNAME", - ".snippet", ".pages" - ])), - # - # ### semiliterate - # - # The semiliterate settings allows the extraction of markdown from - # inside source files. - # It is defined as a list of blocks of settings for different - # filename patterns (typically matching filename extensions). - # All regular expression parameters use ordinary Python `re` syntax. - # - # {% include "mkdocs_simple_plugin/Semiliterate.snippet" %} - # - # {% include "mkdocs_simple_plugin/ExtractionPattern.snippet" %} - # /md - - - ('semiliterate', - config_options.Type( - list, - default=[ - { - 'pattern': r'.*', - 'terminate': r'^\W*md-ignore', - 'extract': [ - { - # md file="example.snippet" - # block comments starting with: `"""md` - 'start': r'^\s*"""\W?md\b', - 'stop': r'^\s*"""\s*$', - # - # ```python - # """md - # This is a documentation comment. - # """ - # ``` - # - }, - { - # line comments starting with: - # `# md` and ending with `# /md`, - 'start': r'^\s*#+\W?md\b', - 'stop': r'^\s*#\s?\/md\s*$', - # stripping leading spaces and `#``, - # and only capturing comment lines. - 'replace': [r'^\s*# ?(.*\n?)$', r'^.*$'], - # - # ```python - # # md - # # This is a documentation comment. - # # /md - # ``` - # - }, - { - # block comments starting with: `/** md` - 'start': r'^\s*/\*+\W?md\b', - 'stop': r'^\s*\*\*/\s*$', - # - # ```c - # /** md - # This is a documentation comment. - # **/ - # ``` - # - }, - { - # in line comments starting with - # `// md`, ending with `// end md`, - 'start': r'^\s*\/\/+\W?md\b', - 'stop': r'^\s*\/\/\send\smd\s*$', - # stripping leading spaces and `//`, - # and only capturing comment lines. - 'replace': [r'^\s*\/\/\s?(.*\n?)$', r'^.*$'], - # - # ```c - # // md - # // This is a documentation comment. - # // end md - # ``` - # - }, - { - # block comments starting with - # `` - 'start': r'\s*$', - # - # ```xml - # - # ``` - # - } - ] - } - ])) + # ### include_folders + # + # Directories whose name matches a glob pattern in this list will be + # searched for documentation + include_folders = config_options.Type(list, default=['*']) + # + # ### ignore_folders + # + # Directories whose name matches a glob pattern in this list will NOT be + # searched for documentation. + ignore_folders = config_options.Type(list, default=[]) + # + # ### ignore_hidden + # + # Hidden directories will not be searched if this is true. + ignore_hidden = config_options.Type(bool, default=True) + # + # ### merge_docs_dir + # + # If true, the contents of the docs directory (if any) will be merged + # at the same level as all other documentation. + # Otherwise, the docs directory will be retained as a subdirectory in + # the result. + merge_docs_dir = config_options.Type(bool, default=True) + # + # ### build_docs_dir + # + # If set, the directory where docs will be collated to be build. + # Otherwise, the build docs directory will be a temporary directory. + build_docs_dir = config_options.Type(str, default='') + # + # ### include_extensions + # + # Any file in the searched directories whose name contains a string in + # this list will simply be copied to the generated documentation. + include_extensions = config_options.Type( + list, + default=[ + ".bmp", ".tif", ".tiff", ".gif", ".svg", ".jpeg", + ".jpg", ".jif", ".jiff", ".jp2", ".jpx", ".j2k", + ".j2c", ".fpx", ".pcd", ".png", ".pdf", "CNAME", + ".snippet", ".pages" + ] + ) + # + # ### semiliterate + # + # The semiliterate settings allows the extraction of markdown from + # inside source files. + # It is defined as a list of blocks of settings for different + # filename patterns (typically matching filename extensions). + # All regular expression parameters use ordinary Python `re` syntax. + # + # {% include "mkdocs_simple_plugin/semiliterate_config.snippet" %} + semiliterate = config_options.ListOfItems( + config_options.SubConfig(SemiliterateConfig), + default=semiliterate_defaults() ) + # # /md + +class SimplePlugin(BasePlugin[SimplePluginConfig]): + """SimplePlugin adds documentation throughout your repo to a mkdocs wiki.""" + def __init__(self): """Set up internal variables.""" self.orig_docs_dir = None + self.mkdocs_simple_config = "" + self.ignore_paths = "" self.paths = None - def on_config(self, config, **kwargs): + def on_config(self, config: SimplePluginConfig, **kwargs): """Update configuration to use a temporary build directory.""" default_config = dict((name, config_option.default) for name, config_option in self.config_scheme) - config['mkdocs_simple_config'] = yaml.dump( + self.mkdocs_simple_config = yaml.dump( default_config, sort_keys=False, default_flow_style=False, @@ -265,7 +358,7 @@ def on_config(self, config, **kwargs): # PY2 returns a byte string by default. The Unicode prefix ensures a # Unicode string is returned. And it makes MkDocs temp dirs easier to # identify. - build_docs_dir = self.config['build_docs_dir'] + build_docs_dir = self.config.build_docs_dir if not build_docs_dir: build_docs_dir = tempfile.mkdtemp( prefix="mkdocs_simple_" + @@ -275,29 +368,29 @@ def on_config(self, config, **kwargs): utils.log.info( "mkdocs-simple-plugin: build_docs_dir: %s", build_docs_dir) - self.config['build_docs_dir'] = build_docs_dir + self.config.build_docs_dir = build_docs_dir # Clean out build folder on config shutil.rmtree(build_docs_dir, ignore_errors=True) os.makedirs(build_docs_dir, exist_ok=True) # Save original docs directory location - self.orig_docs_dir = config['docs_dir'] + self.orig_docs_dir = config.docs_dir # Update the docs_dir with our temporary one - config['docs_dir'] = build_docs_dir + config.docs_dir = build_docs_dir # Add all markdown extensions to include list - self.config['include_extensions'] = list(utils.markdown_extensions) + \ - self.config['include_extensions'] + self.config.include_extensions = list(utils.markdown_extensions) + \ + self.config.include_extensions # Always ignore the output paths - self.config["ignore_paths"] = [ + self.ignore_paths = [ get_config_site_dir(config.config_file_path), - config['site_dir'], - self.config['build_docs_dir']] + config.site_dir, + self.config.build_docs_dir] return config def on_pre_build(self, *, config): """Build documentation directory with files according to settings.""" # Configure simple - simple = Simple(**self.config) + simple = Simple(**self.config, ignore_paths=self.ignore_paths) # Merge docs if self.config["merge_docs_dir"]: diff --git a/mkdocs_simple_plugin/semiliterate.py b/mkdocs_simple_plugin/semiliterate.py index 5568846a..0665af39 100644 --- a/mkdocs_simple_plugin/semiliterate.py +++ b/mkdocs_simple_plugin/semiliterate.py @@ -21,48 +21,6 @@ def get_match(pattern: re.Pattern, line: str) -> re.Match: class ExtractionPattern: """An ExtractionPattern for a file.""" - # md file="ExtractionPattern.snippet" - # ##### start - # - # (optional) The regex pattern to indicate the start of extraction. - # - # Only the first mode whose `start` expression matches is activated, so at - # most one mode of extraction can be active at any time. - # When an extraction is active, lines from the scanned - # file are processed into the destination file. - # - # !!!Note - # The (last) extraction mode (if any) with no `start` - # parameter is active starting at the first line of the scanned - # file; there is no way this mode can be reactivated if it stops. - # This convention allows for convenient "front-matter" extraction. - # - # ##### stop - # - # (optional) The regex pattern to indicate the stop of extraction. - # - # After the extraction has stopped, the file will continue to be searched - # for matching patterns starting with the _next_ line of the scanned file. - # In this way the entire file will be processed looking for start-stop - # pairs. - # - # ##### replace - # - # The `replace` parameter allows extracted lines from a file to - # be transformed in simple ways by regular expressions, for - # example to strip leading comment symbols if necessary. - # - # The `replace` parameter is a list of substitutions to attempt. - # Each substitution is specified either by a two-element list of a - # regular expression and a template, or by just a regular expression. - # - # Once one of the - # `replace` patterns matches, processing stops; no further expressions - # are checked. - # - # - # - # /md def __init__( self, @@ -341,37 +299,6 @@ def extract_line(self, line: str, extraction_pattern: re.Pattern): class Semiliterate: """Extract documentation from source files using regex settings.""" - # md file="Semiliterate.snippet" - # #### pattern - # - # Any file in the searched directories whose name contains this - # required regular expression parameter will be scanned. - # - # #### destination - # - # By default, the extracted documentation will be copied to a file - # whose name is generated by removing the (last) extension from the - # original filename, if any, and appending `.md`. However, if this - # parameter is specified, it will be expanded as a template using - # the match object from matching "pattern" against the filename, - # to produce the name of the destination file. - # - # #### terminate - # - # If specified, all extraction from the file is terminated when - # a line containing this regexp is encountered (whether or not - # any extraction is currently active per the parameters below). - # The last matching group in the `terminate` expression, if any, - # is written to the destination file; note that "start" and "stop" - # below share that same behavior. - # - # #### extract - # - # This parameter determines what will be extracted from a scanned - # file that matches the pattern above. Its value should be a block - # or list of blocks of settings. - # /md - def __init__( self, pattern: str, diff --git a/setup.py b/setup.py index d32c7c71..6388b86f 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ install_requires=[ 'click>=7.1', 'MarkupSafe>=2.1.1', - 'mkdocs>=1.0.6', + 'mkdocs>=1.4.0', 'PyYAML>=6.0'], classifiers=[ 'Development Status :: 4 - Beta',