Skip to content

Commit

Permalink
first ideas
Browse files Browse the repository at this point in the history
  • Loading branch information
haenoe committed Sep 4, 2024
1 parent eb03773 commit 16ce928
Show file tree
Hide file tree
Showing 14 changed files with 123 additions and 4 deletions.
10 changes: 10 additions & 0 deletions doc/manual/book.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ additional-js = ["redirects.js"]
edit-url-template = "https://github.com/NixOS/nix/tree/master/doc/manual/{path}"
git-repository-url = "https://github.com/NixOS/nix"

# Handles replacing @docroot@ with a path to ./src relative to that markdown file,
# {{#include handlebars}}, and the @generated@ syntax used within these. it mostly
# but not entirely replaces the links preprocessor (which we cannot simply use due
# to @generated@ files living in a different directory to make meson happy). we do
# not want to disable the links preprocessor entirely though because that requires
# disabling *all* built-in preprocessors and selectively reenabling those we want.
[preprocessor.substitute]
command = "python3 doc/manual/substitute.py"
before = ["anchors", "links"]

[preprocessor.anchors]
renderers = ["html"]
command = "jq --from-file doc/manual/anchors.jq"
Expand Down
5 changes: 1 addition & 4 deletions doc/manual/src/command-ref/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,13 @@ nix3_cli_files = custom_target(
conf_file_md = custom_target(
command : [
nix_eval_for_docs,
'--write-to', '@OUTPUT@',
'--expr',
'import @INPUT0@ (builtins.fromJSON (builtins.readFile @INPUT1@))',
'import @INPUT0@ { prefix = "conf"; } (builtins.fromJSON (builtins.readFile @INPUT1@))',
],
capture : true,
input : [
'../../generate-settings.nix',
'../../utils.nix',
conf_file_json,
experimental_features_shortlist_md,
],
output : 'conf-file.md',
env : nix_env_for_docs,
Expand Down
1 change: 1 addition & 0 deletions doc/manual/src/contributing/cli-guideline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# CLI guideline
1 change: 1 addition & 0 deletions doc/manual/src/contributing/cxx.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# C++ style guide
1 change: 1 addition & 0 deletions doc/manual/src/contributing/documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Documentation
1 change: 1 addition & 0 deletions doc/manual/src/contributing/experimental-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Experimental Features
1 change: 1 addition & 0 deletions doc/manual/src/contributing/hacking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Hacking
1 change: 1 addition & 0 deletions doc/manual/src/contributing/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Contributing
1 change: 1 addition & 0 deletions doc/manual/src/contributing/json-guideline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# JSON guideline
1 change: 1 addition & 0 deletions doc/manual/src/contributing/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Testing
1 change: 1 addition & 0 deletions doc/manual/src/language/constructs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Language Constructs
1 change: 1 addition & 0 deletions doc/manual/src/language/values.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Data Types
1 change: 1 addition & 0 deletions doc/manual/src/protocols/json/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# JSON Formats
101 changes: 101 additions & 0 deletions doc/manual/substitute.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/usr/bin/env python3

from pathlib import Path
import json
import os, os.path
import sys

name = 'substitute.py'

def log(*args, **kwargs):
kwargs['file'] = sys.stderr
return print(f'{name}:', *args, **kwargs)

def do_include(content: str, relative_md_path: Path, source_root: Path, search_path: Path):
assert not relative_md_path.is_absolute(), f'{relative_md_path=} from mdbook should be relative'

md_path_abs = source_root / relative_md_path
var_abs = md_path_abs.parent
assert var_abs.is_dir(), f'supposed directory {var_abs} is not a directory (cwd={os.getcwd()})'

lines = []
for l in content.splitlines(keepends=True):
if l.strip().startswith("{{#include "):
requested = l.strip()[11:][:-2]
if requested.startswith("@generated@/"):
included = search_path / Path(requested[12:])
requested = included.relative_to(search_path)
else:
included = source_root / relative_md_path.parent / requested
requested = included.resolve().relative_to(source_root)
assert included.exists(), f"{requested} not found at {included}"
lines.append(do_include(included.read_text(), requested, source_root, search_path) + "\n")
else:
lines.append(l)
return "".join(lines)

def recursive_replace(data, book_root, search_path):
match data:
case {'sections': sections}:
return data | dict(
sections = [recursive_replace(section, book_root, search_path) for section in sections],
)
case {'Chapter': chapter}:
path_to_chapter = Path(chapter['path'])
chapter_content = chapter['content']

return data | dict(
Chapter = chapter | dict(
# first process includes. this must happen before docroot processing since
# mdbook does not see these included files, only the final agglomeration.
content = do_include(
chapter_content,
path_to_chapter,
book_root,
search_path
).replace(
'@docroot@',
("../" * len(path_to_chapter.parent.parts) or "./")[:-1]
),
sub_items = [
recursive_replace(sub_item, book_root, search_path)
for sub_item in chapter['sub_items']
],
),
)

case rest:
assert False, f'should have been called on a dict, not {type(rest)=}\n\t{rest=}'

def main():

if len(sys.argv) > 1 and sys.argv[1] == 'supports':
return 0

# mdbook communicates with us over stdin and stdout.
# It splorks us a JSON array, the first element describing the context,
# the second element describing the book itself,
# and then expects us to send it the modified book JSON over stdout.

context, book = json.load(sys.stdin)

# book_root is the directory where book contents leave (ie, src/)
book_root = Path(context['root']) / context['config']['book']['src']

# includes pointing into @generated@ will look here
search_path = Path(os.environ['MDBOOK_SUBSTITUTE_SEARCH'])

# Find @var@ in all parts of our recursive book structure.
replaced_content = recursive_replace(book, book_root, search_path)

replaced_content_str = json.dumps(replaced_content)

# Give mdbook our changes.
print(replaced_content_str)

try:
sys.exit(main())
except AssertionError as e:
print(f'{name}: INTERNAL ERROR in mdbook preprocessor', file=sys.stderr)
print(f'this is a bug in {name}', file=sys.stderr)
raise

0 comments on commit 16ce928

Please sign in to comment.