| 1 | # Rust hyperlink authoring |
| 2 | |
| 3 | `candidate/` is the page writer's output for |
| 4 | `a_link_is_added_to_a_fresh_page_and_reads_back` in |
| 5 | `crates/onestore/tests/page_links.rs`: on a section created in Rust, the |
| 6 | paragraph "Read about Rust" gains a hyperlink the way OneNote stores one, a |
| 7 | hidden field-code run `U+FDDF HYPERLINK "https://example.invalid/rust"` and |
| 8 | the visible label "the Rust site", both flagged as hyperlink runs. The text |
| 9 | and formatting writers treat such runs as ordinary text with flags; equations, |
| 10 | embedded objects and runs with associated data stay refused. |
| 11 | |
| 12 | `cold/` is a fresh OneNote 2010 read: the paragraph text is |
| 13 | `Read about Rust <a href="https://example.invalid/rust">the Rust site</a>`. |
| 14 | `tools/test_link_edit.py` checks this without a VM. Regenerate with |
| 15 | `ONESTORE_LINK_EXPORT` set to a new absolute directory while running the test, |
| 16 | then cold-open it with `tools/native_runner.py OUTPUT COLD --expected-pages 1 |
| 17 | --collect-notebook`. |
| 18 | |
| 19 | ## Internal links |
| 20 | |
| 21 | `native-links/` is OneNote 2010 adding links to a page, to a paragraph on it |
| 22 | and to the section on the Rust-authored page above through the COM API |
| 23 | (`tools/native/page-link.ps1`; `links.json` holds the `onenote:///…` URLs |
| 24 | `GetHyperlinkToObject` returned, `update.xml` the submitted page). In |
| 25 | `notebook/`, OneNote stored each as a `HYPERLINK` field code with the |
| 26 | relative form `onenote:#Link%20target&section-id={section file identity} |
| 27 | &page-id={page notebook-management identity}&end&base-path=<section path>`; |
| 28 | a paragraph link ends with `&object-id={paragraph identity}&n` instead of |
| 29 | `&end`, and a section link has neither title nor page. OneNote rewrote the |
| 30 | target outline after linking, so its own paragraph link names an identity |
| 31 | (`n` 28) the current outline no longer holds. |
| 32 | |
| 33 | `internal/candidate` is the writer's output for |
| 34 | `a_page_links_to_another_page_and_its_paragraph` in |
| 35 | `crates/onestore/tests/page_links.rs`: a section created in Rust with a |
| 36 | second page, whose first page links to that page and to its first paragraph |
| 37 | with URLs built by `onestore::page::link::internal_link`. `internal/cold` is |
| 38 | its cold read with both links. Regenerate with |
| 39 | `ONESTORE_INTERNAL_LINK_EXPORT` and cold-open with `--expected-pages 2`. |
| 40 | |
| 41 | ## Typed links |
| 42 | |
| 43 | `native-typed/` is OneNote 2010 typing on the Rust-authored page above, driven by |
| 44 | `tools/native_links.py` (`links.ahk` the AutoHotkey session, `links.png` the |
| 45 | desktop afterwards). Each URL typed and ended by a space or Enter became a link |
| 46 | of its own text, a hyperlink run with no field code and no label flag: `http`, |
| 47 | `https`, `ftp`, `file`, `mailto`, `news` and `onenote` schemes, `www.` and |
| 48 | `\\server\share` paths. Trailing punctuation and an unmatched closing bracket |
| 49 | stay outside; `me@example.com` and `example.com` stay text. The Link dialog |
| 50 | (Ctrl+K) on the word at the caret, on a selection and on nothing stored the |
| 51 | address as typed (`example.net/x`, which the COM read shows as |
| 52 | `http://example.net/x`) in a hidden field code before a label flagged as one, |
| 53 | the address itself when the text was empty; text typed after a label is plain. |
| 54 | Remove Link (Shift+F10, R) left the URL as plain text, its runs' link flag |
| 55 | false. An interactive session on a copy showed the rest: a click on a link opens |
| 56 | it at once, typing straight after a link of its own text extends it and its |
| 57 | address, and Copy Link to Page puts |
| 58 | `onenote:///<section path>#<title>&section-id={…}&page-id={…}&end` on the |
| 59 | clipboard (`&object-id={…}&n` in place of `&end` for Copy Link to Paragraph), |
| 60 | which pastes as a labelled link. `crates/canvas/src/editor/link.rs` replays |
| 61 | the session through the editor and compares every paragraph's link runs. |
| 62 | |
| 63 | ## Links and equations from the editor |
| 64 | |
| 65 | `editor/candidate` is the canvas editor's output for |
| 66 | `crates/canvas/tests/links_equations.rs` on the internal-link section above: |
| 67 | URLs typed and ended by a space or Enter, the Link dialog on a selection, on the |
| 68 | word at the caret and on nothing, links to the other page and to a paragraph, |
| 69 | Remove Link, and equations typed after Alt+= (one switched to Linear, one after |
| 70 | text in its paragraph), all saved as the ops the editor recorded. |
| 71 | `editor/cold` is its cold OneNote 2010 read: `tools/test_link_edit.py` |
| 72 | compares it with the candidate and checks the links and MathML in |
| 73 | `editor/expected.json`. OneNote's read opens an address without a scheme over |
| 74 | http and links URL text again when it opens a page; its own section does the |
| 75 | same after Remove Link (`native-typed/cold`, its cold read, shows `Gone |
| 76 | ftp://h.example/f` linked again). Regenerate with |
| 77 | `CANVAS_LINKS_EQUATIONS_EXPORT` set to a new directory, move `expected.json` |
| 78 | beside the candidate, and cold-open with `--expected-pages 2 --screenshots`. |