/obsidian-mathlinks-api-sample-plugin

This is a sample Obsidian.md plugin for demonstrating the usage of MathLinks API.

Primary LanguageTypeScript

Sample Plugin for Obsidian MathLinks API

This is a sample Obsidian.md plugin for demonstrating the usage of MathLinks API.

MathLinks is a community plugin that renders MathJax in your links. However, its power is not limited to math. Essentially, it can be used to

  • change how a link is displayed
  • (planned) using arbitrary inline markdown formatting syntaxes supported by Obsidian (see here and here)
    • Currently, only inline math is supported, but support for other syntaxes will also come soon.
  • without actually touching your note's content (e.g. typing an alias for each link), as well as dynamically update the displayed contents.

MathLinks API is here with you to allow other community plugins to utilize this power! This repository contains a sample plugin that displays a link to a heading/block like this:

without property

Moreover, if the note's property contains a certain key that the user defines in the plugin's setting tab (link-display by default), the note title in the links will be replaced with the corresponding property value:

with property

Usage

In this section, I will walk you through the process of building a simple plugin using MathLinks API.

Warning

Make sure that both the npm package obsidian-mathlinks and the Obsidian plugin MathLinks are version 0.5.1 or higher.

Installation

$ npm i -D obsidian-mathlinks

Import

import { Provider, addProvider, update } from 'obsidian-mathlinks';

Implement a custom provider

Given a pre-processed information of a link, Provider determines how the link is displayed through its provide method.

Let's take a link [[Note#heading]] as an example. In this case, the "pre-processed information" contains:

  • parsedLinktext: { path: string, subpath: string } - { path: 'Note', subpath: '#heading' }
  • targetFile: TFile | null - TFile object for Note.md if the link path Note is successfully resolved, null otherwise
  • targetSubpathResult: HeadingSubpathResult | BlockSubpathResult | null - The heading's information given by resolveSubpath
  • sourceFile: TFile - TFile object for the note where this link is stored in

To implement your custom provider, define a subclass of Provider and implement its provide method. It should return

  • string that will be interpreted as a markdown source for the link's displayed text
    • in the near future, arbitrary inline markdown syntaxes such as **bold**/$math$ will be allowed. But currently, only inline math is supported.
  • or null when your provider doesn't want to provide any custom displayed text.
    • In other word, your provider will be ignored when returning null.

provide(
parsedLinktext: { path: string, subpath: string },
targetFile: TFile | null,
targetSubpathResult: HeadingSubpathResult | BlockSubpathResult | null,
sourceFile: TFile
): string | null {
// ignore excluded folders
if (this.plugin.settings.excludedFolders.some(folder =>
sourceFile.path.startsWith(normalizePath(folder + '/')))
) return null;
const { app, settings } = this.plugin;
const { path } = parsedLinktext;
if (!targetFile) return null;
const targetCache = app.metadataCache.getFileCache(targetFile);
if (!targetCache) return null;
let noteTitleDisplay = targetCache.frontmatter?.[settings.key];
if (typeof noteTitleDisplay != 'string') noteTitleDisplay = targetFile.basename;
if (targetSubpathResult?.type == 'heading') {
return (path ? `${noteTitleDisplay} - ` : '')
+ `h${targetSubpathResult.current.level}:${targetSubpathResult.current.heading}`;
} else if (targetSubpathResult?.type == 'block') {
const { id } = targetSubpathResult.block;
let blockType = targetCache?.sections?.find(section => section.id == id)?.type;
if (!blockType && targetCache?.listItems?.find(section => section.id == id)) {
blockType = 'listitem';
}
blockType = blockType ?? 'block';
return (path ? `${noteTitleDisplay} - ` : '')
+ `${blockType}:${id}`;
}
return noteTitleDisplay;
}

Register your provider

In the onload method of your plugin, register your custom provider.

  • addProvider function creates an instance of your provider class using the factory function passed as the second parameter, and then registers it to MathLinks. Finally, it returns the provider object.
    • You have accesss to the MathLinks plugin instance inside the factory function.
  • In most cases, you will want to pass the resulting provider to addChild method of your plugin so that the provider will be properly unloaded when your plugin gets disabled. Otherwise, you are responsible to manage its lifecycle on your own.
  • Make sure you wrap the addProvider call in this.app.workspace.onLayoutReady(() => {...}) so that it will be called after MathLinks is loaded.
export default class MyPlugin extends Plugin {
	async onload() {
        ...
		this.app.workspace.onLayoutReady(() => {
		    this.addChild(
			    addProvider(this.app, (mathLinks) => new MyProvider(mathLinks, this))
		    );
		});
        ...
	}
}

Tell MathLinks to update the displayed text

Use update(app: App, file?: TFile) to inform MathLinks that it should update the display text of links. If file is given, MathLinks will only update the notes affected by changes in that file. Otherwise, MathLinks will update all notes currently open.

Source mode

Provider has enableInSourceMode property, which controls whether your provider gets activated in Source mode or not. The default implementation can be found here.

You can keep your provider in sync with the plugin's settings by the following getter/setter.

get enableInSourceMode() {
// read from the plugin settings
return this.plugin.settings.enableInSourceMode;
}
set enableInSourceMode(enable: boolean) {
// overwrite to the plugin settings
this.plugin.settings.enableInSourceMode = enable;
this.plugin.saveSettings();
// inform MathLinks that the settings have changed
update(this.plugin.app);

If you want to just follow MathLinks's settings, you can use the following getter:

// get enableInSourceMode() {
// return this.mathLinks.nativeProvider.enableInSourceMode;
// }

Note

In source mode, only wikilinks [[...]] are supported.

Remarks

  • The users of your plugin have to install not only your plugin but also MathLinks.
  • A breaking change might be introduced in the future.