163 lines
4.8 KiB
Plaintext
163 lines
4.8 KiB
Plaintext
|
|
#!/usr/bin/env nu
|
||
|
|
# Fix MD013 line length errors by wrapping long lines at natural break points
|
||
|
|
|
||
|
|
def wrap-line [line: string, max_len: int]: string -> string {
|
||
|
|
let len = $line | str length
|
||
|
|
|
||
|
|
# Skip if line is short enough
|
||
|
|
if $len <= $max_len {
|
||
|
|
return $line
|
||
|
|
}
|
||
|
|
|
||
|
|
# Skip table rows (can't easily wrap)
|
||
|
|
if ($line | str trim | str starts-with "|") {
|
||
|
|
return $line
|
||
|
|
}
|
||
|
|
|
||
|
|
# Skip code blocks (shouldn't wrap)
|
||
|
|
if ($line | str trim | str starts-with "```") {
|
||
|
|
return $line
|
||
|
|
}
|
||
|
|
|
||
|
|
# Skip heading lines
|
||
|
|
if ($line | str trim | str starts-with "#") {
|
||
|
|
return $line
|
||
|
|
}
|
||
|
|
|
||
|
|
# Skip list items that start with - or *
|
||
|
|
let trimmed = $line | str trim
|
||
|
|
if ($trimmed | str starts-with "- ") or ($trimmed | str starts-with "* ") or ($trimmed =~ '^\d+\. ') {
|
||
|
|
# List items - try to wrap at sentence boundaries
|
||
|
|
return (wrap-at-punctuation $line $max_len)
|
||
|
|
}
|
||
|
|
|
||
|
|
# Regular prose - wrap at sentence or clause boundaries
|
||
|
|
wrap-at-punctuation $line $max_len
|
||
|
|
}
|
||
|
|
|
||
|
|
def wrap-at-punctuation [line: string, max_len: int]: string -> string {
|
||
|
|
let len = $line | str length
|
||
|
|
if $len <= $max_len {
|
||
|
|
return $line
|
||
|
|
}
|
||
|
|
|
||
|
|
# Find the last space before max_len that follows punctuation or a good break point
|
||
|
|
let break_points = [". " ", " "; " ": " "- " "— " " and " " or " " but " " which " " that " " when " " where "]
|
||
|
|
|
||
|
|
mut best_pos = -1
|
||
|
|
for bp in $break_points {
|
||
|
|
# Find positions of this break point
|
||
|
|
let positions = find-all-positions $line $bp
|
||
|
|
for pos in $positions {
|
||
|
|
# Check if this position is valid (before max_len but not too early)
|
||
|
|
let break_at = $pos + ($bp | str length)
|
||
|
|
if $break_at <= $max_len and $break_at > $best_pos and $break_at > 50 {
|
||
|
|
$best_pos = $break_at
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# If no good break point found, fall back to last space before max_len
|
||
|
|
if $best_pos == -1 {
|
||
|
|
let spaces = find-all-positions $line " "
|
||
|
|
for pos in ($spaces | reverse) {
|
||
|
|
if $pos < $max_len and $pos > 40 {
|
||
|
|
$best_pos = $pos + 1
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# If still no break point, return as-is (can't wrap safely)
|
||
|
|
if $best_pos == -1 {
|
||
|
|
return $line
|
||
|
|
}
|
||
|
|
|
||
|
|
# Split at best position
|
||
|
|
let first = $line | str substring 0..$best_pos | str trim-end
|
||
|
|
let rest = $line | str substring $best_pos..
|
||
|
|
let rest_trimmed = $rest | str trim-start
|
||
|
|
|
||
|
|
# Return wrapped result
|
||
|
|
$"($first)\n($rest_trimmed)"
|
||
|
|
}
|
||
|
|
|
||
|
|
def find-all-positions [text: string, pattern: string]: list<int> {
|
||
|
|
mut positions = []
|
||
|
|
mut start = 0
|
||
|
|
let text_len = $text | str length
|
||
|
|
let pattern_len = $pattern | str length
|
||
|
|
|
||
|
|
while $start < ($text_len - $pattern_len) {
|
||
|
|
let sub = $text | str substring $start..($start + $pattern_len)
|
||
|
|
if $sub == $pattern {
|
||
|
|
$positions = ($positions | append $start)
|
||
|
|
}
|
||
|
|
$start = $start + 1
|
||
|
|
}
|
||
|
|
|
||
|
|
$positions
|
||
|
|
}
|
||
|
|
|
||
|
|
def process-file [file: path, max_len: int] {
|
||
|
|
let content = open $file --raw
|
||
|
|
let lines = $content | split row "\n"
|
||
|
|
|
||
|
|
mut in_code_block = false
|
||
|
|
mut new_lines = []
|
||
|
|
|
||
|
|
for line in $lines {
|
||
|
|
# Track code blocks
|
||
|
|
if ($line | str trim | str starts-with "```") {
|
||
|
|
$in_code_block = not $in_code_block
|
||
|
|
$new_lines = ($new_lines | append $line)
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
|
||
|
|
# Don't process lines inside code blocks
|
||
|
|
if $in_code_block {
|
||
|
|
$new_lines = ($new_lines | append $line)
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
|
||
|
|
# Wrap long lines
|
||
|
|
let wrapped = wrap-line $line $max_len
|
||
|
|
# Split wrapped result back into lines
|
||
|
|
let wrapped_lines = $wrapped | split row "\n"
|
||
|
|
$new_lines = ($new_lines | append $wrapped_lines)
|
||
|
|
}
|
||
|
|
|
||
|
|
let new_content = $new_lines | str join "\n"
|
||
|
|
$new_content | save -f $file
|
||
|
|
}
|
||
|
|
|
||
|
|
def main [
|
||
|
|
file?: path # Specific file to process (optional)
|
||
|
|
--max-len: int = 150 # Maximum line length
|
||
|
|
--dry-run (-d) # Show what would be changed without modifying files
|
||
|
|
] {
|
||
|
|
if $file != null {
|
||
|
|
print $"Processing: ($file)"
|
||
|
|
process-file $file $max_len
|
||
|
|
} else {
|
||
|
|
# Get files with MD013 errors from markdownlint
|
||
|
|
print "Getting files with MD013 errors..."
|
||
|
|
let result = (markdownlint-cli2 --config .markdownlint-cli2.jsonc "**/*.md" | complete)
|
||
|
|
let errors = $result.stderr | lines | where { $in | str contains "MD013" }
|
||
|
|
let files = $errors | each { $in | split row ":" | first } | uniq
|
||
|
|
|
||
|
|
print $"Found ($files | length) files with MD013 errors"
|
||
|
|
|
||
|
|
for f in $files {
|
||
|
|
if $dry_run {
|
||
|
|
print $"Would fix: ($f)"
|
||
|
|
} else {
|
||
|
|
print $"Fixing: ($f)"
|
||
|
|
process-file $f $max_len
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
print "Done"
|
||
|
|
}
|