Skip to content

Feat/auto markdown links tags#81

Draft
Floper wants to merge 11 commits into
philips:mainfrom
Floper:feat/auto-markdown-links-tags
Draft

Feat/auto markdown links tags#81
Floper wants to merge 11 commits into
philips:mainfrom
Floper:feat/auto-markdown-links-tags

Conversation

@Floper

@Floper Floper commented Jun 3, 2026

Copy link
Copy Markdown

Markdown export: links, tags, OCR markup, auto-sync and mirror folder

This PR builds on the updated supernote-typescript submodule (which now parses
internal links and keyword stars) to surface those features as Obsidian-native
constructs in the exported markdown. It also fixes several bugs in the auto-sync
workflow and adds new settings to control the behaviour.

Supernote keywords → Obsidian tags

Starred keywords from the Supernote app are emitted as Obsidian tags (e.g.
#Supernote_Keyword) on the correct page of the exported markdown, rather than
as a flat list at the top of the document.

  • The source page is derived from the KEYWORD footer key prefix (first 4 digits,
    1-indexed), matching the LINKO key format. This is more reliable than the
    KEYWORDPAGE field, which can be '0' (invalid).
  • Tags are emitted before the OCR text on each page but deduplicated: if the
    same tag was already embedded in the processed OCR text (see below), it is not
    repeated in the page header.
  • A note-level keyword map is built at export time so that brand-new tags — not
    yet indexed in the Obsidian vault — are still recognised as tags rather than
    headings during OCR processing.

Supernote links → Wikilinks

Internal links created via the Supernote link feature are emitted as Obsidian
Wikilinks on the correct page.

  • The source page is derived from the LINKO footer key prefix (first 4 digits,
    1-indexed) rather than OBJPAGE, which is unreliable.
  • Links within a page are ordered top-to-bottom by sorting LINKO keys
    (the key encodes the Y coordinate after the page prefix).
  • Page anchors: for same-document links the text field already contains
    #Page N (resolved by the library). For cross-file links the plugin loads the
    target .note from the vault, parses it, and resolves the PAGEID to a page
    number — e.g. [[other-note#Page 2]]. A per-call cache avoids re-parsing the
    same file multiple times.
  • Links with PAGEID: 'none' or where the target file is not in the vault
    produce a plain Wikilink without a page anchor.

OCR markup: # → tags/headings, @ → Wikilinks

A new processHashtagsAndMentions function post-processes the OCR text of each
page:

  • #Word or # Word: checked against the Obsidian vault tag index. If the tag
    exists → inline tag (#Word); otherwise → Markdown heading (# Word). Two-word
    combinations (e.g. # Existing Tag) are also checked as #existing_tag before
    falling back to a heading. The note's own keyword stars are checked first so
    newly created tags are recognised even before they appear in the vault index.
  • @ Word(s): everything after the @ on the same line becomes a Wikilink
    ([[Word(s)]]), supporting multi-word note names.

Auto-sync fixes

  • Path construction bug: the previous code used
    `${file.parent?.path}/${file.basename}.md` which produces //name.md for
    vault-root files (Obsidian returns "/" as the root folder path). The output
    path is now derived from file.path.replace(/\.note$/i, '.md'), which Obsidian
    always formats correctly.
  • Race condition: when a .note file syncs, Obsidian fires both 'create'
    and 'modify' events in quick succession. Both handlers called
    vault.create, causing a "File already exists" error. The overwrite path
    now wraps vault.create in a try/catch and retries with vault.modify when
    the file appeared between the existence check and the create.
  • attachMarkdownFile now properly awaits writeMarkdownFile so errors
    surface rather than being silently dropped as unhandled promise rejections.
  • .catch() handlers added to both vault event callbacks so any remaining errors
    appear in the developer console instead of as uncaught exceptions.

Markdown mirror folder

A new optional setting lets users save all exported markdown files into a
dedicated vault folder that mirrors the .note file structure, instead of
placing each .md file alongside its .note file.

  • Setting: Markdown mirror folder (text input, empty by default = save
    alongside). Example value: SupernoteMarkdowns.
  • ensureFolderExists walks the path segment by segment, creating any missing
    intermediate folders (with a concurrent-creation guard).
  • Works correctly for notes at the vault root and in nested subfolders.

New settings

All new behaviours are opt-out via toggles in the plugin settings:

Setting Default Description
isAutoSyncMarkdownEnabled false Auto-export markdown when a .note file changes
isKeywordsAndLinksEnabled true Convert keywords to tags and links to Wikilinks
isHashtagsMentionsEnabled true Convert # and @ in OCR text
markdownMirrorFolder "" Output folder for mirrored markdown files

@Floper Floper mentioned this pull request Jun 3, 2026
@Floper Floper marked this pull request as draft June 4, 2026 08:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant