Address review feedback for wrapping and footnotes - #266
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
SummaryThis pull request implements reviewer feedback by centralising mutable state across wrapping, footnote renumbering, ordered-list renumbering and HTML-table conversion, hardening error handling, normalising corner-case whitespace, and adding broad test and documentation coverage. Key changes
|
Reviewer's GuideRefactors wrapping, list renumbering, footnote renumbering, and HTML table conversion to centralize mutable state and remove panicking expectations, while tightening wrapping behavior (Unicode-aware indentation, whitespace-only lines) and adding regression tests, plus a small cargo-binstall override fix. Sequence diagram for updated wrap_text paragraph processingsequenceDiagram
participant WT as wrap_text
participant FT as FenceTracker
participant PW as ParagraphWriter
loop for each line in lines
WT->>FT: observe(line)
alt fence line toggled
FT-->>WT: true
WT->>PW: push_verbatim(line)
WT->>WT: continue
else not fence
FT-->>WT: false
alt FT.in_fence()
WT->>PW: push_verbatim(line)
WT->>WT: continue
else not in fence
alt line.trim().is_empty()
WT->>PW: push_blank_line()
WT->>WT: continue
else
alt passthrough block
WT->>PW: push_verbatim(line)
WT->>WT: continue
else prefix_line found
WT->>PW: handle_prefix_line(prefix_line)
WT->>WT: continue
else plain paragraph text
WT->>PW: note_indent(line)
WT->>WT: (text, hard_break) = line_break_parts(line)
WT->>PW: push_wrapped(text, hard_break)
end
end
end
end
end
WT->>PW: flush_paragraph()
Class diagram for updated wrapping, list, footnote, and HTML table state structsclassDiagram
class ParagraphWriter {
- out : &mut Vec~String~
- width : usize
- buf : Vec~(String, bool)~
- indent : String
+ new(out : &mut Vec~String~, width : usize) ParagraphWriter
+ note_indent(line : &str) void
+ push_wrapped(text : String, hard_break : bool) void
+ flush_paragraph() void
+ push_verbatim(line : &str) void
+ push_blank_line() void
+ handle_prefix_line(prefix_line : &PrefixLine) void
- push_wrapped_segment(indent : &str, segment : &str) void
}
class PrefixLine {
+ prefix : String
+ rest : &str
+ repeat_prefix : bool
}
class SplitContext {
+ lines : &mut Vec~String~
+ width : usize
+ new(lines : &mut Vec~String~, width : usize) SplitContext
}
class HtmlTableState {
+ buf : Vec~String~
+ depth : usize
+ in_html() bool
+ flush_raw(out : &mut Vec~String~) void
+ push_html_line(line : &str, out : &mut Vec~String~) void
}
class ListState {
+ indent_stack : Vec~usize~
+ counters : HashMap~usize, usize~
+ reset() void
+ prune_deeper(indent : usize, inclusive : bool) void
+ next_number(indent : usize) usize
+ handle_paragraph_restart(indent : usize, line : &str, prev_blank : bool) bool
}
class DefinitionScanState {
+ mapping : &mut HashMap~usize, usize~
+ next_number : &mut usize
+ numeric_list_range : Option~(usize, usize)~
+ skip_numeric_conversion : bool
+ definitions : Vec~DefinitionLine~
+ is_definition_line : Vec~bool~
+ numeric_candidates : Vec~NumericCandidate~
}
class FenceTracker {
+ observe(line : &str) bool
+ in_fence() bool
}
ParagraphWriter --> PrefixLine : handles
ParagraphWriter --> SplitContext : uses via wrap_preserving_code
ParagraphWriter --> FenceTracker : used in wrap_text
HtmlTableState ..> table_lines_to_markdown : calls
ListState ..> FenceTracker : used in renumber_lists
DefinitionScanState ..> DefinitionLine : owns
DefinitionScanState ..> NumericCandidate : owns
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/footnotes/renumber.rs (1)
337-344:⚠️ Potential issue | 🟠 MajorRemove the panic path in
numeric_candidate_from_line.Parse from
num_match.as_str()directly. Line 339 still indexescaps["num"], which panics when the named group is absent and defeats theOption-based fallback.🔧 Proposed fix
fn numeric_candidate_from_line(line: &str, index: usize) -> Option<NumericCandidate> { let caps = FOOTNOTE_LINE_RE.captures(line)?; - let number = caps["num"].parse::<usize>().ok()?; + let num_match = caps.name("num")?; + let number = num_match.as_str().parse::<usize>().ok()?; let indent = caps.name("indent").map_or("", |m| m.as_str()).to_string(); - let rest = caps.name("rest").map_or("", |m| m.as_str()).to_string(); - let num_match = caps.name("num")?; - let rest_match = caps.name("rest")?; + let rest_match = caps.name("rest")?; + let rest = rest_match.as_str().to_string(); let whitespace = line[num_match.end() + 1..rest_match.start()].to_string(); Some(NumericCandidate { index, number, indent,As per coding guidelines: ".expect() and .unwrap() are forbidden outside of tests. Errors must be propagated."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/footnotes/renumber.rs` around lines 337 - 344, The function numeric_candidate_from_line currently uses caps["num"] which can panic if the named capture is absent; instead use the already-obtained num_match (from caps.name("num")) and parse num_match.as_str() to get the usize (e.g., replace the caps["num"].parse::<usize>() call with parsing num_match.as_str()), keeping the .ok()? propagation so the function returns None on parse failure; also remove any other direct indexing into caps[...] that can panic and rely on the existing num_match/rest_match variables and safe slicing using their start()/end() positions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/footnotes/renumber.rs`:
- Around line 328-329: The code currently discards the Result from write! when
building the definition header (e.g., the line using write!(&mut line,
"[^{new_number}]:") before pushing rewritten_rest), creating a silent failure
path; replace those write! calls (both occurrences around the build of the
header) with infallible string assembly such as let header =
format!("[^{new_number}]:"); line.push_str(&header); (or build the header with
String::from and push_str) so you don't ignore errors and avoid using a fallible
fmt write into the mutable string; apply the same replacement for the second
occurrence near lines 401–402.
In `@src/wrap/tests.rs`:
- Around line 309-314: The test wrap_text_uses_display_width_for_unicode_indent
is too weak: it uses " a" with width 2 which doesn't fail even if indent width
is computed incorrectly; update the test to exercise display-width by using an
input like " a b" and call wrap_text(&input, 4) so the ideographic space (width
2) causes a wrap, and assert that the result equals vec![" a".to_string(),
" b".to_string()]—modify the test body in
wrap_text_uses_display_width_for_unicode_indent to use that input, width, and
expected assertion.
- Around line 302-314: The new regression tests
wrap_text_normalizes_whitespace_only_lines and
wrap_text_uses_display_width_for_unicode_indent should be moved out of the
already-large src/wrap/tests.rs into a dedicated test module file to keep files
under the 400-line limit; create a new test file (for example
tests/wrap_regressions.rs or src/wrap/regressions_tests.rs), copy those two
#[test] functions (which call wrap_text) into it, preserve any necessary
use/imports for wrap_text, and remove them from src/wrap/tests.rs so the
original file stays below the line limit.
---
Outside diff comments:
In `@src/footnotes/renumber.rs`:
- Around line 337-344: The function numeric_candidate_from_line currently uses
caps["num"] which can panic if the named capture is absent; instead use the
already-obtained num_match (from caps.name("num")) and parse num_match.as_str()
to get the usize (e.g., replace the caps["num"].parse::<usize>() call with
parsing num_match.as_str()), keeping the .ok()? propagation so the function
returns None on parse failure; also remove any other direct indexing into
caps[...] that can panic and rely on the existing num_match/rest_match variables
and safe slicing using their start()/end() positions.
🪄 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: d67b626d-6713-4149-8d79-2492c7423851
📒 Files selected for processing (12)
Cargo.tomlsrc/code_emphasis.rssrc/footnotes/renumber.rssrc/html.rssrc/lists.rssrc/wrap.rssrc/wrap/fence.rssrc/wrap/inline.rssrc/wrap/line_buffer.rssrc/wrap/paragraph.rssrc/wrap/tests.rstests/table/convert_html.rs
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
src/wrap/tests.rs (2)
302-324: 🛠️ Refactor suggestion | 🟠 MajorMove these regressions into a dedicated test module.
Lines 302-324 keep
src/wrap/tests.rsat 489 lines, so this PR still breaches the repository cap. Move the new wrapping regressions out of this module and keep the file below the limit.As per coding guidelines, "Files must not exceed 400 lines in length".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/wrap/tests.rs` around lines 302 - 324, The three new regression tests (wrap_text_normalizes_whitespace_only_lines, wrap_text_treats_whitespace_only_lines_as_paragraph_breaks, wrap_text_uses_display_width_for_unicode_indent) should be moved out of the oversized tests.rs into a dedicated test module/file (e.g., a new module named wrap_regressions or regressions) so the original file stays under the 400-line limit; extract those #[test] functions into the new module, ensure the new file/module is compiled as part of the test suite (keeping the same function names and signatures and any necessary use/imports such as wrap_text), and remove the original copies from the large tests.rs.
320-324:⚠️ Potential issue | 🟡 MinorStrengthen the Unicode-width regression.
Lines 320-324 still pass when the ideographic space is mismeasured as one column, so the test does not prove the fix. Use an input that only wraps when that indent consumes two columns, such as
" a b"at width4, and assert the split output.Patch
fn wrap_text_uses_display_width_for_unicode_indent() { - let input = vec![" a".to_string()]; - let wrapped = wrap_text(&input, 2); - assert_eq!(wrapped, vec![" a".to_string()]); + let input = vec![" a b".to_string()]; + let wrapped = wrap_text(&input, 4); + assert_eq!(wrapped, vec![" a".to_string(), " b".to_string()]); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/wrap/tests.rs` around lines 320 - 324, The test wrap_text_uses_display_width_for_unicode_indent currently uses " a" which still passes if the ideographic space is mismeasured; change it to exercise the wrap threshold by using input " a b" and width 4 so the indent (ideographic space = 2 columns) forces a wrap; update the test (function wrap_text_uses_display_width_for_unicode_indent) to call wrap_text(&vec![" a b".to_string()], 4) and assert the expected split output (e.g. assert_eq!(wrapped, vec![" a".to_string(), "b".to_string()])).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/footnotes/renumber.rs`:
- Around line 490-528: This file is over the 400-line limit because the
#[cfg(test)] mod tests block is large; move the entire test module into a new
test file (either src/footnotes/renumber/tests.rs or
tests/footnotes_renumber.rs) preserving the imported functions
numeric_candidate_from_line and renumber_footnotes, and update module imports
accordingly; also replace the duplicated assertions in the
malformed_numeric_candidate_line_is_ignored test with a parameterised rstest
(use #[rstest] with two cases like "7." and "7:") to consolidate into a single
parameterised test function while keeping the existing test names for clarity.
In `@tests/table/convert_html.rs`:
- Around line 81-115: Collapse the two nearly-identical tests into a single
parameterised rstest: remove the functions
converts_indented_multiline_html_table and
converts_indented_table_without_touching_surrounding_content and replace them
with one #[rstest(...)] that supplies the two cases and a single test function
(e.g. converts_indented_html_table_cases) which takes input: Vec<String>,
expected: Vec<String> and asserts assert_eq!(convert_html_tables(&input),
expected); ensure the rstest attribute lists both case::... entries and the test
helper convert_html_tables is used unchanged.
---
Duplicate comments:
In `@src/wrap/tests.rs`:
- Around line 302-324: The three new regression tests
(wrap_text_normalizes_whitespace_only_lines,
wrap_text_treats_whitespace_only_lines_as_paragraph_breaks,
wrap_text_uses_display_width_for_unicode_indent) should be moved out of the
oversized tests.rs into a dedicated test module/file (e.g., a new module named
wrap_regressions or regressions) so the original file stays under the 400-line
limit; extract those #[test] functions into the new module, ensure the new
file/module is compiled as part of the test suite (keeping the same function
names and signatures and any necessary use/imports such as wrap_text), and
remove the original copies from the large tests.rs.
- Around line 320-324: The test wrap_text_uses_display_width_for_unicode_indent
currently uses " a" which still passes if the ideographic space is mismeasured;
change it to exercise the wrap threshold by using input " a b" and width 4 so
the indent (ideographic space = 2 columns) forces a wrap; update the test
(function wrap_text_uses_display_width_for_unicode_indent) to call
wrap_text(&vec![" a b".to_string()], 4) and assert the expected split output
(e.g. assert_eq!(wrapped, vec![" a".to_string(), "b".to_string()])).
🪄 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: 4e0b8687-eb63-4e39-946c-a8b476a89d3d
📒 Files selected for processing (6)
src/footnotes/renumber.rssrc/html.rssrc/wrap.rssrc/wrap/paragraph.rssrc/wrap/tests.rstests/table/convert_html.rs
|
@coderabbitai Have the following now been resolved? Annul any requirements that violate the en-GB-oxendict spelling (-ize / -yse / -our) conventions (for example a request to replace "normalize" with "normalise" or "artefact" with "artifact"), or where the requirement unnecessarily increases cyclomatic complexity. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 12108 🏁 Script executed: Length of output: 7747
Overall Comments
Individual Comments
|
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 `@src/footnotes/renumber/definitions.rs`:
- Line 100: Replace the odd double-super path by re-exporting or importing
DefinitionParts from the immediate parent: in renumber.rs add a re-export/import
for parsing::DefinitionParts (e.g., make DefinitionParts available as
super::parsing::DefinitionParts) and then update the type in definitions.rs to
use the simpler super::parsing::DefinitionParts<'_> (replace
super::super::parsing::DefinitionParts<'_> occurrences). This keeps the module
path clear and locates the change around the DefinitionParts type usage in
definitions.rs and the renumber.rs parent module.
In `@src/footnotes/renumber/tests.rs`:
- Around line 13-18: The test malformed_numeric_candidate_line_is_ignored uses
assert! without a diagnostic message; update the assertion to include a clear
failure message that shows the input, e.g. change the assertion around
numeric_candidate_from_line(line, 0).is_none() to include a message like
"expected None for malformed numeric candidate line: {line}" so failures surface
the offending case.
🪄 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: 3caf340c-8cb1-447f-8018-395c17e6be97
📒 Files selected for processing (4)
src/footnotes/renumber.rssrc/footnotes/renumber/definitions.rssrc/footnotes/renumber/tests.rstests/table/convert_html.rs
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/footnotes/renumber.rs (1)
70-87:⚠️ Potential issue | 🟠 MajorReplace
expectwith fallible handling in production code.Line 73 uses
expectin production code, which violates the guideline forbidding.expect()outside tests. Return early when the capture is missing instead of panicking.🔧 Proposed fix
fn rewrite_refs_in_segment(text: &str, mapping: &HashMap<usize, usize>) -> String { FOOTNOTE_REF_RE .replace_all(text, |caps: &Captures| { - let mat = caps.get(0).expect("regex matched without capture"); + let Some(mat) = caps.get(0) else { + return caps[0].to_string(); + }; if is_definition_like(text, &mat) { return caps[0].to_string(); }As per coding guidelines: "
.expect()and.unwrap()are forbidden outside of tests. Errors must be propagated."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/footnotes/renumber.rs` around lines 70 - 87, The closure in rewrite_refs_in_segment currently calls caps.get(0).expect(...), which can panic; replace that with fallible handling: match or if-let on caps.get(0) (e.g., if let Some(mat) = caps.get(0) { ... } else { ... }), and in the None branch return an appropriate safe fallback (the original matched text or String::new()) instead of panicking; keep the rest of the logic (calling is_definition_like(text, &mat), parsing caps["num"], and using mapping) unchanged so the closure never uses .expect() or .unwrap().
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@src/footnotes/renumber.rs`:
- Around line 70-87: The closure in rewrite_refs_in_segment currently calls
caps.get(0).expect(...), which can panic; replace that with fallible handling:
match or if-let on caps.get(0) (e.g., if let Some(mat) = caps.get(0) { ... }
else { ... }), and in the None branch return an appropriate safe fallback (the
original matched text or String::new()) instead of panicking; keep the rest of
the logic (calling is_definition_like(text, &mat), parsing caps["num"], and
using mapping) unchanged so the closure never uses .expect() or .unwrap().
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 63e834dd-352d-4c55-b0ab-ef615c11d4b0
📒 Files selected for processing (2)
src/footnotes/renumber.rssrc/footnotes/renumber/definitions.rs
|
@coderabbitai pause |
✅ Actions performedReviews paused. |
766c589 to
7d4a095
Compare
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@CHANGELOG.md`:
- Around line 12-13: Update the CHANGELOG entry that currently reads "Normalise
whitespace-only artefacts during wrapping by rebalancing atomic tails." to use
en-GB-oxendict spelling by replacing "Normalise" with "Normalize" so the line
becomes "Normalize whitespace-only artefacts during wrapping by rebalancing
atomic tails."; keep the rest of the entry unchanged and add the triage tags
`[type:spelling]` `[type:docstyle]` if not already present.
In `@src/footnotes/renumber.rs`:
- Around line 8-10: Add module-level documentation for the new module boundary
by adding a leading `//!` comment above `mod parsing` that succinctly explains
the module's purpose and how its re-export of `DefinitionParts` is intended to
be used; also add a Rustdoc `///` comment on the `renumber_footnotes` function
that documents its public API: state that it mutates its input in-place,
describe the exact renumbering rules it applies (e.g., how it maps original
footnote identifiers to new sequential numbers, what it does with references and
definitions, and any invariants preserved), and note any side-effects or
preconditions/postconditions for callers so cargo doc will surface this
behavior.
In `@src/footnotes/renumber/definitions.rs`:
- Around line 19-37: Add Rustdoc comments for the module-visible types and their
fields to document their contracts and mutation semantics: annotate
DefinitionLine, NumericCandidate, and DefinitionUpdates (and their public fields
like index, new_number, line, indent, whitespace, rest, definitions,
is_definition_line) with /// comments describing what each struct represents,
which fields are mutated or read-only after construction, expected
units/constraints (e.g. zero-based index, new_number meaning), and what outputs
or invariants callers can rely on; apply the same documentation pattern to the
other affected regions (lines referenced 118-133 and 198-235) so all pub(super)
APIs in this submodule have concise Rustdoc describing purpose, mutation
behaviour, and visible outputs.
- Around line 315-460: Remove the inline #[cfg(test)] mod tests { ... } block
from definitions.rs and instead add a new test module file named tests.rs
alongside definitions.rs that contains the same test code (keeping the
#[cfg(test)] and use super::{DefinitionLine, assign_new_number,
collect_definition_updates, definition_segment_end, reorder_definition_block,
rewrite_definition_headers, should_convert_numeric_line} line). In the original
definitions.rs replace the removed block with a single declaration #[cfg(test)]
mod tests; so the compiler will include the external tests.rs; ensure the new
tests.rs uses super::* imports as needed and keeps all test functions and helper
fn strings unchanged.
In `@src/wrap/paragraph.rs`:
- Around line 205-216: The test
handle_prefix_line_can_repeat_or_change_the_continuation_prefix only covers the
non-repeating (space-aligned) path; add a second assertion exercising
repeat_prefix = true so blockquote-style continuations are validated. Update the
test body that constructs ParagraphWriter::new and calls handle_prefix_line with
a PrefixLine where prefix is a blockquote-like value (e.g., starting with "> ")
and set repeat_prefix: true, then assert that out contains the wrapped lines
that repeat the prefix on continuation (matching the expected vector for
repeated-prefix wrapping). Ensure you reference the same test function name and
PrefixLine fields (prefix, rest, repeat_prefix) and keep the existing
non-repeating assertion intact.
In `@tests/wrap_unit.rs`:
- Around line 62-88: Add a content-preservation assertion after calling
wrap_text: verify that replacing the inserted line breaks with spaces
reconstructs the original input by asserting wrapped.join(" ") == input[0]; this
uses the existing wrap_text function and the wrapped/local input variables to
ensure no characters are dropped or rewritten during wrapping.
🪄 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: 6c6c762b-6000-428e-ae49-eb3e3b9114f6
📒 Files selected for processing (15)
CHANGELOG.mdCargo.tomldocs/architecture.mdsrc/code_emphasis.rssrc/footnotes/renumber.rssrc/footnotes/renumber/definitions.rssrc/footnotes/renumber/tests.rssrc/html.rssrc/lists.rssrc/wrap.rssrc/wrap/fence.rssrc/wrap/paragraph.rssrc/wrap/tests.rstests/table/convert_html.rstests/wrap_unit.rs
1b0ce55 to
f7b07ed
Compare
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
CHANGELOG: add three Fixed entries for PR #266 (Unicode display-width indentation, indented multi-line HTML table conversion, and the cargo-binstall Linux `bin-dir` correction). renumber.rs: document the `definitions` submodule boundary so cargo doc explains why the parsing and reordering machinery is delegated. definitions.rs: replace the inaccurate "in scan order" doc on `DefinitionUpdates::definitions` with the actual ordering (explicit definitions in scan order; promoted numeric candidates in reverse scan order). renumber/tests.rs: collapse the two `renumber_footnotes_rewrites_*` `#[test]` functions into a single parameterised `#[rstest]`, and add a `proptest` module that verifies sequential numbering, reference consistency, and fenced-region preservation across generated inputs. lists.rs: add unit tests for `ListState::reset` and the indent-pruning behaviour of `ListState::next_number`. tests/table/convert_html.rs: add a regression test that a nested `<table>` inside an outer `<table>` does not flush prematurely and is converted as one contiguous block. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
echo "=== CHANGELOG.md [Unreleased] section ==="
awk '/^## \[Unreleased\]/{p=1} p && /^## \[/ && !/Unreleased/{p=0} p' CHANGELOG.md
echo ""
echo "=== mod definitions doc comment in renumber.rs ==="
sed -n '1,15p' src/footnotes/renumber.rs
echo ""
echo "=== DefinitionUpdates struct doc in definitions.rs ==="
grep -n -B5 -A10 "struct DefinitionUpdates" src/footnotes/renumber/definitions.rs
echo ""
echo "=== renumber/tests.rs full content ==="
cat src/footnotes/renumber/tests.rs 2>/dev/null || echo "NOT FOUND"
echo ""
echo "=== proptest usage in tests ==="
rg -n "proptest" src/ tests/ --include="*.rs" | head -30
echo ""
echo "=== ListState tests in lists.rs ==="
grep -n -A5 "#\[cfg(test\|#\[test\]\|mod tests" src/lists.rs | head -40
echo ""
echo "=== tests/table/convert_html.rs full content ==="
cat tests/table/convert_html.rs
echo ""
echo "=== Cargo.toml dev-dependencies ==="
grep -n -A2 "\[dev-dependencies\]" Cargo.toml | head -20
echo ""
echo "=== open GitHub issues ==="
gh issue list --repo leynos/mdtablefix --state open --limit 30Length of output: 17127
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@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. Do not treat warnings as optional or aspirational. Where a change is out of scope for this PR, propose a GitHub issue unless one exists already. ❌ Failed checks (3 errors, 5 warnings)
|
Add the missing changelog note for wrapping whitespace-only artefact normalisation and atomic-tail rebalancing. Expand the architecture document with concise responsibility notes for `ParagraphWriter`, `HtmlTableState`, `DefinitionScanState`, and `ListState` so the module-level overview reflects the current design without listing private fields.
Exercise representative definition-scan, paragraph-writer, and prefix-line behaviour directly so the refactored helper boundaries are covered without widening private APIs.
Treat whitespace-only input lines as paragraph breaks and emit them as empty strings so downstream consumers see a uniform separator. This was part of the original review-feedback intent on this branch but was lost during the rebase onto main's evolved `wrap_text` flow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Apply Oxford spelling to the wrap CHANGELOG entry, document the `renumber_footnotes` API and the `parsing` re-export shim, and add rustdoc for the `pub(super)` types and functions in `renumber::definitions` so cargo doc surfaces their contracts. Extract the inline `mod tests` block from `definitions.rs` into a sibling `definitions/tests.rs` so the implementation file stays focused. Strengthen `handle_prefix_line_can_repeat_or_change_the_continuation_prefix` with a `repeat_prefix = true` case, and add a join-roundtrip assertion to `wrap_text_preserves_hyphenated_words` so accidental character loss is caught directly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CHANGELOG: add three Fixed entries for PR #266 (Unicode display-width indentation, indented multi-line HTML table conversion, and the cargo-binstall Linux `bin-dir` correction). renumber.rs: document the `definitions` submodule boundary so cargo doc explains why the parsing and reordering machinery is delegated. definitions.rs: replace the inaccurate "in scan order" doc on `DefinitionUpdates::definitions` with the actual ordering (explicit definitions in scan order; promoted numeric candidates in reverse scan order). renumber/tests.rs: collapse the two `renumber_footnotes_rewrites_*` `#[test]` functions into a single parameterised `#[rstest]`, and add a `proptest` module that verifies sequential numbering, reference consistency, and fenced-region preservation across generated inputs. lists.rs: add unit tests for `ListState::reset` and the indent-pruning behaviour of `ListState::next_number`. tests/table/convert_html.rs: add a regression test that a nested `<table>` inside an outer `<table>` does not flush prematurely and is converted as one contiguous block. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
wrap.rs: normalise whitespace-only lines in `handle_pending_continuation` so the pending-prefix path matches the main `wrap_text` loop and never re-emits original whitespace content. footnotes/renumber/definitions.rs: emit a `tracing::warn!` when `reorder_definition_block` skips because the segment count diverges from the block width, and harden `numeric_candidate_from_line` against panics by range-checking the regex-derived slice indices before the byte slice. docs/users-guide.md: document the whitespace-only normalisation, Unicode display-width indentation handling, and indented HTML table conversion under Paragraph wrapping and a new HTML table conversion section. docs/developers-guide.md: add a Stateful pipeline helpers section describing `HtmlTableState`, `DefinitionScanState`, and `ListState`. lists.rs, html.rs: add proptest properties for `ListState::next_number` (newly seen or re-emerged indents always return 1) and `HtmlTableState::push_html_line` (`in_html()` agrees with `depth > 0` after every push, so `saturating_sub` and the flush gate stay coherent). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
definitions.rs: spell "finalized" with the Oxford -ize ending so the comment matches both the en-GB-oxendict convention used elsewhere in the project and the existing `finalize_numeric_candidates` function name. tests/wrap_unit.rs: split the 430-line integration test into focused submodules under `tests/wrap_unit/` so each file sits within the 400-line repository limit. The entry point now wires the `code_spans`, `prefixed`, `footnotes`, `shell_blocks`, and `stream` submodules with `#[path]`. Each submodule carries its own imports; the `assert_footnote_reference_is_intact` helper moves into the footnotes submodule (its sole caller). Insta snapshot files keep their reviewed content; they are renamed without the `wrap_unit__` prefix to match the path insta now picks for the relocated tests, with `prepend_module_to_snapshot = false` pointing them back to `tests/snapshots/`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Parameterize duplicated wrap regression tests, strengthen lossless wrapping assertions, and split definition-block reordering into smaller helper functions while preserving the existing writeback behaviour.
Update the `reorder_definition_block` Rustdoc so it matches the warning emitted when row-count mismatches cause reordering to be skipped.
Add module-level documentation to the HTML and list test modules so module docs remain complete for nested property-test coverage. Emit tracing events for whitespace normalisation, HTML table conversion, ordered-list state resets, and unsupported wrapping prefixes so these behavioural decisions are visible during diagnostics.
Move HTML and inline postprocess tests into test-only child modules so the production source files stay below the repository line limit while retaining access to private helpers. Lower the HTML table conversion event from `warn!` to `debug!` because normal conversions should not be reported as warnings.
Make HTML table start-tag counting match end-tag counting so nested or compact table markup adjusts parser depth consistently. Keep `convert_html_tables` documentation contiguous before `#[must_use]`, and collapse unchanged rebalance cases into one parameterised rstest.
Tighten the `convert_html_tables` Rustdoc so fenced-code behaviour is described once while preserving the existing examples and attribute placement.
Require HTML table conversion to enter a block only when `<table>` starts the trimmed Markdown line, so inline mentions are preserved as ordinary text. Keep a separate unanchored table-tag regex for depth counting once a table block is already active.
4f6baa1 to
650d4e8
Compare
Remove extra blank lines in the developers and users guides, and restore the required blank line before the test infrastructure heading.
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/footnotes/renumber/definitions.rs (1)
1-450:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftDecompose file to comply with 400-line limit.
This file contains 450 lines, exceeding the repository's 400-line maximum. Extract helper functions or split the implementation into focused submodules.
Potential decomposition strategies:
- Extract segment-building helpers (lines 287-364) into a
segmentssubmodule- Extract scan state and collection logic (lines 74-274) into a
scanningsubmodule- Move numeric candidate handling (lines 153-239) into a
candidatessubmoduleAs per coding guidelines, "Files must not exceed 400 lines in length".
♻️ Duplicate comments (2)
tests/wrap_unit/stream.rs (1)
41-48:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAssert opener coupling on every output line.
Update Line 42–47 to validate all lines, not only lines containing backticks. Prevent a false pass when the opener is stranded on a backtick-free line.
Proposed fix
- for line in &output { - if line.contains('`') { - assert!( - !line.ends_with(opener), - "opening bracket must stay with inline code on line: {line:?}" - ); - } - } + assert!( + output.iter().all(|line| !line.ends_with(opener)), + "opening bracket must stay with inline code: {output:?}" + );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/wrap_unit/stream.rs` around lines 41 - 48, The current loop in the tests/wrap_unit/stream.rs that iterates "for line in &output" only performs the "assert!(!line.ends_with(opener), ...)" when the line contains '`', which allows a stranded opener on a backtick-free line to slip through; remove the conditional "if line.contains('`')" so the assert executes for every line in the "for line in &output" loop (keeping the same assertion message) to ensure opener coupling is validated on all output lines.src/footnotes/renumber/tests.rs (1)
16-18:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winSurface the offending line in the assertion.
This assertion still fails without naming the input despite the earlier request to add a diagnostic message.
📝 Proposed enhancement
fn malformed_numeric_candidate_line_is_ignored(#[case] line: &str) { - assert!(numeric_candidate_from_line(line, 0).is_none()); + assert!( + numeric_candidate_from_line(line, 0).is_none(), + "expected None for malformed numeric candidate line: {line}" + ); }As per coding guidelines: "In Rust tests, prefer
.expect(...)over.unwrap()to surface clearer failure diagnostics."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/footnotes/renumber/tests.rs` around lines 16 - 18, The test malformed_numeric_candidate_line_is_ignored should include the input on failure so diagnostics show the offending line; change the assertion to include a message with the `line` value (e.g. use assert!(numeric_candidate_from_line(line, 0).is_none(), "offending line: {:?}", line) or assert_eq!(None, numeric_candidate_from_line(line, 0), "offending line: {:?}", line)) so failures print the problematic input; locate this in the malformed_numeric_candidate_line_is_ignored test and update the assert accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/architecture.md`:
- Line 390: Edit the sentence "Its depth counter tracks nested `<table>` blocks
so only the outermost table is converted at once" and insert a comma before "so"
so it reads: "Its depth counter tracks nested `<table>` blocks, so only the
outermost table is converted at once"; locate this exact fragment (mentioning
"depth counter" and `<table>`) in docs/architecture.md and update the
punctuation accordingly.
In `@docs/developers-guide.md`:
- Line 599: The sentence fragment "which drains the buffer in reverse so the
assigned numbers reflect" needs a comma before "so" to separate the independent
clauses; update the text (the phrase containing "which drains the buffer in
reverse so the assigned numbers reflect") to read "which drains the buffer in
reverse, so the assigned numbers reflect".
- Line 598: Replace the British spelling "finalised" with the
en-GB-oxendict-compliant "finalized" to match the existing function name
finalize_numeric_candidates and the project's spelling guidelines; update the
occurrence in the docs (the phrase "finalised at the end via
`finalize_numeric_candidates`") so the word and the referenced function name use
the same "-ize" form for consistency.
- Line 573: The sentence fragment "Each owns one slice of pipeline behaviour so
the surrounding" needs a comma before "so" to separate the two independent
clauses; update the sentence in docs/developers-guide.md (the line containing
"Each owns one slice of pipeline behaviour so the surrounding") to read "Each
owns one slice of pipeline behaviour, so the surrounding" ensuring punctuation
is corrected.
- Line 609: Edit the sentence fragment "next sequential number for that level —
incrementing the counter so the next" in docs/developers-guide.md and insert a
comma before "so" so it reads "...incrementing the counter, so the next" to
separate the independent clauses properly.
In `@src/footnotes/renumber/tests.rs`:
- Around line 37-41: Add a module-level doc comment at the top of the
proptest_tests module: insert a //! docstring immediately above "mod
proptest_tests" that succinctly explains the module's purpose (property tests
for renumbering footnotes using proptest and Regex) and how it is used,
mirroring the style of the sibling proptest_tests in src/lists.rs; ensure it
precedes the use/imports and the module declaration so the comment is
module-level.
---
Duplicate comments:
In `@src/footnotes/renumber/tests.rs`:
- Around line 16-18: The test malformed_numeric_candidate_line_is_ignored should
include the input on failure so diagnostics show the offending line; change the
assertion to include a message with the `line` value (e.g. use
assert!(numeric_candidate_from_line(line, 0).is_none(), "offending line: {:?}",
line) or assert_eq!(None, numeric_candidate_from_line(line, 0), "offending line:
{:?}", line)) so failures print the problematic input; locate this in the
malformed_numeric_candidate_line_is_ignored test and update the assert
accordingly.
In `@tests/wrap_unit/stream.rs`:
- Around line 41-48: The current loop in the tests/wrap_unit/stream.rs that
iterates "for line in &output" only performs the
"assert!(!line.ends_with(opener), ...)" when the line contains '`', which allows
a stranded opener on a backtick-free line to slip through; remove the
conditional "if line.contains('`')" so the assert executes for every line in the
"for line in &output" loop (keeping the same assertion message) to ensure opener
coupling is validated on all output lines.
🪄 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: f507f378-a5f9-4cee-93c7-d39a073395cf
⛔ Files ignored due to path filters (3)
tests/snapshots/inline_footnote_reference_after_code_wrap.snapis excluded by!**/*.snaptests/snapshots/inline_footnote_reference_after_opener_coupled_code_wrap.snapis excluded by!**/*.snaptests/snapshots/inline_footnote_reference_wrap.snapis excluded by!**/*.snap
📒 Files selected for processing (25)
CHANGELOG.mdCargo.tomldocs/architecture.mddocs/developers-guide.mddocs/users-guide.mdsrc/code_emphasis.rssrc/footnotes/renumber.rssrc/footnotes/renumber/definitions.rssrc/footnotes/renumber/definitions/tests.rssrc/footnotes/renumber/tests.rssrc/html.rssrc/html_tests.rssrc/lists.rssrc/wrap.rssrc/wrap/inline/postprocess.rssrc/wrap/inline/postprocess_tests.rssrc/wrap/paragraph.rssrc/wrap/tests/prefix.rstests/table/convert_html.rstests/wrap_unit.rstests/wrap_unit/code_spans.rstests/wrap_unit/footnotes.rstests/wrap_unit/prefixed.rstests/wrap_unit/shell_blocks.rstests/wrap_unit/stream.rs
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Fix punctuation and Oxford spelling in the architecture and developer docs. Improve footnote renumbering test diagnostics and document the property-test module while broadening stream opener assertions to every output line.
Add property coverage for paragraph wrapping prefixes, definition block ordering, list pruning, and HTML table buffering. Emit trace and debug events for numeric candidate skip decisions, definition-block reorder exits, and HTML table buffer depth transitions.
Centralize mutable state in the list, HTML-table, footnote, and paragraph-wrapping flows so the behaviour is easier to reason about from one place.
Fix the cargo-binstall Linux override, remove production
expectusage from the reviewed paths, normalize whitespace-only wrapped lines, and add regression tests for mixed code-emphasis affixes, Unicode-width indentation, and indented multi-line HTML tables.Summary by Sourcery
Centralize mutable state across paragraph wrapping, footnote renumbering, list renumbering, and HTML table conversion to simplify control flow and improve robustness.
Bug Fixes:
Enhancements:
Build:
Tests: