Skip to content

feat: v2 변환 충실도 개선 (href, 인텍스트 위치, EqEdit, 진단/안전장치) - #2

Merged
myeolinmalchi merged 9 commits into
mainfrom
feat/v2-conversion-fidelity
Jun 16, 2026
Merged

myeolinmalchi merged 9 commits into
mainfrom
feat/v2-conversion-fidelity

Conversation

@myeolinmalchi

@myeolinmalchi myeolinmalchi commented Jun 16, 2026 •

Copy link
Copy Markdown
Owner

변경 요약

v2 변환 충실도 개선 6종을 task 단위로 구현했습니다. 각 항목은 단위 테스트 + 골든으로 검증됩니다.

참고: 이 브랜치는 #1(조용한 손실 보강) 머지 후 그 위로 rebase되어, 현재 v2 커밋 7개만 포함합니다.

흐름 객체 / 링크 (출력 충실도)

  • 인라인 하이퍼링크 <href> — 하이퍼링크 필드를 field_ranges로 앵커 구간을 식별해 <href uri="…">로 emit. URL은 필드 command 첫 ; 세그먼트(이스케이프 해제)에서 추출. Markdown [anchor](uri), payload kind:"href"+uri(additive). 웹/mailto/내부 책갈피 링크 보존.
  • 인텍스트 흐름 객체 위치 — 일반 문단에서 표/그림/수식을 control_text_positions() 문자 위치에 맞춰 본문 분할 후 삽입. 비흐름(머리말/꼬리말/각주/글상자)은 말미 유지, 제목/리스트는 기존 동작 유지.

EqEdit 커버리지

  • 무인자 심볼(perp/parallel/langle·rangle/setminus/long·hook arrows 등) + 인자형 데코레이션(overline/underline/widehat/ddot 등) 추가. 미인식어는 여전히 \text{}로 degrade.

진단 / 안전장치

  • geometry 패스 실패 보고 — location-unavailable / location-page-layout-failed LossEntry(기존엔 조용한 빈 맵).
  • 표 셀 충돌 감지 — 클램프 후 anchor 겹침 시 table-cell-collision.
  • OTSL OOM 캡 — grid rows*cols 100만 셀 상한, 초과 시 table-too-large 후 빈 표.

관련 이슈

closes #

테스트 (이 레포 ci.yml 매트릭스, 모두 통과)

  • cargo clippy --all-targets --no-default-features -- -D warnings — 경고 0
  • cargo test --no-default-features — 통과
  • cargo test --features serde — 통과

골든 갱신: href 6건 + 인텍스트 위치 20건(다수 바이트 동일=순수 재배치). UPDATE_GOLDEN=1로 재생성, word-diff로 객체 재배치·텍스트 무손실 확인.

문서: README 커버리지 표(하이퍼링크 행), CHANGELOG 갱신.

myeolinmalchi and others added 7 commits June 16, 2026 16:57
기존에 \text{}로 떨어지던 토큰들을 정상 변환한다.

- 무인자 심볼 추가: perp/parallel/mid/langle·rangle/lfloor·rfloor/
  lceil·rceil/setminus/longrightarrow 계열/hookrightarrow 등
- 인자형 데코레이션 추가: overline/underline/widehat/widetilde/
  check/breve/ddot/mathring/overbrace/underbrace/overrightarrow

미인식어는 여전히 \text{}로 degrade(테스트로 보장).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
범위 초과 셀을 격자 모서리로 클램프할 때, 이미 점유된 anchor 위치와
겹치면 LossEntry(table-cell-collision)로 기록한다. 정상 표는 anchor가
모두 distinct하므로 충돌이 없다(테스트로 보장).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
with_location 사용 시 좌표 맵이 비거나 부분적일 때 그 사유를 LossReport로
드러낸다(기존엔 조용히 빈 맵 반환).

- 레이아웃 코어(build) 실패: LossEntry(location-unavailable)
- 일부 페이지 레이아웃 실패: LossEntry(location-page-layout-failed)에
  실패 페이지 목록 기록(부분 커버리지)

build_location_map / build_from_core가 &mut LossReport를 받도록 변경.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
rows/cols는 u16이라 악성/손상 표가 최대 ~4.3억 셀 grid를 선언해 메모리를
고갈시킬 수 있다. 재구성 grid 크기(rows*cols)에 100만 셀 캡을 두고, 초과 시
LossEntry(table-too-large) 기록 후 빈 <table>로 안전 처리한다.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
HWP 하이퍼링크 필드를 본문 앵커 텍스트 위치에 <href uri="...">로 표현한다.
기존엔 URL/링크를 손실 기록만 하고 버렸다.

- ir::Inline::Href { uri, content } 추가
- inline.rs: Paragraph.field_ranges로 앵커 구간을 식별하고, Field
  (FieldType::Hyperlink)/HWP3 Hyperlink의 command에서 URL 추출(첫
  ';' 세그먼트, '\' 이스케이프 해제)하여 Href로 래핑
- writer/inline.rs: <href uri="...">content</href> emit(attr 이스케이프)
- markdown: [anchor](uri) 링크
- payload: PayloadInline에 uri 필드 추가(additive), kind="href"
- control.rs: 하이퍼링크 Field는 이제 href로 표현되므로 중복 손실 기록 제거
- 골든 6건 갱신(웹/mailto/내부 책갈피 링크가 <href>로 보존됨)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
일반 문단(HeadType::None)에서 표/그림/수식을 본문 텍스트 뒤에 일괄
append하던 것을, control_text_positions()의 문자 위치에 맞춰 본문을 분할하고
객체를 정확한 위치에 삽입한다.

- inline.rs: extract_inline_segments() — 텍스트를 cut 위치로 분할(하이퍼링크
  span은 경계에서 닫고 재개). extract_inlines는 cuts=[]로 위임
- paragraph.rs: 일반 문단은 interleave_ordinary로 흐름 객체를 위치 삽입,
  나머지(머리말/꼬리말/각주/글상자 등 비흐름)는 기존처럼 말미 배치.
  제목/리스트 문단은 분할이 무의미하므로 기존 동작 유지
- build_control_groups: 컨트롤별 블록 그룹 반환(인덱스 정렬)으로 리팩터
- 골든 20건 갱신: 객체가 실제 문자 위치로 재배치(다수 바이트 동일=순수 재배치)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
href·인텍스트 위치 구현 반영, CHANGELOG에 v2 항목 추가, README 커버리지
표에 하이퍼링크 행 추가.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@myeolinmalchi
myeolinmalchi force-pushed the feat/v2-conversion-fidelity branch from 1d36315 to bfb112e Compare June 16, 2026 07:58
문서는 레포에 추적하지 않고 로컬에서 관리한다. README의 해당 문서 링크 제거.
control.rs 주석과 CHANGELOG에서 docs/v2-known-limitations.md 참조 제거.
@myeolinmalchi
myeolinmalchi merged commit 3397cb8 into main Jun 16, 2026
1 check passed
@myeolinmalchi
myeolinmalchi deleted the feat/v2-conversion-fidelity branch June 16, 2026 08:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant