Skip to content

Add --renumber option to mdtablefix#54

Merged
leynos merged 1 commit intomainfrom
codex/add-renumber-commandline-option
Jul 13, 2025
Merged

Add --renumber option to mdtablefix#54
leynos merged 1 commit intomainfrom
codex/add-renumber-commandline-option

Conversation

@leynos
Copy link
Copy Markdown
Owner

@leynos leynos commented Jul 13, 2025

Summary

  • add --renumber flag to CLI
  • implement renumber_lists helper
  • test renumbering both via library and CLI
  • document the new option
  • add extra tests for nested and multi-paragraph lists

Testing

  • cargo +nightly-2025-06-10 fmt --all
  • cargo +nightly-2025-06-10 clippy -- -D warnings
  • RUSTFLAGS="-D warnings" cargo +nightly-2025-06-10 test
  • markdownlint README.md docs/html-table-support.md docs/release-process.md docs/rust-testing-with-rstest-fixtures.md src/**/*.rs tests/**/*.rs
  • nixie README.md docs/html-table-support.md docs/release-process.md docs/rust-testing-with-rstest-fixtures.md

https://chatgpt.com/codex/tasks/task_e_68737ddcc5748322a24a6922938f2116

Summary by Sourcery

Introduce ordered list renumbering capability via a new --renumber flag, backed by a renumber_lists helper, with updated command processing, tests, and documentation.

New Features:

  • Add --renumber CLI option to sequentially renumber ordered Markdown lists
  • Implement renumber_lists helper to renumber list items by indentation level across code fences

Enhancements:

  • Extend process_lines and rewrite_path to apply renumbering when the flag is used

Documentation:

  • Update README to document the new --renumber option

Tests:

  • Add integration tests for basic renumbering, fenced code blocks, nested lists, multi-paragraph items
  • Add CLI test to verify --renumber flag functionality

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Jul 13, 2025

Reviewer's Guide

Introduces a new --renumber option that sequentially renumbers ordered Markdown lists via a helper function, integrates it into the CLI pipeline and test suite, and documents the feature in README.

Class diagram for new renumber_lists helper and CLI integration

classDiagram
    class Cli {
        +bool wrap
        +bool renumber
        +Vec<PathBuf> files
    }
    class Main {
        +main()
        +process_lines(lines, wrap, renumber)
        +rewrite_path(path, wrap, renumber)
    }
    class Lib {
        +renumber_lists(lines: &[String]) -> Vec<String>
        +process_stream(lines: &[String]) -> Vec<String>
        +process_stream_no_wrap(lines: &[String]) -> Vec<String>
    }
    Cli <.. Main : used by
    Main ..> Lib : calls
    Lib : +renumber_lists
    Lib : +process_stream
    Lib : +process_stream_no_wrap
Loading

File-Level Changes

Change Details Files
Add renumber_lists helper for sequential list numbering
  • Define NUMBERED_RE regex to match numbered list items with indentation
  • Implement renumber_lists with counters stack handling indentation and fenced code blocks
  • Ensure existing logic skips fenced code and resets counters based on indent
src/lib.rs
Integrate --renumber flag into CLI processing
  • Add renumber field to Cli struct
  • Extend process_lines and rewrite_path to accept renumber parameter
  • Conditionally invoke renumber_lists post-wrap in both main and file rewrite paths
src/main.rs
Document new renumber option in usage guide
  • Add --renumber to command usage syntax
  • Include bullet describing ordered list renumbering capability
README.md
Cover renumber functionality with integration tests
  • Add basic, fenced code, nested, and multi-paragraph list tests for renumber_lists
  • Add CLI invocation test to verify --renumber behavior
tests/integration.rs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jul 13, 2025

Summary by CodeRabbit

  • New Features

    • Added a new command-line option to automatically renumber ordered lists in markdown files, ensuring sequential numbering within each indentation level.
  • Documentation

    • Updated usage instructions to describe the new renumbering option.
  • Tests

    • Introduced integration tests to verify correct renumbering behaviour, including support for nested lists, fenced code blocks, and multi-paragraph items.

Walkthrough

Update the CLI and documentation to introduce a --renumber flag for sequentially rewriting ordered lists in markdown files. Implement the renumber_lists function to handle renumbering logic, including support for nested lists and fenced code blocks. Add comprehensive integration tests to validate the new feature and its behaviour across various scenarios.

Changes

File(s) Change Summary
README.md Document the new --renumber CLI option and update usage instructions.
src/lib.rs Add the renumber_lists function and supporting regex for ordered list renumbering, handling nesting and code fences.
src/main.rs Extend CLI with --renumber, update processing logic to invoke renumber_lists, and propagate the flag throughout the workflow.
tests/integration.rs Add integration tests for renumber_lists, covering basic, nested, fenced code, CLI, and multi-paragraph list scenarios.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI
    participant Processor
    participant Renumberer

    User->>CLI: Run mdtablefix [--renumber] [file]
    CLI->>Processor: process_lines(lines, wrap, renumber)
    alt renumber is true
        Processor->>Renumberer: renumber_lists(lines)
        Renumberer-->>Processor: renumbered_lines
        Processor-->>CLI: processed_lines
    else renumber is false
        Processor-->>CLI: processed_lines (unchanged)
    end
    CLI->>User: Output or rewrite file
Loading

Poem

In markdown lands where numbers stray,
A flag emerges: renumber, hooray!
Lists now march in ordered line,
Through code blocks, they intertwine.
Tests abound to keep it neat—
Markdown order, now complete!
📝✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 662e512 and d3de7c1.

📒 Files selected for processing (4)
  • README.md (1 hunks)
  • src/lib.rs (2 hunks)
  • src/main.rs (3 hunks)
  • tests/integration.rs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.md

Instructions used from:

Sources:
⚙️ CodeRabbit Configuration File

**/*.rs

Instructions used from:

Sources:
⚙️ CodeRabbit Configuration File

🧬 Code Graph Analysis (1)
tests/integration.rs (1)
src/lib.rs (1)
  • renumber_lists (494-537)
⏰ Context from checks skipped due to timeout of 240000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-test
🔇 Additional comments (17)
src/lib.rs (2)

227-228: LGTM! Well-structured regex pattern.

The regex correctly captures the components needed for renumbering: indentation, number, spacing, and content. The pattern properly restricts to numbers starting with 1-9 to avoid matching leading zeros.


488-537: Excellent implementation of the renumbering logic.

The function correctly handles:

  • Nested lists using a stack-based approach for tracking indentation levels
  • Preservation of fenced code blocks without modification
  • Sequential numbering within each indentation level
  • Proper unwinding of the counter stack when indentation decreases

The use of #[must_use] is appropriate and the documentation clearly explains the behaviour.

README.md (2)

23-23: LGTM! Usage line correctly updated.

The command-line usage properly reflects the new --renumber option in the appropriate position.


28-28: Clear and concise documentation.

The option description accurately explains the renumbering functionality.

tests/integration.rs (6)

4-4: LGTM! Import correctly added.

The renumber_lists function is properly imported for use in the tests.


668-680: Excellent basic test coverage.

The test correctly verifies that non-sequential numbered lists are renumbered to be sequential (1, 2, 3).


682-699: Good coverage of fenced code block behaviour.

The test properly verifies that numbering continues across fenced code blocks without resetting, which matches the documented behaviour.


701-712: Essential CLI integration test.

The test confirms that the --renumber flag works correctly via the command-line interface with stdin/stdout.


714-737: Thorough nested list testing.

The test correctly validates that nested lists are renumbered independently at each indentation level whilst maintaining the hierarchy.


739-752: Good edge case coverage.

The test ensures that multi-paragraph list items (with blank lines and continued paragraphs) are handled correctly without affecting the numbering logic.

src/main.rs (7)

8-8: LGTM! Import correctly updated.

The import statement properly includes renumber_lists whilst removing the no longer used rewrite and rewrite_no_wrap functions.


19-21: Well-structured CLI argument addition.

The renumber field is properly defined with appropriate clap attributes and documentation.


26-36: Excellent function design.

The process_lines function correctly applies renumbering as a post-processing step after table handling. The conditional application of renumber_lists maintains the existing workflow whilst adding the new functionality.


38-43: Simplified and improved file handling.

The rewrite_path function is now more consistent, using the same processing pipeline as the other code paths. This eliminates the previous duplication between rewrite and rewrite_no_wrap.


75-75: Correct parameter passing.

The main function properly passes the renumber flag to process_lines for stdin processing.


82-82: Consistent flag propagation.

The renumber flag is correctly passed to rewrite_path for in-place file processing.


86-86: Complete integration.

The renumber flag is properly passed to process_lines for file-to-stdout processing, ensuring consistent behaviour across all usage modes.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/add-renumber-commandline-option

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @leynos - I've reviewed your changes and found some issues that need to be addressed.

Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments

### Comment 1
<location> `src/lib.rs:494` </location>
<code_context>
+/// Lines matching `^\s*[1-9][0-9]*\.\s+` are renumbered sequentially within
+/// their indentation level. Numbering continues across fenced code blocks
+/// without resetting.
+pub fn renumber_lists(lines: &[String]) -> Vec<String> {
+    let mut out = Vec::with_capacity(lines.len());
+    let mut counters: Vec<(usize, usize)> = Vec::new();
</code_context>

<issue_to_address>
Consider refactoring the list renumbering logic to use a stack and hash map for indentation and counters, and extract parsing into a helper function.

You can collapse most of the manual “push‐pop‐update” logic by

  1. extracting your numbered-line parsing into a small helper,  
  2. keeping a `Vec<usize>` as your current indent-stack and a `HashMap<indent, next>` counter lookup,  
  3. dropping all deeper indents with one small `while` and the `HashMap::remove`,  
  4. using `entry(…).or_insert(1)` to seed new lists.

That gets you down from nested `is_some_and` checks + two loops into a single concise loop:

```rust
use std::collections::HashMap;
use lazy_static::lazy_static;
use regex::Regex;

lazy_static! {
    static ref FENCE_RE: Regex     = Regex::new(r"^(```|~~~).*").unwrap();
    static ref NUMBERED_RE: Regex  = Regex::new(r"^(\s*)([1-9][0-9]*)\.(\s+)(.*)").unwrap();
}

fn parse_numbered(line: &str) -> Option<(usize, &str, &str)> {
    let caps = NUMBERED_RE.captures(line)?;
    let indent = caps.get(1)?.as_str().len();
    let sep    = caps.get(3)?.as_str();
    let rest   = caps.get(4)?.as_str();
    Some((indent, sep, rest))
}

pub fn renumber_lists(lines: &[String]) -> Vec<String> {
    let mut out     = Vec::with_capacity(lines.len());
    let mut stack   = Vec::<usize>::new();
    let mut counters = HashMap::<usize, usize>::new();
    let mut in_code = false;

    for line in lines {
        if FENCE_RE.is_match(line) {
            in_code = !in_code;
            out.push(line.clone());
            continue;
        }
        if in_code {
            out.push(line.clone());
            continue;
        }
        if let Some((indent, sep, rest)) = parse_numbered(line) {
            // drop all deeper‐indent lists
            while stack.last().map_or(false, |&d| d > indent) {
                counters.remove(&stack.pop().unwrap());
            }
            // start new list at this indent if needed
            if stack.last().map_or(true, |&d| d < indent) {
                stack.push(indent);
                counters.insert(indent, 1);
            }
            // grab & bump our counter
            let num = counters.get_mut(&indent).unwrap();
            let current = *num;
            *num += 1;

            out.push(format!(
                "{}{}.{}{}",
                " ".repeat(indent), current, sep, rest
            ));
        } else {
            out.push(line.clone());
        }
    }
    out
}
```

This:

- removes your manual `(usize,usize)` stack in favor of a single `Vec<usize>` + `HashMap`,  
- collapses your two `while counters.last().…` loops into one small `while`,  
- pulls out the regex logic to a helper for readability,  
- keeps all functionality (fence toggling, in-code passthrough, cross-block counting) intact.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/lib.rs
/// Lines matching `^\s*[1-9][0-9]*\.\s+` are renumbered sequentially within
/// their indentation level. Numbering continues across fenced code blocks
/// without resetting.
pub fn renumber_lists(lines: &[String]) -> Vec<String> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider refactoring the list renumbering logic to use a stack and hash map for indentation and counters, and extract parsing into a helper function.

You can collapse most of the manual “push‐pop‐update” logic by

  1. extracting your numbered-line parsing into a small helper,
  2. keeping a Vec<usize> as your current indent-stack and a HashMap<indent, next> counter lookup,
  3. dropping all deeper indents with one small while and the HashMap::remove,
  4. using entry(…).or_insert(1) to seed new lists.

That gets you down from nested is_some_and checks + two loops into a single concise loop:

use std::collections::HashMap;
use lazy_static::lazy_static;
use regex::Regex;

lazy_static! {
    static ref FENCE_RE: Regex     = Regex::new(r"^(```|~~~).*").unwrap();
    static ref NUMBERED_RE: Regex  = Regex::new(r"^(\s*)([1-9][0-9]*)\.(\s+)(.*)").unwrap();
}

fn parse_numbered(line: &str) -> Option<(usize, &str, &str)> {
    let caps = NUMBERED_RE.captures(line)?;
    let indent = caps.get(1)?.as_str().len();
    let sep    = caps.get(3)?.as_str();
    let rest   = caps.get(4)?.as_str();
    Some((indent, sep, rest))
}

pub fn renumber_lists(lines: &[String]) -> Vec<String> {
    let mut out     = Vec::with_capacity(lines.len());
    let mut stack   = Vec::<usize>::new();
    let mut counters = HashMap::<usize, usize>::new();
    let mut in_code = false;

    for line in lines {
        if FENCE_RE.is_match(line) {
            in_code = !in_code;
            out.push(line.clone());
            continue;
        }
        if in_code {
            out.push(line.clone());
            continue;
        }
        if let Some((indent, sep, rest)) = parse_numbered(line) {
            // drop all deeper‐indent lists
            while stack.last().map_or(false, |&d| d > indent) {
                counters.remove(&stack.pop().unwrap());
            }
            // start new list at this indent if needed
            if stack.last().map_or(true, |&d| d < indent) {
                stack.push(indent);
                counters.insert(indent, 1);
            }
            // grab & bump our counter
            let num = counters.get_mut(&indent).unwrap();
            let current = *num;
            *num += 1;

            out.push(format!(
                "{}{}.{}{}",
                " ".repeat(indent), current, sep, rest
            ));
        } else {
            out.push(line.clone());
        }
    }
    out
}

This:

  • removes your manual (usize,usize) stack in favor of a single Vec<usize> + HashMap,
  • collapses your two while counters.last().… loops into one small while,
  • pulls out the regex logic to a helper for readability,
  • keeps all functionality (fence toggling, in-code passthrough, cross-block counting) intact.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please create an issue for this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have created an issue for your comment: #56

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant