Skip to content

feat(sheet): extract form control checkboxes - #123

Merged
tomsideguide merged 1 commit into
mainfrom
feat/sheet-checkboxes
Aug 20, 2026
Merged

feat(sheet): extract form control checkboxes#123
tomsideguide merged 1 commit into
mainfrom
feat/sheet-checkboxes

Conversation

@tomsideguide

@tomsideguide tomsideguide commented Aug 20, 2026

Copy link
Copy Markdown
Member

Form control checkboxes are drawing objects floating over the grid, so every spreadsheet reader dropped them (#115).

Each checkbox now lands in the cell its anchor starts in, as [x] / [ ] plus its caption: xlsx/xlsm/xlsb read the worksheet's VML drawing, xls reads MSODRAWING + OBJ + TXO, ods reads office:forms controls anchored in a cell. Hidden controls, and controls in hidden rows or columns, are omitted like any hidden content.

Stacked on #122. Watch: the mixed state and ODS controls anchored to the page (coordinates only) are not placed; the new Excel 365 cell checkboxes still come out as TRUE/FALSE.


Summary by cubic

Extracts form control checkboxes and renders them inline in their anchor cell. Previously these shapes were dropped; now cells show “[x]” or “[ ]” plus the caption so user-visible data survives.

  • Behavior and coverage

    • Appends checkboxes after existing cell text; supports multiple per cell. Hidden controls and mixed state are omitted. Controls in hidden rows/columns do not render. ODS controls anchored to the page are not placed. Excel 365 native cell checkboxes still render as TRUE/FALSE.
    • OOXML (.xlsx/.xlsm/.xlsb): reads legacy VML checkboxes via worksheet .rels to vmlDrawing*.vml; ignores non-checkbox shapes and visibility:hidden.
    • BIFF8 .xls: takes anchor from MSODRAWING client anchors, checked state from OBJ (mixed ignored), caption from TXO.
    • ODS: expands office:forms form:checkbox referenced by draw:control in a cell; uses form:label and form:(current-)state.
  • Notes (review and API)

    • New sheet::controls; checkboxes flow through SheetContent.checkboxes and are merged in build_table.
    • Adds XML namespaces FORM and X_VML.
    • Renderers must handle Inline::Checkbox(checked) tokens.

Written for commit 6066677. Summary will update on new commits.

Review in cubic

@tomsideguide
tomsideguide force-pushed the feat/sheet-checkboxes branch 2 times, most recently from 09cf9e9 to 458d52c Compare August 20, 2026 20:27
@tomsideguide
tomsideguide force-pushed the feat/sheet-checkboxes branch from 458d52c to 396865a Compare August 20, 2026 20:28
Base automatically changed from feat/checkbox-inline to main August 20, 2026 20:34
@tomsideguide
tomsideguide force-pushed the feat/sheet-checkboxes branch 2 times, most recently from 4775c3e to 0b723ac Compare August 20, 2026 20:35
@tomsideguide

Copy link
Copy Markdown
Member Author

@cubic-dev-ai review

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2 issues found and verified against the latest diff

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/formats/sheet/xlsx.rs">

<violation number="1" location="src/formats/sheet/xlsx.rs:411">
P2: When a checkbox is anchored at the hidden origin of a merged range, the merge relocation moves it into the first visible row or column. Filter controls anchored in hidden coordinates before merging so hidden controls remain omitted.</violation>
</file>

<file name="src/formats/odf/table.rs">

<violation number="1" location="src/formats/odf/table.rs:28">
P1: Standard ODS places `office:forms` under `office:spreadsheet`, alongside `table:table`. Because `parse_table` receives only the table, `read_checkboxes(elem)` misses those forms and drops every anchored control. Collect forms at spreadsheet scope and pass them into each table parser.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread src/formats/odf/table.rs
pending_rows: 0,
header_rows: 0,
rows_emitted: 0,
checkboxes: read_checkboxes(elem),

@cubic-dev-ai cubic-dev-ai Bot Aug 20, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Standard ODS places office:forms under office:spreadsheet, alongside table:table. Because parse_table receives only the table, read_checkboxes(elem) misses those forms and drops every anchored control. Collect forms at spreadsheet scope and pass them into each table parser.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/formats/odf/table.rs, line 28:

<comment>Standard ODS places `office:forms` under `office:spreadsheet`, alongside `table:table`. Because `parse_table` receives only the table, `read_checkboxes(elem)` misses those forms and drops every anchored control. Collect forms at spreadsheet scope and pass them into each table parser.</comment>

<file context>
@@ -23,6 +25,7 @@ pub fn parse_table(elem: &Element, ctx: &Ctx) -> Result<Vec<Block>, ConvertError
         pending_rows: 0,
         header_rows: 0,
         rows_emitted: 0,
+        checkboxes: read_checkboxes(elem),
     };
     walk_rows(elem, ctx, &mut state, true)?;
</file context>
Fix with cubic

Comment thread src/formats/sheet/controls.rs Outdated
Comment thread src/formats/sheet/xlsx.rs
// the assembly no longer cares which was which.
let mut cells: HashMap<(u32, u32), Vec<Inline>> = HashMap::new();
for (at, boxes) in sheet.checkboxes.drain() {
if at.0 < MAX_ROWS && at.1 < MAX_COLS {

@cubic-dev-ai cubic-dev-ai Bot Aug 20, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: When a checkbox is anchored at the hidden origin of a merged range, the merge relocation moves it into the first visible row or column. Filter controls anchored in hidden coordinates before merging so hidden controls remain omitted.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/formats/sheet/xlsx.rs, line 411:

<comment>When a checkbox is anchored at the hidden origin of a merged range, the merge relocation moves it into the first visible row or column. Filter controls anchored in hidden coordinates before merging so hidden controls remain omitted.</comment>

<file context>
@@ -400,10 +404,20 @@ pub(super) fn build_table(
+    // the assembly no longer cares which was which.
+    let mut cells: HashMap<(u32, u32), Vec<Inline>> = HashMap::new();
+    for (at, boxes) in sheet.checkboxes.drain() {
+        if at.0 < MAX_ROWS && at.1 < MAX_COLS {
+            cells.insert(at, cell_inlines(sheet.cells.remove(&at), &boxes));
+        }
</file context>
Suggested change
if at.0 < MAX_ROWS && at.1 < MAX_COLS {
if at.0 < MAX_ROWS && at.1 < MAX_COLS && !hidden_row(at.0) && !hidden_col(at.1) {
Fix with cubic

Comment thread src/formats/sheet/xls.rs
@cubic-dev-ai

cubic-dev-ai Bot commented Aug 20, 2026

Copy link
Copy Markdown

@cubic-dev-ai review

@tomsideguide I have started the AI code review. It will take a few minutes to complete.

@tomsideguide

Copy link
Copy Markdown
Member Author

@cubic-dev-ai review

@tomsideguide
tomsideguide force-pushed the feat/sheet-checkboxes branch from 0b723ac to 283fe00 Compare August 20, 2026 20:38
@cubic-dev-ai

cubic-dev-ai Bot commented Aug 20, 2026

Copy link
Copy Markdown

@cubic-dev-ai review

@tomsideguide I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 8 files

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread src/formats/sheet/xls.rs Outdated
Comment thread src/formats/sheet/controls.rs Outdated
@tomsideguide
tomsideguide force-pushed the feat/sheet-checkboxes branch from 283fe00 to 6066677 Compare August 20, 2026 21:23
@tomsideguide

Copy link
Copy Markdown
Member Author

@cubic-dev-ai review

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 20, 2026

Copy link
Copy Markdown

@cubic-dev-ai review

@tomsideguide I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 8 files

Re-trigger cubic

@tomsideguide
tomsideguide merged commit a50616f into main Aug 20, 2026
5 checks passed
honzasterba added a commit to honzasterba/anydoc that referenced this pull request Aug 21, 2026
The core model gained Inline::Checkbox and moved task-list state out of
ListItem in firecrawl#123, which updated the Node, Python, and WASM bindings.
The Ruby binding lives only in this fork, so the merge left its inline
match non-exhaustive and its list item build reading a field that is
gone. Every native build failed to compile.

Map the variant the way the other bindings do: kind :checkbox, with the
state on a new checked member, which ListItem loses in the same step.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

1 participant