From ccb5b607ba88bf161253b35c2ea7934ce3baab68 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 24 Oct 2026 02:50:18 +0200 Subject: [PATCH 1/3] Python: parse directly adjacent code blocks Recognize a new directive after closing the preceding block on the same line, so consecutive code examples are all extracted. Tests: `make -C frontend test_rst_pipeline`. Co-Authored-By: Claude Co-Authored-By: Codex --- .../src/rst_code_example_pipeline/blocks.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/blocks.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/blocks.py index 2bdf95858..448dcea38 100644 --- a/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/blocks.py +++ b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/blocks.py @@ -175,7 +175,12 @@ def start_config_block(i, line, indent): if cb_start != -1: process_block(i, line, indent) - else: + # Not `else`: the line that ends a block (the first one indented + # less than its body) may itself start the next one. A + # ``.. code::`` directly following a code block, with no prose + # between them, was otherwise consumed as the terminator and + # never seen as a directive, so the second block vanished. + if cb_start == -1: if line[indent:].startswith(".. code::"): start_code_block(i, line, indent) elif line[indent:].startswith(":code-config:"): From 913f2681e2dc49e783edada36cb5fed5ad193c63 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 24 Oct 2026 02:50:32 +0200 Subject: [PATCH 2/3] Python: test adjacent code block parsing Cover adjacent directives, the second block's attributes, and an outer block following an indented block. Tests: full pipeline suite; all three new tests fail with the original parser and pass with the correction. Co-Authored-By: Claude Co-Authored-By: Codex --- .../tests/test_blocks.py | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/frontend/python/rst_code_example_pipeline/tests/test_blocks.py b/frontend/python/rst_code_example_pipeline/tests/test_blocks.py index 1e38f1255..fc3fcc699 100644 --- a/frontend/python/rst_code_example_pipeline/tests/test_blocks.py +++ b/frontend/python/rst_code_example_pipeline/tests/test_blocks.py @@ -164,6 +164,56 @@ def test_active_defaults_to_true(self): # T-blocks-02: project and main_file attributes # --------------------------------------------------------------------------- +class TestConsecutiveBlocks: + """A code block directly followed by another one, with no prose line + between them: both are parsed. The line that terminates the first block + is the second block's directive, and it used to be consumed as the + terminator only, so the second block was silently dropped.""" + + RST = textwrap.dedent("""\ + Intro. + + .. code:: ada compile_button project=P.First + + procedure First is begin null; end First; + + .. code:: ada run_button project=P.Second + + procedure Second is begin null; end Second; + + Closing paragraph. + """) + + def test_both_blocks_parsed(self): + blocks = [b for b in Block.get_blocks_from_rst(RST_FILE, self.RST) + if isinstance(b, CodeBlock)] + assert [b.project for b in blocks] == ["P.First", "P.Second"] + + def test_second_block_keeps_its_own_attributes(self): + blocks = [b for b in Block.get_blocks_from_rst(RST_FILE, self.RST) + if isinstance(b, CodeBlock)] + assert blocks[1].buttons == ["run"] + assert blocks[1].text.strip() == "procedure Second is begin null; end Second;" + + def test_block_after_an_indented_block(self): + rst = textwrap.dedent("""\ + - item + + .. code:: ada compile_button project=P.Nested + + procedure Nested is begin null; end Nested; + + .. code:: ada compile_button project=P.Outer + + procedure Outer is begin null; end Outer; + + Closing paragraph. + """) + blocks = [b for b in Block.get_blocks_from_rst(RST_FILE, rst) + if isinstance(b, CodeBlock)] + assert [b.project for b in blocks] == ["P.Nested", "P.Outer"] + + class TestProjectAndMainFile: RST = minimal_rst("""\ .. code:: ada project=MyProject main=main.adb From 216e4598141740211d26c4e62684dd9ddd0454c8 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 24 Oct 2026 02:50:44 +0200 Subject: [PATCH 3/3] Makefile: preserve PYTHONPATH in test drivers Escape dollar signs in both test driver definitions so the shell preserves the inherited `PYTHONPATH` when adding `sphinx`. Tests: both driver environment probes and local/Lambda dry runs. Co-Authored-By: Claude Co-Authored-By: Codex --- frontend/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/Makefile b/frontend/Makefile index 66872ce72..4b2b6a8c9 100644 --- a/frontend/Makefile +++ b/frontend/Makefile @@ -6,9 +6,9 @@ SPHINXCONF = sphinx BUILDDIR = dist SRC_TEST_DIR = $(BUILDDIR)/test_output TEST_LAMBDA ?= 0 -TEST_LOCAL_DRIVER = PYTHONPATH="$PYTHONPATH:sphinx" python3 tests/compile_blocks.py --keep_files -B $(SRC_TEST_DIR) +TEST_LOCAL_DRIVER = PYTHONPATH="$$PYTHONPATH:sphinx" python3 tests/compile_blocks.py --keep_files -B $(SRC_TEST_DIR) TEST_OPTIONS ?= -TEST_LAMBDA_DRIVER = PYTHONPATH="$PYTHONPATH:sphinx" python3 tests/execute_rst_code_blocks.py --halt-on-failure +TEST_LAMBDA_DRIVER = PYTHONPATH="$$PYTHONPATH:sphinx" python3 tests/execute_rst_code_blocks.py --halt-on-failure ifeq ($(strip $(TEST_LAMBDA)),1) TEST_DRIVER := $(TEST_LAMBDA_DRIVER)