diff --git a/corpus/paragraph-edit/README.md b/corpus/paragraph-edit/README.md index a79e9aa4b4ff5b1ccd19c5624b398bc504a4e85d..bd0c08d60565a9d42b08016c4b3067b6c9966feb 100644 --- a/corpus/paragraph-edit/README.md +++ b/corpus/paragraph-edit/README.md @@ -37,3 +37,14 @@ typing checks extend the preexisting empty run in an independent expected model. `tools/test_paragraph_edit.py` verifies these controls without a VM. The native join captures establish behavior for subsequent join implementation. Identical captured files link to one canonical copy within this corpus. + +`join-edges`, authored with `tools/native/paragraph-joins.ps1`, adds five native +Backspace cases for differing inherited styles, tags on either side and children +on both sides. A nonempty left paragraph keeps its own tags; right-only tags +disappear from the active result. An empty tagged left paragraph transfers its +tags onto the adopted right text. A left paragraph with children joins through +its last descendant, and the right children become that descendant's peers. +The untouched parent's text gains a timestamp and `0x880034dd`, as in the earlier +native controls; its content and other properties stay unchanged. The test fixes +these observed graph, identity and metadata effects alongside independent native +character-style comparisons. diff --git a/corpus/paragraph-edit/join-edges/before/notebook/Open Notebook.onetoc2 b/corpus/paragraph-edit/join-edges/before/notebook/Open Notebook.onetoc2 new file mode 100644 index 0000000000000000000000000000000000000000..d023391977cfdc5d71f4d8ec81881038cea09def Binary files /dev/null and b/corpus/paragraph-edit/join-edges/before/notebook/Open Notebook.onetoc2 differ diff --git a/corpus/paragraph-edit/join-edges/before/notebook/synthetic.one b/corpus/paragraph-edit/join-edges/before/notebook/synthetic.one new file mode 100644 index 0000000000000000000000000000000000000000..cc807cba0c4c53884d5878614b115f0216c67fb3 Binary files /dev/null and b/corpus/paragraph-edit/join-edges/before/notebook/synthetic.one differ diff --git a/corpus/paragraph-edit/join-edges/before/read/environment.json b/corpus/paragraph-edit/join-edges/before/read/environment.json new file mode 100644 index 0000000000000000000000000000000000000000..489d7862505b701972a6db71fbb23dae03c1b7d5 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/before/read/environment.json @@ -0,0 +1,7 @@ +{ + "powershell": "5.1.14409.1005", + "schema": "xs2010", + "hostname": "ONE-M6-680BB09B", + "cold": false, + "onenote": "14.0.4763.1000" +} diff --git a/corpus/paragraph-edit/join-edges/before/read/hierarchy.xml b/corpus/paragraph-edit/join-edges/before/read/hierarchy.xml new file mode 100644 index 0000000000000000000000000000000000000000..99a3411ed2a5e046c3b0d7e62a63fc0591d4794e --- /dev/null +++ b/corpus/paragraph-edit/join-edges/before/read/hierarchy.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/paragraph-edit/join-edges/before/read/page-000.xml b/corpus/paragraph-edit/join-edges/before/read/page-000.xml new file mode 100644 index 0000000000000000000000000000000000000000..f967b0dbee6563a1ef7beff0fef1fbc9c38062db --- /dev/null +++ b/corpus/paragraph-edit/join-edges/before/read/page-000.xml @@ -0,0 +1,5 @@ + +Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/join-edges/before/read/page-001.xml b/corpus/paragraph-edit/join-edges/before/read/page-001.xml new file mode 100644 index 0000000000000000000000000000000000000000..89917544fadec5e6cf26f5427c4a64244639dcb0 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/before/read/page-001.xml @@ -0,0 +1,5 @@ + +Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/join-edges/before/read/page-002.xml b/corpus/paragraph-edit/join-edges/before/read/page-002.xml new file mode 100644 index 0000000000000000000000000000000000000000..96625efbfa7cce18b409c6923c0007475d8112c4 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/before/read/page-002.xml @@ -0,0 +1,4 @@ + +Right italic]]> diff --git a/corpus/paragraph-edit/join-edges/before/read/page-003.xml b/corpus/paragraph-edit/join-edges/before/read/page-003.xml new file mode 100644 index 0000000000000000000000000000000000000000..4e1367f7c7ba2e7498b80508f484d38b0e842688 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/before/read/page-003.xml @@ -0,0 +1,5 @@ + +Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/join-edges/before/read/page-004.xml b/corpus/paragraph-edit/join-edges/before/read/page-004.xml new file mode 100644 index 0000000000000000000000000000000000000000..b59a189075e43f7b71273c98444cd3d02f782504 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/before/read/page-004.xml @@ -0,0 +1,20 @@ + +Bold 🦀 italic é color 東京
+End
]]>
Fictitious: café, 東京, مرحبا]]>
diff --git a/corpus/paragraph-edit/join-edges/before/read/page-005.xml b/corpus/paragraph-edit/join-edges/before/read/page-005.xml new file mode 100644 index 0000000000000000000000000000000000000000..abb22ebd9a21ee77cc0b9f7e97fb2a0f170c8bd1 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/before/read/page-005.xml @@ -0,0 +1,5 @@ + +Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/join-edges/before/read/payloads.json b/corpus/paragraph-edit/join-edges/before/read/payloads.json new file mode 120000 index 0000000000000000000000000000000000000000..3cf45dc1acb611d7f764e0340d73e87192f81407 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/before/read/payloads.json @@ -0,0 +1 @@ +../../../before/read/payloads.json \ No newline at end of file diff --git a/corpus/paragraph-edit/join-edges/cases.json b/corpus/paragraph-edit/join-edges/cases.json new file mode 100644 index 0000000000000000000000000000000000000000..840144cd822bb67eefa757d31a1af1293bb7d321 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/cases.json @@ -0,0 +1,27 @@ +[ + { + "body": "\u003cone:OE quickStyleIndex=\"0\"\u003e\u003cone:T\u003eLeft \u003c/one:T\u003e\u003c/one:OE\u003e\u003cone:OE quickStyleIndex=\"1\"\u003e\u003cone:T\u003e\u003c![CDATA[Right \u003ci\u003eitalic\u003c/i\u003e]]\u003e\u003c/one:T\u003e\u003c/one:OE\u003e", + "name": "Join inherited styles", + "page": "{E046973C-CAEF-4B56-BEA4-93E05E43212A}{1}{B0}" + }, + { + "body": "\u003cone:OE\u003e\u003cone:Tag index=\"0\" completed=\"true\" disabled=\"false\" creationDate=\"2020-01-02T03:04:05.000Z\" completionDate=\"2020-01-02T04:05:06.000Z\"/\u003e\u003cone:T\u003e\u003c![CDATA[]]\u003e\u003c/one:T\u003e\u003c/one:OE\u003e\u003cone:OE\u003e\u003cone:T\u003e\u003c![CDATA[\u003cb\u003eBold\u003c/b\u003e \u003ci\u003eitalic\u003c/i\u003e 🦀 é \u003cspan style=\"color:#123456\"\u003etail\u003c/span\u003e]]\u003e\u003c/one:T\u003e\u003c/one:OE\u003e", + "name": "Join empty left tag", + "page": "{C06F80E1-9B07-4035-B55C-3144C1873BD1}{1}{B0}" + }, + { + "body": "\u003cone:OE\u003e\u003cone:T\u003eLeft \u003c/one:T\u003e\u003c/one:OE\u003e\u003cone:OE\u003e\u003cone:Tag index=\"0\" completed=\"true\" disabled=\"false\" creationDate=\"2020-01-02T03:04:05.000Z\" completionDate=\"2020-01-02T04:05:06.000Z\"/\u003e\u003cone:T\u003e\u003c![CDATA[\u003cb\u003eBold\u003c/b\u003e \u003ci\u003eitalic\u003c/i\u003e 🦀 é \u003cspan style=\"color:#123456\"\u003etail\u003c/span\u003e]]\u003e\u003c/one:T\u003e\u003c/one:OE\u003e", + "name": "Join right tag", + "page": "{3266A6F4-4313-4C8D-8103-7D8EC811E889}{1}{B0}" + }, + { + "body": "\u003cone:OE\u003e\u003cone:Tag index=\"0\" completed=\"true\" disabled=\"false\" creationDate=\"2020-01-02T03:04:05.000Z\" completionDate=\"2020-01-02T04:05:06.000Z\"/\u003e\u003cone:T\u003eLeft \u003c/one:T\u003e\u003c/one:OE\u003e\u003cone:OE\u003e\u003cone:Tag index=\"0\" completed=\"true\" disabled=\"false\" creationDate=\"2020-01-02T03:04:05.000Z\" completionDate=\"2020-01-02T04:05:06.000Z\"/\u003e\u003cone:T\u003e\u003c![CDATA[\u003cb\u003eBold\u003c/b\u003e \u003ci\u003eitalic\u003c/i\u003e 🦀 é \u003cspan style=\"color:#123456\"\u003etail\u003c/span\u003e]]\u003e\u003c/one:T\u003e\u003c/one:OE\u003e", + "name": "Join both tags", + "page": "{55922D45-C0E9-41E5-BCE7-ECBE10331C71}{1}{B0}" + }, + { + "body": "\u003cone:OE\u003e\u003cone:T\u003eLeft \u003c/one:T\u003e\u003cone:OEChildren\u003e\u003cone:OE\u003e\u003cone:T\u003eLeft child\u003c/one:T\u003e\u003c/one:OE\u003e\u003c/one:OEChildren\u003e\u003c/one:OE\u003e\u003cone:OE\u003e\u003cone:T\u003e\u003c![CDATA[\u003cb\u003eBold\u003c/b\u003e \u003ci\u003eitalic\u003c/i\u003e 🦀 é \u003cspan style=\"color:#123456\"\u003etail\u003c/span\u003e]]\u003e\u003c/one:T\u003e\u003cone:OEChildren\u003e\u003cone:OE\u003e\u003cone:T\u003eRight child\u003c/one:T\u003e\u003c/one:OE\u003e\u003c/one:OEChildren\u003e\u003c/one:OE\u003e", + "name": "Join both children", + "page": "{E151A4C0-B88B-4EFD-8F87-D3269DE420CD}{1}{B0}" + } +] diff --git a/corpus/paragraph-edit/join-edges/joined/notebook/Open Notebook.onetoc2 b/corpus/paragraph-edit/join-edges/joined/notebook/Open Notebook.onetoc2 new file mode 120000 index 0000000000000000000000000000000000000000..a6c7d197861f52dda5ecaf4da2ab7e471f409518 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/notebook/Open Notebook.onetoc2 @@ -0,0 +1 @@ +../../before/notebook/Open Notebook.onetoc2 \ No newline at end of file diff --git a/corpus/paragraph-edit/join-edges/joined/notebook/synthetic.one b/corpus/paragraph-edit/join-edges/joined/notebook/synthetic.one new file mode 100644 index 0000000000000000000000000000000000000000..f59ef79305782e7e6077bc333c5066b56f9574d2 Binary files /dev/null and b/corpus/paragraph-edit/join-edges/joined/notebook/synthetic.one differ diff --git a/corpus/paragraph-edit/join-edges/joined/read/environment.json b/corpus/paragraph-edit/join-edges/joined/read/environment.json new file mode 120000 index 0000000000000000000000000000000000000000..032ba3b41dd4114f7b416f0781d9c5fb61796d7f --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/read/environment.json @@ -0,0 +1 @@ +../../before/read/environment.json \ No newline at end of file diff --git a/corpus/paragraph-edit/join-edges/joined/read/hierarchy.xml b/corpus/paragraph-edit/join-edges/joined/read/hierarchy.xml new file mode 100644 index 0000000000000000000000000000000000000000..927fbf217fb5e9e1db532760fd5e109b159d08e1 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/read/hierarchy.xml @@ -0,0 +1,2 @@ + + diff --git a/corpus/paragraph-edit/join-edges/joined/read/page-000.xml b/corpus/paragraph-edit/join-edges/joined/read/page-000.xml new file mode 100644 index 0000000000000000000000000000000000000000..2671bb457460e8c7f80b0075f2242542857c7ff9 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/read/page-000.xml @@ -0,0 +1,5 @@ + +Bold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/join-edges/joined/read/page-001.xml b/corpus/paragraph-edit/join-edges/joined/read/page-001.xml new file mode 100644 index 0000000000000000000000000000000000000000..7d04fff63cb57e7d0cff194734bd2ceaeddf9892 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/read/page-001.xml @@ -0,0 +1,5 @@ + +Left childBold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/join-edges/joined/read/page-002.xml b/corpus/paragraph-edit/join-edges/joined/read/page-002.xml new file mode 100644 index 0000000000000000000000000000000000000000..7aa663cc47655e1675aa18349a93b1781f55761a --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/read/page-002.xml @@ -0,0 +1,5 @@ + +LeftRight italic]]> diff --git a/corpus/paragraph-edit/join-edges/joined/read/page-003.xml b/corpus/paragraph-edit/join-edges/joined/read/page-003.xml new file mode 100644 index 0000000000000000000000000000000000000000..188674e9d65132dd94c774a6ad7b89c2ae3e0d31 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/read/page-003.xml @@ -0,0 +1,5 @@ + +LeftBold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/join-edges/joined/read/page-004.xml b/corpus/paragraph-edit/join-edges/joined/read/page-004.xml new file mode 100644 index 0000000000000000000000000000000000000000..b93528c8638797b1e2a92890559d0a69cbd4e33e --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/read/page-004.xml @@ -0,0 +1,20 @@ + +Bold 🦀 italic é color 東京
+End
]]>
Fictitious: café, 東京, مرحبا]]>
diff --git a/corpus/paragraph-edit/join-edges/joined/read/page-005.xml b/corpus/paragraph-edit/join-edges/joined/read/page-005.xml new file mode 100644 index 0000000000000000000000000000000000000000..e3255b10a8bfe0665b0111ed083c0510050b8d2b --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/read/page-005.xml @@ -0,0 +1,5 @@ + +LeftBold italic 🦀 é tail]]> diff --git a/corpus/paragraph-edit/join-edges/joined/read/payloads.json b/corpus/paragraph-edit/join-edges/joined/read/payloads.json new file mode 120000 index 0000000000000000000000000000000000000000..3cf45dc1acb611d7f764e0340d73e87192f81407 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/read/payloads.json @@ -0,0 +1 @@ +../../../before/read/payloads.json \ No newline at end of file diff --git a/corpus/paragraph-edit/join-edges/joined/ui/join-both-children.ahk b/corpus/paragraph-edit/join-edges/joined/ui/join-both-children.ahk new file mode 100644 index 0000000000000000000000000000000000000000..8a6180d1a96bf8a92da22309ca1a4308aa24d83b --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/ui/join-both-children.ahk @@ -0,0 +1,22 @@ +#Requires AutoHotkey v2.0 +OnError((exception, mode) => (FileAppend(exception.Message, "**"), ExitApp(1))) +dm := Buffer(220, 0) +NumPut("UShort", 220, dm, 68) +if !DllCall("EnumDisplaySettingsW", "Ptr", 0, "UInt", 0xFFFFFFFF, "Ptr", dm) + throw Error("Cannot inspect display mode") +NumPut("UInt", NumGet(dm, 72, "UInt") | 0x180000, dm, 72) +NumPut("UInt", 1280, dm, 172) +NumPut("UInt", 720, dm, 176) +if DllCall("ChangeDisplaySettingsW", "Ptr", dm, "UInt", 0, "Int") != 0 + throw Error("Display mode rejected") +app := ComObject("OneNote.Application") +app.NavigateTo("{36F927E2-894E-46B6-9880-230A50839CFA}{1}{B0}", "{E2A450C5-7596-4142-BBC7-E4EDC8853D7E}{50}{B0}", false) +hwnd := WinWait("ahk_class Framework::CFrame ahk_exe ONENOTE.EXE",, 10) +if !hwnd + throw Error("OneNote window did not appear") +WinMaximize(hwnd) +WinActivate(hwnd) +if !WinWaitActive(hwnd,, 10) + throw Error("OneNote window did not become active") +Sleep 300 +Send "{Left}{Backspace}" diff --git a/corpus/paragraph-edit/join-edges/joined/ui/join-both-children.json b/corpus/paragraph-edit/join-edges/joined/ui/join-both-children.json new file mode 100644 index 0000000000000000000000000000000000000000..c145a5219f90d58969dea8f1672bddc2dc08f1cc --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/ui/join-both-children.json @@ -0,0 +1,13 @@ +{ + "exit": 0, + "stdout": "", + "stderr": "", + "w": 1280, + "h": 720, + "error": null, + "win": { + "title": "Join both children - Microsoft OneNote", + "class": "Framework::CFrame", + "dialog": false + } +} \ No newline at end of file diff --git a/corpus/paragraph-edit/join-edges/joined/ui/join-both-children.png b/corpus/paragraph-edit/join-edges/joined/ui/join-both-children.png new file mode 100644 index 0000000000000000000000000000000000000000..11d5749a7f4e63ff56fafdc44ec573737e5d923f Binary files /dev/null and b/corpus/paragraph-edit/join-edges/joined/ui/join-both-children.png differ diff --git a/corpus/paragraph-edit/join-edges/joined/ui/join-both-tags.ahk b/corpus/paragraph-edit/join-edges/joined/ui/join-both-tags.ahk new file mode 100644 index 0000000000000000000000000000000000000000..6bf932f7d6dc66e079a65425136943bc105551bf --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/ui/join-both-tags.ahk @@ -0,0 +1,22 @@ +#Requires AutoHotkey v2.0 +OnError((exception, mode) => (FileAppend(exception.Message, "**"), ExitApp(1))) +dm := Buffer(220, 0) +NumPut("UShort", 220, dm, 68) +if !DllCall("EnumDisplaySettingsW", "Ptr", 0, "UInt", 0xFFFFFFFF, "Ptr", dm) + throw Error("Cannot inspect display mode") +NumPut("UInt", NumGet(dm, 72, "UInt") | 0x180000, dm, 72) +NumPut("UInt", 1280, dm, 172) +NumPut("UInt", 720, dm, 176) +if DllCall("ChangeDisplaySettingsW", "Ptr", dm, "UInt", 0, "Int") != 0 + throw Error("Display mode rejected") +app := ComObject("OneNote.Application") +app.NavigateTo("{823AAE67-F12C-49AE-ABE0-1C92DD54A046}{1}{B0}", "{9B7130D0-DD0F-4C6F-963D-61C5A203C4F9}{46}{B0}", false) +hwnd := WinWait("ahk_class Framework::CFrame ahk_exe ONENOTE.EXE",, 10) +if !hwnd + throw Error("OneNote window did not appear") +WinMaximize(hwnd) +WinActivate(hwnd) +if !WinWaitActive(hwnd,, 10) + throw Error("OneNote window did not become active") +Sleep 300 +Send "{Left}{Backspace}" diff --git a/corpus/paragraph-edit/join-edges/joined/ui/join-both-tags.json b/corpus/paragraph-edit/join-edges/joined/ui/join-both-tags.json new file mode 100644 index 0000000000000000000000000000000000000000..81917744462c1be7d4d8960c06222ced468894f5 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/ui/join-both-tags.json @@ -0,0 +1,13 @@ +{ + "exit": 0, + "stdout": "", + "stderr": "", + "w": 1280, + "h": 720, + "error": null, + "win": { + "title": "Join both tags - Microsoft OneNote", + "class": "Framework::CFrame", + "dialog": false + } +} \ No newline at end of file diff --git a/corpus/paragraph-edit/join-edges/joined/ui/join-both-tags.png b/corpus/paragraph-edit/join-edges/joined/ui/join-both-tags.png new file mode 100644 index 0000000000000000000000000000000000000000..a75d48789845585d48b8e0a6ae8ef7c8b8705995 Binary files /dev/null and b/corpus/paragraph-edit/join-edges/joined/ui/join-both-tags.png differ diff --git a/corpus/paragraph-edit/join-edges/joined/ui/join-empty-left-tag.ahk b/corpus/paragraph-edit/join-edges/joined/ui/join-empty-left-tag.ahk new file mode 100644 index 0000000000000000000000000000000000000000..d85358e5a459ffaab2e149433533a8b0b7ba4ca4 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/ui/join-empty-left-tag.ahk @@ -0,0 +1,22 @@ +#Requires AutoHotkey v2.0 +OnError((exception, mode) => (FileAppend(exception.Message, "**"), ExitApp(1))) +dm := Buffer(220, 0) +NumPut("UShort", 220, dm, 68) +if !DllCall("EnumDisplaySettingsW", "Ptr", 0, "UInt", 0xFFFFFFFF, "Ptr", dm) + throw Error("Cannot inspect display mode") +NumPut("UInt", NumGet(dm, 72, "UInt") | 0x180000, dm, 72) +NumPut("UInt", 1280, dm, 172) +NumPut("UInt", 720, dm, 176) +if DllCall("ChangeDisplaySettingsW", "Ptr", dm, "UInt", 0, "Int") != 0 + throw Error("Display mode rejected") +app := ComObject("OneNote.Application") +app.NavigateTo("{17C703C3-AAC2-487E-A25B-C1680CE087E6}{1}{B0}", "{6A8F6379-AECA-4275-B007-DDA813F1CDA8}{47}{B0}", false) +hwnd := WinWait("ahk_class Framework::CFrame ahk_exe ONENOTE.EXE",, 10) +if !hwnd + throw Error("OneNote window did not appear") +WinMaximize(hwnd) +WinActivate(hwnd) +if !WinWaitActive(hwnd,, 10) + throw Error("OneNote window did not become active") +Sleep 300 +Send "{Left}{Backspace}" diff --git a/corpus/paragraph-edit/join-edges/joined/ui/join-empty-left-tag.json b/corpus/paragraph-edit/join-edges/joined/ui/join-empty-left-tag.json new file mode 100644 index 0000000000000000000000000000000000000000..398f3c6030cda2789b80cd651b35e239bab6e965 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/ui/join-empty-left-tag.json @@ -0,0 +1,13 @@ +{ + "exit": 0, + "stdout": "", + "stderr": "", + "w": 1280, + "h": 720, + "error": null, + "win": { + "title": "Join empty left tag - Microsoft OneNote", + "class": "Framework::CFrame", + "dialog": false + } +} \ No newline at end of file diff --git a/corpus/paragraph-edit/join-edges/joined/ui/join-empty-left-tag.png b/corpus/paragraph-edit/join-edges/joined/ui/join-empty-left-tag.png new file mode 100644 index 0000000000000000000000000000000000000000..44e64b4973c5c39dd61e67973874bf679c5448f1 Binary files /dev/null and b/corpus/paragraph-edit/join-edges/joined/ui/join-empty-left-tag.png differ diff --git a/corpus/paragraph-edit/join-edges/joined/ui/join-inherited-styles.ahk b/corpus/paragraph-edit/join-edges/joined/ui/join-inherited-styles.ahk new file mode 100644 index 0000000000000000000000000000000000000000..04379e37e708b70b8f85af7cbead46430714795f --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/ui/join-inherited-styles.ahk @@ -0,0 +1,22 @@ +#Requires AutoHotkey v2.0 +OnError((exception, mode) => (FileAppend(exception.Message, "**"), ExitApp(1))) +dm := Buffer(220, 0) +NumPut("UShort", 220, dm, 68) +if !DllCall("EnumDisplaySettingsW", "Ptr", 0, "UInt", 0xFFFFFFFF, "Ptr", dm) + throw Error("Cannot inspect display mode") +NumPut("UInt", NumGet(dm, 72, "UInt") | 0x180000, dm, 72) +NumPut("UInt", 1280, dm, 172) +NumPut("UInt", 720, dm, 176) +if DllCall("ChangeDisplaySettingsW", "Ptr", dm, "UInt", 0, "Int") != 0 + throw Error("Display mode rejected") +app := ComObject("OneNote.Application") +app.NavigateTo("{37EE141E-FB2A-431D-A9A3-63CC93249D1D}{1}{B0}", "{F1B58AF6-82D4-4DC3-8AA6-D7E96816F6B8}{46}{B0}", false) +hwnd := WinWait("ahk_class Framework::CFrame ahk_exe ONENOTE.EXE",, 10) +if !hwnd + throw Error("OneNote window did not appear") +WinMaximize(hwnd) +WinActivate(hwnd) +if !WinWaitActive(hwnd,, 10) + throw Error("OneNote window did not become active") +Sleep 300 +Send "{Left}{Backspace}" diff --git a/corpus/paragraph-edit/join-edges/joined/ui/join-inherited-styles.json b/corpus/paragraph-edit/join-edges/joined/ui/join-inherited-styles.json new file mode 100644 index 0000000000000000000000000000000000000000..fba53a8629f4cde3fad5f2c896208c90b5f5e821 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/ui/join-inherited-styles.json @@ -0,0 +1,13 @@ +{ + "exit": 0, + "stdout": "", + "stderr": "", + "w": 1280, + "h": 720, + "error": null, + "win": { + "title": "Join inherited styles - Microsoft OneNote", + "class": "Framework::CFrame", + "dialog": false + } +} \ No newline at end of file diff --git a/corpus/paragraph-edit/join-edges/joined/ui/join-inherited-styles.png b/corpus/paragraph-edit/join-edges/joined/ui/join-inherited-styles.png new file mode 100644 index 0000000000000000000000000000000000000000..47c8bb38b6f9a9628710fd199895e28299575ed7 Binary files /dev/null and b/corpus/paragraph-edit/join-edges/joined/ui/join-inherited-styles.png differ diff --git a/corpus/paragraph-edit/join-edges/joined/ui/join-right-tag.ahk b/corpus/paragraph-edit/join-edges/joined/ui/join-right-tag.ahk new file mode 100644 index 0000000000000000000000000000000000000000..4eb66ffd7994849eaa58c9144a34e54b9eb7ae7d --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/ui/join-right-tag.ahk @@ -0,0 +1,22 @@ +#Requires AutoHotkey v2.0 +OnError((exception, mode) => (FileAppend(exception.Message, "**"), ExitApp(1))) +dm := Buffer(220, 0) +NumPut("UShort", 220, dm, 68) +if !DllCall("EnumDisplaySettingsW", "Ptr", 0, "UInt", 0xFFFFFFFF, "Ptr", dm) + throw Error("Cannot inspect display mode") +NumPut("UInt", NumGet(dm, 72, "UInt") | 0x180000, dm, 72) +NumPut("UInt", 1280, dm, 172) +NumPut("UInt", 720, dm, 176) +if DllCall("ChangeDisplaySettingsW", "Ptr", dm, "UInt", 0, "Int") != 0 + throw Error("Display mode rejected") +app := ComObject("OneNote.Application") +app.NavigateTo("{E5CE25D6-72D6-44C6-9604-8DA2057654BE}{1}{B0}", "{CFBA859A-3493-4F22-86CF-0EEDA377AB77}{45}{B0}", false) +hwnd := WinWait("ahk_class Framework::CFrame ahk_exe ONENOTE.EXE",, 10) +if !hwnd + throw Error("OneNote window did not appear") +WinMaximize(hwnd) +WinActivate(hwnd) +if !WinWaitActive(hwnd,, 10) + throw Error("OneNote window did not become active") +Sleep 300 +Send "{Left}{Backspace}" diff --git a/corpus/paragraph-edit/join-edges/joined/ui/join-right-tag.json b/corpus/paragraph-edit/join-edges/joined/ui/join-right-tag.json new file mode 100644 index 0000000000000000000000000000000000000000..37aa92991abef20749ea9e29e3ca454262ef4037 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/ui/join-right-tag.json @@ -0,0 +1,13 @@ +{ + "exit": 0, + "stdout": "", + "stderr": "", + "w": 1280, + "h": 720, + "error": null, + "win": { + "title": "Join right tag - Microsoft OneNote", + "class": "Framework::CFrame", + "dialog": false + } +} \ No newline at end of file diff --git a/corpus/paragraph-edit/join-edges/joined/ui/join-right-tag.png b/corpus/paragraph-edit/join-edges/joined/ui/join-right-tag.png new file mode 100644 index 0000000000000000000000000000000000000000..4be97a38c858f2e0499b81f1a52fabd46976a2ee Binary files /dev/null and b/corpus/paragraph-edit/join-edges/joined/ui/join-right-tag.png differ diff --git a/corpus/paragraph-edit/join-edges/joined/ui/selections.json b/corpus/paragraph-edit/join-edges/joined/ui/selections.json new file mode 100644 index 0000000000000000000000000000000000000000..58c25cd1e88f44c8214b10b34caa2073051db63f --- /dev/null +++ b/corpus/paragraph-edit/join-edges/joined/ui/selections.json @@ -0,0 +1,32 @@ +[ + { + "case": "Join inherited styles", + "page": "{37EE141E-FB2A-431D-A9A3-63CC93249D1D}{1}{B0}", + "object": "{F1B58AF6-82D4-4DC3-8AA6-D7E96816F6B8}{46}{B0}", + "keys": "{Left}{Backspace}" + }, + { + "case": "Join empty left tag", + "page": "{17C703C3-AAC2-487E-A25B-C1680CE087E6}{1}{B0}", + "object": "{6A8F6379-AECA-4275-B007-DDA813F1CDA8}{47}{B0}", + "keys": "{Left}{Backspace}" + }, + { + "case": "Join right tag", + "page": "{E5CE25D6-72D6-44C6-9604-8DA2057654BE}{1}{B0}", + "object": "{CFBA859A-3493-4F22-86CF-0EEDA377AB77}{45}{B0}", + "keys": "{Left}{Backspace}" + }, + { + "case": "Join both tags", + "page": "{823AAE67-F12C-49AE-ABE0-1C92DD54A046}{1}{B0}", + "object": "{9B7130D0-DD0F-4C6F-963D-61C5A203C4F9}{46}{B0}", + "keys": "{Left}{Backspace}" + }, + { + "case": "Join both children", + "page": "{36F927E2-894E-46B6-9880-230A50839CFA}{1}{B0}", + "object": "{E2A450C5-7596-4142-BBC7-E4EDC8853D7E}{50}{B0}", + "keys": "{Left}{Backspace}" + } +] \ No newline at end of file diff --git a/corpus/paragraph-edit/join-edges/run.json b/corpus/paragraph-edit/join-edges/run.json new file mode 100644 index 0000000000000000000000000000000000000000..97553900c2f7590444a9073ac2ef243db9870db1 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/run.json @@ -0,0 +1,19 @@ +{ + "notebook": "/Users/clo/dev/one/corpus/formatted-insertion/native-paragraph/candidate", + "expected_pages": 6, + "author": "evidence/m10/native-paragraph-edges.ps1", + "author_timeout_seconds": 600, + "inspect": true, + "collect_notebook": true, + "base": { + "file": "win7-office-base.qcow2", + "format": "qcow2", + "sha256": "a1a4f8fab782ee14885ff801ca2f6347c208fdcfc3513637096f314315c89346", + "virtual_size": 68719476736 + }, + "scripts": { + "author.ps1": "9c9f9f172794e7be6aeee910731ac50d0db8130799ced1bcc8f4f5c4a37a4932", + "cold.ps1": "c177fc72ae6c2634d186f5671a880de20b09f9716532c37c69cb13aa15c7e331", + "read.ps1": "04013bfcccee40a17e2a225f9b9e96f40a3a8daad9e350609654f8eda3ccbb41" + } +} diff --git a/corpus/paragraph-edit/join-edges/source.json b/corpus/paragraph-edit/join-edges/source.json new file mode 120000 index 0000000000000000000000000000000000000000..dc7b60fc7e02133267116c3c170c237f8123e471 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/source.json @@ -0,0 +1 @@ +../split/source.json \ No newline at end of file diff --git a/corpus/paragraph-edit/join-edges/teardown.json b/corpus/paragraph-edit/join-edges/teardown.json new file mode 120000 index 0000000000000000000000000000000000000000..8b4fa29c76b0c84be8e3815d693a242cc55fbf90 --- /dev/null +++ b/corpus/paragraph-edit/join-edges/teardown.json @@ -0,0 +1 @@ +../joined/teardown.json \ No newline at end of file diff --git a/tools/native/paragraph-joins.ps1 b/tools/native/paragraph-joins.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..6226b0f3498544449ef3d1986c0e3beaa845f920 --- /dev/null +++ b/tools/native/paragraph-joins.ps1 @@ -0,0 +1,40 @@ +param([Parameter(Mandatory=$true)][string]$Root, [Parameter(Mandatory=$true)][string]$CloneHost) +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' +& "$PSScriptRoot\cold-current.ps1" -Root $Root -CloneHost $CloneHost +$app = New-Object -ComObject OneNote.Application +$notebook = '' +try { + $app.OpenHierarchy((Join-Path $Root 'notebook'), '', [ref]$notebook, 0) + $section = '' + $app.OpenHierarchy('synthetic.one', $notebook, [ref]$section, 0) + $mixed = 'Bold italic ' + [char]::ConvertFromUtf32(0x1F980) + ' e' + [char]0x0301 + ' tail' + $text = '' + $child = 'Preserved child' + $tag = '' + $cases = @( + @{ name = 'Join inherited styles'; body = 'Left italic]]>' }, + @{ name = 'Join empty left tag'; body = '' + $tag + '' + $text + '' }, + @{ name = 'Join right tag'; body = 'Left ' + $tag + $text + '' }, + @{ name = 'Join both tags'; body = '' + $tag + 'Left ' + $tag + $text + '' }, + @{ name = 'Join both children'; body = 'Left Left child' + $text + 'Right child' } + ) + $inputs = Join-Path $Root 'inputs' + New-Item -ItemType Directory -Path $inputs | Out-Null + foreach ($case in $cases) { + $page = '' + $app.CreateNewPage($section, [ref]$page, 0) + $xml = '' + $case.name + '' + $case.body + 'Preserved sibling' + [IO.File]::WriteAllText((Join-Path $inputs ($case.name + '.xml')), $xml, [Text.Encoding]::UTF8) + $app.UpdatePageContent($xml, [DateTime]::MinValue, 1, $true) + $case.page = $page + } + $cases | ConvertTo-Json -Depth 6 | Set-Content (Join-Path $Root 'cases.json') -Encoding UTF8 + $app.SyncHierarchy($notebook) +} finally { + if ($notebook) { $app.CloseNotebook($notebook, $false) } + [void][Runtime.InteropServices.Marshal]::FinalReleaseComObject($app) + $app = $null + [GC]::Collect() + [GC]::WaitForPendingFinalizers() +} diff --git a/tools/test_paragraph_edit.py b/tools/test_paragraph_edit.py index e14d5c3ae8d591f8d8469a6dd4cee120ea85e337..4813b927f421f18a8c24b9859ec77d372412985b 100644 --- a/tools/test_paragraph_edit.py +++ b/tools/test_paragraph_edit.py @@ -17,6 +17,61 @@ compare = runpy.run_path(str(ROOT / 'tools/verify-document.py'))['compare'] class ParagraphEditTest(unittest.TestCase): + def test_native_joins_preserve_inherited_styles_and_follow_tag_and_child_rules(self): + fixture = FIXTURE / 'join-edges' + models, captures = {}, {} + with TemporaryDirectory() as temporary: + for phase in ('before', 'joined'): + folder = Path(temporary) / phase + shutil.copytree(fixture / phase / 'read', folder / 'read') + compare(fixture / phase / 'notebook', folder / 'read') + subprocess.run([EXPORTER, fixture / phase / 'notebook/synthetic.one', folder / 'model'], check=True) + model = json.loads((folder / 'model/document.json').read_text()) + models[phase] = {r['nodes'][r['roots']['2']]['kind']['title']: (r, page) + for _, _, r, page in ordered_pages(model)} + captures[phase] = {} + for path in (folder / 'read').glob('page-*.xml'): + page = ET.parse(path).getroot() + captures[phase][page.get('name')] = native_characters(page, page.findall('one:Outline', ns)) + self.assertEqual(len(models[phase]), 6) + cases = json.loads((fixture / 'cases.json').read_text(encoding='utf-8-sig')) + self.assertEqual(len(cases), 5) + for case in cases: + name = case['name'] + with self.subTest(case=name): + old, page = models['before'][name] + new, new_page = models['joined'][name] + self.assertEqual(page, new_page) + outline, = [oid for oid in old['nodes'][page]['children'] if old['nodes'][oid]['kind']['type'] == 'Outline'] + left, right, sibling = old['nodes'][outline]['children'] + self.assertEqual(new['nodes'][outline]['children'], [left, sibling]) + target = old['nodes'][left]['children'][-1] if name == 'Join both children' else left + a, = old['nodes'][target]['content'] + b, = old['nodes'][right]['content'] + empty = old['nodes'][a]['kind']['text'] == '' + survivor = b if empty else a + self.assertEqual(new['nodes'][target]['content'], [survivor]) + self.assertEqual(new['nodes'][survivor]['kind']['text'], old['nodes'][a]['kind']['text'] + old['nodes'][b]['kind']['text']) + self.assertEqual(new['nodes'][survivor]['tags'], old['nodes'][a]['tags']) + children = old['nodes'][left]['children'] + old['nodes'][right]['children'] + self.assertEqual(new['nodes'][left]['children'], children) + self.assertEqual(new['nodes'][sibling], old['nodes'][sibling]) + if name == 'Join both children': + parent_text, = old['nodes'][left]['content'] + original = old['nodes'][parent_text] + current = new['nodes'][parent_text] + self.assertGreater(current['modified'], original['modified']) + expected = {**original, 'modified': current['modified'], + 'extra': [original['extra'][0] + [{'id': 0x880034dd, 'value': 'NoData'}]]} + self.assertEqual(current, expected) + before = [v for paragraph in captures['before'][name] for v in paragraph] + after = [v for paragraph in captures['joined'][name] for v in paragraph] + for (a, old_style), (b, new_style) in zip(before, after, strict=True): + self.assertEqual(a, b) + for key in old_style.keys() | new_style.keys(): + default = 'automatic' if key in ('color', 'highlight') else False + self.assertEqual(old_style.get(key, default), new_style.get(key, default)) + def test_rust_splits_match_native_controls_and_preserve_empty_typing_styles(self): fixture = FIXTURE / 'rust-split' manifest = json.loads((fixture / 'manifest.json').read_text())