From 9d75fefb81dc8d8c764ee53c24c6fb31c710b4d2 Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Tue, 12 Jul 2022 12:14:41 -0700 Subject: [PATCH] feat: Add `extract_on_copy` option Previously, mkdocs_semiliterate would always attempt to extract documentation from a file, even if it matched the `include_extensions` pattern for files to be copied to the documentation site verbatim. Now, by default, such files are not considered candidates for extraction, even if they match a semiliterate pattern. Adds a configuration option `extract_on_copy` which can be set to `true` to restore the prior behavior. Also adds tests for the behavior with and without `extract_on_copy` and makes all `mkdocs build` commands in the tests strict, which they always should have been. Resolves #17. --- README.md | 6 +- assets/icons8-ask-question-100.png | Bin 0 -> 6098 bytes mkdocs.yml | 2 +- mkdocs_semiliterate/plugin.py | 8 +- setup.cfg | 4 +- tests/bootstrap.manifest | 2 + tests/fixtures/extract-inclusion/README.md | 6 + .../assets/icons8-ask-question-100.png | Bin 0 -> 6098 bytes tests/fixtures/extract-inclusion/mkdocs.yml | 12 + tests/fixtures/extract-inclusion/raw.txt | 7 + .../refsite/404.html.cropped | 104 ++++++ .../extract-inclusion/refsite/css/base.css | 318 ++++++++++++++++++ .../refsite/css/bootstrap.min.css | 12 + .../refsite/css/font-awesome.min.css | 4 + .../refsite/index.html.cropped | 131 ++++++++ .../refsite/polished/index.html.cropped | 127 +++++++ .../extract-inclusion/refsite/raw.txt | 7 + tests/fixtures/no-extract-inclusion/README.md | 3 + .../assets/icons8-ask-question-100.png | Bin 0 -> 6098 bytes .../fixtures/no-extract-inclusion/mkdocs.yml | 6 + .../refsite/404.html.cropped | 91 +++++ .../assets/icons8-ask-question-100.png | Bin 0 -> 6098 bytes .../no-extract-inclusion/refsite/css/base.css | 318 ++++++++++++++++++ .../refsite/css/bootstrap.min.css | 12 + .../refsite/css/font-awesome.min.css | 4 + .../refsite/index.html.cropped | 107 ++++++ tests/sites.bash | 2 +- 27 files changed, 1285 insertions(+), 8 deletions(-) create mode 100644 assets/icons8-ask-question-100.png create mode 100644 tests/fixtures/extract-inclusion/README.md create mode 100644 tests/fixtures/extract-inclusion/assets/icons8-ask-question-100.png create mode 100644 tests/fixtures/extract-inclusion/mkdocs.yml create mode 100644 tests/fixtures/extract-inclusion/raw.txt create mode 100644 tests/fixtures/extract-inclusion/refsite/404.html.cropped create mode 100644 tests/fixtures/extract-inclusion/refsite/css/base.css create mode 100644 tests/fixtures/extract-inclusion/refsite/css/bootstrap.min.css create mode 100644 tests/fixtures/extract-inclusion/refsite/css/font-awesome.min.css create mode 100644 tests/fixtures/extract-inclusion/refsite/index.html.cropped create mode 100644 tests/fixtures/extract-inclusion/refsite/polished/index.html.cropped create mode 100644 tests/fixtures/extract-inclusion/refsite/raw.txt create mode 100644 tests/fixtures/no-extract-inclusion/README.md create mode 100644 tests/fixtures/no-extract-inclusion/assets/icons8-ask-question-100.png create mode 100644 tests/fixtures/no-extract-inclusion/mkdocs.yml create mode 100644 tests/fixtures/no-extract-inclusion/refsite/404.html.cropped create mode 100644 tests/fixtures/no-extract-inclusion/refsite/assets/icons8-ask-question-100.png create mode 100644 tests/fixtures/no-extract-inclusion/refsite/css/base.css create mode 100644 tests/fixtures/no-extract-inclusion/refsite/css/bootstrap.min.css create mode 100644 tests/fixtures/no-extract-inclusion/refsite/css/font-awesome.min.css create mode 100644 tests/fixtures/no-extract-inclusion/refsite/index.html.cropped diff --git a/README.md b/README.md index 41c53e0..0e91e8f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# MkDocs semiliterate Plugin +# ![Dreaming of integrated documentation](assets/icons8-ask-question-100.png) MkDocs semiliterate Plugin This plugin for [MkDocs](http://mkdocs.org) is an extension of Allison Thackston's excellent [mkdocs-simple-plugin](https://athackst.github.io/mkdocs-simple-plugin). It allows you to include content from one file into another (via `{! ... !}` syntax), using exactly the same extraction specification that the `simple` plugin already uses for identifying documentation in source files. @@ -28,6 +28,6 @@ or of course if your `pip` is already set up to use a Python 3.5 (or later) inst `pip install mkdocs-semiliterate` -## License +## License and Acknowledgments -This software is licensed under [Apache 2.0](LICENSE). +This software is licensed under [Apache 2.0](LICENSE). [Icons8](https://icons8.com/icon/115368/ask-question) provided the icon. diff --git a/assets/icons8-ask-question-100.png b/assets/icons8-ask-question-100.png new file mode 100644 index 0000000000000000000000000000000000000000..af590b5d92e30ed7a8357026da0de7a6c040412e GIT binary patch literal 6098 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.*(.*\s*)$', '\1\2\3']] diff --git a/mkdocs_semiliterate/plugin.py b/mkdocs_semiliterate/plugin.py index 08e86d0..94894f5 100644 --- a/mkdocs_semiliterate/plugin.py +++ b/mkdocs_semiliterate/plugin.py @@ -320,7 +320,7 @@ terminate: '^\s*\)' # `semiliterate` still incorporates all standard Markdown files # because of the following `extract_standard_markdown` parameter. ('extract_standard_markdown', - config_options.Type(dict, default={})) + config_options.Type(dict, default={})), # If the `enable` key of this dict parameter is true # (it defaults to the opposite of `copy_standard_markdown`), # it adds a semiliterate block causing extraction (and hence @@ -333,6 +333,10 @@ terminate: '^\s*\)' # (which is also the default when `copy_standard_markdown` is true) # will prevent automatic extraction (and hence disable # inclusion-directive processing) from standard Markdown files. + ('extract_on_copy', + config_options.Type(bool, default=False)), + # Whether to also attempt extraction from a file that is copied + # verbatim (because of matching the `include_extensions`). ) def on_config(self, config, **kwargs): @@ -365,6 +369,8 @@ terminate: '^\s*\)' def extract_from(self, from_directory, name, to_directory): if any(ext in name for ext in self.exclude_extensions): return False + if not self.config['extract_on_copy'] and self.in_extensions(name): + return False return super().extract_from(from_directory, name, to_directory) diff --git a/setup.cfg b/setup.cfg index c2e4615..200050d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = mkdocs-semiliterate -version = 0.3.0 +version = 0.4.0 description = Extension of mkdocs-simple-plugin adding easy content inclusion long_description = file: README.md long_description_content_type = text/markdown @@ -25,7 +25,7 @@ license = Apache-2.0 packages = mkdocs_semiliterate install_requires = mkdocs - mkdocs-simple-plugin>=1.0.0 + mkdocs-simple-plugin~=1.0 [options.entry_points] mkdocs.plugins = diff --git a/tests/bootstrap.manifest b/tests/bootstrap.manifest index 02e9a20..611e18f 100644 --- a/tests/bootstrap.manifest +++ b/tests/bootstrap.manifest @@ -1,5 +1,7 @@ site site/404.html +site/assets +site/assets/icons8-ask-question-100.png site/css site/css/theme.css site/css/theme_extra.css diff --git a/tests/fixtures/extract-inclusion/README.md b/tests/fixtures/extract-inclusion/README.md new file mode 100644 index 0000000..3476477 --- /dev/null +++ b/tests/fixtures/extract-inclusion/README.md @@ -0,0 +1,6 @@ +# Want to copy and extract + +The [whole text](raw.txt). + +The [extracted markdown](polished.md). + diff --git a/tests/fixtures/extract-inclusion/assets/icons8-ask-question-100.png b/tests/fixtures/extract-inclusion/assets/icons8-ask-question-100.png new file mode 100644 index 0000000000000000000000000000000000000000..af590b5d92e30ed7a8357026da0de7a6c040412e GIT binary patch literal 6098 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