Export Supernote keywords as tags and links as Wikilinks - #122
Closed
philips-clanker wants to merge 1 commit into
Closed
Export Supernote keywords as tags and links as Wikilinks#122philips-clanker wants to merge 1 commit into
philips-clanker wants to merge 1 commit into
Conversation
Surfaces two supernote-typescript features (sn.keywords, sn.links - see the submodule bump this stacks on) as Obsidian-native constructs in exported markdown: - Starred keywords become Obsidian tags (e.g. #My_Keyword) on the correct page, derived from the KEYWORD footer key's page prefix (more reliable than KEYWORDPAGE, which can be '0'/invalid) - rather than as a flat list at the top of the document. Deduplicated against tags already present in the page's OCR text. - Supernote internal links become Wikilinks on the correct page, ordered top-to-bottom by sorting LINKO keys (the key encodes the Y coordinate after the page prefix). The library already resolves same-document page anchors (ILink.text gets "#Page N" appended); this adds cross-file anchor resolution by loading the target .note file from the vault and looking up its PAGEID, with a per-call cache to avoid re-parsing the same target multiple times. Both gated behind a new "Convert supernote keywords to tags and links to wikilinks" setting, on by default. Split out of #81 (by @Floper), ported onto the current settings.ts declarative API and current main.ts VaultWriter shape, and built on the now-current supernote-typescript link/keyword parsing API rather than #81's own (never-merged) version of it.
This was referenced Jul 27, 2026
philips-clanker
added a commit
that referenced
this pull request
Jul 27, 2026
Testing against a real note with two internal links showed no links rendering at all. Root cause was two bugs stacked: - The LINKTYPE === '1' filter dropped both real links (their LINKTYPE was '0') — the doc comment claiming '1 = internal note link' doesn't hold up against real data. - bucketLinksByPage used ILink.OBJPAGE for the source page, which looked reasonable but is wrong: verified by drawing each link's LINKRECT on every rendered page and measuring ink coverage under it, OBJPAGE (4 and 1) didn't match either link's actual page (array index 0 and 3) under any indexing convention. It tracks something else -- looks like the page's own template label, which had drifted from its current array position. The original sn.links Record key's first-4-characters convention (1-indexed page, taken from PR #122) was actually right; reverting to it. It looked broken against the submodule's own link-tag fixture only because all three of its links happen to share one page and one key prefix -- confirmed by re-checking that fixture's exact expected bucketing rather than just "some valid page index".
pull Bot
pushed a commit
to ben-vargas/supernote-obsidian-plugin
that referenced
this pull request
Jul 28, 2026
Closes philips#127. Buckets each page's ILink entries (from the link parsing merged in philips#121) and overlays a clickable, invisibly-positioned region for each LINKRECT, scaled/repositioned by the same mechanism that already keeps the pdf.js text layer aligned through zoom. Click handling resolves same-file links via PAGEID against the currently loaded pages, and cross-file links by basename against the vault (mirroring VaultWriter.resolvePageAnchor's export-time resolution from PR philips#122), reusing the existing #page=N ephemeral-state anchor for the cross-file page jump rather than inventing a new one. parseLinkRect/bucketLinksByPage live in a new obsidian-free module (src/linkOverlay.ts) so they're unit-testable, including a real-fixture test that verifies LINKRECT's coordinate space against actual parsed data rather than trusting it from a doc comment. Also fixes the vitest/eslint/tsc plumbing needed for a test to read a real .note file from disk (the first test in this repo to need any Node builtins).
This was referenced Jul 29, 2026
pull Bot
pushed a commit
to ben-vargas/supernote-obsidian-plugin
that referenced
this pull request
Jul 29, 2026
…gins Extends PageTextProcessorContext (registerPageTextProcessor's hook, see ocr-plugins.md) with per-page fields an external companion plugin has had no way to see until now: starred keywords, internal links, PAGEID, orientation, and recognition status. Previously the hook only exposed a flat OCR-text string and rasterized image bytes, which was enough to reproduce the OCR-text-pattern half of philips#123 but not philips#122's genuine keyword-star/link handling - see the discussion on philips#145. sn.keywords/sn.links are grouped per page using the same first-4-characters-of-the-Record-key convention supernote-typescript's _parseLinks documents (more reliable than IKeyword.KEYWORDPAGE, which can be '0'/invalid). Verified against a real device-created fixture (supernote-typescript/tests/input/nomad-3.26.40-link-tag-3p.note). Titles were considered too (same "device-native structured signal" category as keywords/links) but dropped from this pass: ITitle has no decoded text, only a bounding box + bitmap, so getting title text needs correlating that box against page.recognitionElements' word boxes - real new logic, not just wiring through an existing field. Bumps the supernote-typescript submodule pointer to a branch (not yet merged) that exports RecognitionStatuses from its index, needed to type the new recognitionStatus field as that enum rather than a bare string - see supernote-typescript#38.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Split out of #81 (by @Floper), stacked on #121 (submodule bump) since it needs
ILink/sn.linksand richersn.keywordsfromsupernote-typescript.#My_Keyword) on the correct page, rather than as a flat list at the top of the document. Page is derived from theKEYWORDfooter key's prefix (more reliable thanKEYWORDPAGE, which can be'0'/invalid - see the parsing library's own test for this). Deduplicated against tags already present in that page's OCR text.LINKOkeys. The library already resolves same-document page anchors (ILink.textgets#Page Nappended); this adds cross-file anchor resolution - loads the target.notefile from the vault and looks up itsPAGEID, with a per-call cache to avoid re-parsing the same target note more than once per export.Ported onto the current
main.ts/settings.tsshape, and built on the now-currentsupernote-typescriptlink/keyword API (#24) rather than #81's own version of that work, which never merged.Test plan
npm run build- cleannpx eslint src/main.ts src/settings.ts- 0 errorsnpx vitest run- 22 passed.notefile with keyword stars and internal links (e.g. the submodule'stests/input/nomad-3.26.40-link-tag-3p.notefixture), verifying tag placement/dedup and same-file/cross-file Wikilink anchors