diff --git a/CHANGELOG.md b/CHANGELOG.md index 447eeae6..e3da3eb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog ## [Unreleased] +### Added +- Global filters and page filters. + +### Fixed +- Delete prefix in nav menu for heading mode. ## [1.0.9] ### Added diff --git a/docs/appendix/filter.md b/docs/appendix/filter.md deleted file mode 100644 index 0059f39a..00000000 --- a/docs/appendix/filter.md +++ /dev/null @@ -1,17 +0,0 @@ -# Filters and Variables - -## Filters - -* `upper` -* `plain` -* `all` -* `link` -* `apilink` -* `sourcelink` -* `short`: removes prefix - - -## Variables - -* `{default}` -* `{class}` diff --git a/docs/examples/google_style.md b/docs/examples/google_style.md index 205bffda..5723f394 100644 --- a/docs/examples/google_style.md +++ b/docs/examples/google_style.md @@ -149,3 +149,18 @@ In this example, note that: * [Example Google Style Python Docstrings](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html#example-google) * [Example NumPy Style Python Docstrings](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html#example-numpy) + + +## Heading Mode + +The other mode to create documentation is heading. For example, + +~~~markdown +## ![mkapi](google_style.ExampleClass) +~~~ + +create a `

` tag for the `google_style.ExampleClass`. + +## ![mkapi](google_style.ExampleClass) + +Note that an ExampleClass item in nav menu is created. diff --git a/docs/examples/numpy_style.md b/docs/examples/numpy_style.md index b7e4e28e..25607f53 100644 --- a/docs/examples/numpy_style.md +++ b/docs/examples/numpy_style.md @@ -149,3 +149,18 @@ In this example, note that: * [Example Google Style Python Docstrings](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html#example-google) * [Example NumPy Style Python Docstrings](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html#example-numpy) + + +## Heading Mode + +The other mode to create documentation is heading. For example, + +~~~markdown +## ![mkapi](numpy_style.ExampleClass) +~~~ + +create a `

` tag for the `google_style.ExampleClass`. + +## ![mkapi](numpy_style.ExampleClass) + +Note that an ExampleClass item in nav menu is created. diff --git a/docs/usage/filter.md b/docs/usage/filter.md new file mode 100644 index 00000000..e561ef44 --- /dev/null +++ b/docs/usage/filter.md @@ -0,0 +1,99 @@ +# Filters + + + +{{ # cache:clear }} + +```python hide +import sys + +if '../../examples' not in sys.path: + sys.path.insert(0, '../../examples') +``` + +## List of Filters + +### upper + +Use upper case letters for package and module object. + +~~~markdown +### ![mkapi](filter) +~~~ + +### ![mkapi](filter) + +~~~markdown +### ![mkapi](filter|upper) +~~~ + +### ![mkapi](filter|upper) + +### short + +Remove prefix. + +~~~markdown +![mkapi](filter.C) +~~~ + +![mkapi](filter.C) + +~~~markdown +![mkapi](filter.C|short) +~~~ + +![mkapi](filter.C|short) + + +### strict + +Show parameters and attributes even if their description is missing. + +~~~markdown +![mkapi](filter.func|strict) +~~~ + +![mkapi](filter.func|strict) + + +## Scope of Filters + +### Page Scope + +For page scope filters, use empty object. + +~~~markdown +![mkapi](|short) +~~~ +~~~markdown +![mkapi](filter.gen) +~~~ +~~~markdown +![mkapi](filter.C) +~~~ + +![mkapi](|short) +![mkapi](filter.gen) +![mkapi](filter.C) + +### Global Scope + +In `mkdocs.yaml`, select global filters: + +~~~yml +# mkdocs.yml +plugins: + - search + - mkapi: + src_dirs: [examples] + filters: [short, strict] +~~~ diff --git a/docs/usage/module.md b/docs/usage/module.md index 15c41a30..ddaffc3b 100644 --- a/docs/usage/module.md +++ b/docs/usage/module.md @@ -58,7 +58,7 @@ If you prefer upper case heading, use the `upper` filter. ## Display Members -`all` filter generates entire module documentation including class and function members. Note that Classes and Functions sections have links to the members +`all` filter generates entire module documentation including class and function members. Note that Classes and Functions sections have links to the members. ~~~ ### ![mkapi](google_style|upper|all) diff --git a/examples/filter.py b/examples/filter.py new file mode 100644 index 00000000..b7d3a243 --- /dev/null +++ b/examples/filter.py @@ -0,0 +1,14 @@ +from typing import Iterator + + +def func(x: int): + """Function.""" + + +def gen() -> Iterator[int]: + """Generator.""" + yield 1 + + +class C: + """Class.""" diff --git a/mkapi/__init__.py b/mkapi/__init__.py index 0570e5c8..eb6e77ee 100644 --- a/mkapi/__init__.py +++ b/mkapi/__init__.py @@ -1,4 +1,4 @@ -__version__ = "1.0.9" +__version__ = "1.0.10" from mkapi.core.module import get_module from mkapi.core.node import get_node diff --git a/mkapi/core/page.py b/mkapi/core/page.py index 911dbeae..521fd8f2 100644 --- a/mkapi/core/page.py +++ b/mkapi/core/page.py @@ -1,7 +1,7 @@ """This module provides a Page class that works with other converter.""" import re from dataclasses import InitVar, dataclass, field -from typing import Iterator, List, Union +from typing import Iterator, List, Tuple, Union from mkapi import utils from mkapi.core import postprocess @@ -30,8 +30,12 @@ class Page: source: InitVar[str] abs_src_path: str abs_api_paths: List[str] = field(default_factory=list, repr=False) + filters: List[str] = field(default_factory=list, repr=False) markdown: str = field(init=False, repr=False) nodes: List[Union[Node, Code]] = field(default_factory=list, init=False, repr=False) + headings: List[Tuple[int, str]] = field( + default_factory=list, init=False, repr=False + ) def __post_init__(self, source): self.markdown = "\n\n".join(self.split(source)) @@ -47,15 +51,21 @@ def resolve_link_from_base(self, base: Base): def split(self, source: str) -> Iterator[str]: cursor = 0 callback = self.resolve_link_from_base - for index, match in enumerate(MKAPI_PATTERN.finditer(source)): + index = 0 + for match in MKAPI_PATTERN.finditer(source): start, end = match.start(), match.end() if cursor < start: markdown = source[cursor:start].strip() if markdown: yield self.resolve_link(markdown) + cursor = end heading, name = match.groups() level = len(heading) name, filters = utils.split_filters(name) + if not name: + self.filters = filters + continue + filters = utils.update_filters(self.filters, filters) if "code" in filters: code = get_code(name) self.nodes.append(code) @@ -66,8 +76,10 @@ def split(self, source: str) -> Iterator[str]: postprocess.transform(node, filters) self.nodes.append(node) markdown = node.get_markdown(level, callback=callback) + if level: + self.headings.append((level, node.object.id)) yield node_markdown(index, markdown, filters) - cursor = end + index += 1 if cursor < len(source): markdown = source[cursor:].strip() if markdown: diff --git a/mkapi/plugins/api.py b/mkapi/plugins/api.py index cce442fa..a75ccc24 100644 --- a/mkapi/plugins/api.py +++ b/mkapi/plugins/api.py @@ -11,7 +11,7 @@ logger = logging.getLogger("mkdocs") -def create_nav(config): +def create_nav(config, global_filters): nav = config["nav"] docs_dir = config["docs_dir"] config_dir = os.path.dirname(config["config_file_path"]) @@ -20,12 +20,14 @@ def create_nav(config): if isinstance(page, dict): for key, value in page.items(): if isinstance(value, str) and value.startswith("mkapi/"): - page[key], abs_api_paths_ = collect(value, docs_dir, config_dir) + page[key], abs_api_paths_ = collect( + value, docs_dir, config_dir, global_filters + ) abs_api_paths.extend(abs_api_paths_) return config, abs_api_paths -def collect(path: str, docs_dir: str, config_dir) -> Tuple[list, list]: +def collect(path: str, docs_dir: str, config_dir, global_filters) -> Tuple[list, list]: _, api_path, *paths, package_path = path.split("/") abs_api_path = os.path.join(docs_dir, api_path) if os.path.exists(abs_api_path): @@ -40,6 +42,7 @@ def collect(path: str, docs_dir: str, config_dir) -> Tuple[list, list]: sys.path.insert(0, root) package_path, filters = utils.split_filters(package_path) + filters = utils.update_filters(global_filters, filters) module = get_module(package_path) nav = [] diff --git a/mkapi/plugins/mkdocs.py b/mkapi/plugins/mkdocs.py index 76171025..9c81a6be 100644 --- a/mkapi/plugins/mkdocs.py +++ b/mkapi/plugins/mkdocs.py @@ -28,6 +28,7 @@ class MkapiPlugin(BasePlugin): config_scheme = ( ("src_dirs", config_options.Type(list, default=[])), ("on_config", config_options.Type(str, default="")), + ("filters", config_options.Type(list, default=[])), ("callback", config_options.Type(str, default="")), ) server = None @@ -46,7 +47,9 @@ def on_config(self, config): self.pages = {} self.abs_api_paths = [] if not self.server: - config, self.abs_api_paths = mkapi.plugins.api.create_nav(config) + config, self.abs_api_paths = mkapi.plugins.api.create_nav( + config, self.config["filters"] + ) global_config["config"] = config global_config["abs_api_paths"] = self.abs_api_paths else: @@ -109,7 +112,9 @@ def on_page_markdown(self, markdown, page, config, files): """Converts Markdown source to intermidiate version.""" abs_src_path = page.file.abs_src_path clean_page_title(page) - page = Page(markdown, abs_src_path, self.abs_api_paths) + page = Page( + markdown, abs_src_path, self.abs_api_paths, filters=self.config["filters"] + ) self.pages[abs_src_path] = page return page.markdown @@ -125,6 +130,9 @@ def on_page_context(self, context, page, config, nav): abs_src_path = page.file.abs_src_path if abs_src_path in self.abs_api_paths: clear_prefix(page.toc, 2) + else: + for level, id in self.pages[abs_src_path].headings: + clear_prefix(page.toc, level, id) return context def on_serve(self, server, config, builder): @@ -135,9 +143,9 @@ def on_serve(self, server, config, builder): return server -def clear_prefix(toc, level: int): +def clear_prefix(toc, level: int, id: str = ""): for toc_item in toc: - if toc_item.level >= level: + if toc_item.level >= level and (not id or toc_item.title == id): toc_item.title = toc_item.title.split(".")[-1] clear_prefix(toc_item.children, level) return diff --git a/mkapi/utils.py b/mkapi/utils.py index 28f63b80..54f7577f 100644 --- a/mkapi/utils.py +++ b/mkapi/utils.py @@ -1,5 +1,5 @@ import importlib -from typing import Any +from typing import Any, List def get_indent(line: str) -> int: @@ -57,9 +57,35 @@ def split_filters(name): ('a.b.c', []) >>> split_filters("a.b.c|upper|strict") ('a.b.c', ['upper', 'strict']) + >>> split_filters("|upper|strict") + ('', ['upper', 'strict']) + >>> split_filters("") + ('', []) """ index = name.find("|") if index == -1: return name, [] name, filters = name[:index], name[index + 1 :] return name, filters.split("|") + + +def update_filters(org: List[str], update: List[str]) -> List[str]: + """ + Examples: + >>> update_filters(['upper'], ['lower']) + ['lower'] + >>> update_filters(['lower'], ['upper']) + ['upper'] + >>> update_filters(['long'], ['short']) + ['short'] + >>> update_filters(['short'], ['long']) + ['long'] + """ + filters = org + update + for x, y in [["lower", "upper"], ["long", "short"]]: + if x in org and y in update: + del filters[filters.index(x)] + if y in org and x in update: + del filters[filters.index(y)] + + return filters diff --git a/mkdocs.yml b/mkdocs.yml index 0e137b02..46995273 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -33,6 +33,7 @@ nav: - usage/module.md - usage/inherit.md - usage/page.md + - usage/filter.md - usage/library.py - usage/custom.md - Appendix: @@ -41,7 +42,6 @@ nav: - appendix/inherit.md - appendix/order.md - appendix/decorator.md - - appendix/filter.md - API: mkapi/api/mkapi|upper|strict markdown_extensions: