diff --git a/mkdocs_simple_plugin/plugin.py b/mkdocs_simple_plugin/plugin.py index 14fc5223..b3b478b8 100644 --- a/mkdocs_simple_plugin/plugin.py +++ b/mkdocs_simple_plugin/plugin.py @@ -36,7 +36,7 @@ ### Example usage (defaults) -{% include "mkdocs_simple_plugin/defaults.snippet" %} +{% include "mkdocs_simple_plugin/example.snippet" %} ### Inline parameters @@ -94,7 +94,6 @@ 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 @@ -102,256 +101,164 @@ from mkdocs_simple_plugin.simple import Simple -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 - +class SimplePlugin(BasePlugin): + """SimplePlugin adds documentation throughout your repo to a mkdocs wiki.""" -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 - # ### 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() + 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 + # + # ``` + # + } + ] + } + ])) ) - # # /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: SimplePluginConfig, **kwargs): + def on_config(self, config, **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( + config['mkdocs_simple_config'] = yaml.dump( default_config, sort_keys=False, default_flow_style=False, @@ -362,7 +269,7 @@ def on_config(self, config: SimplePluginConfig, **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_" + @@ -372,29 +279,29 @@ def on_config(self, config: SimplePluginConfig, **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.ignore_paths = [ + self.config["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, ignore_paths=self.ignore_paths) + simple = Simple(**self.config) # Merge docs if self.config["merge_docs_dir"]: diff --git a/mkdocs_simple_plugin/semiliterate.py b/mkdocs_simple_plugin/semiliterate.py index 0665af39..5568846a 100644 --- a/mkdocs_simple_plugin/semiliterate.py +++ b/mkdocs_simple_plugin/semiliterate.py @@ -21,6 +21,48 @@ 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, @@ -299,6 +341,37 @@ 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,