rumdl 0.0.65__tar.gz → 0.0.66__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rumdl might be problematic. Click here for more details.
- {rumdl-0.0.65 → rumdl-0.0.66}/Cargo.lock +13 -5
- {rumdl-0.0.65 → rumdl-0.0.66}/Cargo.toml +2 -2
- {rumdl-0.0.65 → rumdl-0.0.66}/PKG-INFO +1 -1
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md006_start_bullets.rs +48 -12
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md007_ul_indent.rs +70 -90
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md030_list_marker_space.rs +3 -2
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md034_no_bare_urls.rs +20 -31
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md046_code_block_style.rs +136 -3
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md052_reference_links_images.rs +43 -13
- {rumdl-0.0.65 → rumdl-0.0.66}/src/utils/element_cache.rs +195 -21
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md007_test.rs +2 -2
- {rumdl-0.0.65 → rumdl-0.0.66}/.rumdl.toml +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/MANIFEST.in +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/Makefile +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/README.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/assets/logo.png +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/benches/range_performance.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/benches/range_utils_benchmark.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/benches/rule_performance.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/RULES.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md001.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md002.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md003.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md004.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md005.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md006.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md007.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md009.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md010.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md011.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md012.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md013.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md014.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md018.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md019.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md020.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md021.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md022.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md023.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md024.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md025.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md026.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md027.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md028.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md029.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md030.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md031.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md032.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md033.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md034.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md035.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md036.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md037.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md038.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md039.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md040.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md041.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md042.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md043.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md044.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md045.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md046.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md047.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md048.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md049.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md050.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md051.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md052.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md053.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md054.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md055.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md056.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md057.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/docs/md058.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/issues/plan-rule-parity-with-markdownlint.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/parity_check.py +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/pyproject.toml +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/python/MANIFEST.in +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/python/PYTHON-README.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/python/rumdl/__init__.py +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/python/rumdl/__main__.py +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/python/rumdl/py.typed +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/rumdl.toml.example +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/config.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/init.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/lib.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/lint_context.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/lsp/mod.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/lsp/server.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/lsp/types.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/main.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/markdownlint_config.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/profiling.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/python.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rule.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/blockquote_utils.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/code_block_utils.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/code_fence_utils.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/emphasis_style.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/front_matter_utils.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/heading_utils.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/list_utils.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md001_heading_increment.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md002_first_heading_h1.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md003_heading_style.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md004_unordered_list_style.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md005_list_indent.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md009_trailing_spaces.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md010_no_hard_tabs.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md011_no_reversed_links.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md012_no_multiple_blanks.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md013_line_length.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md014_commands_show_output.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md018_no_missing_space_atx.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md019_no_multiple_space_atx.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md020_no_missing_space_closed_atx.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md021_no_multiple_space_closed_atx.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md022_blanks_around_headings.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md023_heading_start_left.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md024_no_duplicate_heading.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md025_single_title.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md026_no_trailing_punctuation.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md027_multiple_spaces_blockquote.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md028_no_blanks_blockquote.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md029_ordered_list_prefix.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md031_blanks_around_fences.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md032_blanks_around_lists.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md033_no_inline_html.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md035_hr_style.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md036_no_emphasis_only_first.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md037_spaces_around_emphasis.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md038_no_space_in_code.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md039_no_space_in_links.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md040_fenced_code_language.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md041_first_line_heading.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md042_no_empty_links.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md043_required_headings.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md044_proper_names.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md045_no_alt_text.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md047_single_trailing_newline.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md048_code_fence_style.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md049_emphasis_style.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md050_strong_style.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md051_link_fragments.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md053_link_image_reference_definitions.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md054_link_image_style.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md055_table_pipe_style.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md056_table_column_count.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md057_existing_relative_links.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/md058_blanks_around_tables.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/mod.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/rules/strong_style.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/utils/ast_utils.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/utils/code_block_utils.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/utils/document_structure.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/utils/early_returns.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/utils/markdown_elements.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/utils/mod.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/utils/range_utils.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/utils/regex_cache.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/src/utils/string_interner.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/advanced_integration_tests.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/cli_duplication_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/cli_integration_tests.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/commonmark_compliance_tests.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/comprehensive_integration_tests.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/config_application_tests.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/config_tests.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/init_command_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/init_tests.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/integration_tests.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/json_output_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/lib.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/lsp_integration_tests.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/lsp_tests.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/markdownlint_cli_integration.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/markdownlint_config_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/md030_edge_cases.md +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/output_format_tests.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/perf_check.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/pyproject_config_tests.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md001_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md001_unicode_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md002_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md003_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md004_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md005_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md006_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md006_unicode_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md009_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md010_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md011_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md012_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md013_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md014_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md018_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md019_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md020_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md021_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md022_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md023_extended_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md023_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md024_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md025_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md026_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md027_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md028_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md029_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md030_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md031_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md032_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md033_extended_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md033_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md034_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md035_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md036_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md037_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md038_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md039_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md040_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md041_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md042_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md043_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md044_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md045_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md046_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md047_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md048_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md049_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md050_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md051_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md052_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md053_additional_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md053_proptest.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md053_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md054_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md054_unicode_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md055_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md056_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md057_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/md058_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/rules/mod.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/utils/blockquote_utils_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/utils/code_block_utils_extended_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/utils/code_block_utils_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/utils/core_utils_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/utils/front_matter_utils_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/utils/line_index_test.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/utils/mod.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/utils_markdown_edge_cases.rs +0 -0
- {rumdl-0.0.65 → rumdl-0.0.66}/tests/utils_tests.rs +0 -0
|
@@ -1704,7 +1704,7 @@ dependencies = [
|
|
|
1704
1704
|
|
|
1705
1705
|
[[package]]
|
|
1706
1706
|
name = "rumdl"
|
|
1707
|
-
version = "0.0.
|
|
1707
|
+
version = "0.0.66"
|
|
1708
1708
|
dependencies = [
|
|
1709
1709
|
"anyhow",
|
|
1710
1710
|
"assert_cmd",
|
|
@@ -1745,7 +1745,7 @@ dependencies = [
|
|
|
1745
1745
|
"tokio-util",
|
|
1746
1746
|
"toml",
|
|
1747
1747
|
"toml_edit",
|
|
1748
|
-
"tower",
|
|
1748
|
+
"tower 0.5.2",
|
|
1749
1749
|
"tower-lsp",
|
|
1750
1750
|
"tower-service",
|
|
1751
1751
|
"unicode-normalization",
|
|
@@ -2182,7 +2182,16 @@ dependencies = [
|
|
|
2182
2182
|
"pin-project-lite",
|
|
2183
2183
|
"tower-layer",
|
|
2184
2184
|
"tower-service",
|
|
2185
|
-
|
|
2185
|
+
]
|
|
2186
|
+
|
|
2187
|
+
[[package]]
|
|
2188
|
+
name = "tower"
|
|
2189
|
+
version = "0.5.2"
|
|
2190
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2191
|
+
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
|
|
2192
|
+
dependencies = [
|
|
2193
|
+
"tower-layer",
|
|
2194
|
+
"tower-service",
|
|
2186
2195
|
]
|
|
2187
2196
|
|
|
2188
2197
|
[[package]]
|
|
@@ -2209,7 +2218,7 @@ dependencies = [
|
|
|
2209
2218
|
"serde_json",
|
|
2210
2219
|
"tokio",
|
|
2211
2220
|
"tokio-util",
|
|
2212
|
-
"tower",
|
|
2221
|
+
"tower 0.4.13",
|
|
2213
2222
|
"tower-lsp-macros",
|
|
2214
2223
|
"tracing",
|
|
2215
2224
|
]
|
|
@@ -2237,7 +2246,6 @@ version = "0.1.41"
|
|
|
2237
2246
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2238
2247
|
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
|
2239
2248
|
dependencies = [
|
|
2240
|
-
"log",
|
|
2241
2249
|
"pin-project-lite",
|
|
2242
2250
|
"tracing-attributes",
|
|
2243
2251
|
"tracing-core",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "rumdl"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.66"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
description = "A fast Markdown linter written in Rust (Ru(st) MarkDown Linter)"
|
|
6
6
|
authors = ["Ruben J. Jongejan <ruben.jongejan@gmail.com>"]
|
|
@@ -60,7 +60,7 @@ seahash = "4.1"
|
|
|
60
60
|
tower-lsp = "0.20"
|
|
61
61
|
tokio = { version = "1.0", features = ["full"] }
|
|
62
62
|
tokio-util = "0.7"
|
|
63
|
-
tower = "0.
|
|
63
|
+
tower = "0.5.2"
|
|
64
64
|
tower-service = "0.3"
|
|
65
65
|
env_logger = "0.11"
|
|
66
66
|
|
|
@@ -67,6 +67,34 @@ impl MD006StartBullets {
|
|
|
67
67
|
}
|
|
68
68
|
None
|
|
69
69
|
}
|
|
70
|
+
|
|
71
|
+
/// Check if a list item is nested under a parent list item
|
|
72
|
+
fn is_nested_list_item(lines: &[&str], line_idx: usize) -> bool {
|
|
73
|
+
if let Some(current_indent) = Self::is_bullet_list_item(lines[line_idx]) {
|
|
74
|
+
// Look backwards for a parent list item with less indentation
|
|
75
|
+
for i in (0..line_idx).rev() {
|
|
76
|
+
let line = lines[i];
|
|
77
|
+
|
|
78
|
+
// Skip blank lines
|
|
79
|
+
if Self::is_blank_line(line) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// If we find a list item with less indentation, this is nested
|
|
84
|
+
if let Some(parent_indent) = Self::is_bullet_list_item(line) {
|
|
85
|
+
if parent_indent < current_indent {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// If we hit non-list content, stop looking
|
|
91
|
+
if Self::is_bullet_list_item(line).is_none() {
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
false
|
|
97
|
+
}
|
|
70
98
|
}
|
|
71
99
|
|
|
72
100
|
impl Rule for MD006StartBullets {
|
|
@@ -116,6 +144,8 @@ impl Rule for MD006StartBullets {
|
|
|
116
144
|
Node::ListItem(ListItem {
|
|
117
145
|
position, children, ..
|
|
118
146
|
}) => {
|
|
147
|
+
// Only flag top-level list items (depth == 1) that are indented
|
|
148
|
+
// but make sure they're actually top-level and not nested sub-lists
|
|
119
149
|
if depth == 1 && !in_blockquote {
|
|
120
150
|
if let Some(pos) = position {
|
|
121
151
|
let line_idx = pos.start.line.saturating_sub(1);
|
|
@@ -123,17 +153,23 @@ impl Rule for MD006StartBullets {
|
|
|
123
153
|
if let Some(cap) = BULLET_PATTERN.captures(line) {
|
|
124
154
|
let indent = cap[1].len();
|
|
125
155
|
if indent > 0 {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
156
|
+
// Check if this is actually a nested list item
|
|
157
|
+
// by looking for a parent list item above it
|
|
158
|
+
let is_nested = MD006StartBullets::is_nested_list_item(lines, line_idx);
|
|
159
|
+
|
|
160
|
+
if !is_nested {
|
|
161
|
+
result.push(LintWarning {
|
|
162
|
+
rule_name: Some("MD006"),
|
|
163
|
+
severity: Severity::Warning,
|
|
164
|
+
line: line_idx + 1,
|
|
165
|
+
column: 1,
|
|
166
|
+
message: "Consider starting bulleted lists at the beginning of the line".to_string(),
|
|
167
|
+
fix: Some(Fix {
|
|
168
|
+
range: 0..indent,
|
|
169
|
+
replacement: "".to_string(),
|
|
170
|
+
}),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
137
173
|
}
|
|
138
174
|
}
|
|
139
175
|
}
|
|
@@ -310,7 +346,7 @@ impl Rule for MD006StartBullets {
|
|
|
310
346
|
}
|
|
311
347
|
|
|
312
348
|
fn as_maybe_document_structure(&self) -> Option<&dyn crate::rule::MaybeDocumentStructure> {
|
|
313
|
-
|
|
349
|
+
None
|
|
314
350
|
}
|
|
315
351
|
|
|
316
352
|
fn from_config(_config: &crate::config::Config) -> Box<dyn Rule>
|
|
@@ -99,104 +99,84 @@ impl Rule for MD007ULIndent {
|
|
|
99
99
|
self.check(ctx)
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
fn fix(&self, ctx: &crate::lint_context::LintContext) -> Result<String, LintError> {
|
|
103
103
|
let content = ctx.content;
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
norm.extend(chars);
|
|
123
|
-
norm
|
|
124
|
-
})
|
|
125
|
-
.collect();
|
|
126
|
-
|
|
127
|
-
// Recompute logical nesting for each unordered list item
|
|
128
|
-
let mut prev_items: Vec<(usize, usize, usize)> = Vec::new(); // (blockquote_depth, indent, nesting_level)
|
|
129
|
-
for (_, line) in lines.iter_mut().enumerate() {
|
|
130
|
-
let orig_line = line.clone();
|
|
131
|
-
// Inline blockquote prefix parsing (since parse_blockquote_prefix is private)
|
|
132
|
-
let mut rest = orig_line.as_str();
|
|
133
|
-
let mut blockquote_prefix = String::new();
|
|
134
|
-
let mut blockquote_depth = 0;
|
|
135
|
-
loop {
|
|
136
|
-
let trimmed = rest.trim_start();
|
|
137
|
-
if trimmed.starts_with('>') {
|
|
138
|
-
// Find the '>' and a single optional space
|
|
139
|
-
let after = &trimmed[1..];
|
|
140
|
-
let mut chars = after.chars();
|
|
141
|
-
let mut space_count = 0;
|
|
142
|
-
if let Some(' ') = chars.next() {
|
|
143
|
-
space_count = 1;
|
|
144
|
-
}
|
|
145
|
-
let (spaces, after_marker) = after.split_at(space_count);
|
|
146
|
-
blockquote_prefix.push('>');
|
|
147
|
-
blockquote_prefix.push_str(spaces);
|
|
148
|
-
rest = after_marker;
|
|
149
|
-
blockquote_depth += 1;
|
|
150
|
-
} else {
|
|
151
|
-
break;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
// Only process unordered list items outside code blocks
|
|
155
|
-
if rest.trim().is_empty() || rest.starts_with("```") || rest.starts_with("~~~") {
|
|
156
|
-
// Do NOT clear prev_items on blank lines; only skip processing
|
|
157
|
-
continue;
|
|
104
|
+
|
|
105
|
+
// Get the warnings to know which lines need indentation fixing
|
|
106
|
+
let warnings = self.check(ctx)?;
|
|
107
|
+
let mut lines_to_fix: std::collections::HashSet<usize> = std::collections::HashSet::new();
|
|
108
|
+
for warning in &warnings {
|
|
109
|
+
lines_to_fix.insert(warning.line);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
let element_cache = ElementCache::new(content);
|
|
113
|
+
let lines: Vec<&str> = content.lines().collect();
|
|
114
|
+
let mut result_lines: Vec<String> = Vec::new();
|
|
115
|
+
|
|
116
|
+
// Check if any list items have tabs that need normalization
|
|
117
|
+
let mut has_tabs = false;
|
|
118
|
+
for &line in &lines {
|
|
119
|
+
if line.contains('\t') && element_cache.get_list_items().iter().any(|item| item.line_number == lines.iter().position(|&l| l == line).unwrap_or(0) + 1) {
|
|
120
|
+
has_tabs = true;
|
|
121
|
+
break;
|
|
158
122
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// If no warnings and no tabs to normalize, return original content
|
|
126
|
+
if warnings.is_empty() && !has_tabs {
|
|
127
|
+
return Ok(content.to_string());
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
for (line_idx, &line) in lines.iter().enumerate() {
|
|
131
|
+
let line_number = line_idx + 1;
|
|
132
|
+
|
|
133
|
+
// Check if this line is a list item
|
|
134
|
+
if let Some(item) = element_cache.get_list_items().iter().find(|item| item.line_number == line_number) {
|
|
135
|
+
if matches!(item.marker_type, ListMarkerType::Asterisk | ListMarkerType::Plus | ListMarkerType::Minus) {
|
|
136
|
+
// Determine if we need to fix this line
|
|
137
|
+
let needs_indentation_fix = lines_to_fix.contains(&line_number);
|
|
138
|
+
let needs_tab_normalization = line.contains('\t');
|
|
139
|
+
|
|
140
|
+
if needs_indentation_fix || needs_tab_normalization {
|
|
141
|
+
let expected_indent = item.nesting_level * self.indent;
|
|
142
|
+
|
|
143
|
+
// Reconstruct the line with correct indentation
|
|
144
|
+
let marker_char = match item.marker_type {
|
|
145
|
+
ListMarkerType::Asterisk => '*',
|
|
146
|
+
ListMarkerType::Plus => '+',
|
|
147
|
+
ListMarkerType::Minus => '-',
|
|
148
|
+
_ => unreachable!(),
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// Extract the content after the marker and space
|
|
152
|
+
let re = regex::Regex::new(r"^(\s*)([*+-])(\s+)(.*)$").unwrap();
|
|
153
|
+
if let Some(caps) = re.captures(line) {
|
|
154
|
+
let content_part = caps.get(4).map_or("", |m| m.as_str());
|
|
155
|
+
let space_after_marker = caps.get(3).map_or(" ", |m| m.as_str());
|
|
156
|
+
let correct_indent = " ".repeat(expected_indent);
|
|
157
|
+
let fixed_line = format!("{}{}{}{}{}", item.blockquote_prefix, correct_indent, marker_char, space_after_marker, content_part);
|
|
158
|
+
result_lines.push(fixed_line);
|
|
159
|
+
} else {
|
|
160
|
+
// Fallback: just use the original line
|
|
161
|
+
result_lines.push(line.to_string());
|
|
178
162
|
}
|
|
163
|
+
} else {
|
|
164
|
+
result_lines.push(line.to_string());
|
|
179
165
|
}
|
|
166
|
+
} else {
|
|
167
|
+
result_lines.push(line.to_string());
|
|
180
168
|
}
|
|
181
|
-
// Remove stack entries with indent >= current indent and same blockquote depth
|
|
182
|
-
while let Some(&(prev_bq, prev_indent, _)) = prev_items.last() {
|
|
183
|
-
if prev_bq != blockquote_depth || prev_indent < indent {
|
|
184
|
-
break;
|
|
185
|
-
}
|
|
186
|
-
prev_items.pop();
|
|
187
|
-
}
|
|
188
|
-
prev_items.push((blockquote_depth, indent, nesting_level));
|
|
189
|
-
// Reconstruct line with correct indentation
|
|
190
|
-
let correct_indent = " ".repeat(nesting_level * self.indent);
|
|
191
|
-
*line = format!("{}{}{}{}{}", blockquote_prefix, correct_indent, marker, after, content);
|
|
192
169
|
} else {
|
|
193
|
-
|
|
194
|
-
if !rest.trim().is_empty() {
|
|
195
|
-
prev_items.clear();
|
|
196
|
-
}
|
|
170
|
+
result_lines.push(line.to_string());
|
|
197
171
|
}
|
|
198
172
|
}
|
|
199
|
-
|
|
173
|
+
|
|
174
|
+
let result = result_lines.join("\n");
|
|
175
|
+
if content.ends_with('\n') {
|
|
176
|
+
Ok(result + "\n")
|
|
177
|
+
} else {
|
|
178
|
+
Ok(result)
|
|
179
|
+
}
|
|
200
180
|
}
|
|
201
181
|
|
|
202
182
|
/// Get the category of this rule for selective processing
|
|
@@ -185,8 +185,9 @@ impl Rule for MD030ListMarkerSpace {
|
|
|
185
185
|
))
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
fn fix(&self,
|
|
189
|
-
|
|
188
|
+
fn fix(&self, ctx: &crate::lint_context::LintContext) -> Result<String, crate::rule::LintError> {
|
|
189
|
+
// MD030 is not fixable - return content unchanged
|
|
190
|
+
Ok(ctx.content.to_string())
|
|
190
191
|
}
|
|
191
192
|
}
|
|
192
193
|
|
|
@@ -284,13 +284,17 @@ impl MD034NoBareUrls {
|
|
|
284
284
|
if let Some(pos) = &text.position {
|
|
285
285
|
let offset = pos.start.offset + url_start;
|
|
286
286
|
let (line, column) = ctx.offset_to_line_col(offset);
|
|
287
|
+
let url_text = &text_str[url_start..url_end];
|
|
287
288
|
warnings.push(LintWarning {
|
|
288
289
|
rule_name: Some(self.name()),
|
|
289
290
|
line,
|
|
290
291
|
column,
|
|
291
|
-
message: format!("Bare URL found: {}",
|
|
292
|
+
message: format!("Bare URL found: {}", url_text),
|
|
292
293
|
severity: Severity::Warning,
|
|
293
|
-
fix:
|
|
294
|
+
fix: Some(Fix {
|
|
295
|
+
range: offset..(offset + url_text.len()),
|
|
296
|
+
replacement: format!("<{}>", url_text),
|
|
297
|
+
}),
|
|
294
298
|
});
|
|
295
299
|
}
|
|
296
300
|
}
|
|
@@ -401,45 +405,30 @@ impl Rule for MD034NoBareUrls {
|
|
|
401
405
|
}
|
|
402
406
|
|
|
403
407
|
// Get all warnings first - only fix URLs that are actually flagged
|
|
404
|
-
|
|
408
|
+
// Use AST-based detection to match the main linting path (since uses_ast() returns true)
|
|
409
|
+
let ast = crate::utils::ast_utils::get_cached_ast(content);
|
|
410
|
+
let warnings = self.check_with_ast(ctx, &ast)?;
|
|
405
411
|
if warnings.is_empty() {
|
|
406
412
|
return Ok(content.to_string());
|
|
407
413
|
}
|
|
408
414
|
|
|
409
|
-
//
|
|
410
|
-
let mut
|
|
415
|
+
// Sort warnings by byte offset in reverse order (rightmost first) to avoid offset issues
|
|
416
|
+
let mut sorted_warnings = warnings.clone();
|
|
417
|
+
sorted_warnings.sort_by_key(|w| std::cmp::Reverse(w.fix.as_ref().map(|f| f.range.start).unwrap_or(0)));
|
|
411
418
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
// Process lines in reverse order to avoid affecting line indices
|
|
419
|
-
for (line_num, line_warnings) in warnings_by_line.iter().rev() {
|
|
420
|
-
let line_idx = line_num - 1;
|
|
421
|
-
if line_idx >= lines.len() {
|
|
422
|
-
continue;
|
|
423
|
-
}
|
|
419
|
+
let mut result = content.to_string();
|
|
420
|
+
for warning in sorted_warnings {
|
|
421
|
+
if let Some(fix) = &warning.fix {
|
|
422
|
+
let start = fix.range.start;
|
|
423
|
+
let end = fix.range.end;
|
|
424
424
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
sorted_warnings.sort_by_key(|w| std::cmp::Reverse(w.column));
|
|
428
|
-
|
|
429
|
-
for warning in sorted_warnings {
|
|
430
|
-
if let Some(fix) = &warning.fix {
|
|
431
|
-
let line = &mut lines[line_idx];
|
|
432
|
-
let start = fix.range.start;
|
|
433
|
-
let end = fix.range.end;
|
|
434
|
-
|
|
435
|
-
if start <= line.len() && end <= line.len() && start < end {
|
|
436
|
-
line.replace_range(start..end, &fix.replacement);
|
|
437
|
-
}
|
|
425
|
+
if start <= result.len() && end <= result.len() && start < end {
|
|
426
|
+
result.replace_range(start..end, &fix.replacement);
|
|
438
427
|
}
|
|
439
428
|
}
|
|
440
429
|
}
|
|
441
430
|
|
|
442
|
-
Ok(
|
|
431
|
+
Ok(result)
|
|
443
432
|
}
|
|
444
433
|
|
|
445
434
|
/// Get the category of this rule for selective processing
|
|
@@ -50,15 +50,148 @@ impl MD046CodeBlockStyle {
|
|
|
50
50
|
return false;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
// Check if this is part of a list structure
|
|
54
|
+
if self.is_part_of_list_structure(lines, i) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Check if this is part of a formatted text block (not a code block)
|
|
59
|
+
if self.is_part_of_formatted_text_block(lines, i) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Check if preceded by a blank line (typical for code blocks)
|
|
64
|
+
let has_blank_line_before = i == 0 || lines[i - 1].trim().is_empty();
|
|
65
|
+
|
|
66
|
+
// If no blank line before, it's likely list continuation, not a code block
|
|
67
|
+
if !has_blank_line_before {
|
|
56
68
|
return false;
|
|
57
69
|
}
|
|
58
70
|
|
|
59
71
|
true
|
|
60
72
|
}
|
|
61
73
|
|
|
74
|
+
/// Check if an indented line is part of a formatted text block (like license text)
|
|
75
|
+
/// rather than a code block
|
|
76
|
+
fn is_part_of_formatted_text_block(&self, lines: &[&str], i: usize) -> bool {
|
|
77
|
+
let line = lines[i];
|
|
78
|
+
let trimmed = line.trim();
|
|
79
|
+
|
|
80
|
+
// Look for patterns that suggest this is formatted text, not code:
|
|
81
|
+
|
|
82
|
+
// 1. License/legal text patterns
|
|
83
|
+
if trimmed.contains("Copyright") ||
|
|
84
|
+
trimmed.contains("License") ||
|
|
85
|
+
trimmed.contains("Foundation") ||
|
|
86
|
+
trimmed.contains("Certificate") ||
|
|
87
|
+
trimmed.contains("Origin") ||
|
|
88
|
+
trimmed.starts_with("Version ") ||
|
|
89
|
+
trimmed.contains("permitted") ||
|
|
90
|
+
trimmed.contains("contribution") ||
|
|
91
|
+
trimmed.contains("certify") {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 2. Address/contact information patterns
|
|
96
|
+
if trimmed.contains("Drive") ||
|
|
97
|
+
trimmed.contains("Suite") ||
|
|
98
|
+
trimmed.contains("CA,") ||
|
|
99
|
+
trimmed.contains("San Francisco") {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 3. Email signature patterns
|
|
104
|
+
if trimmed.contains("Signed-off-by:") ||
|
|
105
|
+
trimmed.contains("@") && trimmed.contains(".com") {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 4. Check if this is part of a larger block of indented text
|
|
110
|
+
// that looks like formatted prose rather than code
|
|
111
|
+
let mut consecutive_indented_lines = 0;
|
|
112
|
+
let mut has_prose_content = false;
|
|
113
|
+
|
|
114
|
+
// Look at surrounding lines to see if this is part of a prose block
|
|
115
|
+
let start = if i >= 5 { i - 5 } else { 0 };
|
|
116
|
+
let end = if i + 5 < lines.len() { i + 5 } else { lines.len() };
|
|
117
|
+
|
|
118
|
+
for j in start..end {
|
|
119
|
+
let check_line = lines[j];
|
|
120
|
+
if check_line.starts_with(" ") || check_line.starts_with("\t") {
|
|
121
|
+
consecutive_indented_lines += 1;
|
|
122
|
+
let check_trimmed = check_line.trim();
|
|
123
|
+
// Look for prose indicators
|
|
124
|
+
if check_trimmed.len() > 20 &&
|
|
125
|
+
(check_trimmed.contains(" the ") ||
|
|
126
|
+
check_trimmed.contains(" and ") ||
|
|
127
|
+
check_trimmed.contains(" or ") ||
|
|
128
|
+
check_trimmed.contains(" to ") ||
|
|
129
|
+
check_trimmed.contains(" of ") ||
|
|
130
|
+
check_trimmed.contains(" in ") ||
|
|
131
|
+
check_trimmed.contains(" is ") ||
|
|
132
|
+
check_trimmed.contains(" that ")) {
|
|
133
|
+
has_prose_content = true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// If we have many consecutive indented lines with prose content,
|
|
139
|
+
// it's likely formatted text, not code
|
|
140
|
+
if consecutive_indented_lines >= 5 && has_prose_content {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
false
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/// Check if an indented line is part of a list structure
|
|
148
|
+
fn is_part_of_list_structure(&self, lines: &[&str], i: usize) -> bool {
|
|
149
|
+
// Look backwards to find if we're in a list context
|
|
150
|
+
// We need to be more aggressive about detecting list contexts
|
|
151
|
+
|
|
152
|
+
for j in (0..i).rev() {
|
|
153
|
+
let line = lines[j];
|
|
154
|
+
|
|
155
|
+
// Skip empty lines - they don't break list context
|
|
156
|
+
if line.trim().is_empty() {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// If we find a list item, we're definitely in a list context
|
|
161
|
+
if self.is_list_item(line) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Check if this line looks like it's part of a list item
|
|
166
|
+
// (indented content that's not a code block)
|
|
167
|
+
let trimmed = line.trim_start();
|
|
168
|
+
let indent_len = line.len() - trimmed.len();
|
|
169
|
+
|
|
170
|
+
// If we find a line that starts at column 0 and is not a list item,
|
|
171
|
+
// check if it's a structural element that would end list context
|
|
172
|
+
if indent_len == 0 && !trimmed.is_empty() {
|
|
173
|
+
// Headings definitely end list context
|
|
174
|
+
if trimmed.starts_with('#') {
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
// Horizontal rules end list context
|
|
178
|
+
if trimmed.starts_with("---") || trimmed.starts_with("***") {
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
// If it's a paragraph that doesn't look like it's part of a list,
|
|
182
|
+
// we might not be in a list anymore, but let's be conservative
|
|
183
|
+
// and keep looking a bit more
|
|
184
|
+
if j > 0 && j < i - 5 { // Only break if we've looked back a reasonable distance
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Continue looking backwards through indented content
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
false
|
|
193
|
+
}
|
|
194
|
+
|
|
62
195
|
/// Helper function to check if a line is part of a list
|
|
63
196
|
fn is_in_list(&self, lines: &[&str], i: usize) -> bool {
|
|
64
197
|
// Check if current line is a list item
|