feat: Implement double-quoted filename features. (#13)
Adds interpretation of ordinary Python character escapes (like "\t") and a special escape to fetch a particular Git version of a file, in double-quoted strings used as the FILENAME argument of a {! ... !} inclusion directive. Resolves #11. Resolves #12. Co-authored-by: Glen Whitney <glen@studioinfinity.org> Reviewed-on: #13 Co-Authored-By: Glen Whitney <glen@nobody@nowhere.net> Co-Committed-By: Glen Whitney <glen@nobody@nowhere.net>
This commit is contained in:
parent
d0028497dc
commit
f458f716e3
19 changed files with 1225 additions and 14 deletions
|
@ -16,6 +16,8 @@ from mkdocs_simple_plugin.plugin import SimplePlugin, StreamExtract
|
|||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import tempfile
|
||||
import yaml
|
||||
|
||||
|
||||
|
@ -91,9 +93,12 @@ is checked for `{! ... !}`.
|
|||
# OK, we have found (the start of) an inclusion and must process it
|
||||
preamble = line[:include_match.start()]
|
||||
remainder = line[include_match.end(1):]
|
||||
doublequoted = False
|
||||
body_pattern = StreamInclusion.include_quoted_file
|
||||
if include_match[2].isspace():
|
||||
body_pattern = StreamInclusion.include_bare_file
|
||||
elif include_match[2] == '"':
|
||||
doublequoted = True
|
||||
body_match = body_pattern.search(remainder)
|
||||
if not body_match:
|
||||
for extra_line in self.input_stream:
|
||||
|
@ -105,7 +110,64 @@ is checked for `{! ... !}`.
|
|||
errmsg = "semiliterate: End of file while scanning for `!}`"
|
||||
utils.log.error(errmsg)
|
||||
raise EOFError(errmsg)
|
||||
include_path = self.include_root + '/' + body_match['fn']
|
||||
filename = body_match['fn']
|
||||
gitextract = False
|
||||
r""" md
|
||||
### Double-quoted filenames and Git extraction
|
||||
|
||||
Standard Python escape sequences in double-quoted filenames are interpreted
|
||||
as usual; for example you can write
|
||||
```
|
||||
{! ../tests/fixtures/quoted-filename/README.md extract:
|
||||
start: '(.*!.*)'
|
||||
stop: '\s'
|
||||
!}
|
||||
```
|
||||
to include a file whose name (`snippet/Say "Don't"`, in this case) has both
|
||||
double and single quotes.
|
||||
|
||||
Further, `semiliterate` supports a special escape to extract a file from the
|
||||
Git archive of the project (presuming it is under Git version control) and then
|
||||
include content from that file. For example, you could write
|
||||
```
|
||||
{! ../tests/fixtures/git-inclusion/README.md extract:
|
||||
start: '(.*!.*)'
|
||||
stop: '\s'
|
||||
!}
|
||||
```
|
||||
|
||||
to extract content starting after the `### install` line from the
|
||||
`mkdocs.yml` file in the Git commit of this repository
|
||||
tagged `0.1.0`. This feature is primarily useful if you are documenting the
|
||||
development or changes to a project over time, or are documenting a feature
|
||||
in a specific past release of your project, and want to be sure that
|
||||
material included in your documentation does _not_ change as the project
|
||||
progresses. (This behavior is as opposed to the usual case, in which you want
|
||||
your documentation to incorporate the most up-to-date version of extracted
|
||||
content.)
|
||||
|
||||
The precise behavior for a FILENAME argument in a `{! ... !}` inclusion of the
|
||||
form
|
||||
|
||||
`"\git SPECIFIER"`
|
||||
|
||||
is that the output of `git show SPECIFIER` is written to a temporary file,
|
||||
and that file is extracted from.
|
||||
"""
|
||||
if doublequoted:
|
||||
if filename[:5] == r'\git ':
|
||||
gitextract = True
|
||||
filename = filename[5:]
|
||||
filename = (filename.encode('latin-1', 'backslashreplace')
|
||||
.decode('unicode-escape'))
|
||||
include_path = self.include_root + '/' + filename
|
||||
if gitextract:
|
||||
(write_handle, include_path) = tempfile.mkstemp()
|
||||
utils.log.info(
|
||||
f"semiliterate: extracting {filename} to {include_path}")
|
||||
contents = subprocess.check_output(['git', 'show', filename])
|
||||
os.write(write_handle, contents)
|
||||
os.close(write_handle)
|
||||
new_root = re.match(r'(.*)/', include_path)[1]
|
||||
try:
|
||||
include_parameters = yaml.safe_load(body_match['yml'])
|
||||
|
@ -131,10 +193,23 @@ is checked for `{! ... !}`.
|
|||
class SemiliteratePlugin(SimplePlugin):
|
||||
r""" md An extension of the mkdocs-simple-plugin
|
||||
|
||||
In addition, block-comment markdown `/** md` ... `**/` is by
|
||||
default scanned for in all files with _any_ extension, as it's valid in so many
|
||||
disparate languages.
|
||||
### Universal block-comment markdown
|
||||
|
||||
By default, `semiliterate` scans for block-comment markdown `/** md` ... `**/`
|
||||
in all files with _any_ extension, as it's valid in so many disparate languages.
|
||||
(As opposed to `simple`, which defaults to searching for such markdown in a
|
||||
specific list of file types.)
|
||||
"""
|
||||
|
||||
super_sdict = dict(SimplePlugin.config_scheme)
|
||||
super_semi_dflt = super_sdict['semiliterate'].default
|
||||
semi_dflt = [b if 'js' not in b['pattern'] else dict(b, pattern=r'\.')
|
||||
for b in super_semi_dflt]
|
||||
altered_config_scheme = dict(
|
||||
super_sdict,
|
||||
semiliterate=config_options.Type(list, default=semi_dflt)).items()
|
||||
|
||||
add_param_doc = r""" md
|
||||
### Additional plugin parameters
|
||||
|
||||
`semiliterate` adds a couple of new plugin parameters to further tailor its
|
||||
|
@ -150,14 +225,6 @@ default values in parentheses at the beginning of each entry.
|
|||
terminate: '^\s*\)'
|
||||
!}
|
||||
"""
|
||||
|
||||
super_sdict = dict(SimplePlugin.config_scheme)
|
||||
super_semi_dflt = super_sdict['semiliterate'].default
|
||||
semi_dflt = [b if 'js' not in b['pattern'] else dict(b, pattern=r'\.')
|
||||
for b in super_semi_dflt]
|
||||
altered_config_scheme = dict(
|
||||
super_sdict,
|
||||
semiliterate=config_options.Type(list, default=semi_dflt)).items()
|
||||
config_scheme = (
|
||||
# Note documentation of each new parameter **follows** the parameter.
|
||||
*altered_config_scheme,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue