Skip to content

feat: bbox layout engine for docx/xlsx/pptx with ViewOptions infrastructure - #7

Open
Pilser wants to merge 6 commits into
RainLib:mainfrom
Pilser:feat/bbox-engine
Open

feat: bbox layout engine for docx/xlsx/pptx with ViewOptions infrastructure#7
Pilser wants to merge 6 commits into
RainLib:mainfrom
Pilser:feat/bbox-engine

Conversation

@Pilser

@Pilser Pilser commented Jul 19, 2026

Copy link
Copy Markdown

Summary

Add bounding box metadata to text offset maps across all Office formats, enabling layout-aware text targeting for AI agents.

Features Added

  • docx: New layout.rs — page dimensions, paragraph/table bbox computation (twip/EMU → pt)
  • docx: Push spans with bbox metadata in text offset extraction
  • pptx: Parse <a:xfrm> for shape bounding box (position/size EMU → pt); include bbox in text offset spans
  • xlsx: Parse <cols> widths and row heights from sheet XML; compute cell bbox from layout
  • ViewOptions: Added range, grid, render fields; threaded through MCP/resident/watch
  • Table caption: --properties 'title=...' creates <w:tblCaption>
  • Column widths: --properties 'colWidths=180,120,100' sets gridCol widths in twips
  • Page break: officecli set docx '/body/p[1]' pageBreak=true
  • Empty media validation: officecli validate detects 0-byte media files
  • Border color: --properties 'borderColor=1F4E79' (default: black)

Bugs Fixed

  • add image with file=: Only checked src/path but CLI passes file= — caused 0-byte images. Added file fallback in docx + pptx handlers
  • Table border=all: Fell through all match arms, producing empty <w:tblBorders/>. Added "all" shorthand
  • Xlsx set cell text=: Match arm only had "value", not "text" — caused "UNSUPPORTED props: text". Added "text" alias
  • Multi-row table rNcN: All rows got same text due to missing row counter. Fixed with for row in 0..rows + format!("r{}c{}", row + 1, col_idx + 1)
  • Image dimensions: Bare numbers treated as raw EMU (200 EMU = 0.016pt → invisible). Changed to treat as points (×12700)
  • Table border color="auto": LibreOffice renders auto borders as invisible. Default changed to "000000". Added borderColor property for custom colors
  • Drawing xmlns:wp missing: Image/chart drawing templates used wp: prefix without declaring it — caused XML parse errors on subsequent set/add after inserting image
  • [Content_Types].xml malformed: xml.find('>') matched XML declaration ?> instead of <Types> — inserted entries BEFORE <Types> tag, producing invalid XML rejected by LibreOffice

Validation

officecli create test.docx
officecli add test.docx --parent /body --type-name paragraph --properties text=Hello
officecli extract-text test.docx --with-offsets --json | jq '.spans[] | select(.bbox != null) | {path, bbox}'

# Table with borders + custom color
officecli add test.docx --parent /body --type-name table \
  --properties 'cols=3' --properties 'rows=3' \
  --properties 'border=all' --properties 'borderColor=1F4E79' \
  --properties 'title=Products' --properties 'colWidths=180,120,100' \
  --properties 'r1c1=Item' --properties 'r1c2=Price' --properties 'r1c3=Qty'

# Image with proper dims (points)
officecli add test.docx --parent /body/p[1] --type-name image \
  --properties 'file=logo.png' --properties 'width=200' --properties 'height=150'

Files Changed

18 files: layout.rs (new), text_offset.rs (3 formats), pptx navigation/dom_types, xlsx helpers/dom_types, output_format.rs, add.rs, mutations.rs, handler.rs, mcp/resident/watch

Pilsertech added 6 commits July 19, 2026 13:58
Major additions across all Office formats:

Bbox/Layout Engine:
- docx: new layout.rs — page dimensions, paragraph/table bbox computation (twip/EMU to pt)
- docx/xlsx/pptx: push spans with bbox metadata for AI agent text-offset targeting
- pptx: parse &lt;a:xfrm&gt; for shape bounding box (position/size EMU → pt)
- xlsx: parse cols widths and row heights from sheet XML; cell bbox from layout

Screenshot Range Crop (--range):
- view.rs: new --range, --zoom, --padding flags to crop screenshots to element bbox
- handle_screenshot_with_range: find element → get bbox from text offset map → crop

Grid Contact Sheet (--grid):
- view.rs: multi-page tiled thumbnail view using grid columns
- Plumbed through handle_view and handle_screenshot

Render Backend Selection (--render):
- ViewOptions.render field (auto/native/html) threaded through all entry points

Agent Skills CLI:
- New 'skills' subcommand: list available skills, install to Claude/Cursor/Copilot/Windsurf/OpenCode
- Scans skills/ directory, reads SKILL.md headers, installs to agent config dirs

Infrastructure:
- ViewOptions: added range, grid, render fields
- MCP/resident/watch servers: thread range/grid/render params
- AGENTS.md: CRITICAL RULE — no building by AI agents; code review mode guidelines
…table

- Image add: accept 'file' property (not just 'src'/'path') — fixes 0-byte media
- Table border: recognize 'all' shorthand (was falling through to empty)
- Xlsx set cell: accept 'text' alias alongside 'value'
- Multi-row table: fix rNcN text so each row gets unique content (was all rows same)
…_Types.xml insertion position

Three bugs fixed:

1. Table borders used color="auto" which renders invisible in LibreOffice.
   Changed default to "000000" (black). Added borderColor/tblBorderColor/bdrColor
   properties so users can specify custom colors (e.g. borderColor=1F4E79).

2. Drawing XML templates (image + chart) used wp: prefix without declaring
   xmlns:wp — caused XML parse errors on subsequent set/add operations.
   Added xmlns:wp declaration to both templates.

3. Content_Types.xml update functions searched for first '>' in file, which
   matched the PHP/XML declaration '?>', not <Types>. Inserted Default/Override
   entries before <Types> instead of inside it — producing invalid XML that
   LibreOffice refused to open. Fixed by searching from <Types> element.
@Pilser
Pilser force-pushed the feat/bbox-engine branch from d440c3e to 975fb3b Compare July 19, 2026 13:38

@RainLib RainLib left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

当前版本暂不能合并,请在新的 head 提交后重新请求审核。

必须修正:

  1. cargo fmt -- --check 未通过,cargo clippy --all-targets -- -D warnings 也存在 5 个错误;请先 rebase 最新 main 并确保两项通过。
  2. --range 必须按 DOCX、XLSX、PPTX 的不同结构分别实现。当前 XLSX 使用 Sheet1!A1:C3 会被当作普通路径并报 unknown property C3,不能用单一通用路径包装代替格式适配。XLSX 若缺少实现,请对齐 source/OfficeCLI 中的 XLSX 处理方式,但不要混用 DOCX/PPTX 的寻址逻辑。
  3. render 参数目前只被传递,没有驱动实际渲染后端;grid 的通用包装也无法对各格式产生正确分页/工作表网格。请实现真实行为或移除未实现的公开选项。
  4. 本 PR 同时包含 bbox、表格、图片、分页、校验等多组独立修改,不符合仓库 One PR = one atomic change 规则;请拆成可独立验证的 PR。
  5. 为 DOCX、XLSX、PPTX 分别提供命令级 before/after 验证,不能只验证参数被 clap 接收。

完成以上修改并推送新 SHA 后,我会重新执行 fmt、clippy、全工作区测试和各格式命令验证;全部通过后再 Approve。

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants