| 1 | param([Parameter(Mandatory=$true)][string]$Root, [Parameter(Mandatory=$true)][string]$CloneHost) |
| 2 | Set-StrictMode -Version Latest |
| 3 | $ErrorActionPreference = 'Stop' |
| 4 | & "$PSScriptRoot\cold-current.ps1" -Root $Root -CloneHost $CloneHost |
| 5 | $histories = Get-Content (Join-Path $Root 'notebook\histories.json') -Raw -Encoding UTF8 | ConvertFrom-Json |
| 6 | $inputs = Join-Path $Root 'inputs' |
| 7 | New-Item -ItemType Directory -Path $inputs | Out-Null |
| 8 | $app = New-Object -ComObject OneNote.Application |
| 9 | $notebookId = '' |
| 10 | $namespace = 'http://schemas.microsoft.com/office/onenote/2010/onenote' |
| 11 | try { |
| 12 | $app.OpenHierarchy((Join-Path $Root 'notebook'), '', [ref]$notebookId, 0) |
| 13 | $sectionId = '' |
| 14 | $app.OpenHierarchy('synthetic.one', $notebookId, [ref]$sectionId, 0) |
| 15 | foreach ($history in $histories) { |
| 16 | $pageId = '' |
| 17 | $app.CreateNewPage($sectionId, [ref]$pageId, 0) |
| 18 | $state = $history.initial |
| 19 | $paragraphs = New-Object Collections.ArrayList |
| 20 | foreach ($paragraph in $state.paragraphs) { [void]$paragraphs.Add($paragraph) } |
| 21 | $ids = @{} |
| 22 | $outlineId = '' |
| 23 | for ($step = -1; $step -lt $history.operations.Count; $step++) { |
| 24 | if ($step -ge 0) { |
| 25 | $op = $history.operations[$step] |
| 26 | switch ($op.kind) { |
| 27 | 'insert' { $paragraphs.Insert($op.index, $op.paragraph) } |
| 28 | 'delete' { $paragraphs.RemoveAt($op.index) } |
| 29 | 'move' { $paragraph = $paragraphs[$op.index]; $paragraphs.RemoveAt($op.index); $paragraphs.Insert($op.to, $paragraph) } |
| 30 | 'position' { $state.x = $op.x; $state.y = $op.y } |
| 31 | 'cell' { $state.table[$op.row][$op.column] = $op.text } |
| 32 | default { $property = $op.kind; $paragraphs[$op.index].$property = $op.value } |
| 33 | } |
| 34 | } |
| 35 | $xml = '<one:Page xmlns:one="' + $namespace + '" ID="' + $pageId + '"><one:TagDef index="0" type="0" symbol="3" fontColor="automatic" highlightColor="none" name="History checkbox"/><one:Title><one:OE><one:T>' + $history.title + '</one:T></one:OE></one:Title><one:Outline' |
| 36 | if ($outlineId) { $xml += ' objectID="' + $outlineId + '"' } |
| 37 | $xml += '><one:Position x="' + $state.x + '" y="' + $state.y + '"/><one:Size width="480" height="100"/><one:OEChildren>' |
| 38 | foreach ($paragraph in $paragraphs) { |
| 39 | $xml += '<one:OE' |
| 40 | if ($ids.ContainsKey($paragraph.id)) { $xml += ' objectID="' + $ids[$paragraph.id] + '"' } |
| 41 | $xml += '>' |
| 42 | if ($paragraph.tag) { $xml += '<one:Tag index="0" completed="false" disabled="false" creationDate="2020-01-02T03:04:05.000Z"/>' } |
| 43 | $decoration = @() |
| 44 | if ($paragraph.underline) { $decoration += 'underline' } |
| 45 | if ($paragraph.strike) { $decoration += 'line-through' } |
| 46 | if ($decoration.Count -eq 0) { $decoration = @('none') } |
| 47 | $style = 'font-family:Calibri;font-size:' + $paragraph.font_size + 'pt;font-weight:' + $(if ($paragraph.bold) {'bold'} else {'normal'}) + ';font-style:' + $(if ($paragraph.italic) {'italic'} else {'normal'}) + ';text-decoration:' + ($decoration -join ' ') + ';color:' + $paragraph.color + ';background:' + $paragraph.highlight |
| 48 | $html = '<span style="' + $style + '">' + [Security.SecurityElement]::Escape($paragraph.text) + '</span>' |
| 49 | if ($paragraph.link) { $html = '<a href="' + [Security.SecurityElement]::Escape($paragraph.link) + '">' + $html + '</a>' } |
| 50 | $xml += '<one:T><![CDATA[' + $html + ']]></one:T></one:OE>' |
| 51 | } |
| 52 | $xml += '<one:OE><one:Table bordersVisible="true"><one:Columns><one:Column index="0" width="180" isLocked="true"/><one:Column index="1" width="180" isLocked="true"/></one:Columns>' |
| 53 | foreach ($row in $state.table) { |
| 54 | $xml += '<one:Row>' |
| 55 | foreach ($cell in $row) { $xml += '<one:Cell><one:OEChildren><one:OE><one:T><![CDATA[' + [Security.SecurityElement]::Escape($cell) + ']]></one:T></one:OE></one:OEChildren></one:Cell>' } |
| 56 | $xml += '</one:Row>' |
| 57 | } |
| 58 | $xml += '</one:Table></one:OE></one:OEChildren></one:Outline></one:Page>' |
| 59 | [IO.File]::WriteAllText((Join-Path $inputs ('{0:d6}-{1:d2}.xml' -f $history.seed, ($step + 1))), $xml, [Text.Encoding]::UTF8) |
| 60 | $app.UpdatePageContent($xml, [DateTime]::MinValue, 1, $true) |
| 61 | $content = '' |
| 62 | $app.GetPageContent($pageId, [ref]$content, 3, 1) |
| 63 | [xml]$document = $content |
| 64 | $manager = New-Object Xml.XmlNamespaceManager($document.NameTable) |
| 65 | $manager.AddNamespace('one', $namespace) |
| 66 | $outline = $document.SelectSingleNode('/one:Page/one:Outline', $manager) |
| 67 | $outlineId = $outline.GetAttribute('objectID') |
| 68 | $objects = @($outline.SelectNodes('one:OEChildren/one:OE[one:T]', $manager)) |
| 69 | if ($objects.Count -ne $paragraphs.Count) { throw "Native paragraph count changed at seed $($history.seed), step $step." } |
| 70 | for ($index = 0; $index -lt $paragraphs.Count; $index++) { $ids[$paragraphs[$index].id] = $objects[$index].GetAttribute('objectID') } |
| 71 | $log = @{ seed = $history.seed; step = $step; page = $pageId; outline = $outlineId } | ConvertTo-Json -Compress |
| 72 | [IO.File]::AppendAllText((Join-Path $Root 'operations.jsonl'), $log + [Environment]::NewLine, [Text.Encoding]::UTF8) |
| 73 | } |
| 74 | } |
| 75 | $app.SyncHierarchy($notebookId) |
| 76 | $app.CloseNotebook($notebookId, $false) |
| 77 | $notebookId = '' |
| 78 | } finally { |
| 79 | if ($notebookId) { $app.CloseNotebook($notebookId, $false) } |
| 80 | [void][Runtime.InteropServices.Marshal]::FinalReleaseComObject($app) |
| 81 | [GC]::Collect() |
| 82 | [GC]::WaitForPendingFinalizers() |
| 83 | } |