Add markdown table justification script and update settings for output effort
This commit is contained in:
@@ -51,7 +51,7 @@
|
||||
"extraArgs": {
|
||||
"parallel_tool_calls": true,
|
||||
"output_config": {
|
||||
"effort": "max"
|
||||
"effort": "high"
|
||||
}
|
||||
},
|
||||
"noImageSupport": true,
|
||||
|
||||
@@ -32,6 +32,24 @@ Read the rule files from `~/.factory/rules/` and apply them as needed.
|
||||
|
||||
When starting work on a project, run `colgrep init` to build the semantic search index. This enables the colgrep skill for semantic code search across the codebase. The index auto-updates on subsequent searches, so `init` only needs to run once per project.
|
||||
|
||||
### Markdown Table Justification
|
||||
|
||||
To justify markdown tables (ASCII character count justified), use the built-in script:
|
||||
|
||||
```bash
|
||||
# Justify tables in a file (executable with uv shebang)
|
||||
~/.factory/skills/rules/table_justify.py <file>
|
||||
|
||||
# Or via python
|
||||
python ~/.factory/skills/rules/table_justify.py <file>
|
||||
|
||||
# Justify and save to new file
|
||||
~/.factory/skills/rules/table_justify.py <file> -o <output>
|
||||
|
||||
# Justify from stdin
|
||||
cat table.md | ~/.factory/skills/rules/table_justify.py
|
||||
```
|
||||
|
||||
## Research
|
||||
|
||||
- Back all claims with reference code.
|
||||
|
||||
152
.factory/skills/rules/table_justify.py
Executable file
152
.factory/skills/rules/table_justify.py
Executable file
@@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env -S uv run --script
|
||||
# /// script
|
||||
# requires-python = ">=3.11"
|
||||
# ///
|
||||
"""
|
||||
Markdown Table Justifier
|
||||
|
||||
ASCII character-justifies markdown tables by padding all cells
|
||||
to match the maximum width in each column.
|
||||
|
||||
Usage:
|
||||
./table_justify.py <file>
|
||||
./table_justify.py <file> -o <output>
|
||||
cat <file> | table-justify
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def parse_table(lines: list[str]) -> tuple[list[list[str]], list[int]]:
|
||||
"""
|
||||
Parse a markdown table into rows and calculate column widths.
|
||||
Returns (rows, max_widths).
|
||||
"""
|
||||
rows = []
|
||||
max_widths = []
|
||||
|
||||
for line in lines:
|
||||
line = line.rstrip()
|
||||
if not line.startswith("|"):
|
||||
continue
|
||||
|
||||
# Split by | and strip whitespace
|
||||
cells = [cell.strip() for cell in line.split("|")]
|
||||
# Remove empty first/last cells from leading/trailing |
|
||||
cells = [c for c in cells if c or c == ""]
|
||||
if len(cells) > 0 and cells[0] == "":
|
||||
cells = cells[1:]
|
||||
if len(cells) > 0 and cells[-1] == "":
|
||||
cells = cells[:-1]
|
||||
|
||||
if not cells:
|
||||
continue
|
||||
|
||||
rows.append(cells)
|
||||
|
||||
# Update max widths
|
||||
while len(max_widths) < len(cells):
|
||||
max_widths.append(0)
|
||||
|
||||
for i, cell in enumerate(cells):
|
||||
max_widths[i] = max(max_widths[i], len(cell))
|
||||
|
||||
return rows, max_widths
|
||||
|
||||
|
||||
def is_separator_row(row: list[str]) -> bool:
|
||||
"""Check if a row is a header separator (all dashes)."""
|
||||
if not row:
|
||||
return False
|
||||
return all(re.match(r"^-+$", cell.strip().replace(" ", "")) or cell.strip() == "" for cell in row)
|
||||
|
||||
|
||||
def format_separator(widths: list[int]) -> str:
|
||||
"""Format the separator row."""
|
||||
cells = ["-" * w for w in widths]
|
||||
return "|" + "|".join(f" {c} " for c in cells) + "|"
|
||||
|
||||
|
||||
def format_row(row: list[str], widths: list[int]) -> str:
|
||||
"""Format a data row with proper padding."""
|
||||
padded = []
|
||||
for i, cell in enumerate(row):
|
||||
if i < len(widths):
|
||||
padded.append(cell.ljust(widths[i]))
|
||||
else:
|
||||
padded.append(cell)
|
||||
return "|" + "|".join(f" {c} " for c in padded) + "|"
|
||||
|
||||
|
||||
def justify_table(lines: list[str]) -> list[str]:
|
||||
"""Justify a markdown table."""
|
||||
rows, max_widths = parse_table(lines)
|
||||
|
||||
if not rows:
|
||||
return lines
|
||||
|
||||
result = []
|
||||
for i, row in enumerate(rows):
|
||||
if i == 1 and is_separator_row(row):
|
||||
result.append(format_separator(max_widths))
|
||||
else:
|
||||
result.append(format_row(row, max_widths))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def process_content(content: str) -> str:
|
||||
"""Process content and justify all tables found."""
|
||||
lines = content.split("\n")
|
||||
result = []
|
||||
table_lines = []
|
||||
in_table = False
|
||||
|
||||
for line in lines:
|
||||
if line.strip().startswith("|"):
|
||||
table_lines.append(line)
|
||||
in_table = True
|
||||
else:
|
||||
if in_table:
|
||||
# End of table, process it
|
||||
result.extend(justify_table(table_lines))
|
||||
table_lines = []
|
||||
in_table = False
|
||||
result.append(line)
|
||||
|
||||
# Process last table if file ends with one
|
||||
if table_lines:
|
||||
result.extend(justify_table(table_lines))
|
||||
|
||||
return "\n".join(result)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="ASCII character-justify markdown tables"
|
||||
)
|
||||
parser.add_argument("input", nargs="?", help="Input file (default: stdin)")
|
||||
parser.add_argument("-o", "--output", help="Output file (default: stdout)")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Read input
|
||||
if args.input:
|
||||
content = Path(args.input).read_text()
|
||||
else:
|
||||
content = sys.stdin.read()
|
||||
|
||||
# Process
|
||||
result = process_content(content)
|
||||
|
||||
# Write output
|
||||
if args.output:
|
||||
Path(args.output).write_text(result)
|
||||
else:
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user