zensical 0.0.3__cp310-abi3-musllinux_1_2_i686.whl → 0.0.12__cp310-abi3-musllinux_1_2_i686.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of zensical might be problematic. Click here for more details.
- zensical/__init__.py +6 -6
- zensical/__main__.py +28 -0
- zensical/bootstrap/.github/workflows/docs.yml +10 -3
- zensical/bootstrap/zensical.toml +22 -22
- zensical/config.py +191 -197
- zensical/extensions/__init__.py +2 -2
- zensical/extensions/emoji.py +22 -27
- zensical/extensions/links.py +33 -24
- zensical/extensions/preview.py +29 -41
- zensical/extensions/search.py +83 -83
- zensical/extensions/utilities/__init__.py +2 -2
- zensical/extensions/utilities/filter.py +5 -10
- zensical/main.py +36 -47
- zensical/markdown.py +21 -20
- zensical/templates/assets/javascripts/bundle.21aa498e.min.js +3 -0
- zensical/templates/assets/javascripts/workers/{search.5e1f2129.min.js → search.5df7522c.min.js} +1 -1
- zensical/templates/assets/stylesheets/classic/main.6f483be1.min.css +1 -0
- zensical/templates/assets/stylesheets/modern/main.09f707be.min.css +1 -0
- zensical/templates/base.html +4 -4
- zensical/templates/partials/javascripts/base.html +1 -1
- zensical/templates/partials/nav-item.html +1 -1
- zensical/templates/partials/search.html +3 -1
- zensical/zensical.abi3.so +0 -0
- zensical/zensical.pyi +7 -13
- {zensical-0.0.3.dist-info → zensical-0.0.12.dist-info}/METADATA +9 -4
- {zensical-0.0.3.dist-info → zensical-0.0.12.dist-info}/RECORD +30 -29
- {zensical-0.0.3.dist-info → zensical-0.0.12.dist-info}/WHEEL +1 -1
- {zensical-0.0.3.dist-info → zensical-0.0.12.dist-info}/licenses/LICENSE.md +1 -1
- zensical.libs/libgcc_s-f5fcfe20.so.1 +0 -0
- zensical/templates/assets/javascripts/bundle.3c403d54.min.js +0 -3
- zensical/templates/assets/stylesheets/classic/main.c5ffb0a9.min.css +0 -1
- zensical/templates/assets/stylesheets/modern/main.1357c24d.min.css +0 -1
- zensical.libs/libgcc_s-27e5a392.so.1 +0 -0
- {zensical-0.0.3.dist-info → zensical-0.0.12.dist-info}/entry_points.txt +0 -0
zensical/extensions/__init__.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# Copyright (c) Zensical
|
|
1
|
+
# Copyright (c) 2025 Zensical and contributors
|
|
2
2
|
|
|
3
3
|
# SPDX-License-Identifier: MIT
|
|
4
|
-
# Third-party contributions licensed under
|
|
4
|
+
# Third-party contributions licensed under DCO
|
|
5
5
|
|
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
7
|
# of this software and associated documentation files (the "Software"), to
|
zensical/extensions/emoji.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# Copyright (c) Zensical
|
|
1
|
+
# Copyright (c) 2025 Zensical and contributors
|
|
2
2
|
|
|
3
3
|
# SPDX-License-Identifier: MIT
|
|
4
|
-
# Third-party contributions licensed under
|
|
4
|
+
# Third-party contributions licensed under DCO
|
|
5
5
|
|
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
7
|
# of this software and associated documentation files (the "Software"), to
|
|
@@ -26,21 +26,22 @@ from __future__ import annotations
|
|
|
26
26
|
import codecs
|
|
27
27
|
import functools
|
|
28
28
|
import os
|
|
29
|
-
|
|
30
29
|
from glob import iglob
|
|
31
|
-
from
|
|
32
|
-
from pymdownx import emoji, twemoji_db
|
|
30
|
+
from typing import TYPE_CHECKING
|
|
33
31
|
from xml.etree.ElementTree import Element
|
|
34
32
|
|
|
33
|
+
from pymdownx import emoji, twemoji_db
|
|
34
|
+
|
|
35
|
+
if TYPE_CHECKING:
|
|
36
|
+
from markdown import Markdown
|
|
37
|
+
|
|
35
38
|
# -----------------------------------------------------------------------------
|
|
36
39
|
# Functions
|
|
37
40
|
# -----------------------------------------------------------------------------
|
|
38
41
|
|
|
39
42
|
|
|
40
|
-
def twemoji(options:
|
|
41
|
-
"""
|
|
42
|
-
Create twemoji index.
|
|
43
|
-
"""
|
|
43
|
+
def twemoji(options: dict, md: Markdown) -> dict: # noqa: ARG001
|
|
44
|
+
"""Create twemoji index."""
|
|
44
45
|
paths = options.get("custom_icons", [])[:]
|
|
45
46
|
return _load_twemoji_index(tuple(paths))
|
|
46
47
|
|
|
@@ -53,14 +54,12 @@ def to_svg(
|
|
|
53
54
|
alt: str,
|
|
54
55
|
title: str,
|
|
55
56
|
category: str,
|
|
56
|
-
options:
|
|
57
|
+
options: dict,
|
|
57
58
|
md: Markdown,
|
|
58
|
-
):
|
|
59
|
-
"""
|
|
60
|
-
Load icon.
|
|
61
|
-
"""
|
|
59
|
+
) -> Element[str]:
|
|
60
|
+
"""Load icon."""
|
|
62
61
|
if not uc:
|
|
63
|
-
icons = md.inlinePatterns["emoji"].emoji_index["emoji"]
|
|
62
|
+
icons = md.inlinePatterns["emoji"].emoji_index["emoji"] # type: ignore[attr-defined]
|
|
64
63
|
|
|
65
64
|
# Create and return element to host icon
|
|
66
65
|
el = Element("span", {"class": options.get("classes", index)})
|
|
@@ -78,20 +77,16 @@ def to_svg(
|
|
|
78
77
|
# -----------------------------------------------------------------------------
|
|
79
78
|
|
|
80
79
|
|
|
81
|
-
@functools.
|
|
82
|
-
def _load(file: str):
|
|
83
|
-
"""
|
|
84
|
-
Load icon from file.
|
|
85
|
-
"""
|
|
80
|
+
@functools.cache
|
|
81
|
+
def _load(file: str) -> str:
|
|
82
|
+
"""Load icon from file."""
|
|
86
83
|
with codecs.open(file, encoding="utf-8") as f:
|
|
87
84
|
return f.read()
|
|
88
85
|
|
|
89
86
|
|
|
90
|
-
@functools.
|
|
91
|
-
def _load_twemoji_index(paths):
|
|
92
|
-
"""
|
|
93
|
-
Load twemoji index and add icons.
|
|
94
|
-
"""
|
|
87
|
+
@functools.cache
|
|
88
|
+
def _load_twemoji_index(paths: tuple[str, ...]) -> dict:
|
|
89
|
+
"""Load twemoji index and add icons."""
|
|
95
90
|
index = {
|
|
96
91
|
"name": "twemoji",
|
|
97
92
|
"emoji": twemoji_db.emoji,
|
|
@@ -106,8 +101,8 @@ def _load_twemoji_index(paths):
|
|
|
106
101
|
|
|
107
102
|
# Index icons provided by the theme and via custom icons
|
|
108
103
|
glob = os.path.join(base, "**", "*.svg")
|
|
109
|
-
|
|
110
|
-
for file in
|
|
104
|
+
svgs = iglob(os.path.normpath(glob), recursive=True)
|
|
105
|
+
for file in svgs:
|
|
111
106
|
icon = file[len(base) + 1 : -4].replace(os.path.sep, "-")
|
|
112
107
|
|
|
113
108
|
# Add icon to index
|
zensical/extensions/links.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# Copyright (c) Zensical
|
|
1
|
+
# Copyright (c) 2025 Zensical and contributors
|
|
2
2
|
|
|
3
3
|
# SPDX-License-Identifier: MIT
|
|
4
|
-
# Third-party contributions licensed under
|
|
4
|
+
# Third-party contributions licensed under DCO
|
|
5
5
|
|
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
7
|
# of this software and associated documentation files (the "Software"), to
|
|
@@ -23,11 +23,17 @@
|
|
|
23
23
|
|
|
24
24
|
from __future__ import annotations
|
|
25
25
|
|
|
26
|
+
from pathlib import PurePosixPath
|
|
27
|
+
from typing import TYPE_CHECKING
|
|
28
|
+
from urllib.parse import urlparse
|
|
29
|
+
|
|
26
30
|
from markdown import Extension, Markdown
|
|
27
31
|
from markdown.treeprocessors import Treeprocessor
|
|
28
32
|
from markdown.util import AMP_SUBSTITUTE
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
|
|
34
|
+
if TYPE_CHECKING:
|
|
35
|
+
from xml.etree.ElementTree import Element
|
|
36
|
+
|
|
31
37
|
|
|
32
38
|
# -----------------------------------------------------------------------------
|
|
33
39
|
# Classes
|
|
@@ -35,8 +41,7 @@ from urllib.parse import urlparse
|
|
|
35
41
|
|
|
36
42
|
|
|
37
43
|
class LinksProcessor(Treeprocessor):
|
|
38
|
-
"""
|
|
39
|
-
Tree processor to replace links in Markdown with URLs.
|
|
44
|
+
"""Tree processor to replace links in Markdown with URLs.
|
|
40
45
|
|
|
41
46
|
Note that we view this as a bandaid until we can do processing on proper
|
|
42
47
|
HTML ASTs in Rust. In the meantime, we just replace them as we find them.
|
|
@@ -49,10 +54,10 @@ class LinksProcessor(Treeprocessor):
|
|
|
49
54
|
self.path = path # Current page
|
|
50
55
|
self.use_directory_urls = use_directory_urls
|
|
51
56
|
|
|
52
|
-
def run(self, root: Element):
|
|
57
|
+
def run(self, root: Element) -> None:
|
|
53
58
|
# Now, we determine whether the current page is an index page, as we
|
|
54
59
|
# must apply slightly different handling in case of directory URLs
|
|
55
|
-
current_is_index = self.path
|
|
60
|
+
current_is_index = get_name(self.path) in ("index.md", "README.md")
|
|
56
61
|
for el in root.iter():
|
|
57
62
|
# In case the element has a `href` or `src` attribute, we parse it
|
|
58
63
|
# as an URL, so we can analyze and alter its path
|
|
@@ -63,7 +68,7 @@ class LinksProcessor(Treeprocessor):
|
|
|
63
68
|
# Extract value - Python Markdown does some weird stuff where it
|
|
64
69
|
# replaces mailto: links with double encoded entities. MkDocs just
|
|
65
70
|
# skips if it detects that, so we do the same.
|
|
66
|
-
value = el.get(key)
|
|
71
|
+
value = el.get(key, "")
|
|
67
72
|
if AMP_SUBSTITUTE in value:
|
|
68
73
|
continue
|
|
69
74
|
|
|
@@ -81,10 +86,9 @@ class LinksProcessor(Treeprocessor):
|
|
|
81
86
|
if path.endswith(".md"):
|
|
82
87
|
path = path.removesuffix(".md") + ".html"
|
|
83
88
|
if self.use_directory_urls:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
path = path[: -len("README.html")]
|
|
89
|
+
name = get_name(path)
|
|
90
|
+
if name in ("index.html", "README.html"):
|
|
91
|
+
path = path[: -len(name)]
|
|
88
92
|
elif path.endswith(".html"):
|
|
89
93
|
path = path[: -len(".html")] + "/"
|
|
90
94
|
|
|
@@ -101,21 +105,15 @@ class LinksProcessor(Treeprocessor):
|
|
|
101
105
|
|
|
102
106
|
|
|
103
107
|
class LinksExtension(Extension):
|
|
104
|
-
"""
|
|
105
|
-
A Markdown extension to resolve links to other Markdown files.
|
|
106
|
-
"""
|
|
108
|
+
"""A Markdown extension to resolve links to other Markdown files."""
|
|
107
109
|
|
|
108
110
|
def __init__(self, path: str, use_directory_urls: bool):
|
|
109
|
-
"""
|
|
110
|
-
Initialize the extension.
|
|
111
|
-
"""
|
|
111
|
+
"""Initialize the extension."""
|
|
112
112
|
self.path = path # Current page
|
|
113
113
|
self.use_directory_urls = use_directory_urls
|
|
114
114
|
|
|
115
|
-
def extendMarkdown(self, md: Markdown):
|
|
116
|
-
"""
|
|
117
|
-
Register Markdown extension.
|
|
118
|
-
"""
|
|
115
|
+
def extendMarkdown(self, md: Markdown) -> None: # noqa: N802
|
|
116
|
+
"""Register Markdown extension."""
|
|
119
117
|
md.registerExtension(self)
|
|
120
118
|
|
|
121
119
|
# Create and register treeprocessor - we use the same priority as the
|
|
@@ -123,4 +121,15 @@ class LinksExtension(Extension):
|
|
|
123
121
|
# after our treeprocessor, so we can check the original Markdown URIs
|
|
124
122
|
# before they are resolved to URLs.
|
|
125
123
|
processor = LinksProcessor(md, self.path, self.use_directory_urls)
|
|
126
|
-
md.treeprocessors.register(processor, "
|
|
124
|
+
md.treeprocessors.register(processor, "zrelpath", 0)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
# -----------------------------------------------------------------------------
|
|
128
|
+
# Functions
|
|
129
|
+
# -----------------------------------------------------------------------------
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def get_name(path: str) -> str:
|
|
133
|
+
"""Get the name of a file from a given path."""
|
|
134
|
+
pure_path = PurePosixPath(path)
|
|
135
|
+
return pure_path.name
|
zensical/extensions/preview.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# Copyright (c) Zensical
|
|
1
|
+
# Copyright (c) 2025 Zensical and contributors
|
|
2
2
|
|
|
3
3
|
# SPDX-License-Identifier: MIT
|
|
4
|
-
# Third-party contributions licensed under
|
|
4
|
+
# Third-party contributions licensed under DCO
|
|
5
5
|
|
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
7
|
# of this software and associated documentation files (the "Software"), to
|
|
@@ -24,14 +24,17 @@
|
|
|
24
24
|
from __future__ import annotations
|
|
25
25
|
|
|
26
26
|
import posixpath
|
|
27
|
+
from typing import TYPE_CHECKING, Any
|
|
28
|
+
from urllib.parse import urlparse
|
|
27
29
|
|
|
28
30
|
from markdown import Extension, Markdown
|
|
29
31
|
from markdown.treeprocessors import Treeprocessor
|
|
30
|
-
from urllib.parse import urlparse
|
|
31
|
-
from xml.etree.ElementTree import Element
|
|
32
32
|
|
|
33
|
-
from .links import LinksProcessor
|
|
34
|
-
from .utilities.filter import Filter
|
|
33
|
+
from zensical.extensions.links import LinksProcessor
|
|
34
|
+
from zensical.extensions.utilities.filter import Filter
|
|
35
|
+
|
|
36
|
+
if TYPE_CHECKING:
|
|
37
|
+
from xml.etree.ElementTree import Element
|
|
35
38
|
|
|
36
39
|
# -----------------------------------------------------------------------------
|
|
37
40
|
# Classes
|
|
@@ -39,25 +42,20 @@ from .utilities.filter import Filter
|
|
|
39
42
|
|
|
40
43
|
|
|
41
44
|
class PreviewProcessor(Treeprocessor):
|
|
42
|
-
"""
|
|
43
|
-
A Markdown treeprocessor to enable instant previews on links.
|
|
45
|
+
"""A Markdown treeprocessor to enable instant previews on links.
|
|
44
46
|
|
|
45
47
|
Note that this treeprocessor is dependent on the `links` treeprocessor
|
|
46
48
|
registered programmatically before rendering a page.
|
|
47
49
|
"""
|
|
48
50
|
|
|
49
51
|
def __init__(self, md: Markdown, config: dict):
|
|
50
|
-
"""
|
|
51
|
-
Initialize the treeprocessor.
|
|
52
|
-
"""
|
|
52
|
+
"""Initialize the treeprocessor."""
|
|
53
53
|
super().__init__(md)
|
|
54
54
|
self.config = config
|
|
55
55
|
|
|
56
|
-
def run(self, root: Element):
|
|
57
|
-
"""
|
|
58
|
-
|
|
59
|
-
"""
|
|
60
|
-
at = self.md.treeprocessors.get_index_for_name("relpath")
|
|
56
|
+
def run(self, root: Element) -> None:
|
|
57
|
+
"""Run the treeprocessor."""
|
|
58
|
+
at = self.md.treeprocessors.get_index_for_name("zrelpath")
|
|
61
59
|
|
|
62
60
|
# Hack: Python Markdown has no notion of where it is, i.e., which file
|
|
63
61
|
# is being processed. This seems to be a deliberate design decision, as
|
|
@@ -84,9 +82,10 @@ class PreviewProcessor(Treeprocessor):
|
|
|
84
82
|
# Walk through all configurations - @todo refactor so that we don't
|
|
85
83
|
# iterate multiple times over the same elements
|
|
86
84
|
for configuration in configurations:
|
|
87
|
-
if not configuration.get("sources")
|
|
88
|
-
|
|
89
|
-
|
|
85
|
+
if not configuration.get("sources") and not configuration.get(
|
|
86
|
+
"targets"
|
|
87
|
+
):
|
|
88
|
+
continue
|
|
90
89
|
|
|
91
90
|
# Skip if page should not be considered
|
|
92
91
|
filter = get_filter(configuration, "sources")
|
|
@@ -123,8 +122,7 @@ class PreviewProcessor(Treeprocessor):
|
|
|
123
122
|
|
|
124
123
|
|
|
125
124
|
class PreviewExtension(Extension):
|
|
126
|
-
"""
|
|
127
|
-
A Markdown extension to enable instant previews on links.
|
|
125
|
+
"""A Markdown extension to enable instant previews on links.
|
|
128
126
|
|
|
129
127
|
This extensions allows to automatically add the `data-preview` attribute to
|
|
130
128
|
internal links matching specific criteria, so Material for MkDocs renders a
|
|
@@ -132,10 +130,8 @@ class PreviewExtension(Extension):
|
|
|
132
130
|
add previews to links in a programmatic way.
|
|
133
131
|
"""
|
|
134
132
|
|
|
135
|
-
def __init__(self, *args, **kwargs):
|
|
136
|
-
"""
|
|
137
|
-
Initialize the extension.
|
|
138
|
-
"""
|
|
133
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
134
|
+
"""Initialize the extension."""
|
|
139
135
|
self.config = {
|
|
140
136
|
"configurations": [[], "Filter configurations"],
|
|
141
137
|
"sources": [{}, "Link sources"],
|
|
@@ -143,10 +139,8 @@ class PreviewExtension(Extension):
|
|
|
143
139
|
}
|
|
144
140
|
super().__init__(*args, **kwargs)
|
|
145
141
|
|
|
146
|
-
def extendMarkdown(self, md: Markdown):
|
|
147
|
-
"""
|
|
148
|
-
Register Markdown extension.
|
|
149
|
-
"""
|
|
142
|
+
def extendMarkdown(self, md: Markdown) -> None: # noqa: N802
|
|
143
|
+
"""Register Markdown extension."""
|
|
150
144
|
md.registerExtension(self)
|
|
151
145
|
|
|
152
146
|
# Create and register treeprocessor - we use the same priority as the
|
|
@@ -162,17 +156,13 @@ class PreviewExtension(Extension):
|
|
|
162
156
|
# -----------------------------------------------------------------------------
|
|
163
157
|
|
|
164
158
|
|
|
165
|
-
def get_filter(settings: dict, key: str):
|
|
166
|
-
"""
|
|
167
|
-
|
|
168
|
-
"""
|
|
169
|
-
return Filter(config=settings.get(key)) # type: ignore
|
|
159
|
+
def get_filter(settings: dict, key: str) -> Filter:
|
|
160
|
+
"""Get file filter from settings."""
|
|
161
|
+
return Filter(config=settings.get(key, {}))
|
|
170
162
|
|
|
171
163
|
|
|
172
164
|
def resolve(processor_path: str, url_path: str) -> str:
|
|
173
|
-
"""
|
|
174
|
-
Resolve a relative URL path against the processor path.
|
|
175
|
-
"""
|
|
165
|
+
"""Resolve a relative URL path against the processor path."""
|
|
176
166
|
# Remove the file name from the processor path to get the directory
|
|
177
167
|
base_path = posixpath.dirname(processor_path)
|
|
178
168
|
|
|
@@ -194,8 +184,6 @@ def resolve(processor_path: str, url_path: str) -> str:
|
|
|
194
184
|
return posixpath.join(*base_segments)
|
|
195
185
|
|
|
196
186
|
|
|
197
|
-
def makeExtension(**kwargs):
|
|
198
|
-
"""
|
|
199
|
-
Register Markdown extension.
|
|
200
|
-
"""
|
|
187
|
+
def makeExtension(**kwargs: Any) -> PreviewExtension: # noqa: N802
|
|
188
|
+
"""Register Markdown extension."""
|
|
201
189
|
return PreviewExtension(**kwargs)
|