Conversation
Add a comprehensive execution plan document issue-262-nested-code-block-handling.md outlining the approach to fix nested fenced code block normalization. This living document details the purpose, context, constraints, risks, and concrete steps to reuse FenceTracker semantics to preserve nested fenced blocks during fence normalization, preventing inner triple-backtick fences from being altered inside outer fences. This addition aids future implementation, testing, and validation efforts for issue #262. Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>
|
This PR implements Issue ExecPlan
Core implementation
Tests
Documentation
Outcome and verification
Files of primary interest
WalkthroughHandle nested fenced code blocks using a FenceTracker-driven normalisation. Buffer outer fenced blocks in Changes
Sequence Diagram(s)sequenceDiagram
actor Client
participant Normaliser as compress_fences
participant Tracker as FenceTracker
participant Attachor as attach_orphan_specifiers
Client->>Normaliser: submit lines with nested fences
activate Normaliser
Normaliser->>Tracker: open/inspect fence state
activate Tracker
Tracker-->>Normaliser: in_fence=true/false
deactivate Tracker
Normaliser->>Tracker: observe inner fence-like line
activate Tracker
Tracker-->>Normaliser: still in_fence=true
deactivate Tracker
alt inner fence would become structural if outer compressed
Normaliser->>Normaliser: preserve outer delimiter width
else safe to compress
Normaliser->>Normaliser: compress outer delimiters to three backticks
end
Normaliser->>Tracker: observe outer closing fence
activate Tracker
Tracker-->>Normaliser: in_fence=false
deactivate Tracker
deactivate Normaliser
Normaliser-->>Client: return normalised lines
Client->>Attachor: pass lines for orphan-specifier attachment
activate Attachor
Attachor->>Tracker: query in_fence?
activate Tracker
Tracker-->>Attachor: true/false
deactivate Tracker
alt not in fence and specifier candidate found
Attachor->>Attachor: attach specifier to next unlabeled fence
else in fence
Attachor->>Attachor: skip attachment, preserve lines
end
deactivate Attachor
Attachor-->>Client: final output lines
Poem
Caution Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional.
❌ Failed checks (2 errors, 4 warnings)
✅ Passed checks (12 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Reviewer's GuideImplements nested-fence-aware normalization for mdtablefix by reworking compress_fences and attach_orphan_specifiers to use FenceTracker semantics, adding targeted regressions (including CLI) for nested backtick/tilde fences, extending FenceTracker tests, updating architecture docs, and adding an ExecPlan documenting the approach and rollout for issue #262. Sequence diagram for nested-fence-aware compress_fences and attach_orphan_specifierssequenceDiagram
participant CLI
participant Process as process_stream_inner
participant Fences as fences::module
participant Compress as compress_fences
participant Attach as attach_orphan_specifiers
participant Tracker as FenceTracker
participant IsFence as is_fence
CLI->>Process: run with --fences input_lines
Process->>Fences: preprocess lines
Note over Fences: Fence compression phase
Fences->>Compress: compress_fences(lines)
Compress->>Tracker: new()
loop for each line index i
Compress->>Tracker: in_fence()
alt outside_fence
Compress->>IsFence: is_fence(lines[i])
alt no_matching_block
Compress-->>Process: compressed_fence_line or original line
else start_of_matched_block
Compress->>Tracker: observe(lines[i])
Compress->>Tracker: in_fence()
Compress->>Compress: analyze_opening(lines, i)
Compress->>Compress: opening_rewrite(...)
Compress-->>Process: rewrite_fence_line(opening_line, rewrite)
Note over Tracker: tracker now in_fence for outer block
end
else inside_fence
Compress->>Tracker: observe(lines[i])
alt not_a_delimiter
Compress-->>Process: preserve line as literal
else closing_delimiter
Compress->>Compress: rewrite_fence_line(closing_line, active_rewrite)
Compress-->>Process: rewritten closing line
Note over Tracker: fence state closed
end
end
end
Note over Fences: Orphan specifier attachment phase
Fences->>Attach: attach_orphan_specifiers(compressed_lines)
Attach->>Tracker: new()
loop for each line j
Attach->>Tracker: in_fence()
alt inside_fence
Attach->>Tracker: observe(line_j)
Attach-->>Process: push line_j unchanged
else outside_fence
Attach->>Attach: normalize_specifier(line_j)
alt is_orphan_specifier and previous_blank
Attach->>Attach: orphan_specifier_target_without_language(lines, j+1)
alt found_target_fence
Attach->>Attach: attach_specifier_to_fence(target_line, spec, indent)
Attach-->>Process: push updated fence_line
Attach->>Tracker: observe(target_line)
else no_target
Attach-->>Process: push line_j unchanged
Attach->>Tracker: observe(line_j)
end
else normal_line
Attach-->>Process: push line_j unchanged
Attach->>Tracker: observe(line_j)
end
end
end
Process-->>CLI: formatted output lines
Class diagram for updated fence normalization and specifier attachmentclassDiagram
class FenceRewrite {
<<enum>>
+Compress
+PreserveDelimiters
+PreserveAll
}
class OpeningAnalysis {
+FenceRewrite rewrite
}
class FencesModule {
+compress_fences(lines: &[String]) Vec~String~
+attach_orphan_specifiers(lines: &[String]) Vec~String~
-normalize_specifier(line: &str) (String, String)
-marker_char(marker: &str) Option~char~
-fence_line_with_marker(line: &str, marker: &str) Option~String~
-compressed_fence_line(line: &str) Option~String~
-preserved_fence_line(line: &str) Option~String~
-interior_fence_requires_preserved_delimiters(opening_marker: &str, line: &str) bool
-analyze_opening(lines: &[String], opening_index: usize) Option~OpeningAnalysis~
-opening_rewrite(lines: &[String], index: usize, has_conflicting_interior_fence: bool) FenceRewrite
-rewrite_fence_line(line: &str, rewrite: FenceRewrite) String
-attach_specifier_to_fence(fence_line: &str, specifier: &str, spec_indent: &str) String
-orphan_specifier_target(lines: &[String], start: usize) Option~usize~
-orphan_specifier_target_without_language(lines: &[String], start: usize) Option~usize~
}
class FenceTracker {
+new() FenceTracker
+observe(line: &str) bool
+in_fence() bool
}
class IsFenceFn {
+is_fence(line: &str) Option~(String, String, String)~
}
FencesModule --> FenceRewrite : uses
FencesModule --> OpeningAnalysis : constructs
FencesModule --> FenceTracker : holds and calls
FencesModule --> IsFenceFn : calls is_fence
OpeningAnalysis --> FenceRewrite : contains
File-Level Changes
Assessment against linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>
…s present Prevent compressing outer fence delimiters below the length of nested same-marker literal fences to avoid premature termination of the outer block. Specifically, four-character outer backtick fences wrapping inner triple-backtick fences remain four backticks wide, and similarly for tilde fences (e.g., `~~~~` wrapping `~~~`). This fix ensures nested literal content inside fenced blocks is preserved unchanged and stops fence compression from corrupting document structure. It also updates `compress_fences` to track fence state and conditionally apply compression only when safe. Additional improvements include updated regression tests validating the new behaviour and enhanced documentation clarifying fence compression rules and risks. Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>
Make `compress_fences` use shared `FenceTracker` semantics for matched fenced blocks, so literal nested fence examples remain unchanged and unsafe outer delimiters keep their original marker width or family. Make orphan specifier attachment fence-aware so language-looking content inside an outer fence is not attached to an inner literal fence. Document the new normalization rule and keep the ExecPlan current with the delivered behaviour and validation evidence.
|
@coderabbitai Have the following failed checks now been resolved? If further work is required, please provide an AI agent prompt for the remaining work to be done to address these failures. Assessment against linked issues
|
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chainLet me inspect the codebase to craft a precise agent prompt. 🏁 Script executed: Length of output: 151244
|
There was a problem hiding this comment.
Hey - I've found 5 issues, and left some high level feedback:
- The new
compress_fencesimplementation callsanalyze_opening(which rescans from the current line forward with a freshFenceTracker) for each line while not in a fence; consider restructuring to avoid this repeated forward scan (e.g., a single pass with state about the current block) to keep behavior linear on large inputs. src/fences.rsnow mixesFENCE_RE,wrap::is_fence, andFenceTrackerto interpret fence lines; it may be worth consolidating on a single parsing/normalization entry point (or at least documenting the intended division of responsibility) to reduce the risk of subtle divergence between preprocessing and wrapping semantics.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new `compress_fences` implementation calls `analyze_opening` (which rescans from the current line forward with a fresh `FenceTracker`) for each line while not in a fence; consider restructuring to avoid this repeated forward scan (e.g., a single pass with state about the current block) to keep behavior linear on large inputs.
- `src/fences.rs` now mixes `FENCE_RE`, `wrap::is_fence`, and `FenceTracker` to interpret fence lines; it may be worth consolidating on a single parsing/normalization entry point (or at least documenting the intended division of responsibility) to reduce the risk of subtle divergence between preprocessing and wrapping semantics.
## Individual Comments
### Comment 1
<location path="src/fences.rs" line_range="111-120" />
<code_context>
+ marker_ch == opening_ch || marker_ch == '`'
+}
+
+fn analyze_opening(lines: &[String], opening_index: usize) -> Option<OpeningAnalysis> {
+ let (_indent, opening_marker, _info) = is_fence(&lines[opening_index])?;
+
+ let mut tracker = FenceTracker::new();
+ if !tracker.observe(&lines[opening_index]) {
+ return None;
+ }
+
+ let mut has_conflicting_interior_fence = false;
+ for line in lines.iter().skip(opening_index + 1) {
+ let was_in_fence = tracker.in_fence();
+ let observed_fence = tracker.observe(line);
+ if observed_fence && was_in_fence && !tracker.in_fence() {
+ return Some(OpeningAnalysis {
+ rewrite: opening_rewrite(lines, opening_index, has_conflicting_interior_fence),
+ });
+ }
+ if was_in_fence && interior_fence_requires_preserved_delimiters(opening_marker, line) {
+ has_conflicting_interior_fence = true;
+ }
+ }
+
+ None
+}
+
</code_context>
<issue_to_address>
**suggestion (performance):** analyze_opening is re-run from the current index on every outer line, which can make compress_fences O(n²) on large inputs.
Because `compress_fences` calls `analyze_opening` for every line where `!tracker.in_fence()`, and `analyze_opening` scans forward from `opening_index + 1` to the closing fence (or EOF), the same ranges can be re-walked many times, yielding quadratic behavior on large inputs with many long fences. Consider moving this analysis into the main pass (e.g., track `has_conflicting_interior_fence` in `FenceTracker` or alongside it so each line is visited once) or caching results per `opening_index`.
Suggested implementation:
```rust
```
To fully implement the performance fix (avoid re-scanning ranges for each line and make the algorithm O(n)), you will also need to:
1. Move the “interior fence” analysis into the main `compress_fences` pass:
- In `compress_fences`, track for the *current open fence*:
- The `opening_index` (line index of the opening fence).
- The `opening_marker` (backticks/tilde string from `is_fence`).
- A `has_conflicting_interior_fence: bool` flag.
- When you detect an opening fence (where `FenceTracker` transitions from `!in_fence` to `in_fence`), initialize:
- `opening_index` to the current line index.
- `opening_marker` from `is_fence(&lines[opening_index])`.
- `has_conflicting_interior_fence = false`.
- For each subsequent line while `tracker.in_fence()` is `true`, call `interior_fence_requires_preserved_delimiters(opening_marker, line)`, and if it returns `true`, set `has_conflicting_interior_fence = true`.
2. When the main `FenceTracker` detects the closing fence (transition from `in_fence == true` to `false`):
- Use the stored `opening_index` and `has_conflicting_interior_fence` to compute the `OpeningAnalysis`:
- Call `opening_rewrite(lines, opening_index, has_conflicting_interior_fence)` at that point.
- Apply the rewrite logic directly in `compress_fences` instead of calling `analyze_opening`.
3. Remove all remaining calls to `analyze_opening` (they will now be replaced by the logic described above in the main loop).
- If the current code uses `OpeningAnalysis` as a separate step, inline its usage into `compress_fences` when you detect the closing fence.
4. If `OpeningAnalysis` is now only used internally within `compress_fences` and doesn’t need to be a separate abstraction, you may also consider simplifying or removing that type to reduce complexity.
</issue_to_address>
### Comment 2
<location path="tests/fences.rs" line_range="29-38" />
<code_context>
assert!(tracker.in_fence());
}
+#[test]
+fn fence_tracker_keeps_outer_backticks_open_for_inner_triple_backticks() {
+ let mut tracker = FenceTracker::new();
</code_context>
<issue_to_address>
**suggestion (testing):** Consider adding a regression where an orphan specifier appears deeper inside the fenced content, not just immediately after the outer opener.
The new test confirms we don’t attach an orphan specifier between the outer fence and an inner fenced block. To fully cover this behavior, please also add a case where the orphan-like line appears after the inner opening fence (e.g., the `"Rust"` line in your example) and assert that `attach_orphan_specifiers(&compress_fences(&input))` returns `input` unchanged. That will verify we never attach specifiers anywhere inside an active (possibly nested) fence.
</issue_to_address>
### Comment 3
<location path="src/wrap/tests/fence_tracker.rs" line_range="44-53" />
<code_context>
assert!(tracker.in_fence());
}
+#[test]
+fn fence_tracker_keeps_outer_backticks_open_for_inner_triple_backticks() {
+ let mut tracker = FenceTracker::new();
</code_context>
<issue_to_address>
**suggestion (testing):** Consider adding the symmetric case with outer tildes and inner backticks to fully document cross-family behavior.
The new test covers outer backticks with inner tildes. To keep the behavior symmetric and guard against regressions, please also add the mirror case with outer tildes and inner backticks, e.g.:
```rust
#[test]
fn fence_tracker_ignores_backticks_inside_outer_tilde_fence() {
let mut tracker = FenceTracker::default();
assert!(tracker.observe("~~~~"));
assert!(tracker.in_fence());
assert!(tracker.observe("```"));
assert!(tracker.in_fence());
assert!(tracker.observe("~~~~"));
assert!(!tracker.in_fence());
}
```
</issue_to_address>
### Comment 4
<location path="tests/cli_fences.rs" line_range="7-8" />
<code_context>
assert!(tracker.in_fence());
}
+#[test]
+fn fence_tracker_keeps_outer_backticks_open_for_inner_triple_backticks() {
+ let mut tracker = FenceTracker::new();
</code_context>
<issue_to_address>
**suggestion (testing):** Extend CLI regression tests to cover tilde-based outer fences and a case where the outer fence is compressed while preserving nested content.
To parallel the ExecPlan tests and strengthen end-to-end coverage, consider also adding:
1. A tilde-based variant (e.g., `~~~~markdown` with an inner ``` block) to verify CLI behavior matches `compress_fences` unit tests.
2. A case where the outer tilde fence is actually compressed (e.g., `~~~~markdown` → ```markdown) while still preserving the inner literal fence.
This will confirm the CLI flow enforces both compression and nested-fence preservation, not just the non-rewrite path.
</issue_to_address>
### Comment 5
<location path="src/fences.rs" line_range="71" />
<code_context>
+ PreserveAll,
+}
+
+struct OpeningAnalysis {
+ rewrite: FenceRewrite,
+}
</code_context>
<issue_to_address>
**issue (complexity):** Consider simplifying the fence analysis and rewrite helpers by inlining `OpeningAnalysis` into `analyze_opening` and consolidating the marker-handling functions into a single core helper while preserving behavior.
You can trim a fair bit of complexity here without changing behavior by:
### 1. Removing the extra `OpeningAnalysis` wrapper and simplifying `analyze_opening`
`OpeningAnalysis` only wraps a `FenceRewrite`, and `analyze_opening` constructs a new `FenceTracker` for a second pass. You can both:
* return `Option<FenceRewrite>` directly, and
* avoid creating a new `FenceTracker` by using a minimal local state (fence depth + closing index) when looking ahead.
For example:
```rust
fn analyze_opening(lines: &[String], opening_index: usize) -> Option<FenceRewrite> {
let (_indent, opening_marker, _info) = is_fence(&lines[opening_index])?;
let mut depth = 1;
let mut has_conflicting_interior_fence = false;
for line in &lines[opening_index + 1..] {
if let Some((_indent, marker, _info)) = is_fence(line) {
if depth == 1 && interior_fence_requires_preserved_delimiters(opening_marker, line) {
has_conflicting_interior_fence = true;
}
// naive depth tracking: same marker opens, same marker closes
if marker == opening_marker {
depth -= 1;
if depth == 0 {
return Some(opening_rewrite(
lines,
opening_index,
has_conflicting_interior_fence,
));
}
} else {
depth += 1;
}
}
}
None
}
```
Then call it directly from `compress_fences`:
```rust
if !tracker.in_fence() {
if let Some(rewrite) = analyze_opening(lines, index) {
let _ = tracker.observe(line);
active_rewrite = Some(rewrite);
out.push(rewrite_fence_line(line, rewrite));
} else {
out.push(compressed_fence_line(line).unwrap_or_else(|| line.clone()));
}
continue;
}
```
And drop `OpeningAnalysis` entirely:
```rust
// remove:
struct OpeningAnalysis {
rewrite: FenceRewrite,
}
```
This keeps all behavior (including detection of conflicting interior fences) but removes the nested `FenceTracker` and one layer of indirection.
---
### 2. Flattening the fence rewriting helpers
`fence_line_with_marker`, `compressed_fence_line`, and `preserved_fence_line` are a small chain around the same regex. You can make the core behavior visible with a single helper and a simple enum:
```rust
enum MarkerStrategy<'a> {
Compressed, // always ```
PreserveDelimiter, // original marker
}
fn rewrite_marker(line: &str, strategy: MarkerStrategy<'_>) -> Option<String> {
let cap = FENCE_RE.captures(line)?;
let indent = cap.get(1).map_or("", |m| m.as_str());
let orig_marker = cap.get(2).map_or("", |m| m.as_str());
let lang = cap.get(3).map_or("", |m| m.as_str());
if is_null_lang(lang) {
let marker = match strategy {
MarkerStrategy::Compressed => "```",
MarkerStrategy::PreserveDelimiter => orig_marker,
};
Some(format!("{indent}{marker}"))
} else {
let marker = match strategy {
MarkerStrategy::Compressed => "```",
MarkerStrategy::PreserveDelimiter => orig_marker,
};
Some(format!("{indent}{marker}{lang}"))
}
}
```
Then:
```rust
fn compressed_fence_line(line: &str) -> Option<String> {
rewrite_marker(line, MarkerStrategy::Compressed)
}
fn preserved_fence_line(line: &str) -> Option<String> {
rewrite_marker(line, MarkerStrategy::PreserveDelimiter)
}
```
This keeps the same public helpers but removes the extra hop through `fence_line_with_marker` and makes the “indent + marker + lang” logic sit in one obvious place.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/architecture.md`:
- Around line 31-35: Replace the ambiguous phrase "The latter keeps indentation
from the language line when the fence lacks it." with an explicit reference to
the attach_orphan_specifiers function: state that attach_orphan_specifiers is
responsible for preserving/propagating indentation from the language line when a
fence lacks it, so the sentence clearly attributes that behavior to
attach_orphan_specifiers rather than to outer-delimiter compression.
In `@docs/execplans/issue-262-nested-code-block-handling.md`:
- Around line 291-303: Update the ExecPlan text in Stage A so that follow-up
work points to tests/cli_fences.rs (where the CLI regression was implemented)
instead of tests/cli.rs; locate the reference to "tests/cli.rs" in the Stage A
paragraph (search for the phrase or the Stage A header) and replace it with
"tests/cli_fences.rs" to keep the plan consistent with the implemented CLI
regression.
- Around line 176-178: The paragraph has an inline code span for the fence token
that was split across lines, breaking the backtick sequence (e.g. the outer
fence marker like ```` and inner marker like ```); fix it by rejoining the split
backtick span so the entire inline code span (the full sequence of backticks)
appears intact on one line. Ensure the wrapping logic treats inline code spans
(`…`) as atomic: move the whole backtick span to the next line rather than
splitting it, so the rewritten fence token remains a single unbroken code span.
In `@src/fences.rs`:
- Around line 161-166: The doc comment for compress_fences is stale: it claims
“Lines that do not start with backtick fences are returned unchanged,” which is
incorrect because safe tilde fences can still be rewritten to backticks; update
the comment for compress_fences in src/fences.rs to describe behavior accurately
by saying non-fence lines (or lines that are not fence delimiters) are returned
unchanged, and clarify that safe tilde/other fence delimiters may be rewritten
to three backticks when shortened—adjust the surrounding sentences to reflect
that only non-fence content is unchanged while compatible fence formats may be
normalized.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: c6f0ed34-10a6-4271-95b9-5052afd56842
📒 Files selected for processing (6)
docs/architecture.mddocs/execplans/issue-262-nested-code-block-handling.mdsrc/fences.rssrc/wrap/tests/fence_tracker.rstests/cli_fences.rstests/fences.rs
Replace the repeated forward scan in `compress_fences` with a single-pass pending-block implementation. The current open block now carries the marker and conflict state needed to decide whether its delimiters can be rewritten. Consolidate marker rewriting behind one helper and document how preprocessing uses `FENCE_RE` for normalization while relying on `FenceTracker` for shared structural fence semantics. Add regressions for deeper orphan-like content inside fences, symmetric outer-tilde tracker behaviour, and CLI nested-fence variants.
Clarify that `attach_orphan_specifiers` is responsible for carrying language line indentation onto unlabeled fences. Update the ExecPlan to point follow-up CLI coverage at `tests/cli_fences.rs` and keep inline fence marker code spans intact after wrapping. Adjust the `compress_fences` Rustdoc so it describes non-fence lines as unchanged while allowing safe backtick and tilde delimiter normalization.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/execplans/issue-262-nested-code-block-handling.md`:
- Around line 384-394: The docs currently direct testers to run the CLI test
target `cargo test --test cli` but the regression and ExecPlan point to the
specific test file `tests/cli_fences.rs`; update the example commands and
acceptance criteria to run the focused test (`cargo test --test cli_fences` or
target the `cli_fences.rs` test file) and mention `tests/cli_fences.rs`
explicitly so the documented validation path matches the implemented
nested-fence CLI tests; adjust the two occurrences noted (around the shown block
and lines ~435-436) so all references and example commands use the `cli_fences`
test target.
In `@src/fences.rs`:
- Around line 183-197: The code fails to enter fenced-state tracking for
openings recognized by wrap::is_fence when FENCE_RE is narrower; change the
control flow so you call is_fence(line) first and, if it returns Some, call
tracker.observe(line) and create the PendingFenceBlock (using opening_marker
from is_fence) before any FENCE_RE-based short-circuit; otherwise fall back to
the existing compressed_fence_line/continue path. Update the logic around
tracker.in_fence(), FENCE_RE.captures(line), is_fence, tracker.observe,
pending_block and PendingFenceBlock accordingly, and add a regression test that
opens a fence with spaced info (e.g., "``` rust") containing inner fence-like
lines to confirm inner fence-like lines are not rewritten as top-level fences.
In `@src/wrap/tests/fence_tracker.rs`:
- Around line 44-55: Multiple nearly identical tests for nested fence behavior
should be consolidated into a single parameterized rstest: replace the
individual test functions (e.g.,
fence_tracker_keeps_outer_backticks_open_for_inner_triple_backticks and the
other duplicate nested-fence tests) with one #[rstest] function that takes
parameters for outer marker, inner marker, and expected final in_fence state and
add #[case(...)] rows for backticks vs tildes and outer vs inner positions;
inside the test call FenceTracker::new(), then call tracker.observe(...) in the
same sequence used by the originals (observe outer start, assert in_fence,
observe inner start, assert in_fence, observe inner end, assert in_fence,
observe outer end, assert final in_fence) using the passed markers and assert
via tracker.in_fence() after each observe so all variants are covered by cases.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 00628922-3998-4c62-b399-5fb3755293f2
📒 Files selected for processing (5)
docs/execplans/issue-262-nested-code-block-handling.mdsrc/fences.rssrc/wrap/tests/fence_tracker.rstests/cli_fences.rstests/fences.rs
There was a problem hiding this comment.
♻️ Duplicate comments (2)
src/fences.rs (1)
185-194:⚠️ Potential issue | 🟠 MajorTrack structural openings before applying the rewrite regex.
Call
is_fence(line)first and enterFenceTrackerfor every structural opening, even whenFENCE_REcannot normalise that delimiter. As written, an opening such as``` rustfalls through the earlyFENCE_REguard, leaves the tracker outside the block, and lets later literal inner fence lines be rewritten as top-level fences. Add a regression for a spaced-info outer fence.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/fences.rs` around lines 185 - 194, The guard using FENCE_RE before updating the FenceTracker causes structural openings to be missed (e.g., "``` rust" with spacing) so move the is_fence(line) check ahead of the FENCE_RE early-return: call is_fence(line) first, and when it returns Some((_indent, opening_marker, _info)) always call tracker.observe(line) / enter the fence-tracking branch so the tracker knows we are inside a fence even if FENCE_RE.captures(line) is None; keep the compressed_fence_line fallback for non-structural lines, and add a regression test that exercises a spaced-info outer fence like "``` rust" to prevent future regressions.docs/execplans/issue-262-nested-code-block-handling.md (1)
388-398:⚠️ Potential issue | 🟡 MinorPoint the documented CLI validation path at
tests/cli_fences.rs.Replace
cargo test --test cli ...here with thecli_fencestarget. The nested-fence regression is documented elsewhere in this plan as living intests/cli_fences.rs, so the current completion path can pass without exercising the issue-specific CLI coverage.Triage:
[type:docstyle]As per coding guidelines, "Ensure that any API or behavioural changes are reflected in the documentation in
docs/."Also applies to: 439-440
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/execplans/issue-262-nested-code-block-handling.md` around lines 388 - 398, Update the documented CLI validation commands to target the specific test binary that covers the nested-fence regression: replace each occurrence of "cargo test --test cli" with "cargo test --test cli_fences" so the CLI validation runs the tests in tests/cli_fences.rs (including the nested-fence case); ensure both the earlier command and the other occurrences referenced (including the pair noted at the end of the file) are updated so the documented steps actually exercise the nested-fence regression.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@docs/execplans/issue-262-nested-code-block-handling.md`:
- Around line 388-398: Update the documented CLI validation commands to target
the specific test binary that covers the nested-fence regression: replace each
occurrence of "cargo test --test cli" with "cargo test --test cli_fences" so the
CLI validation runs the tests in tests/cli_fences.rs (including the nested-fence
case); ensure both the earlier command and the other occurrences referenced
(including the pair noted at the end of the file) are updated so the documented
steps actually exercise the nested-fence regression.
In `@src/fences.rs`:
- Around line 185-194: The guard using FENCE_RE before updating the FenceTracker
causes structural openings to be missed (e.g., "``` rust" with spacing) so move
the is_fence(line) check ahead of the FENCE_RE early-return: call is_fence(line)
first, and when it returns Some((_indent, opening_marker, _info)) always call
tracker.observe(line) / enter the fence-tracking branch so the tracker knows we
are inside a fence even if FENCE_RE.captures(line) is None; keep the
compressed_fence_line fallback for non-structural lines, and add a regression
test that exercises a spaced-info outer fence like "``` rust" to prevent future
regressions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: cac20dd3-2d96-4918-b73a-2dfbbd1c337c
📒 Files selected for processing (3)
docs/architecture.mddocs/execplans/issue-262-nested-code-block-handling.mdsrc/fences.rs
This comment was marked as resolved.
This comment was marked as resolved.
Use `wrap::is_fence` before the narrower rewrite regex so spaced info strings still enter fenced-state tracking. This prevents nested fence-like content inside those blocks from being treated as top-level fences. Add the focused regression, consolidate nested `FenceTracker` cases into an `rstest` table, and update the ExecPlan validation path to name the `cli_fences` target. Include Markdown normalization produced by the required formatting gate.
This comment was marked as resolved.
This comment was marked as resolved.
There was a problem hiding this comment.
Actionable comments posted: 13
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@AGENTS.md`:
- Around line 241-242: Reflow the sentence so the parenthesis and the backticked
tilde remain together (keep the phrase "Tilde requirements (`~`)" intact) by
adjusting line breaks/wrapping so the opening parenthesis is adjacent to the
backticked tilde; after editing, run make fmt and make markdownlint to validate
formatting.
- Around line 234-235: Reflow the sentence that mentions Cargo.toml so the
parenthetical example stays intact (e.g., `(e.g., `some-crate = "1.2.3"`)`) or
move the line break to occur before the opening parenthesis; remove the stray
leading space at the start of the line containing the example, ensure the
caret/SemVer example `some-crate = "1.2.3"` remains adjacent to `(e.g.,` for
readability, and run `make fmt` to normalize Markdown formatting.
In `@docs/execplans/issue-262-nested-code-block-handling.md`:
- Around line 3-5: Reflow the preamble paragraph so no line exceeds 80
characters by inserting breaks between the comma-separated section names; keep
the inline code formatting for `Constraints`, `Tolerances`, `Risks`, `Progress`,
`Surprises & Discoveries`, `Decision Log`, and `Outcomes & Retrospective`,
producing multiple wrapped lines that read naturally and preserve punctuation
and backticks.
- Around line 456-457: In the sentence within the docs change describing
attach_orphan_specifiers, insert a comma before the coordinating conjunction
"so" so the line reads "...active fenced blocks, so specifier-like lines inside
an outer fence remain content." This update touches the text around the
identifier attach_orphan_specifiers in the affected paragraph; add the comma to
join the two independent clauses correctly.
- Around line 91-93: The bullet point in the
docs/execplans/issue-262-nested-code-block-handling.md file exceeds the
80-column wrap rule; rewrap the sentence that begins with "`tests/cli_fences.rs`
for additional" so no line is longer than 80 characters, breaking the
continuation into multiple wrapped lines while preserving the Markdown bullet,
link text [`tests/cli_fences.rs`](../../tests/cli_fences.rs), and the original
meaning (e.g., wrap after the link or before "because" so the rest of the clause
continues on the next indented line).
- Around line 239-242: In the docs sentence referencing compress_fences and
wrap::is_fence, change the British-spelling "recognised" to the Oxford-preferred
"-ize" form "recognized"; update the phrase so it reads that openings are
"recognized by wrap::is_fence" (leave references to compress_fences, FENCE_RE,
FenceTracker, rstest and tests/cli_fences.rs unchanged).
- Around line 335-338: Reflow the paragraph containing the sentence starting
with "one case that shows `attach_orphan_specifiers`..." so no line exceeds 80
characters; wrap the prose into multiple lines at word boundaries to keep each
line ≤80 columns and preserve the backticked identifier
`attach_orphan_specifiers` and the reference to `tests/cli_fences.rs` and
`--fences` intact.
In `@docs/release-process.md`:
- Around line 10-12: Rewrap the paragraph mentioning the MSRV so the opening
parenthesis doesn't sit alone at line end: move the parenthetical `rust-version
= "1.89"` (or the opening paren) onto the same line as its content so the
sentence reads like "This Minimum Supported Rust Version (MSRV) is also declared
in `Cargo.toml` (`rust-version = \"1.89\`). The `build-test` job in
`.github/workflows/ci.yml` uses this toolchain to guard against regressions."
Adjust the line breaks around "MSRV", "`Cargo.toml`", and the parenthesis to
keep the delimiter with its content for improved readability.
In `@docs/rust-doctest-dry-guide.md`:
- Around line 203-204: The footnote marker `[^9]` was split across lines causing
it to render as text; edit the paragraph containing "scaffolding can be hidden,
presenting the user with only the relevant code." and join the split marker so
the entire `[^9]` appears on the same line immediately after the sentence (no
spaces or line breaks inside the `[^9]` token) to restore proper Markdown
footnote rendering.
- Around line 107-109: Update all doctest code fences in the document to include
an explicit Rust language specifier by changing bare fenced blocks to
triple-backtick fences with "rust" (e.g., ```rust) so examples match the
guidance; ensure every occurrence of bare fences or "Rust"-cased examples is
converted to ```rust and that any inconsistent tilded fences (~~~) are
standardized to the triple-backtick format; review paragraphs discussing
rustdoc/doctest to confirm the examples now obey the `rust`-specifier rule.
In `@docs/rust-testing-with-rstest-fixtures.md`:
- Around line 28-29: The footnote marker is currently attached to the start of
the example paragraph; move the GitHub-flavoured Markdown footnote marker `[^1]`
from the beginning of the sentence that starts on Line 29 to the end of the
preceding claim sentence ("Fixtures address this by encapsulating these
dependencies and their setup logic.") and then remove the leading reference
token from the example sentence so it begins normally ("For instance, if
multiple tests require a logged-in user object or a..."); ensure the footnote
remains `[^1]` and that the example sentence starts without any leading footnote
token.
- Around line 771-772: The footnote marker has been split across two lines (`[`
on one line and `^4]` on the next) which can break GFM parsing; fix by making
the footnote token contiguous (replace the line break so the text reads "needs
to be `.await`ed explicitly within the test body or by using `#[awt][^4]`" or
move `[^4]` directly after the clause) so `[^4]` is a single token on one line,
then run markdownlint to confirm no syntax warnings.
In `@src/fences.rs`:
- Around line 184-223: The code currently treats any is_fence opener as
potentially rewritable and may compress only the closing delimiter, breaking
mismatched fences; fix by recording whether the opener is rewritable when
creating PendingFenceBlock (e.g., set a flag like opening_rewritable =
FENCE_RE.is_match(&opening_marker) in the PendingFenceBlock alongside
opening_marker/lines), then when you finish observing a fence pair (before
calling flush_matched_block), only call flush_matched_block if both the opener’s
opening_rewritable flag and the closing delimiter are rewritable; otherwise push
the original buffered block.lines unchanged (preserving both outer delimiters).
Ensure you use the existing symbols is_fence, PendingFenceBlock, opening_marker,
tracker.observe, interior_fence_requires_preserved_delimiters, and
flush_matched_block to locate where to add the flag and the conditional flush,
and add a regression for a four-backtick spaced-info opener.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: df45a1e8-d687-40f7-bf4d-44937b00f564
📒 Files selected for processing (12)
AGENTS.mdCHANGELOG.mddocs/architecture.mddocs/execplans/issue-262-nested-code-block-handling.mddocs/execplans/replace-bespoke-wrapping-with-textwrap-and-unicode-width.mddocs/execplans/yaml-frontmatter.mddocs/release-process.mddocs/rust-doctest-dry-guide.mddocs/rust-testing-with-rstest-fixtures.mdsrc/fences.rssrc/wrap/tests/fence_tracker.rstests/fences.rs
Update user-facing and developer documentation for the `--fences` behaviour introduced by the nested-fence handling work. Describe when outer delimiters are compressed, when their width is preserved, and how orphan language specifiers are skipped inside active fenced blocks.
Avoid rewriting only one side of a matched fenced block when either outer delimiter is outside the supported normalization regex. This keeps spaced info-string fences intact while preserving existing legacy handling for unmatched blocks. Also address review comments in Markdown documentation by keeping inline examples, tilde markers, and footnote references contiguous after formatting.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/users-guide.md`:
- Around line 60-63: Edit the sentence starting "Outer delimiters are compressed
only when doing so is structurally safe..." and insert a comma before "so" in
the clause "the outer delimiter width is kept so the inner content does not
become a structural close", changing it to "the outer delimiter width is kept,
so the inner content does not become a structural close" to correctly punctuate
the compound sentence.
In `@README.md`:
- Line 64: Update the sentence "Use `--fences` to normalize code block
delimiters." by changing the American spelling "normalize" to the British Oxford
spelling "normalise" so it reads "Use `--fences` to normalise code block
delimiters." Ensure this exact phrase in README.md is replaced to comply with
en-GB-oxendict.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: d8161584-767d-43c7-be60-a52dae90bd72
📒 Files selected for processing (3)
README.mddocs/developers-guide.mddocs/users-guide.md
Add the missing comma in the user guide's `--fences` preservation rule so the compound sentence reads cleanly.
|
Tip For best results, initiate chat on the files or code changes.
No further work should be required for these two checks. Verify that |
There was a problem hiding this comment.
Actionable comments posted: 10
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@AGENTS.md`:
- Around line 234-235: Reflow the sentence containing "caret requirements" so
the opening parenthesis and example opener remain adjacent to their referent:
move "(e.g.," so the phrase reads "caret requirements (e.g.," on the same line
and place the rest of the example on the following line; after editing the
AGENTS.md sentence, run make fmt and make markdownlint to validate formatting.
In `@docs/developers-guide.md`:
- Around line 89-99: The docs currently understate compress_fences behaviour;
update the compress_fences entry to explicitly document the
backtick-inside-tilde case: state that when an inner backtick-fenced block would
become structural after normalization, compress_fences preserves the outer
tilde-fence width and marker family (i.e., it protects a tilde outer fence from
being converted when an inner backtick fence would be structural), and replace
or augment the phrase "same-marker inner fences" to include this cross-marker
(backtick-inside-tilde) exception; also add a short note in the
FenceTracker/attach_orphan_specifiers description that the scanner logic
intentionally skips attachment in such nested cases so readers can correlate the
behaviour with the tests.
In `@docs/execplans/issue-262-nested-code-block-handling.md`:
- Around line 201-247: Add a final Progress item under the existing "Progress"
list noting that the user guide and developer guide were updated and that
documentation gates (e.g. markdownlint and any doc build/validation commands
run) were executed, and set the ExecPlan Status to "COMPLETE"; update the prose
in this document's header/Status field accordingly and ensure the new checklist
entry mirrors the format of prior timestamps and checks so it appears as a
completed item in the roadmap.
- Around line 20-40: Update the example nested code-blocks so the outer fence
uses four backticks in both the "observable success case" and the corrected
output; specifically change the outer triple-backtick fences shown in the diffed
sample to four backticks so the inner ```rust``` block remains literal, and
likewise ensure the prose that follows refers to preserving outer four-backtick
fences (and analogous tilde fences like `~~~~`/`~~~`) to match the corrected
example.
In `@docs/release-process.md`:
- Around line 11-12: The inline code span `.github/workflows/ci.yml` in the
paragraph containing (`rust-version = "1.89"`) is currently split across lines;
rewrap that paragraph so the entire code span stays intact on the same line as
the preceding sentence, producing: "(`rust-version = \"1.89\"`). The
`build-test` job in `.github/workflows/ci.yml`" on one line and place the
remainder "uses this toolchain to guard against regressions." on the following
line, preserving the 80-column limit and treating the code span as an
unbreakable unit.
In `@docs/rust-testing-with-rstest-fixtures.md`:
- Around line 1279-1281: Rewrap the paragraph containing the phrase shown in the
diff so the compound term stays intact by replacing the split "`rstest`" and
"-generated" with a single "`rstest`-generated" token; locate the sentence
starting with "wrappers to ensure that logging is correctly set up before each
`rstest`" and merge the broken line breaks so it reads "...before each
`rstest`-generated test case runs, making it easier to get consistent log output
from tests." Ensure only whitespace/line breaks are changed, preserving the
original wording.
- Line 1288: The phrase "can be used in conjunction with `rstest`" is wordy — in
the sentence containing that exact string replace it with a concise alternative
such as "can be used with `rstest`" or "can be used alongside `rstest`" to
simplify the wording while preserving meaning; update the sentence in
docs/rust-testing-with-rstest-fixtures.md where the phrase appears.
In `@docs/users-guide.md`:
- Around line 60-68: Update the documentation for the mixed-marker preservation
rule to state that --fences preserves an outer tilde-fenced block when a literal
inner backtick fence would become structural after normalization (not just when
the inner and outer use the “same marker family”); edit the paragraph that
currently reads "same marker family" and expand it to explicitly mention the
tilde-outer / backtick-inner case and that any outer fence is kept when
normalization would otherwise turn an inner literal fence into a structural
close; also ensure the orphan-specifier sentence remains unchanged and that
examples or test references (if any) mention this mixed-marker preservation
behaviour for --fences.
In `@src/fences.rs`:
- Around line 167-174: Update the doc comment for compress_fences to state the
guarantee only applies to matched fenced blocks and explicitly mention the
unmatched-block fallback behavior used by flush_unmatched_block; reference the
compress_fences function and flush_unmatched_block helper so readers know that
when input ends with an unclosed fence the code falls back to stateless per-line
rewriting and fence-like lines inside an unclosed block may be rewritten rather
than preserved.
In `@tests/fences.rs`:
- Around line 29-72: These tests duplicate the same pattern and should be
collapsed into an rstest parameterized case: replace the multiple #[test]
functions (preserves_same_marker_nested_backtick_fences,
preserves_same_marker_nested_tilde_fences,
preserves_backtick_fences_nested_inside_tilde_fences,
preserves_tilde_content_inside_backtick_fences,
preserves_inner_fences_inside_spaced_info_fence,
preserves_four_backtick_spaced_info_outer_fence) with a single #[rstest] that
supplies tuples of input (built with lines_vec!) and expected output, then call
compress_fences(&input) and assert_eq!(out, expected) for each case; keep using
the same helpers (lines_vec!, compress_fences) and preserve the case where
expected equals input versus the single case with a different expected vector.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 4bbac326-c72b-4c04-8e4d-41363ea965e0
📒 Files selected for processing (9)
AGENTS.mddocs/developers-guide.mddocs/execplans/issue-262-nested-code-block-handling.mddocs/release-process.mddocs/rust-doctest-dry-guide.mddocs/rust-testing-with-rstest-fixtures.mddocs/users-guide.mdsrc/fences.rstests/fences.rs
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
docs/users-guide.md (1)
60-63:⚠️ Potential issue | 🟡 MinorInsert comma before "so" and document mixed-marker preservation.
Line 63 joins two independent clauses with "so" but lacks a comma. Additionally, the phrase "same marker family" does not reflect the implemented behaviour: from
src/fences.rs:112-123, preservation occurs whenmarker_ch == opening_ch || marker_ch == ''`, meaning a tilde-fenced outer block with a backtick-fenced interior also triggers preservation, not just same-marker scenarios.Triage:
[type:grammar][type:docstyle]📝 Proposed fix
Outer delimiters are compressed only when doing so is structurally safe. If a -four-or-more-backtick fence, or a longer tilde fence, wraps literal inner -fence-like content from the same marker family, the outer delimiter width is -kept, so the inner content does not become a structural close after formatting. +four-or-more-backtick fence wraps literal inner backtick content, or a longer +tilde fence wraps literal inner backtick or tilde content, the outer delimiter +width is kept, so the inner content does not become a structural close after +formatting.As per coding guidelines, "Use a comma before 'so' if it connects two independent clauses" and "Ensure that any API or behavioural changes are reflected in the documentation."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/users-guide.md` around lines 60 - 63, Add a comma before "so" in the sentence to separate the two independent clauses, and update the phrase "same marker family" to accurately describe the implemented rule in src/fences.rs (see the logic around marker_ch and opening_ch in lines ~112-123) by stating that preservation also occurs when marker_ch == opening_ch or when marker_ch == '`' (i.e., a backtick inner fence inside a tilde outer fence is preserved), ensuring the docs reflect mixed-marker preservation behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/users-guide.md`:
- Around line 70-84: Add a second example showing successful compression: insert
a short block after the existing fence-preservation example that demonstrates a
4-backtick outer fence whose interior contains no conflicting 3-backtick fence,
then show the "After running `mdtablefix --fences`" result where the outer fence
is compressed to three backticks; reference the existing demonstration of
delimiter preservation and use the same narrative phrasing ("Before:" and "After
running `mdtablefix --fences`:") so readers see both compression and
preservation behaviors for `mdtablefix --fences`.
- Line 54: The heading "Fence normalisation" uses -ise spelling; change it to
en-GB-Oxford style with -ize by renaming the heading to "Fence normalization"
(update the heading text in docs/users-guide.md where the string "Fence
normalisation" appears).
- Around line 56-58: Replace the British -ise spelling "normalise" with the
required en-GB-oxendict -ize form "normalize" in the sentence that starts "Pass
`--fences` to normalise fenced code block delimiters..." in docs/users-guide.md
so the documentation follows the project's -ize spelling guideline.
---
Duplicate comments:
In `@docs/users-guide.md`:
- Around line 60-63: Add a comma before "so" in the sentence to separate the two
independent clauses, and update the phrase "same marker family" to accurately
describe the implemented rule in src/fences.rs (see the logic around marker_ch
and opening_ch in lines ~112-123) by stating that preservation also occurs when
marker_ch == opening_ch or when marker_ch == '`' (i.e., a backtick inner fence
inside a tilde outer fence is preserved), ensuring the docs reflect mixed-marker
preservation behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: bed254d2-1a5e-4fbb-8dd0-973e1cd53712
📒 Files selected for processing (1)
docs/users-guide.md
Clarify that `compress_fences` protects tilde outer fences when an inner backtick fence would become structural after normalization. Document the unmatched-block fallback and keep the ExecPlan examples aligned with the four-backtick preservation case. Collapse repeated nested-fence tests into one parameterized `rstest` table and clean up the requested Markdown wrapping issues.
Use Oxford -ize spelling in the fence section, make the mixed-marker preservation rule explicit, and add a matching successful compression example so `--fences` documents both safe rewrite and preservation outcomes.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
tests/fences.rs (1)
87-109: 🛠️ Refactor suggestion | 🟠 MajorCollapse these orphan-specifier regressions into one
rstestmatrix.Fold these three tests into one parameterized case. The bodies are identical apart
from the fixtures, and the same table-driven pattern is already in use from
Line 29.Triage:
[type:docstyle]♻️ Proposed refactor
-#[test] -fn does_not_attach_orphan_specifier_inside_outer_fence() { - let input = lines_vec!["````markdown", "Rust", "```", "fn main() {}", "```", "````"]; - let out = attach_orphan_specifiers(&compress_fences(&input)); - assert_eq!(out, input); -} - -#[test] -fn does_not_attach_orphan_specifier_deeper_inside_outer_fence() { - let input = lines_vec!["````markdown", "```", "Rust", "fn main() {}", "```", "````",]; - let out = attach_orphan_specifiers(&compress_fences(&input)); - assert_eq!(out, input); -} - -#[test] -fn attaches_orphan_specifier_without_shortening_preserved_outer_fence() { - let input = lines_vec!["Rust", "````", "```", "fn main() {}", "```", "````"]; - let out = attach_orphan_specifiers(&compress_fences(&input)); - assert_eq!( - out, - lines_vec!["````rust", "```", "fn main() {}", "```", "````"] - ); -} +#[rstest] +#[case( + lines_vec!["````markdown", "Rust", "```", "fn main() {}", "```", "````"], + lines_vec!["````markdown", "Rust", "```", "fn main() {}", "```", "````"] +)] +#[case( + lines_vec!["````markdown", "```", "Rust", "fn main() {}", "```", "````"], + lines_vec!["````markdown", "```", "Rust", "fn main() {}", "```", "````"] +)] +#[case( + lines_vec!["Rust", "````", "```", "fn main() {}", "```", "````"], + lines_vec!["````rust", "```", "fn main() {}", "```", "````"] +)] +fn handles_orphan_specifiers_around_outer_fences( + #[case] input: Vec<String>, + #[case] expected: Vec<String>, +) { + let out = attach_orphan_specifiers(&compress_fences(&input)); + assert_eq!(out, expected); +}As per coding guidelines, "Replace duplicated Rust tests with
#[rstest(...)]parameterized cases."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/fences.rs` around lines 87 - 109, Replace the three near-duplicate tests with a single parameterized rstest: remove does_not_attach_orphan_specifier_inside_outer_fence, does_not_attach_orphan_specifier_deeper_inside_outer_fence, and attaches_orphan_specifier_without_shortening_preserved_outer_fence and add one function (e.g., handles_orphan_specifiers_around_outer_fences) annotated with #[rstest] and multiple #[case(...)] entries; each case should pass an input Vec<String> and the expected Vec<String>, call attach_orphan_specifiers(&compress_fences(&input)) and assert_eq!(out, expected) to preserve existing behavior; use the existing lines_vec! fixtures and ensure rstest is imported/available.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/developers-guide.md`:
- Around line 85-96: Update the section titled "Fence normalisation module" to
use Oxford -ize spelling: change the heading to "Fence normalization module" and
replace all occurrences of "normalisation" -> "normalization" and "normalising"
-> "normalizing" within the paragraph that documents compress_fences and
FenceTracker (the prose mentioning `src/fences.rs`, `compress_fences(lines:
&[String]) -> Vec<String>`, and `FenceTracker`); keep content semantics
identical aside from spelling changes. Ensure the updated text still references
the same functions/behaviour (e.g., same-marker and cross-marker cases) and that
backticks/tilde descriptions are unchanged except for the -ize spelling.
In `@docs/execplans/issue-262-nested-code-block-handling.md`:
- Around line 67-71: Update the paragraph to reflect the shipped behaviour:
describe that the fence preprocessing lives in src/fences.rs and that two
functions are involved—compress_fences(lines) (which performs conditional
outer-fence normalization, not an unconditional rewrite to exactly three
backticks) and attach_orphan_specifiers(lines) (which rewrites a lone language
line such as `Rust` onto the following unlabelled fence); also correct spelling
to "unlabelled" and remove any wording that claims unconditional normalization
to three backticks or implies behavior that is not implemented.
---
Duplicate comments:
In `@tests/fences.rs`:
- Around line 87-109: Replace the three near-duplicate tests with a single
parameterized rstest: remove
does_not_attach_orphan_specifier_inside_outer_fence,
does_not_attach_orphan_specifier_deeper_inside_outer_fence, and
attaches_orphan_specifier_without_shortening_preserved_outer_fence and add one
function (e.g., handles_orphan_specifiers_around_outer_fences) annotated with
#[rstest] and multiple #[case(...)] entries; each case should pass an input
Vec<String> and the expected Vec<String>, call
attach_orphan_specifiers(&compress_fences(&input)) and assert_eq!(out, expected)
to preserve existing behavior; use the existing lines_vec! fixtures and ensure
rstest is imported/available.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 2466d525-a6c5-446b-bce3-113bd51b2b5b
📒 Files selected for processing (7)
AGENTS.mddocs/developers-guide.mddocs/execplans/issue-262-nested-code-block-handling.mddocs/rust-testing-with-rstest-fixtures.mddocs/users-guide.mdsrc/fences.rstests/fences.rs
Use Oxford spelling in the developer fence documentation and update the ExecPlan wording so it describes conditional fence normalization rather than an unconditional rewrite. Replace the repeated orphan-specifier nested-fence tests with one parameterized `rstest` table that preserves the same inputs and expected output.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/execplans/issue-262-nested-code-block-handling.md`:
- Around line 334-339: The Stage A marker-classification sentence incorrectly
groups both examples as "same-marker cases"; update the wording in the Stage A
paragraph so it explicitly distinguishes the two shapes: refer to the
four-backtick-outer / triple-backtick-inner example as a same-marker case (both
use backticks, different lengths) and refer to the triple-tilde-outer /
triple-backtick-inner example as a mixed-marker case (tilde outer, backtick
inner), and adjust the following sentence about preservation to state that outer
four-character fences must remain four characters and that tilde-outer cases
must preserve tilde width.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 04d04307-3770-40f1-affb-3decdcfef2e1
📒 Files selected for processing (3)
docs/developers-guide.mddocs/execplans/issue-262-nested-code-block-handling.mdtests/fences.rs
Distinguish the same-marker and mixed-marker nested fence examples in the ExecPlan so the regression description matches the implemented preservation rules.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/execplans/issue-262-nested-code-block-handling.md`:
- Around line 454-456: Replace the ambiguous single-line command sentence that
currently lists `cargo test --test fences`, `cargo test --test cli_fences` and
references `tests/cli_fences.rs` with an explicit parallel bullet/list of
commands (one command per line) and a clear note of coverage: list `cargo test
--test fences`, `cargo test --test cli_fences` (annotating that `cli_fences`
runs tests in tests/cli_fences.rs), `make check-fmt`, `make lint`, `make test`,
and include the tracker target used elsewhere in the plan (e.g., the same
tracker identifier referenced previously) so the acceptance criteria explicitly
states each command and the tracker coverage.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: b5a9b458-184e-458d-a67a-d5f967887d59
📒 Files selected for processing (1)
docs/execplans/issue-262-nested-code-block-handling.md
Expand the ExecPlan acceptance criteria so each validation command is listed separately, including the `cli_fences` integration target and tracker coverage.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/execplans/issue-262-nested-code-block-handling.md`:
- Around line 89-93: Replace the first occurrence of the acronym "CLI" in the
paragraph that lists `tests/cli.rs` and `tests/cli_fences.rs` with its expanded
form "command-line interface (CLI)" and leave subsequent uses as "CLI"; update
the sentence that currently starts with "CLI" so it reads "command-line
interface (CLI) behaviour" (or equivalent) while keeping the existing link text
(`tests/cli.rs`, `tests/cli_fences.rs`) unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: e4eca565-2b97-4010-b1c6-9f41c4209adf
📒 Files selected for processing (1)
docs/execplans/issue-262-nested-code-block-handling.md
Summary
Changes
Rationale
Plan of work (high level)
Test plan
Acceptance criteria
Progress
Notes
◳ Generated by DevBoxer ◰
ℹ️ Tag @devboxerhub to ask questions and address PR feedback
📎 Task: https://www.devboxer.com/task/0d20afc3-1dba-45f8-bb0d-c8948f1c1c76
📝 Closes #262
Summary by Sourcery
Make fence normalization and orphan specifier attachment preserve nested fenced blocks while aligning behavior with the shared FenceTracker semantics.
Bug Fixes:
Enhancements:
Documentation:
Tests: