mkdocs-include-markdown-plugin 7.1.7__py3-none-any.whl → 7.2.0__py3-none-any.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.
- mkdocs_include_markdown_plugin/config.py +1 -0
- mkdocs_include_markdown_plugin/directive.py +91 -14
- mkdocs_include_markdown_plugin/event.py +76 -38
- mkdocs_include_markdown_plugin/placeholders.py +37 -0
- mkdocs_include_markdown_plugin/plugin.py +12 -1
- mkdocs_include_markdown_plugin/process.py +55 -5
- {mkdocs_include_markdown_plugin-7.1.7.dist-info → mkdocs_include_markdown_plugin-7.2.0.dist-info}/METADATA +62 -1
- mkdocs_include_markdown_plugin-7.2.0.dist-info/RECORD +16 -0
- mkdocs_include_markdown_plugin-7.1.7.dist-info/RECORD +0 -15
- {mkdocs_include_markdown_plugin-7.1.7.dist-info → mkdocs_include_markdown_plugin-7.2.0.dist-info}/WHEEL +0 -0
- {mkdocs_include_markdown_plugin-7.1.7.dist-info → mkdocs_include_markdown_plugin-7.2.0.dist-info}/entry_points.txt +0 -0
- {mkdocs_include_markdown_plugin-7.1.7.dist-info → mkdocs_include_markdown_plugin-7.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -20,6 +20,7 @@ class PluginConfig(Config): # noqa: D101
|
|
|
20
20
|
comments = MkType(bool, default=False)
|
|
21
21
|
rewrite_relative_urls = MkType(bool, default=True)
|
|
22
22
|
heading_offset = MkType(int, default=0)
|
|
23
|
+
order = MkType(str, default='alpha-path')
|
|
23
24
|
start = Optional(MkType(str))
|
|
24
25
|
end = Optional(MkType(str))
|
|
25
26
|
exclude = ListOfItems(MkType(str), default=[])
|
|
@@ -13,8 +13,15 @@ from typing import TYPE_CHECKING
|
|
|
13
13
|
from mkdocs.exceptions import PluginError
|
|
14
14
|
from wcmatch import glob
|
|
15
15
|
|
|
16
|
-
from mkdocs_include_markdown_plugin import process
|
|
17
16
|
from mkdocs_include_markdown_plugin.logger import logger
|
|
17
|
+
from mkdocs_include_markdown_plugin.process import (
|
|
18
|
+
file_lineno_message,
|
|
19
|
+
filter_paths,
|
|
20
|
+
is_absolute_path,
|
|
21
|
+
is_relative_path,
|
|
22
|
+
is_url,
|
|
23
|
+
sort_paths,
|
|
24
|
+
)
|
|
18
25
|
|
|
19
26
|
|
|
20
27
|
@dataclass
|
|
@@ -28,6 +35,7 @@ if TYPE_CHECKING: # pragma: no cover
|
|
|
28
35
|
from typing import Callable, Literal, TypedDict
|
|
29
36
|
|
|
30
37
|
DirectiveBoolArgumentsDict = dict[str, DirectiveBoolArgument]
|
|
38
|
+
OrderOption = tuple[bool, str, str]
|
|
31
39
|
|
|
32
40
|
DefaultValues = TypedDict(
|
|
33
41
|
'DefaultValues', {
|
|
@@ -41,6 +49,7 @@ if TYPE_CHECKING: # pragma: no cover
|
|
|
41
49
|
'recursive': bool,
|
|
42
50
|
'start': str | None,
|
|
43
51
|
'end': str | None,
|
|
52
|
+
'order': str,
|
|
44
53
|
},
|
|
45
54
|
)
|
|
46
55
|
|
|
@@ -92,10 +101,12 @@ def str_arg(arg: str) -> re.Pattern[str]:
|
|
|
92
101
|
|
|
93
102
|
|
|
94
103
|
ARGUMENT_REGEXES = {
|
|
104
|
+
# str
|
|
95
105
|
'start': functools.partial(str_arg, 'start'),
|
|
96
106
|
'end': functools.partial(str_arg, 'end'),
|
|
97
107
|
'exclude': functools.partial(str_arg, 'exclude'),
|
|
98
108
|
'encoding': functools.partial(str_arg, 'encoding'),
|
|
109
|
+
'order': functools.partial(str_arg, 'order'),
|
|
99
110
|
|
|
100
111
|
# bool
|
|
101
112
|
'comments': functools.partial(arg, 'comments'),
|
|
@@ -178,7 +189,7 @@ def warn_invalid_directive_arguments(
|
|
|
178
189
|
)
|
|
179
190
|
for maybe_arg in _maybe_arguments_iter(arguments_string):
|
|
180
191
|
if maybe_arg not in valid_args:
|
|
181
|
-
location =
|
|
192
|
+
location = file_lineno_message(
|
|
182
193
|
page_src_path, docs_dir, directive_lineno(),
|
|
183
194
|
)
|
|
184
195
|
logger.warning(
|
|
@@ -283,12 +294,13 @@ def resolve_file_paths_to_include( # noqa: PLR0912
|
|
|
283
294
|
includer_page_src_path: str | None,
|
|
284
295
|
docs_dir: str,
|
|
285
296
|
ignore_paths: list[str],
|
|
297
|
+
order: str,
|
|
286
298
|
) -> tuple[list[str], bool]:
|
|
287
299
|
"""Resolve the file paths to include for a directive."""
|
|
288
|
-
if
|
|
300
|
+
if is_url(include_string):
|
|
289
301
|
return [include_string], True
|
|
290
302
|
|
|
291
|
-
if
|
|
303
|
+
if is_absolute_path(include_string):
|
|
292
304
|
if os.name == 'nt': # pragma: no cover
|
|
293
305
|
# Windows
|
|
294
306
|
fpath = os.path.normpath(include_string)
|
|
@@ -299,21 +311,25 @@ def resolve_file_paths_to_include( # noqa: PLR0912
|
|
|
299
311
|
if not is_file:
|
|
300
312
|
return [], False
|
|
301
313
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
),
|
|
314
|
+
paths = filter_paths([fpath], ignore_paths)
|
|
315
|
+
is_url_ = False
|
|
316
|
+
return sort_paths(paths, parse_order_option(order)), is_url_
|
|
305
317
|
|
|
306
318
|
try:
|
|
307
319
|
is_file = stat.S_ISREG(os.stat(include_string).st_mode)
|
|
308
320
|
except (FileNotFoundError, OSError):
|
|
309
321
|
is_file = False
|
|
310
|
-
|
|
322
|
+
paths = filter_paths(
|
|
311
323
|
[include_string] if is_file else glob.iglob(
|
|
312
324
|
include_string, flags=GLOB_FLAGS,
|
|
313
325
|
),
|
|
314
|
-
ignore_paths
|
|
326
|
+
ignore_paths,
|
|
327
|
+
)
|
|
328
|
+
is_url_ = False
|
|
329
|
+
sort_paths(paths, parse_order_option(order))
|
|
330
|
+
return paths, is_url_
|
|
315
331
|
|
|
316
|
-
if
|
|
332
|
+
if is_relative_path(include_string):
|
|
317
333
|
if includer_page_src_path is None: # pragma: no cover
|
|
318
334
|
raise PluginError(
|
|
319
335
|
'Relative paths are not allowed when the includer page'
|
|
@@ -338,7 +354,10 @@ def resolve_file_paths_to_include( # noqa: PLR0912
|
|
|
338
354
|
root_dir=root_dir,
|
|
339
355
|
):
|
|
340
356
|
paths.append(os.path.join(root_dir, fp))
|
|
341
|
-
|
|
357
|
+
paths = filter_paths(paths, ignore_paths)
|
|
358
|
+
is_url_ = False
|
|
359
|
+
sort_paths(paths, parse_order_option(order))
|
|
360
|
+
return paths, is_url_
|
|
342
361
|
|
|
343
362
|
# relative to docs_dir
|
|
344
363
|
paths = []
|
|
@@ -357,7 +376,10 @@ def resolve_file_paths_to_include( # noqa: PLR0912
|
|
|
357
376
|
root_dir=root_dir,
|
|
358
377
|
):
|
|
359
378
|
paths.append(os.path.join(root_dir, fp))
|
|
360
|
-
|
|
379
|
+
paths = filter_paths(paths, ignore_paths)
|
|
380
|
+
is_url_ = False
|
|
381
|
+
sort_paths(paths, parse_order_option(order))
|
|
382
|
+
return paths, is_url_
|
|
361
383
|
|
|
362
384
|
|
|
363
385
|
def resolve_file_paths_to_exclude(
|
|
@@ -366,10 +388,10 @@ def resolve_file_paths_to_exclude(
|
|
|
366
388
|
docs_dir: str,
|
|
367
389
|
) -> list[str]:
|
|
368
390
|
"""Resolve the file paths to exclude for a directive."""
|
|
369
|
-
if
|
|
391
|
+
if is_absolute_path(exclude_string):
|
|
370
392
|
return glob.glob(exclude_string, flags=GLOB_FLAGS)
|
|
371
393
|
|
|
372
|
-
if
|
|
394
|
+
if is_relative_path(exclude_string):
|
|
373
395
|
if includer_page_src_path is None: # pragma: no cover
|
|
374
396
|
raise PluginError(
|
|
375
397
|
'Relative paths are not allowed when the includer page'
|
|
@@ -394,3 +416,58 @@ def resolve_file_paths_to_exclude(
|
|
|
394
416
|
flags=GLOB_FLAGS,
|
|
395
417
|
root_dir=docs_dir,
|
|
396
418
|
)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def validate_order_option(
|
|
422
|
+
order: str,
|
|
423
|
+
page_src_path: str | None,
|
|
424
|
+
docs_dir: str,
|
|
425
|
+
directive_lineno: Callable[[], int],
|
|
426
|
+
directive: str,
|
|
427
|
+
) -> None:
|
|
428
|
+
"""Validate the 'order' option."""
|
|
429
|
+
regex = get_order_option_regex()
|
|
430
|
+
match = regex.match(order)
|
|
431
|
+
if not match:
|
|
432
|
+
location = file_lineno_message(
|
|
433
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
434
|
+
)
|
|
435
|
+
raise PluginError(
|
|
436
|
+
f"Invalid value '{order}' for the 'order' argument in"
|
|
437
|
+
f" '{directive}' directive at {location}. The argument"
|
|
438
|
+
" 'order' must be a string that matches the regex"
|
|
439
|
+
f" '{regex.pattern}'.",
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
@functools.cache
|
|
444
|
+
def get_order_option_regex() -> re.Pattern[str]:
|
|
445
|
+
"""Return the compiled regex to validate the 'order' option."""
|
|
446
|
+
return re.compile(
|
|
447
|
+
r'^-?'
|
|
448
|
+
r'(?:'
|
|
449
|
+
r'(?:alpha|natural)?(?:-?(?:path|name|extension))?'
|
|
450
|
+
r'|system|random|size|mtime|ctime|atime'
|
|
451
|
+
r')?$',
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def parse_order_option(order: str) -> OrderOption:
|
|
456
|
+
"""Parse the 'order' option into a tuple."""
|
|
457
|
+
ascending = False
|
|
458
|
+
order_type = 'alpha'
|
|
459
|
+
order_by = 'path'
|
|
460
|
+
if order.startswith('-'):
|
|
461
|
+
ascending = True
|
|
462
|
+
order = order[1:]
|
|
463
|
+
order_split = order.split('-', 1)
|
|
464
|
+
if len(order_split) == 2: # noqa: PLR2004
|
|
465
|
+
order_type, order_by = order_split
|
|
466
|
+
elif order_split[0] in (
|
|
467
|
+
'alpha', 'random', 'natural', 'system',
|
|
468
|
+
'size', 'mtime', 'ctime', 'atime',
|
|
469
|
+
):
|
|
470
|
+
order_type = order_split[0]
|
|
471
|
+
elif order_split[0] in ('name', 'path', 'extension'):
|
|
472
|
+
order_by = order_split[0]
|
|
473
|
+
return ascending, order_type, order_by
|
|
@@ -24,14 +24,20 @@ from mkdocs_include_markdown_plugin.directive import (
|
|
|
24
24
|
parse_string_argument,
|
|
25
25
|
resolve_file_paths_to_exclude,
|
|
26
26
|
resolve_file_paths_to_include,
|
|
27
|
+
validate_order_option,
|
|
27
28
|
warn_invalid_directive_arguments,
|
|
28
29
|
)
|
|
29
30
|
from mkdocs_include_markdown_plugin.files_watcher import FilesWatcher
|
|
30
31
|
from mkdocs_include_markdown_plugin.logger import logger
|
|
32
|
+
from mkdocs_include_markdown_plugin.placeholders import (
|
|
33
|
+
escape_placeholders,
|
|
34
|
+
save_placeholder,
|
|
35
|
+
unescape_placeholders,
|
|
36
|
+
)
|
|
31
37
|
|
|
32
38
|
|
|
33
39
|
if TYPE_CHECKING: # pragma: no cover
|
|
34
|
-
from typing import
|
|
40
|
+
from typing import TypedDict
|
|
35
41
|
|
|
36
42
|
from mkdocs.structure.pages import Page
|
|
37
43
|
|
|
@@ -46,23 +52,6 @@ if TYPE_CHECKING: # pragma: no cover
|
|
|
46
52
|
)
|
|
47
53
|
|
|
48
54
|
|
|
49
|
-
# Placeholders (taken from Python-Markdown)
|
|
50
|
-
STX = '\u0002'
|
|
51
|
-
''' "Start of Text" marker for placeholder templates. '''
|
|
52
|
-
ETX = '\u0003'
|
|
53
|
-
''' "End of Text" marker for placeholder templates. '''
|
|
54
|
-
INLINE_PLACEHOLDER_PREFIX = f'{STX}klzzwxh:'
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def build_placeholder(
|
|
58
|
-
num: int,
|
|
59
|
-
directive: Literal['include', 'include-markdown'],
|
|
60
|
-
) -> str:
|
|
61
|
-
"""Return a placeholder."""
|
|
62
|
-
directive_prefix = 'im' if directive == 'include-markdown' else 'i'
|
|
63
|
-
return f'{INLINE_PLACEHOLDER_PREFIX}{directive_prefix}{num}{ETX}'
|
|
64
|
-
|
|
65
|
-
|
|
66
55
|
@dataclass
|
|
67
56
|
class Settings: # noqa: D101
|
|
68
57
|
exclude: list[str] | None
|
|
@@ -98,8 +87,8 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
98
87
|
else:
|
|
99
88
|
settings_ignore_paths = []
|
|
100
89
|
|
|
101
|
-
|
|
102
|
-
|
|
90
|
+
markdown = escape_placeholders(markdown)
|
|
91
|
+
placeholders_contents: list[tuple[str, str]] = []
|
|
103
92
|
|
|
104
93
|
def found_include_tag( # noqa: PLR0912, PLR0915
|
|
105
94
|
match: re.Match[str],
|
|
@@ -153,13 +142,42 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
153
142
|
):
|
|
154
143
|
ignore_paths.append(path)
|
|
155
144
|
|
|
145
|
+
order = defaults['order']
|
|
146
|
+
if 'order' in used_arguments:
|
|
147
|
+
order_match = ARGUMENT_REGEXES['order']().search(
|
|
148
|
+
arguments_string,
|
|
149
|
+
)
|
|
150
|
+
order_ = parse_string_argument(order_match)
|
|
151
|
+
if order_ is None:
|
|
152
|
+
location = process.file_lineno_message(
|
|
153
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
154
|
+
)
|
|
155
|
+
raise PluginError(
|
|
156
|
+
"Invalid empty 'order' argument in 'include'"
|
|
157
|
+
f' directive at {location}',
|
|
158
|
+
)
|
|
159
|
+
validate_order_option(
|
|
160
|
+
order_, page_src_path, docs_dir, directive_lineno, 'include',
|
|
161
|
+
)
|
|
162
|
+
order = order_
|
|
163
|
+
|
|
156
164
|
file_paths_to_include, is_url = resolve_file_paths_to_include(
|
|
157
165
|
filename,
|
|
158
166
|
page_src_path,
|
|
159
167
|
docs_dir,
|
|
160
168
|
ignore_paths,
|
|
169
|
+
order,
|
|
161
170
|
)
|
|
162
171
|
|
|
172
|
+
if is_url and 'order' in used_arguments: # pragma: no cover
|
|
173
|
+
location = process.file_lineno_message(
|
|
174
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
175
|
+
)
|
|
176
|
+
logger.warning(
|
|
177
|
+
f"Ignoring 'order' argument of 'include' directive"
|
|
178
|
+
f" at {location} because the included path is a URL",
|
|
179
|
+
)
|
|
180
|
+
|
|
163
181
|
if not file_paths_to_include:
|
|
164
182
|
location = process.file_lineno_message(
|
|
165
183
|
page_src_path, docs_dir, directive_lineno(),
|
|
@@ -311,11 +329,7 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
311
329
|
f' {readable_files_to_include}',
|
|
312
330
|
)
|
|
313
331
|
|
|
314
|
-
|
|
315
|
-
include_index = len(new_found_include_contents)
|
|
316
|
-
placeholder = build_placeholder(include_index, 'include')
|
|
317
|
-
new_found_include_contents.append((placeholder, text_to_include))
|
|
318
|
-
return placeholder
|
|
332
|
+
return save_placeholder(placeholders_contents, text_to_include)
|
|
319
333
|
|
|
320
334
|
def found_include_markdown_tag( # noqa: PLR0912, PLR0915
|
|
321
335
|
match: re.Match[str],
|
|
@@ -369,13 +383,46 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
369
383
|
):
|
|
370
384
|
ignore_paths.append(path)
|
|
371
385
|
|
|
386
|
+
order = defaults['order']
|
|
387
|
+
if 'order' in used_arguments:
|
|
388
|
+
order_match = ARGUMENT_REGEXES['order']().search(
|
|
389
|
+
arguments_string,
|
|
390
|
+
)
|
|
391
|
+
order_ = parse_string_argument(order_match)
|
|
392
|
+
if order_ is None:
|
|
393
|
+
location = process.file_lineno_message(
|
|
394
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
395
|
+
)
|
|
396
|
+
raise PluginError(
|
|
397
|
+
"Invalid empty 'order' argument in 'include-markdown'"
|
|
398
|
+
f' directive at {location}',
|
|
399
|
+
)
|
|
400
|
+
validate_order_option(
|
|
401
|
+
order_,
|
|
402
|
+
page_src_path,
|
|
403
|
+
docs_dir,
|
|
404
|
+
directive_lineno,
|
|
405
|
+
'include-markdown',
|
|
406
|
+
)
|
|
407
|
+
order = order_
|
|
408
|
+
|
|
372
409
|
file_paths_to_include, is_url = resolve_file_paths_to_include(
|
|
373
410
|
filename,
|
|
374
411
|
page_src_path,
|
|
375
412
|
docs_dir,
|
|
376
413
|
ignore_paths,
|
|
414
|
+
order,
|
|
377
415
|
)
|
|
378
416
|
|
|
417
|
+
if is_url and 'order' in used_arguments: # pragma: no cover
|
|
418
|
+
location = process.file_lineno_message(
|
|
419
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
420
|
+
)
|
|
421
|
+
logger.warning(
|
|
422
|
+
f"Ignoring 'order' argument of 'include-markdown' directive"
|
|
423
|
+
f" at {location} because the included path is a URL",
|
|
424
|
+
)
|
|
425
|
+
|
|
379
426
|
if not file_paths_to_include:
|
|
380
427
|
location = process.file_lineno_message(
|
|
381
428
|
page_src_path, docs_dir, directive_lineno(),
|
|
@@ -607,15 +654,7 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
607
654
|
f' {readable_files_to_include}',
|
|
608
655
|
)
|
|
609
656
|
|
|
610
|
-
|
|
611
|
-
markdown_include_index = len(new_found_include_markdown_contents)
|
|
612
|
-
placeholder = build_placeholder(
|
|
613
|
-
markdown_include_index, 'include-markdown',
|
|
614
|
-
)
|
|
615
|
-
new_found_include_markdown_contents.append(
|
|
616
|
-
(placeholder, text_to_include),
|
|
617
|
-
)
|
|
618
|
-
return placeholder
|
|
657
|
+
return save_placeholder(placeholders_contents, text_to_include)
|
|
619
658
|
|
|
620
659
|
# Replace contents by placeholders
|
|
621
660
|
markdown = tags['include-markdown'].sub(
|
|
@@ -628,11 +667,9 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
628
667
|
)
|
|
629
668
|
|
|
630
669
|
# Replace placeholders by contents
|
|
631
|
-
for placeholder, text in
|
|
632
|
-
markdown = markdown.replace(placeholder, text, 1)
|
|
633
|
-
for placeholder, text in new_found_include_markdown_contents:
|
|
670
|
+
for placeholder, text in placeholders_contents:
|
|
634
671
|
markdown = markdown.replace(placeholder, text, 1)
|
|
635
|
-
return markdown
|
|
672
|
+
return unescape_placeholders(markdown)
|
|
636
673
|
|
|
637
674
|
|
|
638
675
|
def on_page_markdown(
|
|
@@ -671,6 +708,7 @@ def on_page_markdown(
|
|
|
671
708
|
'recursive': config.recursive,
|
|
672
709
|
'start': config.start,
|
|
673
710
|
'end': config.end,
|
|
711
|
+
'order': config.order,
|
|
674
712
|
},
|
|
675
713
|
Settings(
|
|
676
714
|
exclude=config.exclude,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Module for placeholders processing."""
|
|
2
|
+
|
|
3
|
+
# Placeholders (taken from Python-Markdown)
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
STX = '\u0002'
|
|
8
|
+
''' "Start of Text" marker for placeholder templates. '''
|
|
9
|
+
ETX = '\u0003'
|
|
10
|
+
''' "End of Text" marker for placeholder templates. '''
|
|
11
|
+
INLINE_PLACEHOLDER_PREFIX = f'{STX}klzzwxh:'
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def build_placeholder(num: int) -> str:
|
|
15
|
+
"""Return a placeholder."""
|
|
16
|
+
return f'{INLINE_PLACEHOLDER_PREFIX}{num}{ETX}'
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def escape_placeholders(text: str) -> str:
|
|
20
|
+
"""Escape placeholders in the given text."""
|
|
21
|
+
return text.replace(STX, f'\\{STX}').replace(ETX, f'\\{ETX}')
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def unescape_placeholders(text: str) -> str:
|
|
25
|
+
"""Unescape placeholders in the given text."""
|
|
26
|
+
return text.replace(f'\\{STX}', STX).replace(f'\\{ETX}', ETX)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def save_placeholder(
|
|
30
|
+
placeholders_contents: list[tuple[str, str]],
|
|
31
|
+
text_to_include: str,
|
|
32
|
+
) -> str:
|
|
33
|
+
"""Save the included text and return the placeholder."""
|
|
34
|
+
inclusion_index = len(placeholders_contents)
|
|
35
|
+
placeholder = build_placeholder(inclusion_index)
|
|
36
|
+
placeholders_contents.append((placeholder, text_to_include))
|
|
37
|
+
return placeholder
|
|
@@ -11,7 +11,6 @@ from mkdocs.plugins import BasePlugin, event_priority
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING: # pragma: no cover
|
|
14
|
-
|
|
15
14
|
from mkdocs.config.defaults import MkDocsConfig
|
|
16
15
|
from mkdocs.livereload import LiveReloadServer
|
|
17
16
|
from mkdocs.structure.files import Files
|
|
@@ -19,6 +18,9 @@ if TYPE_CHECKING: # pragma: no cover
|
|
|
19
18
|
|
|
20
19
|
from mkdocs_include_markdown_plugin.cache import Cache, initialize_cache
|
|
21
20
|
from mkdocs_include_markdown_plugin.config import PluginConfig
|
|
21
|
+
from mkdocs_include_markdown_plugin.directive import (
|
|
22
|
+
get_order_option_regex,
|
|
23
|
+
)
|
|
22
24
|
from mkdocs_include_markdown_plugin.event import (
|
|
23
25
|
on_page_markdown as _on_page_markdown,
|
|
24
26
|
)
|
|
@@ -50,6 +52,15 @@ class IncludeMarkdownPlugin(BasePlugin[PluginConfig]):
|
|
|
50
52
|
' "include-markdown".',
|
|
51
53
|
)
|
|
52
54
|
|
|
55
|
+
if self.config.order != 'alpha-path':
|
|
56
|
+
regex = get_order_option_regex()
|
|
57
|
+
if not regex.match(self.config.order):
|
|
58
|
+
raise PluginError(
|
|
59
|
+
f"Invalid value '{self.config.order}' for the 'order'"
|
|
60
|
+
' global setting. Order must be a string'
|
|
61
|
+
f" that matches the regex '{regex.pattern}'.",
|
|
62
|
+
)
|
|
63
|
+
|
|
53
64
|
return config
|
|
54
65
|
|
|
55
66
|
@cached_property
|
|
@@ -15,6 +15,7 @@ if TYPE_CHECKING: # pragma: no cover
|
|
|
15
15
|
from typing import Any
|
|
16
16
|
|
|
17
17
|
from mkdocs_include_markdown_plugin.cache import Cache
|
|
18
|
+
from mkdocs_include_markdown_plugin.directive import OrderOption
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
# Markdown regular expressions. Taken from the original Markdown.pl by John
|
|
@@ -494,12 +495,12 @@ def filter_paths(
|
|
|
494
495
|
|
|
495
496
|
Args:
|
|
496
497
|
filepaths (list): Set of source paths to filter.
|
|
497
|
-
ignore_paths (list): Paths that
|
|
498
|
+
ignore_paths (list): Paths that are ignored.
|
|
498
499
|
|
|
499
500
|
Returns:
|
|
500
501
|
list: Non filtered paths ordered alphabetically.
|
|
501
502
|
"""
|
|
502
|
-
|
|
503
|
+
result = []
|
|
503
504
|
for filepath in filepaths:
|
|
504
505
|
# ignore by filepath
|
|
505
506
|
if filepath in ignore_paths:
|
|
@@ -514,11 +515,60 @@ def filter_paths(
|
|
|
514
515
|
# ignore if is a directory
|
|
515
516
|
try:
|
|
516
517
|
if not stat.S_ISDIR(os.stat(filepath).st_mode):
|
|
517
|
-
|
|
518
|
+
result.append(filepath)
|
|
518
519
|
except (FileNotFoundError, OSError): # pragma: no cover
|
|
519
520
|
continue
|
|
520
|
-
|
|
521
|
-
|
|
521
|
+
return result
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
def natural_sort_key(s: str) -> list[Any]:
|
|
525
|
+
"""Key function for natural sorting of strings."""
|
|
526
|
+
return [int(text) if text.isdigit() else text.lower()
|
|
527
|
+
for text in re.split(r'(\d+)', s)]
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
def sort_paths(paths: list[str], order: OrderOption) -> list[str]:
|
|
531
|
+
"""Sort a list of paths in-place according to an order option."""
|
|
532
|
+
ascending, order_type, order_by = order
|
|
533
|
+
|
|
534
|
+
if order_type == 'random':
|
|
535
|
+
import random # noqa: PLC0415
|
|
536
|
+
|
|
537
|
+
random.shuffle(paths)
|
|
538
|
+
return paths
|
|
539
|
+
|
|
540
|
+
key = None
|
|
541
|
+
if order_type == 'alpha':
|
|
542
|
+
if order_by == 'name':
|
|
543
|
+
def key(p: str) -> str:
|
|
544
|
+
return os.path.basename(p)
|
|
545
|
+
elif order_by == 'extension':
|
|
546
|
+
def key(p: str) -> str:
|
|
547
|
+
return os.path.splitext(p)[1]
|
|
548
|
+
elif order_type == 'natural':
|
|
549
|
+
if order_by == 'extension':
|
|
550
|
+
def key(p: str) -> str:
|
|
551
|
+
return natural_sort_key(os.path.splitext(p)[1]) # type: ignore
|
|
552
|
+
elif order_by == 'name':
|
|
553
|
+
def key(p: str) -> str:
|
|
554
|
+
return natural_sort_key(os.path.basename(p)) # type: ignore
|
|
555
|
+
else:
|
|
556
|
+
key = natural_sort_key # type: ignore
|
|
557
|
+
elif order_type == 'size':
|
|
558
|
+
def key(p: str) -> int: # type: ignore
|
|
559
|
+
return os.path.getsize(p)
|
|
560
|
+
ascending = not ascending # larger files first
|
|
561
|
+
elif order_type == 'mtime':
|
|
562
|
+
def key(p: str) -> float: # type: ignore
|
|
563
|
+
return os.path.getmtime(p)
|
|
564
|
+
elif order_type == 'ctime':
|
|
565
|
+
def key(p: str) -> float: # type: ignore
|
|
566
|
+
return os.path.getctime(p)
|
|
567
|
+
elif order_type == 'atime':
|
|
568
|
+
def key(p: str) -> float: # type: ignore
|
|
569
|
+
return os.path.getatime(p)
|
|
570
|
+
paths.sort(key=key, reverse=ascending)
|
|
571
|
+
return paths
|
|
522
572
|
|
|
523
573
|
|
|
524
574
|
def _is_valid_url_scheme_char(c: str) -> bool:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mkdocs-include-markdown-plugin
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.2.0
|
|
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
|
|
@@ -226,6 +226,32 @@ content to include.
|
|
|
226
226
|
- <a name="include-markdown_recursive" href="#include-markdown_recursive">#</a>
|
|
227
227
|
**recursive** (_true_): When this option is disabled, included files are not
|
|
228
228
|
processed for recursive includes. Possible values are `true` and `false`.
|
|
229
|
+
- <a name="include-markdown_order" href="#include-markdown_order">#</a>
|
|
230
|
+
**order** (_'alpha-path'_): Define the order in which multiple files are included
|
|
231
|
+
when using globs. Possible values are:
|
|
232
|
+
- A combination of an optional order type and an optional order by separated
|
|
233
|
+
by a hyphen (`-`), and optionally prefixed by a hyphen (`-`) to indicate
|
|
234
|
+
ascending order. If an order type or an order by is not specified, the defaults
|
|
235
|
+
are used. It follows the form:
|
|
236
|
+
`[-]<order_type>-<order_by>` where:
|
|
237
|
+
- **Order type**:
|
|
238
|
+
- `'alpha'` (default): Alphabetical order.
|
|
239
|
+
- `'natural'`: Natural order, so that e.g. `file2.md` comes before `file10.md`.
|
|
240
|
+
- **Order by**:
|
|
241
|
+
- `'path'` (default): Order by full file path.
|
|
242
|
+
- `'name'`: Order by file name only.
|
|
243
|
+
- `'extension'`: Order by file extension.
|
|
244
|
+
- A combination of an optional prefix hyphen to denote ascending order and
|
|
245
|
+
one of the following values in the form `[-]<value>` where `<value>` is one of:
|
|
246
|
+
- `'size'`: Order by file size.
|
|
247
|
+
- `'mtime'`: Order by file modification time.
|
|
248
|
+
- `'ctime'`: Order by file creation time (or the last metadata change time
|
|
249
|
+
on Unix systems).
|
|
250
|
+
- `'atime'`: Order by file last access time.
|
|
251
|
+
- `'random'`: Random order.
|
|
252
|
+
- `'system'`: Order provided by the operating system. This is the same as not
|
|
253
|
+
specifying any order and relying on the default order of the filesystem. This
|
|
254
|
+
may be different between operating systems, so use it with care.
|
|
229
255
|
- <a name="include-markdown_encoding" href="#include-markdown_encoding">#</a>
|
|
230
256
|
**encoding** (_'utf-8'_): Specify the encoding of the included file.
|
|
231
257
|
If not defined `'utf-8'` will be used.
|
|
@@ -284,6 +310,7 @@ content to include.
|
|
|
284
310
|
{%
|
|
285
311
|
include-markdown "**"
|
|
286
312
|
exclude="./{index,LICENSE}.md"
|
|
313
|
+
order="name"
|
|
287
314
|
%}
|
|
288
315
|
```
|
|
289
316
|
|
|
@@ -291,6 +318,13 @@ content to include.
|
|
|
291
318
|
{% include-markdown '/escap\'ed/single-quotes/in/file\'/name.md' %}
|
|
292
319
|
```
|
|
293
320
|
|
|
321
|
+
```jinja
|
|
322
|
+
{%
|
|
323
|
+
include-markdown "**"
|
|
324
|
+
order="-natural-extension"
|
|
325
|
+
%}
|
|
326
|
+
```
|
|
327
|
+
|
|
294
328
|
<!-- mdpo-disable-next-line -->
|
|
295
329
|
|
|
296
330
|
#### **`include`**
|
|
@@ -317,6 +351,32 @@ Includes the content of a file or a group of files.
|
|
|
317
351
|
- <a name="include_recursive" href="#include_recursive">#</a>
|
|
318
352
|
**recursive** (_true_): When this option is disabled, included files are not
|
|
319
353
|
processed for recursive includes. Possible values are `true` and `false`.
|
|
354
|
+
- <a name="include_order" href="#include_order">#</a>
|
|
355
|
+
**order** (_'alpha-path'_): Define the order in which multiple files are included
|
|
356
|
+
when using globs. Possible values are:
|
|
357
|
+
- A combination of an optional order type and an optional order by separated
|
|
358
|
+
by a hyphen (`-`), and optionally prefixed by a hyphen (`-`) to indicate
|
|
359
|
+
ascending order. If an order type or an order by is not specified, the defaults
|
|
360
|
+
are used. It follows the form:
|
|
361
|
+
`[-]<order_type>-<order_by>` where:
|
|
362
|
+
- **Order type**:
|
|
363
|
+
- `'alpha'` (default): Alphabetical order.
|
|
364
|
+
- `'natural'`: Natural order, so that e.g. `file2.md` comes before `file10.md`.
|
|
365
|
+
- **Order by**:
|
|
366
|
+
- `'path'` (default): Order by full file path.
|
|
367
|
+
- `'name'`: Order by file name only.
|
|
368
|
+
- `'extension'`: Order by file extension.
|
|
369
|
+
- A combination of an optional prefix hyphen to denote ascending order and
|
|
370
|
+
one of the following values in the form `[-]<value>` where `<value>` is one of:
|
|
371
|
+
- `'size'`: Order by file size.
|
|
372
|
+
- `'mtime'`: Order by file modification time.
|
|
373
|
+
- `'ctime'`: Order by file creation time (or the last metadata change time
|
|
374
|
+
on Unix systems).
|
|
375
|
+
- `'atime'`: Order by file last access time.
|
|
376
|
+
- `'random'`: Random order.
|
|
377
|
+
- `'system'`: Order provided by the operating system. This is the same as not
|
|
378
|
+
specifying any order and relying on the default order of the filesystem. This
|
|
379
|
+
may be different between operating systems, so use it with care.
|
|
320
380
|
- <a name="include_encoding" href="#include_encoding">#</a>
|
|
321
381
|
**encoding** (_'utf-8'_): Specify the encoding of the included file.
|
|
322
382
|
If not defined `'utf-8'` will be used.
|
|
@@ -341,6 +401,7 @@ Includes the content of a file or a group of files.
|
|
|
341
401
|
{%
|
|
342
402
|
include '**'
|
|
343
403
|
exclude='./*.md'
|
|
404
|
+
order='random'
|
|
344
405
|
%}
|
|
345
406
|
```
|
|
346
407
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
mkdocs_include_markdown_plugin/__init__.py,sha256=ByOde15RQSHlZTmkepPSzIt0GzUIv_-GKORFDnxnOmc,193
|
|
2
|
+
mkdocs_include_markdown_plugin/cache.py,sha256=iKZXwehr2Mus0NRcsKFRC6xMC4B5aG4pP-Yb1ooCQo4,3836
|
|
3
|
+
mkdocs_include_markdown_plugin/config.py,sha256=AuJWYB_sAbRYpecXy6HHugQR09kKjlibcYX6kkWmBVc,1137
|
|
4
|
+
mkdocs_include_markdown_plugin/directive.py,sha256=NiW8rtNJB2PzZE2fIPlqACc4oK8-XvQsV3D4uV5LJqs,14659
|
|
5
|
+
mkdocs_include_markdown_plugin/event.py,sha256=BXPoc7q66QWrojI4ypMfRR9FT567vpNmaXDgiWtKW38,26341
|
|
6
|
+
mkdocs_include_markdown_plugin/files_watcher.py,sha256=hu-63u8syl00mXP59vP_iqD7T1R9iU9JjiZOHDV5fas,298
|
|
7
|
+
mkdocs_include_markdown_plugin/logger.py,sha256=nl63G4IJSt5mEYHbObuh7BmmowSv-aa1l_v9I257570,230
|
|
8
|
+
mkdocs_include_markdown_plugin/placeholders.py,sha256=LBxFagmDDJ8le4AYrLJbt7WqYBu-kpJP6QqGWH7tDrs,1132
|
|
9
|
+
mkdocs_include_markdown_plugin/plugin.py,sha256=t7eIgB3Z6XmcPOzlTqE15ajhY3oYPNKOZLb6D1_hx7I,4334
|
|
10
|
+
mkdocs_include_markdown_plugin/process.py,sha256=J7P7x70nXD9GGs2bbBzdJmlm9LcujMTtdfKUsyBhK0k,22601
|
|
11
|
+
mkdocs_include_markdown_plugin/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
mkdocs_include_markdown_plugin-7.2.0.dist-info/METADATA,sha256=axDz994hej34gNXyh8DsBNwB7n8zuyOy_oue70M3Gfk,15851
|
|
13
|
+
mkdocs_include_markdown_plugin-7.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
14
|
+
mkdocs_include_markdown_plugin-7.2.0.dist-info/entry_points.txt,sha256=WEL5m7sw5ZMBwmdOs5S_9mGoZfLCaUDPkDKw7CUk16Q,96
|
|
15
|
+
mkdocs_include_markdown_plugin-7.2.0.dist-info/licenses/LICENSE,sha256=qm1MNzU_lIANFB-1cBpD9hqdD_Htv3_Xr6hobt0IHq8,11365
|
|
16
|
+
mkdocs_include_markdown_plugin-7.2.0.dist-info/RECORD,,
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
mkdocs_include_markdown_plugin/__init__.py,sha256=ByOde15RQSHlZTmkepPSzIt0GzUIv_-GKORFDnxnOmc,193
|
|
2
|
-
mkdocs_include_markdown_plugin/cache.py,sha256=iKZXwehr2Mus0NRcsKFRC6xMC4B5aG4pP-Yb1ooCQo4,3836
|
|
3
|
-
mkdocs_include_markdown_plugin/config.py,sha256=VX95U8-9gFzPUIBSTA8TSL4xOD49qTMSs8dhFiilGns,1091
|
|
4
|
-
mkdocs_include_markdown_plugin/directive.py,sha256=A6pgzbvXiuLgsPs46W0RSEh1N0sxOjmQLwvHBk_CNm0,12425
|
|
5
|
-
mkdocs_include_markdown_plugin/event.py,sha256=0LdBA_4GxcY2nSU-PDiDqb9FFCqaC3LraiY0f0M-LIw,24954
|
|
6
|
-
mkdocs_include_markdown_plugin/files_watcher.py,sha256=hu-63u8syl00mXP59vP_iqD7T1R9iU9JjiZOHDV5fas,298
|
|
7
|
-
mkdocs_include_markdown_plugin/logger.py,sha256=nl63G4IJSt5mEYHbObuh7BmmowSv-aa1l_v9I257570,230
|
|
8
|
-
mkdocs_include_markdown_plugin/plugin.py,sha256=0muHIhmklC7v-QKWsAcAtZKhhZQ2olH6b28b3_3e4gI,3850
|
|
9
|
-
mkdocs_include_markdown_plugin/process.py,sha256=FQ3f4h6uNKelllh_Wk95Zl8xGrfD6Cc0jCP-9s7Bmf4,20803
|
|
10
|
-
mkdocs_include_markdown_plugin/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
-
mkdocs_include_markdown_plugin-7.1.7.dist-info/METADATA,sha256=jozFV_ZWEAECbS5smW2KpwYKmQ1REKxz89l_jq8aEgs,12770
|
|
12
|
-
mkdocs_include_markdown_plugin-7.1.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
13
|
-
mkdocs_include_markdown_plugin-7.1.7.dist-info/entry_points.txt,sha256=WEL5m7sw5ZMBwmdOs5S_9mGoZfLCaUDPkDKw7CUk16Q,96
|
|
14
|
-
mkdocs_include_markdown_plugin-7.1.7.dist-info/licenses/LICENSE,sha256=qm1MNzU_lIANFB-1cBpD9hqdD_Htv3_Xr6hobt0IHq8,11365
|
|
15
|
-
mkdocs_include_markdown_plugin-7.1.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|