mkdocs-include-markdown-plugin 6.1.1__tar.gz → 6.2.1__tar.gz
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.
- {mkdocs_include_markdown_plugin-6.1.1 → mkdocs_include_markdown_plugin-6.2.1}/PKG-INFO +40 -30
- {mkdocs_include_markdown_plugin-6.1.1 → mkdocs_include_markdown_plugin-6.2.1}/README.md +39 -29
- {mkdocs_include_markdown_plugin-6.1.1 → mkdocs_include_markdown_plugin-6.2.1}/pyproject.toml +1 -1
- {mkdocs_include_markdown_plugin-6.1.1 → mkdocs_include_markdown_plugin-6.2.1}/src/mkdocs_include_markdown_plugin/cache.py +6 -6
- {mkdocs_include_markdown_plugin-6.1.1 → mkdocs_include_markdown_plugin-6.2.1}/src/mkdocs_include_markdown_plugin/directive.py +38 -5
- {mkdocs_include_markdown_plugin-6.1.1 → mkdocs_include_markdown_plugin-6.2.1}/src/mkdocs_include_markdown_plugin/event.py +151 -169
- mkdocs_include_markdown_plugin-6.2.1/src/mkdocs_include_markdown_plugin/logger.py +10 -0
- {mkdocs_include_markdown_plugin-6.1.1 → mkdocs_include_markdown_plugin-6.2.1}/src/mkdocs_include_markdown_plugin/plugin.py +2 -2
- {mkdocs_include_markdown_plugin-6.1.1 → mkdocs_include_markdown_plugin-6.2.1}/src/mkdocs_include_markdown_plugin/process.py +45 -4
- {mkdocs_include_markdown_plugin-6.1.1 → mkdocs_include_markdown_plugin-6.2.1}/.gitignore +0 -0
- {mkdocs_include_markdown_plugin-6.1.1 → mkdocs_include_markdown_plugin-6.2.1}/LICENSE +0 -0
- {mkdocs_include_markdown_plugin-6.1.1 → mkdocs_include_markdown_plugin-6.2.1}/src/mkdocs_include_markdown_plugin/__init__.py +0 -0
- {mkdocs_include_markdown_plugin-6.1.1 → mkdocs_include_markdown_plugin-6.2.1}/src/mkdocs_include_markdown_plugin/config.py +0 -0
- {mkdocs_include_markdown_plugin-6.1.1 → mkdocs_include_markdown_plugin-6.2.1}/src/mkdocs_include_markdown_plugin/files_watcher.py +0 -0
- {mkdocs_include_markdown_plugin-6.1.1 → mkdocs_include_markdown_plugin-6.2.1}/src/mkdocs_include_markdown_plugin/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: mkdocs-include-markdown-plugin
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.2.1
|
|
4
4
|
Summary: Mkdocs Markdown includer plugin.
|
|
5
5
|
Project-URL: Source, https://github.com/mondeja/mkdocs-include-markdown-plugin
|
|
6
6
|
Project-URL: Documentation, https://github.com/mondeja/mkdocs-include-markdown-plugin#documentation
|
|
@@ -43,6 +43,7 @@ Description-Content-Type: text/markdown
|
|
|
43
43
|
[![License][license-image]][license-link]
|
|
44
44
|
[![Tests][tests-image]][tests-link]
|
|
45
45
|
[![Coverage status][coverage-image]][coverage-link]
|
|
46
|
+
[![Downloads][downloads-image]][downloads-link]
|
|
46
47
|
|
|
47
48
|
<!-- mdpo-enable -->
|
|
48
49
|
|
|
@@ -190,9 +191,12 @@ content to include.
|
|
|
190
191
|
- <a name="include-markdown_trailing-newlines" href="#include-markdown_trailing-newlines">#</a>
|
|
191
192
|
**trailing-newlines** (_true_): When this option is disabled, the trailing newlines
|
|
192
193
|
found in the content to include are stripped. Possible values are `true` and `false`.
|
|
194
|
+
- <a name="include-markdown_recursive" href="#include-markdown_recursive">#</a>
|
|
195
|
+
**recursive** (_true_): When this option is disabled, included files are not
|
|
196
|
+
processed for recursive includes. Possible values are `true` and `false`.
|
|
193
197
|
- <a name="include-markdown_encoding" href="#include-markdown_encoding">#</a>
|
|
194
|
-
**encoding** (
|
|
195
|
-
If not defined `utf-8` will be used.
|
|
198
|
+
**encoding** (_'utf-8'_): Specify the encoding of the included file.
|
|
199
|
+
If not defined `'utf-8'` will be used.
|
|
196
200
|
- <a name="include-markdown_rewrite-relative-urls" href="#include-markdown_rewrite-relative-urls">#</a>
|
|
197
201
|
**rewrite-relative-urls** (_true_): When this option is enabled (default),
|
|
198
202
|
Markdown links and images in the content that are specified by a relative URL
|
|
@@ -212,42 +216,42 @@ content to include.
|
|
|
212
216
|
|
|
213
217
|
```jinja
|
|
214
218
|
{%
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
219
|
+
include-markdown "../README.md"
|
|
220
|
+
start="<!--intro-start-->"
|
|
221
|
+
end="<!--intro-end-->"
|
|
218
222
|
%}
|
|
219
223
|
```
|
|
220
224
|
|
|
221
225
|
```jinja
|
|
222
226
|
{%
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
227
|
+
include-markdown 'includes/header.md'
|
|
228
|
+
start='<!--\n\ttable-start\n-->'
|
|
229
|
+
end='<!--\n\ttable-end\n-->'
|
|
230
|
+
rewrite-relative-urls=false
|
|
231
|
+
comments=false
|
|
228
232
|
%}
|
|
229
233
|
```
|
|
230
234
|
|
|
231
235
|
```jinja
|
|
232
236
|
{%
|
|
233
|
-
|
|
234
|
-
|
|
237
|
+
include-markdown "includes/header.md"
|
|
238
|
+
heading-offset=1
|
|
235
239
|
%}
|
|
236
240
|
```
|
|
237
241
|
|
|
238
242
|
```jinja
|
|
239
243
|
{%
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
+
include-markdown "../LICENSE*"
|
|
245
|
+
start="<!--license \"start\" -->"
|
|
246
|
+
end='<!--license "end" -->'
|
|
247
|
+
exclude="../*.rst"
|
|
244
248
|
%}
|
|
245
249
|
```
|
|
246
250
|
|
|
247
251
|
```jinja
|
|
248
252
|
{%
|
|
249
|
-
|
|
250
|
-
|
|
253
|
+
include-markdown "**"
|
|
254
|
+
exclude="./{index,LICENSE}.md"
|
|
251
255
|
%}
|
|
252
256
|
```
|
|
253
257
|
|
|
@@ -278,12 +282,12 @@ Includes the content of a file or a group of files.
|
|
|
278
282
|
- <a name="include_trailing-newlines" href="#include_trailing-newlines">#</a>
|
|
279
283
|
**trailing-newlines** (_true_): When this option is disabled, the trailing newlines
|
|
280
284
|
found in the content to include are stripped. Possible values are `true` and `false`.
|
|
281
|
-
- <a name="
|
|
282
|
-
**encoding** (_utf-8_): Specify the encoding of the included file.
|
|
283
|
-
If not defined `utf-8` will be used.
|
|
284
|
-
- <a name="recursive" href="#include_recursive">#</a>
|
|
285
|
+
- <a name="include_recursive" href="#include_recursive">#</a>
|
|
285
286
|
**recursive** (_true_): When this option is disabled, included files are not
|
|
286
287
|
processed for recursive includes. Possible values are `true` and `false`.
|
|
288
|
+
- <a name="include_encoding" href="#include_encoding">#</a>
|
|
289
|
+
**encoding** (_'utf-8'_): Specify the encoding of the included file.
|
|
290
|
+
If not defined `'utf-8'` will be used.
|
|
287
291
|
|
|
288
292
|
##### Examples
|
|
289
293
|
|
|
@@ -295,23 +299,24 @@ Includes the content of a file or a group of files.
|
|
|
295
299
|
|
|
296
300
|
```jinja
|
|
297
301
|
{%
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
302
|
+
include "../examples.md"
|
|
303
|
+
start="~~~yaml"
|
|
304
|
+
end="~~~\n"
|
|
301
305
|
%}
|
|
302
306
|
```
|
|
303
307
|
|
|
304
308
|
```jinja
|
|
305
309
|
{%
|
|
306
|
-
|
|
307
|
-
|
|
310
|
+
include '**'
|
|
311
|
+
exclude='./*.md'
|
|
308
312
|
%}
|
|
309
313
|
```
|
|
310
314
|
|
|
311
315
|
## Acknowledgment
|
|
312
316
|
|
|
313
|
-
- Joe Rickerby and contributors for
|
|
314
|
-
[giving me the permissions][cibuildwheel-470] to
|
|
317
|
+
- [Joe Rickerby] and [contributors] for
|
|
318
|
+
[giving me the permissions][cibuildwheel-470] to
|
|
319
|
+
[separate this plugin][cibuildwheel-475] from the
|
|
315
320
|
documentation of [cibuildwheel][cibuildwheel-repo-link].
|
|
316
321
|
|
|
317
322
|
[Bash wildcard globs]: https://facelessuser.github.io/wcmatch/glob/#syntax
|
|
@@ -326,9 +331,14 @@ Includes the content of a file or a group of files.
|
|
|
326
331
|
[coverage-link]: https://app.codecov.io/gh/mondeja/mkdocs-include-markdown-plugin
|
|
327
332
|
[license-image]: https://img.shields.io/pypi/l/mkdocs-include-markdown-plugin?color=light-green&logo=apache&logoColor=white
|
|
328
333
|
[license-link]: https://github.com/mondeja/mkdocs-include-markdown-plugin/blob/master/LICENSE
|
|
334
|
+
[downloads-image]: https://img.shields.io/pypi/dm/mkdocs-include-markdown-plugin
|
|
335
|
+
[downloads-link]: https://pepy.tech/project/mkdocs-include-markdown-plugin
|
|
329
336
|
[platformdirs]: https://pypi.org/project/platformdirs/
|
|
330
337
|
[cibuildwheel-470]: https://github.com/pypa/cibuildwheel/issues/470
|
|
338
|
+
[cibuildwheel-475]: https://github.com/pypa/cibuildwheel/pull/475
|
|
331
339
|
[cibuildwheel-repo-link]: https://github.com/pypa/cibuildwheel
|
|
332
340
|
[es-readme-link]: https://github.com/mondeja/mkdocs-include-markdown-plugin/blob/master/locale/es/README.md
|
|
333
341
|
[fr-readme-link]: https://github.com/mondeja/mkdocs-include-markdown-plugin/blob/master/locale/fr/README.md
|
|
334
342
|
[`docs_dir`]: https://www.mkdocs.org/user-guide/configuration/#docs_dir
|
|
343
|
+
[Joe Rickerby]: https://github.com/joerick
|
|
344
|
+
[contributors]: https://github.com/mondeja/mkdocs-include-markdown-plugin/graphs/contributors
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
[![License][license-image]][license-link]
|
|
9
9
|
[![Tests][tests-image]][tests-link]
|
|
10
10
|
[![Coverage status][coverage-image]][coverage-link]
|
|
11
|
+
[![Downloads][downloads-image]][downloads-link]
|
|
11
12
|
|
|
12
13
|
<!-- mdpo-enable -->
|
|
13
14
|
|
|
@@ -155,9 +156,12 @@ content to include.
|
|
|
155
156
|
- <a name="include-markdown_trailing-newlines" href="#include-markdown_trailing-newlines">#</a>
|
|
156
157
|
**trailing-newlines** (_true_): When this option is disabled, the trailing newlines
|
|
157
158
|
found in the content to include are stripped. Possible values are `true` and `false`.
|
|
159
|
+
- <a name="include-markdown_recursive" href="#include-markdown_recursive">#</a>
|
|
160
|
+
**recursive** (_true_): When this option is disabled, included files are not
|
|
161
|
+
processed for recursive includes. Possible values are `true` and `false`.
|
|
158
162
|
- <a name="include-markdown_encoding" href="#include-markdown_encoding">#</a>
|
|
159
|
-
**encoding** (
|
|
160
|
-
If not defined `utf-8` will be used.
|
|
163
|
+
**encoding** (_'utf-8'_): Specify the encoding of the included file.
|
|
164
|
+
If not defined `'utf-8'` will be used.
|
|
161
165
|
- <a name="include-markdown_rewrite-relative-urls" href="#include-markdown_rewrite-relative-urls">#</a>
|
|
162
166
|
**rewrite-relative-urls** (_true_): When this option is enabled (default),
|
|
163
167
|
Markdown links and images in the content that are specified by a relative URL
|
|
@@ -177,42 +181,42 @@ content to include.
|
|
|
177
181
|
|
|
178
182
|
```jinja
|
|
179
183
|
{%
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
184
|
+
include-markdown "../README.md"
|
|
185
|
+
start="<!--intro-start-->"
|
|
186
|
+
end="<!--intro-end-->"
|
|
183
187
|
%}
|
|
184
188
|
```
|
|
185
189
|
|
|
186
190
|
```jinja
|
|
187
191
|
{%
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
192
|
+
include-markdown 'includes/header.md'
|
|
193
|
+
start='<!--\n\ttable-start\n-->'
|
|
194
|
+
end='<!--\n\ttable-end\n-->'
|
|
195
|
+
rewrite-relative-urls=false
|
|
196
|
+
comments=false
|
|
193
197
|
%}
|
|
194
198
|
```
|
|
195
199
|
|
|
196
200
|
```jinja
|
|
197
201
|
{%
|
|
198
|
-
|
|
199
|
-
|
|
202
|
+
include-markdown "includes/header.md"
|
|
203
|
+
heading-offset=1
|
|
200
204
|
%}
|
|
201
205
|
```
|
|
202
206
|
|
|
203
207
|
```jinja
|
|
204
208
|
{%
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
+
include-markdown "../LICENSE*"
|
|
210
|
+
start="<!--license \"start\" -->"
|
|
211
|
+
end='<!--license "end" -->'
|
|
212
|
+
exclude="../*.rst"
|
|
209
213
|
%}
|
|
210
214
|
```
|
|
211
215
|
|
|
212
216
|
```jinja
|
|
213
217
|
{%
|
|
214
|
-
|
|
215
|
-
|
|
218
|
+
include-markdown "**"
|
|
219
|
+
exclude="./{index,LICENSE}.md"
|
|
216
220
|
%}
|
|
217
221
|
```
|
|
218
222
|
|
|
@@ -243,12 +247,12 @@ Includes the content of a file or a group of files.
|
|
|
243
247
|
- <a name="include_trailing-newlines" href="#include_trailing-newlines">#</a>
|
|
244
248
|
**trailing-newlines** (_true_): When this option is disabled, the trailing newlines
|
|
245
249
|
found in the content to include are stripped. Possible values are `true` and `false`.
|
|
246
|
-
- <a name="
|
|
247
|
-
**encoding** (_utf-8_): Specify the encoding of the included file.
|
|
248
|
-
If not defined `utf-8` will be used.
|
|
249
|
-
- <a name="recursive" href="#include_recursive">#</a>
|
|
250
|
+
- <a name="include_recursive" href="#include_recursive">#</a>
|
|
250
251
|
**recursive** (_true_): When this option is disabled, included files are not
|
|
251
252
|
processed for recursive includes. Possible values are `true` and `false`.
|
|
253
|
+
- <a name="include_encoding" href="#include_encoding">#</a>
|
|
254
|
+
**encoding** (_'utf-8'_): Specify the encoding of the included file.
|
|
255
|
+
If not defined `'utf-8'` will be used.
|
|
252
256
|
|
|
253
257
|
##### Examples
|
|
254
258
|
|
|
@@ -260,23 +264,24 @@ Includes the content of a file or a group of files.
|
|
|
260
264
|
|
|
261
265
|
```jinja
|
|
262
266
|
{%
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
267
|
+
include "../examples.md"
|
|
268
|
+
start="~~~yaml"
|
|
269
|
+
end="~~~\n"
|
|
266
270
|
%}
|
|
267
271
|
```
|
|
268
272
|
|
|
269
273
|
```jinja
|
|
270
274
|
{%
|
|
271
|
-
|
|
272
|
-
|
|
275
|
+
include '**'
|
|
276
|
+
exclude='./*.md'
|
|
273
277
|
%}
|
|
274
278
|
```
|
|
275
279
|
|
|
276
280
|
## Acknowledgment
|
|
277
281
|
|
|
278
|
-
- Joe Rickerby and contributors for
|
|
279
|
-
[giving me the permissions][cibuildwheel-470] to
|
|
282
|
+
- [Joe Rickerby] and [contributors] for
|
|
283
|
+
[giving me the permissions][cibuildwheel-470] to
|
|
284
|
+
[separate this plugin][cibuildwheel-475] from the
|
|
280
285
|
documentation of [cibuildwheel][cibuildwheel-repo-link].
|
|
281
286
|
|
|
282
287
|
[Bash wildcard globs]: https://facelessuser.github.io/wcmatch/glob/#syntax
|
|
@@ -291,9 +296,14 @@ Includes the content of a file or a group of files.
|
|
|
291
296
|
[coverage-link]: https://app.codecov.io/gh/mondeja/mkdocs-include-markdown-plugin
|
|
292
297
|
[license-image]: https://img.shields.io/pypi/l/mkdocs-include-markdown-plugin?color=light-green&logo=apache&logoColor=white
|
|
293
298
|
[license-link]: https://github.com/mondeja/mkdocs-include-markdown-plugin/blob/master/LICENSE
|
|
299
|
+
[downloads-image]: https://img.shields.io/pypi/dm/mkdocs-include-markdown-plugin
|
|
300
|
+
[downloads-link]: https://pepy.tech/project/mkdocs-include-markdown-plugin
|
|
294
301
|
[platformdirs]: https://pypi.org/project/platformdirs/
|
|
295
302
|
[cibuildwheel-470]: https://github.com/pypa/cibuildwheel/issues/470
|
|
303
|
+
[cibuildwheel-475]: https://github.com/pypa/cibuildwheel/pull/475
|
|
296
304
|
[cibuildwheel-repo-link]: https://github.com/pypa/cibuildwheel
|
|
297
305
|
[es-readme-link]: https://github.com/mondeja/mkdocs-include-markdown-plugin/blob/master/locale/es/README.md
|
|
298
306
|
[fr-readme-link]: https://github.com/mondeja/mkdocs-include-markdown-plugin/blob/master/locale/fr/README.md
|
|
299
307
|
[`docs_dir`]: https://www.mkdocs.org/user-guide/configuration/#docs_dir
|
|
308
|
+
[Joe Rickerby]: https://github.com/joerick
|
|
309
|
+
[contributors]: https://github.com/mondeja/mkdocs-include-markdown-plugin/graphs/contributors
|
|
@@ -39,24 +39,24 @@ class Cache:
|
|
|
39
39
|
hashlib.sha3_512(url.encode()).digest(),
|
|
40
40
|
).decode('utf-8')
|
|
41
41
|
|
|
42
|
-
def read_file(self, fpath: str) -> str: # noqa: D102
|
|
43
|
-
with open(fpath, encoding=
|
|
42
|
+
def read_file(self, fpath: str, encoding: str = 'utf-8') -> str: # noqa: D102
|
|
43
|
+
with open(fpath, encoding=encoding) as f:
|
|
44
44
|
return f.read().split('\n', 1)[1]
|
|
45
45
|
|
|
46
|
-
def get_(self, url: str) -> str | None: # noqa: D102
|
|
46
|
+
def get_(self, url: str, encoding: str = 'utf-8') -> str | None: # noqa: D102
|
|
47
47
|
key = self.generate_unique_key_from_url(url)
|
|
48
48
|
fpath = os.path.join(self.cache_dir, key)
|
|
49
49
|
if os.path.isfile(fpath):
|
|
50
50
|
creation_time = self.get_creation_time_from_fpath(fpath)
|
|
51
51
|
if time.time() < creation_time + self.expiration_seconds:
|
|
52
|
-
return self.read_file(fpath)
|
|
52
|
+
return self.read_file(fpath, encoding=encoding)
|
|
53
53
|
os.remove(fpath)
|
|
54
54
|
return None
|
|
55
55
|
|
|
56
|
-
def set_(self, url: str, value: str) -> None: # noqa: D102
|
|
56
|
+
def set_(self, url: str, value: str, encoding: str = 'utf-8') -> None: # noqa: D102
|
|
57
57
|
key = self.generate_unique_key_from_url(url)
|
|
58
58
|
fpath = os.path.join(self.cache_dir, key)
|
|
59
|
-
with open(fpath, 'w', encoding=
|
|
59
|
+
with open(fpath, 'w', encoding=encoding) as f:
|
|
60
60
|
f.write(f'{int(time.time())}\n')
|
|
61
61
|
f.write(value)
|
|
62
62
|
|
|
@@ -12,6 +12,7 @@ from mkdocs.exceptions import PluginError
|
|
|
12
12
|
from wcmatch import glob
|
|
13
13
|
|
|
14
14
|
from mkdocs_include_markdown_plugin import process
|
|
15
|
+
from mkdocs_include_markdown_plugin.logger import logger
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
@dataclass
|
|
@@ -21,7 +22,7 @@ class DirectiveBoolArgument: # noqa: D101
|
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
if TYPE_CHECKING:
|
|
24
|
-
from typing import TypedDict
|
|
25
|
+
from typing import Literal, TypedDict
|
|
25
26
|
|
|
26
27
|
DirectiveBoolArgumentsDict = dict[str, DirectiveBoolArgument]
|
|
27
28
|
|
|
@@ -44,14 +45,14 @@ if TYPE_CHECKING:
|
|
|
44
45
|
GLOB_FLAGS = glob.NEGATE | glob.EXTGLOB | glob.GLOBSTAR | glob.BRACE
|
|
45
46
|
RE_ESCAPED_PUNCTUATION = re.escape(string.punctuation)
|
|
46
47
|
|
|
47
|
-
DOUBLE_QUOTED_STR_RE = r'([^"]|(?<=\\)
|
|
48
|
-
SINGLE_QUOTED_STR_RE = r"([^']|(?<=\\)
|
|
48
|
+
DOUBLE_QUOTED_STR_RE = r'([^"]|(?<=\\)")+'
|
|
49
|
+
SINGLE_QUOTED_STR_RE = r"([^']|(?<=\\)')+"
|
|
49
50
|
|
|
50
51
|
# In the following regular expression, the substrings "$OPENING_TAG"
|
|
51
52
|
# and "$CLOSING_TAG" will be replaced by the effective opening and
|
|
52
53
|
# closing tags in the `on_config` plugin event.
|
|
53
54
|
INCLUDE_TAG_RE = rf'''
|
|
54
|
-
(?P<_includer_indent>[ \t\
|
|
55
|
+
(?P<_includer_indent>[ \t\w\\.]*?)$OPENING_TAG
|
|
55
56
|
\s*
|
|
56
57
|
include
|
|
57
58
|
\s+
|
|
@@ -103,6 +104,38 @@ ARGUMENT_REGEXES = {
|
|
|
103
104
|
'heading-offset': arg('heading-offset'),
|
|
104
105
|
}
|
|
105
106
|
|
|
107
|
+
INCLUDE_DIRECTIVE_ARGS = {
|
|
108
|
+
key for key in ARGUMENT_REGEXES if key not in (
|
|
109
|
+
'rewrite-relative-urls', 'heading-offset', 'comments',
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
INCLUDE_MARKDOWN_DIRECTIVE_ARGS = set(ARGUMENT_REGEXES)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def warn_invalid_directive_arguments(
|
|
117
|
+
arguments_string: str,
|
|
118
|
+
directive_lineno: int,
|
|
119
|
+
directive: Literal['include', 'include-markdown'],
|
|
120
|
+
page_src_path: str | None,
|
|
121
|
+
docs_dir: str,
|
|
122
|
+
) -> None:
|
|
123
|
+
"""Warns about the invalid arguments passed to a directive."""
|
|
124
|
+
arg_re = re.compile(rf'[\w-]*=[{RE_ESCAPED_PUNCTUATION}\w]*')
|
|
125
|
+
valid_args = (
|
|
126
|
+
INCLUDE_DIRECTIVE_ARGS if directive == 'include'
|
|
127
|
+
else INCLUDE_MARKDOWN_DIRECTIVE_ARGS
|
|
128
|
+
)
|
|
129
|
+
for arg_value in re.findall(arg_re, arguments_string):
|
|
130
|
+
if arg_value.split('=', 1)[0] not in valid_args:
|
|
131
|
+
location = process.file_lineno_message(
|
|
132
|
+
page_src_path, docs_dir, directive_lineno,
|
|
133
|
+
)
|
|
134
|
+
logger.warning(
|
|
135
|
+
f"Invalid argument '{arg_value}' in"
|
|
136
|
+
f" '{directive}' directive at {location}. Ignoring...",
|
|
137
|
+
)
|
|
138
|
+
|
|
106
139
|
|
|
107
140
|
def parse_filename_argument(
|
|
108
141
|
match: re.Match[str],
|
|
@@ -138,7 +171,7 @@ def create_include_tag(
|
|
|
138
171
|
"""Create a regex pattern to match an inclusion tag directive.
|
|
139
172
|
|
|
140
173
|
Replaces the substrings '$OPENING_TAG' and '$CLOSING_TAG' from
|
|
141
|
-
|
|
174
|
+
INCLUDE_TAG_RE by the effective tag.
|
|
142
175
|
"""
|
|
143
176
|
return re.compile(
|
|
144
177
|
INCLUDE_TAG_RE.replace(' include', f' {tag}').replace(
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import html
|
|
6
|
-
import logging
|
|
7
6
|
import os
|
|
8
7
|
import re
|
|
9
8
|
import textwrap
|
|
@@ -23,12 +22,14 @@ from mkdocs_include_markdown_plugin.directive import (
|
|
|
23
22
|
parse_string_argument,
|
|
24
23
|
resolve_file_paths_to_exclude,
|
|
25
24
|
resolve_file_paths_to_include,
|
|
25
|
+
warn_invalid_directive_arguments,
|
|
26
26
|
)
|
|
27
27
|
from mkdocs_include_markdown_plugin.files_watcher import FilesWatcher
|
|
28
|
+
from mkdocs_include_markdown_plugin.logger import logger
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
if TYPE_CHECKING:
|
|
31
|
-
from typing import TypedDict
|
|
32
|
+
from typing import Literal, TypedDict
|
|
32
33
|
|
|
33
34
|
from mkdocs.structure.pages import Page
|
|
34
35
|
|
|
@@ -43,49 +44,26 @@ if TYPE_CHECKING:
|
|
|
43
44
|
)
|
|
44
45
|
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
# mkdocs.plugin.get_plugin_logger
|
|
53
|
-
logger = logging.getLogger('mkdocs.plugins.include_markdown')
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def lineno_from_content_start(content: str, start: int) -> int:
|
|
57
|
-
"""Return the line number of the first line of ``start`` in ``content``."""
|
|
58
|
-
return content[:start].count('\n') + 1
|
|
47
|
+
# Placeholders (taken from Python-Markdown)
|
|
48
|
+
STX = '\u0002'
|
|
49
|
+
''' "Start of Text" marker for placeholder templates. '''
|
|
50
|
+
ETX = '\u0003'
|
|
51
|
+
''' "End of Text" marker for placeholder templates. '''
|
|
52
|
+
INLINE_PLACEHOLDER_PREFIX = f'{STX}klzzwxh:'
|
|
59
53
|
|
|
60
54
|
|
|
61
|
-
def
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"""
|
|
69
|
-
if os.name != 'nt': # pragma: nt no cover
|
|
70
|
-
return os.path.relpath(path, start)
|
|
71
|
-
try: # pragma: nt cover
|
|
72
|
-
return os.path.relpath(path, start)
|
|
73
|
-
except ValueError: # pragma: no cover
|
|
74
|
-
return path
|
|
55
|
+
def build_placeholder(
|
|
56
|
+
num: int,
|
|
57
|
+
directive: Literal['include', 'include-markdown'],
|
|
58
|
+
) -> str:
|
|
59
|
+
"""Return a placeholder."""
|
|
60
|
+
directive_prefix = 'im' if directive == 'include-markdown' else 'i'
|
|
61
|
+
return f'{INLINE_PLACEHOLDER_PREFIX}{directive_prefix}{num}{ETX}'
|
|
75
62
|
|
|
76
63
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
lineno: int,
|
|
81
|
-
) -> str:
|
|
82
|
-
"""Return a message with the file path and line number."""
|
|
83
|
-
if page_src_path is None: # pragma: no cover
|
|
84
|
-
return f'generated page content (line {lineno})'
|
|
85
|
-
return (
|
|
86
|
-
f'{safe_os_path_relpath(page_src_path, docs_dir)}'
|
|
87
|
-
f':{lineno}'
|
|
88
|
-
)
|
|
64
|
+
@dataclass
|
|
65
|
+
class Settings: # noqa: D101
|
|
66
|
+
exclude: list[str] | None
|
|
89
67
|
|
|
90
68
|
|
|
91
69
|
def get_file_content( # noqa: PLR0913, PLR0915
|
|
@@ -119,46 +97,55 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
119
97
|
if page_src_path in settings_ignore_paths:
|
|
120
98
|
return markdown
|
|
121
99
|
|
|
100
|
+
new_found_include_contents: list[tuple[str, str]] = []
|
|
101
|
+
new_found_include_markdown_contents: list[tuple[str, str]] = []
|
|
102
|
+
|
|
122
103
|
def found_include_tag( # noqa: PLR0912, PLR0915
|
|
123
104
|
match: re.Match[str],
|
|
124
105
|
) -> str:
|
|
125
106
|
directive_match_start = match.start()
|
|
107
|
+
directive_lineno = process.lineno_from_content_start(
|
|
108
|
+
markdown,
|
|
109
|
+
directive_match_start,
|
|
110
|
+
)
|
|
126
111
|
|
|
127
112
|
includer_indent = match['_includer_indent']
|
|
128
113
|
|
|
129
114
|
filename, raw_filename = parse_filename_argument(match)
|
|
130
115
|
if filename is None:
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
directive_match_start,
|
|
116
|
+
location = process.file_lineno_message(
|
|
117
|
+
page_src_path, docs_dir, directive_lineno,
|
|
134
118
|
)
|
|
135
119
|
raise PluginError(
|
|
136
120
|
"Found no path passed including with 'include'"
|
|
137
|
-
' directive at'
|
|
138
|
-
f' {file_lineno_message(page_src_path, docs_dir, lineno)}',
|
|
121
|
+
f' directive at {location}',
|
|
139
122
|
)
|
|
140
123
|
|
|
141
124
|
arguments_string = match['arguments']
|
|
142
125
|
|
|
126
|
+
warn_invalid_directive_arguments(
|
|
127
|
+
arguments_string,
|
|
128
|
+
directive_lineno,
|
|
129
|
+
'include',
|
|
130
|
+
page_src_path,
|
|
131
|
+
docs_dir,
|
|
132
|
+
)
|
|
133
|
+
|
|
143
134
|
exclude_match = ARGUMENT_REGEXES['exclude'].search(arguments_string)
|
|
144
135
|
ignore_paths = [*settings_ignore_paths]
|
|
145
136
|
if exclude_match is not None:
|
|
146
137
|
exclude_string = parse_string_argument(exclude_match)
|
|
147
138
|
if exclude_string is None:
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
directive_match_start,
|
|
139
|
+
location = process.file_lineno_message(
|
|
140
|
+
page_src_path, docs_dir, directive_lineno,
|
|
151
141
|
)
|
|
152
142
|
raise PluginError(
|
|
153
143
|
"Invalid empty 'exclude' argument in 'include'"
|
|
154
|
-
' directive at'
|
|
155
|
-
f' {file_lineno_message(page_src_path, docs_dir, lineno)}',
|
|
144
|
+
f' directive at {location}',
|
|
156
145
|
)
|
|
157
146
|
|
|
158
147
|
for path in resolve_file_paths_to_exclude(
|
|
159
|
-
|
|
160
|
-
page_src_path,
|
|
161
|
-
docs_dir,
|
|
148
|
+
exclude_string, page_src_path, docs_dir,
|
|
162
149
|
):
|
|
163
150
|
if path not in ignore_paths:
|
|
164
151
|
ignore_paths.append(path)
|
|
@@ -171,13 +158,11 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
171
158
|
)
|
|
172
159
|
|
|
173
160
|
if not file_paths_to_include:
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
directive_match_start,
|
|
161
|
+
location = process.file_lineno_message(
|
|
162
|
+
page_src_path, docs_dir, directive_lineno,
|
|
177
163
|
)
|
|
178
164
|
raise PluginError(
|
|
179
|
-
f"No files found including '{raw_filename}' at"
|
|
180
|
-
f' {file_lineno_message(page_src_path, docs_dir, lineno)}',
|
|
165
|
+
f"No files found including '{raw_filename}' at {location}",
|
|
181
166
|
)
|
|
182
167
|
|
|
183
168
|
if files_watcher is not None and not is_url:
|
|
@@ -190,14 +175,12 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
190
175
|
arguments_string,
|
|
191
176
|
)
|
|
192
177
|
if invalid_bool_args:
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
directive_match_start,
|
|
178
|
+
location = process.file_lineno_message(
|
|
179
|
+
page_src_path, docs_dir, directive_lineno,
|
|
196
180
|
)
|
|
197
181
|
raise PluginError(
|
|
198
182
|
f"Invalid value for '{invalid_bool_args[0]}' argument of"
|
|
199
|
-
" 'include' directive at"
|
|
200
|
-
f' {file_lineno_message(page_src_path, docs_dir, lineno)}.'
|
|
183
|
+
f" 'include' directive at {location}."
|
|
201
184
|
f' Possible values are true or false.',
|
|
202
185
|
)
|
|
203
186
|
|
|
@@ -205,13 +188,12 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
205
188
|
if start_match:
|
|
206
189
|
start = parse_string_argument(start_match)
|
|
207
190
|
if start is None:
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
directive_match_start,
|
|
191
|
+
location = process.file_lineno_message(
|
|
192
|
+
page_src_path, docs_dir, directive_lineno,
|
|
211
193
|
)
|
|
212
194
|
raise PluginError(
|
|
213
195
|
"Invalid empty 'start' argument in 'include' directive at"
|
|
214
|
-
f' {
|
|
196
|
+
f' {location}',
|
|
215
197
|
)
|
|
216
198
|
else:
|
|
217
199
|
start = defaults['start']
|
|
@@ -220,13 +202,12 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
220
202
|
if end_match:
|
|
221
203
|
end = parse_string_argument(end_match)
|
|
222
204
|
if end is None:
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
directive_match_start,
|
|
205
|
+
location = process.file_lineno_message(
|
|
206
|
+
page_src_path, docs_dir, directive_lineno,
|
|
226
207
|
)
|
|
227
208
|
raise PluginError(
|
|
228
209
|
"Invalid empty 'end' argument in 'include' directive at"
|
|
229
|
-
f' {
|
|
210
|
+
f' {location}',
|
|
230
211
|
)
|
|
231
212
|
else:
|
|
232
213
|
end = defaults['end']
|
|
@@ -235,14 +216,12 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
235
216
|
if encoding_match:
|
|
236
217
|
encoding = parse_string_argument(encoding_match)
|
|
237
218
|
if encoding is None:
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
directive_match_start,
|
|
219
|
+
location = process.file_lineno_message(
|
|
220
|
+
page_src_path, docs_dir, directive_lineno,
|
|
241
221
|
)
|
|
242
222
|
raise PluginError(
|
|
243
223
|
"Invalid empty 'encoding' argument in 'include'"
|
|
244
|
-
' directive at'
|
|
245
|
-
f' {file_lineno_message(page_src_path, docs_dir, lineno)}',
|
|
224
|
+
f' directive at {location}',
|
|
246
225
|
)
|
|
247
226
|
else:
|
|
248
227
|
encoding = defaults['encoding']
|
|
@@ -251,7 +230,9 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
251
230
|
expected_but_any_found = [start is not None, end is not None]
|
|
252
231
|
for file_path in file_paths_to_include:
|
|
253
232
|
if process.is_url(filename):
|
|
254
|
-
new_text_to_include = process.read_url(
|
|
233
|
+
new_text_to_include = process.read_url(
|
|
234
|
+
file_path, http_cache, encoding,
|
|
235
|
+
)
|
|
255
236
|
else:
|
|
256
237
|
new_text_to_include = process.read_file(file_path, encoding)
|
|
257
238
|
|
|
@@ -308,69 +289,72 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
308
289
|
if expected_but_any_found[i]:
|
|
309
290
|
delimiter_value = locals()[delimiter_name]
|
|
310
291
|
readable_files_to_include = ', '.join([
|
|
311
|
-
safe_os_path_relpath(fpath, docs_dir)
|
|
292
|
+
process.safe_os_path_relpath(fpath, docs_dir)
|
|
312
293
|
for fpath in file_paths_to_include
|
|
313
294
|
])
|
|
314
295
|
plural_suffix = 's' if len(file_paths_to_include) > 1 else ''
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
directive_match_start,
|
|
318
|
-
)
|
|
319
|
-
file_lineno = file_lineno_message(
|
|
320
|
-
page_src_path, docs_dir, lineno,
|
|
296
|
+
location = process.file_lineno_message(
|
|
297
|
+
page_src_path, docs_dir, directive_lineno,
|
|
321
298
|
)
|
|
322
299
|
logger.warning(
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
f' not detected in the file{plural_suffix}'
|
|
328
|
-
f' {readable_files_to_include}'
|
|
329
|
-
),
|
|
300
|
+
f"Delimiter {delimiter_name} '{delimiter_value}'"
|
|
301
|
+
f" of 'include' directive at {location}"
|
|
302
|
+
f' not detected in the file{plural_suffix}'
|
|
303
|
+
f' {readable_files_to_include}',
|
|
330
304
|
)
|
|
331
305
|
|
|
332
|
-
|
|
306
|
+
nonlocal new_found_include_contents
|
|
307
|
+
include_index = len(new_found_include_contents)
|
|
308
|
+
placeholder = build_placeholder(include_index, 'include')
|
|
309
|
+
new_found_include_contents.append((placeholder, text_to_include))
|
|
310
|
+
return placeholder
|
|
333
311
|
|
|
334
312
|
def found_include_markdown_tag( # noqa: PLR0912, PLR0915
|
|
335
313
|
match: re.Match[str],
|
|
336
314
|
) -> str:
|
|
337
315
|
directive_match_start = match.start()
|
|
316
|
+
directive_lineno = process.lineno_from_content_start(
|
|
317
|
+
markdown,
|
|
318
|
+
directive_match_start,
|
|
319
|
+
)
|
|
338
320
|
|
|
339
321
|
includer_indent = match['_includer_indent']
|
|
340
322
|
empty_includer_indent = ' ' * len(includer_indent)
|
|
341
323
|
|
|
342
324
|
filename, raw_filename = parse_filename_argument(match)
|
|
343
325
|
if filename is None:
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
directive_match_start,
|
|
326
|
+
location = process.file_lineno_message(
|
|
327
|
+
page_src_path, docs_dir, directive_lineno,
|
|
347
328
|
)
|
|
348
329
|
raise PluginError(
|
|
349
330
|
"Found no path passed including with 'include-markdown'"
|
|
350
|
-
f' directive at'
|
|
351
|
-
f' {file_lineno_message(page_src_path, docs_dir, lineno)}',
|
|
331
|
+
f' directive at {location}',
|
|
352
332
|
)
|
|
353
333
|
|
|
354
334
|
arguments_string = match['arguments']
|
|
355
335
|
|
|
336
|
+
warn_invalid_directive_arguments(
|
|
337
|
+
arguments_string,
|
|
338
|
+
directive_lineno,
|
|
339
|
+
'include-markdown',
|
|
340
|
+
page_src_path,
|
|
341
|
+
docs_dir,
|
|
342
|
+
)
|
|
343
|
+
|
|
356
344
|
exclude_match = ARGUMENT_REGEXES['exclude'].search(arguments_string)
|
|
357
345
|
ignore_paths = [*settings_ignore_paths]
|
|
358
346
|
if exclude_match is not None:
|
|
359
347
|
exclude_string = parse_string_argument(exclude_match)
|
|
360
348
|
if exclude_string is None:
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
directive_match_start,
|
|
349
|
+
location = process.file_lineno_message(
|
|
350
|
+
page_src_path, docs_dir, directive_lineno,
|
|
364
351
|
)
|
|
365
352
|
raise PluginError(
|
|
366
353
|
"Invalid empty 'exclude' argument in 'include-markdown'"
|
|
367
|
-
f' directive at'
|
|
368
|
-
f' {file_lineno_message(page_src_path, docs_dir, lineno)}',
|
|
354
|
+
f' directive at {location}',
|
|
369
355
|
)
|
|
370
356
|
for path in resolve_file_paths_to_exclude(
|
|
371
|
-
|
|
372
|
-
page_src_path,
|
|
373
|
-
docs_dir,
|
|
357
|
+
exclude_string, page_src_path, docs_dir,
|
|
374
358
|
):
|
|
375
359
|
if path not in ignore_paths:
|
|
376
360
|
ignore_paths.append(path)
|
|
@@ -383,13 +367,11 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
383
367
|
)
|
|
384
368
|
|
|
385
369
|
if not file_paths_to_include:
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
directive_match_start,
|
|
370
|
+
location = process.file_lineno_message(
|
|
371
|
+
page_src_path, docs_dir, directive_lineno,
|
|
389
372
|
)
|
|
390
373
|
raise PluginError(
|
|
391
|
-
f"No files found including '{raw_filename}' at"
|
|
392
|
-
f' {file_lineno_message(page_src_path, docs_dir, lineno)}',
|
|
374
|
+
f"No files found including '{raw_filename}' at {location}",
|
|
393
375
|
)
|
|
394
376
|
|
|
395
377
|
if files_watcher is not None and not is_url:
|
|
@@ -399,21 +381,19 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
399
381
|
[
|
|
400
382
|
'rewrite-relative-urls', 'comments',
|
|
401
383
|
'preserve-includer-indent', 'dedent',
|
|
402
|
-
'trailing-newlines',
|
|
384
|
+
'trailing-newlines', 'recursive',
|
|
403
385
|
],
|
|
404
386
|
defaults,
|
|
405
387
|
arguments_string,
|
|
406
388
|
)
|
|
407
389
|
if invalid_bool_args:
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
directive_match_start,
|
|
390
|
+
location = process.file_lineno_message(
|
|
391
|
+
page_src_path, docs_dir, directive_lineno,
|
|
411
392
|
)
|
|
412
393
|
raise PluginError(
|
|
413
394
|
f"Invalid value for '{invalid_bool_args[0]}' argument of"
|
|
414
395
|
" 'include-markdown' directive at"
|
|
415
|
-
f' {
|
|
416
|
-
f' Possible values are true or false.',
|
|
396
|
+
f' {location}. Possible values are true or false.',
|
|
417
397
|
)
|
|
418
398
|
|
|
419
399
|
# start and end arguments
|
|
@@ -421,14 +401,12 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
421
401
|
if start_match:
|
|
422
402
|
start = parse_string_argument(start_match)
|
|
423
403
|
if start is None:
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
directive_match_start,
|
|
404
|
+
location = process.file_lineno_message(
|
|
405
|
+
page_src_path, docs_dir, directive_lineno,
|
|
427
406
|
)
|
|
428
407
|
raise PluginError(
|
|
429
408
|
"Invalid empty 'start' argument in 'include-markdown'"
|
|
430
|
-
f' directive at'
|
|
431
|
-
f' {file_lineno_message(page_src_path, docs_dir, lineno)}',
|
|
409
|
+
f' directive at {location}',
|
|
432
410
|
)
|
|
433
411
|
else:
|
|
434
412
|
start = defaults['start']
|
|
@@ -437,14 +415,12 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
437
415
|
if end_match:
|
|
438
416
|
end = parse_string_argument(end_match)
|
|
439
417
|
if end is None:
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
directive_match_start,
|
|
418
|
+
location = process.file_lineno_message(
|
|
419
|
+
page_src_path, docs_dir, directive_lineno,
|
|
443
420
|
)
|
|
444
421
|
raise PluginError(
|
|
445
422
|
"Invalid empty 'end' argument in 'include-markdown'"
|
|
446
|
-
f' directive at'
|
|
447
|
-
f' {file_lineno_message(page_src_path, docs_dir, lineno)}',
|
|
423
|
+
f' directive at {location}',
|
|
448
424
|
)
|
|
449
425
|
else:
|
|
450
426
|
end = defaults['end']
|
|
@@ -453,14 +429,12 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
453
429
|
if encoding_match:
|
|
454
430
|
encoding = parse_string_argument(encoding_match)
|
|
455
431
|
if encoding is None:
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
directive_match_start,
|
|
432
|
+
location = process.file_lineno_message(
|
|
433
|
+
page_src_path, docs_dir, directive_lineno,
|
|
459
434
|
)
|
|
460
435
|
raise PluginError(
|
|
461
436
|
"Invalid empty 'encoding' argument in 'include-markdown'"
|
|
462
|
-
' directive at'
|
|
463
|
-
f' {file_lineno_message(page_src_path, docs_dir, lineno)}',
|
|
437
|
+
f' directive at {location}',
|
|
464
438
|
)
|
|
465
439
|
else:
|
|
466
440
|
encoding = defaults['encoding']
|
|
@@ -472,26 +446,22 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
472
446
|
if offset_match:
|
|
473
447
|
offset_raw_value = offset_match[1]
|
|
474
448
|
if offset_raw_value == '':
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
directive_match_start,
|
|
449
|
+
location = process.file_lineno_message(
|
|
450
|
+
page_src_path, docs_dir, directive_lineno,
|
|
478
451
|
)
|
|
479
452
|
raise PluginError(
|
|
480
453
|
"Invalid empty 'heading-offset' argument in"
|
|
481
|
-
" 'include-markdown' directive at"
|
|
482
|
-
f' {file_lineno_message(page_src_path, docs_dir, lineno)}',
|
|
454
|
+
f" 'include-markdown' directive at {location}",
|
|
483
455
|
)
|
|
484
456
|
try:
|
|
485
457
|
offset = int(offset_raw_value)
|
|
486
458
|
except ValueError:
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
directive_match_start,
|
|
459
|
+
location = process.file_lineno_message(
|
|
460
|
+
page_src_path, docs_dir, directive_lineno,
|
|
490
461
|
)
|
|
491
462
|
raise PluginError(
|
|
492
463
|
f"Invalid 'heading-offset' argument \"{offset_raw_value}\""
|
|
493
|
-
" in 'include-markdown' directive at"
|
|
494
|
-
f' {file_lineno_message(page_src_path, docs_dir, lineno)}',
|
|
464
|
+
f" in 'include-markdown' directive at {location}",
|
|
495
465
|
) from None
|
|
496
466
|
else:
|
|
497
467
|
offset = defaults['heading-offset']
|
|
@@ -513,7 +483,9 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
513
483
|
text_to_include = ''
|
|
514
484
|
for file_path in file_paths_to_include:
|
|
515
485
|
if process.is_url(filename):
|
|
516
|
-
new_text_to_include = process.read_url(
|
|
486
|
+
new_text_to_include = process.read_url(
|
|
487
|
+
file_path, http_cache, encoding,
|
|
488
|
+
)
|
|
517
489
|
else:
|
|
518
490
|
new_text_to_include = process.read_file(file_path, encoding)
|
|
519
491
|
|
|
@@ -530,16 +502,17 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
530
502
|
expected_but_any_found[i] = False
|
|
531
503
|
|
|
532
504
|
# nested includes
|
|
533
|
-
|
|
534
|
-
new_text_to_include
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
505
|
+
if bool_options['recursive'].value:
|
|
506
|
+
new_text_to_include = get_file_content(
|
|
507
|
+
new_text_to_include,
|
|
508
|
+
file_path,
|
|
509
|
+
docs_dir,
|
|
510
|
+
tags,
|
|
511
|
+
defaults,
|
|
512
|
+
settings,
|
|
513
|
+
files_watcher=files_watcher,
|
|
514
|
+
http_cache=http_cache,
|
|
515
|
+
)
|
|
543
516
|
|
|
544
517
|
# trailing newlines right stripping
|
|
545
518
|
if not bool_options['trailing-newlines'].value:
|
|
@@ -601,38 +574,47 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
601
574
|
if expected_but_any_found[i]:
|
|
602
575
|
delimiter_value = locals()[delimiter_name]
|
|
603
576
|
readable_files_to_include = ', '.join([
|
|
604
|
-
safe_os_path_relpath(fpath, docs_dir)
|
|
577
|
+
process.safe_os_path_relpath(fpath, docs_dir)
|
|
605
578
|
for fpath in file_paths_to_include
|
|
606
579
|
])
|
|
607
580
|
plural_suffix = 's' if len(file_paths_to_include) > 1 else ''
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
directive_match_start,
|
|
611
|
-
)
|
|
612
|
-
file_lineno = file_lineno_message(
|
|
613
|
-
page_src_path, docs_dir, lineno,
|
|
581
|
+
location = process.file_lineno_message(
|
|
582
|
+
page_src_path, docs_dir, directive_lineno,
|
|
614
583
|
)
|
|
615
584
|
logger.warning(
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
f' not detected in the file{plural_suffix}'
|
|
621
|
-
f' {readable_files_to_include}'
|
|
622
|
-
),
|
|
585
|
+
f"Delimiter {delimiter_name} '{delimiter_value}' of"
|
|
586
|
+
f" 'include-markdown' directive at {location}"
|
|
587
|
+
f' not detected in the file{plural_suffix}'
|
|
588
|
+
f' {readable_files_to_include}',
|
|
623
589
|
)
|
|
624
590
|
|
|
625
|
-
|
|
591
|
+
nonlocal new_found_include_markdown_contents
|
|
592
|
+
markdown_include_index = len(new_found_include_markdown_contents)
|
|
593
|
+
placeholder = build_placeholder(
|
|
594
|
+
markdown_include_index, 'include-markdown',
|
|
595
|
+
)
|
|
596
|
+
new_found_include_markdown_contents.append(
|
|
597
|
+
(placeholder, text_to_include),
|
|
598
|
+
)
|
|
599
|
+
return placeholder
|
|
626
600
|
|
|
601
|
+
# Replace contents by placeholders
|
|
627
602
|
markdown = tags['include-markdown'].sub(
|
|
628
603
|
found_include_markdown_tag,
|
|
629
604
|
markdown,
|
|
630
605
|
)
|
|
631
|
-
|
|
606
|
+
markdown = tags['include'].sub(
|
|
632
607
|
found_include_tag,
|
|
633
608
|
markdown,
|
|
634
609
|
)
|
|
635
610
|
|
|
611
|
+
# Replace placeholders by contents
|
|
612
|
+
for placeholder, text in new_found_include_contents:
|
|
613
|
+
markdown = markdown.replace(placeholder, text, 1)
|
|
614
|
+
for placeholder, text in new_found_include_markdown_contents:
|
|
615
|
+
markdown = markdown.replace(placeholder, text, 1)
|
|
616
|
+
return markdown
|
|
617
|
+
|
|
636
618
|
|
|
637
619
|
def on_page_markdown(
|
|
638
620
|
markdown: str,
|
|
@@ -4,7 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from collections.abc import Callable
|
|
6
6
|
from functools import cached_property
|
|
7
|
-
from typing import TYPE_CHECKING
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
8
|
|
|
9
9
|
from mkdocs.exceptions import PluginError
|
|
10
10
|
from mkdocs.livereload import LiveReloadServer
|
|
@@ -98,7 +98,7 @@ class IncludeMarkdownPlugin(BasePlugin[PluginConfig]):
|
|
|
98
98
|
self,
|
|
99
99
|
server: LiveReloadServer,
|
|
100
100
|
config: MkDocsConfig, # noqa: ARG002
|
|
101
|
-
builder: Callable
|
|
101
|
+
builder: Callable, # noqa: ARG002
|
|
102
102
|
) -> None:
|
|
103
103
|
if self._server is None: # pragma: no cover
|
|
104
104
|
self._server = server
|
|
@@ -13,6 +13,8 @@ from urllib.request import Request, urlopen
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
if TYPE_CHECKING:
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
16
18
|
from mkdocs_include_markdown_plugin.cache import Cache
|
|
17
19
|
|
|
18
20
|
|
|
@@ -441,14 +443,53 @@ def read_file(file_path: str, encoding: str) -> str:
|
|
|
441
443
|
return f.read()
|
|
442
444
|
|
|
443
445
|
|
|
444
|
-
def read_url(
|
|
446
|
+
def read_url(
|
|
447
|
+
url: str,
|
|
448
|
+
http_cache: Cache | None,
|
|
449
|
+
encoding: str = 'utf-8',
|
|
450
|
+
) -> Any:
|
|
445
451
|
"""Read an HTTP location and return its content."""
|
|
446
452
|
if http_cache is not None:
|
|
447
|
-
cached_content = http_cache.get_(url)
|
|
453
|
+
cached_content = http_cache.get_(url, encoding)
|
|
448
454
|
if cached_content is not None:
|
|
449
455
|
return cached_content
|
|
450
456
|
with urlopen(Request(url)) as response:
|
|
451
|
-
content = response.read().decode(
|
|
457
|
+
content = response.read().decode(encoding)
|
|
452
458
|
if http_cache is not None:
|
|
453
|
-
http_cache.set_(url, content)
|
|
459
|
+
http_cache.set_(url, content, encoding)
|
|
454
460
|
return content
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
def safe_os_path_relpath(path: str, start: str) -> str:
|
|
464
|
+
"""Return the relative path of a file from a start directory.
|
|
465
|
+
|
|
466
|
+
Safe version of `os.path.relpath` that catches `ValueError` exceptions
|
|
467
|
+
on Windows and returns the original path in case of error.
|
|
468
|
+
On Windows, `ValueError` is raised when `path` and `start` are on
|
|
469
|
+
different drives.
|
|
470
|
+
"""
|
|
471
|
+
if os.name != 'nt': # pragma: nt no cover
|
|
472
|
+
return os.path.relpath(path, start)
|
|
473
|
+
try: # pragma: nt cover
|
|
474
|
+
return os.path.relpath(path, start)
|
|
475
|
+
except ValueError: # pragma: no cover
|
|
476
|
+
return path
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def file_lineno_message(
|
|
480
|
+
page_src_path: str | None,
|
|
481
|
+
docs_dir: str,
|
|
482
|
+
lineno: int,
|
|
483
|
+
) -> str:
|
|
484
|
+
"""Return a message with the file path and line number."""
|
|
485
|
+
if page_src_path is None: # pragma: no cover
|
|
486
|
+
return f'generated page content (line {lineno})'
|
|
487
|
+
return (
|
|
488
|
+
f'{safe_os_path_relpath(page_src_path, docs_dir)}'
|
|
489
|
+
f':{lineno}'
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def lineno_from_content_start(content: str, start: int) -> int:
|
|
494
|
+
"""Return the line number of the first line of ``start`` in ``content``."""
|
|
495
|
+
return content[:start].count('\n') + 1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|