From 05d7f605b87b675c7495d0bb275f82020edc209a Mon Sep 17 00:00:00 2001 From: airmang <38392618+airmang@users.noreply.github.com> Date: Tue, 6 Oct 2026 17:03:55 +0900 Subject: [PATCH 1/6] feat(table): insert columns by cloning a grid column apply_table_ops could insert rows (insert_row_by_clone) but no columns. insert_column_by_clone inserts count columns right of grid column ref_col (left of it with side "left"), cloning it: - each new column is as wide as ref_col, and the table grows by it; - each new cell takes the format of the cell of the same row in ref_col, and its text unless blank is set, which leaves one empty paragraph as Hangul does; - a cell merged across the new columns grows its colSpan and width, next to a merged cell ending (on the left, starting) at ref_col each new column gets an empty cell of its format and rows, and a cell merged down ref_col is cloned with its rows; - cell zones move with their columns. Eighteen Hangul-saved files: 3x3 tables made by Hangul and the same tables after Hangul inserted columns (right, left, three, right of a wider column, merged cells across, ending at and down the column, formats per row, a table as wide as the text). With blank the inserted tables match Hangul's cell for cell, but for the stored width of a cell merged across the new column, which Hangul leaves as it was and draws by the grid. The row insertion shares its paragraph id helper (_fresh_ids). Co-Authored-By: Claude Opus 5.5 --- docs/editor-menu-reverse-map.md | 2 +- src/hwpx/table_patch.py | 135 ++++++++++-- .../table_insert_column_base.hwpx | Bin 0 -> 6213 bytes .../table_insert_column_formats2_base.hwpx | Bin 0 -> 6360 bytes .../table_insert_column_formats2_side1.hwpx | Bin 0 -> 6396 bytes .../table_insert_column_formats_base.hwpx | Bin 0 -> 6467 bytes .../table_insert_column_formats_side1.hwpx | Bin 0 -> 6507 bytes .../table_insert_column_full_width0_base.hwpx | Bin 0 -> 6213 bytes ...table_insert_column_full_width0_side1.hwpx | Bin 0 -> 6248 bytes .../table_insert_column_merge_r0c01_base.hwpx | Bin 0 -> 6244 bytes ...table_insert_column_merge_r0c01_side1.hwpx | Bin 0 -> 6285 bytes .../table_insert_column_merge_r0c12_base.hwpx | Bin 0 -> 6241 bytes ...table_insert_column_merge_r0c12_side1.hwpx | Bin 0 -> 6271 bytes .../table_insert_column_side0_count1.hwpx | Bin 0 -> 6252 bytes .../table_insert_column_side1_count1.hwpx | Bin 0 -> 6248 bytes .../table_insert_column_side1_count3.hwpx | Bin 0 -> 6305 bytes ...table_insert_column_vmerge_c1r01_base.hwpx | Bin 0 -> 6233 bytes ...able_insert_column_vmerge_c1r01_side1.hwpx | Bin 0 -> 6261 bytes ...able_insert_column_wide_col1_all_base.hwpx | Bin 0 -> 6234 bytes ...ble_insert_column_wide_col1_all_side1.hwpx | Bin 0 -> 6275 bytes tests/test_insert_column_by_clone.py | 200 ++++++++++++++++++ 21 files changed, 318 insertions(+), 19 deletions(-) create mode 100644 tests/fixtures/hancom_saved/table_insert_column_base.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_formats2_base.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_formats2_side1.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_formats_base.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_formats_side1.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_full_width0_base.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_full_width0_side1.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_merge_r0c01_base.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_merge_r0c01_side1.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_merge_r0c12_base.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_merge_r0c12_side1.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_side0_count1.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_side1_count1.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_side1_count3.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_vmerge_c1r01_base.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_vmerge_c1r01_side1.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_wide_col1_all_base.hwpx create mode 100644 tests/fixtures/hancom_saved/table_insert_column_wide_col1_all_side1.hwpx create mode 100644 tests/test_insert_column_by_clone.py diff --git a/docs/editor-menu-reverse-map.md b/docs/editor-menu-reverse-map.md index 09a61040..09872baa 100644 --- a/docs/editor-menu-reverse-map.md +++ b/docs/editor-menu-reverse-map.md @@ -154,7 +154,7 @@ Windows 한컴 전용 표면은 이 스캔으로 부재를 단정할 수 없다. | 셀 테두리/배경 | [대응 영역] | `HwpxOxmlTable.set_cell_border_fill`(+ `ensure_border_fill`)로 테두리, `set_cell_shading`(+ `ensure_shading_border_fill`)로 배경색, `set_cell_fill_image`/`set_cell_fill_gradient`로 이미지/그라데이션 배경까지 전부 확인(`oxml/table.py:775-843`) — 표 구조 변경/문단·표 저작/편집 영역이 대응 | | 표 나누기 | ✅ [대응 영역] | ~~신규 갭~~ **트레인㊸ 갭⑤에서 해소**(`f7e4e67`) — `apply_table_ops`의 `split_table` op가 물리 행 인덱스에서 표를 둘로 나눈다(병합 셀이 경계를 걸치면 fail-closed 거부), v16 render-verified | | 표 붙이기 | ✅ [대응 영역] | ~~신규 갭~~ **트레인㊸ 갭⑤에서 해소**(`f7e4e67`) — `apply_table_ops`의 `merge_table` op가 그 역연산을 수행한다(colCnt 불일치·실텍스트 존재 시 거부), v16 render-verified | -| 줄/칸 추가하기… | [대응 영역] | 표 구조 변경(`insert_row_by_clone`) | +| 줄/칸 추가하기… | [대응 영역] | 표 구조 변경(`insert_row_by_clone`, `insert_column_by_clone`) | | 줄/칸 지우기… | [대응 영역] | 표 구조 변경(`delete_row`/`delete_column`) | | 셀 나누기… | [대응 영역] | 표 구조 변경(`split_cell_vertical`) | | 셀 합치기 | [대응 영역] | 표 생성(`merge_cells`) | diff --git a/src/hwpx/table_patch.py b/src/hwpx/table_patch.py index 415bbf79..93885c2d 100644 --- a/src/hwpx/table_patch.py +++ b/src/hwpx/table_patch.py @@ -27,7 +27,7 @@ import re from dataclasses import dataclass from pathlib import Path -from typing import Any, Iterable, Mapping, Sequence +from typing import Any, Callable, Iterable, Mapping, Sequence from .errors import HwpxError from .oxml.table_sizes import effective_cell_margin_source @@ -1247,6 +1247,22 @@ def _clone_row_template(rows: list[str], ref_row: int) -> str: return (opening.group(0) if opening else "") + "".join(tc for _, tc in sorted(cells, key=lambda c: c[0])) + "" +def _fresh_ids(table: str, used_ids: set[int] | None) -> Callable[[re.Match[str]], str]: + """A ``_PARA_ID_RE`` substitution giving each paragraph the lowest id used neither in + *table* nor in *used_ids* (the ids of the whole document).""" + occupied = set(used_ids or ()) | {int(m.group(2)) for m in _PARA_ID_RE.finditer(table)} + next_id = 1 + + def fresh_id(match: re.Match[str]) -> str: + nonlocal next_id + while next_id in occupied: + next_id += 1 + occupied.add(next_id) + return match.group(1) + str(next_id) + match.group(3) + + return fresh_id + + def _insert_row_by_clone( table: str, ref_row: int, count: int = 1, *, used_ids: set[int] | None = None ) -> str: @@ -1277,16 +1293,7 @@ def shift(tc: str): # build the clones from the ORIGINAL rows, before the shift ref = _clone_row_template(rows, ref_row) shifted = [_map_cells(r, shift) for r in rows] - occupied = set(used_ids or ()) | {int(m.group(2)) for m in _PARA_ID_RE.finditer(table)} - next_id = 1 - - def fresh_id(match: re.Match[str]) -> str: - nonlocal next_id - while next_id in occupied: - next_id += 1 - occupied.add(next_id) - return match.group(1) + str(next_id) + match.group(3) - + fresh_id = _fresh_ids(table, used_ids) clones = [] for k in range(1, count + 1): clone = _map_cells(ref, lambda tc: _ss(tc, "cellAddr", "rowAddr", ref_row + k)) @@ -1296,6 +1303,85 @@ def fresh_id(match: re.Match[str]) -> str: return _rebuild(prefix, new_rows, suffix, rowcnt=len(new_rows)) +def _shift_zone_columns(prefix: str, first: int, count: int) -> str: + """The ``hp:cellzone`` entries of a table head with *count* columns inserted from grid + column *first* on: a zone from there on moves over, a zone running on across it grows.""" + + def shift(match: re.Match[str]) -> str: + zone = match.group(0) + start, end = _si(zone, "cellzone", "startColAddr"), _si(zone, "cellzone", "endColAddr") + if start is None or end is None or end < first: + return zone + if start >= first: + zone = _ss(zone, "cellzone", "startColAddr", start + count) + return _ss(zone, "cellzone", "endColAddr", end + count) + + return re.sub(r"]*>", shift, prefix) + + +def _insert_column_by_clone( + table: str, + ref_col: int, + count: int = 1, + *, + side: str = "right", + blank: bool = False, + used_ids: set[int] | None = None, +) -> str: + """Insert *count* columns right (or with *side* ``"left"``, left) of grid column *ref_col* + by cloning it (formatting preserved, paragraph ids refreshed). Columns past them shift, + and the table grows by the new columns, each as wide as *ref_col*, as Hancom's column + insertion widens it. With *blank* each new cell holds one empty paragraph of its cell's + paragraph and character shape, as Hancom inserts them. + + Merged cells follow Hancom's insertion as in :func:`_insert_row_by_clone`: a cell running + on across the new columns grows its colSpan and width over them instead of being cloned, + and next to a merged cell that ends (or, on the left, starts) at *ref_col* each new + column gets an empty cell of its format and rows.""" + _guard_flat(table) + if side not in ("left", "right"): + raise TableStructureError(f"insert_column_by_clone: side must be 'left' or 'right', got {side!r}") + if count < 1: + return table + prefix, rows, suffix = _parse_table(table) + columns = _grid_width(rows) + if not 0 <= ref_col < columns: + raise TableStructureError(f"ref col {ref_col} out of range") + widths = _uniform_col_widths(rows) or _grid_col_widths(table) + if widths is None: + raise TableStructureError( + "insert_column_by_clone: the column widths are underivable from the grid -- refusing (fail-closed)" + ) + width = widths[ref_col] + first = ref_col + 1 if side == "right" else ref_col # the first new column + fresh_id = _fresh_ids(table, used_ids) + + def clones(tc: str) -> str: + if blank or (_si(tc, "cellSpan", "colSpan") or 1) > 1: + tc = _ss(_ss(_empty_cell_like(tc), "cellSpan", "colSpan", 1), "cellSz", "width", width) + return "".join( + _PARA_ID_RE.sub(fresh_id, _ss(tc, "cellAddr", "colAddr", first + k)) for k in range(count) + ) + + def widen(tc: str) -> str: + col, span = _si(tc, "cellAddr", "colAddr"), _si(tc, "cellSpan", "colSpan") or 1 + assert col is not None # required hp:tc attr + if col < first <= col + span - 1: # runs on across the new columns -> grows over them + tc = _ss(tc, "cellSpan", "colSpan", span + count) + return _ss(tc, "cellSz", "width", (_si(tc, "cellSz", "width") or 0) + count * width) + moved = _ss(tc, "cellAddr", "colAddr", col + count) if col >= first else tc + if side == "right" and col + span - 1 == ref_col: + return moved + clones(tc) + if side == "left" and col == ref_col: + return clones(tc) + moved + return moved + + new_rows = [_map_cells(row, widen) for row in rows] + prefix = _ss(prefix, "sz", "width", (_si(prefix, "sz", "width") or 0) + count * width) + prefix = _shift_zone_columns(prefix, first, count) + return _rebuild(prefix, new_rows, suffix, colcnt=columns + count) + + def _insert_block_by_clone(table: str, r0: int, r1: int, count: int = 1) -> str: """Clone a contiguous **vertical-merge block** (physical rows ``r0..r1``) *count* times, preserving the block's internal span pattern (FR-001). @@ -1515,6 +1601,9 @@ def _widths_arg(o: Mapping[str, Any]) -> dict[int, int]: "delete_row": lambda t, o: _delete_rows(t, o["rows"] if "rows" in o else [o["row"]]), "reorder_rows": lambda t, o: _reorder_rows(t, [int(x) for x in o["order"]]), "insert_row_by_clone": lambda t, o: _insert_row_by_clone(t, o["ref_row"], int(o.get("count", 1))), + "insert_column_by_clone": lambda t, o: _insert_column_by_clone( + t, int(o["ref_col"]), int(o.get("count", 1)), side=str(o.get("side", "right")), + blank=bool(o.get("blank", False))), "insert_block_by_clone": lambda t, o: _insert_block_by_clone(t, int(o["ref_rows"][0]), int(o["ref_rows"][1]), int(o.get("count", 1))), "set_column_widths": lambda t, o: _set_column_widths(t, _widths_arg(o)), "autofit_columns": lambda t, o: _autofit_columns(t, min_frac=float(o.get("min_frac", 0.06)), damp=float(o.get("damp", 0.5))), @@ -1525,6 +1614,16 @@ def _widths_arg(o: Mapping[str, Any]) -> dict[int, int]: } +#: The ops whose new paragraphs take ids unused in the whole document. +_CLONE_OPS = { + "insert_row_by_clone": lambda t, o, ids: _insert_row_by_clone( + t, o["ref_row"], int(o.get("count", 1)), used_ids=ids), + "insert_column_by_clone": lambda t, o, ids: _insert_column_by_clone( + t, int(o["ref_col"]), int(o.get("count", 1)), side=str(o.get("side", "right")), + blank=bool(o.get("blank", False)), used_ids=ids), +} + + def _set_row_heights(table: str, heights: Mapping[int, int]) -> str: """행높이 명시 설정(HWPUNIT, 1pt=100) — Stage 3 간격 프리미티브. @@ -1920,8 +2019,11 @@ def apply_table_ops( each changed table back so untouched bytes stay identical. Op dicts: ``{op: 'delete_column'|'delete_row'|'delete_table'| - 'insert_row_by_clone'|'insert_block_by_clone'|'split_table'|'merge_table'| - 'fill_cell', section_path?, table_index, ...}``. ``insert_block_by_clone`` + 'insert_row_by_clone'|'insert_column_by_clone'|'insert_block_by_clone'| + 'split_table'|'merge_table'|'fill_cell', section_path?, table_index, ...}``. + ``insert_column_by_clone`` takes ``ref_col`` + ``count`` (+ ``side: 'left'``, + ``blank`` for empty new cells) and inserts right (left) of that grid column, + widening the table. ``insert_block_by_clone`` takes ``ref_rows: [r0, r1]`` (a vertical-merge block) + ``count``; ``delete_column`` derives widths from the merged grid when no uniform ``colSpan==1`` row exists (FR-003). @@ -2026,13 +2128,10 @@ def _log(name, sp, ti, status, **extra) -> None: elif name == "merge_table": new_section, dims_after = _merge_tables(section, spans, ti) elif name in _STRUCT_OPS: - if name == "insert_row_by_clone": + if name in _CLONE_OPS: used_ids = {int(m.group(2)) for data in sections.values() for m in _PARA_ID_RE.finditer(data.decode("utf-8"))} - new_table = _insert_row_by_clone( - section[ts:te].decode("utf-8"), op["ref_row"], - int(op.get("count", 1)), used_ids=used_ids, - ) + new_table = _CLONE_OPS[name](section[ts:te].decode("utf-8"), op, used_ids) else: new_table = _STRUCT_OPS[name](section[ts:te].decode("utf-8"), op) _validate_or_raise(new_table) diff --git a/tests/fixtures/hancom_saved/table_insert_column_base.hwpx b/tests/fixtures/hancom_saved/table_insert_column_base.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..a75953babfbde2389471057a168f371535aa5635 GIT binary patch literal 6213 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 OzTOy4Qoal(fd2!s!QlP? literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/table_insert_column_formats2_side1.hwpx b/tests/fixtures/hancom_saved/table_insert_column_formats2_side1.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..efdf24e2142c0bccdb2c4b1a388ae3265151027a GIT binary patch literal 6396 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 R0I(2W9|R}W-6Rvh{{hb&2GRfk literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/table_insert_column_formats_side1.hwpx b/tests/fixtures/hancom_saved/table_insert_column_formats_side1.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..81d00e5b778cd96302a7e899f52b938ce0c5570c GIT binary patch literal 6507 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

pkTXjpKeK2EcL8Q%H@r@Joj@pQ8bo! z+Od3-$SWBh)gj#)%o`M8Q}484E%jz$P_WG|jBh@tIcWmYWZ9dHisKuNJ6OyjV;yMU zeiL#@z4vByf?k-!n!$9qfW4Q@G_#%<#f%elE69ogoq_^m&ESbVCt86AO(ZH=7etE> z<-A)JC%*mk#sq3#gCGQ7v0~|R(4pnrR8FByass=Bu6cH# zXb$Cp@U<8Lp1Y2M$^u~$Z-?BDbQNxK0Oy^CXW^7)qFsX92gZdhw(*Dw?oNEFMvj^N zS!4Zj?*0vyg2W^|dcmr(((;ABYQkmNo>>d2iNwEiR)?!=x`-oO8cvNxQf}PS7ozXE z@P`|8We)7dG}-QKw=BfvUYq|v`_?nYGE-dcO3&i^%SFf5u*dBwpo z@*;nP;W)f0zC#72?-u$e@UUdXLY8hv?8w0A@FYw9HNj$XTS6~gbFq|W*#3TTPMrkpj)3d;=M#nnl=`{(-sL4Tjr8m(_N1s z)P0+oM#Qg1^YWy0O}o~~Wt^sGJ%g-KV{_+bK+NW4_tVyhl|t-1H|*Yy_MJFFdNct& z2YgJ`%pvWxFLSxDV`b-Ln_2IC`wS;&vF0&p;mz*-_9(AzGW_k-rEeVAd8eI0i|25- zH!u8b=ceK|5&Y+2@Zxc~AFox$r6XS?m7r$-5jMjIqMJd1vjDO8>JcOAeW!KaW$j`u zyjjeeXRHAxM}vySTtj&0G#?M5EiD_sj?HQA-NR6hfLEddF{XAyxVvLS1Gg*c_IR$L zc0+(T{8DvwZZ+;^ykMph^~af|n^_8l_A!pow9>pwblgTqOd)yy{<2Tuxxv7ikg#T$ z=JPJilAx^Qux-t@)>$)C`yT9iId)>rz?&0xvRV`yT{DXX6B$y<5wAj(BVZ#6brczK zpz&MPW$WZQ$mEXCJ0I0e?FW`!MdR@7#*v*=cXTg(>}&|cDwXa9zx7tTzwqD!h8=zG z=O{XF_R_>gp0wLmS4X^33N8IK@3Voio{clww@I~GLr816jdY*v-}B{2?wljQ%+(SH zGiS_vHI!iTyegUyK1+-oU~cP#5dvJTtZQEkIfe3*D+TtrPIw2Y>d6Q5L~Fm)V`g4R z5o6`> zxGR|_@KuNsneOjcGV(M3UMlls;)z}_=wN1BS}lQFVoR`P-0Rqj@j* z9oA`NfxHO}Z}*m;LnO!IvgM6(XzmQLn02N0Kev8KKNOUHQ;Mh=a=6;gJwsaVdGezU ze_Tf3%*2c%F-P)a zRq!xc3fRWkI#X{bA)TN6j7HUqwK;-KiDA2=7zS=Y$ijI@AOgOMltU-mLMgbnXN*c* zDU{c?7~U&yia5D19xZ?pF2q$w(+9KMO><|N2^sgsqz`%;>)Y*#9XUVy}LW`E=h1==$;Hbs+u8vT9T6Ci_ zJfN|QScMiRT6s6c2o!a|v1;udLHFEo|{A&Iff`lldnu3-CT> zhkM18Wr?{GJYDxsHwj#TIy>m(MFp4d-+xtcsA{HS@QOf7X*c!rR!GfH8j_=w#0gv( z=6tVA9T!72=n=Y!u5%k-RwaA=khzhO{dGlw{uooHX#Uge2exvS_wuq?^Wyd075E3$ z+2KFEOA0KIT*M1q;i-^f zIE_}E`X`MkE-VH9G#N}C{$fuR=hmvU zA>bGOzT>ph)c-xjz%al(*sNJ}M)u!ph&ko%7!GCw&S1*_X9HqV&l8>ZcGv>s0ZD(^ zPd__^g_I~4k1E96JO!{wHg=rF4{xo_cy;SnXro>X_y-EbjB|PmSQLYM^goQN6Fw91 z0N*h_uALF)gTe$Wg=CZ*zB80imwX3Jx72YaxKPBv6AbVFG8RuPdQn`qW`nJ-peUd8MoO8Yo;Q^?XUw-l?u7TRJ?CqMl<4)@Kb0KIqC`ycJ0dt7GF+?IXA?N=7E z-t$%pPq@vD!j-tE>~p|26cug-Id02R?8xm>mN>HW#4cRh=gUD_8)}`GV>2OnT?BQA z*~KX8%$2OvdZKB!!H2@ks3wp7i-zDC2yFF^_qP!<X1iW*bGPn6cp-atP?vk7fzrir4)z!;$ZP znvy#Cd|TqP8XaGF`^&GXD)BsYQrPpTNrk>|yr916>|oh7^{=BQS+609DlH$;K|?aQ zkLedaU3`(yaOCEdU6{vOU7v$}p~r#}Mkb%5(9*gpV+m=S&h z{PR3}9pXAO|ADwq{y%y8I>2=X{sRz)0r)2$U$?x@Wq&LKDE_fRu9EX_X1k7YJ*EG_ zXrlZ_1pblWuOnRF(0>pvF&y!Go&NFSe>}+RtNRaz2qs7T#`x!2*H**Dun+)1i23?q LIO)q(G6DQQXfZR( literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/table_insert_column_full_width0_base.hwpx b/tests/fixtures/hancom_saved/table_insert_column_full_width0_base.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..8e590b4823d8ce1d62441244180789c679ef11a5 GIT binary patch literal 6213 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 SApqby_8W-hq`He;0r)??M}boS literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/table_insert_column_full_width0_side1.hwpx b/tests/fixtures/hancom_saved/table_insert_column_full_width0_side1.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..b0531402cf784957b8b3c04866846ef10a1d8e29 GIT binary patch literal 6248 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 HD**ooVPKj3 literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/table_insert_column_merge_r0c01_base.hwpx b/tests/fixtures/hancom_saved/table_insert_column_merge_r0c01_base.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..92673fe29777b01065f8b2b50fd3b7de6e547011 GIT binary patch literal 6244 zcmZ`-2Ut@}(+(g=?^Rj|BE1(ux{yFcSc(s=NdKO?++WmZ%&<*Z_!b}$MaB`H9$NT{Q zb3+y+EFc5|!V#88D?5aZEJz;);gB~+Pe3YzsgfB;yF37(|7Or-VR$8u37I4fz z7`>4wS&#_mQkVazb-5ml>_6-y3sU_{Dd0V8YdcFg5OZbY>iE}`-!dRUx&NB)(#mXr zLb}#URXhNI?8e`=S3)Ata0D79XbU&Dg1cOrar;4^%d`afGa6E_a1Kw(ysY5pD7cit z8&wwdk{CTa&}$HgTmdlf%4I`C(A#GP>&a$jAj^|AQSm-$G*%=vyf8ckN|rh$hYvV> zUd~GE@ngxP!%tm1iEx&{$g58Xz!IGB-IG%$on`J+g1CxJ=9Y%@+6&$R^Sz~SSz=Ck z3JZYAIz(PJRc=S8TUNQTz@e@msG?DIiyy{r(j6*(kX&rwugVb59zTwTz>*wac@m%P01VAG(POX2)_AZ1lOoZEW!IjIZWFk#_AHpQ=qlouq4dPHb%4PSF=2$E~*m43X!78!0nWXy_ z8A}OwQ`<~xaDj89w8BiLp{-rIY3$x)>*^H1{mHPEjc5@{nal?abqh|4Vxvx4A_GoT znLW*x6w4Cy+jm^2_4SK8Sj?b`Ba3T~dC@sy{!+_XGDMEyTlSIo=Cwl4{QL^bv!hPM zMOT^{`+~puwFOY+0vQ(M9xp08$3)_z6-cbKmfM^c)tiI(f5z;rtsf6;EaxH;Q?HBd zyjb(&*nN>MclLdJSN_@A@pwej`H%HLGTSb-h41JmOn9)vN``h}Nj%QxXUu!bKzGQb z{YFrP*Ub86-r{;!1|6Py#y+(;O9o0!HM2qbunn+iLydTpXTr!qyT`0k_5C)GCpm#; zKg!(9Ihpe=9Fa7bptB?2D9w$or57h`8e`v_tjQ;?A8uI_;2N*#uG}%vmhk^xd3*0BSZe=B_k7cR;bb6=43le?K02hVEEuT!mp{wgH#i&u)wdL8zhN6$Q#lS3l5 z33PFtm%=omeDMf+b0uv1H4TO^6?`30T&qExj$3BaRyY@y6heJLS|J%vPSPmX>iV%p zWuuII-BuXG8G>nJrbUERdo%aV{2ic{{^uxEDUDU4CV;B*hvx8k97#CIGTrwZY)z4< zTcH$_bRwT(dvQ67%u+%F{j-=Q85!+nrOJ(!$4Sh27cfS+;_>r!DrlC$=L5PjBtAW%jm{!o{b7|NMR4kdNXR`w_A4tr! zqO`xrl0OL7Kk&;3S9kH8;;Gm~IyOsw#%YM_L#;?Mv~nG~QCtMn4l;rWu5XJI#GEu* z#`Rv~9UVW2sn9kia1tN4n5iY->TnoD7~;Dx>NX^M;1=_E-jG$XX?nlhd~5fYNe?*M zR>*XEFU8VtyQN0wu=cUNk(UF_*JCIh&_$2Z>vM6Hs;fSjt)1;lz=m$~{D*TD)|6>M zr<>hfytld4y2q8hjpHLe5s1`hW_%g1NK-|$$My!`+y6XHEUi$R4^Za(xUfs2cDAY; zVk!8xVEsuny+@RwkpXQ-&q3?0a4IR9d-{V^YsPB0hDL97!uz6z9%&Hj5RA|ggmZP2 zdC4(*QQ>EyShDX99_IUfg?PBhC6b1l*1aZHVy{O}r2Yu>=ed0V?lDl4l@b%!wss~c za(g;4Z0pAyv+Nv`Ig>&c#G1P2+4TJ6#Nw$NEX9z$<=t~IF-=c-bZu&CG_FrW#x3Sd zl~F&}8EL2V`=rIqO3e~|fdf00MBtn6QDeJug1wamDb#UfCYl7hbUv##^xZ>rlVj?q z7fS&YgXCXJ{oYCGlh2`cl~`nu$CAriok2-@;cfYv-?%-5GQ*1Bqn*(&@>eW$n)@*&@o zCy4!dgxw~G*CG?sq~5$-8oh>ch^4zzValGt$>VcHnnD8*Wgk5g4YDz)-<}k&F@-m} zj@X>L>Bl4Ciq@>6`$9U9zPBZ!prf~D-8#XK!03_7~ndBt1oMW%l|+iKh!a*DEf z^p$;S{*ALk$O13~o2Y@JR@F#)iPdcK7m2#(Ksb3UHrI{9Bh1?)8cN8%o|t`&v$)GV zP`v`f5C`oeQsx3#jUp zeDE-S=+Kc;%uSv}?bunK?b7M2wWR%#T*RCpLY<_etWb6&8@rXdtu?c&6E|Rese$fY z%=HS13Rrz;)te6myo!5X>>p)#QDfaw6pR*U^m%Wr!bv|Y_7^FE=7=gYH@Uv+Xy%s{ z$hsik1WrE(@53eii;0+G$|td1$TRm@@)t+%J~mrxK0Jp!4Xlis-Yl_YYMCBBUp#YL zztaF?fLlc^yrI(2a=GY=misIXq7Hj}piC7v3!p2ifR1_vJ@184bwdW)2TSH&5h^e{ zvpY&nJ01!CND5(MKi$CtuJUzG3l&lB&N4)bkxhvn4xw(Zs@ zue_Y<V9VksE(VNV3BkfBi;)K;=Nif0qR5IG)%U8QFmQkBX|R8EWBpLbR(e* zKL8At+Y9S%BB|%Z&71X%b#$-ku+YJ=1Db?;WKV1X3%M}zx*3#2<0Cm0RGBaficca| z%I>APU@bl%h)|aIp#v&Ew5WQVh*d-nW<=kTy#{WQAE@Q|xZh15zAe5g!Dv5+ayAXF zg)zOUI$q#HwRdeBrMBhVv~W}-unGV=oRr5~)giK<+m}a{XMj29=(jRTakP3RZY13A zEN&2dGr66O)hn;$8?zcP#q{O8?e=r#+eBs@Xfqq|NIZFNKj{`R-YPjy*H-c7glRqL zqi05YAu;GQOjixw+al55H?+#t(fBvF&UX58@JMp9pW8KZ&UtR^ws*H$T)4NlWX$+g5 zx>I8xUwHD$(Yx_2PoKAkytgxN$&3g=T)VRU`j`oTj!i6as@<`7+yM#$D~>3YG7=iL zXb;GZQH$vY`fb$lR1-@)>jQn;FmI8Jh$|b!@|-$uc_EQ5$Nx6Q#^d_T zEUjBxWjTWTmKFid;6je)(~uA?L!;d^W}^?19~7h|lCuDiXhr96pDn?t{A5I%;bz|Mv zN?p#SjhD+gqQ`F9Qt(ORGyZe60`f@k<2)By<2!^Poy;m++Rx$R4g-mqcDBBlQO$|9@$B|hLcOLzg+=3j;<=9f2iV79#hxYHm7fy24IWzL zPYhOm$W@wRxG1Yi+vb}D?MA+6O-PBd@20drtaB_Q&@QnSdUbx$ToNdqym+5%crQ=Z z`O|<7u`IV&X=63Jd!xwpPpAGzdZS{+Xg!Vu5>1=C#Y7-7K?tvCSd!Q@1MN}oU0h9r55(-0|;jepgJB22j zNtJK-L4y(~9`xe#Szn`FT*e0c8~Ia?bK6G@;$=EbjOkHuG#ZmGqb}LlHKIqWU5FU` zoTEFk6K|DwLCMxj!{-a(_1E@yUc73Y2 zs_&|D-r$EuIpdiJ?1W-%tuM09A?4QcBot?hr}H(j9Jm8`O&Rw78a?daC?JgbA?^s1 zae=!%y(V9GvfkImH`H#L%t>QTT|v!gjqTOCXq(8JX}~NGk~E^B-uaZMkzb7m$-AXJ z%&-w0^(k0yv~v1R`nQQ25A`xy;SSq`JrXlwwZHCY$p3q}objzQ1em2-;$W7HS*|7+ zrpOP~f(Tk-@?dj21SSJ^v9hj?=|T7lk%OOqbQ$yTQPWrS<$I<5TA!8mYZ7;cPnb;Z zi>6Yl3MjR{TC%`-0xF_(>8JI$`xX&@HN-}SlFcSRuE5a5=Ip$fm_?GE)0IOyOL$R~ z(kA(-Q(^y)9Iiyx@z@jn4#w30YO|zU!ZQSx4nfg3eT4!fNzcN3thbj02C5c_G8A-c zm{a<#Ppi*_vU+OeN2znevTf{Ugj;u0l*NV|4(>9PR}W|?%_%ZL4hOPggd8_%i+@)HCCL)Xcf0-0G~Hb3bwVp`fiji{v|%-t^$(Edybl93 zL0dw*{1)WC%j}`|ETC)6c;al$b69%jd!9w(%2%djdV%2i=C&4p2in>9s%FpLw-G~W zabBr@OLzzh<|z74l9q)XKE-*r&WCuRv0u4(gBbztAth;& zE(9+(pC%hU|ElZksFM}!Te>fvUUr~n3ca6Ba1Z<~ad^kC>IV(UQ9|q(t{iKQd#cXk z2kN>Q+a4?iAJa zKY;99>^SG#WYaGmAPZ3&l01m-z^4R-R_0rTJUv6UFx^pGJg~ieR{AnAfrM0F!{Ztc zO?(tt)E10y!N}?ikN*9+AkXn9gNP!v6y>N{o z%?TbXC86W8uF|DhWaa|IdFqI@i+u_iBi1x%54dR#FqCE zd-a{m3HKj7Gxs%ZxIKNv0a+6`MsP3=IE`ulj{{;NkGD>rJ+?6Uv$#ly$)90cgqud_C76k$y4L*-*5Qa*)3a}U+S5J!x z>cT|IMdiSb%M69oh0CDH#v1PE#}pxE(GSEA4W(l9V+u+(Y_SbA4e~fXbuBHi zmS_^yts=&XtashNsPmnMz}8tjmikR?_G}28-D8$-|J(JDykCtUV_Yr((=M~8-*L;y z9ARe-N1-p{wRo61VVe*!ZYij07fGj_vh~F80MKFZitQOsl-|@dXAb%_A#prn_s+07 zonS!o>%~N96d#=o_8f9t>C+NF=+k6|ul$C_;($?FHY66>I5_LmBZvElE(k0r5TtKn zNa@8>kyFi+bT-h$J=Zo|hNZ2Jg-!ieD8Q(MDK1_u>R#Rj0Du4=-^>2LCElx2S1Y=g zbN`l-!u0?yCv literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/table_insert_column_merge_r0c01_side1.hwpx b/tests/fixtures/hancom_saved/table_insert_column_merge_r0c01_side1.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..ba0d08968616c38d262f9416ce4b63f0b5527778 GIT binary patch literal 6285 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/table_insert_column_merge_r0c12_base.hwpx b/tests/fixtures/hancom_saved/table_insert_column_merge_r0c12_base.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..9101839d816b659bbddef9c072d008b704086070 GIT binary patch literal 6241 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/table_insert_column_side0_count1.hwpx b/tests/fixtures/hancom_saved/table_insert_column_side0_count1.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..7c30cb154a41b8e2cd8ccc217ccf25ed169c03d7 GIT binary patch literal 6252 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 KY2xx!0R9hz7?sfg literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/table_insert_column_side1_count1.hwpx b/tests/fixtures/hancom_saved/table_insert_column_side1_count1.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..ca0f5e20f9f8da3a31570366bad5d8b3dca13793 GIT binary patch literal 6248 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 N^}=$}$oZ}S{2y4mnpOY+ literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/table_insert_column_side1_count3.hwpx b/tests/fixtures/hancom_saved/table_insert_column_side1_count3.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..c7283fa41ccebc46a8e3ba55e87eeaefa887e692 GIT binary patch literal 6305 zcmZ`-2UwHK5)ER2(0fs80BJ%(N2>JRLQ?^$p$H^MLRYFFNGE{wB1MXHQBgVw2qGX| z6p-GLF8u}XeR?n7d&#%i-9I~LXD73BGNY%7dzl*W*NY7h^g~{i3OhM(1lZ={=mJN3 zyTYwpU7a0mtk8}~1jND9mCwh~RqtPdVy9U@X>kC6^G1Xf^nkmeu!{w}T%4ulupg{{ zKac?n3P8cEaD)xg))8SZ12!^L;g_dTPtTI0xkpghNHl&a80#0t{in%yLgrI_gkiT~Wv!bo+;b{3k z+RK1VbYV(*FkMAu0|Q+cnAOGV9@0$)EQ%dDBF;yG=OY_8*f|Qr~D!Z_4Mn;qh_s8^+Jn zm^I5V26*77U@-YjK;IL$Wi80VfO#CBm7K@SK8wPlJyK|#SZa7lbh*$tHbG%XRS)U!T>F+09%Lm*+R9 z0b{j@=Xq2G?VTREm1Y9_upn?%z1k|jA-j23r08B+sd2CxLlUDK7pXdR3Lkht)S{#o zccGb9ryiq164!jo(5zp_EKX0aGEb^<^hfD!4`G4)F9bEkqg5Gigr1QU`o@185$l@G zy6v8zph6fW#N$2f&TU&ZnyI&~!YCRbkN0&^#i@LV+wnckfk;xg%_vfgMeN5)Dr^dw zKneHISV^sOgY%$tqRhwDTRy-t*&mWEX;QFmk44Qd#|u$P=iFkbopzBI8FJAP>T{vW z>29*2m=mL4lXM?9GAeCnwp5oNoLRijht3xXzA=|8P2?QCdM}p1>J8K{D5#_|FYZWG zc)qc|Cww!gHI%A=m0?=;{*003#>@hD67cxz-s&hPkOB&P9XXX!DS!v~G&Ewm3Kp5cBqLz|!k9#@ke(+?$9PnEHI z%V9CT--w*qGDsS$Udn_uOm{lTRFa!Z_*H!YcF zJI>0|HH}LFj!5lK)?b&am*PRcp%*1=9A;k`dsRsMZlHNlfP3UsSM|ENo>=hK3*RqH zyId#l-Z-}d`B$^P0pY^j7!wF-ho_}4C+`C0>`14m_a&0}(Gz(lgZ6t|KmEMs(jsEk zKro=|Y?QY8^&|wnmExs)i&_j(ss#GNK-+%Y_G^~owz#J@6wsb9orr9o!%WJ>+FqO? znK;uxkNK<74B@nxaUnsqk2%|x!A|Nn!6ztGIgM?KHh`*gM|{!MRKlSFbuwB<-G@c@38x?A0k$MR+0>De5?OnYMA zT2OjlWyo(u8|?)ZD%X7AJ;GD9k9BU6_=H=R*n^svU})jq_n!&K>+fm}pKtiQb>Uu}2lN8BOsoPpJ)c>zm#y|2iq+Bd$PYr3{^X5OtF z?*O$J|B-GJwATDefB((>d#1ilG*buabgXU$l)j%zU#htqDYLb)eGOfPHGOY5QDsRV zhq!Qbec%)4(dZgcdT5pu(*Y8Cmy`WY~mTuMbwG1zo|OPGUE@d1^3EnoAU1c zQEY5CggxVU*bRVr`jesXw2Czm0rJY0>vE;6CCR!WFM3GLj|`rXJ?_MS6)Y+0T{8!# zKINJ`tP6bjW#Va>O{QrXYwzP6-(eD5)0-K6le?$KGrmVxBw1=}C?;MKR2#V@4w8Qk zJoG_qe@8g3aQe}QEEWAG z9u(Z>ob92%sK?9&H7!AT$|o@S{0O>9#GzOSf5pg(8Kg)jw1xRvz*=Z;NxhoI%vyDp zHzv)B+aW#1O6p~3r7c_|)|1}uN`H$g5t2LpDXLitNhWGp?A#MD8*dS@7R*VDJE^OC zC|<$OMiHgo#mzh>b=`TTgG`RYn%mVjP?Vm1|K znoN_s()e?==C^0@Z_kG1lBjxr9`#iucNL7_j1ddF{4YPe3-h#Alz~H)>z3r$B!9yIr@52;u+_@Y2igVNC z2HV%0zP6Jgy8CCu3*DA@rVHFHHuXTuzHOg}da5NMwoQG3D{pIlg7VqlP2Sb_zKn## z^ll&JyHqL^JepPx+A@YRd>R$kT$ad!KIKqYA_|AQ;hRCbt`x_RpCxxmCXjGd=9~G? z!Y>&$)l|UI)mCyC({|y!Qbr682%18d@@YW<1b(!LY?;gWP^m5!{xQe6=(O#OH&)$X zZh?rxRv8BNG*+;Fp!p_txh>f#*k>(C@L=tWB2(;L3&FA;TF>v@PSD`va`n_#b6;R% zP2cywX;+)A+daC11Y4PM27Kvqb|y_9c9Ptr?U1DDHjma+qA{FU-9c#?y2ofdhPUt4 z6=~tb!xnMC3SIBJPi!TRK$PX{2wRK07KeSDlv-k-JpaCZJXQoDC@xLLeqemgNdo`s znxNtX#lpmd8>>f8WjUUG%#4eyku`iW(zTLL)Hypxd#8`QzV7Xn!a9u)RiEjj*9I4c zukuc!TrHjy#u7gh@v6*|ot{0-ZE-h0=I?qnB*Ig_5Pv=C89KXzpl#AvY#Ju)=5II5U>aQ_^C9Qe z=_xH4ogAmVQwbUEj7{o#+@LtuyefzHYO*)0bs@w>zi#NwR`HQ`&ZWX)_|o$@8IpF- z@)_5?W2nivexz;H<*uYS$wn=1!-g|epCf-~pKo%Uwc8(@ypAM69lc}&2V1_NiQYm4 z!CUlKg<9^{qVCQ{kf*yt!n?Z#FGOORXLdda)OzRw4Jnz5a!h@3%r5uY@>10cnwA5T zIDz#I`wa!z6e7SL8)bR^8t&2bqoW)xIqd~5N)3sWTHWIt~ZtWbfBPP5AUQz<1hsF2}fDK#BE;d79}_?5DKLI6g}+J zmr_IaHuShIwwRhHgW6c(=l$eV&6ku(?Kn}C?YLJU3iWsvCaPY=4kVk)DdSdcWZcasDc$ddf(_9N$+@Gfl^r z7oG_DM)J7ivxP=p7hU0#z!A>M%w%J1l(1=UR|Yd>ACyJNMoFc zdf8XX^hCa0v$tF2<%drc9dIpn%X}L=jg0C~sFtsoC7Gj^3MLfB2&R)uE*I&pvG8i` zt`6R5x?TKo(B9~A@j{ZZxqjWmZuaCLssGgL!Bfqt z)w(Bi!_w~%y5atJ|7$)fvXM0;;(tKL8am)ZHds$8Nt)?pe=ON41(fT z(=X^mVnS*so9luPmRjpZ{_cOxtp<({8b~FLtq)JUzbsFN+-lI_!`{h8*6Pn@dK)J>;(4bxCr)I<(Ts`5 zpN(+NbfHJ@gr}3w4(D4NasExa4Mb;UyjZ%`!?yEWTh9&d;RyGH=(%|q!oAP}XfJd% zkC2*JMKw-*sD~Iif$i0?O}8;>h9Ed`oGo#VkcuS(I|l=M1u=vU@NZ}}3G((1EaZ76 zPK@nQa5Ng5X`{}G+&xBH6IYNt^h_i9U0Rt}Y{eLuw%>FUw^z~Qo&rW)t)T4G*I=nR zq9f3IV&D7un#q%8%srwM{>WB5>dJ1-DKa8tIho1p>{M0=y)Y&Oc`y6b_H4g&!^Vb2 zcykW=XNZzyo)5G5On(p^kIIU>Iev_cFo^(JNAbxW*x*Ro{lQy=W&}?U$bA-ysy>V= z2uFseQrNq(-K~=1v=;Pl>>1l1nPcYrAp6?YSYJ@Y`-{v#v%(1E)~4I8JEu62c=m$& z*=wuQ3%2A+YWW7j9@YjIduZ%|wUrI!`PFq)AU4<}+R71uO`qLt?P@UHh+rtWvj2Ox zVXpuUBl*DVPxPJ|v9L^~@?-}@Nf$h7ET^hcr#8|^6F5mm#gxzP+KqUw67kol*h^Eg z*%u}j-7&X6J}D(;mSE>{=akA7oDrt9PkZ1}(z}z-ox(DbaA?$ibs?16GWD9^H;|1} zSUg7{G*p80I4ZzyZC0S~Vl{|d&h5rEgR`dBA=c1 z6c{RN`m_`$`*JZ*=M@?`R{nT~(yjRz6{*4KZ28+cG|b&>7Og3rF?LVsy93hj zrHSfP_LiFX#!1UP4i{b#49N-}n_6%sq>1dkCHFTSBOxZtZJ%gdcavuHS34#7x3@?~ zEH_bJ0sv~T#fS4U(C`0$=f=ZUAOsv-?J|tI~)Vhlo>Xfiwp&7;c}MO zNmK-VlqkCoH-wXcjN`XU+$hwR*BN>gzeqPOiTNtCB#6?OE&#jx2>23j7_QDOydI)U z3L#KYa3V2YeG~}q9glK%U%JWoJ%B+ySx-!_@|uc?+r<9E3BZR%v(e*4?*XZAThFcQ z=cgFc=mo;RH?=kgJJC+ORkQSa+e)lXi~B@vGx;_+obyFT%4ZJ!E0=5aKBqewh7D)g zrRrEa5>T9U={F=nhtCS|`m;klBg!%*+(02K57JEir(mwm`nlnO<=diJ6?+;M>Lytr zUFFS`f%Tx5J2WIelM{x4vMl+Y8T$8cX~KR^yrXN`AdpkfUfE-Ld-YmgMS<}kQ-*kc zNVbCGO&jjqZ1&tZW3(c)OB3zA{-U<`mdg6+x@$fMn^9>WS%k)CiM^zD0!naXb)j{{ zgJWbfqol^no`d*tc}Pk!38|5m*JWOsq&Tv;Rm1Dkrnbj;^lwifyaydO!{xo^+ULD4 zBZ_7()lHx7(7(HCrhJeX+A+m~meKE|>=y#Lw;3So>u_gZFZEd(MzKW;)97azh@*vJ zZ?47|9=y}%{&D}tb2rNrl_ED8+#t=_uRWANbZ*y>ogX*XBbqXR@A2$fqw*GlX}~H9QSd3dEB$jxIzz!`S8GB zIAVy$OVGMV;JxvuAuYm4F?RvxI|nu6A`qCNP^GY}vhy5633bUFc&z>vPyBs~2+R0e zqWgDlBotzb%9b528EYFqkF3=6AfQ*bP(|t;1g{C(_&$4qQ{V`zx1y6D%ZmmUuL;t7 zW%evI1#j_Mz@F7_-`dEsmh+mlReZ>2aXVC*Z`3JAz=5IyRgi<4m%e7d@q#Uy>?ENT z=om8}pu4KsayB>~l-mk=1^@azoH}DMGvy7@7^+KEga!G|efzXFa9qW3iP>wm*TVjX zJ;>D)GbjFUvmyDW%shDF1Uq7|6lO z4x|Lxn?cOM_LjmxZ7mrVejp{x$;95=#1>)?5(c`1U_eSy5g{uVK{-hooxhPN;UM-f zK`R$wpp}!8gCHB5tE(%kl?fckj@1mpY6HDf%+8jLlbwTu?LSWgQaYJff}F&EYcCAc zRn?GE(@>R^*3?wh08-kSSVN$~KpyxAY=1Z6xEq;4A%Bfbox!%|D$aJMAoxFUy&*7R zASdunm;b1Bw;s6cANCOj%KfDjrK*Jm*bGDozp`|;{cFlUGC($w|C;a4%2a?NqPEX+ zj{pGdCx6>s5@PQJvUh^9S%FN0tx7RkRw+t ziP3xnOaKCL!~jF@pj%38Z@kwKJhrof$UQc=cm|$3Aw&{@iXu|wvD2nSPylCd%PAha zovavk`YNg=qs^h}dk(Mz$U_p3-06fe$mg$kF)FEqXq6l`{F#PK4pt7cx$W}BmH<@qOK@t;il*g#34spHp zu}V{n3}#g83oV0T6@w@>wepXz)pxyS8PIEU=;v-(=h za94SWcLkkiw6%*n$&Ka3$Cfu7nVfRD{RCFCh0tvycB~^&OlsM^e0__`bE2+zxYnAR z20{*f+XM0QC`pz?9G9gWVj@wT#4ycOR@)tx6)P$r6F_g`EU3> z+xO29xjvfM7xlWnn0ViObFvwPZPlZ&bmZhg`bg{SGs#yD{zr5zUStPSl&&&U)?2~v zJ!dz!^OrY!GKn53W*!spkY~aaCU~}R#QUX@1klT zIjn>$%QMH@6Prjru-;H23717t=Rz_cM(m_Do-s%KWroW>5UdiK>2aBkw^28UFfJUW z@8h!eG=e1Lam)-Shg^Twv9X_xyqVt(3|2~Lo}>)G?>Swi%*7}|{gbNq)M3hiXJkM{%m2%G7(o|omegtl5v@CwPk)=qTVY8#@ z?P20$Q0SeIdSej(z6+JJAuIF8L`Axs{nyz3Koskr7fGcR3X6eKbRA3kml8hNFJrj9!H7&U^vv&>V3 z%o86a8%CZZF??3wyCCD{B9ep^VN{oZAxYifG?{i1 zP8#8IivSi17 zooAohW$0oRw@9||4g?MDeMXn2sfT^v7h&uFT$oA_hi#~gx=-Z2Zb{rbLNxVV@#@z~ zAnq{ELaA?!fHuxNY+sUG2y(%{y3-w;tQpZ>pnOQ*@#;LftWnG~=j--)$L56hpo1l(JoJR-E!SX3=8GqD0kzPXkznSDGKNgSumY62`bq4(VeH-?DYz zH2S=mo=Ye(OV=-<91P0x{EmsJFP1hm|MS=Nvgg$kL5jL6+__4W&)RlzV>lx|mmc=V zi}v8{XP(QXq*I!UBI(3RQlVz9c15WNI+u<&;)F#yK)eBBQbI^m@Sru;qo!1*=sFA& zhUSx392ITZpLE&PWd=S91(cv36@Lis9C^joS6rTXy7w+;lFT4-j(;CmvZQ0DurqMgI^F3}kl4 z_UwOAkDeWDnjhyE6Zw4p)zCST9IEEDqc?XFH9x)_m#YzH+v69-EEhC&vDcUS@?O+U z)hBrqBit9hx;rJ6?@y-;>D&*uB;)n=If(p+vv$eqssq4ZO(iBIuPhu-KSA^*fKRex z)rBf+UQB*3N?^m|z~QfGNq#5p8|VTAi8!PVSioW_4T= zFdsEBL%$9uXA6OMgj})vmfw~Wc1SN%ugj%%$yO3!&U zZ{KM}Z)9YmXy0(XfZ3PJ%EDm0)GTP%YwfA8m;~;vqtu-fDx?DZ9VB@g{Bu$3TJ<|V zZ}HZd>=qjKV8~zWxJh2ipe{j6ZS2Oj)p*^-L$qu>-TCKN_%cNw-1H)S3thE*&%`(o zJWPmSN|1_0j3ZK0mkLR?ve{7y?O@pYs=4f%8ndt9pSwdw0{UA@Q9 zlqDH0KIdKzkNn)=Txpr70`0HEt0;D3iN-WqYpyq)hkM9)SMKQ#UjtPm{|(jlj=I)KZ)G5?0Q6Dxa2|=1UE6C8Up$`X8Pw(( zO{b+ldZ9{K9dE(JH{uxV3D#}zlgnsFJ6=(2$i6SbLNgFN9dDxuLJXRB=IephrQumO zhWOjX0<0B3mkT)Pm4X*oB6tWw?IQZZ7z>1Ex7HI2w#ehK6u-JOGUQOkXlx(=C3-t{ zJKQ*L@V#|i`6@l>gemH!e0u~D&aVthv6t#2aq6aEf&%(K0=UYC$+^Bx`0L4sm`v44q+b5}Ilh%@Zq@Mh` zJV#{de5tB;QNmbcB=;ew-!kEan*4_s<0JbD{nB6M=X&|jo)>I;~eX7<^N6-w#|6DUL6p>Bh1U$ zqH!_gS|F5oBinKsI;HH!Rm1X*Pq4Ic%S*EW@X`9^CD=;UclctKK6TFE+n5UhbrQ38 z1t{lRm$$^~74CscGfU&1D}pQU7xcls&c%&2D5w5wv;{*cXUU=5WsF|wy5d5!K99Oj zrRjyG`Jmi7v=Z70m!2wg#?0sqIn3E<^aY?dt!C0j_>}dtGG>Mi=caWYr0`4zD{>|@ z>q6<)wI3N+pd$-TPns9}^ zJidsGXmQ*SpoJLC+@^RuK;kenv}TV*hB293(cQ1bVJUFJD;y-Ad64&+Dx<3?X3&3cZQKP!W5+9&j$`%oBD9s=nB8b%FFiI=X1;pXJ z!qS9==(LUSXR5cki7mSqOe}0~q3E_cXU3ktsZ-;@&Bf0#SN_>S9H+rcl0zVo_I*|4 z`U|cyP9!A3!k#^(G{q$8?DA!P6F3U=ovD==zus)-_{X%4sBY|(i4vFzlf&G+@TJi( z6&Ula9PywI$i9x&}Y%_08VhUv`k;!{3{}h`r&%?!!A5Fee2sOqD%4*bf%;z9F4M4VHAMOGZw%JH%gGtVnS%>*?33Ce17f8LaJ)V zsv{xMEiPdK8-DvOYJJJ*6UB_Y(e{OqGj!GbIiI7I5MpHUFrykDQbvySC*6yOUvC4R z2EWY|atC&b<1BOBcr0(f8psGflnNWfS)NGygcV0TZk{Weu%=o#a$!L<_GZrALEIv@ zF0*9Y^J+Ho(vsv1$BXOA+3iFy?Uu>1`3Y{<_0yfcw}5{$rrRUdr}S{96o$9EG+7M_ zash)}+0>veS|B$kRwp;7&kUS$yk(yeq65*S1A79E^P0JYEl?&4EhCK`?TFnNP{QBBu$Gun>wr=c6 zdEy@swShzeejOW3ncHTObV>~bbJgLnO{L+NCpJ%59N#$CbtpjlS!@{@18Lv8sybDa zA#0Z{fwp%Q>}SS~b8ffUZ||*_F1~FR6~0z8MEIKF>s6N45@(TDkzq4~C%-0OdwALl zHMgjW>9hA^$B};90sZdgt)MOL!~9MyL7ReNA(kc|gm5ikj9+hQ5T%n$!<@HT5201@9o%6Hj*&NGUc$O)z?TQ9Za_N&OCSotO zJD;ux5*R1ba?GNd*#t+^_^=1^V_k=PTkNi|4plCpXNqZ5lcf$?Tvc7OXZO{LjuYgC z=U9SgIokG9rMO3IP9;dntA>;$=fz27&W5sM*lo87MJZXLNs5ow-pf26i^vpznMFw6 zM`hHW)cxKffw<2*1z8BaQRZ~Bg=q$>)a7!$8f9FB<67T{E;fbxv>xZJ{uCw#T6X7L z^Bz=)^sU@4%zt~KQ0P_*-U9%j3VwFGE8qNcZo4xcymG*5zE+u9=;ken83-sJU^rikSs)L%#H z8$w}<6VTdOU9TA@iVr}Mk+8wk+41)Q4bFr+J8z1SE_##5C#vzPmD9@TLg&uj%mI2f z3?{EP+()0!9_5=htu2tI5VM9XwzRkU**u=BmoxUNZ^w{-jQCFOF!3cYhX>`xG@`MocJTdk=k_bhvYnr;_3q_6dxdx)PeH2mo%s79#Gp+PUWT(7tfxLF3Y|6XJ%a2GSRCfn5s}PQvQlc*C5i&R;blO^t{vHJd}m zTH#a?T!iWwntV=N8nsW~Yh5&`(;qkrS* z&A5KmDN}>Q^t^t{6*|t~#$j5>+M)ApTnR0V*O`@E@1kmkn@vNDvz$vr+IE$sh@fZ{ zIMr0m5bcN?Y8?H7=S)u^wjidkWXtM-jOv zglH}IKT$b#@!VvN$9o}tTix=Ku%c)u?=sz}5Z*pjfEBp=00B=le& zG9lTu!UF7?%JdQ4Qd%C;PtTEwm2VoJ^X?NtdPNj0&Bhw6ZK#Lm$ykwF#h83O)XXs7 zK3ayLrik!>;IB{sR|#HGykE(^y9)qN0=#|h`v2B-?@Qe;Yx4z$k z|GR+sm)u{EbAx-=Khf!TIrBci{Y3OPz#;M<0Dq>X_aW{x^KS@h?ElHr_W|xR@Na9C!CYI?{)>?{{SIKp|St~ literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/table_insert_column_vmerge_c1r01_side1.hwpx b/tests/fixtures/hancom_saved/table_insert_column_vmerge_c1r01_side1.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..9d14cbaf9a1ad3ef6180f35e6ed1854340160a4e GIT binary patch literal 6261 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 VBE+*00B{-q_Q7+~+}WuB{2x+dq8I=G literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/table_insert_column_wide_col1_all_base.hwpx b/tests/fixtures/hancom_saved/table_insert_column_wide_col1_all_base.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..a466c947d0b85173553e5b8e8710c5d27830c751 GIT binary patch literal 6234 zcmZ`-1zc0@_a7o9-5@=XuF)tR6Br;Z-J@Z18{MFU2nwSc5fqUY2|+-R6e%euNOuVe zg2aEkp|5;?|Lybao_qJ4?>*1C=Q-bdjvfT}G7aGG4+kJ(NBJf-_T+pJVuz=zCluum zhuXp69I^=Aix!__lKg?Y2FVy901^a5Mvd6pa>*(vap}0hnynzhy9-m z@<5QVD3BfMUU68XJLyWPt2Ql%1EOod?VdDi8FBB7y9R3UV$!*ELkZCVwNb zV?n%-*Ij(%fi5T%{JMyUudlDLiyaooQ`i9}?2b4$%+o_eOcVqX`R8sxc9fkn6s7#z zdU@dOTLx-+2Denz4GnJ@0NFk5++YZKpd?mu^*Wb8=aK^g_LpSu?dsvE>+NX|#r}h} z8-|nziUH4U`NypD^^}%9=dZ zV1<;U4e^0#Kp=$@VDLU-O5YzZe|y&#%3U`1TA{{{-@5e>97AzPC?=aT{<;2^Y$ zjn41ef>mb(L@)EoG?7JMzbJq;HhtHhM=p=`%TFnimmG53+VGXT0)uut3ttN*JfAAf z0VW%~o<5;2?(Fs{tg;k7Fo*zFH*0JN8F5`HU`%C3@Q`WJWC#F9ByCC? zaF^TYbeqv&(!@4XBg-LO%S1iBswX$9CU(lqe8h!|J`vVFpQz5M7kf3im@m3hkw><{AoWbO)5K8vF$@rzUBrz(v0#n9@IZtJYQBPg5K~L&} zzE%gyMJa~O>)se+1vvWtas#2yJ7ZjT7<>P15$B1)^CB>t2X zUutRYkNq0a9z|Wu&N!!VXI>4Cenf~;B6ZYVY=_T7T4RL1qqkO84+qy4i@h>(2qd=d zu0&khzMH3TygR&N7&(j*hvZKcC3!Zda zi+LD0wYvUvezhl`9v_mwMTd9C1$_C`J2YbmQ^^j&iA18U}Di z`+_~&NOw(#$P*;8g4QuZ2SDBZO=sjJg*1V5k$(3oN6RB5 z_XEmFda4zH$k7TN`Frf>F{FL^SP0E0@nQaJT|l_NAuY zBK1DYQe{2i&HVe&mu2<6GVXAIj6H`XMGD5y7S;5&Edv zA?5vLfzk1ObhVx(k*DOi{Zu{0MyLCbmpP&Dyg^fzA6^;1|5f>$&Ml3Lt=!vZR(p$9BOuME)jO^hY?=D7i%9HsLH_6Q>Rb)4j^y`Igl^vtGb*aJW~0=2-py^3Y8@{d z#5ssOFIf#pV(?28u`r?Q?Aw3Koj@&1d&_u;dc{%;&)nj&{Ra>R{qX)NYh}F3okz?BmBJXQTvT0Jtt#pXC>BE+t8G485C&wT^ zPZy#nhbU$$BI;y~DZU`LRaxa=hcb&B-7%Sl3GL5xzVg1a{*hGKq-6i3WBtdw)k7Ci z?_#yBuoIHl8(>A%NQbKMfy~M|Y!vDz=o(@Z66x z9|~^=H-!g(nocWs$h9bEABZjp93#cGP|6wn^8NI9KJe$&>ue3Rl+!N>Ym7ZpK2i*a z9|d^r&3d`6UkjXPW}Y;hRmf$~R*Q4+^(@WaF*&+(qD)(A0;K9^V5WsN#|*fU;WuXs zBsGxO@wI%j235Z;d~sV;AKd?3?p`_3ZrS6Q&S7hjzOt(P{jK{?CinvYOmMlvl1V@A z@-cn_DZE)BDRW!PrHRjz(yQ!tjtS{MX7ZoZ&7Ayz{Yg9=lXH8x1OUKQApn3DOGUqk z2MKjJXM54VsK*?Gz{pUY(9#{ave{dss$Sd|Q->fnu9~6D5SBF}!ZCN%v^Bzr!}J#_ z^6*=;lDxr_GLs%Jng~g~r3VRu8!c#CPB$G=&Dlih?+zty=G4Es=h|VfBF*{J%m1sJ zt%VBkYGJazT(z(1#25@_&126CcMO-LZND79q1GF;B7@o7=Te^GxDh+i6S&2Nk%O>& z`7TGW*kEP0Kw!2IQ%HK#e|W-w3n%sD%$ASrI%Px>K;4s;#gP`2;ErBkM_(?i2gz_CofB4sIm)oJA$kxJ4k8#+eWB6rFEHQW!^Cs8^}z@ zE*mv&P@i#q82{AjJ7q}l##4eZ2uw7$oA2!Tab53~zjCZmAc24V=Oy2KMf{Uqybp1s z^c4d9{V_w5IQBHzWQOMC5NUH@BN6Wppn!^^m?CvBlWcoXWG&lfGW|z`wz}ihV2uT)a`Kl#v5LJ!v)r{e z_o04)-z(s6NSxrP1fbm5O(n7b>!-wPF13$H7_P&u>gc`{pd5WMH?G{=@d-srx0rvT z6L8exwdUf5;h|?A1XmZ8?~x%jfyvWoQ|`1@yuufT-|^?z49%jeXSrS_uh%tQ*2A+T zwg5{r?ejF)%Bg<92IMhN}g+)j^@ja+AAY}$8v1eB7xQ2_%xRj3S z20&jE75gCN`bTS>>F$vM+Yz9{)oE{*N7FW-@_xFs*%MV!+~aXB9Sp*=#A9an=T@0MQneM8@!41K(mk3g~mbmjs+@h)s0n;W(HAwYY zN-~4bNiMlk@(N>*={lsyudHd`vRm7lwE!>YadSv$K0GA}S_HDhlx&xg8@*Ycc|)Vm z!KmiC`!4C|KDxAyKbkoF&@_#znu+xeoo}PBiXL?Al?je~beh>>D?c4a)BsFW2ws_(dVz}9wpw*V2gCL5xLI4h3vsh> zd8c5@i7S{weiGFiDH}@S(USS)o-Z-xv0v$4Z|Su3y({_8Q;TkM23~z2!qz#vu@z9B zP{`2ZNR%wZ>8(IO!~f;%()8Be+x1fl_%b?rXU>i)VY~e4-l8F3oAWtSgfI)eo^Y>& z4vWPo1{(ZbJ6K*spkD_r-dqbQx6;Q+QM>83GBypM$C1eBRbzWU<{l2!RIXUh8KaSi zD9$%Cq4{VK7t!CGM+QCex_+jvLd1hUtI^1IGadZE*`tF}%5@4EEa-oF5VyO;_er@< z`kvLE#|!iO35KmoFa2Jm!StuK+~=o24t?}p^e$aT@PX(=$HCS80zSE@CbvdO0-Z=R z{NN*ssJP0B*Av~y?#76W^l<4hlOM!v%34e5y)Bgo0NRCa{dm)8Fq!~ zma+Si3_-C;4%^(kM`>4bLU_LUoP-ducIk3m5)QCHFy>59O?)n<>v@28v-l{W78N&g zjcKw?mZtvo;>*>l9OXJ2%{;zE=4xIy;}6+H5EU*lisII{Q$qoy*K79G$HNBXOSBS) zHSKurvPGBps|nb-G7s|F$>o0qehl34_P&=jBc-QxdkgRjcdryzY z+y6?ahZ^-IM@((TRqapfCZGCxDhoSQ3g8A@{3gpXXx&=z>PVp9~QpMwxNi&Y{k;dh98;wk0aGmyt-W2n+^5dG2 z+aN;EnbHqtT?a?T{g{@5@>b}O)Mb(>@;) zDr?O3%c)VWD`7rug_WG7H4Sc4u*7~vQ?&n#jUBonzn7QBFpZ=vRNP7E_)!!)d)Cnb zZ~h=o-5x4z?`ORoNZIZhZ`9SZwmcJi5Wyp`En|k&mH=6AIeypakkK`1x&B)gxzBS- zocrQ<-qD+@bELzs0X-^BIWJ>&vi7e`plx!5gr53ZULV+3nkrx3R(v$+%K8i$utHqY z5{hV9y7%Vx{ZJNG`P+EMR*3yl$~*6Eq*@M%|71<#BFI;6EL$pI$9bu&hk*LHLVZQ_ z5I#mwKa?=a4^_h_rXf{XgOe0xJKUX+)>qt3A?QR%Cw})nWB9uVt@dDBkhL)2Pgs(y zhbQl_aOXud3HFGDqEOf(8F|jZ-Vb#kmq8>^XIiUMs|h@OBW7xp%|anFvZzLkeO5B} z`btY3XW-5p-{svV|7q7VQ*8IDrB1ZI|m^+MlvjD%n7xTNSkQwVPG-R0xOX72&l?T389bWp^G#sVcN$bLrvGCn#+;@Xm zs21!jN5$d%ETzQU%K7-DjD%H&lgInojY818IF)l&kZ0+@w<6vQw(;a6<4&gKC>q;L zZqO8wgL_O8SGZ`D4B2sfnA7Hh@Zifi;(R58S1j2BPCsjpMGO1t6-Q}`^D+`T1=9XTq*3FZrMV}F^6iL zlK$yDxwy4fs!ISsEw*cL-oN?v;&$#lZ0kVS1@4q%+?SLkN^wl9<;&R=&85z`-Bw~G z+yGUy6(j|N0@SGbj<&_q@t84Yr3gxmwJpYe)lYIQt5SjLY{`k*$cA-)KpHq$iKzDXqWzWDR}F23tq&c4I{xh3&&%8hQ<>S{=+V%SY^M( z&LzLgUL^~cn&wWwF}!B7R6k6K>Y8Cg$?JDh4T%wXcNoH&n{XHERtIg3;yDt;Y4!6A zrBUJr^-K?q4qxl@?%a`mim=T9m)O$YO3)tGnc&A!6+Nu%saTkX70iL*pMJ3QFswR} zqZcG@8O+t)B-drM^mxRbAuDjJ%7sW&VsXc7=XLjD`fbw?yKtK(X^i5ZF~pXB?ISLB z17fh_|Ji`p%oD8N?{*195t8!Aee%J+QADXm$)IW+!A}6kjmEa)#P?fk7~c+)N}t?#N3T5jBmwXF zCWyf=w|}`ca+lx6;BoVw>2{vIqTd%s)nEY|vnX|e3HJhF7s^UxaRG8kj@x%*n6TN{wKXCE;Uh3!PIpr2=BX>wL_GwO*ak-ax1*kG@{_f8waF<_%rR= z`QeId+Vg`Jxlh2!n$1JgVSNgC*7Pyz*mBF*%A6{Yzq+WFKl6C7h3`xINF|OQ1m_aX zU#S3V61Jsyv6Xv%6#!rdgoU3U|84AE)VkQmJ)irxmMr%8Ph0hTeZLj|cL(z?y}xef zhmEdZ+39yb^CG~-O7u6tS8RRy3*f(X=|zZ(wEP=_hx~t%^hJP+1pFHy1PkzAI=-lR zk;{H-dQ$u+Le7)(FJ`-laWSR;#&}No9}oN|!CyqUxS@X|Y++whe#Pl;EB?oWycpfT gF|J{Q{TIf6V_gq|hh-rE;0pE|h~=c7^IZY>KYUn^*#H0l literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/table_insert_column_wide_col1_all_side1.hwpx b/tests/fixtures/hancom_saved/table_insert_column_wide_col1_all_side1.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..6a030b77b28630713d706e385464a7f10baeb4c2 GIT binary patch literal 6275 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 literal 0 HcmV?d00001 diff --git a/tests/test_insert_column_by_clone.py b/tests/test_insert_column_by_clone.py new file mode 100644 index 00000000..a030960b --- /dev/null +++ b/tests/test_insert_column_by_clone.py @@ -0,0 +1,200 @@ +"""``insert_column_by_clone`` inserts grid columns the way Hancom's column insertion does. + +``tests/fixtures/hancom_saved/table_insert_column_*`` are 3x3 tables made by Hangul (``*_base``) and the +same tables after Hangul inserted columns right (``side0_count1``: left) of a cell of column 1 (the other +files). Hangul's rules: + +- A new column is as wide as the column it is inserted right of, and the table grows by it, past the + text width if need be. +- Each new cell takes the border fill, paragraph shape and character shape of the cell of the same row + in that column, and holds one empty paragraph. +- A cell merged across the new columns grows its colSpan over them (Hangul leaves its stored width as it + was and draws it by the grid), right of a cell merged from the left that ends at the column each new + column gets a cell of its own, and a cell merged down the column is cloned with its rows. + +``blank=True`` gives Hangul's empty cells; by default the new cells keep the text of the cells they +clone, as ``insert_row_by_clone`` does. +""" + +from __future__ import annotations + +import io +import re +import zipfile +from pathlib import Path + +import pytest +from lxml import etree + +from hwpx.document import HwpxDocument +from hwpx.table_patch import TableStructureError, _insert_column_by_clone, apply_table_ops + +HP = "{http://www.hancom.co.kr/hwpml/2011/paragraph}" +FIXTURES = Path(__file__).parent / "fixtures" / "hancom_saved" + + +def _table(data: bytes) -> etree._Element: + with zipfile.ZipFile(io.BytesIO(data)) as archive: + root = etree.fromstring(archive.read("Contents/section0.xml")) + return next(root.iter(HP + "tbl")) + + +def _cells(data: bytes) -> list[list[tuple]]: + """Each row's cells as (row, col, rowSpan, colSpan, width, height, border fill, paragraph shape, + character shape of the first paragraph (0 without a run), text).""" + rows = [] + for tr in _table(data).findall(HP + "tr"): + cells = [] + for tc in tr.findall(HP + "tc"): + addr, span, size = tc.find(HP + "cellAddr"), tc.find(HP + "cellSpan"), tc.find(HP + "cellSz") + paragraph = tc.find(HP + "subList").find(HP + "p") + run = paragraph.find(HP + "run") + cells.append(( + int(addr.get("rowAddr")), int(addr.get("colAddr")), + int(span.get("rowSpan")), int(span.get("colSpan")), + int(size.get("width")), int(size.get("height")), + tc.get("borderFillIDRef"), paragraph.get("paraPrIDRef"), + run.get("charPrIDRef") if run is not None else "0", + "".join(t.text or "" for t in tc.iter(HP + "t")), + )) + rows.append(cells) + return rows + + +def _insert(data: bytes, ref_col: int, count: int = 1, **options) -> bytes: + op = {"op": "insert_column_by_clone", "table_index": 0, "ref_col": ref_col, "count": count, **options} + result = apply_table_ops(data, [op]) + assert result.ok, result.skipped + return result.data + + +def _saved(name: str) -> bytes: + return (FIXTURES / f"table_insert_column_{name}.hwpx").read_bytes() + + +@pytest.mark.parametrize( + ("base", "inserted", "count", "side"), + [ + ("base", "side1_count1", 1, "right"), + ("base", "side1_count3", 3, "right"), + ("base", "side0_count1", 1, "left"), + ("wide_col1_all_base", "wide_col1_all_side1", 1, "right"), + ("merge_r0c01_base", "merge_r0c01_side1", 1, "right"), + ("merge_r0c12_base", "merge_r0c12_side1", 1, "right"), + ("vmerge_c1r01_base", "vmerge_c1r01_side1", 1, "right"), + ("formats_base", "formats_side1", 1, "right"), + ("formats2_base", "formats2_side1", 1, "right"), + ("full_width0_base", "full_width0_side1", 1, "right"), + ], +) +def test_blank_columns_are_the_ones_hancom_inserts(base: str, inserted: str, count: int, side: str) -> None: + data = _insert(_saved(base), 1, count, side=side, blank=True) + + mine, hancom = _cells(data), _cells(_saved(inserted)) + assert _table(data).get("colCnt") == _table(_saved(inserted)).get("colCnt") + assert _table(data).find(HP + "sz").attrib == _table(_saved(inserted)).find(HP + "sz").attrib + without_spanned_widths = [ + [cell[:4] + (None if cell[3] > 1 else cell[4],) + cell[5:] for cell in row] for row in mine + ] + assert without_spanned_widths == [ + [cell[:4] + (None if cell[3] > 1 else cell[4],) + cell[5:] for cell in row] for row in hancom + ] + + +def test_a_cell_merged_across_the_new_column_is_written_as_wide_as_its_columns() -> None: + data = _insert(_saved("merge_r0c12_base"), 1, blank=True) + + merged = _cells(data)[0][1] + assert merged[3] == 3 + assert merged[4] == 3 * 13984 # Hangul keeps the old 27968 and draws the cell by the grid + assert _cells(_saved("merge_r0c12_side1"))[0][1][4] == 2 * 13984 + + +def test_by_default_the_new_cells_keep_the_text_they_clone() -> None: + data = _insert(_saved("formats_base"), 1) + + for row, cells in enumerate(_cells(data)): + assert [cell[9] for cell in cells] == [f"r{row}c0", f"r{row}c1", f"r{row}c1", f"r{row}c2"] + assert [cell[6:9] for cell in _cells(data)[1][1:3]] == [("4", "1", "1"), ("4", "1", "1")] + + +def test_left_of_a_column_merged_cells_follow_the_same_rules() -> None: + document = HwpxDocument.new() + table = document.add_table(rows=2, cols=4) + for row in range(2): + for col in range(4): + table.cell(row, col).text = f"r{row}c{col}" + table.merge_cells("A1:B1") + table.merge_cells("C1:D1") + + data = _insert(document.to_bytes(), 1, side="left") + rows = _cells(data) + assert [cell[1:4] + (cell[9],) for cell in rows[0]] == [(0, 1, 3, "r0c0r0c1"), (3, 1, 2, "r0c2r0c3")] + assert [cell[1] for cell in rows[1]] == [0, 1, 2, 3, 4] + assert rows[1][1][9] == rows[1][2][9] == "r1c1" + + data = _insert(document.to_bytes(), 2, side="left") + rows = _cells(data) + assert [cell[1:4] + (cell[9],) for cell in rows[0]] == [ + (0, 1, 2, "r0c0r0c1"), (2, 1, 1, ""), (3, 1, 2, "r0c2r0c3"), + ] + assert rows[0][1][4] == rows[1][2][4] + + +def test_new_paragraphs_take_ids_unused_in_the_document() -> None: + document = HwpxDocument.new() + table = document.add_table(rows=2, cols=2) + table.cell(0, 0).text = "a" + + data = _insert(document.to_bytes(), 0, count=2) + + with zipfile.ZipFile(io.BytesIO(data)) as archive: + section = archive.read("Contents/section0.xml").decode("utf-8") + ids = re.findall(r']*\bid="(\d+)"', section) + assert len(ids) == len(set(ids)) + + +def _bare_table(zones: str = "") -> str: + rows = "".join( + "" + "".join( + f'' + f"{row}{col}" + f'' + f'' + for col in range(3) + ) + "" + for row in range(2) + ) + return f'{zones}{rows}' + + +def test_cell_zones_move_with_their_columns() -> None: + zones = ( + "" + '' + '' + '' + "" + ) + + table = _insert_column_by_clone(_bare_table(zones), 1) + + found = re.findall(r'startColAddr="(\d+)" endRowAddr="\d+" endColAddr="(\d+)"', table) + assert found == [("0", "0"), ("0", "3"), ("3", "3")] + assert 'colCnt="4"' in table and ' None: + with pytest.raises(TableStructureError, match="out of range"): + _insert_column_by_clone(_bare_table(), 3) + with pytest.raises(TableStructureError, match="side"): + _insert_column_by_clone(_bare_table(), 0, side="above") + nested = _bare_table().replace("00", '00') + with pytest.raises(TableStructureError, match="nested"): + _insert_column_by_clone(nested, 0) + result = apply_table_ops(_saved("base"), [{"op": "insert_column_by_clone", "table_index": 0, "ref_col": 3}]) + assert not result.ok and "out of range" in result.skipped[0].reason From 3b85eec856b22cae53e38d0b82df0ffbef5241be Mon Sep 17 00:00:00 2001 From: airmang <38392618+airmang@users.noreply.github.com> Date: Tue, 6 Oct 2026 17:03:56 +0900 Subject: [PATCH 2/6] docs(changelog): note the addition Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b325c2cb..a0903a4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ 모든 중요한 변경 사항은 이 문서에 기록됩니다. 형식은 [Keep a Changelog](https://keepachangelog.com/ko/1.1.0/)과 [Semantic Versioning](https://semver.org/lang/ko/)을 따릅니다. +## [Unreleased] + +### 추가 + +- 표 구조 편집(`hwpx.table_patch.apply_table_ops`)에 열 삽입 `insert_column_by_clone`을 더한다. 격자 열 + `ref_col`의 오른쪽(`side: "left"`면 왼쪽)에 그 열을 복제한 열 `count`개를 넣는다. + - 새 열은 기준 열과 같은 폭이고, 표는 그만큼 넓어진다. 본문 폭을 넘어도 줄이지 않는다. + - 새 칸은 같은 행 기준 칸의 테두리·문단 모양·글자 모양을 따른다. 글은 행 삽입(`insert_row_by_clone`)처럼 + 복제하고, `blank: true`면 한/글처럼 빈 문단 하나만 둔다. + - 새 열을 가로지르는 합친 칸은 그 열만큼 colSpan과 폭이 는다. 기준 열에서 끝나는(왼쪽이면 시작하는) + 합친 칸 옆에는 그 칸 서식의 빈 칸이 들어가고, 기준 열에서 세로로 합친 칸은 같은 행들에 걸쳐 복제된다. + - 칸 영역(`hp:cellzone`)의 열 주소도 함께 옮긴다. + ## [6.8.0] - 2026-10-06 `import hwpx`가 HWP 5.0 모듈과 `hwpx.tools`를 처음 쓸 때 읽도록 바꿔 가벼워진 릴리스입니다. FormFit은 글꼴 From e184f0bfeffaf8f7a1bb2c2757bbaf59dc124aff Mon Sep 17 00:00:00 2001 From: airmang <38392618+airmang@users.noreply.github.com> Date: Tue, 6 Oct 2026 17:11:45 +0900 Subject: [PATCH 3/6] fix(table): refuse structure edits on cells without an address or a size Tables written by other programs can hold hp:tc elements with their paragraphs straight inside, without hp:subList, hp:cellAddr, hp:cellSpan or hp:cellSz. Deleting a row or a column, inserting rows or columns, setting or fitting column widths and splitting the table stopped on an AssertionError there, and inserting a row or reordering rows refused it for an unrelated reason. _guard_flat, which every one of these edits calls first, now refuses such a table as it refuses one holding a table. Co-Authored-By: Claude Opus 5.5 --- src/hwpx/table_patch.py | 7 +++ .../test_table_ops_cells_without_geometry.py | 61 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 tests/test_table_ops_cells_without_geometry.py diff --git a/src/hwpx/table_patch.py b/src/hwpx/table_patch.py index 93885c2d..e462bc76 100644 --- a/src/hwpx/table_patch.py +++ b/src/hwpx/table_patch.py @@ -854,9 +854,16 @@ def _ss(chunk: str, tag: str, attr: str, val: int) -> str: def _guard_flat(table: str) -> None: + """Refuse a table structure edits cannot handle: one holding a table, or one with a + cell missing the address or size OWPML requires of it.""" # the table's own plus any nested ones; >1 open == nested if len(re.findall(r" 1: raise TableStructureError("nested tables are unsupported for structure edits") + for tc in _S_TC.findall(table): + if None in (_si(tc, "cellAddr", "colAddr"), _si(tc, "cellAddr", "rowAddr"), _si(tc, "cellSz", "width")): + raise TableStructureError( + "a cell without hp:cellAddr or hp:cellSz is unsupported for structure edits" + ) def _parse_table(table: str) -> tuple[str, list[str], str]: diff --git a/tests/test_table_ops_cells_without_geometry.py b/tests/test_table_ops_cells_without_geometry.py new file mode 100644 index 00000000..8ef52937 --- /dev/null +++ b/tests/test_table_ops_cells_without_geometry.py @@ -0,0 +1,61 @@ +"""Table structure edits refuse a table whose cells lack the address or size OWPML requires. + +Such tables turn up in documents written by other programs: ``hp:tc`` holding paragraphs straight, with no +``hp:subList``, ``hp:cellAddr``, ``hp:cellSpan`` or ``hp:cellSz``. Every structure edit used to stop on an +``AssertionError`` there; it now reports the table as refused, as it does a table holding a table. +""" + +from __future__ import annotations + +import io +import re +import zipfile + +import pytest + +from hwpx.document import HwpxDocument +from hwpx.table_patch import apply_table_ops + +SECTION = "Contents/section0.xml" + + +def _document_with_bare_cells() -> bytes: + document = HwpxDocument.new() + table = document.add_table(rows=3, cols=3) + for row in range(3): + for col in range(3): + table.cell(row, col).text = f"r{row}c{col}" + source = io.BytesIO(document.to_bytes()) + target = io.BytesIO() + with zipfile.ZipFile(source) as original, zipfile.ZipFile(target, "w", zipfile.ZIP_DEFLATED) as rewritten: + for info in original.infolist(): + data = original.read(info.filename) + if info.filename == SECTION: + text = data.decode("utf-8") + text = re.sub(r"]*/>", "", text) + data = text.encode("utf-8") + rewritten.writestr(info, data) + return target.getvalue() + + +@pytest.mark.parametrize( + "op", + [ + {"op": "delete_column", "col": 1}, + {"op": "delete_row", "row": 1}, + {"op": "insert_row_by_clone", "ref_row": 0}, + {"op": "insert_block_by_clone", "ref_rows": [0, 1]}, + {"op": "insert_column_by_clone", "ref_col": 0}, + {"op": "set_column_widths", "widths": [1000, 2000, 3000]}, + {"op": "autofit_columns"}, + {"op": "reorder_rows", "order": [2, 1, 0]}, + {"op": "split_table", "split_row": 1}, + ], +) +def test_a_structure_edit_refuses_cells_without_an_address_or_a_size(op: dict) -> None: + data = _document_with_bare_cells() + + result = apply_table_ops(data, [{**op, "table_index": 0}]) + + assert not result.ok + assert "without hp:cellAddr or hp:cellSz" in result.skipped[0].reason From e680d8c19471735f6ff44a0eb7f77bf514339135 Mon Sep 17 00:00:00 2001 From: airmang <38392618+airmang@users.noreply.github.com> Date: Tue, 6 Oct 2026 17:11:46 +0900 Subject: [PATCH 4/6] docs(changelog): note the fix Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0903a4f..3a57b537 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,12 @@ 합친 칸 옆에는 그 칸 서식의 빈 칸이 들어가고, 기준 열에서 세로로 합친 칸은 같은 행들에 걸쳐 복제된다. - 칸 영역(`hp:cellzone`)의 열 주소도 함께 옮긴다. +### 고침 + +- 표 구조 편집(`apply_table_ops`)이 `hp:cellAddr`·`hp:cellSz`가 없는 칸(다른 프로그램이 쓴 표)에서 + `AssertionError`로 멈추거나 엉뚱한 이유로 거부하던 것을 고친다. 행·열 삭제와 삽입, 열 폭 설정과 맞춤, 표 나누기, + 행 순서 바꾸기가 이제 그런 표를 표 안의 표처럼 거부한다. + ## [6.8.0] - 2026-10-06 `import hwpx`가 HWP 5.0 모듈과 `hwpx.tools`를 처음 쓸 때 읽도록 바꿔 가벼워진 릴리스입니다. FormFit은 글꼴 From 741a201521df984941d425aa66f2432eff257121 Mon Sep 17 00:00:00 2001 From: airmang <38392618+airmang@users.noreply.github.com> Date: Tue, 6 Oct 2026 18:02:26 +0900 Subject: [PATCH 5/6] fix(table): refuse deleting every row or every column of a table delete_column on the only column of a one-column table, or on every column, stopped on a ZeroDivisionError sharing out the freed width among no columns left. delete_row on every row left a table without rows and refused it only for the grid it left. Hangul does not delete the last row or column either; both now refuse and point to delete_table. Co-Authored-By: Claude Opus 5.5 --- src/hwpx/table_patch.py | 8 +++++ tests/test_table_ops_delete_every_line.py | 44 +++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 tests/test_table_ops_delete_every_line.py diff --git a/src/hwpx/table_patch.py b/src/hwpx/table_patch.py index e462bc76..85c0f72a 100644 --- a/src/hwpx/table_patch.py +++ b/src/hwpx/table_patch.py @@ -977,6 +977,10 @@ def _delete_columns(table: str, del_cols: Iterable[int]) -> str: ncol = max(widths) + 1 freed = sum(widths[c] for c in del_cols) survivors = [c for c in range(ncol) if c not in del_cols] + if not survivors: + raise TableStructureError( + "delete_column: deleting every column would leave no table -- delete the table instead (delete_table)" + ) targets = [c for c in survivors if c > dmax and c != survivors[-1]] or survivors add, rem = divmod(freed, len(targets)) nw = {c: widths[c] for c in survivors} @@ -1061,6 +1065,10 @@ def _delete_rows(table: str, del_rows: Iterable[int]) -> str: _guard_flat(table) del_rows = sorted(set(del_rows), reverse=True) prefix, rows, suffix = _parse_table(table) + if set(range(len(rows))) <= set(del_rows): + raise TableStructureError( + "delete_row: deleting every row would leave no table -- delete the table instead (delete_table)" + ) for empty in del_rows: if empty >= len(rows): raise TableStructureError(f"row index {empty} out of range") diff --git a/tests/test_table_ops_delete_every_line.py b/tests/test_table_ops_delete_every_line.py new file mode 100644 index 00000000..40eef023 --- /dev/null +++ b/tests/test_table_ops_delete_every_line.py @@ -0,0 +1,44 @@ +"""Deleting every row or every column of a table is refused, as Hangul refuses it. + +Hangul does not delete the only column of a one-column table or the only row of a one-row table: the table +stays as it was. ``delete_column`` used to stop on a ``ZeroDivisionError`` there, and ``delete_row`` refused +it for an unrelated reason (the grid it left). Both now point to ``delete_table``. +""" + +from __future__ import annotations + +import pytest + +from hwpx.document import HwpxDocument +from hwpx.table_patch import apply_table_ops + + +def _document(rows: int, cols: int) -> bytes: + document = HwpxDocument.new() + table = document.add_table(rows=rows, cols=cols) + table.cell(0, 0).text = "a" + return document.to_bytes() + + +@pytest.mark.parametrize( + ("rows", "cols", "op"), + [ + (2, 1, {"op": "delete_column", "col": 0}), + (2, 3, {"op": "delete_column", "cols": [0, 1, 2]}), + (1, 2, {"op": "delete_row", "row": 0}), + (3, 2, {"op": "delete_row", "rows": [2, 0, 1]}), + ], +) +def test_deleting_every_row_or_column_is_refused(rows: int, cols: int, op: dict) -> None: + data = _document(rows, cols) + + result = apply_table_ops(data, [{**op, "table_index": 0}]) + + assert not result.ok + assert result.data == data + assert "would leave no table" in result.skipped[0].reason and "delete_table" in result.skipped[0].reason + + +def test_deleting_all_but_one_still_works() -> None: + assert apply_table_ops(_document(2, 3), [{"op": "delete_column", "cols": [0, 1], "table_index": 0}]).ok + assert apply_table_ops(_document(3, 2), [{"op": "delete_row", "rows": [0, 1], "table_index": 0}]).ok From 1a216fc082f90462c12ec4e25e8ee394fff32167 Mon Sep 17 00:00:00 2001 From: airmang <38392618+airmang@users.noreply.github.com> Date: Tue, 6 Oct 2026 18:02:29 +0900 Subject: [PATCH 6/6] docs(changelog): note the fix Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a57b537..8a9f0705 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,9 @@ - 표 구조 편집(`apply_table_ops`)이 `hp:cellAddr`·`hp:cellSz`가 없는 칸(다른 프로그램이 쓴 표)에서 `AssertionError`로 멈추거나 엉뚱한 이유로 거부하던 것을 고친다. 행·열 삭제와 삽입, 열 폭 설정과 맞춤, 표 나누기, 행 순서 바꾸기가 이제 그런 표를 표 안의 표처럼 거부한다. +- 표의 열을 모두 지우는 `delete_column`(1열 표의 열 포함)이 `ZeroDivisionError`로 멈추던 것을 고친다. 행을 모두 + 지우는 `delete_row`도 남는 격자 탓으로만 거부했다. 한/글도 마지막 행·열은 지우지 않는다. 이제 둘 다 거부하고 + `delete_table`을 쓰라고 알린다. ## [6.8.0] - 2026-10-06