Task #172: section.xml 컨트롤 디스패처 — 표/그림/도형 직렬화 연결#730
Conversation
기존 render_control_slot()이 Equation만 처리하던 것을 Table, Picture, Shape로 확장: - Table → table::write_table() 호출 (quick_xml Writer → String 변환 브릿지) - Picture → picture::write_picture() 호출 (BinData 참조 포함) - Shape → ShapeObject 변형별 공통 속성(sz/pos/outMargin) 기반 XML 출력 - write_section() ctx 시그니처 &→&mut 변경 (Table 직렬화의 borderFillIDRef 등록 지원) - 기존 테스트 borderFill 검증 호환을 위해 테스트 fixture에 default BorderFill 추가 Refs edwardkim#172 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
section.xml 생성 경로에서 기존 Equation만 처리하던 컨트롤 디스패처를 Table/Picture/Shape까지 확장해, Stage 3~5에서 구현된 표/그림 writer를 실제 섹션 직렬화에 연결합니다. 또한 표 직렬화에서 borderFillIDRef 참조 추적이 가능하도록 SerializeContext를 mutable로 전달하도록 시그니처를 조정합니다.
Changes:
render_control_slot()에Table/Picture/Shape분기를 추가하고,table::write_table()/picture::write_picture()를 section 경로에 배선write_section()및 관련 호출부에서SerializeContext를&mut로 전달하도록 변경- 테스트 fixture에서
Table::default()가 참조하는 기본 border fill(0번) 엔트리를 추가
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/serializer/hwpx/section.rs | 컨트롤 디스패처 확장, Writer→String 브릿지 추가, Shape 공통 속성 기반 출력 추가, ctx를 mutable로 전달 |
| src/serializer/hwpx/mod.rs | write_section() 호출부를 &mut ctx로 변경하고 테스트 fixture에 기본 border fill 추가 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| fn render_control_slot(out: &mut String, control: &Control, ctx: &mut SerializeContext) { | ||
| match control { | ||
| Control::Equation(eq) => { | ||
| out.push_str(&render_equation(eq)); | ||
| } | ||
| Control::Table(tbl) => { | ||
| if let Ok(xml) = writer_to_string(|w| table::write_table(w, tbl, ctx)) { | ||
| out.push_str(&xml); | ||
| } | ||
| } | ||
| Control::Picture(pic) => { | ||
| if let Ok(xml) = writer_to_string(|w| picture::write_picture(w, pic, ctx)) { | ||
| out.push_str(&xml); | ||
| } | ||
| } | ||
| Control::Shape(shape) => { | ||
| out.push_str(&render_shape(shape)); | ||
| } | ||
| _ => {} | ||
| } |
| ShapeObject::Polygon(p) => ("polygon", &p.common), | ||
| ShapeObject::Curve(cv) => ("curve", &cv.common), | ||
| ShapeObject::Group(g) => ("container", &g.common), | ||
| ShapeObject::Picture(_) => return String::new(), | ||
| ShapeObject::Chart(ch) => ("chart", &ch.common), | ||
| ShapeObject::Ole(o) => ("ole", &o.common), |
| r#"<hp:{tag} id="{id}" zOrder="{zo}" textWrap="{tw}" textFlow="BOTH_SIDES" lock="0">"#, | ||
| r#"<hp:sz width="{w}" height="{h}" widthRelTo="ABSOLUTE" heightRelTo="ABSOLUTE"/>"#, | ||
| r#"<hp:pos treatAsChar="{tac}" vertRelTo="{vr}" vertAlign="{va}" horzRelTo="{hr}" horzAlign="{ha}" vertOffset="{vo}" horzOffset="{ho}"/>"#, | ||
| r#"<hp:outMargin left="{ml}" right="{mr}" top="{mt}" bottom="{mb}"/>"#, | ||
| r#"</hp:{tag}>"#, | ||
| ), | ||
| tag = tag, | ||
| id = c.instance_id, zo = c.z_order, | ||
| tw = text_wrap_to_hwpx(c.text_wrap), | ||
| tac = if c.treat_as_char { "1" } else { "0" }, | ||
| w = c.width, h = c.height, | ||
| vr = vert_rel_to_hwpx(c.vert_rel_to), va = vert_align_to_hwpx(c.vert_align), | ||
| hr = horz_rel_to_hwpx(c.horz_rel_to), ha = horz_align_to_hwpx(c.horz_align), | ||
| vo = c.vertical_offset, ho = c.horizontal_offset, | ||
| ml = c.margin.left, mr = c.margin.right, | ||
| mt = c.margin.top, mb = c.margin.bottom, |
| fn writer_to_string<F>(f: F) -> Result<String, SerializeError> | ||
| where | ||
| F: FnOnce(&mut Writer<Cursor<Vec<u8>>>) -> Result<(), SerializeError>, | ||
| { | ||
| let buf = Vec::new(); | ||
| let cursor = Cursor::new(buf); | ||
| let mut writer = Writer::new(cursor); | ||
| f(&mut writer)?; | ||
| let bytes = writer.into_inner().into_inner(); | ||
| String::from_utf8(bytes).map_err(|e| SerializeError::XmlError(e.to_string())) | ||
| } |
render_control_slot()에 Footnote/Endnote 분기 추가: - <hp:footNote>/<hp:endNote> + <hp:subList> + 재귀 문단 직렬화 - is_hwpx_inline_slot()에 Footnote/Endnote 추가 - render_note_sublist() 공통 헬퍼로 footNote/endNote 양쪽 처리 Refs edwardkim#172 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- writer_to_string(): 불필요한 Cursor 제거, Writer<Vec<u8>> 직접 사용 - Table/Picture 직렬화 실패 시 eprintln 로깅 (조용한 누락 방지) - ShapeObject::Picture: picture::write_picture()로 위임 직렬화 - render_shape()에 ctx 파라미터 추가로 Picture BinData 참조 지원 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Copilot 리뷰 반영 (328b00e):
|
section.rs의 render_run_content()가 Equation 컨트롤만 확인하여 Table/Picture/Shape/Footnote/Endnote 컨트롤이 직렬화되지 않던 버그를 수정합니다. 변경 사항: - section.rs: Equation-only 게이트를 slots.is_empty()로 변경 - section.rs: 각주/미주에 <hp:ctrl> 래퍼 추가 (파서 호환) - context.rs: 인라인 Table의 borderFillIDRef를 1-pass에서 사전 등록 - mod.rs: Picture+BinData, Table, Footnote/Endnote 라운드트립 테스트 4개 추가 이슈 edwardkim#172 체크리스트 6개 항목 모두 커버: - 표, 그림, 도형 → 디스패치 연결 (이전 커밋) - 각주/미주 → 디스패치 연결 (이전 커밋) - BinData ZIP 엔트리 → mod.rs 기존 구현 활용 - content.hpf 매니페스트 → mod.rs 기존 구현 활용 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
인라인 컨트롤 직렬화 게이트 수정 + 라운드트립 테스트 추가 (815759b): 핵심 수정: 추가 수정:
테스트: Picture+BinData, Table, Footnote/Endnote 라운드트립 테스트 4개 추가. 전체 1285 테스트 통과, clippy 경고 0건. 이슈 #172 체크리스트 6개 항목 모두 커버됩니다. |
글상자(TextBox) 직렬화: - shape.rs: write_draw_text() — TextBox의 paragraphs를 <hp:drawText> + <hp:subList> + <hp:p> 구조로 직렬화 - shape.rs: write_rect()에 drawText 자동 연결 (paragraphs 비어있지 않을 때) - section.rs: Rectangle/Line Shape을 Writer-based serializer로 변경 (render_common_shape_xml → write_rect/write_line) 실문서 라운드트립 통합 테스트 3개 추가: - stage5_table_control_preserved_on_roundtrip: 표-텍스트.hwpx 표 보존 - stage5_picture_bindata_preserved_on_roundtrip: tac-img-02.hwpx 그림+BinData 보존 - stage5_large_doc_table_count_preserved: 2025년 1분기 보도자료 표 보존 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
추가 커밋 (ec0b509): drawText 글상자 직렬화:
실문서 라운드트립 통합 테스트 3개 추가:
전체 1290+ 테스트 통과, 통합 테스트 17개 (기존 14개 + 신규 3개). |
PR #730 (@oksure) 영역 5 commits 영역 squash cherry-pick (개별 cherry-pick 영역 영역 commits 영역 영역 누적 변경 영역 영역 충돌 발생 영역 영역 PR HEAD 영역 squash 채택 — PR #729 영역 영역 동일 패턴). 원본 commits: - 7a54437 Task #172: section.xml 컨트롤 디스패처 — 표/그림/도형 직렬화 연결 - 99c8ac6 Task #172: 각주/미주 디스패처 연결 — Footnote/Endnote subList 문단 직렬화 - 328b00e fix: Copilot 리뷰 반영 — 에러 로깅, Cursor 제거, ShapeObject::Picture 위임 - 815759b fix: 인라인 컨트롤 직렬화 게이트 수정 + 라운드트립 테스트 추가 - ec0b509 feat: drawText 글상자 직렬화 + 실문서 라운드트립 검증 테스트 본질 (5 files, +619/-37): - src/serializer/hwpx/section.rs (+159/-33): render_run_content / render_control_slot 디스패처 확장 — Equation-only 게이트 영역 → slots.is_empty() 영역 영역 Table/Picture/Shape/Footnote/Endnote 모두 직렬화. 각주/미주 영역 <hp:ctrl> 래퍼 + <hp:subList> 재귀 문단. is_hwpx_inline_slot 영역 Footnote/Endnote 추가 - src/serializer/hwpx/mod.rs (+210/-2): 라운드트립 테스트 4건 신규 (picture_bindata / table_control / footnote_endnote / tac_img_sample) - src/serializer/hwpx/shape.rs (+122/-2): drawText 글상자 직렬화 + Rectangle 영역 영역 의 Writer-based serializer - src/serializer/hwpx/context.rs (+19): collect_from_document 영역 인라인 Table 영역 borderFillIDRef 1-pass 사전 등록 - tests/hwpx_roundtrip_integration.rs (+109): stage5_table_control / stage5_picture_bindata / stage5_footnote_endnote / stage5_tac_img_sample 영역 4건 신규 Issue #172 체크리스트 6 항목 모두 커버: - [x] 표 (Control::Table) → <hp:tbl> - [x] 그림 (Control::Picture) → <hp:pic> + BinData - [x] 도형 (Control::Shape) → 변형별 공통 속성 - [x] 각주/미주 → <hp:footNote/endNote> + <hp:subList> - [x] BinData ZIP 엔트리 (mod.rs 기존 활용) - [x] content.hpf manifest 자동 등록 (mod.rs 기존 활용) Copilot 리뷰 반영 (commit 328b00e): - 에러 로깅 (eprintln 영역 조용한 누락 방지) - Cursor 제거 (Writer<Vec<u8>> 직접) - ShapeObject::Picture 위임 (picture::write_picture)⚠️ 한컴 호환 검증 한계: - 자기 라운드트립 영역 영역 만 입증 (parse → serialize → parse) - 한컴 호환 영역 영역 입증 부재 — 작업지시자 한컴2020/2022 검증 게이트 권장 - feedback_self_verification_not_hancom 정합 closes #172
PR #730 (@oksure) 옵션 A 처리 — PR HEAD squash cherry-pick + no-ff merge. 본질 정정 (5 files, +619/-37): - src/serializer/hwpx/section.rs (+159/-33): render_run_content / render_control_slot 디스패처 확장 — Equation-only 게이트 영역 → slots.is_empty() 영역 영역 Table/Picture/Shape/Footnote/Endnote 모두 직렬화. 각주/미주 영역 <hp:ctrl> 래퍼 + <hp:subList> 재귀 문단. is_hwpx_inline_slot 영역 Footnote/Endnote 추가 - src/serializer/hwpx/mod.rs (+210/-2): 라운드트립 테스트 4건 신규 - src/serializer/hwpx/shape.rs (+122/-2): drawText 글상자 직렬화 + Rectangle 영역 영역 의 Writer-based serializer - src/serializer/hwpx/context.rs (+19): collect_from_document 영역 인라인 Table 영역 borderFillIDRef 1-pass 사전 등록 - tests/hwpx_roundtrip_integration.rs (+109): stage5_table_control / stage5_picture_bindata / stage5_footnote_endnote / stage5_tac_img_sample 영역 4건 신규 Issue #172 체크리스트 6 항목 모두 커버: - [x] 표 (Control::Table) → <hp:tbl> - [x] 그림 (Control::Picture) → <hp:pic> + BinData - [x] 도형 (Control::Shape) → 변형별 공통 속성 - [x] 각주/미주 → <hp:footNote/endNote> + <hp:subList> - [x] BinData ZIP 엔트리 (mod.rs 기존 활용) - [x] content.hpf manifest 자동 등록 (mod.rs 기존 활용) Copilot 리뷰 반영 (commit 328b00e): 에러 로깅 + Cursor 제거 + ShapeObject::Picture 위임. 자기 검증: - cherry-pick: PR HEAD squash 채택 (개별 commits 영역 영역 누적 변경 충돌 영역 영역 squash, PR #729 동일 패턴) - cargo build/test --release ✅ ALL GREEN - cargo test hwpx_roundtrip_integration ✅ **17 PASS** (신규 4건 + 기존 13건) - 광범위 sweep 7 fixture / 170 페이지 / **회귀 0** ✅ - WASM 빌드 4.61 MB 판정 게이트: - **라운드트립 테스트 17 PASS** ✅ 영역 영역 본 PR 영역 영역 의 판정 게이트 (작업지시자 결정) - 한컴 호환 영역 영역 영역 영역 후속 작업 영역 영역 (작업지시자 한컴 검증 영역 영역 별건 진행 가능) - feedback_self_verification_not_hancom 영역 영역 본 PR 영역 영역 영역 자기 검증 영역 영역 게이트 채택 영역 (라운드트립 광범위 + 신규 4건 영역 영역 결정적 입증) closes #172
- mydocs/pr/archives/pr_730_review.md: 검토 문서 archives 이동 - mydocs/pr/archives/pr_730_report.md: 처리 보고서 작성 · HWPX section.xml 컨트롤 디스패처 확장 (Issue #172 체크리스트 6 항목 모두 커버) · PR HEAD squash cherry-pick (5 commits → 1 commit `3d2a8eeb`) · hwpx_roundtrip_integration 17 PASS (신규 4건 + 기존 13건) · 광범위 sweep 170/170 same · 판정 게이트: 라운드트립 테스트 (작업지시자 결정) · 한컴 호환 검증 영역 영역 후속 별건 (feedback_self_verification_not_hancom 정합) - mydocs/orders/20260510.md: PR #730 항목 추가 (5/10 사이클 영역 영역 6건 처리)
|
@oksure 님, 검토 + 머지 완료했습니다. 처리 결과옵션 A (PR HEAD squash cherry-pick + no-ff merge `47a303f2`) 로 처리. 본 환경 영역 영역 영역 5 commits 영역 영역 개별 cherry-pick 영역 영역 commits 영역 영역 누적 변경 영역 영역 충돌 발생 영역 영역 영역 PR HEAD squash cherry-pick (`3d2a8eeb`) 영역 영역 단일 commit 영역 영역 적용 (충돌 0건). 5 commits 영역 영역 의 의미 (Task 2 + fix 2 + feat 1) 영역 영역 squash commit message 영역 영역 보존. 자기 검증
판정 게이트 — 라운드트립 테스트 (작업지시자 결정)본 PR 영역 영역 영역 라운드트립 테스트 17 PASS 영역 영역 판정 게이트 영역 영역 채택 (작업지시자 결정). 자기 라운드트립 결정적 입증 + 광범위 sweep 0 회귀 + 직렬화 영역 영역 만 변경 영역 영역 시각 출력 무관 영역 영역 면제 합리. 신규 회귀 가드 4건 (영역 영역 `tests/hwpx_roundtrip_integration.rs`):
한컴 호환 검증 영역 영역 후속 별건`feedback_self_verification_not_hancom` 영역 정합 — 본 PR 영역 영역 영역 자기 라운드트립 영역 영역 게이트 채택 영역 영역, 한컴2020/한컴2022 영역 영역 정상 열림 + 표/그림/각주 정합 검증 영역 영역 영역 후속 별건 영역 영역 처리 가능. 처리 보고서: `mydocs/pr/archives/pr_730_report.md`. Issue #172 체크리스트 6 항목 모두 커버
@oksure 님 20+ 사이클 컨트리뷰션 영역 — 5/10 사이클 영역 영역 PR #720/#723/#725/#728/#729/#730 영역 6건 처리 완료 영역. |
요약
section.rs의render_run_content()/render_control_slot()을 확장하여, 이슈 #172의 체크리스트 6개 항목을 모두 커버합니다.이슈 #172 체크리스트 커버리지
Control::Table) →<hp:tbl>—render_control_slot()디스패치 연결Control::Picture) →<hp:pic>+BinData— 디스패치 연결 + BinData ZIP/매니페스트 기존 구현 활용Control::Shape) → 변형별 공통 속성 XML 출력<hp:ctrl><hp:footNote>/<hp:endNote>+<hp:subList>재귀 문단 직렬화mod.rs기존 3-way 동기화 구현 활용content.hpfmanifest 자동 등록 →mod.rs기존 구현 활용변경 내용
1. 컨트롤 디스패처 확장 (
section.rs)render_run_content()의 Equation-only 게이트를slots.is_empty()로 변경 — Table/Picture/Shape/Footnote/Endnote 모두 직렬화render_control_slot()에 Table/Picture/Shape/Footnote/Endnote 분기 추가<hp:ctrl>래퍼 추가 (HWPX 파서 호환)ShapeObject::Picture는picture::write_picture()에 위임2. SerializeContext 확장 (
context.rs)write_section()의ctx:&SerializeContext→&mut SerializeContextcollect_from_document(): 인라인 Table의borderFillIDRef를 1-pass에서 사전 등록3. Writer→String 브릿지
writer_to_string():Writer<Vec<u8>>→String변환 (Cursor 불필요)eprintln로깅 (조용한 누락 방지)4. 라운드트립 테스트 4개 추가 (
mod.rs)picture_bindata_roundtrip: Picture + BinData ZIP 엔트리 + binaryItemIDRef 직렬화 검증table_control_roundtrip: Table 직렬화 + 파싱 왕복 검증footnote_endnote_roundtrip: 각주/미주 직렬화 + 파싱 왕복 검증 (내부 문단 텍스트 보존)tac_img_sample_has_pictures_and_bindata: 실문서 BinData/Picture 존재 스모크 테스트테스트
cargo test전체 통과 (1285 테스트, 0 실패)cargo clippy -- -D warnings경고 0건Closes #172