Metadata-Version: 2.4
Name: ascii-box-aligner
Version: 0.1.0
Summary: Align ASCII box-drawing diagrams in Markdown files, with CJK and nesting support.
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# ascii-box-aligner

在 Markdown 文档的 **围栏代码块**（` ``` `）内，自动对齐 **ASCII / Unicode 框线字符**绘制的示意图：统一右侧竖线与边框宽度，并在内容溢出时按需加宽方框。支持 **中日韩全角字符**（按终端可视宽度计算占列）、**多层嵌套**与并排小框。

---

## 功能概览

| 能力 | 说明 |
|------|------|
| 处理范围 | 仅处理 fenced code block 内的文本；围栏外的 Markdown 原样保留 |
| 竖线与宽度 | 按「可视列」对齐右侧 `│`、`┤` 等；必要时拉长顶/底的 `─` _run |
| CJK | 全角字符按 2 列宽；对部分 Unicode「ambiguous」符号（箭头、制表几何图形等）按 1 列处理 |
| 嵌套 | 基于父子关系 **后序（_innermost first）** 对齐，避免外框先于内框改写 |
| 加宽策略 | 仅在确有「有意义内容」溢出时才加宽；空格与可伸缩横线（`─`/`═`/`━`）一般不迫使加宽 |
| 原位改写 | `-w` / `--write` 可将结果写回文件 |

---

## 环境要求

- **Python** ≥ 3.10  
- 无第三方运行时依赖（标准库即可）。

---

## 安装

### 使用 uv（推荐）

```bash
cd ascii-box-aligner
uv sync
```

### 使用 pip（可编辑安装）

```bash
pip install -e .
```

安装后可通过入口 **`ascii-box-aligner`** 调用 CLI。

---

## 命令行用法

```text
ascii-box-aligner [-w|--write] [FILE ...]
```

| 参数 | 含义 |
|------|------|
| `FILE` | 一个或多个 Markdown 文件路径 |
| （省略或使用 `-`） | 从 **stdin** 读取，结果写到 **stdout** |
| `-w` / `--write` | 将对齐后的全文 **写回对应输入文件**（不能与 stdin `-` 同时使用） |

### 示例

```bash
# 预览：对齐后打印到终端
ascii-box-aligner notes.md

# 原地改写
ascii-box-aligner -w notes.md

# 管道
cat diagram.md | ascii-box-aligner > aligned.md
```

退出码：`0` 成功；读文件失败等为非零。

---

## Python API

适合在脚本或其它工具里嵌入：

```python
from ascii_box_aligner import align_text

md = Path("notes.md").read_text(encoding="utf-8")
fixed = align_text(md)
Path("notes-aligned.md").write_text(fixed, encoding="utf-8")
```

### 额外导出

```python
from ascii_box_aligner import Box, visual_width, visual_to_str_index
```

- **`visual_width(s)`**：字符串整行的可视宽度（用于理解「列」与检测逻辑）。  
- **`visual_to_str_index`**：可视列 ↔ 字符串下标换算（框线与 CJK 混排时使用）。

---

## 工作原理（简述）

整体流水线在源码注释中有更细的说明（见 `src/ascii_box_aligner/aligner.py` 开头）。

1. **围栏扫描**  
   找出 Markdown 中成对的 \`\`\` 围栏；仅在围栏 **内部** 行上操作。

2. **方框检测**  
   在每个围栏内扫描「顶边」：`┌`（或 `╔`/`┏`），必要时支持从 `├` 开头的分枝顶边（后跟横线）。  
   左侧竖线在向下追踪时允许 **小幅抖动**（适应手写示意图里轻微错位）。

3. **嵌套树**  
   根据包含关系建立父子结构；对齐顺序为 **post-order**（先子后父）。

4. **单框对齐**（对每个框）  
   - 遍历框内各行（不含顶/底边专用逻辑的简述）：估算「有意义内容」所需的最右可视列；  
   - `new_right = max(原始右边列, 各行需求)`，并可应用少量启发式（例如抑制单行抖动导致的无谓加宽）；  
   - 重绘顶/底横边（含标签的边尽量只做横向闭合伸缩）；  
   - 内容行在「内容与右边框」之间调节空格或可伸缩横线，使边框落在目标列。

**可视列**：与终端渲染一致——多数 CJK 为 2 列；框线字符等为 1 列（详见 `models.char_visual_width`）。

---

## 支持的框线字符

检测与对齐涵盖常用的 light / heavy 框线与接头，例如：

- 角：`┌ ┐ └ ┘` 及双线变体等  
- 竖横：`│ ─`、`┃`、`═`、`━`  
- 接头：`├ ┤ ┬ ┴ ┼` 及双线变体等  

只要示意图主要由上述字符构成，一般可被识别；极其随意的混合或非矩形拼贴可能失败。

---

## 限制与注意事项

1. **只处理围栏代码块**：普通段落里的框线图不会被改写。  
2. **识别假设**：依赖清晰的顶左角 + 顶右角 + 大致落地的底左角闭合；严重残缺或非矩形布局可能检测不到或误判。  
3. **标签横边**：顶/底边若夹带大量正文标签，加宽时可能跳过整块重绘以防破坏文案（CLI 仍会尽量伸缩末尾横线与角）。  
4. **审美目标**：算法优先「对齐」与「不溢出」，与某一手工排版版本的空格分布可能略有差异。

---

## 目录结构

```text
.
├── pyproject.toml          # 项目元数据与脚本入口
├── main.py                 # 可选入口，转发到 CLI
├── README.md
└── src/ascii_box_aligner/
    ├── __init__.py         # 导出 align_text 等
    ├── cli.py              # 命令行
    ├── aligner.py          # 对齐主算法
    ├── detector.py         # 围栏与方框检测、建树
    └── models.py           # Box、可视宽度工具
```

---

## 许可证与版本

版本号见 `pyproject.toml` 中的 `[project]`。若仓库另附 `LICENSE`，以该文件为准。
